home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / drivers / char / vt.c < prev   
Encoding:
C/C++ Source or Header  |  1995-02-15  |  21.9 KB  |  904 lines

  1. /*
  2.  *  linux/drivers/char/vt.c
  3.  *
  4.  *  Copyright (C) 1992 obz under the linux copyright
  5.  *
  6.  *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
  7.  *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
  8.  */
  9.  
  10. #include <linux/types.h>
  11. #include <linux/errno.h>
  12. #include <linux/sched.h>
  13. #include <linux/tty.h>
  14. #include <linux/timer.h>
  15. #include <linux/kernel.h>
  16. #include <linux/kd.h>
  17. #include <linux/vt.h>
  18. #include <linux/string.h>
  19. #include <linux/malloc.h>
  20.  
  21. #include <asm/io.h>
  22. #include <asm/segment.h>
  23.  
  24. #include "kbd_kern.h"
  25. #include "vt_kern.h"
  26. #include "diacr.h"
  27. #include "selection.h"
  28.  
  29. extern struct tty_driver console_driver;
  30. extern int sel_cons;
  31.  
  32. #define VT_IS_IN_USE(i)    (console_driver.table[i] && console_driver.table[i]->count)
  33. #define VT_BUSY(i)    (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons)
  34.  
  35. /*
  36.  * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
  37.  * experimentation and study of X386 SYSV handling.
  38.  *
  39.  * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
  40.  * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
  41.  * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
  42.  * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
  43.  * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
  44.  * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
  45.  * to the current console is done by the main ioctl code.
  46.  */
  47.  
  48. struct vt_struct *vt_cons[MAX_NR_CONSOLES];
  49.  
  50. asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
  51.  
  52. extern int getkeycode(unsigned int scancode);
  53. extern int setkeycode(unsigned int scancode, unsigned int keycode);
  54. extern void compute_shiftstate(void);
  55. extern void change_console(unsigned int new_console);
  56. extern void complete_change_console(unsigned int new_console);
  57. extern int vt_waitactive(void);
  58. extern void do_blank_screen(int nopowersave);
  59. extern void do_unblank_screen(void);
  60.  
  61. extern unsigned int keymap_count;
  62.  
  63. /*
  64.  * routines to load custom translation table and EGA/VGA font from console.c
  65.  */
  66. extern int con_set_trans(char * table);
  67. extern int con_get_trans(char * table);
  68. extern void con_clear_unimap(struct unimapinit *ui);
  69. extern int con_set_unimap(ushort ct, struct unipair *list);
  70. extern int con_get_unimap(ushort ct, ushort *uct, struct unipair *list);
  71. extern int con_set_font(char * fontmap);
  72. extern int con_get_font(char * fontmap);
  73.  
  74. /*
  75.  * these are the valid i/o ports we're allowed to change. they map all the
  76.  * video ports
  77.  */
  78. #define GPFIRST 0x3b4
  79. #define GPLAST 0x3df
  80. #define GPNUM (GPLAST - GPFIRST + 1)
  81.  
  82. /*
  83.  * Generates sound of some count for some number of clock ticks
  84.  * [count = 1193180 / frequency]
  85.  *
  86.  * If freq is 0, will turn off sound, else will turn it on for that time.
  87.  * If msec is 0, will return immediately, else will sleep for msec time, then
  88.  * turn sound off.
  89.  *
  90.  * We use the BEEP_TIMER vector since we're using the same method to
  91.  * generate sound, and we'll overwrite any beep in progress. That may
  92.  * be something to fix later, if we like.
  93.  *
  94.  * We also return immediately, which is what was implied within the X
  95.  * comments - KDMKTONE doesn't put the process to sleep.
  96.  */
  97. static void
  98. kd_nosound(unsigned long ignored)
  99. {
  100.     /* disable counter 2 */
  101.     outb(inb_p(0x61)&0xFC, 0x61);
  102.     return;
  103. }
  104.  
  105. void
  106. kd_mksound(unsigned int count, unsigned int ticks)
  107. {
  108.     static struct timer_list sound_timer = { NULL, NULL, 0, 0, kd_nosound };
  109.  
  110.     cli();
  111.     del_timer(&sound_timer);
  112.     if (count) {
  113.         /* enable counter 2 */
  114.         outb_p(inb_p(0x61)|3, 0x61);
  115.         /* set command for counter 2, 2 byte write */
  116.         outb_p(0xB6, 0x43);
  117.         /* select desired HZ */
  118.         outb_p(count & 0xff, 0x42);
  119.         outb((count >> 8) & 0xff, 0x42);
  120.  
  121.         if (ticks) {
  122.             sound_timer.expires = ticks;
  123.             add_timer(&sound_timer);
  124.         }
  125.     } else
  126.         kd_nosound(0);
  127.     sti();
  128.     return;
  129. }
  130.  
  131. /*
  132.  * We handle the console-specific ioctl's here.  We allow the
  133.  * capability to modify any console, not just the fg_console. 
  134.  */
  135. int vt_ioctl(struct tty_struct *tty, struct file * file,
  136.          unsigned int cmd, unsigned long arg)
  137. {
  138.     int i, perm;
  139.     unsigned int console;
  140.     unsigned char ucval;
  141.     struct kbd_struct * kbd;
  142.     struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
  143.  
  144.     console = vt->vc_num;
  145.  
  146.     if (!vc_cons_allocated(console))     /* impossible? */
  147.         return -ENOIOCTLCMD;
  148.  
  149.     /*
  150.      * To have permissions to do most of the vt ioctls, we either have
  151.      * to be the owner of the tty, or super-user.
  152.      */
  153.     perm = 0;
  154.     if (current->tty == tty || suser())
  155.         perm = 1;
  156.  
  157.     kbd = kbd_table + console;
  158.     switch (cmd) {
  159.     case KIOCSOUND:
  160.         if (!perm)
  161.             return -EPERM;
  162.         kd_mksound((unsigned int)arg, 0);
  163.         return 0;
  164.  
  165.     case KDMKTONE:
  166.         if (!perm)
  167.             return -EPERM;
  168.     {
  169.         unsigned int ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
  170.  
  171.         /*
  172.          * Generate the tone for the appropriate number of ticks.
  173.          * If the time is zero, turn off sound ourselves.
  174.          */
  175.         kd_mksound(arg & 0xffff, ticks);
  176.         if (ticks == 0)
  177.             kd_nosound(0);
  178.         return 0;
  179.     }
  180.  
  181.     case KDGKBTYPE:
  182.         /*
  183.          * this is naive.
  184.          */
  185.         i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
  186.         if (!i)
  187.             put_fs_byte(KB_101, (char *) arg);
  188.         return i;
  189.  
  190.     case KDADDIO:
  191.     case KDDELIO:
  192.         /*
  193.          * KDADDIO and KDDELIO may be able to add ports beyond what
  194.          * we reject here, but to be safe...
  195.          */
  196.         if (arg < GPFIRST || arg > GPLAST)
  197.             return -EINVAL;
  198.         return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
  199.  
  200.     case KDENABIO:
  201.     case KDDISABIO:
  202.         return sys_ioperm(GPFIRST, GPNUM,
  203.                   (cmd == KDENABIO)) ? -ENXIO : 0;
  204.  
  205.     case KDSETMODE:
  206.         /*
  207.          * currently, setting the mode from KD_TEXT to KD_GRAPHICS
  208.          * doesn't do a whole lot. i'm not sure if it should do any
  209.          * restoration of modes or what...
  210.          */
  211.         if (!perm)
  212.             return -EPERM;
  213.         switch (arg) {
  214.         case KD_GRAPHICS:
  215.             break;
  216.         case KD_TEXT0:
  217.         case KD_TEXT1:
  218.             arg = KD_TEXT;
  219.         case KD_TEXT:
  220.             break;
  221.         default:
  222.             return -EINVAL;
  223.         }
  224.         if (vt_cons[console]->vc_mode == (unsigned char) arg)
  225.             return 0;
  226.         vt_cons[console]->vc_mode = (unsigned char) arg;
  227.         if (console != fg_console)
  228.             return 0;
  229.         /*
  230.          * explicitly blank/unblank the screen if switching modes
  231.          */
  232.         if (arg == KD_TEXT)
  233.             do_unblank_screen();
  234.         else
  235.             do_blank_screen(1);
  236.         return 0;
  237.  
  238.     case KDGETMODE:
  239.         i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
  240.         if (!i)
  241.             put_fs_long(vt_cons[console]->vc_mode, (unsigned long *) arg);
  242.         return i;
  243.  
  244.     case KDMAPDISP:
  245.     case KDUNMAPDISP:
  246.         /*
  247.          * these work like a combination of mmap and KDENABIO.
  248.          * this could be easily finished.
  249.          */
  250.         return -EINVAL;
  251.  
  252.     case KDSKBMODE:
  253.         if (!perm)
  254.             return -EPERM;
  255.         switch(arg) {
  256.           case K_RAW:
  257.             kbd->kbdmode = VC_RAW;
  258.             break;
  259.           case K_MEDIUMRAW:
  260.             kbd->kbdmode = VC_MEDIUMRAW;
  261.             break;
  262.           case K_XLATE:
  263.             kbd->kbdmode = VC_XLATE;
  264.             compute_shiftstate();
  265.             break;
  266.           case K_UNICODE:
  267.             kbd->kbdmode = VC_UNICODE;
  268.             compute_shiftstate();
  269.             break;
  270.           default:
  271.             return -EINVAL;
  272.         }
  273.         if (tty->ldisc.flush_buffer)
  274.             tty->ldisc.flush_buffer(tty);
  275.         return 0;
  276.  
  277.     case KDGKBMODE:
  278.         i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
  279.         if (!i) {
  280.             ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
  281.                  (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
  282.                  (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
  283.                  K_XLATE);
  284.             put_fs_long(ucval, (unsigned long *) arg);
  285.         }
  286.         return i;
  287.  
  288.     /* this could be folded into KDSKBMODE, but for compatibility
  289.        reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
  290.     case KDSKBMETA:
  291.         switch(arg) {
  292.           case K_METABIT:
  293.             clr_vc_kbd_mode(kbd, VC_META);
  294.             break;
  295.           case K_ESCPREFIX:
  296.             set_vc_kbd_mode(kbd, VC_META);
  297.             break;
  298.           default:
  299.             return -EINVAL;
  300.         }
  301.         return 0;
  302.  
  303.     case KDGKBMETA:
  304.         i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
  305.         if (!i) {
  306.             ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX :
  307.                  K_METABIT);
  308.             put_fs_long(ucval, (unsigned long *) arg);
  309.         }
  310.         return i;
  311.  
  312.     case KDGETKEYCODE:
  313.     {
  314.         struct kbkeycode * const a = (struct kbkeycode *)arg;
  315.         unsigned int sc;
  316.         int kc;
  317.  
  318.         i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbkeycode));
  319.         if (i)
  320.             return i;
  321.         sc = get_fs_long((int *) &a->scancode);
  322.         kc = getkeycode(sc);
  323.         if (kc < 0)
  324.             return kc;
  325.         put_fs_long(kc, (int *) &a->keycode);
  326.         return 0;
  327.     }
  328.  
  329.     case KDSETKEYCODE:
  330.     {
  331.         struct kbkeycode * const a = (struct kbkeycode *)arg;
  332.         unsigned int sc, kc;
  333.  
  334.         if (!perm)
  335.             return -EPERM;
  336.         i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbkeycode));
  337.         if (i)
  338.             return i;
  339.         sc = get_fs_long((int *) &a->scancode);
  340.         kc = get_fs_long((int *) &a->keycode);
  341.         return setkeycode(sc, kc);
  342.     }
  343.  
  344.     case KDGKBENT:
  345.     {
  346.         struct kbentry * const a = (struct kbentry *)arg;
  347.         ushort *key_map, val;
  348.         u_char s;
  349.  
  350.         i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
  351.         if (i)
  352.             return i;
  353.         if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
  354.             return -EINVAL;
  355.         if ((s = get_fs_byte((char *) &a->kb_table)) >= MAX_NR_KEYMAPS)
  356.             return -EINVAL;
  357.         key_map = key_maps[s];
  358.         if (key_map) {
  359.             val = U(key_map[i]);
  360.             if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
  361.             val = K_HOLE;
  362.         } else
  363.             val = (i ? K_HOLE : K_NOSUCHMAP);
  364.         put_fs_word(val, (short *) &a->kb_value);
  365.         return 0;
  366.     }
  367.  
  368.     case KDSKBENT:
  369.     {
  370.         const struct kbentry * a = (struct kbentry *)arg;
  371.         ushort *key_map;
  372.         u_char s;
  373.         u_short v, ov;
  374.  
  375.         if (!perm)
  376.             return -EPERM;
  377.         i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbentry));
  378.         if (i)
  379.             return i;
  380.         if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
  381.             return -EINVAL;
  382.         if ((s = get_fs_byte((char *) &a->kb_table)) >= MAX_NR_KEYMAPS)
  383.             return -EINVAL;
  384.         v = get_fs_word(&a->kb_value);
  385.         if (!i && v == K_NOSUCHMAP) {
  386.             /* disallocate map */
  387.             key_map = key_maps[s];
  388.             if (s && key_map) {
  389.                 key_maps[s] = 0;
  390.                 if (key_map[0] == U(K_ALLOCATED)) {
  391.                 kfree_s(key_map, sizeof(plain_map));
  392.                 keymap_count--;
  393.                 }
  394.             }
  395.             return 0;
  396.         }
  397.  
  398.         if (KTYP(v) < NR_TYPES) {
  399.             if (KVAL(v) > max_vals[KTYP(v)])
  400.             return -EINVAL;
  401.         } else
  402.             if (kbd->kbdmode != VC_UNICODE)
  403.             return -EINVAL;
  404.  
  405.         /* assignment to entry 0 only tests validity of args */
  406.         if (!i)
  407.             return 0;
  408.  
  409.         if (!(key_map = key_maps[s])) {
  410.             int j;
  411.  
  412.             if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && !suser())
  413.                 return -EPERM;
  414.  
  415.             key_map = (ushort *) kmalloc(sizeof(plain_map),
  416.                              GFP_KERNEL);
  417.             if (!key_map)
  418.                 return -ENOMEM;
  419.             key_maps[s] = key_map;
  420.             key_map[0] = U(K_ALLOCATED);
  421.             for (j = 1; j < NR_KEYS; j++)
  422.                 key_map[j] = U(K_HOLE);
  423.             keymap_count++;
  424.         }
  425.         ov = U(key_map[i]);
  426.         if (v == ov)
  427.             return 0;    /* nothing to do */
  428.         /*
  429.          * Only the Superuser can set or unset the Secure
  430.          * Attention Key.
  431.          */
  432.         if (((ov == K_SAK) || (v == K_SAK)) && !suser())
  433.             return -EPERM;
  434.         key_map[i] = U(v);
  435.         if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
  436.             compute_shiftstate();
  437.         return 0;
  438.     }
  439.  
  440.     case KDGKBSENT:
  441.     {
  442.         struct kbsentry *a = (struct kbsentry *)arg;
  443.         char *p;
  444.         u_char *q;
  445.         int sz;
  446.  
  447.         i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry));
  448.         if (i)
  449.             return i;
  450.         if ((i = get_fs_byte(&a->kb_func)) >= MAX_NR_FUNC || i < 0)
  451.             return -EINVAL;
  452.         sz = sizeof(a->kb_string) - 1; /* sz should have been
  453.                           a struct member */
  454.         q = a->kb_string;
  455.         p = func_table[i];
  456.         if(p)
  457.             for ( ; *p && sz; p++, sz--)
  458.                 put_fs_byte(*p, q++);
  459.         put_fs_byte(0, q);
  460.         return ((p && *p) ? -EOVERFLOW : 0);
  461.     }
  462.  
  463.     case KDSKBSENT:
  464.     {
  465.         struct kbsentry * const a = (struct kbsentry *)arg;
  466.         int delta;
  467.         char *first_free, *fj, *fnw;
  468.         int j, k, sz;
  469.         u_char *p;
  470.         char *q;
  471.  
  472.         if (!perm)
  473.             return -EPERM;
  474.         i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbsentry));
  475.         if (i)
  476.             return i;
  477.         if ((i = get_fs_byte(&a->kb_func)) >= MAX_NR_FUNC)
  478.             return -EINVAL;
  479.         q = func_table[i];
  480.  
  481.         first_free = funcbufptr + (funcbufsize - funcbufleft);
  482.         for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) ;
  483.         if (j < MAX_NR_FUNC)
  484.             fj = func_table[j];
  485.         else
  486.             fj = first_free;
  487.  
  488.         delta = (q ? -strlen(q) : 1);
  489.         sz = sizeof(a->kb_string);     /* sz should have been
  490.                            a struct member */
  491.         for (p = a->kb_string; get_fs_byte(p) && sz; p++,sz--)
  492.             delta++;
  493.         if (!sz)
  494.             return -EOVERFLOW;
  495.         if (delta <= funcbufleft) {     /* it fits in current buf */
  496.             if (j < MAX_NR_FUNC) {
  497.             memmove(fj + delta, fj, first_free - fj);
  498.             for (k = j; k < MAX_NR_FUNC; k++)
  499.                 if (func_table[k])
  500.                 func_table[k] += delta;
  501.             }
  502.             if (!q)
  503.               func_table[i] = fj;
  504.             funcbufleft -= delta;
  505.         } else {            /* allocate a larger buffer */
  506.             sz = 256;
  507.             while (sz < funcbufsize - funcbufleft + delta)
  508.               sz <<= 1;
  509.             fnw = (char *) kmalloc(sz, GFP_KERNEL);
  510.             if(!fnw)
  511.               return -ENOMEM;
  512.  
  513.             if (!q)
  514.               func_table[i] = fj;
  515.             if (fj > funcbufptr)
  516.             memmove(fnw, funcbufptr, fj - funcbufptr);
  517.             for (k = 0; k < j; k++)
  518.               if (func_table[k])
  519.             func_table[k] = fnw + (func_table[k] - funcbufptr);
  520.  
  521.             if (first_free > fj) {
  522.             memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
  523.             for (k = j; k < MAX_NR_FUNC; k++)
  524.               if (func_table[k])
  525.                 func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
  526.             }
  527.             if (funcbufptr != func_buf)
  528.               kfree_s(funcbufptr, funcbufsize);
  529.             funcbufptr = fnw;
  530.             funcbufleft = funcbufleft - delta + sz - funcbufsize;
  531.             funcbufsize = sz;
  532.         }
  533.         for (p = a->kb_string, q = func_table[i]; ; p++, q++)
  534.             if (!(*q = get_fs_byte(p)))
  535.                 break;
  536.         return 0;
  537.     }
  538.  
  539.     case KDGKBDIACR:
  540.     {
  541.         struct kbdiacrs *a = (struct kbdiacrs *)arg;
  542.  
  543.         i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs));
  544.         if (i)
  545.             return i;
  546.         put_fs_long(accent_table_size, &a->kb_cnt);
  547.         memcpy_tofs(a->kbdiacr, accent_table,
  548.                 accent_table_size*sizeof(struct kbdiacr));
  549.         return 0;
  550.     }
  551.  
  552.     case KDSKBDIACR:
  553.     {
  554.         struct kbdiacrs *a = (struct kbdiacrs *)arg;
  555.         unsigned int ct;
  556.  
  557.         if (!perm)
  558.             return -EPERM;
  559.         i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs));
  560.         if (i)
  561.             return i;
  562.         ct = get_fs_long(&a->kb_cnt);
  563.         if (ct >= MAX_DIACR)
  564.             return -EINVAL;
  565.         accent_table_size = ct;
  566.         memcpy_fromfs(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr));
  567.         return 0;
  568.     }
  569.  
  570.     /* the ioctls below read/set the flags usually shown in the leds */
  571.     /* don't use them - they will go away without warning */
  572.     case KDGKBLED:
  573.         i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
  574.         if (i)
  575.             return i;
  576.         put_fs_byte(kbd->ledflagstate |
  577.                 (kbd->default_ledflagstate << 4), (char *) arg);
  578.         return 0;
  579.  
  580.     case KDSKBLED:
  581.         if (!perm)
  582.             return -EPERM;
  583.         if (arg & ~0x77)
  584.             return -EINVAL;
  585.         kbd->ledflagstate = (arg & 7);
  586.         kbd->default_ledflagstate = ((arg >> 4) & 7);
  587.         set_leds();
  588.         return 0;
  589.  
  590.     /* the ioctls below only set the lights, not the functions */
  591.     /* for those, see KDGKBLED and KDSKBLED above */
  592.     case KDGETLED:
  593.         i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
  594.         if (i)
  595.             return i;
  596.         put_fs_byte(getledstate(), (char *) arg);
  597.         return 0;
  598.  
  599.     case KDSETLED:
  600.         if (!perm)
  601.           return -EPERM;
  602.         setledstate(kbd, arg);
  603.         return 0;
  604.  
  605.     /*
  606.      * A process can indicate its willingness to accept signals
  607.      * generated by pressing an appropriate key combination.
  608.      * Thus, one can have a daemon that e.g. spawns a new console
  609.      * upon a keypress and then changes to it.
  610.      * Probably init should be changed to do this (and have a
  611.      * field ks (`keyboard signal') in inittab describing the
  612.      * desired action), so that the number of background daemons
  613.      * does not increase.
  614.      */
  615.     case KDSIGACCEPT:
  616.     {
  617.         extern int spawnpid, spawnsig;
  618.         if (!perm)
  619.           return -EPERM;
  620.         if (arg < 1 || arg > NSIG || arg == SIGKILL)
  621.           return -EINVAL;
  622.         spawnpid = current->pid;
  623.         spawnsig = arg;
  624.         return 0;
  625.     }
  626.  
  627.     case VT_SETMODE:
  628.     {
  629.         struct vt_mode *vtmode = (struct vt_mode *)arg;
  630.         char mode;
  631.  
  632.         if (!perm)
  633.             return -EPERM;
  634.         i = verify_area(VERIFY_WRITE, (void *)vtmode, sizeof(struct vt_mode));
  635.         if (i)
  636.             return i;
  637.         mode = get_fs_byte(&vtmode->mode);
  638.         if (mode != VT_AUTO && mode != VT_PROCESS)
  639.             return -EINVAL;
  640.         vt_cons[console]->vt_mode.mode = mode;
  641.         vt_cons[console]->vt_mode.waitv = get_fs_byte(&vtmode->waitv);
  642.         vt_cons[console]->vt_mode.relsig = get_fs_word(&vtmode->relsig);
  643.         vt_cons[console]->vt_mode.acqsig = get_fs_word(&vtmode->acqsig);
  644.         /* the frsig is ignored, so we set it to 0 */
  645.         vt_cons[console]->vt_mode.frsig = 0;
  646.         vt_cons[console]->vt_pid = current->pid;
  647.         vt_cons[console]->vt_newvt = 0;
  648.         return 0;
  649.     }
  650.  
  651.     case VT_GETMODE:
  652.     {
  653.         struct vt_mode *vtmode = (struct vt_mode *)arg;
  654.  
  655.         i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct vt_mode));
  656.         if (i)
  657.             return i;
  658.         put_fs_byte(vt_cons[console]->vt_mode.mode, &vtmode->mode);
  659.         put_fs_byte(vt_cons[console]->vt_mode.waitv, &vtmode->waitv);
  660.         put_fs_word(vt_cons[console]->vt_mode.relsig, &vtmode->relsig);
  661.         put_fs_word(vt_cons[console]->vt_mode.acqsig, &vtmode->acqsig);
  662.         put_fs_word(vt_cons[console]->vt_mode.frsig, &vtmode->frsig);
  663.         return 0;
  664.     }
  665.  
  666.     /*
  667.      * Returns global vt state. Note that VT 0 is always open, since
  668.      * it's an alias for the current VT, and people can't use it here.
  669.      * We cannot return state for more than 16 VTs, since v_state is short.
  670.      */
  671.     case VT_GETSTATE:
  672.     {
  673.         struct vt_stat *vtstat = (struct vt_stat *)arg;
  674.         unsigned short state, mask;
  675.  
  676.         i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat));
  677.         if (i)
  678.             return i;
  679.         put_fs_word(fg_console + 1, &vtstat->v_active);
  680.         state = 1;    /* /dev/tty0 is always open */
  681.         for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
  682.             if (VT_IS_IN_USE(i))
  683.                 state |= mask;
  684.         put_fs_word(state, &vtstat->v_state);
  685.         return 0;
  686.     }
  687.  
  688.     /*
  689.      * Returns the first available (non-opened) console.
  690.      */
  691.     case VT_OPENQRY:
  692.         i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
  693.         if (i)
  694.             return i;
  695.         for (i = 0; i < MAX_NR_CONSOLES; ++i)
  696.             if (! VT_IS_IN_USE(i))
  697.                 break;
  698.         put_fs_long(i < MAX_NR_CONSOLES ? (i+1) : -1,
  699.                 (unsigned long *)arg);
  700.         return 0;
  701.  
  702.     /*
  703.      * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
  704.      * with num >= 1 (switches to vt 0, our console, are not allowed, just
  705.      * to preserve sanity).
  706.      */
  707.     case VT_ACTIVATE:
  708.         if (!perm)
  709.             return -EPERM;
  710.         if (arg == 0 || arg > MAX_NR_CONSOLES)
  711.             return -ENXIO;
  712.         arg--;
  713.         i = vc_allocate(arg);
  714.         if (i)
  715.             return i;
  716.         change_console(arg);
  717.         return 0;
  718.  
  719.     /*
  720.      * wait until the specified VT has been activated
  721.      */
  722.     case VT_WAITACTIVE:
  723.         if (!perm)
  724.             return -EPERM;
  725.         if (arg == 0 || arg > MAX_NR_CONSOLES)
  726.             return -ENXIO;
  727.         arg--;
  728.         while (fg_console != arg)
  729.         {
  730.             if (vt_waitactive() < 0)
  731.                 return -EINTR;
  732.         }
  733.         return 0;
  734.  
  735.     /*
  736.      * If a vt is under process control, the kernel will not switch to it
  737.      * immediately, but postpone the operation until the process calls this
  738.      * ioctl, allowing the switch to complete.
  739.      *
  740.      * According to the X sources this is the behavior:
  741.      *    0:    pending switch-from not OK
  742.      *    1:    pending switch-from OK
  743.      *    2:    completed switch-to OK
  744.      */
  745.     case VT_RELDISP:
  746.         if (!perm)
  747.             return -EPERM;
  748.         if (vt_cons[console]->vt_mode.mode != VT_PROCESS)
  749.             return -EINVAL;
  750.  
  751.         /*
  752.          * Switching-from response
  753.          */
  754.         if (vt_cons[console]->vt_newvt >= 0)
  755.         {
  756.             if (arg == 0)
  757.                 /*
  758.                  * Switch disallowed, so forget we were trying
  759.                  * to do it.
  760.                  */
  761.                 vt_cons[console]->vt_newvt = -1;
  762.  
  763.             else
  764.             {
  765.                 /*
  766.                  * The current vt has been released, so
  767.                  * complete the switch.
  768.                  */
  769.                 int newvt = vt_cons[console]->vt_newvt;
  770.                 vt_cons[console]->vt_newvt = -1;
  771.                 i = vc_allocate(newvt);
  772.                 if (i)
  773.                     return i;
  774.                 complete_change_console(newvt);
  775.             }
  776.         }
  777.  
  778.         /*
  779.          * Switched-to response
  780.          */
  781.         else
  782.         {
  783.             /*
  784.              * If it's just an ACK, ignore it
  785.              */
  786.             if (arg != VT_ACKACQ)
  787.                 return -EINVAL;
  788.         }
  789.  
  790.         return 0;
  791.  
  792.      /*
  793.       * Disallocate memory associated to VT (but leave VT1)
  794.       */
  795.      case VT_DISALLOCATE:
  796.         if (arg > MAX_NR_CONSOLES)
  797.             return -ENXIO;
  798.         if (arg == 0) {
  799.             /* disallocate all unused consoles, but leave 0 */
  800.             for (i=1; i<MAX_NR_CONSOLES; i++)
  801.               if (! VT_BUSY(i))
  802.             vc_disallocate(i);
  803.         } else {
  804.             /* disallocate a single console, if possible */
  805.             arg--;
  806.             if (VT_BUSY(arg))
  807.               return -EBUSY;
  808.             if (arg)                  /* leave 0 */
  809.               vc_disallocate(arg);
  810.         }
  811.         return 0;
  812.  
  813.     case VT_RESIZE:
  814.     {
  815.         struct vt_sizes *vtsizes = (struct vt_sizes *) arg;
  816.         ushort ll,cc;
  817.         if (!perm)
  818.             return -EPERM;
  819.         i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes));
  820.         if (i)
  821.             return i;
  822.         ll = get_fs_word(&vtsizes->v_rows);
  823.         cc = get_fs_word(&vtsizes->v_cols);
  824.         return vc_resize(ll, cc);
  825.     }
  826.  
  827.     case PIO_FONT:
  828.         if (!perm)
  829.             return -EPERM;
  830.         if (vt_cons[fg_console]->vc_mode != KD_TEXT)
  831.             return -EINVAL;
  832.         return con_set_font((char *)arg);
  833.         /* con_set_font() defined in console.c */
  834.  
  835.     case GIO_FONT:
  836.         if (vt_cons[fg_console]->vc_mode != KD_TEXT)
  837.             return -EINVAL;
  838.         return con_get_font((char *)arg);
  839.         /* con_get_font() defined in console.c */
  840.  
  841.     case PIO_SCRNMAP:
  842.         if (!perm)
  843.             return -EPERM;
  844.         return con_set_trans((char *)arg);
  845.  
  846.     case GIO_SCRNMAP:
  847.         return con_get_trans((char *)arg);
  848.  
  849.     case PIO_UNIMAPCLR:
  850.           { struct unimapinit ui;
  851.         if (!perm)
  852.             return -EPERM;
  853.         i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapinit));
  854.         if (i)
  855.           return i;
  856.         memcpy_fromfs(&ui, (void *)arg, sizeof(struct unimapinit));
  857.         con_clear_unimap(&ui);
  858.         return 0;
  859.           }
  860.  
  861.     case PIO_UNIMAP:
  862.           { struct unimapdesc *ud;
  863.         u_short ct;
  864.         struct unipair *list;
  865.  
  866.         if (!perm)
  867.             return -EPERM;
  868.         i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapdesc));
  869.         if (i == 0) {
  870.             ud = (struct unimapdesc *) arg;
  871.             ct = get_fs_word(&ud->entry_ct);
  872.             list = (struct unipair *) get_fs_long(&ud->entries);
  873.             i = verify_area(VERIFY_READ, (void *) list,
  874.                     ct*sizeof(struct unipair));
  875.         }
  876.         if (i)
  877.           return i;
  878.         return con_set_unimap(ct, list);
  879.           }
  880.  
  881.     case GIO_UNIMAP:
  882.           { struct unimapdesc *ud;
  883.         u_short ct;
  884.         struct unipair *list;
  885.  
  886.         i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct unimapdesc));
  887.         if (i == 0) {
  888.             ud = (struct unimapdesc *) arg;
  889.             ct = get_fs_word(&ud->entry_ct);
  890.             list = (struct unipair *) get_fs_long(&ud->entries);
  891.             if (ct)
  892.               i = verify_area(VERIFY_WRITE, (void *) list,
  893.                       ct*sizeof(struct unipair));
  894.         }
  895.         if (i)
  896.           return i;
  897.         return con_get_unimap(ct, &(ud->entry_ct), list);
  898.           }
  899.  
  900.     default:
  901.         return -ENOIOCTLCMD;
  902.     }
  903. }
  904.