#include <linux/major.h>
#include <linux/fs.h>
#include <linux/console.h>
+#include <linux/consolemap.h>
#include <linux/signal.h>
#include <linux/timex.h>
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;
}
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)
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;
}
/*
* Switching-from response
*/
+ acquire_console_sem();
if (vc->vt_newvt >= 0) {
if (arg == 0)
/*
* complete the switch.
*/
int newvt;
- acquire_console_sem();
newvt = vc->vt_newvt;
vc->vt_newvt = -1;
i = vc_allocate(newvt);
* other console switches..
*/
complete_change_console(vc_cons[newvt].d);
- release_console_sem();
}
}
/*
* 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;
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;
}
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();
}
/*
* 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)
{
break;
}
release_console_sem();
- retval = -EINTR;
+ retval = -ERESTARTNOHAND;
if (signal_pending(current))
break;
schedule();
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;
/*
* 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;
}