X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fchar%2Fvt_ioctl.c;h=e6f89e8b9258429fc99754ec492918d94089bcfd;hb=068f4070868c801c7d7aa1ae1193c1c854193545;hp=c6f6f42097391b20f434a669ae6b0f263fda63ee;hpb=31f6e1bd3b58c9a67e5ea0c2d372fbf5fc9e326d;p=linux-2.6-omap-h63xx.git diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index c6f6f420973..e6f89e8b925 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -582,10 +583,27 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, case KDGKBDIACR: { struct kbdiacrs __user *a = up; + struct kbdiacr diacr; + int i; if (put_user(accent_table_size, &a->kb_cnt)) return -EFAULT; - if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr))) + for (i = 0; i < accent_table_size; i++) { + diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr); + diacr.base = conv_uni_to_8bit(accent_table[i].base); + diacr.result = conv_uni_to_8bit(accent_table[i].result); + if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) + return -EFAULT; + } + return 0; + } + case KDGKBDIACRUC: + { + struct kbdiacrsuc __user *a = up; + + if (put_user(accent_table_size, &a->kb_cnt)) + return -EFAULT; + if (copy_to_user(a->kbdiacruc, accent_table, accent_table_size*sizeof(struct kbdiacruc))) return -EFAULT; return 0; } @@ -593,6 +611,30 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, case KDSKBDIACR: { struct kbdiacrs __user *a = up; + struct kbdiacr diacr; + unsigned int ct; + int i; + + if (!perm) + return -EPERM; + if (get_user(ct,&a->kb_cnt)) + return -EFAULT; + if (ct >= MAX_DIACR) + return -EINVAL; + accent_table_size = ct; + for (i = 0; i < ct; i++) { + if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) + return -EFAULT; + accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr); + accent_table[i].base = conv_8bit_to_uni(diacr.base); + accent_table[i].result = conv_8bit_to_uni(diacr.result); + } + return 0; + } + + case KDSKBDIACRUC: + { + struct kbdiacrsuc __user *a = up; unsigned int ct; if (!perm) @@ -602,7 +644,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (ct >= MAX_DIACR) return -EINVAL; accent_table_size = ct; - if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr))) + if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc))) return -EFAULT; return 0; } @@ -770,6 +812,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, /* * Switching-from response */ + acquire_console_sem(); if (vc->vt_newvt >= 0) { if (arg == 0) /* @@ -784,7 +827,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, * complete the switch. */ int newvt; - acquire_console_sem(); newvt = vc->vt_newvt; vc->vt_newvt = -1; i = vc_allocate(newvt); @@ -798,7 +840,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, * other console switches.. */ complete_change_console(vc_cons[newvt].d); - release_console_sem(); } } @@ -810,9 +851,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, /* * If it's just an ACK, ignore it */ - if (arg != VT_ACKACQ) + if (arg != VT_ACKACQ) { + release_console_sem(); return -EINVAL; + } } + release_console_sem(); return 0; @@ -845,14 +889,24 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, case VT_RESIZE: { struct vt_sizes __user *vtsizes = up; + struct vc_data *vc; + ushort ll,cc; if (!perm) return -EPERM; if (get_user(ll, &vtsizes->v_rows) || get_user(cc, &vtsizes->v_cols)) return -EFAULT; - for (i = 0; i < MAX_NR_CONSOLES; i++) - vc_lock_resize(vc_cons[i].d, cc, ll); + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + vc = vc_cons[i].d; + + if (vc) { + vc->vc_resize_user = 1; + vc_lock_resize(vc_cons[i].d, cc, ll); + } + } + return 0; } @@ -898,6 +952,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, vc_cons[i].d->vc_scan_lines = vlin; if (clin) vc_cons[i].d->vc_font.height = clin; + vc_cons[i].d->vc_resize_user = 1; vc_resize(vc_cons[i].d, cc, ll); release_console_sem(); } @@ -1030,7 +1085,7 @@ 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. + * 0 if activation, -EINTR if interrupted by a signal handler. */ int vt_waitactive(int vt) { @@ -1055,7 +1110,7 @@ int vt_waitactive(int vt) break; } release_console_sem(); - retval = -EINTR; + retval = -ERESTARTNOHAND; if (signal_pending(current)) break; schedule(); @@ -1070,7 +1125,7 @@ int vt_waitactive(int vt) void reset_vc(struct vc_data *vc) { vc->vc_mode = KD_TEXT; - kbd_table[vc->vc_num].kbdmode = VC_XLATE; + kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; vc->vt_mode.mode = VT_AUTO; vc->vt_mode.waitv = 0; vc->vt_mode.relsig = 0; @@ -1208,15 +1263,18 @@ void change_console(struct vc_data *new_vc) /* * Send the signal as privileged - kill_pid() will * tell us if the process has gone or something else - * is awry + * is awry. + * + * We need to set vt_newvt *before* sending the signal or we + * have a race. */ + vc->vt_newvt = new_vc->vc_num; if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 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. */ - vc->vt_newvt = new_vc->vc_num; return; }