akbd.c revision 1.26 1 /* $NetBSD: akbd.c,v 1.26 2002/08/13 15:00:42 aymeric 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/kernel.h>
37 #include <sys/poll.h>
38 #include <sys/select.h>
39 #include <sys/proc.h>
40 #include <sys/signalvar.h>
41 #include <sys/systm.h>
42
43 #include <dev/wscons/wsconsio.h>
44 #include <dev/wscons/wskbdvar.h>
45 #include <dev/wscons/wsksymdef.h>
46 #include <dev/wscons/wsksymvar.h>
47 #include <dev/ofw/openfirm.h>
48
49 #include <machine/autoconf.h>
50 #define KEYBOARD_ARRAY
51 #include <machine/keyboard.h>
52
53 #include <macppc/dev/adbvar.h>
54 #include <macppc/dev/aedvar.h>
55 #include <macppc/dev/akbdmap.h>
56 #include <macppc/dev/akbdvar.h>
57 #include <macppc/dev/pm_direct.h>
58
59 #include "aed.h"
60
61 /*
62 * Function declarations.
63 */
64 static int akbdmatch __P((struct device *, struct cfdata *, void *));
65 static void akbdattach __P((struct device *, struct device *, void *));
66 void kbd_adbcomplete __P((caddr_t buffer, caddr_t data_area, int adb_command));
67 static void kbd_processevent __P((adb_event_t *event, struct akbd_softc *));
68 static void kbd_passup __P((struct akbd_softc *sc, int));
69 #ifdef notyet
70 static u_char getleds __P((int));
71 static int setleds __P((struct akbd_softc *, u_char));
72 static void blinkleds __P((struct akbd_softc *));
73 #endif
74
75 /* Driver definition. */
76 struct cfattach akbd_ca = {
77 sizeof(struct akbd_softc), akbdmatch, akbdattach
78 };
79
80 extern struct cfdriver akbd_cd;
81
82 int akbd_enable __P((void *, int));
83 void akbd_set_leds __P((void *, int));
84 int akbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
85 #ifdef WSDISPLAY_COMPAT_RAWKBD
86 static void akbd_rawrepeat __P((void *));
87 #endif
88
89 struct wskbd_accessops akbd_accessops = {
90 akbd_enable,
91 akbd_set_leds,
92 akbd_ioctl,
93 };
94
95 void akbd_cngetc __P((void *, u_int *, int *));
96 void akbd_cnpollc __P((void *, int));
97
98 struct wskbd_consops akbd_consops = {
99 akbd_cngetc,
100 akbd_cnpollc,
101 };
102
103 struct wskbd_mapdata akbd_keymapdata = {
104 akbd_keydesctab,
105 #ifdef AKBD_LAYOUT
106 AKBD_LAYOUT,
107 #else
108 KB_US,
109 #endif
110 };
111
112 static int akbd_is_console;
113 static int akbd_console_attached;
114 static int pcmcia_soft_eject;
115
116 static int
117 akbdmatch(parent, cf, aux)
118 struct device *parent;
119 struct cfdata *cf;
120 void *aux;
121 {
122 struct adb_attach_args *aa_args = aux;
123
124 if (aa_args->origaddr == ADBADDR_KBD)
125 return 1;
126 else
127 return 0;
128 }
129
130 static void
131 akbdattach(parent, self, aux)
132 struct device *parent, *self;
133 void *aux;
134 {
135 ADBSetInfoBlock adbinfo;
136 struct akbd_softc *sc = (struct akbd_softc *)self;
137 struct adb_attach_args *aa_args = aux;
138 int error, kbd_done;
139 short cmd;
140 u_char buffer[9];
141 struct wskbddev_attach_args a;
142
143 #ifdef WSDISPLAY_COMPAT_RAWKBD
144 callout_init(&sc->sc_rawrepeat_ch);
145 #endif
146
147 /* ohare based models have soft ejectable card slot. */
148 if (OF_finddevice("/bandit/ohare") != -1)
149 pcmcia_soft_eject = 1;
150
151 sc->origaddr = aa_args->origaddr;
152 sc->adbaddr = aa_args->adbaddr;
153 sc->handler_id = aa_args->handler_id;
154
155 sc->sc_leds = (u_int8_t)0x00; /* initially off */
156
157 adbinfo.siServiceRtPtr = (Ptr)kbd_adbcomplete;
158 adbinfo.siDataAreaAddr = (caddr_t)sc;
159
160 switch (sc->handler_id) {
161 case ADB_STDKBD:
162 printf("standard keyboard\n");
163 break;
164 case ADB_ISOKBD:
165 printf("standard keyboard (ISO layout)\n");
166 break;
167 case ADB_EXTKBD:
168 cmd = ADBTALK(sc->adbaddr, 1);
169 kbd_done =
170 (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) == 0);
171
172 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */
173 if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x20) {
174 printf("Mouseman (non-EMP) pseudo keyboard\n");
175 adbinfo.siServiceRtPtr = (Ptr)0;
176 adbinfo.siDataAreaAddr = (Ptr)0;
177 } else if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x21) {
178 printf("Trackman (non-EMP) pseudo keyboard\n");
179 adbinfo.siServiceRtPtr = (Ptr)0;
180 adbinfo.siDataAreaAddr = (Ptr)0;
181 } else {
182 printf("extended keyboard\n");
183 #ifdef notyet
184 blinkleds(sc);
185 #endif
186 }
187 break;
188 case ADB_EXTISOKBD:
189 printf("extended keyboard (ISO layout)\n");
190 #ifdef notyet
191 blinkleds(sc);
192 #endif
193 break;
194 case ADB_KBDII:
195 printf("keyboard II\n");
196 break;
197 case ADB_ISOKBDII:
198 printf("keyboard II (ISO layout)\n");
199 break;
200 case ADB_PBKBD:
201 printf("PowerBook keyboard\n");
202 break;
203 case ADB_PBISOKBD:
204 printf("PowerBook keyboard (ISO layout)\n");
205 break;
206 case ADB_ADJKPD:
207 printf("adjustable keypad\n");
208 break;
209 case ADB_ADJKBD:
210 printf("adjustable keyboard\n");
211 break;
212 case ADB_ADJISOKBD:
213 printf("adjustable keyboard (ISO layout)\n");
214 break;
215 case ADB_ADJJAPKBD:
216 printf("adjustable keyboard (Japanese layout)\n");
217 break;
218 case ADB_PBEXTISOKBD:
219 printf("PowerBook extended keyboard (ISO layout)\n");
220 break;
221 case ADB_PBEXTJAPKBD:
222 printf("PowerBook extended keyboard (Japanese layout)\n");
223 break;
224 case ADB_JPKBDII:
225 printf("keyboard II (Japanese layout)\n");
226 break;
227 case ADB_PBEXTKBD:
228 printf("PowerBook extended keyboard\n");
229 break;
230 case ADB_DESIGNKBD:
231 printf("extended keyboard\n");
232 #ifdef notyet
233 blinkleds(sc);
234 #endif
235 break;
236 case ADB_PBJPKBD:
237 printf("PowerBook keyboard (Japanese layout)\n");
238 break;
239 case ADB_PBG3KBD:
240 printf("PowerBook G3 keyboard\n");
241 break;
242 case ADB_PBG3JPKBD:
243 printf("PowerBook G3 keyboard (Japanese layout)\n");
244 break;
245 default:
246 printf("mapped device (%d)\n", sc->handler_id);
247 break;
248 }
249 error = SetADBInfo(&adbinfo, sc->adbaddr);
250 #ifdef ADB_DEBUG
251 if (adb_debug)
252 printf("akbd: returned %d from SetADBInfo\n", error);
253 #endif
254
255 if (akbd_is_console && !akbd_console_attached) {
256 wskbd_cnattach(&akbd_consops, sc, &akbd_keymapdata);
257 akbd_console_attached = 1;
258 }
259
260 a.console = akbd_is_console;
261 a.keymap = &akbd_keymapdata;
262 a.accessops = &akbd_accessops;
263 a.accesscookie = sc;
264
265 sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
266 }
267
268
269 /*
270 * Handle putting the keyboard data received from the ADB into
271 * an ADB event record.
272 */
273 void
274 kbd_adbcomplete(buffer, data_area, adb_command)
275 caddr_t buffer;
276 caddr_t data_area;
277 int adb_command;
278 {
279 adb_event_t event;
280 struct akbd_softc *ksc;
281 int adbaddr;
282 #ifdef ADB_DEBUG
283 int i;
284
285 if (adb_debug)
286 printf("adb: transaction completion\n");
287 #endif
288
289 adbaddr = ADB_CMDADDR(adb_command);
290 ksc = (struct akbd_softc *)data_area;
291
292 event.addr = adbaddr;
293 event.hand_id = ksc->handler_id;
294 event.def_addr = ksc->origaddr;
295 event.byte_count = buffer[0];
296 memcpy(event.bytes, buffer + 1, event.byte_count);
297
298 #ifdef ADB_DEBUG
299 if (adb_debug) {
300 printf("akbd: from %d at %d (org %d) %d:", event.addr,
301 event.hand_id, event.def_addr, buffer[0]);
302 for (i = 1; i <= buffer[0]; i++)
303 printf(" %x", buffer[i]);
304 printf("\n");
305 }
306 #endif
307
308 microtime(&event.timestamp);
309
310 kbd_processevent(&event, ksc);
311 }
312
313 /*
314 * Given a keyboard ADB event, record the keycodes and call the key
315 * repeat handler, optionally passing the event through the mouse
316 * button emulation handler first.
317 */
318 static void
319 kbd_processevent(event, ksc)
320 adb_event_t *event;
321 struct akbd_softc *ksc;
322 {
323 adb_event_t new_event;
324
325 new_event = *event;
326 new_event.u.k.key = event->bytes[0];
327 new_event.bytes[1] = 0xff;
328 kbd_intr(&new_event);
329 #if NAED > 0
330 aed_input(&new_event);
331 #endif
332 if (event->bytes[1] != 0xff) {
333 new_event.u.k.key = event->bytes[1];
334 new_event.bytes[0] = event->bytes[1];
335 new_event.bytes[1] = 0xff;
336 kbd_intr(&new_event);
337 #if NAED > 0
338 aed_input(&new_event);
339 #endif
340 }
341
342 }
343
344 #ifdef notyet
345 /*
346 * Get the actual hardware LED state and convert it to softc format.
347 */
348 static u_char
349 getleds(addr)
350 int addr;
351 {
352 short cmd;
353 u_char buffer[9], leds;
354
355 leds = 0x00; /* all off */
356 buffer[0] = 0;
357
358 /* talk R2 */
359 cmd = ADBTALK(addr, 2);
360 if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) == 0 &&
361 buffer[0] > 0)
362 leds = ~(buffer[2]) & 0x07;
363
364 return (leds);
365 }
366
367 /*
368 * Set the keyboard LED's.
369 *
370 * Automatically translates from ioctl/softc format to the
371 * actual keyboard register format
372 */
373 static int
374 setleds(ksc, leds)
375 struct akbd_softc *ksc;
376 u_char leds;
377 {
378 int addr;
379 short cmd;
380 u_char buffer[9];
381
382 if ((leds & 0x07) == (ksc->sc_leds & 0x07))
383 return (0);
384
385 addr = ksc->adbaddr;
386 buffer[0] = 0;
387
388 cmd = ADBTALK(addr, 2);
389 if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) || buffer[0] == 0)
390 return (EIO);
391
392 leds = ~leds & 0x07;
393 buffer[2] &= 0xf8;
394 buffer[2] |= leds;
395
396 cmd = ADBLISTEN(addr, 2);
397 adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd);
398
399 cmd = ADBTALK(addr, 2);
400 if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) || buffer[0] == 0)
401 return (EIO);
402
403 ksc->sc_leds = ~((u_int8_t)buffer[2]) & 0x07;
404
405 if ((buffer[2] & 0xf8) != leds)
406 return (EIO);
407 else
408 return (0);
409 }
410
411 /*
412 * Toggle all of the LED's on and off, just for show.
413 */
414 static void
415 blinkleds(ksc)
416 struct akbd_softc *ksc;
417 {
418 int addr, i;
419 u_char blinkleds, origleds;
420
421 addr = ksc->adbaddr;
422 origleds = getleds(addr);
423 blinkleds = LED_NUMLOCK | LED_CAPSLOCK | LED_SCROLL_LOCK;
424
425 (void)setleds(ksc, blinkleds);
426
427 for (i = 0; i < 10000; i++)
428 delay(50);
429
430 /* make sure that we restore the LED settings */
431 i = 10;
432 do {
433 (void)setleds(ksc, (u_char)0x00);
434 } while (setleds(ksc, (u_char)0x00) && (i-- > 0));
435
436 return;
437 }
438 #endif
439
440 int
441 akbd_enable(v, on)
442 void *v;
443 int on;
444 {
445 return 0;
446 }
447
448 void
449 akbd_set_leds(v, on)
450 void *v;
451 int on;
452 {
453 }
454
455 int
456 akbd_ioctl(v, cmd, data, flag, p)
457 void *v;
458 u_long cmd;
459 caddr_t data;
460 int flag;
461 struct proc *p;
462 {
463 #ifdef WSDISPLAY_COMPAT_RAWKBD
464 struct akbd_softc *sc = (struct akbd_softc *) v;
465 #endif
466
467 switch (cmd) {
468
469 case WSKBDIO_GTYPE:
470 *(int *)data = WSKBD_TYPE_ADB;
471 return 0;
472 case WSKBDIO_SETLEDS:
473 return 0;
474 case WSKBDIO_GETLEDS:
475 *(int *)data = 0;
476 return 0;
477 #ifdef WSDISPLAY_COMPAT_RAWKBD
478 case WSKBDIO_SETMODE:
479 sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
480 callout_stop(&sc->sc_rawrepeat_ch);
481 return 0;
482 #endif
483 }
484 /* kbdioctl(...); */
485
486 return EPASSTHROUGH;
487 }
488
489 #ifdef WSDISPLAY_COMPAT_RAWKBD
490 static void
491 akbd_rawrepeat(v)
492 void *v;
493 {
494 struct akbd_softc *sc = (struct akbd_softc *) v;
495 int s = spltty();
496
497 /* check for race condition and avoid it */
498 if (sc->sc_nrep == 0) {
499 splx(s);
500 return;
501 }
502
503 wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
504 splx(s);
505 callout_reset(&sc->sc_rawrepeat_ch, hz * AKBD_RAW_REPEAT_DELAYN / 1000,
506 akbd_rawrepeat, sc);
507 }
508 #endif
509
510 extern int adb_polling;
511
512 void
513 kbd_passup(sc,key)
514 struct akbd_softc *sc;
515 int key;
516 {
517 if (sc->sc_polling) {
518 if (sc->sc_npolledkeys <
519 (sizeof(sc->sc_polledkeys)/sizeof(unsigned char))) {
520 sc->sc_polledkeys[sc->sc_npolledkeys++] = key;
521 }
522 #ifdef ADB_DEBUG
523 else {
524 printf("akbd: dumping polled key 0x%02x\n",key);
525 }
526 #endif
527 #ifdef WSDISPLAY_COMPAT_RAWKBD
528 } else if (sc->sc_rawkbd) {
529 char cbuf[AKBD_RAW_MAX_KEYS * 2];
530 int s;
531 int j = 0;
532 int npress = 0;
533 int c = keyboard[ADBK_KEYVAL(key)][3];
534
535 callout_stop(&sc->sc_rawrepeat_ch);
536
537 if (c == 0) /* XXX */
538 return;
539
540 if (c & 0x80)
541 cbuf[j++] = 0xe0;
542
543 cbuf[j++] = c & 0x7f;
544
545 if (!ADBK_PRESS(key))
546 cbuf[j - 1] |= 0x80;
547 else {
548 /* this only records last key pressed */
549 if (c & 0x80)
550 sc->sc_rep[npress++] = 0xe0;
551 sc->sc_rep[npress++] = c & 0x7f;
552 }
553
554 s = spltty();
555 wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
556 splx(s);
557
558 sc->sc_nrep = npress;
559 if (npress != 0)
560 callout_reset(&sc->sc_rawrepeat_ch,
561 hz * AKBD_RAW_REPEAT_DELAY1 / 1000,
562 akbd_rawrepeat, sc);
563 #endif
564 } else {
565 int press, val;
566 int type;
567
568 press = ADBK_PRESS(key);
569 val = ADBK_KEYVAL(key);
570
571 type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
572
573 wskbd_input(sc->sc_wskbddev, type, val);
574 }
575 }
576
577 int
578 kbd_intr(arg)
579 void *arg;
580 {
581 adb_event_t *event = arg;
582 int key;
583 #ifdef CAPS_IS_CONTROL
584 static int shift;
585 #endif
586
587 struct akbd_softc *sc = akbd_cd.cd_devs[0];
588
589 key = event->u.k.key;
590
591 #ifdef CAPS_IS_CONTROL
592 /*
593 * Caps lock is weird. The key sequence generated is:
594 * press: down(57) [57] (LED turns on)
595 * release: up(127) [255]
596 * press: up(127) [255]
597 * release: up(57) [185] (LED turns off)
598 */
599 if ((key == 57) || (key == 185))
600 shift = 0;
601
602 if (key == 255) {
603 if (shift == 0) {
604 key = 185;
605 shift = 1;
606 } else {
607 key = 57;
608 shift = 0;
609 }
610 }
611 #endif
612
613 switch (key) {
614 #ifndef CAPS_IS_CONTROL
615 case 57: /* Caps Lock pressed */
616 case 185: /* Caps Lock released */
617 key = ADBK_KEYDOWN(ADBK_KEYVAL(key));
618 kbd_passup(sc,key);
619 key = ADBK_KEYUP(ADBK_KEYVAL(key));
620 break;
621 #endif
622 case 245:
623 if (pcmcia_soft_eject)
624 pm_eject_pcmcia(0);
625 break;
626 case 244:
627 if (pcmcia_soft_eject)
628 pm_eject_pcmcia(1);
629 break;
630 }
631
632 kbd_passup(sc,key);
633
634 return 0;
635 }
636
637 int
638 akbd_cnattach()
639 {
640
641 akbd_is_console = 1;
642 return 0;
643 }
644
645 void
646 akbd_cngetc(v, type, data)
647 void *v;
648 u_int *type;
649 int *data;
650 {
651 int key, press, val;
652 int s;
653 struct akbd_softc *sc = v;
654
655 s = splhigh();
656
657 KASSERT(sc->sc_polling);
658 KASSERT(adb_polling);
659
660 while (sc->sc_npolledkeys == 0) {
661 adb_intr();
662 DELAY(10000); /* XXX */
663 }
664
665 splx(s);
666
667 key = sc->sc_polledkeys[0];
668 sc->sc_npolledkeys--;
669 memmove(sc->sc_polledkeys,sc->sc_polledkeys+1,
670 sc->sc_npolledkeys * sizeof(unsigned char));
671
672 press = ADBK_PRESS(key);
673 val = ADBK_KEYVAL(key);
674
675 *data = val;
676 *type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
677 }
678
679 void
680 akbd_cnpollc(v, on)
681 void *v;
682 int on;
683 {
684 struct akbd_softc *sc = v;
685 sc->sc_polling = on;
686 if (!on) {
687 int i;
688 for(i=0;i<sc->sc_npolledkeys;i++) {
689 kbd_passup(sc,sc->sc_polledkeys[i]);
690 }
691 sc->sc_npolledkeys = 0;
692 }
693 adb_polling = on;
694 }
695