[3cbb63a] | 1 | /* |
---|
| 2 | * linux/drivers/char/vt.c |
---|
| 3 | * |
---|
| 4 | * Copyright (C) 1992 obz under the linux copyright |
---|
| 5 | * |
---|
| 6 | * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 |
---|
| 7 | * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 |
---|
| 8 | * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 |
---|
| 9 | * Some code moved for less code duplication - Andi Kleen - Mar 1997 |
---|
| 10 | * |
---|
| 11 | * |
---|
| 12 | * by: Rosimildo da Silva -- |
---|
| 13 | * Ported to RTEMS to provide the basic interface to the console |
---|
| 14 | * driver. Removed all stuff not required, such as VT_, Fonts, etc. |
---|
| 15 | */ |
---|
| 16 | |
---|
[b88e366] | 17 | #include <string.h> /* memcpy */ |
---|
[3cbb63a] | 18 | #include <sys/types.h> |
---|
| 19 | #include <errno.h> |
---|
| 20 | |
---|
| 21 | #include <i386_io.h> |
---|
[7a0a5531] | 22 | #include <rtems.h> |
---|
[3cbb63a] | 23 | #include <rtems/kd.h> |
---|
| 24 | #include <rtems/keyboard.h> |
---|
| 25 | |
---|
| 26 | /* |
---|
| 27 | * Console (vt and kd) routines, as defined by USL SVR4 manual, and by |
---|
| 28 | * experimentation and study of X386 SYSV handling. |
---|
| 29 | * |
---|
| 30 | * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and |
---|
| 31 | * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, |
---|
| 32 | * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will |
---|
| 33 | * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to |
---|
| 34 | * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using |
---|
| 35 | * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing |
---|
| 36 | * to the current console is done by the main ioctl code. |
---|
| 37 | */ |
---|
| 38 | |
---|
| 39 | struct vt_struct *vt_cons[MAX_NR_CONSOLES]; |
---|
| 40 | |
---|
| 41 | /* Keyboard type: Default is KB_101, but can be set by machine |
---|
| 42 | * specific code. |
---|
| 43 | */ |
---|
| 44 | unsigned char keyboard_type = KB_101; |
---|
| 45 | |
---|
| 46 | /* |
---|
| 47 | * Generates sound of some frequency for some number of clock ticks |
---|
| 48 | * |
---|
| 49 | * If freq is 0, will turn off sound, else will turn it on for that time. |
---|
| 50 | * If msec is 0, will return immediately, else will sleep for msec time, then |
---|
| 51 | * turn sound off. |
---|
| 52 | * |
---|
| 53 | * We also return immediately, which is what was implied within the X |
---|
| 54 | * comments - KDMKTONE doesn't put the process to sleep. |
---|
| 55 | */ |
---|
| 56 | |
---|
| 57 | #if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \ |
---|
| 58 | || (defined(__mips__) && !defined(CONFIG_SGI)) |
---|
| 59 | |
---|
| 60 | static void |
---|
| 61 | kd_nosound(unsigned long ignored) |
---|
| 62 | { |
---|
| 63 | /* disable counter 2 */ |
---|
| 64 | outb(inb_p(0x61)&0xFC, 0x61); |
---|
| 65 | return; |
---|
| 66 | } |
---|
| 67 | |
---|
| 68 | void |
---|
| 69 | _kd_mksound(unsigned int hz, unsigned int ticks) |
---|
| 70 | { |
---|
[d57c04e] | 71 | unsigned int count = 0; |
---|
| 72 | int level; |
---|
[3cbb63a] | 73 | |
---|
| 74 | if (hz > 20 && hz < 32767) |
---|
| 75 | count = 1193180 / hz; |
---|
[6128a4a] | 76 | |
---|
[d57c04e] | 77 | _CPU_ISR_Disable(level); |
---|
[3cbb63a] | 78 | /* del_timer(&sound_timer); */ |
---|
| 79 | if (count) { |
---|
| 80 | /* enable counter 2 */ |
---|
| 81 | outb_p(inb_p(0x61)|3, 0x61); |
---|
| 82 | /* set command for counter 2, 2 byte write */ |
---|
| 83 | outb_p(0xB6, 0x43); |
---|
| 84 | /* select desired HZ */ |
---|
| 85 | outb_p(count & 0xff, 0x42); |
---|
| 86 | outb((count >> 8) & 0xff, 0x42); |
---|
| 87 | |
---|
| 88 | /* |
---|
| 89 | if (ticks) { |
---|
| 90 | sound_timer.expires = jiffies+ticks; |
---|
| 91 | add_timer(&sound_timer); |
---|
| 92 | } |
---|
| 93 | */ |
---|
| 94 | } else |
---|
| 95 | kd_nosound(0); |
---|
| 96 | |
---|
[d57c04e] | 97 | _CPU_ISR_Enable (level); |
---|
[3cbb63a] | 98 | return; |
---|
| 99 | } |
---|
| 100 | |
---|
| 101 | #else |
---|
| 102 | |
---|
| 103 | void |
---|
| 104 | _kd_mksound(unsigned int hz, unsigned int ticks) |
---|
| 105 | { |
---|
| 106 | } |
---|
| 107 | |
---|
| 108 | #endif |
---|
| 109 | |
---|
| 110 | void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound; |
---|
| 111 | |
---|
| 112 | #define i (tmp.kb_index) |
---|
| 113 | #define s (tmp.kb_table) |
---|
| 114 | #define v (tmp.kb_value) |
---|
| 115 | static inline int |
---|
| 116 | do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kbd) |
---|
| 117 | { |
---|
| 118 | struct kbentry tmp; |
---|
| 119 | ushort *key_map, val; |
---|
| 120 | |
---|
| 121 | tmp = *user_kbe; |
---|
| 122 | if (i >= NR_KEYS || s >= MAX_NR_KEYMAPS) |
---|
[6128a4a] | 123 | return -EINVAL; |
---|
[3cbb63a] | 124 | |
---|
| 125 | switch (cmd) { |
---|
| 126 | case KDGKBENT: |
---|
| 127 | key_map = key_maps[s]; |
---|
| 128 | if (key_map) { |
---|
| 129 | val = U(key_map[i]); |
---|
| 130 | if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) |
---|
| 131 | val = K_HOLE; |
---|
| 132 | } else |
---|
| 133 | val = (i ? K_HOLE : K_NOSUCHMAP); |
---|
| 134 | user_kbe->kb_value = val; |
---|
| 135 | return 0; |
---|
| 136 | |
---|
| 137 | case KDSKBENT: |
---|
| 138 | return -EINVAL; |
---|
| 139 | } |
---|
| 140 | return 0; |
---|
| 141 | } |
---|
| 142 | #undef i |
---|
| 143 | #undef s |
---|
| 144 | #undef v |
---|
| 145 | |
---|
| 146 | #define HZ 100 |
---|
| 147 | |
---|
[6128a4a] | 148 | static inline int |
---|
[3cbb63a] | 149 | do_kbkeycode_ioctl(int cmd, struct kbkeycode *user_kbkc, int perm) |
---|
| 150 | { |
---|
| 151 | struct kbkeycode tmp; |
---|
| 152 | int kc = 0; |
---|
| 153 | |
---|
| 154 | tmp = *user_kbkc; |
---|
| 155 | switch (cmd) { |
---|
| 156 | case KDGETKEYCODE: |
---|
| 157 | kc = getkeycode(tmp.scancode); |
---|
| 158 | if (kc >= 0) |
---|
| 159 | user_kbkc->keycode = kc; |
---|
| 160 | break; |
---|
| 161 | case KDSETKEYCODE: |
---|
| 162 | if (!perm) |
---|
| 163 | return -EPERM; |
---|
| 164 | kc = setkeycode(tmp.scancode, tmp.keycode); |
---|
| 165 | break; |
---|
| 166 | } |
---|
| 167 | return kc; |
---|
| 168 | } |
---|
| 169 | |
---|
| 170 | static inline int |
---|
| 171 | do_kdgkb_ioctl(int cmd, struct kbsentry *user_kdgkb, int perm) |
---|
| 172 | { |
---|
| 173 | return -EINVAL; |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | /* |
---|
| 177 | * We handle the console-specific ioctl's here. We allow the |
---|
[6128a4a] | 178 | * capability to modify any console, not just the fg_console. |
---|
[3cbb63a] | 179 | */ |
---|
| 180 | int vt_ioctl( unsigned int cmd, unsigned long arg) |
---|
| 181 | { |
---|
| 182 | int perm; |
---|
| 183 | unsigned int console; |
---|
| 184 | unsigned char ucval; |
---|
| 185 | struct kbd_struct * kbd; |
---|
| 186 | |
---|
| 187 | console = 0; |
---|
| 188 | /* |
---|
| 189 | * To have permissions to do most of the vt ioctls, we either have |
---|
| 190 | * to be the owner of the tty, or super-user. |
---|
| 191 | */ |
---|
| 192 | perm = 1; |
---|
| 193 | kbd = kbd_table + console; |
---|
| 194 | switch (cmd) { |
---|
| 195 | case KIOCSOUND: |
---|
| 196 | if (!perm) |
---|
| 197 | return -EPERM; |
---|
| 198 | if (arg) |
---|
| 199 | arg = 1193180 / arg; |
---|
| 200 | kd_mksound(arg, 0); |
---|
| 201 | return 0; |
---|
| 202 | |
---|
| 203 | case KDMKTONE: |
---|
| 204 | if (!perm) |
---|
| 205 | return -EPERM; |
---|
| 206 | { |
---|
| 207 | unsigned int ticks, count; |
---|
[6128a4a] | 208 | |
---|
[3cbb63a] | 209 | /* |
---|
| 210 | * Generate the tone for the appropriate number of ticks. |
---|
| 211 | * If the time is zero, turn off sound ourselves. |
---|
| 212 | */ |
---|
| 213 | ticks = HZ * ((arg >> 16) & 0xffff) / 1000; |
---|
| 214 | count = ticks ? (arg & 0xffff) : 0; |
---|
| 215 | if (count) |
---|
| 216 | count = 1193180 / count; |
---|
| 217 | kd_mksound(count, ticks); |
---|
| 218 | return 0; |
---|
| 219 | } |
---|
| 220 | |
---|
| 221 | case KDGKBTYPE: |
---|
| 222 | /* |
---|
| 223 | * this is naive. |
---|
| 224 | */ |
---|
| 225 | ucval = keyboard_type; |
---|
| 226 | goto setchar; |
---|
| 227 | |
---|
| 228 | case KDSETMODE: |
---|
| 229 | case KDGETMODE: |
---|
| 230 | return -EINVAL; |
---|
| 231 | |
---|
| 232 | case KDSKBMODE: |
---|
| 233 | if (!perm) |
---|
| 234 | return -EPERM; |
---|
| 235 | switch(arg) { |
---|
| 236 | case K_RAW: |
---|
| 237 | kbd->kbdmode = VC_RAW; |
---|
| 238 | break; |
---|
| 239 | case K_MEDIUMRAW: |
---|
| 240 | kbd->kbdmode = VC_MEDIUMRAW; |
---|
| 241 | break; |
---|
| 242 | case K_XLATE: |
---|
| 243 | kbd->kbdmode = VC_XLATE; |
---|
| 244 | compute_shiftstate(); |
---|
| 245 | break; |
---|
| 246 | case K_UNICODE: |
---|
| 247 | kbd->kbdmode = VC_UNICODE; |
---|
| 248 | compute_shiftstate(); |
---|
| 249 | break; |
---|
| 250 | default: |
---|
| 251 | return -EINVAL; |
---|
| 252 | } |
---|
| 253 | return 0; |
---|
| 254 | |
---|
| 255 | case KDGKBMODE: |
---|
| 256 | ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : |
---|
| 257 | (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : |
---|
| 258 | (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : |
---|
| 259 | K_XLATE); |
---|
| 260 | goto setint; |
---|
| 261 | |
---|
| 262 | /* this could be folded into KDSKBMODE, but for compatibility |
---|
| 263 | reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ |
---|
| 264 | case KDSKBMETA: |
---|
| 265 | switch(arg) { |
---|
| 266 | case K_METABIT: |
---|
| 267 | clr_vc_kbd_mode(kbd, VC_META); |
---|
| 268 | break; |
---|
| 269 | case K_ESCPREFIX: |
---|
| 270 | set_vc_kbd_mode(kbd, VC_META); |
---|
| 271 | break; |
---|
| 272 | default: |
---|
| 273 | return -EINVAL; |
---|
| 274 | } |
---|
| 275 | return 0; |
---|
| 276 | |
---|
| 277 | case KDGKBMETA: |
---|
| 278 | ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); |
---|
| 279 | setint: |
---|
| 280 | *(int *)arg = ucval; |
---|
| 281 | return 0; |
---|
| 282 | |
---|
| 283 | case KDGETKEYCODE: |
---|
| 284 | case KDSETKEYCODE: |
---|
| 285 | return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm); |
---|
| 286 | |
---|
| 287 | case KDGKBENT: |
---|
| 288 | case KDSKBENT: |
---|
| 289 | return do_kdsk_ioctl(cmd, (struct kbentry *)arg, perm, kbd); |
---|
| 290 | |
---|
| 291 | case KDGKBDIACR: |
---|
| 292 | { |
---|
| 293 | struct kbdiacrs *a = (struct kbdiacrs *)arg; |
---|
| 294 | a->kb_cnt = accent_table_size; |
---|
| 295 | memcpy( a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr) ); |
---|
| 296 | return 0; |
---|
| 297 | } |
---|
| 298 | |
---|
| 299 | case KDSKBDIACR: |
---|
| 300 | { |
---|
| 301 | struct kbdiacrs *a = (struct kbdiacrs *)arg; |
---|
| 302 | unsigned int ct; |
---|
| 303 | |
---|
| 304 | if (!perm) |
---|
| 305 | return -EPERM; |
---|
| 306 | ct = a->kb_cnt; |
---|
| 307 | if (ct >= MAX_DIACR) |
---|
| 308 | return -EINVAL; |
---|
| 309 | accent_table_size = ct; |
---|
| 310 | memcpy(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr)); |
---|
| 311 | return 0; |
---|
| 312 | } |
---|
| 313 | |
---|
| 314 | /* the ioctls below read/set the flags usually shown in the leds */ |
---|
| 315 | /* don't use them - they will go away without warning */ |
---|
| 316 | case KDGKBLED: |
---|
| 317 | ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); |
---|
| 318 | goto setchar; |
---|
| 319 | |
---|
| 320 | case KDSKBLED: |
---|
| 321 | if (!perm) |
---|
| 322 | return -EPERM; |
---|
| 323 | if (arg & ~0x77) |
---|
| 324 | return -EINVAL; |
---|
| 325 | kbd->ledflagstate = (arg & 7); |
---|
| 326 | kbd->default_ledflagstate = ((arg >> 4) & 7); |
---|
| 327 | set_leds(); |
---|
| 328 | return 0; |
---|
| 329 | |
---|
| 330 | /* the ioctls below only set the lights, not the functions */ |
---|
| 331 | /* for those, see KDGKBLED and KDSKBLED above */ |
---|
| 332 | case KDGETLED: |
---|
| 333 | ucval = getledstate(); |
---|
| 334 | setchar: |
---|
| 335 | *(char*)arg = ucval; |
---|
| 336 | return 0; |
---|
| 337 | |
---|
| 338 | case KDSETLED: |
---|
| 339 | if (!perm) |
---|
| 340 | return -EPERM; |
---|
| 341 | setledstate(kbd, arg); |
---|
| 342 | return 0; |
---|
| 343 | |
---|
| 344 | default: |
---|
| 345 | return -EINVAL; |
---|
| 346 | } |
---|
| 347 | } |
---|