/*
       *  linux/drivers/char/vt.c
       *
       *  Copyright (C) 1992 obz under the linux copyright
       *
       *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
       *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
       *  Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
       *  Some code moved for less code duplication - Andi Kleen - Mar 1997
       */
      
      #include <linux/config.h>
      #include <linux/types.h>
      #include <linux/errno.h>
      #include <linux/sched.h>
      #include <linux/tty.h>
      #include <linux/timer.h>
      #include <linux/kernel.h>
      #include <linux/kd.h>
      #include <linux/vt.h>
      #include <linux/string.h>
      #include <linux/malloc.h>
      #include <linux/major.h>
      #include <linux/fs.h>
      #include <linux/console.h>
      
      #include <asm/io.h>
      #include <asm/uaccess.h>
      
      #if defined(__mc68000__) || defined(CONFIG_APUS)
      #include <asm/machdep.h>
      #endif
      
      #include <linux/kbd_kern.h>
      #include <linux/vt_kern.h>
      #include <linux/kbd_diacr.h>
      #include <linux/selection.h>
      
      #ifdef CONFIG_FB_COMPAT_XPMAC
      #include <asm/vc_ioctl.h>
      #endif /* CONFIG_FB_COMPAT_XPMAC */
      
      char vt_dont_switch;
      extern struct tty_driver console_driver;
      
      #define VT_IS_IN_USE(i)	(console_driver.table[i] && console_driver.table[i]->count)
      #define VT_BUSY(i)	(VT_IS_IN_USE(i) || i == fg_console || i == sel_cons)
      
      /*
       * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
       * experimentation and study of X386 SYSV handling.
       *
       * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
       * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
       * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
       * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
       * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
       * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
       * to the current console is done by the main ioctl code.
       */
      
      struct vt_struct *vt_cons[MAX_NR_CONSOLES];
      
      /* Keyboard type: Default is KB_101, but can be set by machine
       * specific code.
       */
      unsigned char keyboard_type = KB_101;
      
      #if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__)
      asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
      #endif
      
      unsigned int video_font_height;
      unsigned int default_font_height;
      unsigned int video_scan_lines;
      
      /*
       * 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)
      
      /*
       * Generates sound of some frequency for some number of clock ticks
       *
       * If freq is 0, will turn off sound, else will turn it on for that time.
       * If msec is 0, will return immediately, else will sleep for msec time, then
       * turn sound off.
       *
       * We also return immediately, which is what was implied within the X
       * comments - KDMKTONE doesn't put the process to sleep.
       */
      
      #if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \
          || (defined(__mips__) && !defined(CONFIG_SGI_IP22)) \
          || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE))
      
      static void
 101  kd_nosound(unsigned long ignored)
      {
      	/* disable counter 2 */
      	outb(inb_p(0x61)&0xFC, 0x61);
 105  	return;
      }
      
      void
 109  _kd_mksound(unsigned int hz, unsigned int ticks)
      {
      	static struct timer_list sound_timer = { function: kd_nosound };
      	unsigned int count = 0;
      	unsigned long flags;
      
 115  	if (hz > 20 && hz < 32767)
      		count = 1193180 / hz;
      	
      	save_flags(flags);
      	cli();
      	del_timer(&sound_timer);
 121  	if (count) {
      		/* 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(count & 0xff, 0x42);
      		outb((count >> 8) & 0xff, 0x42);
      
 130  		if (ticks) {
      			sound_timer.expires = jiffies+ticks;
      			add_timer(&sound_timer);
      		}
 134  	} else
      		kd_nosound(0);
      	restore_flags(flags);
 137  	return;
      }
      
      #else
      
      void
      _kd_mksound(unsigned int hz, unsigned int ticks)
      {
      }
      
      #endif
      
      void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound;
      
      
      #define i (tmp.kb_index)
      #define s (tmp.kb_table)
      #define v (tmp.kb_value)
      static inline int
 156  do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kbd)
      {
      	struct kbentry tmp;
      	ushort *key_map, val, ov;
      
 161  	if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
 162  		return -EFAULT;
 163  	if (i >= NR_KEYS || s >= MAX_NR_KEYMAPS)
 164  		return -EINVAL;	
      
 166  	switch (cmd) {
 167  	case KDGKBENT:
      		key_map = key_maps[s];
 169  		if (key_map) {
      		    val = U(key_map[i]);
 171  		    if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
      			val = K_HOLE;
 173  		} else
      		    val = (i ? K_HOLE : K_NOSUCHMAP);
 175  		return put_user(val, &user_kbe->kb_value);
 176  	case KDSKBENT:
 177  		if (!perm)
 178  			return -EPERM;
 179  		if (!i && v == K_NOSUCHMAP) {
      			/* disallocate map */
      			key_map = key_maps[s];
 182  			if (s && key_map) {
      			    key_maps[s] = 0;
 184  			    if (key_map[0] == U(K_ALLOCATED)) {
      					kfree(key_map);
      					keymap_count--;
      			    }
      			}
 189  			break;
      		}
      
 192  		if (KTYP(v) < NR_TYPES) {
 193  		    if (KVAL(v) > max_vals[KTYP(v)])
 194  				return -EINVAL;
      		} else
 196  		    if (kbd->kbdmode != VC_UNICODE)
 197  				return -EINVAL;
      
      		/* ++Geert: non-PC keyboards may generate keycode zero */
      #if !defined(__mc68000__) && !defined(__powerpc__)
      		/* assignment to entry 0 only tests validity of args */
 202  		if (!i)
 203  			break;
      #endif
      
 206  		if (!(key_map = key_maps[s])) {
      			int j;
      
      			if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
 210  			    !capable(CAP_SYS_RESOURCE))
 211  				return -EPERM;
      
      			key_map = (ushort *) kmalloc(sizeof(plain_map),
      						     GFP_KERNEL);
 215  			if (!key_map)
 216  				return -ENOMEM;
      			key_maps[s] = key_map;
      			key_map[0] = U(K_ALLOCATED);
 219  			for (j = 1; j < NR_KEYS; j++)
      				key_map[j] = U(K_HOLE);
      			keymap_count++;
      		}
      		ov = U(key_map[i]);
 224  		if (v == ov)
 225  			break;	/* nothing to do */
      		/*
      		 * Attention Key.
      		 */
 229  		if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
 230  			return -EPERM;
      		key_map[i] = U(v);
 232  		if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
      			compute_shiftstate();
 234  		break;
      	}
 236  	return 0;
      }
      #undef i
      #undef s
      #undef v
      
      static inline int 
 243  do_kbkeycode_ioctl(int cmd, struct kbkeycode *user_kbkc, int perm)
      {
      	struct kbkeycode tmp;
      	int kc = 0;
      
 248  	if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
 249  		return -EFAULT;
 250  	switch (cmd) {
 251  	case KDGETKEYCODE:
      		kc = getkeycode(tmp.scancode);
 253  		if (kc >= 0)
      			kc = put_user(kc, &user_kbkc->keycode);
 255  		break;
 256  	case KDSETKEYCODE:
 257  		if (!perm)
 258  			return -EPERM;
      		kc = setkeycode(tmp.scancode, tmp.keycode);
 260  		break;
      	}
 262  	return kc;
      }
      
      static inline int
 266  do_kdgkb_ioctl(int cmd, struct kbsentry *user_kdgkb, int perm)
      {
      	struct kbsentry tmp;
      	char *p;
      	u_char *q;
      	int sz;
      	int delta;
      	char *first_free, *fj, *fnw;
      	int i, j, k;
      
      	/* we mostly copy too much here (512bytes), but who cares ;) */
 277  	if (copy_from_user(&tmp, user_kdgkb, sizeof(struct kbsentry)))
 278  		return -EFAULT;
      	tmp.kb_string[sizeof(tmp.kb_string)-1] = '\0';
 280  	if (tmp.kb_func >= MAX_NR_FUNC)
 281  		return -EINVAL;
      	i = tmp.kb_func;
      
 284  	switch (cmd) {
 285  	case KDGKBSENT:
      		sz = sizeof(tmp.kb_string) - 1; /* sz should have been
      						  a struct member */
      		q = user_kdgkb->kb_string;
      		p = func_table[i];
 290  		if(p)
 291  			for ( ; *p && sz; p++, sz--)
      				put_user(*p, q++);
      		put_user('\0', q);
 294  		return ((p && *p) ? -EOVERFLOW : 0);
 295  	case KDSKBSENT:
 296  		if (!perm)
 297  			return -EPERM;
      
      		q = func_table[i];
      		first_free = funcbufptr + (funcbufsize - funcbufleft);
 301  		for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 
      			;
 303  		if (j < MAX_NR_FUNC)
      			fj = func_table[j];
 305  		else
      			fj = first_free;
      
      		delta = (q ? -strlen(q) : 1) + strlen(tmp.kb_string);
 309  		if (delta <= funcbufleft) { 	/* it fits in current buf */
 310  		    if (j < MAX_NR_FUNC) {
      			memmove(fj + delta, fj, first_free - fj);
 312  			for (k = j; k < MAX_NR_FUNC; k++)
 313  			    if (func_table[k])
      				func_table[k] += delta;
      		    }
 316  		    if (!q)
      		      func_table[i] = fj;
      		    funcbufleft -= delta;
 319  		} else {			/* allocate a larger buffer */
      		    sz = 256;
 321  		    while (sz < funcbufsize - funcbufleft + delta)
      		      sz <<= 1;
      		    fnw = (char *) kmalloc(sz, GFP_KERNEL);
 324  		    if(!fnw)
 325  		      return -ENOMEM;
      
 327  		    if (!q)
      		      func_table[i] = fj;
 329  		    if (fj > funcbufptr)
      			memmove(fnw, funcbufptr, fj - funcbufptr);
 331  		    for (k = 0; k < j; k++)
 332  		      if (func_table[k])
      			func_table[k] = fnw + (func_table[k] - funcbufptr);
      
 335  		    if (first_free > fj) {
      			memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
 337  			for (k = j; k < MAX_NR_FUNC; k++)
 338  			  if (func_table[k])
      			    func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
      		    }
 341  		    if (funcbufptr != func_buf)
      		      kfree(funcbufptr);
      		    funcbufptr = fnw;
      		    funcbufleft = funcbufleft - delta + sz - funcbufsize;
      		    funcbufsize = sz;
      		}
      		strcpy(func_table[i], tmp.kb_string);
 348  		break;
      	}
 350  	return 0;
      }
      
      static inline int 
 354  do_fontx_ioctl(int cmd, struct consolefontdesc *user_cfd, int perm)
      {
      	struct consolefontdesc cfdarg;
      	struct console_font_op op;
      	int i;
      
 360  	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) 
 361  		return -EFAULT;
       	
 363  	switch (cmd) {
 364  	case PIO_FONTX:
 365  		if (!perm)
 366  			return -EPERM;
      		op.op = KD_FONT_OP_SET;
      		op.flags = KD_FONT_FLAG_OLD;
      		op.width = 8;
      		op.height = cfdarg.charheight;
      		op.charcount = cfdarg.charcount;
      		op.data = cfdarg.chardata;
 373  		return con_font_op(fg_console, &op);
 374  	case GIO_FONTX: {
      		op.op = KD_FONT_OP_GET;
      		op.flags = KD_FONT_FLAG_OLD;
      		op.width = 8;
      		op.height = cfdarg.charheight;
      		op.charcount = cfdarg.charcount;
      		op.data = cfdarg.chardata;
      		i = con_font_op(fg_console, &op);
 382  		if (i)
 383  			return i;
      		cfdarg.charheight = op.height;
      		cfdarg.charcount = op.charcount;
 386  		if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
 387  			return -EFAULT;
 388  		return 0;
      		}
      	}
 391  	return -EINVAL;
      }
      
      static inline int 
 395  do_unimap_ioctl(int cmd, struct unimapdesc *user_ud,int perm)
      {
      	struct unimapdesc tmp;
      	int i = 0; 
      
 400  	if (copy_from_user(&tmp, user_ud, sizeof tmp))
 401  		return -EFAULT;
 402  	if (tmp.entries) {
      		i = verify_area(VERIFY_WRITE, tmp.entries, 
      						tmp.entry_ct*sizeof(struct unipair));
 405  		if (i) return i;
      	}
 407  	switch (cmd) {
 408  	case PIO_UNIMAP:
 409  		if (!perm)
 410  			return -EPERM;
 411  		return con_set_unimap(fg_console, tmp.entry_ct, tmp.entries);
 412  	case GIO_UNIMAP:
 413  		return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
      	}
 415  	return 0;
      }
      
      /*
       * We handle the console-specific ioctl's here.  We allow the
       * capability to modify any console, not just the fg_console. 
       */
 422  int vt_ioctl(struct tty_struct *tty, struct file * file,
      	     unsigned int cmd, unsigned long arg)
      {
      	int i, perm;
      	unsigned int console;
      	unsigned char ucval;
      	struct kbd_struct * kbd;
      	struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
      
      	console = vt->vc_num;
      
 433  	if (!vc_cons_allocated(console)) 	/* impossible? */
 434  		return -ENOIOCTLCMD;
      
      	/*
      	 * To have permissions to do most of the vt ioctls, we either have
      	 * to be the owner of the tty, or super-user.
      	 */
      	perm = 0;
 441  	if (current->tty == tty || suser())
      		perm = 1;
       
      	kbd = kbd_table + console;
 445  	switch (cmd) {
 446  	case KIOCSOUND:
 447  		if (!perm)
 448  			return -EPERM;
 449  		if (arg)
      			arg = 1193180 / arg;
      		kd_mksound(arg, 0);
 452  		return 0;
      
 454  	case KDMKTONE:
 455  		if (!perm)
 456  			return -EPERM;
      	{
      		unsigned int ticks, count;
      		
      		/*
      		 * Generate the tone for the appropriate number of ticks.
      		 * If the time is zero, turn off sound ourselves.
      		 */
      		ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
      		count = ticks ? (arg & 0xffff) : 0;
 466  		if (count)
      			count = 1193180 / count;
      		kd_mksound(count, ticks);
 469  		return 0;
      	}
      
 472  	case KDGKBTYPE:
      		/*
      		 * this is naive.
      		 */
      		ucval = keyboard_type;
 477  		goto setchar;
      
      #if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__)
      		/*
      		 * These cannot be implemented on any machine that implements
      		 * ioperm() in user level (such as Alpha PCs).
      		 */
 484  	case KDADDIO:
 485  	case KDDELIO:
      		/*
      		 * KDADDIO and KDDELIO may be able to add ports beyond what
      		 * we reject here, but to be safe...
      		 */
 490  		if (arg < GPFIRST || arg > GPLAST)
 491  			return -EINVAL;
 492  		return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
      
 494  	case KDENABIO:
 495  	case KDDISABIO:
      		return sys_ioperm(GPFIRST, GPNUM,
 497  				  (cmd == KDENABIO)) ? -ENXIO : 0;
      #endif
      
      #if defined(__mc68000__) || defined(CONFIG_APUS)
      	/* Linux/m68k interface for setting the keyboard delay/repeat rate */
      		
      	case KDKBDREP:
      	{
      		struct kbd_repeat kbrep;
      		
      		if (!mach_kbdrate) return( -EINVAL );
      		if (!suser()) return( -EPERM );
      
      		if (copy_from_user(&kbrep, (void *)arg,
      				   sizeof(struct kbd_repeat)))
      			return -EFAULT;
      		if ((i = mach_kbdrate( &kbrep ))) return( i );
      		if (copy_to_user((void *)arg, &kbrep,
      				 sizeof(struct kbd_repeat)))
      			return -EFAULT;
      		return 0;
      	}
      #endif
      
 521  	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...
      		 */
 527  		if (!perm)
 528  			return -EPERM;
 529  		switch (arg) {
 530  		case KD_GRAPHICS:
 531  			break;
 532  		case KD_TEXT0:
 533  		case KD_TEXT1:
      			arg = KD_TEXT;
 535  		case KD_TEXT:
 536  			break;
 537  		default:
 538  			return -EINVAL;
      		}
 540  		if (vt_cons[console]->vc_mode == (unsigned char) arg)
 541  			return 0;
      		vt_cons[console]->vc_mode = (unsigned char) arg;
 543  		if (console != fg_console)
 544  			return 0;
      		/*
      		 * explicitly blank/unblank the screen if switching modes
      		 */
 548  		if (arg == KD_TEXT)
      			unblank_screen();
 550  		else
      			do_blank_screen(1);
 552  		return 0;
      
 554  	case KDGETMODE:
      		ucval = vt_cons[console]->vc_mode;
 556  		goto setint;
      
 558  	case KDMAPDISP:
 559  	case KDUNMAPDISP:
      		/*
      		 * these work like a combination of mmap and KDENABIO.
      		 * this could be easily finished.
      		 */
 564  		return -EINVAL;
      
 566  	case KDSKBMODE:
 567  		if (!perm)
 568  			return -EPERM;
 569  		switch(arg) {
 570  		  case K_RAW:
      			kbd->kbdmode = VC_RAW;
 572  			break;
 573  		  case K_MEDIUMRAW:
      			kbd->kbdmode = VC_MEDIUMRAW;
 575  			break;
 576  		  case K_XLATE:
      			kbd->kbdmode = VC_XLATE;
      			compute_shiftstate();
 579  			break;
 580  		  case K_UNICODE:
      			kbd->kbdmode = VC_UNICODE;
      			compute_shiftstate();
 583  			break;
 584  		  default:
 585  			return -EINVAL;
      		}
 587  		if (tty->ldisc.flush_buffer)
      			tty->ldisc.flush_buffer(tty);
 589  		return 0;
      
 591  	case KDGKBMODE:
      		ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
      				 (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
      				 (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
      				 K_XLATE);
 596  		goto setint;
      
      	/* this could be folded into KDSKBMODE, but for compatibility
      	   reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
 600  	case KDSKBMETA:
 601  		switch(arg) {
 602  		  case K_METABIT:
      			clr_vc_kbd_mode(kbd, VC_META);
 604  			break;
 605  		  case K_ESCPREFIX:
      			set_vc_kbd_mode(kbd, VC_META);
 607  			break;
 608  		  default:
 609  			return -EINVAL;
      		}
 611  		return 0;
      
 613  	case KDGKBMETA:
      		ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
      	setint:
 616  		return put_user(ucval, (int *)arg); 
      
 618  	case KDGETKEYCODE:
 619  	case KDSETKEYCODE:
 620  		if(!capable(CAP_SYS_ADMIN))
      			perm=0;
 622  		return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm);
      
 624  	case KDGKBENT:
 625  	case KDSKBENT:
 626  		return do_kdsk_ioctl(cmd, (struct kbentry *)arg, perm, kbd);
      
 628  	case KDGKBSENT:
 629  	case KDSKBSENT:
 630  		return do_kdgkb_ioctl(cmd, (struct kbsentry *)arg, perm);
      
 632  	case KDGKBDIACR:
      	{
      		struct kbdiacrs *a = (struct kbdiacrs *)arg;
      
 636  		if (put_user(accent_table_size, &a->kb_cnt))
 637  			return -EFAULT;
 638  		if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr)))
 639  			return -EFAULT;
 640  		return 0;
      	}
      
 643  	case KDSKBDIACR:
      	{
      		struct kbdiacrs *a = (struct kbdiacrs *)arg;
      		unsigned int ct;
      
 648  		if (!perm)
 649  			return -EPERM;
 650  		if (get_user(ct,&a->kb_cnt))
 651  			return -EFAULT;
 652  		if (ct >= MAX_DIACR)
 653  			return -EINVAL;
      		accent_table_size = ct;
 655  		if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr)))
 656  			return -EFAULT;
 657  		return 0;
      	}
      
      	/* the ioctls below read/set the flags usually shown in the leds */
      	/* don't use them - they will go away without warning */
 662  	case KDGKBLED:
      		ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
 664  		goto setchar;
      
 666  	case KDSKBLED:
 667  		if (!perm)
 668  			return -EPERM;
 669  		if (arg & ~0x77)
 670  			return -EINVAL;
      		kbd->ledflagstate = (arg & 7);
      		kbd->default_ledflagstate = ((arg >> 4) & 7);
      		set_leds();
 674  		return 0;
      
      	/* the ioctls below only set the lights, not the functions */
      	/* for those, see KDGKBLED and KDSKBLED above */
 678  	case KDGETLED:
      		ucval = getledstate();
      	setchar:
 681  		return put_user(ucval, (char*)arg);
      
 683  	case KDSETLED:
 684  		if (!perm)
 685  		  return -EPERM;
      		setledstate(kbd, arg);
 687  		return 0;
      
      	/*
      	 * A process can indicate its willingness to accept signals
      	 * generated by pressing an appropriate key combination.
      	 * Thus, one can have a daemon that e.g. spawns a new console
      	 * upon a keypress and then changes to it.
      	 * Probably init should be changed to do this (and have a
      	 * field ks (`keyboard signal') in inittab describing the
      	 * desired action), so that the number of background daemons
      	 * does not increase.
      	 */
 699  	case KDSIGACCEPT:
      	{
      		extern int spawnpid, spawnsig;
 702  		if (!perm || !capable(CAP_KILL))
 703  		  return -EPERM;
 704  		if (arg < 1 || arg > _NSIG || arg == SIGKILL)
 705  		  return -EINVAL;
      		spawnpid = current->pid;
      		spawnsig = arg;
 708  		return 0;
      	}
      
 711  	case VT_SETMODE:
      	{
      		struct vt_mode tmp;
      
 715  		if (!perm)
 716  			return -EPERM;
 717  		if (copy_from_user(&tmp, (void*)arg, sizeof(struct vt_mode)))
 718  			return -EFAULT;
 719  		if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS)
 720  			return -EINVAL;
      		vt_cons[console]->vt_mode = tmp;
      		/* the frsig is ignored, so we set it to 0 */
      		vt_cons[console]->vt_mode.frsig = 0;
      		vt_cons[console]->vt_pid = current->pid;
      		/* no switch is required -- saw@shade.msu.ru */
      		vt_cons[console]->vt_newvt = -1; 
 727  		return 0;
      	}
      
 730  	case VT_GETMODE:
      		return copy_to_user((void*)arg, &(vt_cons[console]->vt_mode), 
 732  							sizeof(struct vt_mode)) ? -EFAULT : 0; 
      
      	/*
      	 * Returns global vt state. Note that VT 0 is always open, since
      	 * it's an alias for the current VT, and people can't use it here.
      	 * We cannot return state for more than 16 VTs, since v_state is short.
      	 */
 739  	case VT_GETSTATE:
      	{
      		struct vt_stat *vtstat = (struct vt_stat *)arg;
      		unsigned short state, mask;
      
      		i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat));
 745  		if (i)
 746  			return i;
      		put_user(fg_console + 1, &vtstat->v_active);
      		state = 1;	/* /dev/tty0 is always open */
 749  		for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
 750  			if (VT_IS_IN_USE(i))
      				state |= mask;
 752  		return put_user(state, &vtstat->v_state);
      	}
      
      	/*
      	 * Returns the first available (non-opened) console.
      	 */
 758  	case VT_OPENQRY:
 759  		for (i = 0; i < MAX_NR_CONSOLES; ++i)
 760  			if (! VT_IS_IN_USE(i))
 761  				break;
      		ucval = i < MAX_NR_CONSOLES ? (i+1) : -1;
 763  		goto setint;		 
      
      	/*
      	 * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
      	 * with num >= 1 (switches to vt 0, our console, are not allowed, just
      	 * to preserve sanity).
      	 */
 770  	case VT_ACTIVATE:
 771  		if (!perm)
 772  			return -EPERM;
 773  		if (arg == 0 || arg > MAX_NR_CONSOLES)
 774  			return -ENXIO;
      		arg--;
      		i = vc_allocate(arg);
 777  		if (i)
 778  			return i;
      		set_console(arg);
 780  		return 0;
      
      	/*
      	 * wait until the specified VT has been activated
      	 */
 785  	case VT_WAITACTIVE:
 786  		if (!perm)
 787  			return -EPERM;
 788  		if (arg == 0 || arg > MAX_NR_CONSOLES)
 789  			return -ENXIO;
 790  		return vt_waitactive(arg-1);
      
      	/*
      	 * If a vt is under process control, the kernel will not switch to it
      	 * immediately, but postpone the operation until the process calls this
      	 * ioctl, allowing the switch to complete.
      	 *
      	 * According to the X sources this is the behavior:
      	 *	0:	pending switch-from not OK
      	 *	1:	pending switch-from OK
      	 *	2:	completed switch-to OK
      	 */
 802  	case VT_RELDISP:
 803  		if (!perm)
 804  			return -EPERM;
 805  		if (vt_cons[console]->vt_mode.mode != VT_PROCESS)
 806  			return -EINVAL;
      
      		/*
      		 * Switching-from response
      		 */
 811  		if (vt_cons[console]->vt_newvt >= 0)
      		{
 813  			if (arg == 0)
      				/*
      				 * Switch disallowed, so forget we were trying
      				 * to do it.
      				 */
      				vt_cons[console]->vt_newvt = -1;
      
 820  			else
      			{
      				/*
      				 * The current vt has been released, so
      				 * complete the switch.
      				 */
      				int newvt = vt_cons[console]->vt_newvt;
      				vt_cons[console]->vt_newvt = -1;
      				i = vc_allocate(newvt);
 829  				if (i)
 830  					return i;
      				/*
      				 * When we actually do the console switch,
      				 * make sure we are atomic with respect to
      				 * other console switches..
      				 */
 836  				spin_lock_irq(&console_lock);
      				complete_change_console(newvt);
 838  				spin_unlock_irq(&console_lock);
      			}
      		}
      
      		/*
      		 * Switched-to response
      		 */
 845  		else
      		{
      			/*
      			 * If it's just an ACK, ignore it
      			 */
 850  			if (arg != VT_ACKACQ)
 851  				return -EINVAL;
      		}
      
 854  		return 0;
      
      	 /*
      	  * Disallocate memory associated to VT (but leave VT1)
      	  */
 859  	 case VT_DISALLOCATE:
 860  		if (arg > MAX_NR_CONSOLES)
 861  			return -ENXIO;
 862  		if (arg == 0) {
      		    /* disallocate all unused consoles, but leave 0 */
 864  		    for (i=1; i<MAX_NR_CONSOLES; i++)
 865  		      if (! VT_BUSY(i))
      			vc_disallocate(i);
 867  		} else {
      		    /* disallocate a single console, if possible */
      		    arg--;
 870  		    if (VT_BUSY(arg))
 871  		      return -EBUSY;
 872  		    if (arg)			      /* leave 0 */
      		      vc_disallocate(arg);
      		}
 875  		return 0;
      
 877  	case VT_RESIZE:
      	{
      		struct vt_sizes *vtsizes = (struct vt_sizes *) arg;
      		ushort ll,cc;
 881  		if (!perm)
 882  			return -EPERM;
      		i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes));
 884  		if (i)
 885  			return i;
      		get_user(ll, &vtsizes->v_rows);
      		get_user(cc, &vtsizes->v_cols);
 888  		return vc_resize_all(ll, cc);
      	}
      
 891  	case VT_RESIZEX:
      	{
      		struct vt_consize *vtconsize = (struct vt_consize *) arg;
      		ushort ll,cc,vlin,clin,vcol,ccol;
 895  		if (!perm)
 896  			return -EPERM;
      		i = verify_area(VERIFY_READ, (void *)vtconsize, sizeof(struct vt_consize));
 898  		if (i)
 899  			return i;
      		get_user(ll, &vtconsize->v_rows);
      		get_user(cc, &vtconsize->v_cols);
      		get_user(vlin, &vtconsize->v_vlin);
      		get_user(clin, &vtconsize->v_clin);
      		get_user(vcol, &vtconsize->v_vcol);
      		get_user(ccol, &vtconsize->v_ccol);
      		vlin = vlin ? vlin : video_scan_lines;
 907  		if ( clin )
      		  {
 909  		    if ( ll )
      		      {
 911  			if ( ll != vlin/clin )
 912  			  return -EINVAL; /* Parameters don't add up */
      		      }
 914  		    else 
      		      ll = vlin/clin;
      		  }
 917  		if ( vcol && ccol )
      		  {
 919  		    if ( cc )
      		      {
 921  			if ( cc != vcol/ccol )
 922  			  return -EINVAL;
      		      }
 924  		    else
      		      cc = vcol/ccol;
      		  }
      
 928  		if ( clin > 32 )
 929  		  return -EINVAL;
      		    
 931  		if ( vlin )
      		  video_scan_lines = vlin;
 933  		if ( clin )
      		  video_font_height = clin;
      		
 936  		return vc_resize_all(ll, cc);
        	}
      
 939  	case PIO_FONT: {
      		struct console_font_op op;
 941  		if (!perm)
 942  			return -EPERM;
      		op.op = KD_FONT_OP_SET;
      		op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC;	/* Compatibility */
      		op.width = 8;
      		op.height = 0;
      		op.charcount = 256;
      		op.data = (char *) arg;
 949  		return con_font_op(fg_console, &op);
      	}
      
 952  	case GIO_FONT: {
      		struct console_font_op op;
      		op.op = KD_FONT_OP_GET;
      		op.flags = KD_FONT_FLAG_OLD;
      		op.width = 8;
      		op.height = 32;
      		op.charcount = 256;
      		op.data = (char *) arg;
 960  		return con_font_op(fg_console, &op);
      	}
      
 963  	case PIO_CMAP:
 964                  if (!perm)
 965  			return -EPERM;
 966                  return con_set_cmap((char *)arg);
      
 968  	case GIO_CMAP:
 969                  return con_get_cmap((char *)arg);
      
 971  	case PIO_FONTX:
 972  	case GIO_FONTX:
 973  		return do_fontx_ioctl(cmd, (struct consolefontdesc *)arg, perm);
      
 975  	case PIO_FONTRESET:
      	{
 977  		if (!perm)
 978  			return -EPERM;
      
      #ifdef BROKEN_GRAPHICS_PROGRAMS
      		/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
      		   font is not saved. */
 983  		return -ENOSYS;
      #else
      		{
      		struct console_font_op op;
      		op.op = KD_FONT_OP_SET_DEFAULT;
      		op.data = NULL;
      		i = con_font_op(fg_console, &op);
      		if (i) return i;
      		con_set_default_unimap(fg_console);
      		return 0;
      		}
      #endif
      	}
      
 997  	case KDFONTOP: {
      		struct console_font_op op;
 999  		if (copy_from_user(&op, (void *) arg, sizeof(op)))
1000  			return -EFAULT;
1001  		if (!perm && op.op != KD_FONT_OP_GET)
1002  			return -EPERM;
      		i = con_font_op(console, &op);
1004  		if (i) return i;
1005  		if (copy_to_user((void *) arg, &op, sizeof(op)))
1006  			return -EFAULT;
1007  		return 0;
      	}
      
1010  	case PIO_SCRNMAP:
1011  		if (!perm)
1012  			return -EPERM;
1013  		return con_set_trans_old((unsigned char *)arg);
      
1015  	case GIO_SCRNMAP:
1016  		return con_get_trans_old((unsigned char *)arg);
      
1018  	case PIO_UNISCRNMAP:
1019  		if (!perm)
1020  			return -EPERM;
1021  		return con_set_trans_new((unsigned short *)arg);
      
1023  	case GIO_UNISCRNMAP:
1024  		return con_get_trans_new((unsigned short *)arg);
      
1026  	case PIO_UNIMAPCLR:
      	      { struct unimapinit ui;
1028  		if (!perm)
1029  			return -EPERM;
      		i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit));
1031  		if (i) return -EFAULT;
      		con_clear_unimap(fg_console, &ui);
1033  		return 0;
      	      }
      
1036  	case PIO_UNIMAP:
1037  	case GIO_UNIMAP:
1038  		return do_unimap_ioctl(cmd, (struct unimapdesc *)arg, perm);
      
1040  	case VT_LOCKSWITCH:
1041  		if (!suser())
1042  		   return -EPERM;
      		vt_dont_switch = 1;
1044  		return 0;
1045  	case VT_UNLOCKSWITCH:
1046  		if (!suser())
1047  		   return -EPERM;
      		vt_dont_switch = 0;
1049  		return 0;
      #ifdef CONFIG_FB_COMPAT_XPMAC
      	case VC_GETMODE:
      		{
      			struct vc_mode mode;
      
      			i = verify_area(VERIFY_WRITE, (void *) arg,
      					sizeof(struct vc_mode));
      			if (i == 0)
      				i = console_getmode(&mode);
      			if (i)
      				return i;
      			if (copy_to_user((void *) arg, &mode, sizeof(mode)))
      				return -EFAULT;
      			return 0;
      		}
      	case VC_SETMODE:
      	case VC_INQMODE:
      		{
      			struct vc_mode mode;
      
      			if (!perm)
      				return -EPERM;
      			i = verify_area(VERIFY_READ, (void *) arg,
      					sizeof(struct vc_mode));
      			if (i)
      				return i;
      			if (copy_from_user(&mode, (void *) arg, sizeof(mode)))
      				return -EFAULT;
      			return console_setmode(&mode, cmd == VC_SETMODE);
      		}
      	case VC_SETCMAP:
      		{
      			unsigned char cmap[3][256], *p;
      			int n_entries, cmap_size, i, j;
      
      			if (!perm)
      				return -EPERM;
      			if (arg == (unsigned long) VC_POWERMODE_INQUIRY
      			    || arg <= VESA_POWERDOWN) {
      				/* compatibility hack: VC_POWERMODE
      				   was changed from 0x766a to 0x766c */
      				return console_powermode((int) arg);
      			}
      			i = verify_area(VERIFY_READ, (void *) arg,
      					sizeof(int));
      			if (i)
      				return i;
      			if (get_user(cmap_size, (int *) arg))
      				return -EFAULT;
      			if (cmap_size % 3)
      				return -EINVAL;
      			n_entries = cmap_size / 3;
      			if ((unsigned) n_entries > 256)
      				return -EINVAL;
      			p = (unsigned char *) (arg + sizeof(int));
      			for (j = 0; j < n_entries; ++j)
      				for (i = 0; i < 3; ++i)
      					if (get_user(cmap[i][j], p++))
      						return -EFAULT;
      			return console_setcmap(n_entries, cmap[0],
      					       cmap[1], cmap[2]);
      		}
      	case VC_GETCMAP:
      		/* not implemented yet */
      		return -ENOIOCTLCMD;
      	case VC_POWERMODE:
      		if (!perm)
      			return -EPERM;
      		return console_powermode((int) arg);
      #endif /* CONFIG_FB_COMPAT_XPMAC */
1120  	default:
1121  		return -ENOIOCTLCMD;
      	}
      }
      
      /*
       * Sometimes we want to wait until a particular VT has been activated. We
       * do it in a very simple manner. Everybody waits on a single queue and
       * get woken up at once. Those that are satisfied go on with their business,
       * while those not ready go back to sleep. Seems overkill to add a wait
       * to each vt just for this - usually this does nothing!
       */
      static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue);
      
      /*
       * Sleeps until a vt is activated, or the task is interrupted. Returns
       * 0 if activation, -EINTR if interrupted.
       */
1138  int vt_waitactive(int vt)
      {
      	int retval;
      	DECLARE_WAITQUEUE(wait, current);
      
      	add_wait_queue(&vt_activate_queue, &wait);
1144  	for (;;) {
1145  		set_current_state(TASK_INTERRUPTIBLE);
      		retval = 0;
1147  		if (vt == fg_console)
1148  			break;
      		retval = -EINTR;
1150  		if (signal_pending(current))
1151  			break;
      		schedule();
      	}
      	remove_wait_queue(&vt_activate_queue, &wait);
      	current->state = TASK_RUNNING;
1156  	return retval;
      }
      
      #define vt_wake_waitactive() wake_up(&vt_activate_queue)
      
1161  void reset_vc(unsigned int new_console)
      {
      	vt_cons[new_console]->vc_mode = KD_TEXT;
      	kbd_table[new_console].kbdmode = VC_XLATE;
      	vt_cons[new_console]->vt_mode.mode = VT_AUTO;
      	vt_cons[new_console]->vt_mode.waitv = 0;
      	vt_cons[new_console]->vt_mode.relsig = 0;
      	vt_cons[new_console]->vt_mode.acqsig = 0;
      	vt_cons[new_console]->vt_mode.frsig = 0;
      	vt_cons[new_console]->vt_pid = -1;
      	vt_cons[new_console]->vt_newvt = -1;
      	reset_palette (new_console) ;
      }
      
      /*
       * Performs the back end of a vt switch
       */
1178  void complete_change_console(unsigned int new_console)
      {
      	unsigned char old_vc_mode;
      
      	last_console = fg_console;
      
      	/*
      	 * If we're switching, we could be going from KD_GRAPHICS to
      	 * KD_TEXT mode or vice versa, which means we need to blank or
      	 * unblank the screen later.
      	 */
      	old_vc_mode = vt_cons[fg_console]->vc_mode;
      	switch_screen(new_console);
      
      	/*
      	 * If this new console is under process control, send it a signal
      	 * telling it that it has acquired. Also check if it has died and
      	 * clean up (similar to logic employed in change_console())
      	 */
1197  	if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS)
      	{
      		/*
      		 * Send the signal as privileged - kill_proc() will
      		 * tell us if the process has gone or something else
      		 * is awry
      		 */
      		if (kill_proc(vt_cons[new_console]->vt_pid,
      			      vt_cons[new_console]->vt_mode.acqsig,
1206  			      1) != 0)
      		{
      		/*
      		 * The controlling process has died, so we revert back to
      		 * normal operation. In this case, we'll also change back
      		 * to KD_TEXT mode. I'm not sure if this is strictly correct
      		 * but it saves the agony when the X server dies and the screen
      		 * remains blanked due to KD_GRAPHICS! It would be nice to do
      		 * this outside of VT_PROCESS but there is no single process
      		 * to account for and tracking tty count may be undesirable.
      		 */
      		        reset_vc(new_console);
      		}
      	}
      
      	/*
      	 * We do this here because the controlling process above may have
      	 * gone, and so there is now a new vc_mode
      	 */
1225  	if (old_vc_mode != vt_cons[new_console]->vc_mode)
      	{
1227  		if (vt_cons[new_console]->vc_mode == KD_TEXT)
      			unblank_screen();
1229  		else
      			do_blank_screen(1);
      	}
      
      	/*
      	 * Wake anyone waiting for their VT to activate
      	 */
      	vt_wake_waitactive();
1237  	return;
      }
      
      /*
       * Performs the front-end of a vt switch
       */
1243  void change_console(unsigned int new_console)
      {
1245          if ((new_console == fg_console) || (vt_dont_switch))
1246                  return;
1247          if (!vc_cons_allocated(new_console))
1248  		return;
      
      	/*
      	 * If this vt is in process mode, then we need to handshake with
      	 * that process before switching. Essentially, we store where that
      	 * vt wants to switch to and wait for it to tell us when it's done
      	 * (via VT_RELDISP ioctl).
      	 *
      	 * We also check to see if the controlling process still exists.
      	 * If it doesn't, we reset this vt to auto mode and continue.
      	 * This is a cheap way to track process control. The worst thing
      	 * that can happen is: we send a signal to a process, it dies, and
      	 * the switch gets "lost" waiting for a response; hopefully, the
      	 * user will try again, we'll detect the process is gone (unless
      	 * the user waits just the right amount of time :-) and revert the
      	 * vt to auto control.
      	 */
1265  	if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS)
      	{
      		/*
      		 * Send the signal as privileged - kill_proc() will
      		 * tell us if the process has gone or something else
      		 * is awry
      		 */
      		if (kill_proc(vt_cons[fg_console]->vt_pid,
      			      vt_cons[fg_console]->vt_mode.relsig,
1274  			      1) == 0)
      		{
      			/*
      			 * It worked. Mark the vt to switch to and
      			 * return. The process needs to send us a
      			 * VT_RELDISP ioctl to complete the switch.
      			 */
      			vt_cons[fg_console]->vt_newvt = new_console;
1282  			return;
      		}
      
      		/*
      		 * The controlling process has died, so we revert back to
      		 * normal operation. In this case, we'll also change back
      		 * to KD_TEXT mode. I'm not sure if this is strictly correct
      		 * but it saves the agony when the X server dies and the screen
      		 * remains blanked due to KD_GRAPHICS! It would be nice to do
      		 * this outside of VT_PROCESS but there is no single process
      		 * to account for and tracking tty count may be undesirable.
      		 */
      		reset_vc(fg_console);
      
      		/*
      		 * Fall through to normal (VT_AUTO) handling of the switch...
      		 */
      	}
      
      	/*
      	 * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
      	 */
1304  	if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
1305  		return;
      
      	complete_change_console(new_console);
      }