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

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