00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <linux/config.h>
00013 #include <linux/types.h>
00014 #include <linux/errno.h>
00015 #include <linux/sched.h>
00016 #include <linux/tty.h>
00017 #include <linux/timer.h>
00018 #include <linux/kernel.h>
00019 #include <linux/kd.h>
00020 #include <linux/vt.h>
00021 #include <linux/string.h>
00022 #include <linux/malloc.h>
00023 #include <linux/major.h>
00024 #include <linux/fs.h>
00025
00026 #include <asm/io.h>
00027 #include <asm/uaccess.h>
00028
00029 #include <linux/kbd_kern.h>
00030 #include <linux/vt_kern.h>
00031 #include <linux/kbd_diacr.h>
00032 #include <linux/selection.h>
00033
00034 #ifdef CONFIG_FB_COMPAT_XPMAC
00035 #include <asm/vc_ioctl.h>
00036 #endif
00037
00038 char vt_dont_switch = 0;
00039 extern struct tty_driver console_driver;
00040
00041 #define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count)
00042 #define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons)
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 struct vt_struct *vt_cons[MAX_NR_CONSOLES];
00058
00059
00060
00061
00062 unsigned char keyboard_type = KB_101;
00063
00064 #ifndef __alpha__
00065 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
00066 #endif
00067
00068 unsigned int video_font_height;
00069 unsigned int default_font_height;
00070 unsigned int video_scan_lines;
00071
00072
00073
00074
00075
00076 #define GPFIRST 0x3b4
00077 #define GPLAST 0x3df
00078 #define GPNUM (GPLAST - GPFIRST + 1)
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 #if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \
00092 || (defined(__mips__) && !defined(CONFIG_SGI))
00093
00094 static void
00095 kd_nosound(unsigned long ignored)
00096 {
00097
00098 outb(inb_p(0x61)&0xFC, 0x61);
00099 return;
00100 }
00101
00102 void
00103 _kd_mksound(unsigned int hz, unsigned int ticks)
00104 {
00105 static struct timer_list sound_timer = { NULL, NULL, 0, 0,
00106 kd_nosound };
00107
00108 unsigned int count = 0;
00109
00110 if (hz > 20 && hz < 32767)
00111 count = 1193180 / hz;
00112
00113 cli();
00114 del_timer(&sound_timer);
00115 if (count) {
00116
00117 outb_p(inb_p(0x61)|3, 0x61);
00118
00119 outb_p(0xB6, 0x43);
00120
00121 outb_p(count & 0xff, 0x42);
00122 outb((count >> 8) & 0xff, 0x42);
00123
00124 if (ticks) {
00125 sound_timer.expires = jiffies+ticks;
00126 add_timer(&sound_timer);
00127 }
00128 } else
00129 kd_nosound(0);
00130 sti();
00131 return;
00132 }
00133
00134 #else
00135
00136 void
00137 _kd_mksound(unsigned int hz, unsigned int ticks)
00138 {
00139 }
00140
00141 #endif
00142
00143 void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound;
00144
00145
00146 #define i (tmp.kb_index)
00147 #define s (tmp.kb_table)
00148 #define v (tmp.kb_value)
00149 static inline int
00150 do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kbd)
00151 {
00152 struct kbentry tmp;
00153 ushort *key_map, val, ov;
00154
00155 if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
00156 return -EFAULT;
00157 if (i >= NR_KEYS || s >= MAX_NR_KEYMAPS)
00158 return -EINVAL;
00159
00160 switch (cmd) {
00161 case KDGKBENT:
00162 key_map = key_maps[s];
00163 if (key_map) {
00164 val = U(key_map[i]);
00165 if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
00166 val = K_HOLE;
00167 } else
00168 val = (i ? K_HOLE : K_NOSUCHMAP);
00169 return put_user(val, &user_kbe->kb_value);
00170 case KDSKBENT:
00171 if (!perm)
00172 return -EPERM;
00173 if (!i && v == K_NOSUCHMAP) {
00174
00175 key_map = key_maps[s];
00176 if (s && key_map) {
00177 key_maps[s] = 0;
00178 if (key_map[0] == U(K_ALLOCATED)) {
00179 kfree_s(key_map, sizeof(plain_map));
00180 keymap_count--;
00181 }
00182 }
00183 break;
00184 }
00185
00186 if (KTYP(v) < NR_TYPES) {
00187 if (KVAL(v) > max_vals[KTYP(v)])
00188 return -EINVAL;
00189 } else
00190 if (kbd->kbdmode != VC_UNICODE)
00191 return -EINVAL;
00192
00193
00194 #if !defined(__mc68000__) && !defined(__powerpc__)
00195
00196 if (!i)
00197 break;
00198 #endif
00199
00200 if (!(key_map = key_maps[s])) {
00201 int j;
00202
00203 if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
00204 !capable(CAP_SYS_RESOURCE))
00205 return -EPERM;
00206
00207 key_map = (ushort *) kmalloc(sizeof(plain_map),
00208 GFP_KERNEL);
00209 if (!key_map)
00210 return -ENOMEM;
00211 key_maps[s] = key_map;
00212 key_map[0] = U(K_ALLOCATED);
00213 for (j = 1; j < NR_KEYS; j++)
00214 key_map[j] = U(K_HOLE);
00215 keymap_count++;
00216 }
00217 ov = U(key_map[i]);
00218 if (v == ov)
00219 break;
00220
00221
00222
00223 if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
00224 return -EPERM;
00225 key_map[i] = U(v);
00226 if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
00227 compute_shiftstate();
00228 break;
00229 }
00230 return 0;
00231 }
00232 #undef i
00233 #undef s
00234 #undef v
00235
00236 static inline int
00237 do_kbkeycode_ioctl(int cmd, struct kbkeycode *user_kbkc, int perm)
00238 {
00239 struct kbkeycode tmp;
00240 int kc = 0;
00241
00242 if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
00243 return -EFAULT;
00244 switch (cmd) {
00245 case KDGETKEYCODE:
00246 kc = getkeycode(tmp.scancode);
00247 if (kc >= 0)
00248 kc = put_user(kc, &user_kbkc->keycode);
00249 break;
00250 case KDSETKEYCODE:
00251 if (!perm)
00252 return -EPERM;
00253 kc = setkeycode(tmp.scancode, tmp.keycode);
00254 break;
00255 }
00256 return kc;
00257 }
00258
00259 static inline int
00260 do_kdgkb_ioctl(int cmd, struct kbsentry *user_kdgkb, int perm)
00261 {
00262 struct kbsentry tmp;
00263 char *p;
00264 u_char *q;
00265 int sz;
00266 int delta;
00267 char *first_free, *fj, *fnw;
00268 int i, j, k;
00269
00270
00271 if (copy_from_user(&tmp, user_kdgkb, sizeof(struct kbsentry)))
00272 return -EFAULT;
00273 tmp.kb_string[sizeof(tmp.kb_string)-1] = '\0';
00274 if (tmp.kb_func >= MAX_NR_FUNC)
00275 return -EINVAL;
00276 i = tmp.kb_func;
00277
00278 switch (cmd) {
00279 case KDGKBSENT:
00280 sz = sizeof(tmp.kb_string) - 1;
00281
00282 q = user_kdgkb->kb_string;
00283 p = func_table[i];
00284 if(p)
00285 for ( ; *p && sz; p++, sz--)
00286 put_user(*p, q++);
00287 put_user('\0', q);
00288 return ((p && *p) ? -EOVERFLOW : 0);
00289 case KDSKBSENT:
00290 if (!perm)
00291 return -EPERM;
00292
00293 q = func_table[i];
00294 first_free = funcbufptr + (funcbufsize - funcbufleft);
00295 for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
00296 ;
00297 if (j < MAX_NR_FUNC)
00298 fj = func_table[j];
00299 else
00300 fj = first_free;
00301
00302 delta = (q ? -strlen(q) : 1) + strlen(tmp.kb_string);
00303 if (delta <= funcbufleft) {
00304 if (j < MAX_NR_FUNC) {
00305 memmove(fj + delta, fj, first_free - fj);
00306 for (k = j; k < MAX_NR_FUNC; k++)
00307 if (func_table[k])
00308 func_table[k] += delta;
00309 }
00310 if (!q)
00311 func_table[i] = fj;
00312 funcbufleft -= delta;
00313 } else {
00314 sz = 256;
00315 while (sz < funcbufsize - funcbufleft + delta)
00316 sz <<= 1;
00317 fnw = (char *) kmalloc(sz, GFP_KERNEL);
00318 if(!fnw)
00319 return -ENOMEM;
00320
00321 if (!q)
00322 func_table[i] = fj;
00323 if (fj > funcbufptr)
00324 memmove(fnw, funcbufptr, fj - funcbufptr);
00325 for (k = 0; k < j; k++)
00326 if (func_table[k])
00327 func_table[k] = fnw + (func_table[k] - funcbufptr);
00328
00329 if (first_free > fj) {
00330 memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
00331 for (k = j; k < MAX_NR_FUNC; k++)
00332 if (func_table[k])
00333 func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
00334 }
00335 if (funcbufptr != func_buf)
00336 kfree_s(funcbufptr, funcbufsize);
00337 funcbufptr = fnw;
00338 funcbufleft = funcbufleft - delta + sz - funcbufsize;
00339 funcbufsize = sz;
00340 }
00341 strcpy(func_table[i], tmp.kb_string);
00342 break;
00343 }
00344 return 0;
00345 }
00346
00347 static inline int
00348 do_fontx_ioctl(int cmd, struct consolefontdesc *user_cfd, int perm)
00349 {
00350 struct consolefontdesc cfdarg;
00351 struct console_font_op op;
00352 int i;
00353
00354 if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc)))
00355 return -EFAULT;
00356
00357 switch (cmd) {
00358 case PIO_FONTX:
00359 if (!perm)
00360 return -EPERM;
00361 op.op = KD_FONT_OP_SET;
00362 op.flags = KD_FONT_FLAG_OLD;
00363 op.width = 8;
00364 op.height = cfdarg.charheight;
00365 op.charcount = cfdarg.charcount;
00366 op.data = cfdarg.chardata;
00367 return con_font_op(fg_console, &op);
00368 case GIO_FONTX: {
00369 op.op = KD_FONT_OP_GET;
00370 op.flags = KD_FONT_FLAG_OLD;
00371 op.width = 8;
00372 op.height = cfdarg.charheight;
00373 op.charcount = cfdarg.charcount;
00374 op.data = cfdarg.chardata;
00375 i = con_font_op(fg_console, &op);
00376 if (i)
00377 return i;
00378 cfdarg.charheight = op.height;
00379 cfdarg.charcount = op.charcount;
00380 if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
00381 return -EFAULT;
00382 return 0;
00383 }
00384 }
00385 return -EINVAL;
00386 }
00387
00388 static inline int
00389 do_unimap_ioctl(int cmd, struct unimapdesc *user_ud,int perm)
00390 {
00391 struct unimapdesc tmp;
00392 int i = 0;
00393
00394 if (copy_from_user(&tmp, user_ud, sizeof tmp))
00395 return -EFAULT;
00396 if (tmp.entries) {
00397
00398 i = verify_area(VERIFY_WRITE, tmp.entries,
00399 (size_t)tmp.entry_ct * sizeof(struct unipair));
00400 if (i) return i;
00401 }
00402 switch (cmd) {
00403 case PIO_UNIMAP:
00404 if (!perm)
00405 return -EPERM;
00406 return con_set_unimap(fg_console, tmp.entry_ct, tmp.entries);
00407 case GIO_UNIMAP:
00408 return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
00409 }
00410 return 0;
00411 }
00412
00413
00414
00415
00416
00417 int vt_ioctl(struct tty_struct *tty, struct file * file,
00418 unsigned int cmd, unsigned long arg)
00419 {
00420 int i, perm;
00421 unsigned int console;
00422 unsigned char ucval;
00423 struct kbd_struct * kbd;
00424 struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
00425
00426 console = vt->vc_num;
00427
00428 if (!vc_cons_allocated(console))
00429 return -ENOIOCTLCMD;
00430
00431
00432
00433
00434
00435 perm = 0;
00436 if (current->tty == tty || suser())
00437 perm = 1;
00438
00439 kbd = kbd_table + console;
00440 switch (cmd) {
00441 case KIOCSOUND:
00442 if (!perm)
00443 return -EPERM;
00444 if (arg)
00445 arg = 1193180 / arg;
00446 kd_mksound(arg, 0);
00447 return 0;
00448
00449 case KDMKTONE:
00450 if (!perm)
00451 return -EPERM;
00452 {
00453 unsigned int ticks, count;
00454
00455
00456
00457
00458
00459 ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
00460 count = ticks ? (arg & 0xffff) : 0;
00461 if (count)
00462 count = 1193180 / count;
00463 kd_mksound(count, ticks);
00464 return 0;
00465 }
00466
00467 case KDGKBTYPE:
00468
00469
00470
00471 ucval = keyboard_type;
00472 goto setchar;
00473
00474 #ifndef __alpha__
00475
00476
00477
00478
00479 case KDADDIO:
00480 case KDDELIO:
00481
00482
00483
00484
00485 if (arg < GPFIRST || arg > GPLAST)
00486 return -EINVAL;
00487 return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
00488
00489 case KDENABIO:
00490 case KDDISABIO:
00491 return sys_ioperm(GPFIRST, GPNUM,
00492 (cmd == KDENABIO)) ? -ENXIO : 0;
00493 #endif
00494
00495 case KDSETMODE:
00496
00497
00498
00499
00500
00501 if (!perm)
00502 return -EPERM;
00503 switch (arg) {
00504 case KD_GRAPHICS:
00505 break;
00506 case KD_TEXT0:
00507 case KD_TEXT1:
00508 arg = KD_TEXT;
00509 case KD_TEXT:
00510 break;
00511 default:
00512 return -EINVAL;
00513 }
00514 if (vt_cons[console]->vc_mode == (unsigned char) arg)
00515 return 0;
00516 vt_cons[console]->vc_mode = (unsigned char) arg;
00517 if (console != fg_console)
00518 return 0;
00519
00520
00521
00522 if (arg == KD_TEXT)
00523 unblank_screen();
00524 else
00525 do_blank_screen(1);
00526 return 0;
00527
00528 case KDGETMODE:
00529 ucval = vt_cons[console]->vc_mode;
00530 goto setint;
00531
00532 case KDMAPDISP:
00533 case KDUNMAPDISP:
00534
00535
00536
00537
00538 return -EINVAL;
00539
00540 case KDSKBMODE:
00541 if (!perm)
00542 return -EPERM;
00543 switch(arg) {
00544 case K_RAW:
00545 kbd->kbdmode = VC_RAW;
00546 break;
00547 case K_MEDIUMRAW:
00548 kbd->kbdmode = VC_MEDIUMRAW;
00549 break;
00550 case K_XLATE:
00551 kbd->kbdmode = VC_XLATE;
00552 compute_shiftstate();
00553 break;
00554 case K_UNICODE:
00555 kbd->kbdmode = VC_UNICODE;
00556 compute_shiftstate();
00557 break;
00558 default:
00559 return -EINVAL;
00560 }
00561 if (tty->ldisc.flush_buffer)
00562 tty->ldisc.flush_buffer(tty);
00563 return 0;
00564
00565 case KDGKBMODE:
00566 ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
00567 (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
00568 (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
00569 K_XLATE);
00570 goto setint;
00571
00572
00573
00574 case KDSKBMETA:
00575 switch(arg) {
00576 case K_METABIT:
00577 clr_vc_kbd_mode(kbd, VC_META);
00578 break;
00579 case K_ESCPREFIX:
00580 set_vc_kbd_mode(kbd, VC_META);
00581 break;
00582 default:
00583 return -EINVAL;
00584 }
00585 return 0;
00586
00587 case KDGKBMETA:
00588 ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
00589 setint:
00590 return put_user(ucval, (int *)arg);
00591
00592 case KDGETKEYCODE:
00593 case KDSETKEYCODE:
00594 if(!suser())
00595 perm=0;
00596 return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm);
00597
00598 case KDGKBENT:
00599 case KDSKBENT:
00600 return do_kdsk_ioctl(cmd, (struct kbentry *)arg, perm, kbd);
00601
00602 case KDGKBSENT:
00603 case KDSKBSENT:
00604 return do_kdgkb_ioctl(cmd, (struct kbsentry *)arg, perm);
00605
00606 case KDGKBDIACR:
00607 {
00608 struct kbdiacrs *a = (struct kbdiacrs *)arg;
00609
00610 if (put_user(accent_table_size, &a->kb_cnt))
00611 return -EFAULT;
00612 if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr)))
00613 return -EFAULT;
00614 return 0;
00615 }
00616
00617 case KDSKBDIACR:
00618 {
00619 struct kbdiacrs *a = (struct kbdiacrs *)arg;
00620 unsigned int ct;
00621
00622 if (!perm)
00623 return -EPERM;
00624 if (get_user(ct,&a->kb_cnt))
00625 return -EFAULT;
00626 if (ct >= MAX_DIACR)
00627 return -EINVAL;
00628 accent_table_size = ct;
00629 if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr)))
00630 return -EFAULT;
00631 return 0;
00632 }
00633
00634
00635
00636 case KDGKBLED:
00637 ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
00638 goto setchar;
00639
00640 case KDSKBLED:
00641 if (!perm)
00642 return -EPERM;
00643 if (arg & ~0x77)
00644 return -EINVAL;
00645 kbd->ledflagstate = (arg & 7);
00646 kbd->default_ledflagstate = ((arg >> 4) & 7);
00647 set_leds();
00648 return 0;
00649
00650
00651
00652 case KDGETLED:
00653 ucval = getledstate();
00654 setchar:
00655 return put_user(ucval, (char*)arg);
00656
00657 case KDSETLED:
00658 if (!perm)
00659 return -EPERM;
00660 setledstate(kbd, arg);
00661 return 0;
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 case KDSIGACCEPT:
00674 {
00675 extern int spawnpid, spawnsig;
00676 if (!perm)
00677 return -EPERM;
00678 if (arg < 1 || arg > _NSIG || arg == SIGKILL)
00679 return -EINVAL;
00680 spawnpid = current->pid;
00681 spawnsig = arg;
00682 return 0;
00683 }
00684
00685 case VT_SETMODE:
00686 {
00687 struct vt_mode tmp;
00688
00689 if (!perm)
00690 return -EPERM;
00691 if (copy_from_user(&tmp, (void*)arg, sizeof(struct vt_mode)))
00692 return -EFAULT;
00693 if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS)
00694 return -EINVAL;
00695 vt_cons[console]->vt_mode = tmp;
00696
00697 vt_cons[console]->vt_mode.frsig = 0;
00698 vt_cons[console]->vt_pid = current->pid;
00699
00700 vt_cons[console]->vt_newvt = -1;
00701 return 0;
00702 }
00703
00704 case VT_GETMODE:
00705 return copy_to_user((void*)arg, &(vt_cons[console]->vt_mode),
00706 sizeof(struct vt_mode)) ? -EFAULT : 0;
00707
00708
00709
00710
00711
00712
00713 case VT_GETSTATE:
00714 {
00715 struct vt_stat *vtstat = (struct vt_stat *)arg;
00716 unsigned short state, mask;
00717
00718 i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat));
00719 if (i)
00720 return i;
00721 put_user(fg_console + 1, &vtstat->v_active);
00722 state = 1;
00723 for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
00724 if (VT_IS_IN_USE(i))
00725 state |= mask;
00726 return put_user(state, &vtstat->v_state);
00727 }
00728
00729
00730
00731
00732 case VT_OPENQRY:
00733 for (i = 0; i < MAX_NR_CONSOLES; ++i)
00734 if (! VT_IS_IN_USE(i))
00735 break;
00736 ucval = i < MAX_NR_CONSOLES ? (i+1) : -1;
00737 goto setint;
00738
00739
00740
00741
00742
00743
00744 case VT_ACTIVATE:
00745 if (!perm)
00746 return -EPERM;
00747 if (arg == 0 || arg > MAX_NR_CONSOLES)
00748 return -ENXIO;
00749 arg--;
00750 i = vc_allocate(arg);
00751 if (i)
00752 return i;
00753 set_console(arg);
00754 return 0;
00755
00756
00757
00758
00759 case VT_WAITACTIVE:
00760 if (!perm)
00761 return -EPERM;
00762 if (arg == 0 || arg > MAX_NR_CONSOLES)
00763 return -ENXIO;
00764 return vt_waitactive(arg-1);
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776 case VT_RELDISP:
00777 if (!perm)
00778 return -EPERM;
00779 if (vt_cons[console]->vt_mode.mode != VT_PROCESS)
00780 return -EINVAL;
00781
00782
00783
00784
00785 if (vt_cons[console]->vt_newvt >= 0)
00786 {
00787 if (arg == 0)
00788
00789
00790
00791
00792 vt_cons[console]->vt_newvt = -1;
00793
00794 else
00795 {
00796
00797
00798
00799
00800 int newvt = vt_cons[console]->vt_newvt;
00801 vt_cons[console]->vt_newvt = -1;
00802 i = vc_allocate(newvt);
00803 if (i)
00804 return i;
00805
00806
00807
00808
00809
00810 start_bh_atomic();
00811 complete_change_console(newvt);
00812 end_bh_atomic();
00813 }
00814 }
00815
00816
00817
00818
00819 else
00820 {
00821
00822
00823
00824 if (arg != VT_ACKACQ)
00825 return -EINVAL;
00826 }
00827
00828 return 0;
00829
00830
00831
00832
00833 case VT_DISALLOCATE:
00834 if (arg > MAX_NR_CONSOLES)
00835 return -ENXIO;
00836 if (arg == 0) {
00837
00838 for (i=1; i<MAX_NR_CONSOLES; i++)
00839 if (! VT_BUSY(i))
00840 vc_disallocate(i);
00841 } else {
00842
00843 arg--;
00844 if (VT_BUSY(arg))
00845 return -EBUSY;
00846 if (arg)
00847 vc_disallocate(arg);
00848 }
00849 return 0;
00850
00851 case VT_RESIZE:
00852 {
00853 struct vt_sizes *vtsizes = (struct vt_sizes *) arg;
00854 ushort ll,cc;
00855 if (!perm)
00856 return -EPERM;
00857 i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes));
00858 if (i)
00859 return i;
00860 get_user(ll, &vtsizes->v_rows);
00861 get_user(cc, &vtsizes->v_cols);
00862 return vc_resize_all(ll, cc);
00863 }
00864
00865 case VT_RESIZEX:
00866 {
00867 struct vt_consize *vtconsize = (struct vt_consize *) arg;
00868 ushort ll,cc,vlin,clin,vcol,ccol;
00869 if (!perm)
00870 return -EPERM;
00871 i = verify_area(VERIFY_READ, (void *)vtconsize, sizeof(struct vt_consize));
00872 if (i)
00873 return i;
00874 get_user(ll, &vtconsize->v_rows);
00875 get_user(cc, &vtconsize->v_cols);
00876 get_user(vlin, &vtconsize->v_vlin);
00877 get_user(clin, &vtconsize->v_clin);
00878 get_user(vcol, &vtconsize->v_vcol);
00879 get_user(ccol, &vtconsize->v_ccol);
00880 vlin = vlin ? vlin : video_scan_lines;
00881 if ( clin )
00882 {
00883 if ( ll )
00884 {
00885 if ( ll != vlin/clin )
00886 return -EINVAL;
00887 }
00888 else
00889 ll = vlin/clin;
00890 }
00891 if ( vcol && ccol )
00892 {
00893 if ( cc )
00894 {
00895 if ( cc != vcol/ccol )
00896 return -EINVAL;
00897 }
00898 else
00899 cc = vcol/ccol;
00900 }
00901
00902 if ( clin > 32 )
00903 return -EINVAL;
00904
00905 if ( vlin )
00906 video_scan_lines = vlin;
00907 if ( clin )
00908 video_font_height = clin;
00909
00910 return vc_resize_all(ll, cc);
00911 }
00912
00913 case PIO_FONT: {
00914 struct console_font_op op;
00915 if (!perm)
00916 return -EPERM;
00917 op.op = KD_FONT_OP_SET;
00918 op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC;
00919 op.width = 8;
00920 op.height = 0;
00921 op.charcount = 256;
00922 op.data = (char *) arg;
00923 return con_font_op(fg_console, &op);
00924 }
00925
00926 case GIO_FONT: {
00927 struct console_font_op op;
00928 op.op = KD_FONT_OP_GET;
00929 op.flags = KD_FONT_FLAG_OLD;
00930 op.width = 8;
00931 op.height = 32;
00932 op.charcount = 256;
00933 op.data = (char *) arg;
00934 return con_font_op(fg_console, &op);
00935 }
00936
00937 case PIO_CMAP:
00938 if (!perm)
00939 return -EPERM;
00940 return con_set_cmap((char *)arg);
00941
00942 case GIO_CMAP:
00943 return con_get_cmap((char *)arg);
00944
00945 case PIO_FONTX:
00946 case GIO_FONTX:
00947 return do_fontx_ioctl(cmd, (struct consolefontdesc *)arg, perm);
00948
00949 case PIO_FONTRESET:
00950 {
00951 if (!perm)
00952 return -EPERM;
00953
00954 #ifdef BROKEN_GRAPHICS_PROGRAMS
00955
00956
00957 return -ENOSYS;
00958 #else
00959 {
00960 struct console_font_op op;
00961 op.op = KD_FONT_OP_SET_DEFAULT;
00962 op.data = NULL;
00963 i = con_font_op(fg_console, &op);
00964 if (i) return i;
00965 con_set_default_unimap(fg_console);
00966 return 0;
00967 }
00968 #endif
00969 }
00970
00971 case KDFONTOP: {
00972 struct console_font_op op;
00973 if (copy_from_user(&op, (void *) arg, sizeof(op)))
00974 return -EFAULT;
00975 if (!perm && op.op != KD_FONT_OP_GET)
00976 return -EPERM;
00977 i = con_font_op(console, &op);
00978 if (i) return i;
00979 if (copy_to_user((void *) arg, &op, sizeof(op)))
00980 return -EFAULT;
00981 return 0;
00982 }
00983
00984 case PIO_SCRNMAP:
00985 if (!perm)
00986 return -EPERM;
00987 return con_set_trans_old((unsigned char *)arg);
00988
00989 case GIO_SCRNMAP:
00990 return con_get_trans_old((unsigned char *)arg);
00991
00992 case PIO_UNISCRNMAP:
00993 if (!perm)
00994 return -EPERM;
00995 return con_set_trans_new((unsigned short *)arg);
00996
00997 case GIO_UNISCRNMAP:
00998 return con_get_trans_new((unsigned short *)arg);
00999
01000 case PIO_UNIMAPCLR:
01001 { struct unimapinit ui;
01002 if (!perm)
01003 return -EPERM;
01004 i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit));
01005 if (i) return -EFAULT;
01006 con_clear_unimap(fg_console, &ui);
01007 return 0;
01008 }
01009
01010 case PIO_UNIMAP:
01011 case GIO_UNIMAP:
01012 return do_unimap_ioctl(cmd, (struct unimapdesc *)arg, perm);
01013
01014 case VT_LOCKSWITCH:
01015 if (!suser())
01016 return -EPERM;
01017 vt_dont_switch = 1;
01018 return 0;
01019 case VT_UNLOCKSWITCH:
01020 if (!suser())
01021 return -EPERM;
01022 vt_dont_switch = 0;
01023 return 0;
01024 #ifdef CONFIG_FB_COMPAT_XPMAC
01025 case VC_GETMODE:
01026 {
01027 struct vc_mode mode;
01028
01029 i = verify_area(VERIFY_WRITE, (void *) arg,
01030 sizeof(struct vc_mode));
01031 if (i == 0)
01032 i = console_getmode(&mode);
01033 if (i)
01034 return i;
01035 if (copy_to_user((void *) arg, &mode, sizeof(mode)))
01036 return -EFAULT;
01037 return 0;
01038 }
01039 case VC_SETMODE:
01040 case VC_INQMODE:
01041 {
01042 struct vc_mode mode;
01043
01044 if (!perm)
01045 return -EPERM;
01046 i = verify_area(VERIFY_READ, (void *) arg,
01047 sizeof(struct vc_mode));
01048 if (i)
01049 return i;
01050 if (copy_from_user(&mode, (void *) arg, sizeof(mode)))
01051 return -EFAULT;
01052 return console_setmode(&mode, cmd == VC_SETMODE);
01053 }
01054 case VC_SETCMAP:
01055 {
01056 unsigned char cmap[3][256], *p;
01057 int n_entries, cmap_size, i, j;
01058
01059 if (!perm)
01060 return -EPERM;
01061 if (arg == (unsigned long) VC_POWERMODE_INQUIRY
01062 || arg <= VESA_POWERDOWN) {
01063
01064
01065 return console_powermode((int) arg);
01066 }
01067 i = verify_area(VERIFY_READ, (void *) arg,
01068 sizeof(int));
01069 if (i)
01070 return i;
01071 if (get_user(cmap_size, (int *) arg))
01072 return -EFAULT;
01073 if (cmap_size % 3)
01074 return -EINVAL;
01075 n_entries = cmap_size / 3;
01076 if ((unsigned) n_entries > 256)
01077 return -EINVAL;
01078 p = (unsigned char *) (arg + sizeof(int));
01079 for (j = 0; j < n_entries; ++j)
01080 for (i = 0; i < 3; ++i)
01081 if (get_user(cmap[i][j], p++))
01082 return -EFAULT;
01083 return console_setcmap(n_entries, cmap[0],
01084 cmap[1], cmap[2]);
01085 }
01086 case VC_GETCMAP:
01087
01088 return -ENOIOCTLCMD;
01089 case VC_POWERMODE:
01090 if (!perm)
01091 return -EPERM;
01092 return console_powermode((int) arg);
01093 #endif
01094 default:
01095 return -ENOIOCTLCMD;
01096 }
01097 }
01098
01099
01100
01101
01102
01103
01104
01105
01106 static struct wait_queue *vt_activate_queue = NULL;
01107
01108
01109
01110
01111
01112 int vt_waitactive(int vt)
01113 {
01114 int retval;
01115 struct wait_queue wait = { current, NULL };
01116
01117 add_wait_queue(&vt_activate_queue, &wait);
01118 for (;;) {
01119 current->state = TASK_INTERRUPTIBLE;
01120 retval = 0;
01121 if (vt == fg_console)
01122 break;
01123 retval = -EINTR;
01124 if (signal_pending(current))
01125 break;
01126 schedule();
01127 }
01128 remove_wait_queue(&vt_activate_queue, &wait);
01129 current->state = TASK_RUNNING;
01130 return retval;
01131 }
01132
01133 #define vt_wake_waitactive() wake_up(&vt_activate_queue)
01134
01135 void reset_vc(unsigned int new_console)
01136 {
01137 vt_cons[new_console]->vc_mode = KD_TEXT;
01138 kbd_table[new_console].kbdmode = VC_XLATE;
01139 vt_cons[new_console]->vt_mode.mode = VT_AUTO;
01140 vt_cons[new_console]->vt_mode.waitv = 0;
01141 vt_cons[new_console]->vt_mode.relsig = 0;
01142 vt_cons[new_console]->vt_mode.acqsig = 0;
01143 vt_cons[new_console]->vt_mode.frsig = 0;
01144 vt_cons[new_console]->vt_pid = -1;
01145 vt_cons[new_console]->vt_newvt = -1;
01146 reset_palette (new_console) ;
01147 }
01148
01149
01150
01151
01152 void complete_change_console(unsigned int new_console)
01153 {
01154 unsigned char old_vc_mode;
01155
01156 last_console = fg_console;
01157
01158
01159
01160
01161
01162
01163 old_vc_mode = vt_cons[fg_console]->vc_mode;
01164 switch_screen(new_console);
01165
01166
01167
01168
01169
01170
01171 if (vt_cons[new_console]->vt_mode.mode == VT_PROCESS)
01172 {
01173
01174
01175
01176
01177
01178 if (kill_proc(vt_cons[new_console]->vt_pid,
01179 vt_cons[new_console]->vt_mode.acqsig,
01180 1) != 0)
01181 {
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191 reset_vc(new_console);
01192 }
01193 }
01194
01195
01196
01197
01198
01199 if (old_vc_mode != vt_cons[new_console]->vc_mode)
01200 {
01201 if (vt_cons[new_console]->vc_mode == KD_TEXT)
01202 unblank_screen();
01203 else
01204 do_blank_screen(1);
01205 }
01206
01207
01208
01209
01210 vt_wake_waitactive();
01211 return;
01212 }
01213
01214
01215
01216
01217 void change_console(unsigned int new_console)
01218 {
01219 if ((new_console == fg_console) || (vt_dont_switch))
01220 return;
01221 if (!vc_cons_allocated(new_console))
01222 return;
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239 if (vt_cons[fg_console]->vt_mode.mode == VT_PROCESS)
01240 {
01241
01242
01243
01244
01245
01246 if (kill_proc(vt_cons[fg_console]->vt_pid,
01247 vt_cons[fg_console]->vt_mode.relsig,
01248 1) == 0)
01249 {
01250
01251
01252
01253
01254
01255 vt_cons[fg_console]->vt_newvt = new_console;
01256 return;
01257 }
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268 reset_vc(fg_console);
01269
01270
01271
01272
01273 }
01274
01275
01276
01277
01278 if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
01279 return;
01280
01281 complete_change_console(new_console);
01282 }
01283