1/*
2 *  linux/arch/m68k/hp300/hil.c
3 *
4 *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
5 *
6 *  HP300 Human Interface Loop driver.  This handles the keyboard and mouse.
7 */
8
9#include <linux/stddef.h>
10#include <linux/kernel.h>
11#include <linux/sched.h>
12#include <linux/init.h>
13#include <linux/keyboard.h>
14#include <linux/kbd_ll.h>
15#include <asm/io.h>
16#include <asm/hwtest.h>
17#include <asm/ptrace.h>
18#include <asm/irq.h>
19#include <asm/system.h>
20
21#define HILBASE			0xf0428000
22#define HIL_DATA			0x1
23#define HIL_CMD			0x3
24
25#define	HIL_BUSY		0x02
26#define	HIL_DATA_RDY		0x01
27
28#define hil_busy()		(in_8(HILBASE + HIL_CMD) & HIL_BUSY)
29#define hil_data_available()	(in_8(HILBASE + HIL_CMD) & HIL_DATA_RDY)
30#define hil_status()		(in_8(HILBASE + HIL_CMD))
31#define hil_command(x)		out_8(HILBASE + HIL_CMD, (x))
32#define hil_read_data()		(in_8(HILBASE + HIL_DATA))
33#define hil_write_data(x)	out_8(HILBASE + HIL_DATA, (x))
34
35#define	HIL_SETARD		0xA0		/* set auto-repeat delay */
36#define	HIL_SETARR		0xA2		/* set auto-repeat rate */
37#define	HIL_SETTONE		0xA3		/* set tone generator */
38#define	HIL_CNMT		0xB2		/* clear nmi */
39#define	HIL_INTON		0x5C		/* Turn on interrupts. */
40#define	HIL_INTOFF		0x5D		/* Turn off interrupts. */
41#define	HIL_TRIGGER		0xC5		/* trigger command */
42#define	HIL_STARTCMD		0xE0		/* start loop command */
43#define	HIL_TIMEOUT		0xFE		/* timeout */
44#define	HIL_READTIME		0x13		/* Read real time register */
45
46#define	HIL_READBUSY		0x02		/* internal "busy" register */
47#define	HIL_READKBDLANG		0x12		/* read keyboard language code */
48#define	HIL_READKBDSADR	 	0xF9
49#define	HIL_WRITEKBDSADR 	0xE9
50#define	HIL_READLPSTAT  	0xFA
51#define	HIL_WRITELPSTAT 	0xEA
52#define	HIL_READLPCTRL  	0xFB
53#define	HIL_WRITELPCTRL 	0xEB
54
55#define HIL_IRQ			1
56
57#define plain_map		hp_plain_map
58#define shift_map		hp_shift_map
59#define altgr_map		hp_altgr_map
60#define ctrl_map		hp_ctrl_map
61#define shift_ctrl_map		hp_shift_ctrl_map
62#define alt_map			hp_alt_map
63#define ctrl_alt_map		hp_ctrl_alt_map
64
65u_short plain_map[NR_KEYS] = {
66	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
67	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
68	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
69	0xfb62,	0xfb76,	0xfb63,	0xfb78,	0xfb7a,	0xf200,	0xf200,	0xf01b,
70	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
71	0xfb68,	0xfb67,	0xfb66,	0xfb64,	0xfb73,	0xfb61,	0xf200,	0xf207,
72	0xfb75,	0xfb79,	0xfb74,	0xfb72,	0xfb65,	0xfb77,	0xfb71,	0xf009,
73	0xf037,	0xf036,	0xf035,	0xf034,	0xf033,	0xf032,	0xf031,	0xf060,
74	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
75	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
76	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
77	0xf038,	0xf039,	0xf030,	0xf02d,	0xf03d,	0xf008,	0xf200,	0xf200,
78	0xfb69,	0xfb6f,	0xfb70,	0xf05b,	0xf05d,	0xf05c,	0xf200,	0xf200,
79	0xfb6a,	0xfb6b,	0xfb6c,	0xf03b,	0xf027,	0xf201,	0xf200,	0xf200,
80	0xfb6d,	0xf02c,	0xf02e,	0xf02f,	0xf200,	0xf200,	0xf200,	0xf200,
81	0xfb6e,	0xf020,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
82};
83
84u_short shift_map[NR_KEYS] = {
85	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
86	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
87	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
88	0xfb42,	0xfb56,	0xfb43,	0xfb58,	0xfb5a,	0xf200,	0xf200,	0xf07f,
89	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
90	0xfb48,	0xfb47,	0xfb46,	0xfb44,	0xfb53,	0xfb41,	0xf200,	0xf207,
91	0xfb55,	0xfb59,	0xfb54,	0xfb52,	0xfb45,	0xfb57,	0xfb51,	0xf009,
92	0xf026,	0xf05e,	0xf025,	0xf024,	0xf023,	0xf040,	0xf021,	0xf07e,
93	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
94	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
95	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
96	0xf02a,	0xf028,	0xf029,	0xf05f,	0xf02b,	0xf200,	0xf200,	0xf200,
97	0xfb49,	0xfb4f,	0xfb50,	0xf07b,	0xf07d,	0xf07c,	0xf200,	0xf200,
98	0xfb4a,	0xfb4b,	0xfb4c,	0xf03a,	0xf022,	0xf201,	0xf200,	0xf200,
99	0xfb4d,	0xf03c,	0xf03e,	0xf03f,	0xf200,	0xf200,	0xf200,	0xf200,
100	0xfb4e,	0xf020,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
101};
102
103u_short altgr_map[NR_KEYS] = {
104	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
105	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
106	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
107	0xfb62,	0xfb76,	0xfb63,	0xfb78,	0xfb7a,	0xf200,	0xf200,	0xf200,
108	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
109	0xfb68,	0xfb67,	0xfb66,	0xfb64,	0xfb73,	0xfb61,	0xf200,	0xf207,
110	0xfb75,	0xfb79,	0xfb74,	0xfb72,	0xfb65,	0xfb77,	0xfb71,	0xf200,
111	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf040,	0xf021,	0xf200,
112	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
113	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
114	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
115	0xf02a,	0xf05b,	0xf05d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
116	0xfb69,	0xfb6f,	0xfb70,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
117	0xfb6a,	0xfb6b,	0xfb6c,	0xf200,	0xf200,	0xf201,	0xf200,	0xf200,
118	0xfb6d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
119	0xfb6e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
120};
121
122u_short ctrl_map[NR_KEYS] = {
123	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
124	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
125	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
126	0xf002,	0xf016,	0xf003,	0xf018,	0xf01a,	0xf200,	0xf200,	0xf200,
127	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
128	0xf008,	0xf007,	0xf006,	0xf004,	0xf013,	0xf001,	0xf200,	0xf207,
129	0xf015,	0xf019,	0xf014,	0xf012,	0xf005,	0xf017,	0xf011,	0xf200,
130	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf000,
131	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
132	0xf200,	0xf503,	0xf502,	0xf501,	0xf500,	0xf200,	0xf200,	0xf200,
133	0xf200,	0xf504,	0xf505,	0xf506,	0xf507,	0xf200,	0xf200,	0xf200,
134	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
135	0xf009,	0xf00f,	0xf010,	0xf200,	0xf200,	0xf01c,	0xf200,	0xf200,
136	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf007,	0xf201,	0xf200,	0xf200,
137	0xf00d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
138	0xf00e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
139};
140
141u_short shift_ctrl_map[NR_KEYS] = {
142	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
143	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
144	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
145	0xf002,	0xf016,	0xf003,	0xf018,	0xf01a,	0xf200,	0xf200,	0xf200,
146	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
147	0xf008,	0xf007,	0xf006,	0xf004,	0xf013,	0xf001,	0xf200,	0xf207,
148	0xf015,	0xf019,	0xf014,	0xf012,	0xf005,	0xf017,	0xf011,	0xf200,
149	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
150	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
151	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
152	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
153	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
154	0xf009,	0xf00f,	0xf010,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
155	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf200,	0xf201,	0xf200,	0xf200,
156	0xf00d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
157	0xf00e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
158};
159
160u_short alt_map[NR_KEYS] = {
161	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
162	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
163	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
164	0xf862,	0xf876,	0xf863,	0xf878,	0xf87a,	0xf200,	0xf200,	0xf200,
165	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
166	0xf868,	0xf867,	0xf866,	0xf864,	0xf873,	0xf861,	0xf200,	0xf207,
167	0xf875,	0xf879,	0xf874,	0xf872,	0xf865,	0xf877,	0xf871,	0xf809,
168	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf860,
169	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
170	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
171	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
172	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
173	0xf869,	0xf86f,	0xf870,	0xf200,	0xf200,	0xf85c,	0xf200,	0xf200,
174	0xf86a,	0xf86b,	0xf86c,	0xf83b,	0xf827,	0xf201,	0xf200,	0xf200,
175	0xf86d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
176	0xf86e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
177};
178
179u_short ctrl_alt_map[NR_KEYS] = {
180	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
181	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
182	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
183	0xf802,	0xf816,	0xf803,	0xf818,	0xf81a,	0xf200,	0xf200,	0xf200,
184	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
185	0xf808,	0xf807,	0xf806,	0xf804,	0xf813,	0xf801,	0xf200,	0xf207,
186	0xf815,	0xf819,	0xf814,	0xf812,	0xf805,	0xf817,	0xf811,	0xf200,
187	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
188	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
189	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
190	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
191	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
192	0xf809,	0xf80f,	0xf810,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
193	0xf80a,	0xf80b,	0xf80c,	0xf200,	0xf200,	0xf201,	0xf200,	0xf200,
194	0xf80d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
195	0xf80e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
196};
197
198#undef plain_map
199#undef ctrl_alt_map
200#undef shift_map
201#undef altgr_map
202#undef ctrl_map
203#undef shift_ctrl_map
204#undef alt_map
205
206struct {
207  unsigned char s, c;
208  int valid;
209} hil_last;
210
211#define hil_getlast(s,c)  do { s = hil_last.s; c = hil_last.c; hil_last.valid = 0; } while (0)
212
213struct {
214  unsigned char data[16];
215  unsigned int ptr;
216} poll;
217
218unsigned char curdev = 0;
219
220static void poll_finished(void)
221{
222  switch (poll.data[0])
223  {
224  case 0x40:
225    {
226      int down = (poll.data[1] & 1) == 0;
227      unsigned char scode = poll.data[1] >> 1;
228      handle_scancode(scode, down);
229    }
230    break;
231  }
232  curdev = 0;
233}
234
235static inline void handle_status(unsigned char s, unsigned char c)
236{
237  if (c & 0x8) {
238    /* End of block */
239    if (c & 0x10)
240      poll_finished();
241  } else {
242    if (c & 0x10) {
243      if (curdev)
244	poll_finished();		/* just in case */
245      curdev = c & 7;
246      poll.ptr = 0;
247    }
248  }
249}
250
251static inline void handle_data(unsigned char s, unsigned char c)
252{
253  if (curdev)
254    poll.data[poll.ptr++] = c;
255}
256
257/*
258 * Handle HIL interrupts.
259 */
260
261static void hil_interrupt(int irq, void *handle, struct pt_regs *regs)
262{
263  unsigned char s, c;
264  s = hil_status(); c = hil_read_data();
265  switch (s >> 4)
266  {
267  case 0x5:
268    handle_status(s, c);
269    break;
270  case 0x6:
271    handle_data(s, c);
272    break;
273  case 0x4:
274    hil_last.s = s;
275    hil_last.c = c;
276    mb();
277    hil_last.valid = 1;
278    break;
279  }
280}
281
282/*
283 * Send a command to the HIL
284 */
285
286static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
287{
288  unsigned long flags;
289  save_flags(flags); cli();
290  while (hil_busy());
291  hil_command(cmd);
292  while (len--) {
293    while (hil_busy());
294    hil_write_data(*(data++));
295  }
296  restore_flags(flags);
297}
298
299/*
300 * Initialise HIL.
301 */
302
303int __init hp300_keyb_init(void)
304{
305  unsigned char s, c, kbid;
306  unsigned int n = 0;
307
308  memcpy(key_maps[0], hp_plain_map, sizeof(plain_map));
309  memcpy(key_maps[1], hp_shift_map, sizeof(plain_map));
310  memcpy(key_maps[4], hp_ctrl_map, sizeof(plain_map));
311
312  if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
313    return 1;		/* maybe this can happen */
314
315  request_irq(HIL_IRQ, hil_interrupt, 0, "HIL", NULL);
316
317  /* Turn on interrupts */
318  hil_do(HIL_INTON, NULL, 0);
319
320  /* Look for keyboards */
321  hil_do(HIL_READKBDSADR, NULL, 0);
322  while (!hil_last.valid) {
323    if (n++ > 100000) {
324      printk("HIL: timed out, assuming no keyboard present.\n");
325      return 1;
326    }
327    mb();
328  }
329  hil_getlast(s, c);
330  if (c == 0) {
331    printk("HIL: no keyboard present.\n");
332    return 1;
333  }
334  for (kbid = 0; (kbid < 8) && ((c & (1<<kbid)) == 0); kbid++);
335  printk("HIL: keyboard found at id %d\n", kbid);
336  /* set it to raw mode */
337  c = 0;
338  hil_do(HIL_WRITEKBDSADR, &c, 1);
339  return 0;
340}
341