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
12 * Amiga support by Hamish Macdonald
15 #include <linux/config.h>
16 #include <linux/types.h>
17 #include <linux/sched.h>
18 #include <linux/interrupt.h>
19 #include <linux/errno.h>
20 #include <linux/keyboard.h>
22 #include <linux/kbd_ll.h>
23 #include <linux/delay.h>
24 #include <linux/timer.h>
25 #include <linux/random.h>
26 #include <linux/kernel.h>
27 #include <linux/ioport.h>
28 #include <linux/init.h>
29 #include <linux/kbd_kern.h>
31 #include <asm/amigaints.h>
32 #include <asm/amigahw.h>
35 #define AMIKEY_CAPS (0x62)
36 #define BREAK_MASK (0x80)
37 #define RESET_WARNING (0xf0) /* before rotation */
39 static u_short amiplain_map[NR_KEYS] __initdata = {
40 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
41 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf05c, 0xf200, 0xf300,
42 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
43 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf200, 0xf301, 0xf302, 0xf303,
44 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b,
45 0xfb6c, 0xf03b, 0xf027, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
46 0xf200, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d,
47 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
48 0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
49 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
50 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
51 0xf108, 0xf109, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf30a, 0xf11b,
52 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
53 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
54 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
55 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
58 static u_short amishift_map[NR_KEYS] __initdata = {
59 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026,
60 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07c, 0xf200, 0xf300,
61 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
62 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf200, 0xf301, 0xf302, 0xf303,
63 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b,
64 0xfb4c, 0xf03a, 0xf022, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
65 0xf200, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d,
66 0xf03c, 0xf03e, 0xf03f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
67 0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
68 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
69 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111,
70 0xf112, 0xf113, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf203,
71 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
72 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
73 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
74 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
77 static u_short amialtgr_map[NR_KEYS] __initdata = {
78 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, 0xf07b,
79 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, 0xf300,
80 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
81 0xf200, 0xf200, 0xf200, 0xf07e, 0xf200, 0xf301, 0xf302, 0xf303,
82 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
83 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
84 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
85 0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
86 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
87 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
88 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513,
89 0xf514, 0xf515, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
90 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
91 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
92 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
93 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
96 static u_short amictrl_map[NR_KEYS] __initdata = {
97 0xf000, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
98 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf01c, 0xf200, 0xf300,
99 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
100 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf200, 0xf301, 0xf302, 0xf303,
101 0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b,
102 0xf00c, 0xf200, 0xf007, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
103 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d,
104 0xf200, 0xf200, 0xf07f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
105 0xf000, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
106 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
107 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
108 0xf108, 0xf109, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf202,
109 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
110 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
111 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
112 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
115 static u_short amishift_ctrl_map[NR_KEYS] __initdata = {
116 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
117 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
118 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
119 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
120 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
121 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
122 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
123 0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
124 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
125 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
126 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
127 0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
128 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
129 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
130 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
131 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
134 static u_short amialt_map[NR_KEYS] __initdata = {
135 0xf860, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, 0xf837,
136 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf85c, 0xf200, 0xf900,
137 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
138 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf200, 0xf901, 0xf902, 0xf903,
139 0xf861, 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b,
140 0xf86c, 0xf83b, 0xf827, 0xf200, 0xf200, 0xf904, 0xf905, 0xf906,
141 0xf200, 0xf87a, 0xf878, 0xf863, 0xf876, 0xf862, 0xf86e, 0xf86d,
142 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf310, 0xf907, 0xf908, 0xf909,
143 0xf820, 0xf87f, 0xf809, 0xf30e, 0xf80d, 0xf81b, 0xf87f, 0xf200,
144 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
145 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
146 0xf508, 0xf509, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
147 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
148 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
149 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
150 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
153 static u_short amictrl_alt_map[NR_KEYS] __initdata = {
154 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
155 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
156 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
157 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
158 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
159 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
160 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
161 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, 0xf307, 0xf308, 0xf309,
162 0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
163 0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
164 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
165 0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
166 0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
167 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
168 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
169 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
172 #define DEFAULT_KEYB_REP_DELAY (HZ/4)
173 #define DEFAULT_KEYB_REP_RATE (HZ/25)
175 /* These could be settable by some ioctl() in future... */
176 static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
177 static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
179 static unsigned char rep_scancode;
180 static void amikeyb_rep(unsigned long ignore);
181 static struct timer_list amikeyb_rep_timer = {function: amikeyb_rep};
183 static void amikeyb_rep(unsigned long ignore)
191 amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
192 add_timer(&amikeyb_rep_timer);
193 handle_scancode(rep_scancode, 1);
195 restore_flags(flags);
198 static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
200 unsigned char scancode, break_flag, keycode;
201 static int reset_warning = 0;
203 /* save frame for register dump */
206 /* get and invert scancode (keyboard is active low) */
207 scancode = ~ciaa.sdr;
209 /* switch SP pin to output for handshake */
212 #if 0 /* No longer used */
214 * On receipt of the second RESET_WARNING, we must not pull KDAT high
215 * again to delay the hard reset as long as possible.
217 * Note that not all keyboards send reset warnings...
220 if (scancode == RESET_WARNING) {
221 printk(KERN_ALERT "amikeyb: Ctrl-Amiga-Amiga reset warning!!\n"
222 "The system will be reset within 10 seconds!!\n");
223 /* Panic doesn't sync from within an interrupt, so we do nothing */
226 /* Probably a mistake, cancel the alert */
230 /* wait until 85 us have expired */
232 /* switch CIA serial port to input mode */
235 tasklet_schedule(&keyboard_tasklet);
237 /* rotate scan code to get up/down bit in proper position */
238 scancode = ((scancode >> 1) & 0x7f) | ((scancode << 7) & 0x80);
241 * Check make/break first
243 break_flag = scancode & BREAK_MASK;
244 keycode = scancode & (unsigned char)~BREAK_MASK;
246 if (keycode == AMIKEY_CAPS) {
247 /* if the key is CAPS, fake a press/release. */
248 handle_scancode(AMIKEY_CAPS, 1);
249 handle_scancode(AMIKEY_CAPS, 0);
250 } else if (keycode < 0x78) {
253 del_timer(&amikeyb_rep_timer);
256 del_timer(&amikeyb_rep_timer);
257 rep_scancode = keycode;
258 amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
259 add_timer(&amikeyb_rep_timer);
261 handle_scancode(keycode, !break_flag);
268 printk(KERN_WARNING "amikeyb: keyboard lost sync\n");
271 printk(KERN_WARNING "amikeyb: keyboard buffer overflow\n");
273 #if 0 /* obsolete according to the HRM */
275 printk(KERN_WARNING "amikeyb: keyboard controller failure\n");
279 printk(KERN_ERR "amikeyb: keyboard selftest failure\n");
282 printk(KERN_INFO "amikeyb: initiate power-up key stream\n");
285 printk(KERN_INFO "amikeyb: terminate power-up key stream\n");
287 #if 0 /* obsolete according to the HRM */
289 printk(KERN_WARNING "amikeyb: keyboard interrupt\n");
293 printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
299 int __init amiga_keyb_init(void)
301 if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
303 if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
307 memcpy(key_maps[0], amiplain_map, sizeof(plain_map));
308 memcpy(key_maps[1], amishift_map, sizeof(plain_map));
309 memcpy(key_maps[2], amialtgr_map, sizeof(plain_map));
310 memcpy(key_maps[4], amictrl_map, sizeof(plain_map));
311 memcpy(key_maps[5], amishift_ctrl_map, sizeof(plain_map));
312 memcpy(key_maps[8], amialt_map, sizeof(plain_map));
313 memcpy(key_maps[12], amictrl_alt_map, sizeof(plain_map));
316 * Initialize serial data direction.
318 ciaa.cra &= ~0x41; /* serial data in, turn off TA */
321 * arrange for processing of keyboard interrupt
323 request_irq(IRQ_AMIGA_CIAA_SP, keyboard_interrupt, 0, "keyboard", NULL);
328 int amiga_kbdrate( struct kbd_repeat *k )
331 /* convert from msec to jiffies */
332 key_repeat_delay = (k->delay * HZ + 500) / 1000;
333 if (key_repeat_delay < 1)
334 key_repeat_delay = 1;
337 key_repeat_rate = (k->rate * HZ + 500) / 1000;
338 if (key_repeat_rate < 1)
342 k->delay = key_repeat_delay * 1000 / HZ;
343 k->rate = key_repeat_rate * 1000 / HZ;
348 int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
350 #ifdef CONFIG_MAGIC_SYSRQ
351 /* SHIFT+ALTGR+HELP pressed? */
352 if ((keycode == 0x5f) && ((shift_state & 0xff) == 3))