/* * kernel/chr_drv/vt.c * * (C) 1992 obz under the linux copyright */ #include <errno.h> #include <sys/types.h> #include <sys/kd.h> #include <sys/vt.h> #include <asm/io.h> #include <asm/segment.h> #include <linux/sched.h> #include <linux/tty.h> #include <linux/timer.h> #include <linux/kernel.h> #include "vt_kern.h" /* * console (vt and kd) routines, as defined by usl svr4 manual */ struct vt_cons vt_cons[NR_CONSOLES]; extern unsigned char kleds; extern unsigned char kraw; extern unsigned char ke0; extern int sys_ioperm(unsigned long from, unsigned long num, int on); extern void set_leds(void); /* * these are the valid i/o ports we're allowed to change. they map all the * video ports */ #define GPFIRST 0x3b4 #define GPLAST 0x3df #define GPNUM (GPLAST - GPFIRST + 1) /* * turns on sound of some freq. 0 turns it off. * stolen from console.c, so i'm not sure if its the correct interpretation */ static int kiocsound(unsigned int freq) { if (freq == 0) { /* disable counter 2 */ outb(inb_p(0x61)&0xFC, 0x61); } else { /* enable counter 2 */ outb_p(inb_p(0x61)|3, 0x61); /* set command for counter 2, 2 byte write */ outb_p(0xB6, 0x43); /* select desired HZ */ outb_p(freq & 0xff, 0x42); outb((freq >> 8) & 0xff, 0x42); } return 0; } /* * all the vt ioctls affect only consoles, so we reject all other ttys. * we also have the capability to modify any console, not just the fg_console. */ int vt_ioctl(struct tty_struct *tty, int dev, int cmd, int arg) { int console = dev ? dev - 1 : fg_console; unsigned char ucval; if (!IS_A_CONSOLE(dev) || console < 0 || console >= NR_CONSOLES) return -EINVAL; switch (cmd) { case KIOCSOUND: return kiocsound((unsigned int)arg); case KDGKBTYPE: /* * this is naive. */ verify_area((void *) arg, sizeof(unsigned char)); put_fs_byte(KB_101, (unsigned char *) arg); return 0; case KDADDIO: case KDDELIO: /* * KDADDIO and KDDELIO may be able to add ports beyond what * we reject here, but to be safe... */ if (arg < GPFIRST || arg > GPLAST) return -EINVAL; return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; case KDENABIO: case KDDISABIO: return sys_ioperm(GPFIRST, GPNUM, (cmd == KDENABIO)) ? -ENXIO : 0; case KDSETMODE: /* * currently, setting the mode from KD_TEXT to KD_GRAPHICS * doesn't do a whole lot. i'm not sure if it should do any * restoration of modes or what... */ switch (arg) { case KD_GRAPHICS: break; case KD_TEXT0: case KD_TEXT1: arg = KD_TEXT; case KD_TEXT: break; default: return -EINVAL; } if (vt_cons[console].vt_mode == (unsigned char) arg) return 0; vt_cons[console].vt_mode = (unsigned char) arg; if (console != fg_console) return 0; if (arg == KD_TEXT) unblank_screen(); else { timer_active &= 1<<BLANK_TIMER; blank_screen(); } return 0; case KDGETMODE: verify_area((void *) arg, sizeof(unsigned long)); put_fs_long(vt_cons[console].vt_mode, (unsigned long *) arg); return 0; case KDMAPDISP: case KDUNMAPDISP: /* * these work like a combination of mmap and KDENABIO. * this could be easily finished. */ return -EINVAL; case KDSKBMODE: if (arg == K_RAW) { if (console == fg_console) { kraw = 1; ke0 = 0; } else { vt_cons[console].vc_kbdraw = 1; vt_cons[console].vc_kbde0 = 0; } } else if (arg == K_XLATE) { if (console == fg_console) kraw = 0; else vt_cons[console].vc_kbdraw = 0; } else return -EINVAL; flush_input(tty); return 0; case KDGKBMODE: verify_area((void *) arg, sizeof(unsigned long)); ucval = (console == fg_console) ? kraw : vt_cons[console].vc_kbdraw; put_fs_long(ucval ? K_RAW : K_XLATE, (unsigned long *) arg); return 0; case KDGETLED: verify_area((void *) arg, sizeof(unsigned char)); ucval = (console == fg_console) ? kleds : vt_cons[console].vc_kbdleds; put_fs_byte((((ucval & 1) ? LED_SCR : 0) | ((ucval & 2) ? LED_NUM : 0) | ((ucval & 4) ? LED_CAP : 0)), (unsigned char *) arg); return 0; case KDSETLED: if (arg & ~7) return -EINVAL; ucval = (((arg & LED_SCR) ? 1 : 0) | ((arg & LED_NUM) ? 2 : 0) | ((arg & LED_CAP) ? 4 : 0)); if (console == fg_console) { kleds = ucval; set_leds(); } else vt_cons[console].vc_kbdleds = ucval; return 0; default: return -EINVAL; } }