1 /*
2 * linux/arch/m68k/amiga/amikeyb.c
3 *
4 * Amiga Keyboard driver for Linux/m68k
5 *
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 */
10
11 /*
12 * Amiga support by Hamish Macdonald
13 */
14
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>
21 #include <linux/kd.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>
30
31 #include <asm/amigaints.h>
32 #include <asm/amigahw.h>
33 #include <asm/irq.h>
34
35 #define AMIKEY_CAPS (0x62)
36 #define BREAK_MASK (0x80)
37 #define RESET_WARNING (0xf0) /* before rotation */
38
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,
56 };
57
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,
75 };
76
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,
94 };
95
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,
113 };
114
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,
132 };
133
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,
151 };
152
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,
170 };
171
172 #define DEFAULT_KEYB_REP_DELAY (HZ/4)
173 #define DEFAULT_KEYB_REP_RATE (HZ/25)
174
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;
178
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};
182
amikeyb_rep(unsigned long ignore)183 static void amikeyb_rep(unsigned long ignore)
184 {
185 unsigned long flags;
186 save_flags(flags);
187 cli();
188
189 kbd_pt_regs = NULL;
190
191 amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
192 add_timer(&amikeyb_rep_timer);
193 handle_scancode(rep_scancode, 1);
194
195 restore_flags(flags);
196 }
197
keyboard_interrupt(int irq,void * dummy,struct pt_regs * fp)198 static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
199 {
200 unsigned char scancode, break_flag, keycode;
201 static int reset_warning = 0;
202
203 /* save frame for register dump */
204 kbd_pt_regs = fp;
205
206 /* get and invert scancode (keyboard is active low) */
207 scancode = ~ciaa.sdr;
208
209 /* switch SP pin to output for handshake */
210 ciaa.cra |= 0x40;
211
212 #if 0 /* No longer used */
213 /*
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.
216 *
217 * Note that not all keyboards send reset warnings...
218 */
219 if (reset_warning)
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 */
224 return;
225 } else
226 /* Probably a mistake, cancel the alert */
227 reset_warning = 0;
228 #endif
229
230 /* wait until 85 us have expired */
231 udelay(85);
232 /* switch CIA serial port to input mode */
233 ciaa.cra &= ~0x40;
234
235 tasklet_schedule(&keyboard_tasklet);
236
237 /* rotate scan code to get up/down bit in proper position */
238 scancode = ((scancode >> 1) & 0x7f) | ((scancode << 7) & 0x80);
239
240 /*
241 * Check make/break first
242 */
243 break_flag = scancode & BREAK_MASK;
244 keycode = scancode & (unsigned char)~BREAK_MASK;
245
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) {
251 /* handle repeat */
252 if (break_flag) {
253 del_timer(&amikeyb_rep_timer);
254 rep_scancode = 0;
255 } else {
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);
260 }
261 handle_scancode(keycode, !break_flag);
262 } else
263 switch (keycode) {
264 case 0x78:
265 reset_warning = 1;
266 break;
267 case 0x79:
268 printk(KERN_WARNING "amikeyb: keyboard lost sync\n");
269 break;
270 case 0x7a:
271 printk(KERN_WARNING "amikeyb: keyboard buffer overflow\n");
272 break;
273 #if 0 /* obsolete according to the HRM */
274 case 0x7b:
275 printk(KERN_WARNING "amikeyb: keyboard controller failure\n");
276 break;
277 #endif
278 case 0x7c:
279 printk(KERN_ERR "amikeyb: keyboard selftest failure\n");
280 break;
281 case 0x7d:
282 printk(KERN_INFO "amikeyb: initiate power-up key stream\n");
283 break;
284 case 0x7e:
285 printk(KERN_INFO "amikeyb: terminate power-up key stream\n");
286 break;
287 #if 0 /* obsolete according to the HRM */
288 case 0x7f:
289 printk(KERN_WARNING "amikeyb: keyboard interrupt\n");
290 break;
291 #endif
292 default:
293 printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
294 scancode);
295 break;
296 }
297 }
298
amiga_keyb_init(void)299 int __init amiga_keyb_init(void)
300 {
301 if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
302 return -EIO;
303 if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
304 return -EBUSY;
305
306 /* setup key map */
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));
314
315 /*
316 * Initialize serial data direction.
317 */
318 ciaa.cra &= ~0x41; /* serial data in, turn off TA */
319
320 /*
321 * arrange for processing of keyboard interrupt
322 */
323 request_irq(IRQ_AMIGA_CIAA_SP, keyboard_interrupt, 0, "keyboard", NULL);
324
325 return 0;
326 }
327
amiga_kbdrate(struct kbd_repeat * k)328 int amiga_kbdrate( struct kbd_repeat *k )
329 {
330 if (k->delay > 0) {
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;
335 }
336 if (k->rate > 0) {
337 key_repeat_rate = (k->rate * HZ + 500) / 1000;
338 if (key_repeat_rate < 1)
339 key_repeat_rate = 1;
340 }
341
342 k->delay = key_repeat_delay * 1000 / HZ;
343 k->rate = key_repeat_rate * 1000 / HZ;
344
345 return( 0 );
346 }
347
amiga_kbd_translate(unsigned char keycode,unsigned char * keycodep,char raw_mode)348 int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
349 {
350 #ifdef CONFIG_MAGIC_SYSRQ
351 /* SHIFT+ALTGR+HELP pressed? */
352 if ((keycode == 0x5f) && ((shift_state & 0xff) == 3))
353 *keycodep = 0xff;
354 else
355 #endif
356 *keycodep = keycode;
357 return 1;
358 }
359
360