home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / drivers / char / vt.c < prev   
Encoding:
C/C++ Source or Header  |  1994-02-11  |  14.1 KB  |  592 lines

  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)
  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)
  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,
  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. }
  592.