1 | /* |
---|
2 | * linux/drivers/char/vt.c |
---|
3 | * |
---|
4 | * Copyright (C) 1992 obz under the linux copyright |
---|
5 | * |
---|
6 | * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 |
---|
7 | * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 |
---|
8 | * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 |
---|
9 | * Some code moved for less code duplication - Andi Kleen - Mar 1997 |
---|
10 | * |
---|
11 | * |
---|
12 | * by: Rosimildo da Silva -- |
---|
13 | * Ported to RTEMS to provide the basic interface to the console |
---|
14 | * driver. Removed all stuff not required, such as VT_, Fonts, etc. |
---|
15 | */ |
---|
16 | |
---|
17 | #include <string.h> /* memcpy */ |
---|
18 | #include <sys/types.h> |
---|
19 | #include <errno.h> |
---|
20 | |
---|
21 | #include <i386_io.h> |
---|
22 | #include <rtems.h> |
---|
23 | #include <rtems/kd.h> |
---|
24 | #include <rtems/keyboard.h> |
---|
25 | |
---|
26 | /* |
---|
27 | * Console (vt and kd) routines, as defined by USL SVR4 manual, and by |
---|
28 | * experimentation and study of X386 SYSV handling. |
---|
29 | * |
---|
30 | * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and |
---|
31 | * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, |
---|
32 | * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will |
---|
33 | * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to |
---|
34 | * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using |
---|
35 | * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing |
---|
36 | * to the current console is done by the main ioctl code. |
---|
37 | */ |
---|
38 | |
---|
39 | struct vt_struct *vt_cons[MAX_NR_CONSOLES]; |
---|
40 | |
---|
41 | /* Keyboard type: Default is KB_101, but can be set by machine |
---|
42 | * specific code. |
---|
43 | */ |
---|
44 | unsigned char keyboard_type = KB_101; |
---|
45 | |
---|
46 | /* |
---|
47 | * Generates sound of some frequency for some number of clock ticks |
---|
48 | * |
---|
49 | * If freq is 0, will turn off sound, else will turn it on for that time. |
---|
50 | * If msec is 0, will return immediately, else will sleep for msec time, then |
---|
51 | * turn sound off. |
---|
52 | * |
---|
53 | * We also return immediately, which is what was implied within the X |
---|
54 | * comments - KDMKTONE doesn't put the process to sleep. |
---|
55 | */ |
---|
56 | |
---|
57 | #if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \ |
---|
58 | || (defined(__mips__) && !defined(CONFIG_SGI)) |
---|
59 | |
---|
60 | static void |
---|
61 | kd_nosound(unsigned long ignored) |
---|
62 | { |
---|
63 | /* disable counter 2 */ |
---|
64 | outb(inb_p(0x61)&0xFC, 0x61); |
---|
65 | return; |
---|
66 | } |
---|
67 | |
---|
68 | void |
---|
69 | _kd_mksound(unsigned int hz, unsigned int ticks) |
---|
70 | { |
---|
71 | unsigned int count = 0; |
---|
72 | rtems_interrupt_level level; |
---|
73 | |
---|
74 | if (hz > 20 && hz < 32767) |
---|
75 | count = 1193180 / hz; |
---|
76 | |
---|
77 | rtems_interrupt_disable(level); |
---|
78 | /* del_timer(&sound_timer); */ |
---|
79 | if (count) { |
---|
80 | /* enable counter 2 */ |
---|
81 | outb_p(inb_p(0x61)|3, 0x61); |
---|
82 | /* set command for counter 2, 2 byte write */ |
---|
83 | outb_p(0xB6, 0x43); |
---|
84 | /* select desired HZ */ |
---|
85 | outb_p(count & 0xff, 0x42); |
---|
86 | outb((count >> 8) & 0xff, 0x42); |
---|
87 | |
---|
88 | /* |
---|
89 | if (ticks) { |
---|
90 | sound_timer.expires = jiffies+ticks; |
---|
91 | add_timer(&sound_timer); |
---|
92 | } |
---|
93 | */ |
---|
94 | } else |
---|
95 | kd_nosound(0); |
---|
96 | |
---|
97 | rtems_interrupt_enable(level); |
---|
98 | return; |
---|
99 | } |
---|
100 | |
---|
101 | #else |
---|
102 | |
---|
103 | void |
---|
104 | _kd_mksound(unsigned int hz, unsigned int ticks) |
---|
105 | { |
---|
106 | } |
---|
107 | |
---|
108 | #endif |
---|
109 | |
---|
110 | void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound; |
---|
111 | |
---|
112 | #define i (tmp.kb_index) |
---|
113 | #define s (tmp.kb_table) |
---|
114 | #define v (tmp.kb_value) |
---|
115 | static inline int |
---|
116 | do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kbd) |
---|
117 | { |
---|
118 | struct kbentry tmp; |
---|
119 | ushort *key_map, val; |
---|
120 | |
---|
121 | tmp = *user_kbe; |
---|
122 | if (i >= NR_KEYS) /* s cannot be >= MAX_NR_KEYMAPS */ |
---|
123 | return -EINVAL; |
---|
124 | |
---|
125 | switch (cmd) { |
---|
126 | case KDGKBENT: |
---|
127 | key_map = key_maps[s]; |
---|
128 | if (key_map) { |
---|
129 | val = U(key_map[i]); |
---|
130 | if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) |
---|
131 | val = K_HOLE; |
---|
132 | } else |
---|
133 | val = (i ? K_HOLE : K_NOSUCHMAP); |
---|
134 | user_kbe->kb_value = val; |
---|
135 | return 0; |
---|
136 | |
---|
137 | case KDSKBENT: |
---|
138 | return -EINVAL; |
---|
139 | } |
---|
140 | return 0; |
---|
141 | } |
---|
142 | #undef i |
---|
143 | #undef s |
---|
144 | #undef v |
---|
145 | |
---|
146 | #define HZ 100 |
---|
147 | |
---|
148 | static inline int |
---|
149 | do_kbkeycode_ioctl(int cmd, struct kbkeycode *user_kbkc, int perm) |
---|
150 | { |
---|
151 | struct kbkeycode tmp; |
---|
152 | int kc = 0; |
---|
153 | |
---|
154 | tmp = *user_kbkc; |
---|
155 | switch (cmd) { |
---|
156 | case KDGETKEYCODE: |
---|
157 | kc = getkeycode(tmp.scancode); |
---|
158 | if (kc >= 0) |
---|
159 | user_kbkc->keycode = kc; |
---|
160 | break; |
---|
161 | case KDSETKEYCODE: |
---|
162 | if (!perm) |
---|
163 | return -EPERM; |
---|
164 | kc = setkeycode(tmp.scancode, tmp.keycode); |
---|
165 | break; |
---|
166 | } |
---|
167 | return kc; |
---|
168 | } |
---|
169 | |
---|
170 | static inline int |
---|
171 | do_kdgkb_ioctl(int cmd, struct kbsentry *user_kdgkb, int perm) |
---|
172 | { |
---|
173 | return -EINVAL; |
---|
174 | } |
---|
175 | |
---|
176 | /* |
---|
177 | * We handle the console-specific ioctl's here. We allow the |
---|
178 | * capability to modify any console, not just the fg_console. |
---|
179 | */ |
---|
180 | int vt_ioctl( unsigned int cmd, unsigned long arg) |
---|
181 | { |
---|
182 | int perm; |
---|
183 | unsigned int console; |
---|
184 | unsigned char ucval; |
---|
185 | struct kbd_struct * kbd; |
---|
186 | |
---|
187 | console = 0; |
---|
188 | /* |
---|
189 | * To have permissions to do most of the vt ioctls, we either have |
---|
190 | * to be the owner of the tty, or super-user. |
---|
191 | */ |
---|
192 | perm = 1; |
---|
193 | kbd = kbd_table + console; |
---|
194 | switch (cmd) { |
---|
195 | case KIOCSOUND: |
---|
196 | if (!perm) |
---|
197 | return -EPERM; |
---|
198 | if (arg) |
---|
199 | arg = 1193180 / arg; |
---|
200 | kd_mksound(arg, 0); |
---|
201 | return 0; |
---|
202 | |
---|
203 | case KDMKTONE: |
---|
204 | if (!perm) |
---|
205 | return -EPERM; |
---|
206 | { |
---|
207 | unsigned int ticks, count; |
---|
208 | |
---|
209 | /* |
---|
210 | * Generate the tone for the appropriate number of ticks. |
---|
211 | * If the time is zero, turn off sound ourselves. |
---|
212 | */ |
---|
213 | ticks = HZ * ((arg >> 16) & 0xffff) / 1000; |
---|
214 | count = ticks ? (arg & 0xffff) : 0; |
---|
215 | if (count) |
---|
216 | count = 1193180 / count; |
---|
217 | kd_mksound(count, ticks); |
---|
218 | return 0; |
---|
219 | } |
---|
220 | |
---|
221 | case KDGKBTYPE: |
---|
222 | /* |
---|
223 | * this is naive. |
---|
224 | */ |
---|
225 | ucval = keyboard_type; |
---|
226 | goto setchar; |
---|
227 | |
---|
228 | case KDSETMODE: |
---|
229 | case KDGETMODE: |
---|
230 | return -EINVAL; |
---|
231 | |
---|
232 | case KDSKBMODE: |
---|
233 | if (!perm) |
---|
234 | return -EPERM; |
---|
235 | switch(arg) { |
---|
236 | case K_RAW: |
---|
237 | kbd->kbdmode = VC_RAW; |
---|
238 | break; |
---|
239 | case K_MEDIUMRAW: |
---|
240 | kbd->kbdmode = VC_MEDIUMRAW; |
---|
241 | break; |
---|
242 | case K_XLATE: |
---|
243 | kbd->kbdmode = VC_XLATE; |
---|
244 | compute_shiftstate(); |
---|
245 | break; |
---|
246 | case K_UNICODE: |
---|
247 | kbd->kbdmode = VC_UNICODE; |
---|
248 | compute_shiftstate(); |
---|
249 | break; |
---|
250 | default: |
---|
251 | return -EINVAL; |
---|
252 | } |
---|
253 | return 0; |
---|
254 | |
---|
255 | case KDGKBMODE: |
---|
256 | ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : |
---|
257 | (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW : |
---|
258 | (kbd->kbdmode == VC_UNICODE) ? K_UNICODE : |
---|
259 | K_XLATE); |
---|
260 | goto setint; |
---|
261 | |
---|
262 | /* this could be folded into KDSKBMODE, but for compatibility |
---|
263 | reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ |
---|
264 | case KDSKBMETA: |
---|
265 | switch(arg) { |
---|
266 | case K_METABIT: |
---|
267 | clr_vc_kbd_mode(kbd, VC_META); |
---|
268 | break; |
---|
269 | case K_ESCPREFIX: |
---|
270 | set_vc_kbd_mode(kbd, VC_META); |
---|
271 | break; |
---|
272 | default: |
---|
273 | return -EINVAL; |
---|
274 | } |
---|
275 | return 0; |
---|
276 | |
---|
277 | case KDGKBMETA: |
---|
278 | ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); |
---|
279 | setint: |
---|
280 | *(int *)arg = ucval; |
---|
281 | return 0; |
---|
282 | |
---|
283 | case KDGETKEYCODE: |
---|
284 | case KDSETKEYCODE: |
---|
285 | return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm); |
---|
286 | |
---|
287 | case KDGKBENT: |
---|
288 | case KDSKBENT: |
---|
289 | return do_kdsk_ioctl(cmd, (struct kbentry *)arg, perm, kbd); |
---|
290 | |
---|
291 | case KDGKBDIACR: |
---|
292 | { |
---|
293 | struct kbdiacrs *a = (struct kbdiacrs *)arg; |
---|
294 | a->kb_cnt = accent_table_size; |
---|
295 | memcpy( a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr) ); |
---|
296 | return 0; |
---|
297 | } |
---|
298 | |
---|
299 | case KDSKBDIACR: |
---|
300 | { |
---|
301 | struct kbdiacrs *a = (struct kbdiacrs *)arg; |
---|
302 | unsigned int ct; |
---|
303 | |
---|
304 | if (!perm) |
---|
305 | return -EPERM; |
---|
306 | ct = a->kb_cnt; |
---|
307 | if (ct >= MAX_DIACR) |
---|
308 | return -EINVAL; |
---|
309 | accent_table_size = ct; |
---|
310 | memcpy(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr)); |
---|
311 | return 0; |
---|
312 | } |
---|
313 | |
---|
314 | /* the ioctls below read/set the flags usually shown in the leds */ |
---|
315 | /* don't use them - they will go away without warning */ |
---|
316 | case KDGKBLED: |
---|
317 | ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); |
---|
318 | goto setchar; |
---|
319 | |
---|
320 | case KDSKBLED: |
---|
321 | if (!perm) |
---|
322 | return -EPERM; |
---|
323 | if (arg & ~0x77) |
---|
324 | return -EINVAL; |
---|
325 | kbd->ledflagstate = (arg & 7); |
---|
326 | kbd->default_ledflagstate = ((arg >> 4) & 7); |
---|
327 | set_leds(); |
---|
328 | return 0; |
---|
329 | |
---|
330 | /* the ioctls below only set the lights, not the functions */ |
---|
331 | /* for those, see KDGKBLED and KDSKBLED above */ |
---|
332 | case KDGETLED: |
---|
333 | ucval = getledstate(); |
---|
334 | setchar: |
---|
335 | *(char*)arg = ucval; |
---|
336 | return 0; |
---|
337 | |
---|
338 | case KDSETLED: |
---|
339 | if (!perm) |
---|
340 | return -EPERM; |
---|
341 | setledstate(kbd, arg); |
---|
342 | return 0; |
---|
343 | |
---|
344 | default: |
---|
345 | return -EINVAL; |
---|
346 | } |
---|
347 | } |
---|