diff options
-rw-r--r-- | drivers/acorn/char/defkeymap-l7200.c | 2 | ||||
-rw-r--r-- | drivers/char/consolemap.c | 22 | ||||
-rw-r--r-- | drivers/char/defkeymap.c_shipped | 2 | ||||
-rw-r--r-- | drivers/char/keyboard.c | 35 | ||||
-rw-r--r-- | drivers/char/vt_ioctl.c | 46 | ||||
-rw-r--r-- | drivers/s390/char/defkeymap.c | 2 | ||||
-rw-r--r-- | drivers/s390/char/keyboard.c | 66 | ||||
-rw-r--r-- | drivers/s390/char/keyboard.h | 4 | ||||
-rw-r--r-- | drivers/tc/lk201-map.c_shipped | 2 | ||||
-rw-r--r-- | include/linux/consolemap.h | 1 | ||||
-rw-r--r-- | include/linux/kbd_diacr.h | 2 | ||||
-rw-r--r-- | include/linux/kd.h | 10 |
12 files changed, 158 insertions, 36 deletions
diff --git a/drivers/acorn/char/defkeymap-l7200.c b/drivers/acorn/char/defkeymap-l7200.c index 9e18ce742e38..28a5fbc6aa1a 100644 --- a/drivers/acorn/char/defkeymap-l7200.c +++ b/drivers/acorn/char/defkeymap-l7200.c @@ -346,7 +346,7 @@ char *func_table[MAX_NR_FUNC] = { 0, }; -struct kbdiacr accent_table[MAX_DIACR] = { +struct kbdiacruc accent_table[MAX_DIACR] = { {'`', 'A', '\300'}, {'`', 'a', '\340'}, {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, {'^', 'A', '\302'}, {'^', 'a', '\342'}, diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c index 163f3fce3f84..6b104e45a322 100644 --- a/drivers/char/consolemap.c +++ b/drivers/char/consolemap.c @@ -669,19 +669,29 @@ void con_protect_unimap(struct vc_data *vc, int rdonly) p->readonly = rdonly; } +/* + * Always use USER_MAP. These functions are used by the keyboard, + * which shouldn't be affected by G0/G1 switching, etc. + * If the user map still contains default values, i.e. the + * direct-to-font mapping, then assume user is using Latin1. + */ /* may be called during an interrupt */ u32 conv_8bit_to_uni(unsigned char c) { - /* - * Always use USER_MAP. This function is used by the keyboard, - * which shouldn't be affected by G0/G1 switching, etc. - * If the user map still contains default values, i.e. the - * direct-to-font mapping, then assume user is using Latin1. - */ unsigned short uni = translations[USER_MAP][c]; return uni == (0xf000 | c) ? c : uni; } +int conv_uni_to_8bit(u32 uni) +{ + int c; + for (c = 0; c < 0x100; c++) + if (translations[USER_MAP][c] == uni || + (translations[USER_MAP][c] == (c | 0xf000) && uni == c)) + return c; + return -1; +} + int conv_uni_to_pc(struct vc_data *conp, long ucs) { diff --git a/drivers/char/defkeymap.c_shipped b/drivers/char/defkeymap.c_shipped index 453a2f1ffa15..0aa419a61767 100644 --- a/drivers/char/defkeymap.c_shipped +++ b/drivers/char/defkeymap.c_shipped @@ -222,7 +222,7 @@ char *func_table[MAX_NR_FUNC] = { NULL, }; -struct kbdiacr accent_table[MAX_DIACR] = { +struct kbdiacruc accent_table[MAX_DIACR] = { {'`', 'A', '\300'}, {'`', 'a', '\340'}, {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, {'^', 'A', '\302'}, {'^', 'a', '\342'}, diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index d95f316afb5a..5ae2a3250c50 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -38,6 +38,7 @@ #include <linux/kbd_kern.h> #include <linux/kbd_diacr.h> #include <linux/vt_kern.h> +#include <linux/consolemap.h> #include <linux/sysrq.h> #include <linux/input.h> #include <linux/reboot.h> @@ -403,9 +404,12 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) return d; if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, conv_8bit_to_uni(d)); - else if (d < 0x100) - put_queue(vc, d); + to_utf8(vc, d); + else { + int c = conv_uni_to_8bit(d); + if (c != -1) + put_queue(vc, c); + } return ch; } @@ -417,9 +421,12 @@ static void fn_enter(struct vc_data *vc) { if (diacr) { if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, conv_8bit_to_uni(diacr)); - else if (diacr < 0x100) - put_queue(vc, diacr); + to_utf8(vc, diacr); + else { + int c = conv_uni_to_8bit(diacr); + if (c != -1) + put_queue(vc, c); + } diacr = 0; } put_queue(vc, 13); @@ -627,9 +634,12 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) return; } if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, conv_8bit_to_uni(value)); - else if (value < 0x100) - put_queue(vc, value); + to_utf8(vc, value); + else { + int c = conv_uni_to_8bit(value); + if (c != -1) + put_queue(vc, c); + } } /* @@ -646,7 +656,12 @@ static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag) static void k_self(struct vc_data *vc, unsigned char value, char up_flag) { - k_unicode(vc, value, up_flag); + unsigned int uni; + if (kbd->kbdmode == VC_UNICODE) + uni = value; + else + uni = conv_8bit_to_uni(value); + k_unicode(vc, uni, up_flag); } static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index f69a8258095c..6c7384afff13 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -23,6 +23,7 @@ #include <linux/major.h> #include <linux/fs.h> #include <linux/console.h> +#include <linux/consolemap.h> #include <linux/signal.h> #include <linux/timex.h> @@ -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; } diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c index 564baca01b7c..389346cda6c8 100644 --- a/drivers/s390/char/defkeymap.c +++ b/drivers/s390/char/defkeymap.c @@ -150,7 +150,7 @@ char *func_table[MAX_NR_FUNC] = { NULL, }; -struct kbdiacr accent_table[MAX_DIACR] = { +struct kbdiacruc accent_table[MAX_DIACR] = { {'^', 'c', '\003'}, {'^', 'd', '\004'}, {'^', 'z', '\032'}, {'^', '\012', '\000'}, }; diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index f62f9a4e8950..cee4d4e42429 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -11,6 +11,7 @@ #include <linux/sched.h> #include <linux/sysrq.h> +#include <linux/consolemap.h> #include <linux/kbd_kern.h> #include <linux/kbd_diacr.h> #include <asm/uaccess.h> @@ -82,11 +83,11 @@ kbd_alloc(void) { if (!kbd->fn_handler) goto out_func; kbd->accent_table = - kmalloc(sizeof(struct kbdiacr)*MAX_DIACR, GFP_KERNEL); + kmalloc(sizeof(struct kbdiacruc)*MAX_DIACR, GFP_KERNEL); if (!kbd->accent_table) goto out_fn_handler; memcpy(kbd->accent_table, accent_table, - sizeof(struct kbdiacr)*MAX_DIACR); + sizeof(struct kbdiacruc)*MAX_DIACR); kbd->accent_table_size = accent_table_size; return kbd; @@ -183,8 +184,8 @@ kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc) * Otherwise, conclude that DIACR was not combining after all, * queue it and return CH. */ -static unsigned char -handle_diacr(struct kbd_data *kbd, unsigned char ch) +static unsigned int +handle_diacr(struct kbd_data *kbd, unsigned int ch) { int i, d; @@ -460,7 +461,6 @@ int kbd_ioctl(struct kbd_data *kbd, struct file *file, unsigned int cmd, unsigned long arg) { - struct kbdiacrs __user *a; void __user *argp; int ct, perm; @@ -481,17 +481,40 @@ kbd_ioctl(struct kbd_data *kbd, struct file *file, case KDSKBSENT: return do_kdgkb_ioctl(kbd, argp, cmd, perm); case KDGKBDIACR: - a = argp; + { + struct kbdiacrs __user *a = argp; + struct kbdiacr diacr; + int i; if (put_user(kbd->accent_table_size, &a->kb_cnt)) return -EFAULT; + for (i = 0; i < kbd->accent_table_size; i++) { + diacr.diacr = kbd->accent_table[i].diacr; + diacr.base = kbd->accent_table[i].base; + diacr.result = kbd->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 = argp; + ct = kbd->accent_table_size; - if (copy_to_user(a->kbdiacr, kbd->accent_table, - ct * sizeof(struct kbdiacr))) + if (put_user(ct, &a->kb_cnt)) + return -EFAULT; + if (copy_to_user(a->kbdiacruc, kbd->accent_table, + ct * sizeof(struct kbdiacruc))) return -EFAULT; return 0; + } case KDSKBDIACR: - a = argp; + { + struct kbdiacrs __user *a = argp; + struct kbdiacr diacr; + int i; + if (!perm) return -EPERM; if (get_user(ct, &a->kb_cnt)) @@ -499,10 +522,31 @@ kbd_ioctl(struct kbd_data *kbd, struct file *file, if (ct >= MAX_DIACR) return -EINVAL; kbd->accent_table_size = ct; - if (copy_from_user(kbd->accent_table, a->kbdiacr, - ct * sizeof(struct kbdiacr))) + for (i = 0; i < ct; i++) { + if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) + return -EFAULT; + kbd->accent_table[i].diacr = diacr.diacr; + kbd->accent_table[i].base = diacr.base; + kbd->accent_table[i].result = diacr.result; + } + return 0; + } + case KDSKBDIACRUC: + { + struct kbdiacrsuc __user *a = argp; + + if (!perm) + return -EPERM; + if (get_user(ct, &a->kb_cnt)) + return -EFAULT; + if (ct >= MAX_DIACR) + return -EINVAL; + kbd->accent_table_size = ct; + if (copy_from_user(kbd->accent_table, a->kbdiacruc, + ct * sizeof(struct kbdiacruc))) return -EFAULT; return 0; + } default: return -ENOIOCTLCMD; } diff --git a/drivers/s390/char/keyboard.h b/drivers/s390/char/keyboard.h index f7bf45c6bf0d..5ccfe9cf126d 100644 --- a/drivers/s390/char/keyboard.h +++ b/drivers/s390/char/keyboard.h @@ -25,9 +25,9 @@ struct kbd_data { unsigned short **key_maps; char **func_table; fn_handler_fn **fn_handler; - struct kbdiacr *accent_table; + struct kbdiacruc *accent_table; unsigned int accent_table_size; - unsigned char diacr; + unsigned int diacr; unsigned short sysrq; }; diff --git a/drivers/tc/lk201-map.c_shipped b/drivers/tc/lk201-map.c_shipped index a9df8f5bf62b..4d2aba597343 100644 --- a/drivers/tc/lk201-map.c_shipped +++ b/drivers/tc/lk201-map.c_shipped @@ -225,7 +225,7 @@ char *func_table[MAX_NR_FUNC] = { 0, }; -struct kbdiacr accent_table[MAX_DIACR] = { +struct kbdiacruc accent_table[MAX_DIACR] = { {'`', 'A', ''}, {'`', 'a', ''}, {'\'', 'A', ''}, {'\'', 'a', ''}, {'^', 'A', ''}, {'^', 'a', ''}, diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h index 06b2768c603f..e2bf7e5db39a 100644 --- a/include/linux/consolemap.h +++ b/include/linux/consolemap.h @@ -16,4 +16,5 @@ extern u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode); extern unsigned short *set_translate(int m, struct vc_data *vc); extern int conv_uni_to_pc(struct vc_data *conp, long ucs); extern u32 conv_8bit_to_uni(unsigned char c); +extern int conv_uni_to_8bit(u32 uni); void console_map_init(void); diff --git a/include/linux/kbd_diacr.h b/include/linux/kbd_diacr.h index 1c1a3ff0535b..7274ec68c246 100644 --- a/include/linux/kbd_diacr.h +++ b/include/linux/kbd_diacr.h @@ -2,7 +2,7 @@ #define _DIACR_H #include <linux/kd.h> -extern struct kbdiacr accent_table[]; +extern struct kbdiacruc accent_table[]; extern unsigned int accent_table_size; #endif /* _DIACR_H */ diff --git a/include/linux/kd.h b/include/linux/kd.h index 28be4fbe9044..c91fc0c9c495 100644 --- a/include/linux/kd.h +++ b/include/linux/kd.h @@ -125,6 +125,16 @@ struct kbdiacrs { #define KDGKBDIACR 0x4B4A /* read kernel accent table */ #define KDSKBDIACR 0x4B4B /* write kernel accent table */ +struct kbdiacruc { + __u32 diacr, base, result; +}; +struct kbdiacrsuc { + unsigned int kb_cnt; /* number of entries in following array */ + struct kbdiacruc kbdiacruc[256]; /* MAX_DIACR from keyboard.h */ +}; +#define KDGKBDIACRUC 0x4BFA /* read kernel accent table - UCS */ +#define KDSKBDIACRUC 0x4BFB /* write kernel accent table - UCS */ + struct kbkeycode { unsigned int scancode, keycode; }; |