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