1 /* $NetBSD: akbd.c,v 1.42 2009/03/14 21:04:11 dsl Exp $ */
4 * Copyright (C) 1998 Colin Wood
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: akbd.c,v 1.42 2009/03/14 21:04:11 dsl Exp $");
36 #include <sys/param.h>
37 #include <sys/device.h>
38 #include <sys/fcntl.h>
40 #include <sys/select.h>
42 #include <sys/signalvar.h>
43 #include <sys/systm.h>
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 #include <dev/ofw/openfirm.h>
51 #include <dev/adb/adb_keymap.h>
53 #include <machine/autoconf.h>
54 #define KEYBOARD_ARRAY
55 #include <machine/keyboard.h>
57 #include <macppc/dev/adbvar.h>
58 #include <macppc/dev/aedvar.h>
59 #include <macppc/dev/akbdvar.h>
60 #include <macppc/dev/pm_direct.h>
65 * Function declarations.
67 static int akbdmatch(struct device
*, struct cfdata
*, void *);
68 static void akbdattach(struct device
*, struct device
*, void *);
69 static void kbd_processevent(adb_event_t
*event
, struct akbd_softc
*);
71 static u_char
getleds(int);
72 static int setleds(struct akbd_softc
*, u_char
);
73 static void blinkleds(struct akbd_softc
*);
76 /* Driver definition. */
77 CFATTACH_DECL(akbd
, sizeof(struct akbd_softc
),
78 akbdmatch
, akbdattach
, NULL
, NULL
);
80 extern struct cfdriver akbd_cd
;
82 int akbd_enable(void *, int);
83 void akbd_set_leds(void *, int);
84 int akbd_ioctl(void *, u_long
, void *, int, struct lwp
*);
86 struct wskbd_accessops akbd_accessops
= {
92 void akbd_cngetc(void *, u_int
*, int *);
93 void akbd_cnpollc(void *, int);
95 struct wskbd_consops akbd_consops
= {
100 struct wskbd_mapdata akbd_keymapdata
= {
109 static int akbd_is_console
;
110 static int akbd_console_attached
;
111 static int pcmcia_soft_eject
;
114 akbdmatch(struct device
*parent
, struct cfdata
*cf
, void *aux
)
116 struct adb_attach_args
*aa_args
= aux
;
118 if (aa_args
->origaddr
== ADBADDR_KBD
)
125 akbdattach(struct device
*parent
, struct device
*self
, void *aux
)
127 ADBSetInfoBlock adbinfo
;
128 struct akbd_softc
*sc
= (struct akbd_softc
*)self
;
129 struct adb_attach_args
*aa_args
= aux
;
133 struct wskbddev_attach_args a
;
135 /* ohare based models have soft ejectable card slot. */
136 if (OF_finddevice("/bandit/ohare") != -1)
137 pcmcia_soft_eject
= 1;
139 sc
->origaddr
= aa_args
->origaddr
;
140 sc
->adbaddr
= aa_args
->adbaddr
;
141 sc
->handler_id
= aa_args
->handler_id
;
143 sc
->sc_leds
= (u_int8_t
)0x00; /* initially off */
145 adbinfo
.siServiceRtPtr
= (Ptr
)kbd_adbcomplete
;
146 adbinfo
.siDataAreaAddr
= (void *)sc
;
148 switch (sc
->handler_id
) {
150 printf("standard keyboard\n");
153 printf("standard keyboard (ISO layout)\n");
156 cmd
= ADBTALK(sc
->adbaddr
, 1);
158 (adb_op_sync((Ptr
)buffer
, NULL
, (Ptr
)0, cmd
) == 0);
160 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */
161 if (kbd_done
&& buffer
[1] == 0x9a && buffer
[2] == 0x20) {
162 printf("Mouseman (non-EMP) pseudo keyboard\n");
163 adbinfo
.siServiceRtPtr
= (Ptr
)0;
164 adbinfo
.siDataAreaAddr
= (Ptr
)0;
165 } else if (kbd_done
&& buffer
[1] == 0x9a && buffer
[2] == 0x21) {
166 printf("Trackman (non-EMP) pseudo keyboard\n");
167 adbinfo
.siServiceRtPtr
= (Ptr
)0;
168 adbinfo
.siDataAreaAddr
= (Ptr
)0;
170 printf("extended keyboard\n");
177 printf("extended keyboard (ISO layout)\n");
183 printf("keyboard II\n");
186 printf("keyboard II (ISO layout)\n");
189 printf("PowerBook keyboard\n");
192 printf("PowerBook keyboard (ISO layout)\n");
195 printf("adjustable keypad\n");
198 printf("adjustable keyboard\n");
201 printf("adjustable keyboard (ISO layout)\n");
204 printf("adjustable keyboard (Japanese layout)\n");
206 case ADB_PBEXTISOKBD
:
207 printf("PowerBook extended keyboard (ISO layout)\n");
209 case ADB_PBEXTJAPKBD
:
210 printf("PowerBook extended keyboard (Japanese layout)\n");
213 printf("keyboard II (Japanese layout)\n");
216 printf("PowerBook extended keyboard\n");
219 printf("extended keyboard\n");
225 printf("PowerBook keyboard (Japanese layout)\n");
228 printf("PowerBook G3 keyboard\n");
231 printf("PowerBook G3 keyboard (Japanese layout)\n");
234 printf("mapped device (%d)\n", sc
->handler_id
);
237 error
= SetADBInfo(&adbinfo
, sc
->adbaddr
);
240 printf("akbd: returned %d from SetADBInfo\n", error
);
243 if (akbd_is_console
&& !akbd_console_attached
) {
244 wskbd_cnattach(&akbd_consops
, sc
, &akbd_keymapdata
);
245 akbd_console_attached
= 1;
248 a
.console
= akbd_is_console
;
249 a
.keymap
= &akbd_keymapdata
;
250 a
.accessops
= &akbd_accessops
;
253 sc
->sc_wskbddev
= config_found(self
, &a
, wskbddevprint
);
258 * Handle putting the keyboard data received from the ADB into
259 * an ADB event record.
262 kbd_adbcomplete(uint8_t *buffer
, uint8_t *data_area
, int adb_command
)
265 struct akbd_softc
*ksc
;
271 printf("adb: transaction completion\n");
274 adbaddr
= ADB_CMDADDR(adb_command
);
275 ksc
= (struct akbd_softc
*)data_area
;
277 event
.addr
= adbaddr
;
278 event
.hand_id
= ksc
->handler_id
;
279 event
.def_addr
= ksc
->origaddr
;
280 event
.byte_count
= buffer
[0];
281 memcpy(event
.bytes
, buffer
+ 1, event
.byte_count
);
285 printf("akbd: from %d at %d (org %d) %d:", event
.addr
,
286 event
.hand_id
, event
.def_addr
, buffer
[0]);
287 for (i
= 1; i
<= buffer
[0]; i
++)
288 printf(" %x", buffer
[i
]);
293 microtime(&event
.timestamp
);
295 kbd_processevent(&event
, ksc
);
299 * Given a keyboard ADB event, record the keycodes and call the key
300 * repeat handler, optionally passing the event through the mouse
301 * button emulation handler first.
304 kbd_processevent(adb_event_t
*event
, struct akbd_softc
*ksc
)
306 adb_event_t new_event
;
309 new_event
.u
.k
.key
= event
->bytes
[0];
310 new_event
.bytes
[1] = 0xff;
311 kbd_intr(&new_event
);
313 aed_input(&new_event
);
315 if (event
->bytes
[1] != 0xff) {
316 new_event
.u
.k
.key
= event
->bytes
[1];
317 new_event
.bytes
[0] = event
->bytes
[1];
318 new_event
.bytes
[1] = 0xff;
319 kbd_intr(&new_event
);
321 aed_input(&new_event
);
329 * Get the actual hardware LED state and convert it to softc format.
335 u_char buffer
[9], leds
;
337 leds
= 0x00; /* all off */
341 cmd
= ADBTALK(addr
, 2);
342 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
) == 0 &&
344 leds
= ~(buffer
[2]) & 0x07;
350 * Set the keyboard LED's.
352 * Automatically translates from ioctl/softc format to the
353 * actual keyboard register format
356 setleds(struct akbd_softc
*ksc
, u_char leds
)
362 if ((leds
& 0x07) == (ksc
->sc_leds
& 0x07))
368 cmd
= ADBTALK(addr
, 2);
369 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
) || buffer
[0] == 0)
376 cmd
= ADBLISTEN(addr
, 2);
377 adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
);
379 cmd
= ADBTALK(addr
, 2);
380 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
) || buffer
[0] == 0)
383 ksc
->sc_leds
= ~((u_int8_t
)buffer
[2]) & 0x07;
385 if ((buffer
[2] & 0xf8) != leds
)
392 * Toggle all of the LED's on and off, just for show.
395 blinkleds(struct akbd_softc
*ksc
)
398 u_char blinkleds
, origleds
;
401 origleds
= getleds(addr
);
402 blinkleds
= LED_NUMLOCK
| LED_CAPSLOCK
| LED_SCROLL_LOCK
;
404 (void)setleds(ksc
, blinkleds
);
406 for (i
= 0; i
< 10000; i
++)
409 /* make sure that we restore the LED settings */
412 (void)setleds(ksc
, (u_char
)0x00);
413 } while (setleds(ksc
, (u_char
)0x00) && (i
-- > 0));
420 akbd_enable(void *v
, int on
)
426 akbd_set_leds(void *v
, int on
)
431 akbd_ioctl(void *v
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
433 #ifdef WSDISPLAY_COMPAT_RAWKBD
434 struct akbd_softc
*sc
= (struct akbd_softc
*) v
;
440 *(int *)data
= WSKBD_TYPE_ADB
;
442 case WSKBDIO_SETLEDS
:
444 case WSKBDIO_GETLEDS
:
447 #ifdef WSDISPLAY_COMPAT_RAWKBD
448 case WSKBDIO_SETMODE
:
449 sc
->sc_rawkbd
= *(int *)data
== WSKBD_RAW
;
458 extern int adb_polling
;
461 kbd_passup(struct akbd_softc
*sc
,int key
)
463 if (sc
->sc_polling
) {
464 if (sc
->sc_npolledkeys
<
465 (sizeof(sc
->sc_polledkeys
)/sizeof(unsigned char))) {
466 sc
->sc_polledkeys
[sc
->sc_npolledkeys
++] = key
;
470 printf("akbd: dumping polled key 0x%02x\n",key
);
473 #ifdef WSDISPLAY_COMPAT_RAWKBD
474 } else if (sc
->sc_rawkbd
) {
478 int c
= keyboard
[ADBK_KEYVAL(key
)][3];
480 if (c
== 0) /* XXX */
486 cbuf
[j
++] = (c
& 0x7f) | (ADBK_PRESS(key
)? 0 : 0x80);
489 wskbd_rawinput(sc
->sc_wskbddev
, cbuf
, j
);
496 press
= ADBK_PRESS(key
);
497 val
= ADBK_KEYVAL(key
);
499 type
= press
? WSCONS_EVENT_KEY_DOWN
: WSCONS_EVENT_KEY_UP
;
501 wskbd_input(sc
->sc_wskbddev
, type
, val
);
508 adb_event_t
*event
= arg
;
510 #ifdef CAPS_IS_CONTROL
514 struct akbd_softc
*sc
= device_lookup_private(&akbd_cd
, 0);
516 key
= event
->u
.k
.key
;
518 #ifdef CAPS_IS_CONTROL
520 * Caps lock is weird. The key sequence generated is:
521 * press: down(57) [57] (LED turns on)
522 * release: up(127) [255]
523 * press: up(127) [255]
524 * release: up(57) [185] (LED turns off)
526 if ((key
== 57) || (key
== 185))
541 #ifndef CAPS_IS_CONTROL
542 case 57: /* Caps Lock pressed */
543 case 185: /* Caps Lock released */
544 key
= ADBK_KEYDOWN(ADBK_KEYVAL(key
));
546 key
= ADBK_KEYUP(ADBK_KEYVAL(key
));
550 if (pcmcia_soft_eject
)
554 if (pcmcia_soft_eject
)
573 akbd_cngetc(void *v
, u_int
*type
, int *data
)
577 struct akbd_softc
*sc
= v
;
581 KASSERT(sc
->sc_polling
);
582 KASSERT(adb_polling
);
584 while (sc
->sc_npolledkeys
== 0) {
586 DELAY(10000); /* XXX */
591 key
= sc
->sc_polledkeys
[0];
592 sc
->sc_npolledkeys
--;
593 memmove(sc
->sc_polledkeys
,sc
->sc_polledkeys
+1,
594 sc
->sc_npolledkeys
* sizeof(unsigned char));
596 press
= ADBK_PRESS(key
);
597 val
= ADBK_KEYVAL(key
);
600 *type
= press
? WSCONS_EVENT_KEY_DOWN
: WSCONS_EVENT_KEY_UP
;
604 akbd_cnpollc(void *v
, int on
)
606 struct akbd_softc
*sc
= v
;
610 for(i
=0;i
<sc
->sc_npolledkeys
;i
++) {
611 kbd_passup(sc
,sc
->sc_polledkeys
[i
]);
613 sc
->sc_npolledkeys
= 0;