File: /usr/src/linux/drivers/char/amikeyb.c

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     
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     
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     
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     
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     
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