root/kernel/chr_drv/vt.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. kd_nosound
  2. kd_mksound
  3. vt_ioctl

   1 /*
   2  *  kernel/chr_drv/vt.c
   3  *
   4  *  Copyright (C) 1992 obz under the linux copyright
   5  */
   6 
   7 #include <linux/types.h>
   8 #include <linux/errno.h>
   9 #include <linux/sched.h>
  10 #include <linux/tty.h>
  11 #include <linux/timer.h>
  12 #include <linux/kernel.h>
  13 #include <linux/keyboard.h>
  14 #include <linux/kd.h>
  15 #include <linux/vt.h>
  16 
  17 #include <asm/io.h>
  18 #include <asm/segment.h>
  19 
  20 #include "vt_kern.h"
  21 
  22 /*
  23  * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
  24  * experimentation and study of X386 SYSV handling.
  25  *
  26  * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
  27  * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
  28  * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
  29  * always treat our set of vt as numbered 1..NR_CONSOLES (corresponding to
  30  * ttys 0..NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
  31  * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
  32  * to the current console is done by the main ioctl code.
  33  */
  34 
  35 struct vt_cons vt_cons[NR_CONSOLES];
  36 
  37 extern "C" int sys_ioperm(unsigned long from, unsigned long num, int on);
  38 
  39 extern void change_console(unsigned int new_console);
  40 extern void complete_change_console(unsigned int new_console);
  41 extern int vt_waitactive(void);
  42 
  43 /*
  44  * these are the valid i/o ports we're allowed to change. they map all the
  45  * video ports
  46  */
  47 #define GPFIRST 0x3b4
  48 #define GPLAST 0x3df
  49 #define GPNUM (GPLAST - GPFIRST + 1)
  50 
  51 /*
  52  * Generates sound of some count for some number of clock ticks
  53  * [count = 1193180 / frequency]
  54  *
  55  * If freq is 0, will turn off sound, else will turn it on for that time.
  56  * If msec is 0, will return immediately, else will sleep for msec time, then
  57  * turn sound off.
  58  *
  59  * We use the BEEP_TIMER vector since we're using the same method to
  60  * generate sound, and we'll overwrite any beep in progress. That may
  61  * be something to fix later, if we like.
  62  *
  63  * We also return immediately, which is what was implied within the X
  64  * comments - KDMKTONE doesn't put the process to sleep.
  65  */
  66 static void
  67 kd_nosound(unsigned long ignored)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69         /* disable counter 2 */
  70         outb(inb_p(0x61)&0xFC, 0x61);
  71         return;
  72 }
  73 
  74 void
  75 kd_mksound(unsigned int count, unsigned int ticks)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77         static struct timer_list sound_timer = { NULL, 0, 0, kd_nosound };
  78 
  79         cli();
  80         del_timer(&sound_timer);
  81         if (count) {
  82                 /* enable counter 2 */
  83                 outb_p(inb_p(0x61)|3, 0x61);
  84                 /* set command for counter 2, 2 byte write */
  85                 outb_p(0xB6, 0x43);
  86                 /* select desired HZ */
  87                 outb_p(count & 0xff, 0x42);
  88                 outb((count >> 8) & 0xff, 0x42);
  89 
  90                 if (ticks) {
  91                         sound_timer.expires = ticks;
  92                         add_timer(&sound_timer);
  93                 }
  94         } else
  95                 kd_nosound(0);
  96         sti();
  97         return;
  98 }
  99 
 100 /*
 101  * We handle the console-specific ioctl's here.  We allow the
 102  * capability to modify any console, not just the fg_console. 
 103  */
 104 int vt_ioctl(struct tty_struct *tty, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 105              unsigned int cmd, unsigned long arg)
 106 {
 107         int console, i;
 108         unsigned char ucval;
 109         struct kbd_struct * kbd;
 110 
 111         console = tty->line - 1;
 112 
 113         if (console < 0 || console >= NR_CONSOLES)
 114                 return -EINVAL;
 115 
 116         kbd = kbd_table + console;
 117         switch (cmd) {
 118         case KIOCSOUND:
 119                 kd_mksound((unsigned int)arg, 0);
 120                 return 0;
 121 
 122         case KDMKTONE:
 123         {
 124                 unsigned int ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
 125 
 126                 /*
 127                  * Generate the tone for the appropriate number of ticks.
 128                  * If the time is zero, turn off sound ourselves.
 129                  */
 130                 kd_mksound(arg & 0xffff, ticks);
 131                 if (ticks == 0)
 132                         kd_nosound(0);
 133                 return 0;
 134         }
 135 
 136         case KDGKBTYPE:
 137                 /*
 138                  * this is naive.
 139                  */
 140                 i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
 141                 if (!i)
 142                         put_fs_byte(KB_101, (char *) arg);
 143                 return i;
 144 
 145         case KDADDIO:
 146         case KDDELIO:
 147                 /*
 148                  * KDADDIO and KDDELIO may be able to add ports beyond what
 149                  * we reject here, but to be safe...
 150                  */
 151                 if (arg < GPFIRST || arg > GPLAST)
 152                         return -EINVAL;
 153                 return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
 154 
 155         case KDENABIO:
 156         case KDDISABIO:
 157                 return sys_ioperm(GPFIRST, GPNUM,
 158                                   (cmd == KDENABIO)) ? -ENXIO : 0;
 159 
 160         case KDSETMODE:
 161                 /*
 162                  * currently, setting the mode from KD_TEXT to KD_GRAPHICS
 163                  * doesn't do a whole lot. i'm not sure if it should do any
 164                  * restoration of modes or what...
 165                  */
 166                 switch (arg) {
 167                 case KD_GRAPHICS:
 168                         break;
 169                 case KD_TEXT0:
 170                 case KD_TEXT1:
 171                         arg = KD_TEXT;
 172                 case KD_TEXT:
 173                         break;
 174                 default:
 175                         return -EINVAL;
 176                 }
 177                 if (vt_cons[console].vc_mode == (unsigned char) arg)
 178                         return 0;
 179                 vt_cons[console].vc_mode = (unsigned char) arg;
 180                 if (console != fg_console)
 181                         return 0;
 182                 /*
 183                  * explicitly blank/unblank the screen if switching modes
 184                  */
 185                 if (arg == KD_TEXT)
 186                         unblank_screen();
 187                 else {
 188                         timer_active &= ~(1<<BLANK_TIMER);
 189                         blank_screen();
 190                 }
 191                 return 0;
 192 
 193         case KDGETMODE:
 194                 i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
 195                 if (!i)
 196                         put_fs_long(vt_cons[console].vc_mode, (unsigned long *) arg);
 197                 return i;
 198 
 199         case KDMAPDISP:
 200         case KDUNMAPDISP:
 201                 /*
 202                  * these work like a combination of mmap and KDENABIO.
 203                  * this could be easily finished.
 204                  */
 205                 return -EINVAL;
 206 
 207         case KDSKBMODE:
 208                 if (arg == K_RAW) {
 209                         set_vc_kbd_flag(kbd, VC_RAW);
 210                 } else if (arg == K_XLATE) {
 211                         clr_vc_kbd_flag(kbd, VC_RAW);
 212                 }
 213                 else
 214                         return -EINVAL;
 215                 flush_input(tty);
 216                 return 0;
 217 
 218         case KDGKBMODE:
 219                 i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
 220                 if (!i) {
 221                         ucval = vc_kbd_flag(kbd, VC_RAW);
 222                         put_fs_long(ucval ? K_RAW : K_XLATE, (unsigned long *) arg);
 223                 }
 224                 return i;
 225 
 226         case KDGKBENT:
 227         {
 228                 struct kbentry * const a = (struct kbentry *)arg;
 229                 u_char i;
 230                 u_char s;
 231 
 232                 verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
 233                 if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
 234                         return -EINVAL;
 235                 if ((s = get_fs_byte((char *) &a->kb_table)) >= NR_KEYMAPS)
 236                         return -EINVAL;
 237                 put_fs_word(key_map[s][i], (short *) &a->kb_value);
 238                 return 0;
 239         }
 240 
 241         case KDSKBENT:
 242         {
 243                 const struct kbentry * a = (struct kbentry *)arg;
 244                 u_char i;
 245                 u_char s;
 246                 u_short v;
 247 
 248                 verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
 249                 if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
 250                         return -EINVAL;
 251                 if ((s = get_fs_byte((char *) &a->kb_table)) >= NR_KEYMAPS)
 252                         return -EINVAL;
 253                 if (KTYP(v = get_fs_word(&a->kb_value)) >= NR_TYPES)
 254                         return -EINVAL;
 255                 if (KVAL(v) > max_vals[KTYP(v)])
 256                         return -EINVAL;
 257                 key_map[s][i] = v;
 258                 return 0;
 259         }
 260 
 261         case KDGETLED:
 262                 i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
 263                 if (i)
 264                         return i;
 265                 ucval = 0;
 266                 if (vc_kbd_flag(kbd, VC_SCROLLOCK))
 267                         ucval |= LED_SCR;
 268                 if (vc_kbd_flag(kbd, VC_NUMLOCK))
 269                         ucval |= LED_NUM;
 270                 if (vc_kbd_flag(kbd, VC_CAPSLOCK))
 271                         ucval |= LED_CAP;
 272                 put_fs_byte(ucval, (char *) arg);
 273                 return 0;
 274 
 275         case KDSETLED:
 276                 if (arg & ~7)
 277                         return -EINVAL;
 278                 if (arg & LED_SCR)
 279                         set_vc_kbd_flag(kbd, VC_SCROLLOCK);
 280                 else
 281                         clr_vc_kbd_flag(kbd, VC_SCROLLOCK);
 282                 if (arg & LED_NUM)
 283                         set_vc_kbd_flag(kbd, VC_NUMLOCK);
 284                 else
 285                         clr_vc_kbd_flag(kbd, VC_NUMLOCK);
 286                 if (arg & LED_CAP)
 287                         set_vc_kbd_flag(kbd, VC_CAPSLOCK);
 288                 else
 289                         clr_vc_kbd_flag(kbd, VC_CAPSLOCK);
 290                 set_leds();
 291                 return 0;
 292 
 293         case VT_SETMODE:
 294         {
 295                 struct vt_mode *vtmode = (struct vt_mode *)arg;
 296                 char mode;
 297 
 298                 i = verify_area(VERIFY_WRITE, (void *)vtmode, sizeof(struct vt_mode));
 299                 if (i)
 300                         return i;
 301                 mode = get_fs_byte(&vtmode->mode);
 302                 if (mode != VT_AUTO && mode != VT_PROCESS)
 303                         return -EINVAL;
 304                 vt_cons[console].vt_mode.mode = mode;
 305                 vt_cons[console].vt_mode.waitv = get_fs_byte(&vtmode->waitv);
 306                 vt_cons[console].vt_mode.relsig = get_fs_word(&vtmode->relsig);
 307                 vt_cons[console].vt_mode.acqsig = get_fs_word(&vtmode->acqsig);
 308                 /* the frsig is ignored, so we set it to 0 */
 309                 vt_cons[console].vt_mode.frsig = 0;
 310                 vt_cons[console].vt_pid = current->pid;
 311                 vt_cons[console].vt_newvt = 0;
 312                 return 0;
 313         }
 314 
 315         case VT_GETMODE:
 316         {
 317                 struct vt_mode *vtmode = (struct vt_mode *)arg;
 318 
 319                 i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct vt_mode));
 320                 if (i)
 321                         return i;
 322                 put_fs_byte(vt_cons[console].vt_mode.mode, &vtmode->mode);
 323                 put_fs_byte(vt_cons[console].vt_mode.waitv, &vtmode->waitv);
 324                 put_fs_word(vt_cons[console].vt_mode.relsig, &vtmode->relsig);
 325                 put_fs_word(vt_cons[console].vt_mode.acqsig, &vtmode->acqsig);
 326                 put_fs_word(vt_cons[console].vt_mode.frsig, &vtmode->frsig);
 327                 return 0;
 328         }
 329 
 330         /*
 331          * Returns global vt state. Note that VT 0 is always open, since
 332          * it's an alias for the current VT, and people can't use it here.
 333          */
 334         case VT_GETSTATE:
 335         {
 336                 struct vt_stat *vtstat = (struct vt_stat *)arg;
 337                 unsigned short state, mask;
 338 
 339                 i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat));
 340                 if (i)
 341                         return i;
 342                 put_fs_word(fg_console + 1, &vtstat->v_active);
 343                 state = 1;      /* /dev/tty0 is always open */
 344                 for (i = 1, mask = 2; i <= NR_CONSOLES; ++i, mask <<= 1)
 345                         if (tty_table[i] && tty_table[i]->count > 0)
 346                                 state |= mask;
 347                 put_fs_word(state, &vtstat->v_state);
 348                 return 0;
 349         }
 350 
 351         /*
 352          * Returns the first available (non-opened) console.
 353          */
 354         case VT_OPENQRY:
 355                 i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
 356                 if (i)
 357                         return i;
 358                 for (i = 1; i <= NR_CONSOLES; ++i)
 359                         if (!tty_table[i] || tty_table[i]->count == 0)
 360                                 break;
 361                 put_fs_long(i <= NR_CONSOLES ? i : -1, (unsigned long *)arg);
 362                 return 0;
 363 
 364         /*
 365          * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
 366          * with num >= 1 (switches to vt 0, our console) are not allowed, just
 367          * to preserve sanity.
 368          */
 369         case VT_ACTIVATE:
 370                 if (arg == 0 || arg > NR_CONSOLES)
 371                         return -ENXIO;
 372                 change_console(arg - 1);
 373                 return 0;
 374 
 375         /*
 376          * wait until the specified VT has been activated
 377          */
 378         case VT_WAITACTIVE:
 379                 if (arg == 0 || arg > NR_CONSOLES)
 380                         return -ENXIO;
 381                 while (fg_console != arg - 1)
 382                 {
 383                         if (vt_waitactive() < 0)
 384                                 return -EINTR;
 385                 }
 386                 return 0;
 387 
 388         /*
 389          * If a vt is under process control, the kernel will not switch to it
 390          * immediately, but postpone the operation until the process calls this
 391          * ioctl, allowing the switch to complete.
 392          *
 393          * According to the X sources this is the behavior:
 394          *      0:      pending switch-from not OK
 395          *      1:      pending switch-from OK
 396          *      2:      completed switch-to OK
 397          */
 398         case VT_RELDISP:
 399                 if (vt_cons[console].vt_mode.mode != VT_PROCESS)
 400                         return -EINVAL;
 401 
 402                 /*
 403                  * Switching-from response
 404                  */
 405                 if (vt_cons[console].vt_newvt >= 0)
 406                 {
 407                         if (arg == 0)
 408                                 /*
 409                                  * Switch disallowed, so forget we were trying
 410                                  * to do it.
 411                                  */
 412                                 vt_cons[console].vt_newvt = -1;
 413 
 414                         else
 415                         {
 416                                 /*
 417                                  * The current vt has been released, so
 418                                  * complete the switch.
 419                                  */
 420                                 int newvt = vt_cons[console].vt_newvt;
 421                                 vt_cons[console].vt_newvt = -1;
 422                                 complete_change_console(newvt);
 423                         }
 424                 }
 425 
 426                 /*
 427                  * Switched-to response
 428                  */
 429                 else
 430                 {
 431                         /*
 432                          * If it's just an ACK, ignore it
 433                          */
 434                         if (arg != VT_ACKACQ)
 435                                 return -EINVAL;
 436                 }
 437 
 438                 return 0;
 439 
 440         default:
 441                 return -EINVAL;
 442         }
 443 }

/* [previous][next][first][last][top][bottom][index][help] */