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

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