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

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