Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/drivers/char/vt.c 3 * 4 * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/kernel.h> 9 #include <fiwix/console.h> 10 #include <fiwix/keyboard.h> 11 #include <fiwix/tty.h> 12 #include <fiwix/vt.h> 13 #include <fiwix/kd.h> 14 #include <fiwix/errno.h> 15 #include <fiwix/stdio.h> 16 #include <fiwix/string.h> 17 18 int kbdmode = 0; 19 20 int vt_ioctl(struct tty *tty, int cmd, unsigned long int arg) 21 { 22 struct vconsole *vc; 23 int n, errno; 24 25 /* only virtual consoles support the following ioctl commands */ 26 if(MAJOR(tty->dev) != VCONSOLES_MAJOR) { 27 return -ENXIO; 28 } 29 30 vc = (struct vconsole *)tty->driver_data; 31 32 switch(cmd) { 33 case KDGETLED: 34 if((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned char)))) { 35 return errno; 36 } 37 memset_b((void *)arg, vc->led_status, sizeof(char)); 38 break; 39 40 case KDSETLED: 41 if(arg > 7) { 42 return -EINVAL; 43 } 44 vc->led_status = arg; 45 set_leds(vc->led_status); 46 break; 47 48 /* FIXME: implement KDGKBLED and KDSKBLED 49 * it will need to convert 'scrlock, numlock, capslock' into led_flags. 50 */ 51 52 case KDGKBTYPE: 53 if((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned char)))) { 54 return errno; 55 } 56 memset_b((void *)arg, KB_101, sizeof(char)); 57 break; 58 59 case KDSETMODE: 60 if(arg != KD_TEXT && arg != KD_GRAPHICS) { 61 return -EINVAL; 62 } 63 if(vc->vc_mode != arg) { 64 vc->vc_mode = arg; 65 if(arg == KD_GRAPHICS) { 66 video.blank_screen(vc); 67 } else { 68 unblank_screen(vc); 69 } 70 } 71 break; 72 73 case KDGETMODE: 74 if((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned char)))) { 75 return errno; 76 } 77 memset_b((void *)arg, vc->vc_mode, sizeof(char)); 78 break; 79 80 case KDGKBMODE: 81 if((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned char)))) { 82 return errno; 83 } 84 memset_b((void *)arg, tty->kbd.mode, sizeof(unsigned char)); 85 break; 86 87 case KDSKBMODE: 88 if(arg != K_RAW && arg != K_XLATE && arg != K_MEDIUMRAW) { 89 arg = K_XLATE; 90 } 91 tty->kbd.mode = arg; 92 tty_queue_flush(&tty->read_q); 93 break; 94 95 case KDSKBENT: 96 { 97 struct kbentry *k = (struct kbentry *)arg; 98 if((errno = check_user_area(VERIFY_WRITE, (void *)k, sizeof(struct kbentry)))) { 99 return errno; 100 } 101 if(k->kb_table < NR_MODIFIERS) { 102 if(k->kb_index < NR_SCODES) { 103 keymap[(k->kb_index * NR_MODIFIERS) + k->kb_table] = k->kb_value; 104 } else { 105 return -EINVAL; 106 } 107 } else { 108 printk("%s(): kb_table value '%d' not supported.\n", __FUNCTION__, k->kb_table); 109 return -EINVAL; 110 } 111 } 112 break; 113 114 case VT_OPENQRY: 115 { 116 int *val = (int *)arg; 117 if((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) { 118 return errno; 119 } 120 for(n = 1; n < NR_VCONSOLES + 1; n++) { 121 tty = get_tty(MKDEV(VCONSOLES_MAJOR, n)); 122 if(!tty->count) { 123 break; 124 } 125 } 126 *val = (n < NR_VCONSOLES + 1 ? n : -1); 127 } 128 break; 129 130 case VT_GETMODE: 131 { 132 struct vt_mode *vt_mode = (struct vt_mode *)arg; 133 if((errno = check_user_area(VERIFY_WRITE, (void *)vt_mode, sizeof(struct vt_mode)))) { 134 return errno; 135 } 136 memcpy_b(vt_mode, &vc->vt_mode, sizeof(struct vt_mode)); 137 } 138 break; 139 140 case VT_SETMODE: 141 { 142 struct vt_mode *vt_mode = (struct vt_mode *)arg; 143 if((errno = check_user_area(VERIFY_READ, (void *)vt_mode, sizeof(struct vt_mode)))) { 144 return errno; 145 } 146 if(vt_mode->mode != VT_AUTO && vt_mode->mode != VT_PROCESS) { 147 return -EINVAL; 148 } 149 memcpy_b(&vc->vt_mode, vt_mode, sizeof(struct vt_mode)); 150 vc->vt_mode.frsig = 0; /* ignored */ 151 tty->pid = current->pid; 152 vc->switchto_tty = 0; 153 } 154 break; 155 156 case VT_GETSTATE: 157 { 158 struct vt_stat *vt_stat = (struct vt_stat *)arg; 159 if((errno = check_user_area(VERIFY_WRITE, (void *)vt_stat, sizeof(struct vt_stat)))) { 160 return errno; 161 } 162 vt_stat->v_active = current_cons; 163 vt_stat->v_state = 1; /* /dev/tty0 is always opened */ 164 for(n = 1; n < NR_VCONSOLES + 1; n++) { 165 tty = get_tty(MKDEV(VCONSOLES_MAJOR, n)); 166 if(tty->count) { 167 vt_stat->v_state |= (1 << n); 168 } 169 } 170 } 171 break; 172 173 case VT_RELDISP: 174 if(vc->vt_mode.mode != VT_PROCESS) { 175 return -EINVAL; 176 } 177 if(vc->switchto_tty < 0) { 178 if(arg != VT_ACKACQ) { 179 return -EINVAL; 180 } 181 } else { 182 if(arg) { 183 int switchto_tty; 184 switchto_tty = vc->switchto_tty; 185 vc->switchto_tty = -1; 186 vconsole_select_final(switchto_tty); 187 } else { 188 vc->switchto_tty = -1; 189 } 190 } 191 break; 192 193 case VT_ACTIVATE: 194 if(current_cons == MINOR(tty->dev) || IS_SUPERUSER) { 195 if(!arg || arg > NR_VCONSOLES) { 196 return -ENXIO; 197 } 198 vconsole_select(--arg); 199 } else { 200 return -EPERM; 201 } 202 break; 203 204 case VT_WAITACTIVE: 205 if(current_cons == MINOR(tty->dev)) { 206 break; 207 } 208 if(!arg || arg > NR_VCONSOLES) { 209 return -ENXIO; 210 } 211 printk("ACTIVATING another tty!! (cmd = 0x%x)\n", cmd); 212 break; 213 214 default: 215 return -EINVAL; 216 } 217 return 0; 218 }