diff options
author | Alan Cox <alan@linux.intel.com> | 2012-02-28 09:49:23 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-03-08 13:50:35 -0500 |
commit | 079c9534a96da9a85a2a2f9715851050fbfbf749 (patch) | |
tree | 0e3782ff6d341f38c6f0b3840cb3c8f2bc922df8 /drivers/tty/vt | |
parent | 0fb8379dab9f97e4c56de8f9ea772c10eda27561 (diff) |
vt:tackle kbd_table
Keyboard struct lifetime is easy, but the locking is not and is completely
ignored by the existing code. Tackle this one head on
- Make the kbd_table private so we can run down all direct users
- Hoick the relevant ioctl handlers into the keyboard layer
- Lock them with the keyboard lock so they don't change mid keypress
- Add helpers for things like console stop/start so we isolate the poking
around properly
- Tweak the braille console so it still builds
There are a couple of FIXME locking cases left for ioctls that are so hideous
they should be addressed in a later patch. After this patch the kbd_table is
private and all the keyboard jiggery pokery is in one place.
This update fixes speakup and also a memory leak in the original.
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r-- | drivers/tty/vt/keyboard.c | 621 | ||||
-rw-r--r-- | drivers/tty/vt/selection.c | 9 | ||||
-rw-r--r-- | drivers/tty/vt/vt.c | 27 | ||||
-rw-r--r-- | drivers/tty/vt/vt_ioctl.c | 325 |
4 files changed, 627 insertions, 355 deletions
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 898e359c5424..70d0593d3bc6 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c | |||
@@ -68,8 +68,6 @@ extern void ctrl_alt_del(void); | |||
68 | 68 | ||
69 | #define KBD_DEFLOCK 0 | 69 | #define KBD_DEFLOCK 0 |
70 | 70 | ||
71 | void compute_shiftstate(void); | ||
72 | |||
73 | /* | 71 | /* |
74 | * Handler Tables. | 72 | * Handler Tables. |
75 | */ | 73 | */ |
@@ -100,35 +98,29 @@ static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; | |||
100 | * Variables exported for vt_ioctl.c | 98 | * Variables exported for vt_ioctl.c |
101 | */ | 99 | */ |
102 | 100 | ||
103 | /* maximum values each key_handler can handle */ | ||
104 | const int max_vals[] = { | ||
105 | 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, | ||
106 | NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, | ||
107 | 255, NR_LOCK - 1, 255, NR_BRL - 1 | ||
108 | }; | ||
109 | |||
110 | const int NR_TYPES = ARRAY_SIZE(max_vals); | ||
111 | |||
112 | struct kbd_struct kbd_table[MAX_NR_CONSOLES]; | ||
113 | EXPORT_SYMBOL_GPL(kbd_table); | ||
114 | static struct kbd_struct *kbd = kbd_table; | ||
115 | |||
116 | struct vt_spawn_console vt_spawn_con = { | 101 | struct vt_spawn_console vt_spawn_con = { |
117 | .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), | 102 | .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), |
118 | .pid = NULL, | 103 | .pid = NULL, |
119 | .sig = 0, | 104 | .sig = 0, |
120 | }; | 105 | }; |
121 | 106 | ||
122 | /* | ||
123 | * Variables exported for vt.c | ||
124 | */ | ||
125 | |||
126 | int shift_state = 0; | ||
127 | 107 | ||
128 | /* | 108 | /* |
129 | * Internal Data. | 109 | * Internal Data. |
130 | */ | 110 | */ |
131 | 111 | ||
112 | static struct kbd_struct kbd_table[MAX_NR_CONSOLES]; | ||
113 | static struct kbd_struct *kbd = kbd_table; | ||
114 | |||
115 | /* maximum values each key_handler can handle */ | ||
116 | static const int max_vals[] = { | ||
117 | 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, | ||
118 | NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, | ||
119 | 255, NR_LOCK - 1, 255, NR_BRL - 1 | ||
120 | }; | ||
121 | |||
122 | static const int NR_TYPES = ARRAY_SIZE(max_vals); | ||
123 | |||
132 | static struct input_handler kbd_handler; | 124 | static struct input_handler kbd_handler; |
133 | static DEFINE_SPINLOCK(kbd_event_lock); | 125 | static DEFINE_SPINLOCK(kbd_event_lock); |
134 | static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ | 126 | static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ |
@@ -138,6 +130,8 @@ static int npadch = -1; /* -1 or number assembled on pad */ | |||
138 | static unsigned int diacr; | 130 | static unsigned int diacr; |
139 | static char rep; /* flag telling character repeat */ | 131 | static char rep; /* flag telling character repeat */ |
140 | 132 | ||
133 | static int shift_state = 0; | ||
134 | |||
141 | static unsigned char ledstate = 0xff; /* undefined */ | 135 | static unsigned char ledstate = 0xff; /* undefined */ |
142 | static unsigned char ledioctl; | 136 | static unsigned char ledioctl; |
143 | 137 | ||
@@ -188,7 +182,7 @@ static int getkeycode_helper(struct input_handle *handle, void *data) | |||
188 | return d->error == 0; /* stop as soon as we successfully get one */ | 182 | return d->error == 0; /* stop as soon as we successfully get one */ |
189 | } | 183 | } |
190 | 184 | ||
191 | int getkeycode(unsigned int scancode) | 185 | static int getkeycode(unsigned int scancode) |
192 | { | 186 | { |
193 | struct getset_keycode_data d = { | 187 | struct getset_keycode_data d = { |
194 | .ke = { | 188 | .ke = { |
@@ -215,7 +209,7 @@ static int setkeycode_helper(struct input_handle *handle, void *data) | |||
215 | return d->error == 0; /* stop as soon as we successfully set one */ | 209 | return d->error == 0; /* stop as soon as we successfully set one */ |
216 | } | 210 | } |
217 | 211 | ||
218 | int setkeycode(unsigned int scancode, unsigned int keycode) | 212 | static int setkeycode(unsigned int scancode, unsigned int keycode) |
219 | { | 213 | { |
220 | struct getset_keycode_data d = { | 214 | struct getset_keycode_data d = { |
221 | .ke = { | 215 | .ke = { |
@@ -383,9 +377,11 @@ static void to_utf8(struct vc_data *vc, uint c) | |||
383 | /* | 377 | /* |
384 | * Called after returning from RAW mode or when changing consoles - recompute | 378 | * Called after returning from RAW mode or when changing consoles - recompute |
385 | * shift_down[] and shift_state from key_down[] maybe called when keymap is | 379 | * shift_down[] and shift_state from key_down[] maybe called when keymap is |
386 | * undefined, so that shiftkey release is seen | 380 | * undefined, so that shiftkey release is seen. The caller must hold the |
381 | * kbd_event_lock. | ||
387 | */ | 382 | */ |
388 | void compute_shiftstate(void) | 383 | |
384 | static void do_compute_shiftstate(void) | ||
389 | { | 385 | { |
390 | unsigned int i, j, k, sym, val; | 386 | unsigned int i, j, k, sym, val; |
391 | 387 | ||
@@ -418,6 +414,15 @@ void compute_shiftstate(void) | |||
418 | } | 414 | } |
419 | } | 415 | } |
420 | 416 | ||
417 | /* We still have to export this method to vt.c */ | ||
418 | void compute_shiftstate(void) | ||
419 | { | ||
420 | unsigned long flags; | ||
421 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
422 | do_compute_shiftstate(); | ||
423 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
424 | } | ||
425 | |||
421 | /* | 426 | /* |
422 | * We have a combining character DIACR here, followed by the character CH. | 427 | * We have a combining character DIACR here, followed by the character CH. |
423 | * If the combination occurs in the table, return the corresponding value. | 428 | * If the combination occurs in the table, return the corresponding value. |
@@ -637,7 +642,7 @@ static void fn_SAK(struct vc_data *vc) | |||
637 | 642 | ||
638 | static void fn_null(struct vc_data *vc) | 643 | static void fn_null(struct vc_data *vc) |
639 | { | 644 | { |
640 | compute_shiftstate(); | 645 | do_compute_shiftstate(); |
641 | } | 646 | } |
642 | 647 | ||
643 | /* | 648 | /* |
@@ -990,6 +995,8 @@ unsigned char getledstate(void) | |||
990 | 995 | ||
991 | void setledstate(struct kbd_struct *kbd, unsigned int led) | 996 | void setledstate(struct kbd_struct *kbd, unsigned int led) |
992 | { | 997 | { |
998 | unsigned long flags; | ||
999 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
993 | if (!(led & ~7)) { | 1000 | if (!(led & ~7)) { |
994 | ledioctl = led; | 1001 | ledioctl = led; |
995 | kbd->ledmode = LED_SHOW_IOCTL; | 1002 | kbd->ledmode = LED_SHOW_IOCTL; |
@@ -997,6 +1004,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led) | |||
997 | kbd->ledmode = LED_SHOW_FLAGS; | 1004 | kbd->ledmode = LED_SHOW_FLAGS; |
998 | 1005 | ||
999 | set_leds(); | 1006 | set_leds(); |
1007 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1000 | } | 1008 | } |
1001 | 1009 | ||
1002 | static inline unsigned char getleds(void) | 1010 | static inline unsigned char getleds(void) |
@@ -1036,6 +1044,75 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data) | |||
1036 | return 0; | 1044 | return 0; |
1037 | } | 1045 | } |
1038 | 1046 | ||
1047 | /** | ||
1048 | * vt_get_leds - helper for braille console | ||
1049 | * @console: console to read | ||
1050 | * @flag: flag we want to check | ||
1051 | * | ||
1052 | * Check the status of a keyboard led flag and report it back | ||
1053 | */ | ||
1054 | int vt_get_leds(int console, int flag) | ||
1055 | { | ||
1056 | unsigned long flags; | ||
1057 | struct kbd_struct * kbd = kbd_table + console; | ||
1058 | int ret; | ||
1059 | |||
1060 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1061 | ret = vc_kbd_led(kbd, flag); | ||
1062 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1063 | |||
1064 | return ret; | ||
1065 | } | ||
1066 | EXPORT_SYMBOL_GPL(vt_get_leds); | ||
1067 | |||
1068 | /** | ||
1069 | * vt_set_led_state - set LED state of a console | ||
1070 | * @console: console to set | ||
1071 | * @leds: LED bits | ||
1072 | * | ||
1073 | * Set the LEDs on a console. This is a wrapper for the VT layer | ||
1074 | * so that we can keep kbd knowledge internal | ||
1075 | */ | ||
1076 | void vt_set_led_state(int console, int leds) | ||
1077 | { | ||
1078 | struct kbd_struct * kbd = kbd_table + console; | ||
1079 | setledstate(kbd, leds); | ||
1080 | } | ||
1081 | |||
1082 | /** | ||
1083 | * vt_kbd_con_start - Keyboard side of console start | ||
1084 | * @console: console | ||
1085 | * | ||
1086 | * Handle console start. This is a wrapper for the VT layer | ||
1087 | * so that we can keep kbd knowledge internal | ||
1088 | */ | ||
1089 | void vt_kbd_con_start(int console) | ||
1090 | { | ||
1091 | struct kbd_struct * kbd = kbd_table + console; | ||
1092 | unsigned long flags; | ||
1093 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1094 | clr_vc_kbd_led(kbd, VC_SCROLLOCK); | ||
1095 | set_leds(); | ||
1096 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1097 | } | ||
1098 | |||
1099 | /** | ||
1100 | * vt_kbd_con_stop - Keyboard side of console stop | ||
1101 | * @console: console | ||
1102 | * | ||
1103 | * Handle console stop. This is a wrapper for the VT layer | ||
1104 | * so that we can keep kbd knowledge internal | ||
1105 | */ | ||
1106 | void vt_kbd_con_stop(int console) | ||
1107 | { | ||
1108 | struct kbd_struct * kbd = kbd_table + console; | ||
1109 | unsigned long flags; | ||
1110 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1111 | set_vc_kbd_led(kbd, VC_SCROLLOCK); | ||
1112 | set_leds(); | ||
1113 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1114 | } | ||
1115 | |||
1039 | /* | 1116 | /* |
1040 | * This is the tasklet that updates LED state on all keyboards | 1117 | * This is the tasklet that updates LED state on all keyboards |
1041 | * attached to the box. The reason we use tasklet is that we | 1118 | * attached to the box. The reason we use tasklet is that we |
@@ -1255,7 +1332,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1255 | if (rc == NOTIFY_STOP || !key_map) { | 1332 | if (rc == NOTIFY_STOP || !key_map) { |
1256 | atomic_notifier_call_chain(&keyboard_notifier_list, | 1333 | atomic_notifier_call_chain(&keyboard_notifier_list, |
1257 | KBD_UNBOUND_KEYCODE, ¶m); | 1334 | KBD_UNBOUND_KEYCODE, ¶m); |
1258 | compute_shiftstate(); | 1335 | do_compute_shiftstate(); |
1259 | kbd->slockstate = 0; | 1336 | kbd->slockstate = 0; |
1260 | return; | 1337 | return; |
1261 | } | 1338 | } |
@@ -1615,3 +1692,495 @@ int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) | |||
1615 | } | 1692 | } |
1616 | return ret; | 1693 | return ret; |
1617 | } | 1694 | } |
1695 | |||
1696 | /** | ||
1697 | * vt_do_kdskbmode - set keyboard mode ioctl | ||
1698 | * @console: the console to use | ||
1699 | * @arg: the requested mode | ||
1700 | * | ||
1701 | * Update the keyboard mode bits while holding the correct locks. | ||
1702 | * Return 0 for success or an error code. | ||
1703 | */ | ||
1704 | int vt_do_kdskbmode(int console, unsigned int arg) | ||
1705 | { | ||
1706 | struct kbd_struct * kbd = kbd_table + console; | ||
1707 | int ret = 0; | ||
1708 | unsigned long flags; | ||
1709 | |||
1710 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1711 | switch(arg) { | ||
1712 | case K_RAW: | ||
1713 | kbd->kbdmode = VC_RAW; | ||
1714 | break; | ||
1715 | case K_MEDIUMRAW: | ||
1716 | kbd->kbdmode = VC_MEDIUMRAW; | ||
1717 | break; | ||
1718 | case K_XLATE: | ||
1719 | kbd->kbdmode = VC_XLATE; | ||
1720 | do_compute_shiftstate(); | ||
1721 | break; | ||
1722 | case K_UNICODE: | ||
1723 | kbd->kbdmode = VC_UNICODE; | ||
1724 | do_compute_shiftstate(); | ||
1725 | break; | ||
1726 | case K_OFF: | ||
1727 | kbd->kbdmode = VC_OFF; | ||
1728 | break; | ||
1729 | default: | ||
1730 | ret = -EINVAL; | ||
1731 | } | ||
1732 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1733 | return ret; | ||
1734 | } | ||
1735 | |||
1736 | /** | ||
1737 | * vt_do_kdskbmeta - set keyboard meta state | ||
1738 | * @console: the console to use | ||
1739 | * @arg: the requested meta state | ||
1740 | * | ||
1741 | * Update the keyboard meta bits while holding the correct locks. | ||
1742 | * Return 0 for success or an error code. | ||
1743 | */ | ||
1744 | int vt_do_kdskbmeta(int console, unsigned int arg) | ||
1745 | { | ||
1746 | struct kbd_struct * kbd = kbd_table + console; | ||
1747 | int ret = 0; | ||
1748 | unsigned long flags; | ||
1749 | |||
1750 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1751 | switch(arg) { | ||
1752 | case K_METABIT: | ||
1753 | clr_vc_kbd_mode(kbd, VC_META); | ||
1754 | break; | ||
1755 | case K_ESCPREFIX: | ||
1756 | set_vc_kbd_mode(kbd, VC_META); | ||
1757 | break; | ||
1758 | default: | ||
1759 | ret = -EINVAL; | ||
1760 | } | ||
1761 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1762 | return ret; | ||
1763 | } | ||
1764 | |||
1765 | int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, | ||
1766 | int perm) | ||
1767 | { | ||
1768 | struct kbkeycode tmp; | ||
1769 | int kc = 0; | ||
1770 | |||
1771 | if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) | ||
1772 | return -EFAULT; | ||
1773 | switch (cmd) { | ||
1774 | case KDGETKEYCODE: | ||
1775 | kc = getkeycode(tmp.scancode); | ||
1776 | if (kc >= 0) | ||
1777 | kc = put_user(kc, &user_kbkc->keycode); | ||
1778 | break; | ||
1779 | case KDSETKEYCODE: | ||
1780 | if (!perm) | ||
1781 | return -EPERM; | ||
1782 | kc = setkeycode(tmp.scancode, tmp.keycode); | ||
1783 | break; | ||
1784 | } | ||
1785 | return kc; | ||
1786 | } | ||
1787 | |||
1788 | #define i (tmp.kb_index) | ||
1789 | #define s (tmp.kb_table) | ||
1790 | #define v (tmp.kb_value) | ||
1791 | |||
1792 | int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, | ||
1793 | int console) | ||
1794 | { | ||
1795 | struct kbd_struct * kbd = kbd_table + console; | ||
1796 | struct kbentry tmp; | ||
1797 | ushort *key_map, *new_map, val, ov; | ||
1798 | unsigned long flags; | ||
1799 | |||
1800 | if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) | ||
1801 | return -EFAULT; | ||
1802 | |||
1803 | if (!capable(CAP_SYS_TTY_CONFIG)) | ||
1804 | perm = 0; | ||
1805 | |||
1806 | switch (cmd) { | ||
1807 | case KDGKBENT: | ||
1808 | /* Ensure another thread doesn't free it under us */ | ||
1809 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1810 | key_map = key_maps[s]; | ||
1811 | if (key_map) { | ||
1812 | val = U(key_map[i]); | ||
1813 | if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) | ||
1814 | val = K_HOLE; | ||
1815 | } else | ||
1816 | val = (i ? K_HOLE : K_NOSUCHMAP); | ||
1817 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1818 | return put_user(val, &user_kbe->kb_value); | ||
1819 | case KDSKBENT: | ||
1820 | if (!perm) | ||
1821 | return -EPERM; | ||
1822 | if (!i && v == K_NOSUCHMAP) { | ||
1823 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1824 | /* deallocate map */ | ||
1825 | key_map = key_maps[s]; | ||
1826 | if (s && key_map) { | ||
1827 | key_maps[s] = NULL; | ||
1828 | if (key_map[0] == U(K_ALLOCATED)) { | ||
1829 | kfree(key_map); | ||
1830 | keymap_count--; | ||
1831 | } | ||
1832 | } | ||
1833 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1834 | break; | ||
1835 | } | ||
1836 | |||
1837 | if (KTYP(v) < NR_TYPES) { | ||
1838 | if (KVAL(v) > max_vals[KTYP(v)]) | ||
1839 | return -EINVAL; | ||
1840 | } else | ||
1841 | if (kbd->kbdmode != VC_UNICODE) | ||
1842 | return -EINVAL; | ||
1843 | |||
1844 | /* ++Geert: non-PC keyboards may generate keycode zero */ | ||
1845 | #if !defined(__mc68000__) && !defined(__powerpc__) | ||
1846 | /* assignment to entry 0 only tests validity of args */ | ||
1847 | if (!i) | ||
1848 | break; | ||
1849 | #endif | ||
1850 | |||
1851 | new_map = kmalloc(sizeof(plain_map), GFP_KERNEL); | ||
1852 | if (!new_map) | ||
1853 | return -ENOMEM; | ||
1854 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1855 | key_map = key_maps[s]; | ||
1856 | if (key_map == NULL) { | ||
1857 | int j; | ||
1858 | |||
1859 | if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && | ||
1860 | !capable(CAP_SYS_RESOURCE)) { | ||
1861 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1862 | kfree(new_map); | ||
1863 | return -EPERM; | ||
1864 | } | ||
1865 | key_maps[s] = new_map; | ||
1866 | key_map[0] = U(K_ALLOCATED); | ||
1867 | for (j = 1; j < NR_KEYS; j++) | ||
1868 | key_map[j] = U(K_HOLE); | ||
1869 | keymap_count++; | ||
1870 | } else | ||
1871 | kfree(new_map); | ||
1872 | |||
1873 | ov = U(key_map[i]); | ||
1874 | if (v == ov) | ||
1875 | goto out; | ||
1876 | /* | ||
1877 | * Attention Key. | ||
1878 | */ | ||
1879 | if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) { | ||
1880 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1881 | return -EPERM; | ||
1882 | } | ||
1883 | key_map[i] = U(v); | ||
1884 | if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) | ||
1885 | do_compute_shiftstate(); | ||
1886 | out: | ||
1887 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1888 | break; | ||
1889 | } | ||
1890 | return 0; | ||
1891 | } | ||
1892 | #undef i | ||
1893 | #undef s | ||
1894 | #undef v | ||
1895 | |||
1896 | /* FIXME: This one needs untangling and locking */ | ||
1897 | int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) | ||
1898 | { | ||
1899 | struct kbsentry *kbs; | ||
1900 | char *p; | ||
1901 | u_char *q; | ||
1902 | u_char __user *up; | ||
1903 | int sz; | ||
1904 | int delta; | ||
1905 | char *first_free, *fj, *fnw; | ||
1906 | int i, j, k; | ||
1907 | int ret; | ||
1908 | |||
1909 | if (!capable(CAP_SYS_TTY_CONFIG)) | ||
1910 | perm = 0; | ||
1911 | |||
1912 | kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); | ||
1913 | if (!kbs) { | ||
1914 | ret = -ENOMEM; | ||
1915 | goto reterr; | ||
1916 | } | ||
1917 | |||
1918 | /* we mostly copy too much here (512bytes), but who cares ;) */ | ||
1919 | if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { | ||
1920 | ret = -EFAULT; | ||
1921 | goto reterr; | ||
1922 | } | ||
1923 | kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; | ||
1924 | i = kbs->kb_func; | ||
1925 | |||
1926 | switch (cmd) { | ||
1927 | case KDGKBSENT: | ||
1928 | sz = sizeof(kbs->kb_string) - 1; /* sz should have been | ||
1929 | a struct member */ | ||
1930 | up = user_kdgkb->kb_string; | ||
1931 | p = func_table[i]; | ||
1932 | if(p) | ||
1933 | for ( ; *p && sz; p++, sz--) | ||
1934 | if (put_user(*p, up++)) { | ||
1935 | ret = -EFAULT; | ||
1936 | goto reterr; | ||
1937 | } | ||
1938 | if (put_user('\0', up)) { | ||
1939 | ret = -EFAULT; | ||
1940 | goto reterr; | ||
1941 | } | ||
1942 | kfree(kbs); | ||
1943 | return ((p && *p) ? -EOVERFLOW : 0); | ||
1944 | case KDSKBSENT: | ||
1945 | if (!perm) { | ||
1946 | ret = -EPERM; | ||
1947 | goto reterr; | ||
1948 | } | ||
1949 | |||
1950 | q = func_table[i]; | ||
1951 | first_free = funcbufptr + (funcbufsize - funcbufleft); | ||
1952 | for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) | ||
1953 | ; | ||
1954 | if (j < MAX_NR_FUNC) | ||
1955 | fj = func_table[j]; | ||
1956 | else | ||
1957 | fj = first_free; | ||
1958 | |||
1959 | delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); | ||
1960 | if (delta <= funcbufleft) { /* it fits in current buf */ | ||
1961 | if (j < MAX_NR_FUNC) { | ||
1962 | memmove(fj + delta, fj, first_free - fj); | ||
1963 | for (k = j; k < MAX_NR_FUNC; k++) | ||
1964 | if (func_table[k]) | ||
1965 | func_table[k] += delta; | ||
1966 | } | ||
1967 | if (!q) | ||
1968 | func_table[i] = fj; | ||
1969 | funcbufleft -= delta; | ||
1970 | } else { /* allocate a larger buffer */ | ||
1971 | sz = 256; | ||
1972 | while (sz < funcbufsize - funcbufleft + delta) | ||
1973 | sz <<= 1; | ||
1974 | fnw = kmalloc(sz, GFP_KERNEL); | ||
1975 | if(!fnw) { | ||
1976 | ret = -ENOMEM; | ||
1977 | goto reterr; | ||
1978 | } | ||
1979 | |||
1980 | if (!q) | ||
1981 | func_table[i] = fj; | ||
1982 | if (fj > funcbufptr) | ||
1983 | memmove(fnw, funcbufptr, fj - funcbufptr); | ||
1984 | for (k = 0; k < j; k++) | ||
1985 | if (func_table[k]) | ||
1986 | func_table[k] = fnw + (func_table[k] - funcbufptr); | ||
1987 | |||
1988 | if (first_free > fj) { | ||
1989 | memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); | ||
1990 | for (k = j; k < MAX_NR_FUNC; k++) | ||
1991 | if (func_table[k]) | ||
1992 | func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; | ||
1993 | } | ||
1994 | if (funcbufptr != func_buf) | ||
1995 | kfree(funcbufptr); | ||
1996 | funcbufptr = fnw; | ||
1997 | funcbufleft = funcbufleft - delta + sz - funcbufsize; | ||
1998 | funcbufsize = sz; | ||
1999 | } | ||
2000 | strcpy(func_table[i], kbs->kb_string); | ||
2001 | break; | ||
2002 | } | ||
2003 | ret = 0; | ||
2004 | reterr: | ||
2005 | kfree(kbs); | ||
2006 | return ret; | ||
2007 | } | ||
2008 | |||
2009 | int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) | ||
2010 | { | ||
2011 | struct kbd_struct * kbd = kbd_table + console; | ||
2012 | unsigned long flags; | ||
2013 | unsigned char ucval; | ||
2014 | |||
2015 | switch(cmd) { | ||
2016 | /* the ioctls below read/set the flags usually shown in the leds */ | ||
2017 | /* don't use them - they will go away without warning */ | ||
2018 | case KDGKBLED: | ||
2019 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
2020 | ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); | ||
2021 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
2022 | return put_user(ucval, (char __user *)arg); | ||
2023 | |||
2024 | case KDSKBLED: | ||
2025 | if (!perm) | ||
2026 | return -EPERM; | ||
2027 | if (arg & ~0x77) | ||
2028 | return -EINVAL; | ||
2029 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
2030 | kbd->ledflagstate = (arg & 7); | ||
2031 | kbd->default_ledflagstate = ((arg >> 4) & 7); | ||
2032 | set_leds(); | ||
2033 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
2034 | break; | ||
2035 | |||
2036 | /* the ioctls below only set the lights, not the functions */ | ||
2037 | /* for those, see KDGKBLED and KDSKBLED above */ | ||
2038 | case KDGETLED: | ||
2039 | ucval = getledstate(); | ||
2040 | return put_user(ucval, (char __user *)arg); | ||
2041 | |||
2042 | case KDSETLED: | ||
2043 | if (!perm) | ||
2044 | return -EPERM; | ||
2045 | setledstate(kbd, arg); | ||
2046 | return 0; | ||
2047 | } | ||
2048 | return -ENOIOCTLCMD; | ||
2049 | } | ||
2050 | |||
2051 | int vt_do_kdgkbmode(int console) | ||
2052 | { | ||
2053 | struct kbd_struct * kbd = kbd_table + console; | ||
2054 | /* This is a spot read so needs no locking */ | ||
2055 | switch (kbd->kbdmode) { | ||
2056 | case VC_RAW: | ||
2057 | return K_RAW; | ||
2058 | case VC_MEDIUMRAW: | ||
2059 | return K_MEDIUMRAW; | ||
2060 | case VC_UNICODE: | ||
2061 | return K_UNICODE; | ||
2062 | case VC_OFF: | ||
2063 | return K_OFF; | ||
2064 | default: | ||
2065 | return K_XLATE; | ||
2066 | } | ||
2067 | } | ||
2068 | |||
2069 | /** | ||
2070 | * vt_do_kdgkbmeta - report meta status | ||
2071 | * @console: console to report | ||
2072 | * | ||
2073 | * Report the meta flag status of this console | ||
2074 | */ | ||
2075 | int vt_do_kdgkbmeta(int console) | ||
2076 | { | ||
2077 | struct kbd_struct * kbd = kbd_table + console; | ||
2078 | /* Again a spot read so no locking */ | ||
2079 | return vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT; | ||
2080 | } | ||
2081 | |||
2082 | /** | ||
2083 | * vt_reset_unicode - reset the unicode status | ||
2084 | * @console: console being reset | ||
2085 | * | ||
2086 | * Restore the unicode console state to its default | ||
2087 | */ | ||
2088 | void vt_reset_unicode(int console) | ||
2089 | { | ||
2090 | unsigned long flags; | ||
2091 | |||
2092 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
2093 | kbd_table[console].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; | ||
2094 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
2095 | } | ||
2096 | |||
2097 | /** | ||
2098 | * vt_get_shiftstate - shift bit state | ||
2099 | * | ||
2100 | * Report the shift bits from the keyboard state. We have to export | ||
2101 | * this to support some oddities in the vt layer. | ||
2102 | */ | ||
2103 | int vt_get_shift_state(void) | ||
2104 | { | ||
2105 | /* Don't lock as this is a transient report */ | ||
2106 | return shift_state; | ||
2107 | } | ||
2108 | |||
2109 | /** | ||
2110 | * vt_reset_keyboard - reset keyboard state | ||
2111 | * @console: console to reset | ||
2112 | * | ||
2113 | * Reset the keyboard bits for a console as part of a general console | ||
2114 | * reset event | ||
2115 | */ | ||
2116 | void vt_reset_keyboard(int console) | ||
2117 | { | ||
2118 | struct kbd_struct * kbd = kbd_table + console; | ||
2119 | unsigned long flags; | ||
2120 | |||
2121 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
2122 | set_vc_kbd_mode(kbd, VC_REPEAT); | ||
2123 | clr_vc_kbd_mode(kbd, VC_CKMODE); | ||
2124 | clr_vc_kbd_mode(kbd, VC_APPLIC); | ||
2125 | clr_vc_kbd_mode(kbd, VC_CRLF); | ||
2126 | kbd->lockstate = 0; | ||
2127 | kbd->slockstate = 0; | ||
2128 | kbd->ledmode = LED_SHOW_FLAGS; | ||
2129 | kbd->ledflagstate = kbd->default_ledflagstate; | ||
2130 | /* do not do set_leds here because this causes an endless tasklet loop | ||
2131 | when the keyboard hasn't been initialized yet */ | ||
2132 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
2133 | } | ||
2134 | |||
2135 | /** | ||
2136 | * vt_get_kbd_mode_bit - read keyboard status bits | ||
2137 | * @console: console to read from | ||
2138 | * @bit: mode bit to read | ||
2139 | * | ||
2140 | * Report back a vt mode bit. We do this without locking so the | ||
2141 | * caller must be sure that there are no synchronization needs | ||
2142 | */ | ||
2143 | |||
2144 | int vt_get_kbd_mode_bit(int console, int bit) | ||
2145 | { | ||
2146 | struct kbd_struct * kbd = kbd_table + console; | ||
2147 | return vc_kbd_mode(kbd, bit); | ||
2148 | } | ||
2149 | |||
2150 | /** | ||
2151 | * vt_set_kbd_mode_bit - read keyboard status bits | ||
2152 | * @console: console to read from | ||
2153 | * @bit: mode bit to read | ||
2154 | * | ||
2155 | * Set a vt mode bit. We do this without locking so the | ||
2156 | * caller must be sure that there are no synchronization needs | ||
2157 | */ | ||
2158 | |||
2159 | void vt_set_kbd_mode_bit(int console, int bit) | ||
2160 | { | ||
2161 | struct kbd_struct * kbd = kbd_table + console; | ||
2162 | unsigned long flags; | ||
2163 | |||
2164 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
2165 | set_vc_kbd_mode(kbd, bit); | ||
2166 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
2167 | } | ||
2168 | |||
2169 | /** | ||
2170 | * vt_clr_kbd_mode_bit - read keyboard status bits | ||
2171 | * @console: console to read from | ||
2172 | * @bit: mode bit to read | ||
2173 | * | ||
2174 | * Report back a vt mode bit. We do this without locking so the | ||
2175 | * caller must be sure that there are no synchronization needs | ||
2176 | */ | ||
2177 | |||
2178 | void vt_clr_kbd_mode_bit(int console, int bit) | ||
2179 | { | ||
2180 | struct kbd_struct * kbd = kbd_table + console; | ||
2181 | unsigned long flags; | ||
2182 | |||
2183 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
2184 | clr_vc_kbd_mode(kbd, bit); | ||
2185 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
2186 | } | ||
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 7a0a12ae5458..738e45a35131 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | extern void poke_blanked_console(void); | 31 | extern void poke_blanked_console(void); |
32 | 32 | ||
33 | /* FIXME: all this needs locking */ | ||
33 | /* Variables for selection control. */ | 34 | /* Variables for selection control. */ |
34 | /* Use a dynamic buffer, instead of static (Dec 1994) */ | 35 | /* Use a dynamic buffer, instead of static (Dec 1994) */ |
35 | struct vc_data *sel_cons; /* must not be deallocated */ | 36 | struct vc_data *sel_cons; /* must not be deallocated */ |
@@ -138,7 +139,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t | |||
138 | char *bp, *obp; | 139 | char *bp, *obp; |
139 | int i, ps, pe, multiplier; | 140 | int i, ps, pe, multiplier; |
140 | u16 c; | 141 | u16 c; |
141 | struct kbd_struct *kbd = kbd_table + fg_console; | 142 | int mode; |
142 | 143 | ||
143 | poke_blanked_console(); | 144 | poke_blanked_console(); |
144 | 145 | ||
@@ -182,7 +183,11 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t | |||
182 | clear_selection(); | 183 | clear_selection(); |
183 | sel_cons = vc_cons[fg_console].d; | 184 | sel_cons = vc_cons[fg_console].d; |
184 | } | 185 | } |
185 | use_unicode = kbd && kbd->kbdmode == VC_UNICODE; | 186 | mode = vt_do_kdgkbmode(fg_console); |
187 | if (mode == K_UNICODE) | ||
188 | use_unicode = 1; | ||
189 | else | ||
190 | use_unicode = 0; | ||
186 | 191 | ||
187 | switch (sel_mode) | 192 | switch (sel_mode) |
188 | { | 193 | { |
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e716839fab6e..ecdcc8a8f0ca 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c | |||
@@ -1028,9 +1028,9 @@ void vc_deallocate(unsigned int currcons) | |||
1028 | * VT102 emulator | 1028 | * VT102 emulator |
1029 | */ | 1029 | */ |
1030 | 1030 | ||
1031 | #define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) | 1031 | #define set_kbd(vc, x) vt_set_kbd_mode_bit((vc)->vc_num, (x)) |
1032 | #define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) | 1032 | #define clr_kbd(vc, x) vt_clr_kbd_mode_bit((vc)->vc_num, (x)) |
1033 | #define is_kbd(vc, x) vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) | 1033 | #define is_kbd(vc, x) vt_get_kbd_mode_bit((vc)->vc_num, (x)) |
1034 | 1034 | ||
1035 | #define decarm VC_REPEAT | 1035 | #define decarm VC_REPEAT |
1036 | #define decckm VC_CKMODE | 1036 | #define decckm VC_CKMODE |
@@ -1652,16 +1652,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) | |||
1652 | vc->vc_deccm = global_cursor_default; | 1652 | vc->vc_deccm = global_cursor_default; |
1653 | vc->vc_decim = 0; | 1653 | vc->vc_decim = 0; |
1654 | 1654 | ||
1655 | set_kbd(vc, decarm); | 1655 | vt_reset_keyboard(vc->vc_num); |
1656 | clr_kbd(vc, decckm); | ||
1657 | clr_kbd(vc, kbdapplic); | ||
1658 | clr_kbd(vc, lnm); | ||
1659 | kbd_table[vc->vc_num].lockstate = 0; | ||
1660 | kbd_table[vc->vc_num].slockstate = 0; | ||
1661 | kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS; | ||
1662 | kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate; | ||
1663 | /* do not do set_leds here because this causes an endless tasklet loop | ||
1664 | when the keyboard hasn't been initialized yet */ | ||
1665 | 1656 | ||
1666 | vc->vc_cursor_type = cur_default; | 1657 | vc->vc_cursor_type = cur_default; |
1667 | vc->vc_complement_mask = vc->vc_s_complement_mask; | 1658 | vc->vc_complement_mask = vc->vc_s_complement_mask; |
@@ -1979,7 +1970,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) | |||
1979 | case 'q': /* DECLL - but only 3 leds */ | 1970 | case 'q': /* DECLL - but only 3 leds */ |
1980 | /* map 0,1,2,3 to 0,1,2,4 */ | 1971 | /* map 0,1,2,3 to 0,1,2,4 */ |
1981 | if (vc->vc_par[0] < 4) | 1972 | if (vc->vc_par[0] < 4) |
1982 | setledstate(kbd_table + vc->vc_num, | 1973 | vt_set_led_state(vc->vc_num, |
1983 | (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4); | 1974 | (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4); |
1984 | return; | 1975 | return; |
1985 | case 'r': | 1976 | case 'r': |
@@ -2642,7 +2633,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) | |||
2642 | * kernel-internal variable; programs not closely | 2633 | * kernel-internal variable; programs not closely |
2643 | * related to the kernel should not use this. | 2634 | * related to the kernel should not use this. |
2644 | */ | 2635 | */ |
2645 | data = shift_state; | 2636 | data = vt_get_shift_state(); |
2646 | ret = __put_user(data, p); | 2637 | ret = __put_user(data, p); |
2647 | break; | 2638 | break; |
2648 | case TIOCL_GETMOUSEREPORTING: | 2639 | case TIOCL_GETMOUSEREPORTING: |
@@ -2753,8 +2744,7 @@ static void con_stop(struct tty_struct *tty) | |||
2753 | console_num = tty->index; | 2744 | console_num = tty->index; |
2754 | if (!vc_cons_allocated(console_num)) | 2745 | if (!vc_cons_allocated(console_num)) |
2755 | return; | 2746 | return; |
2756 | set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); | 2747 | vt_kbd_con_stop(console_num); |
2757 | set_leds(); | ||
2758 | } | 2748 | } |
2759 | 2749 | ||
2760 | /* | 2750 | /* |
@@ -2768,8 +2758,7 @@ static void con_start(struct tty_struct *tty) | |||
2768 | console_num = tty->index; | 2758 | console_num = tty->index; |
2769 | if (!vc_cons_allocated(console_num)) | 2759 | if (!vc_cons_allocated(console_num)) |
2770 | return; | 2760 | return; |
2771 | clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); | 2761 | vt_kbd_con_start(console_num); |
2772 | set_leds(); | ||
2773 | } | 2762 | } |
2774 | 2763 | ||
2775 | static void con_flush_chars(struct tty_struct *tty) | 2764 | static void con_flush_chars(struct tty_struct *tty) |
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 80af0f9bef5b..28ca0aa8664f 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c | |||
@@ -195,232 +195,7 @@ int vt_waitactive(int n) | |||
195 | #define GPLAST 0x3df | 195 | #define GPLAST 0x3df |
196 | #define GPNUM (GPLAST - GPFIRST + 1) | 196 | #define GPNUM (GPLAST - GPFIRST + 1) |
197 | 197 | ||
198 | #define i (tmp.kb_index) | ||
199 | #define s (tmp.kb_table) | ||
200 | #define v (tmp.kb_value) | ||
201 | static inline int | ||
202 | do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd) | ||
203 | { | ||
204 | struct kbentry tmp; | ||
205 | ushort *key_map, val, ov; | ||
206 | |||
207 | if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) | ||
208 | return -EFAULT; | ||
209 | |||
210 | if (!capable(CAP_SYS_TTY_CONFIG)) | ||
211 | perm = 0; | ||
212 | |||
213 | switch (cmd) { | ||
214 | case KDGKBENT: | ||
215 | key_map = key_maps[s]; | ||
216 | if (key_map) { | ||
217 | val = U(key_map[i]); | ||
218 | if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) | ||
219 | val = K_HOLE; | ||
220 | } else | ||
221 | val = (i ? K_HOLE : K_NOSUCHMAP); | ||
222 | return put_user(val, &user_kbe->kb_value); | ||
223 | case KDSKBENT: | ||
224 | if (!perm) | ||
225 | return -EPERM; | ||
226 | if (!i && v == K_NOSUCHMAP) { | ||
227 | /* deallocate map */ | ||
228 | key_map = key_maps[s]; | ||
229 | if (s && key_map) { | ||
230 | key_maps[s] = NULL; | ||
231 | if (key_map[0] == U(K_ALLOCATED)) { | ||
232 | kfree(key_map); | ||
233 | keymap_count--; | ||
234 | } | ||
235 | } | ||
236 | break; | ||
237 | } | ||
238 | |||
239 | if (KTYP(v) < NR_TYPES) { | ||
240 | if (KVAL(v) > max_vals[KTYP(v)]) | ||
241 | return -EINVAL; | ||
242 | } else | ||
243 | if (kbd->kbdmode != VC_UNICODE) | ||
244 | return -EINVAL; | ||
245 | |||
246 | /* ++Geert: non-PC keyboards may generate keycode zero */ | ||
247 | #if !defined(__mc68000__) && !defined(__powerpc__) | ||
248 | /* assignment to entry 0 only tests validity of args */ | ||
249 | if (!i) | ||
250 | break; | ||
251 | #endif | ||
252 | |||
253 | if (!(key_map = key_maps[s])) { | ||
254 | int j; | ||
255 | |||
256 | if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && | ||
257 | !capable(CAP_SYS_RESOURCE)) | ||
258 | return -EPERM; | ||
259 | |||
260 | key_map = kmalloc(sizeof(plain_map), | ||
261 | GFP_KERNEL); | ||
262 | if (!key_map) | ||
263 | return -ENOMEM; | ||
264 | key_maps[s] = key_map; | ||
265 | key_map[0] = U(K_ALLOCATED); | ||
266 | for (j = 1; j < NR_KEYS; j++) | ||
267 | key_map[j] = U(K_HOLE); | ||
268 | keymap_count++; | ||
269 | } | ||
270 | ov = U(key_map[i]); | ||
271 | if (v == ov) | ||
272 | break; /* nothing to do */ | ||
273 | /* | ||
274 | * Attention Key. | ||
275 | */ | ||
276 | if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) | ||
277 | return -EPERM; | ||
278 | key_map[i] = U(v); | ||
279 | if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) | ||
280 | compute_shiftstate(); | ||
281 | break; | ||
282 | } | ||
283 | return 0; | ||
284 | } | ||
285 | #undef i | ||
286 | #undef s | ||
287 | #undef v | ||
288 | |||
289 | static inline int | ||
290 | do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm) | ||
291 | { | ||
292 | struct kbkeycode tmp; | ||
293 | int kc = 0; | ||
294 | |||
295 | if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) | ||
296 | return -EFAULT; | ||
297 | switch (cmd) { | ||
298 | case KDGETKEYCODE: | ||
299 | kc = getkeycode(tmp.scancode); | ||
300 | if (kc >= 0) | ||
301 | kc = put_user(kc, &user_kbkc->keycode); | ||
302 | break; | ||
303 | case KDSETKEYCODE: | ||
304 | if (!perm) | ||
305 | return -EPERM; | ||
306 | kc = setkeycode(tmp.scancode, tmp.keycode); | ||
307 | break; | ||
308 | } | ||
309 | return kc; | ||
310 | } | ||
311 | |||
312 | static inline int | ||
313 | do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) | ||
314 | { | ||
315 | struct kbsentry *kbs; | ||
316 | char *p; | ||
317 | u_char *q; | ||
318 | u_char __user *up; | ||
319 | int sz; | ||
320 | int delta; | ||
321 | char *first_free, *fj, *fnw; | ||
322 | int i, j, k; | ||
323 | int ret; | ||
324 | |||
325 | if (!capable(CAP_SYS_TTY_CONFIG)) | ||
326 | perm = 0; | ||
327 | |||
328 | kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); | ||
329 | if (!kbs) { | ||
330 | ret = -ENOMEM; | ||
331 | goto reterr; | ||
332 | } | ||
333 | |||
334 | /* we mostly copy too much here (512bytes), but who cares ;) */ | ||
335 | if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { | ||
336 | ret = -EFAULT; | ||
337 | goto reterr; | ||
338 | } | ||
339 | kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; | ||
340 | i = kbs->kb_func; | ||
341 | |||
342 | switch (cmd) { | ||
343 | case KDGKBSENT: | ||
344 | sz = sizeof(kbs->kb_string) - 1; /* sz should have been | ||
345 | a struct member */ | ||
346 | up = user_kdgkb->kb_string; | ||
347 | p = func_table[i]; | ||
348 | if(p) | ||
349 | for ( ; *p && sz; p++, sz--) | ||
350 | if (put_user(*p, up++)) { | ||
351 | ret = -EFAULT; | ||
352 | goto reterr; | ||
353 | } | ||
354 | if (put_user('\0', up)) { | ||
355 | ret = -EFAULT; | ||
356 | goto reterr; | ||
357 | } | ||
358 | kfree(kbs); | ||
359 | return ((p && *p) ? -EOVERFLOW : 0); | ||
360 | case KDSKBSENT: | ||
361 | if (!perm) { | ||
362 | ret = -EPERM; | ||
363 | goto reterr; | ||
364 | } | ||
365 | 198 | ||
366 | q = func_table[i]; | ||
367 | first_free = funcbufptr + (funcbufsize - funcbufleft); | ||
368 | for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) | ||
369 | ; | ||
370 | if (j < MAX_NR_FUNC) | ||
371 | fj = func_table[j]; | ||
372 | else | ||
373 | fj = first_free; | ||
374 | |||
375 | delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); | ||
376 | if (delta <= funcbufleft) { /* it fits in current buf */ | ||
377 | if (j < MAX_NR_FUNC) { | ||
378 | memmove(fj + delta, fj, first_free - fj); | ||
379 | for (k = j; k < MAX_NR_FUNC; k++) | ||
380 | if (func_table[k]) | ||
381 | func_table[k] += delta; | ||
382 | } | ||
383 | if (!q) | ||
384 | func_table[i] = fj; | ||
385 | funcbufleft -= delta; | ||
386 | } else { /* allocate a larger buffer */ | ||
387 | sz = 256; | ||
388 | while (sz < funcbufsize - funcbufleft + delta) | ||
389 | sz <<= 1; | ||
390 | fnw = kmalloc(sz, GFP_KERNEL); | ||
391 | if(!fnw) { | ||
392 | ret = -ENOMEM; | ||
393 | goto reterr; | ||
394 | } | ||
395 | |||
396 | if (!q) | ||
397 | func_table[i] = fj; | ||
398 | if (fj > funcbufptr) | ||
399 | memmove(fnw, funcbufptr, fj - funcbufptr); | ||
400 | for (k = 0; k < j; k++) | ||
401 | if (func_table[k]) | ||
402 | func_table[k] = fnw + (func_table[k] - funcbufptr); | ||
403 | |||
404 | if (first_free > fj) { | ||
405 | memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); | ||
406 | for (k = j; k < MAX_NR_FUNC; k++) | ||
407 | if (func_table[k]) | ||
408 | func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; | ||
409 | } | ||
410 | if (funcbufptr != func_buf) | ||
411 | kfree(funcbufptr); | ||
412 | funcbufptr = fnw; | ||
413 | funcbufleft = funcbufleft - delta + sz - funcbufsize; | ||
414 | funcbufsize = sz; | ||
415 | } | ||
416 | strcpy(func_table[i], kbs->kb_string); | ||
417 | break; | ||
418 | } | ||
419 | ret = 0; | ||
420 | reterr: | ||
421 | kfree(kbs); | ||
422 | return ret; | ||
423 | } | ||
424 | 199 | ||
425 | static inline int | 200 | static inline int |
426 | do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) | 201 | do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) |
@@ -497,7 +272,6 @@ int vt_ioctl(struct tty_struct *tty, | |||
497 | { | 272 | { |
498 | struct vc_data *vc = tty->driver_data; | 273 | struct vc_data *vc = tty->driver_data; |
499 | struct console_font_op op; /* used in multiple places here */ | 274 | struct console_font_op op; /* used in multiple places here */ |
500 | struct kbd_struct * kbd; | ||
501 | unsigned int console; | 275 | unsigned int console; |
502 | unsigned char ucval; | 276 | unsigned char ucval; |
503 | unsigned int uival; | 277 | unsigned int uival; |
@@ -523,7 +297,6 @@ int vt_ioctl(struct tty_struct *tty, | |||
523 | if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) | 297 | if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) |
524 | perm = 1; | 298 | perm = 1; |
525 | 299 | ||
526 | kbd = kbd_table + console; | ||
527 | switch (cmd) { | 300 | switch (cmd) { |
528 | case TIOCLINUX: | 301 | case TIOCLINUX: |
529 | ret = tioclinux(tty, arg); | 302 | ret = tioclinux(tty, arg); |
@@ -565,7 +338,8 @@ int vt_ioctl(struct tty_struct *tty, | |||
565 | * this is naive. | 338 | * this is naive. |
566 | */ | 339 | */ |
567 | ucval = KB_101; | 340 | ucval = KB_101; |
568 | goto setchar; | 341 | ret = put_user(ucval, (char __user *)arg); |
342 | break; | ||
569 | 343 | ||
570 | /* | 344 | /* |
571 | * These cannot be implemented on any machine that implements | 345 | * These cannot be implemented on any machine that implements |
@@ -670,68 +444,25 @@ int vt_ioctl(struct tty_struct *tty, | |||
670 | case KDSKBMODE: | 444 | case KDSKBMODE: |
671 | if (!perm) | 445 | if (!perm) |
672 | goto eperm; | 446 | goto eperm; |
673 | switch(arg) { | 447 | ret = vt_do_kdskbmode(console, arg); |
674 | case K_RAW: | 448 | if (ret == 0) |
675 | kbd->kbdmode = VC_RAW; | 449 | tty_ldisc_flush(tty); |
676 | break; | ||
677 | case K_MEDIUMRAW: | ||
678 | kbd->kbdmode = VC_MEDIUMRAW; | ||
679 | break; | ||
680 | case K_XLATE: | ||
681 | kbd->kbdmode = VC_XLATE; | ||
682 | compute_shiftstate(); | ||
683 | break; | ||
684 | case K_UNICODE: | ||
685 | kbd->kbdmode = VC_UNICODE; | ||
686 | compute_shiftstate(); | ||
687 | break; | ||
688 | case K_OFF: | ||
689 | kbd->kbdmode = VC_OFF; | ||
690 | break; | ||
691 | default: | ||
692 | ret = -EINVAL; | ||
693 | goto out; | ||
694 | } | ||
695 | tty_ldisc_flush(tty); | ||
696 | break; | 450 | break; |
697 | 451 | ||
698 | case KDGKBMODE: | 452 | case KDGKBMODE: |
699 | switch (kbd->kbdmode) { | 453 | uival = vt_do_kdgkbmode(console); |
700 | case VC_RAW: | 454 | ret = put_user(uival, (int __user *)arg); |
701 | uival = K_RAW; | 455 | break; |
702 | break; | ||
703 | case VC_MEDIUMRAW: | ||
704 | uival = K_MEDIUMRAW; | ||
705 | break; | ||
706 | case VC_UNICODE: | ||
707 | uival = K_UNICODE; | ||
708 | break; | ||
709 | case VC_OFF: | ||
710 | uival = K_OFF; | ||
711 | break; | ||
712 | default: | ||
713 | uival = K_XLATE; | ||
714 | break; | ||
715 | } | ||
716 | goto setint; | ||
717 | 456 | ||
718 | /* this could be folded into KDSKBMODE, but for compatibility | 457 | /* this could be folded into KDSKBMODE, but for compatibility |
719 | reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ | 458 | reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ |
720 | case KDSKBMETA: | 459 | case KDSKBMETA: |
721 | switch(arg) { | 460 | ret = vt_do_kdskbmeta(console, arg); |
722 | case K_METABIT: | ||
723 | clr_vc_kbd_mode(kbd, VC_META); | ||
724 | break; | ||
725 | case K_ESCPREFIX: | ||
726 | set_vc_kbd_mode(kbd, VC_META); | ||
727 | break; | ||
728 | default: | ||
729 | ret = -EINVAL; | ||
730 | } | ||
731 | break; | 461 | break; |
732 | 462 | ||
733 | case KDGKBMETA: | 463 | case KDGKBMETA: |
734 | uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); | 464 | /* FIXME: should review whether this is worth locking */ |
465 | uival = vt_do_kdgkbmeta(console); | ||
735 | setint: | 466 | setint: |
736 | ret = put_user(uival, (int __user *)arg); | 467 | ret = put_user(uival, (int __user *)arg); |
737 | break; | 468 | break; |
@@ -740,17 +471,17 @@ int vt_ioctl(struct tty_struct *tty, | |||
740 | case KDSETKEYCODE: | 471 | case KDSETKEYCODE: |
741 | if(!capable(CAP_SYS_TTY_CONFIG)) | 472 | if(!capable(CAP_SYS_TTY_CONFIG)) |
742 | perm = 0; | 473 | perm = 0; |
743 | ret = do_kbkeycode_ioctl(cmd, up, perm); | 474 | ret = vt_do_kbkeycode_ioctl(cmd, up, perm); |
744 | break; | 475 | break; |
745 | 476 | ||
746 | case KDGKBENT: | 477 | case KDGKBENT: |
747 | case KDSKBENT: | 478 | case KDSKBENT: |
748 | ret = do_kdsk_ioctl(cmd, up, perm, kbd); | 479 | ret = vt_do_kdsk_ioctl(cmd, up, perm, console); |
749 | break; | 480 | break; |
750 | 481 | ||
751 | case KDGKBSENT: | 482 | case KDGKBSENT: |
752 | case KDSKBSENT: | 483 | case KDSKBSENT: |
753 | ret = do_kdgkb_ioctl(cmd, up, perm); | 484 | ret = vt_do_kdgkb_ioctl(cmd, up, perm); |
754 | break; | 485 | break; |
755 | 486 | ||
756 | /* Diacritical processing. Handled in keyboard.c as it has | 487 | /* Diacritical processing. Handled in keyboard.c as it has |
@@ -765,33 +496,10 @@ int vt_ioctl(struct tty_struct *tty, | |||
765 | /* the ioctls below read/set the flags usually shown in the leds */ | 496 | /* the ioctls below read/set the flags usually shown in the leds */ |
766 | /* don't use them - they will go away without warning */ | 497 | /* don't use them - they will go away without warning */ |
767 | case KDGKBLED: | 498 | case KDGKBLED: |
768 | ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); | ||
769 | goto setchar; | ||
770 | |||
771 | case KDSKBLED: | 499 | case KDSKBLED: |
772 | if (!perm) | ||
773 | goto eperm; | ||
774 | if (arg & ~0x77) { | ||
775 | ret = -EINVAL; | ||
776 | break; | ||
777 | } | ||
778 | kbd->ledflagstate = (arg & 7); | ||
779 | kbd->default_ledflagstate = ((arg >> 4) & 7); | ||
780 | set_leds(); | ||
781 | break; | ||
782 | |||
783 | /* the ioctls below only set the lights, not the functions */ | ||
784 | /* for those, see KDGKBLED and KDSKBLED above */ | ||
785 | case KDGETLED: | 500 | case KDGETLED: |
786 | ucval = getledstate(); | ||
787 | setchar: | ||
788 | ret = put_user(ucval, (char __user *)arg); | ||
789 | break; | ||
790 | |||
791 | case KDSETLED: | 501 | case KDSETLED: |
792 | if (!perm) | 502 | ret = vt_do_kdskled(console, cmd, arg, perm); |
793 | goto eperm; | ||
794 | setledstate(kbd, arg); | ||
795 | break; | 503 | break; |
796 | 504 | ||
797 | /* | 505 | /* |
@@ -1286,7 +994,7 @@ eperm: | |||
1286 | void reset_vc(struct vc_data *vc) | 994 | void reset_vc(struct vc_data *vc) |
1287 | { | 995 | { |
1288 | vc->vc_mode = KD_TEXT; | 996 | vc->vc_mode = KD_TEXT; |
1289 | kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; | 997 | vt_reset_unicode(vc->vc_num); |
1290 | vc->vt_mode.mode = VT_AUTO; | 998 | vc->vt_mode.mode = VT_AUTO; |
1291 | vc->vt_mode.waitv = 0; | 999 | vc->vt_mode.waitv = 0; |
1292 | vc->vt_mode.relsig = 0; | 1000 | vc->vt_mode.relsig = 0; |
@@ -1309,6 +1017,7 @@ void vc_SAK(struct work_struct *work) | |||
1309 | console_lock(); | 1017 | console_lock(); |
1310 | vc = vc_con->d; | 1018 | vc = vc_con->d; |
1311 | if (vc) { | 1019 | if (vc) { |
1020 | /* FIXME: review tty ref counting */ | ||
1312 | tty = vc->port.tty; | 1021 | tty = vc->port.tty; |
1313 | /* | 1022 | /* |
1314 | * SAK should also work in all raw modes and reset | 1023 | * SAK should also work in all raw modes and reset |