akbd.c revision 1.3.2.3 1 /* $NetBSD: akbd.c,v 1.3.2.3 1999/03/10 16:00:15 scottr Exp $ */
2
3 /*
4 * Copyright (C) 1998 Colin Wood
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Colin Wood.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/fcntl.h>
36 #include <sys/poll.h>
37 #include <sys/select.h>
38 #include <sys/proc.h>
39 #include <sys/signalvar.h>
40 #include <sys/systm.h>
41
42 #include "aed.h"
43 #include "wskbd.h"
44
45 #include <dev/wscons/wsconsio.h>
46 #include <dev/wscons/wskbdvar.h>
47 #include <dev/wscons/wsksymdef.h>
48 #include <dev/wscons/wsksymvar.h>
49
50 #include <machine/autoconf.h>
51 #include <machine/cpu.h>
52 #define KEYBOARD_ARRAY
53 #include <machine/keyboard.h>
54 #include <machine/viareg.h>
55
56 #include <mac68k/mac68k/macrom.h>
57 #include <mac68k/dev/adbvar.h>
58 #include <mac68k/dev/aedvar.h>
59 #include <macppc/dev/akbdmap.h>
60 #include <mac68k/dev/akbdvar.h>
61 #include <mac68k/dev/amsvar.h>
62
63 /*
64 * Function declarations.
65 */
66 static int akbdmatch __P((struct device *, struct cfdata *, void *));
67 static void akbdattach __P((struct device *, struct device *, void *));
68 void kbd_adbcomplete __P((caddr_t buffer, caddr_t data_area, int adb_command));
69 static void kbd_processevent __P((adb_event_t *event, struct akbd_softc *));
70 #ifdef notyet
71 static u_char getleds __P((int));
72 static int setleds __P((struct akbd_softc *, u_char));
73 static void blinkleds __P((struct akbd_softc *));
74 #endif
75
76 /*
77 * Local variables.
78 */
79 static volatile int kbd_done; /* Did ADBOp() complete? */
80
81 /* Driver definition. */
82 struct cfattach akbd_ca = {
83 sizeof(struct akbd_softc), akbdmatch, akbdattach
84 };
85
86 extern struct cfdriver akbd_cd;
87
88 int kbd_intr __P((adb_event_t *event));
89 int akbd_enable __P((void *, int));
90 void akbd_set_leds __P((void *, int));
91 int akbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
92
93 struct wskbd_accessops akbd_accessops = {
94 akbd_enable,
95 akbd_set_leds,
96 akbd_ioctl,
97 };
98
99 void akbd_cngetc __P((void *, u_int *, int *));
100 void akbd_cnpollc __P((void *, int));
101 int akbd_cnattach __P((void));
102
103 struct wskbd_consops akbd_consops = {
104 akbd_cngetc,
105 akbd_cnpollc,
106 };
107
108 struct wskbd_mapdata akbd_keymapdata = {
109 akbd_keydesctab,
110 KB_US,
111 };
112
113 static int akbd_is_console __P((void));
114
115 static int
116 akbdmatch(parent, cf, aux)
117 struct device *parent;
118 struct cfdata *cf;
119 void *aux;
120 {
121 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
122
123 if (aa_args->origaddr == ADBADDR_KBD)
124 return 1;
125 else
126 return 0;
127 }
128
129 static void
130 akbdattach(parent, self, aux)
131 struct device *parent, *self;
132 void *aux;
133 {
134 ADBSetInfoBlock adbinfo;
135 struct akbd_softc *sc = (struct akbd_softc *)self;
136 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
137 int count, error;
138 short cmd;
139 u_char buffer[9];
140 #if NWSKBD > 0
141 struct wskbddev_attach_args a;
142 #endif
143
144 sc->origaddr = aa_args->origaddr;
145 sc->adbaddr = aa_args->adbaddr;
146 sc->handler_id = aa_args->handler_id;
147
148 sc->sc_leds = (u_int8_t)0x00; /* initially off */
149
150 adbinfo.siServiceRtPtr = (Ptr)adb_kbd_asmcomplete;
151 adbinfo.siDataAreaAddr = (caddr_t)sc;
152
153 switch (sc->handler_id) {
154 case ADB_STDKBD:
155 printf("standard keyboard\n");
156 break;
157 case ADB_ISOKBD:
158 printf("standard keyboard (ISO layout)\n");
159 break;
160 case ADB_EXTKBD:
161 kbd_done = 0;
162 cmd = (((sc->adbaddr << 4) & 0xf0) | 0x0d ); /* talk R1 */
163 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
164 (Ptr)&kbd_done, cmd);
165
166 /* Wait until done, but no more than 2 secs */
167 count = 40000;
168 while (!kbd_done && count-- > 0)
169 delay(50);
170
171 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */
172 if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x20) {
173 printf("Mouseman (non-EMP) pseudo keyboard\n");
174 adbinfo.siServiceRtPtr = (Ptr)0;
175 adbinfo.siDataAreaAddr = (Ptr)0;
176 } else if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x21) {
177 printf("Trackman (non-EMP) pseudo keyboard\n");
178 adbinfo.siServiceRtPtr = (Ptr)0;
179 adbinfo.siDataAreaAddr = (Ptr)0;
180 } else {
181 printf("extended keyboard\n");
182 #ifdef notyet
183 blinkleds(sc);
184 #endif
185 }
186 break;
187 case ADB_EXTISOKBD:
188 printf("extended keyboard (ISO layout)\n");
189 #ifdef notyet
190 blinkleds(sc);
191 #endif
192 break;
193 case ADB_KBDII:
194 printf("keyboard II\n");
195 break;
196 case ADB_ISOKBDII:
197 printf("keyboard II (ISO layout)\n");
198 break;
199 case ADB_PBKBD:
200 printf("PowerBook keyboard\n");
201 break;
202 case ADB_PBISOKBD:
203 printf("PowerBook keyboard (ISO layout)\n");
204 break;
205 case ADB_ADJKPD:
206 printf("adjustable keypad\n");
207 break;
208 case ADB_ADJKBD:
209 printf("adjustable keyboard\n");
210 break;
211 case ADB_ADJISOKBD:
212 printf("adjustable keyboard (ISO layout)\n");
213 break;
214 case ADB_ADJJAPKBD:
215 printf("adjustable keyboard (Japanese layout)\n");
216 break;
217 case ADB_PBEXTISOKBD:
218 printf("PowerBook extended keyboard (ISO layout)\n");
219 break;
220 case ADB_PBEXTJAPKBD:
221 printf("PowerBook extended keyboard (Japanese layout)\n");
222 break;
223 case ADB_JPKBDII:
224 printf("keyboard II (Japanese layout)\n");
225 break;
226 case ADB_PBEXTKBD:
227 printf("PowerBook extended keyboard\n");
228 break;
229 case ADB_DESIGNKBD:
230 printf("extended keyboard\n");
231 #ifdef notyet
232 blinkleds(sc);
233 #endif
234 break;
235 case ADB_PBJPKBD:
236 printf("PowerBook keyboard (Japanese layout)\n");
237 break;
238 default:
239 printf("mapped device (%d)\n", sc->handler_id);
240 break;
241 }
242 error = SetADBInfo(&adbinfo, sc->adbaddr);
243 #ifdef ADB_DEBUG
244 if (adb_debug)
245 printf("akbd: returned %d from SetADBInfo\n", error);
246 #endif
247
248 #if NWSKBD > 0
249 a.console = akbd_is_console();
250 a.keymap = &akbd_keymapdata;
251 a.accessops = &akbd_accessops;
252 a.accesscookie = sc;
253
254 sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
255 #endif
256 }
257
258
259 /*
260 * Handle putting the keyboard data received from the ADB into
261 * an ADB event record.
262 */
263 void
264 kbd_adbcomplete(buffer, data_area, adb_command)
265 caddr_t buffer;
266 caddr_t data_area;
267 int adb_command;
268 {
269 adb_event_t event;
270 struct akbd_softc *ksc;
271 int adbaddr;
272 #ifdef ADB_DEBUG
273 int i;
274
275 if (adb_debug)
276 printf("adb: transaction completion\n");
277 #endif
278
279 adbaddr = (adb_command & 0xf0) >> 4;
280 ksc = (struct akbd_softc *)data_area;
281
282 event.addr = adbaddr;
283 event.hand_id = ksc->handler_id;
284 event.def_addr = ksc->origaddr;
285 event.byte_count = buffer[0];
286 memcpy(event.bytes, buffer + 1, event.byte_count);
287
288 #ifdef ADB_DEBUG
289 if (adb_debug) {
290 printf("akbd: from %d at %d (org %d) %d:", event.addr,
291 event.hand_id, event.def_addr, buffer[0]);
292 for (i = 1; i <= buffer[0]; i++)
293 printf(" %x", buffer[i]);
294 printf("\n");
295 }
296 #endif
297
298 microtime(&event.timestamp);
299
300 kbd_processevent(&event, ksc);
301 }
302
303 /*
304 * Given a keyboard ADB event, record the keycodes and call the key
305 * repeat handler, optionally passing the event through the mouse
306 * button emulation handler first.
307 */
308 static void
309 kbd_processevent(event, ksc)
310 adb_event_t *event;
311 struct akbd_softc *ksc;
312 {
313 adb_event_t new_event;
314
315 new_event = *event;
316 new_event.u.k.key = event->bytes[0];
317 new_event.bytes[1] = 0xff;
318 #if NWSKBD > 0
319 kbd_intr(&new_event);
320 #endif
321 #if NAED > 0
322 aed_input(&new_event);
323 #endif
324 if (event->bytes[1] != 0xff) {
325 new_event.u.k.key = event->bytes[1];
326 new_event.bytes[0] = event->bytes[1];
327 new_event.bytes[1] = 0xff;
328 #if NWSKBD > 0
329 kbd_intr(&new_event);
330 #endif
331 #if NAED > 0
332 aed_input(&new_event);
333 #endif
334 }
335
336 }
337
338 #ifdef notyet
339 /*
340 * Get the actual hardware LED state and convert it to softc format.
341 */
342 static u_char
343 getleds(addr)
344 int addr;
345 {
346 short cmd;
347 u_char buffer[9], leds;
348
349 leds = 0x00; /* all off */
350 buffer[0] = 0;
351 kbd_done = 0;
352
353 /* talk R2 */
354 cmd = ((addr & 0xf) << 4) | 0x0c | 0x02;
355 ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
356 while (!kbd_done)
357 /* busy-wait until done */ ;
358
359 if (buffer[0] > 0)
360 leds = ~(buffer[2]) & 0x07;
361
362 return (leds);
363 }
364
365 /*
366 * Set the keyboard LED's.
367 *
368 * Automatically translates from ioctl/softc format to the
369 * actual keyboard register format
370 */
371 static int
372 setleds(ksc, leds)
373 struct akbd_softc *ksc;
374 u_char leds;
375 {
376 int addr;
377 short cmd;
378 u_char buffer[9];
379
380 if ((leds & 0x07) == (ksc->sc_leds & 0x07))
381 return (0);
382
383 addr = ksc->adbaddr;
384 buffer[0] = 0;
385 kbd_done = 0;
386
387 /* talk R2 */
388 cmd = ((addr & 0xf) << 4) | 0x0c | 0x02;
389 ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
390 while (!kbd_done)
391 /* busy-wait until done */ ;
392
393 if (buffer[0] == 0)
394 return (EIO);
395
396 leds = ~leds & 0x07;
397 buffer[2] &= 0xf8;
398 buffer[2] |= leds;
399
400 /* listen R2 */
401 cmd = ((addr & 0xf) << 4) | 0x08 | 0x02;
402 ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
403 while (!kbd_done)
404 /* busy-wait until done */ ;
405
406 /* talk R2 */
407 cmd = ((addr & 0xf) << 4) | 0x0c | 0x02;
408 ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
409 while (!kbd_done)
410 /* busy-wait until done */ ;
411
412 if (buffer[0] == 0)
413 return (EIO);
414
415 ksc->sc_leds = ~((u_int8_t)buffer[2]) & 0x07;
416
417 if ((buffer[2] & 0xf8) != leds)
418 return (EIO);
419 else
420 return (0);
421 }
422
423 /*
424 * Toggle all of the LED's on and off, just for show.
425 */
426 static void
427 blinkleds(ksc)
428 struct akbd_softc *ksc;
429 {
430 int addr, i;
431 u_char blinkleds, origleds;
432
433 addr = ksc->adbaddr;
434 origleds = getleds(addr);
435 blinkleds = LED_NUMLOCK | LED_CAPSLOCK | LED_SCROLL_LOCK;
436
437 (void)setleds(ksc, blinkleds);
438
439 for (i = 0; i < 10000; i++)
440 delay(50);
441
442 /* make sure that we restore the LED settings */
443 i = 10;
444 do {
445 (void)setleds(ksc, (u_char)0x00);
446 } while (setleds(ksc, (u_char)0x00) && (i-- > 0));
447
448 return;
449 }
450 #endif
451
452 int
453 akbd_is_console()
454 {
455 extern struct mac68k_machine_S mac68k_machine;
456
457 return ((mac68k_machine.serial_console & 0x03) == 0);
458 }
459
460 int
461 akbd_enable(v, on)
462 void *v;
463 int on;
464 {
465 return 0;
466 }
467
468 void
469 akbd_set_leds(v, on)
470 void *v;
471 int on;
472 {
473 }
474
475 int
476 akbd_ioctl(v, cmd, data, flag, p)
477 void *v;
478 u_long cmd;
479 caddr_t data;
480 int flag;
481 struct proc *p;
482 {
483 switch (cmd) {
484
485 case WSKBDIO_GTYPE:
486 *(int *)data = 0; /* XXX */
487 return 0;
488 case WSKBDIO_SETLEDS:
489 return 0;
490 case WSKBDIO_GETLEDS:
491 *(int *)data = 0;
492 return 0;
493 case WSKBDIO_BELL:
494 case WSKBDIO_COMPLEXBELL:
495 #define d ((struct wskbd_bell_data *)data)
496 mac68k_ring_bell(d->pitch, d->period * HZ / 1000, 100);
497 /* comes in as msec, goes out as ticks; volume ignored */
498 #undef d
499 return (0);
500 }
501 /* kbdioctl(...); */
502
503 return -1;
504 }
505
506 static int polledkey;
507 extern int adb_polling;
508
509 int
510 kbd_intr(event)
511 adb_event_t *event;
512 {
513 int key, press, val;
514 int type;
515
516 struct akbd_softc *sc = akbd_cd.cd_devs[0];
517
518 key = event->u.k.key;
519 press = ADBK_PRESS(key);
520 val = ADBK_KEYVAL(key);
521
522 type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
523
524 if (key == 185) { /* Caps Lock released */
525 type = WSCONS_EVENT_KEY_DOWN;
526 wskbd_input(sc->sc_wskbddev, type, val);
527 type = WSCONS_EVENT_KEY_UP;
528 }
529
530 if (adb_polling)
531 polledkey = key;
532 else
533 wskbd_input(sc->sc_wskbddev, type, val);
534
535 return 0;
536 }
537
538 int
539 akbd_cnattach()
540 {
541 if (!akbd_is_console())
542 return -1;
543
544 wskbd_cnattach(&akbd_consops, NULL, &akbd_keymapdata);
545
546 return 0;
547 }
548
549 void
550 akbd_cngetc(v, type, data)
551 void *v;
552 u_int *type;
553 int *data;
554 {
555 int intbits, key, press, val;
556 int s;
557
558 s = splhigh();
559
560 polledkey = -1;
561 adb_polling = 1;
562
563 while (polledkey == -1) {
564 intbits = via_reg(VIA1, vIFR);
565
566 if (intbits & V1IF_ADBRDY) {
567 mrg_adbintr();
568 via_reg(VIA1, vIFR) = V1IF_ADBRDY;
569 }
570 if (intbits & 0x10) {
571 mrg_pmintr();
572 via_reg(VIA1, vIFR) = 0x10;
573 }
574 }
575
576 adb_polling = 0;
577 splx(s);
578
579 key = polledkey;
580 press = ADBK_PRESS(key);
581 val = ADBK_KEYVAL(key);
582
583 *data = val;
584 *type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
585 }
586
587 void
588 akbd_cnpollc(v, on)
589 void *v;
590 int on;
591 {
592 }
593