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

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