* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / drivers / char / amikeyb.c
blob42e1ea7c85806f2752120f04366dd4f4159327f2
1 /*
2 * linux/arch/m68k/amiga/amikeyb.c
4 * Amiga Keyboard driver for Linux/m68k
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 */
12 * Amiga support by Hamish Macdonald
15 #include <linux/types.h>
16 #include <linux/sched.h>
17 #include <linux/interrupt.h>
18 #include <linux/errno.h>
19 #include <linux/keyboard.h>
20 #include <linux/delay.h>
21 #include <linux/timer.h>
22 #include <linux/kd.h>
23 #include <linux/random.h>
24 #include <linux/kernel.h>
25 #include <linux/init.h>
26 #include <linux/kbd_ll.h>
28 #include <asm/amigaints.h>
29 #include <asm/amigahw.h>
30 #include <asm/irq.h>
32 #define AMIKEY_CAPS (0x62)
33 #define BREAK_MASK (0x80)
34 #define RESET_WARNING (0xf0) /* before rotation */
36 static u_short amiplain_map[NR_KEYS] __initdata = {
37 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
38 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf05c, 0xf200, 0xf300,
39 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
40 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf200, 0xf301, 0xf302, 0xf303,
41 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b,
42 0xfb6c, 0xf03b, 0xf027, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
43 0xf200, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d,
44 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
45 0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
46 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
47 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
48 0xf108, 0xf109, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf30a, 0xf11b,
49 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
50 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
51 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
52 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
55 static u_short amishift_map[NR_KEYS] __initdata = {
56 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026,
57 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07c, 0xf200, 0xf300,
58 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
59 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf200, 0xf301, 0xf302, 0xf303,
60 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b,
61 0xfb4c, 0xf03a, 0xf022, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
62 0xf200, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d,
63 0xf03c, 0xf03e, 0xf03f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
64 0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
65 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
66 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111,
67 0xf112, 0xf113, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf203,
68 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
69 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
70 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
71 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
74 static u_short amialtgr_map[NR_KEYS] __initdata = {
75 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, 0xf07b,
76 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, 0xf300,
77 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
78 0xf200, 0xf200, 0xf200, 0xf07e, 0xf200, 0xf301, 0xf302, 0xf303,
79 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
80 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
81 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
82 0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
83 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
84 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
85 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513,
86 0xf514, 0xf515, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
87 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
88 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
89 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
90 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
93 static u_short amictrl_map[NR_KEYS] __initdata = {
94 0xf000, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
95 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf01c, 0xf200, 0xf300,
96 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
97 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf200, 0xf301, 0xf302, 0xf303,
98 0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b,
99 0xf00c, 0xf200, 0xf007, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
100 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d,
101 0xf200, 0xf200, 0xf07f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
102 0xf000, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
103 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
104 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
105 0xf108, 0xf109, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf202,
106 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
107 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
108 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
109 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
112 static u_short amishift_ctrl_map[NR_KEYS] __initdata = {
113 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
114 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
115 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
116 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
117 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
118 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
119 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
120 0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
121 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
122 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
123 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
124 0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
125 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
126 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
127 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
128 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
131 static u_short amialt_map[NR_KEYS] __initdata = {
132 0xf860, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, 0xf837,
133 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf85c, 0xf200, 0xf900,
134 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
135 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf200, 0xf901, 0xf902, 0xf903,
136 0xf861, 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b,
137 0xf86c, 0xf83b, 0xf827, 0xf200, 0xf200, 0xf904, 0xf905, 0xf906,
138 0xf200, 0xf87a, 0xf878, 0xf863, 0xf876, 0xf862, 0xf86e, 0xf86d,
139 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf310, 0xf907, 0xf908, 0xf909,
140 0xf820, 0xf87f, 0xf809, 0xf30e, 0xf80d, 0xf81b, 0xf87f, 0xf200,
141 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
142 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
143 0xf508, 0xf509, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
144 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
145 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
146 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
147 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
150 static u_short amictrl_alt_map[NR_KEYS] __initdata = {
151 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
152 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
153 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
154 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
155 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
156 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
157 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
158 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, 0xf307, 0xf308, 0xf309,
159 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
160 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
161 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
162 0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
163 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
164 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
165 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
166 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
169 #define DEFAULT_KEYB_REP_DELAY (HZ/4)
170 #define DEFAULT_KEYB_REP_RATE (HZ/25)
172 /* These could be settable by some ioctl() in future... */
173 static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
174 static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
176 static unsigned char rep_scancode;
177 static void amikeyb_rep(unsigned long ignore);
178 static struct timer_list amikeyb_rep_timer = {NULL, NULL, 0, 0, amikeyb_rep};
180 static void amikeyb_rep(unsigned long ignore)
182 unsigned long flags;
183 save_flags(flags);
184 cli();
186 kbd_pt_regs = NULL;
188 amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
189 amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
190 add_timer(&amikeyb_rep_timer);
191 handle_scancode(rep_scancode, 1);
193 restore_flags(flags);
196 static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
198 unsigned char scancode, break_flag, keycode;
199 static int reset_warning = 0;
201 /* save frame for register dump */
202 kbd_pt_regs = fp;
204 /* get and invert scancode (keyboard is active low) */
205 scancode = ~ciaa.sdr;
207 /* switch SP pin to output for handshake */
208 ciaa.cra |= 0x40;
210 #if 0 /* No longer used */
212 * On receipt of the second RESET_WARNING, we must not pull KDAT high
213 * again to delay the hard reset as long as possible.
215 * Note that not all keyboards send reset warnings...
217 if (reset_warning)
218 if (scancode == RESET_WARNING) {
219 printk(KERN_ALERT "amikeyb: Ctrl-Amiga-Amiga reset warning!!\n"
220 "The system will be reset within 10 seconds!!\n");
221 /* Panic doesn't sync from within an interrupt, so we do nothing */
222 return;
223 } else
224 /* Probably a mistake, cancel the alert */
225 reset_warning = 0;
226 #endif
228 /* wait until 85 us have expired */
229 udelay(85);
230 /* switch CIA serial port to input mode */
231 ciaa.cra &= ~0x40;
233 mark_bh(KEYBOARD_BH);
235 /* rotate scan code to get up/down bit in proper position */
236 scancode = ((scancode >> 1) & 0x7f) | ((scancode << 7) & 0x80);
239 * Check make/break first
241 break_flag = scancode & BREAK_MASK;
242 keycode = scancode & (unsigned char)~BREAK_MASK;
244 if (keycode == AMIKEY_CAPS) {
245 /* if the key is CAPS, fake a press/release. */
246 handle_scancode(AMIKEY_CAPS, 1);
247 handle_scancode(AMIKEY_CAPS, 0);
248 } else if (keycode < 0x78) {
249 /* handle repeat */
250 if (break_flag) {
251 del_timer(&amikeyb_rep_timer);
252 rep_scancode = 0;
253 } else {
254 del_timer(&amikeyb_rep_timer);
255 rep_scancode = keycode;
256 amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
257 amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
258 add_timer(&amikeyb_rep_timer);
260 handle_scancode(keycode, !break_flag);
261 } else
262 switch (keycode) {
263 case 0x78:
264 reset_warning = 1;
265 break;
266 case 0x79:
267 printk(KERN_WARNING "amikeyb: keyboard lost sync\n");
268 break;
269 case 0x7a:
270 printk(KERN_WARNING "amikeyb: keyboard buffer overflow\n");
271 break;
272 #if 0 /* obsolete according to the HRM */
273 case 0x7b:
274 printk(KERN_WARNING "amikeyb: keyboard controller failure\n");
275 break;
276 #endif
277 case 0x7c:
278 printk(KERN_ERR "amikeyb: keyboard selftest failure\n");
279 break;
280 case 0x7d:
281 printk(KERN_INFO "amikeyb: initiate power-up key stream\n");
282 break;
283 case 0x7e:
284 printk(KERN_INFO "amikeyb: terminate power-up key stream\n");
285 break;
286 #if 0 /* obsolete according to the HRM */
287 case 0x7f:
288 printk(KERN_WARNING "amikeyb: keyboard interrupt\n");
289 break;
290 #endif
291 default:
292 printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
293 scancode);
294 break;
298 int __init amiga_keyb_init(void)
300 if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
301 return -EIO;
303 /* setup key map */
304 memcpy(key_maps[0], amiplain_map, sizeof(plain_map));
305 memcpy(key_maps[1], amishift_map, sizeof(plain_map));
306 memcpy(key_maps[2], amialtgr_map, sizeof(plain_map));
307 memcpy(key_maps[4], amictrl_map, sizeof(plain_map));
308 memcpy(key_maps[5], amishift_ctrl_map, sizeof(plain_map));
309 memcpy(key_maps[8], amialt_map, sizeof(plain_map));
310 memcpy(key_maps[12], amictrl_alt_map, sizeof(plain_map));
313 * Initialize serial data direction.
315 ciaa.cra &= ~0x41; /* serial data in, turn off TA */
318 * arrange for processing of keyboard interrupt
320 request_irq(IRQ_AMIGA_CIAA_SP, keyboard_interrupt, 0, "keyboard", NULL);
322 return 0;
325 int amiga_kbdrate( struct kbd_repeat *k )
327 if (k->delay > 0) {
328 /* convert from msec to jiffies */
329 key_repeat_delay = (k->delay * HZ + 500) / 1000;
330 if (key_repeat_delay < 1)
331 key_repeat_delay = 1;
333 if (k->rate > 0) {
334 key_repeat_rate = (k->rate * HZ + 500) / 1000;
335 if (key_repeat_rate < 1)
336 key_repeat_rate = 1;
339 k->delay = key_repeat_delay * 1000 / HZ;
340 k->rate = key_repeat_rate * 1000 / HZ;
342 return( 0 );