1 /* $NetBSD: akbd.c,v 1.20 2007/03/05 21:06:24 he 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.20 2007/03/05 21:06:24 he Exp $");
38 #include <sys/param.h>
39 #include <sys/device.h>
40 #include <sys/fcntl.h>
42 #include <sys/select.h>
44 #include <sys/signalvar.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
51 #include <dev/wscons/wsconsio.h>
52 #include <dev/wscons/wskbdvar.h>
53 #include <dev/wscons/wsksymdef.h>
54 #include <dev/wscons/wsksymvar.h>
56 #include <machine/autoconf.h>
57 #include <machine/cpu.h>
58 #define KEYBOARD_ARRAY
59 #include <machine/keyboard.h>
60 #include <machine/viareg.h>
62 #include <mac68k/mac68k/macrom.h>
63 #include <mac68k/dev/adbvar.h>
64 #include <mac68k/dev/aedvar.h>
65 #include <mac68k/dev/akbdmap.h>
66 #include <mac68k/dev/akbdvar.h>
67 #include <mac68k/dev/amsvar.h>
70 * Function declarations.
72 static int akbdmatch(struct device
*, struct cfdata
*, void *);
73 static void akbdattach(struct device
*, struct device
*, void *);
74 static void kbd_processevent(adb_event_t
*, struct akbd_softc
*);
76 static u_char
getleds(int);
77 static int setleds(struct akbd_softc
*, u_char
);
78 static void blinkleds(struct akbd_softc
*);
85 /* Driver definition. */
86 CFATTACH_DECL(akbd
, sizeof(struct akbd_softc
),
87 akbdmatch
, akbdattach
, NULL
, NULL
);
89 extern struct cfdriver akbd_cd
;
91 int kbd_intr(adb_event_t
*, struct akbd_softc
*);
92 int akbd_enable(void *, int);
93 void akbd_set_leds(void *, int);
94 int akbd_ioctl(void *, u_long
, void *, int, struct lwp
*);
96 struct wskbd_accessops akbd_accessops
= {
102 void akbd_cngetc(void *, u_int
*, int *);
103 void akbd_cnpollc(void *, int);
104 int akbd_cnattach(void);
106 struct wskbd_consops akbd_consops
= {
111 struct wskbd_mapdata akbd_keymapdata
= {
116 static int akbd_is_console(void);
119 akbdmatch(struct device
*parent
, struct cfdata
*cf
, void *aux
)
121 struct adb_attach_args
*aa_args
= (struct adb_attach_args
*)aux
;
123 if (aa_args
->origaddr
== ADBADDR_KBD
)
130 akbdattach(struct device
*parent
, struct device
*self
, void *aux
)
132 ADBSetInfoBlock adbinfo
;
133 struct akbd_softc
*sc
= (struct akbd_softc
*)self
;
134 struct adb_attach_args
*aa_args
= (struct adb_attach_args
*)aux
;
139 struct wskbddev_attach_args a
;
140 static int akbd_console_initted
;
146 sc
->origaddr
= aa_args
->origaddr
;
147 sc
->adbaddr
= aa_args
->adbaddr
;
148 sc
->handler_id
= aa_args
->handler_id
;
150 sc
->sc_leds
= (u_int8_t
)0x00; /* initially off */
152 adbinfo
.siServiceRtPtr
= (Ptr
)adb_kbd_asmcomplete
;
153 adbinfo
.siDataAreaAddr
= (void *)sc
;
155 switch (sc
->handler_id
) {
157 printf("standard keyboard\n");
160 printf("standard keyboard (ISO layout)\n");
163 cmd
= ADBTALK(sc
->adbaddr
, 1);
165 (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
) == 0);
167 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */
168 if (kbd_done
&& buffer
[1] == 0x9a && buffer
[2] == 0x20) {
169 printf("Mouseman (non-EMP) pseudo keyboard\n");
170 adbinfo
.siServiceRtPtr
= (Ptr
)0;
171 adbinfo
.siDataAreaAddr
= (Ptr
)0;
174 #endif /* NWSKBD > 0 */
175 } else if (kbd_done
&& buffer
[1] == 0x9a && buffer
[2] == 0x21) {
176 printf("Trackman (non-EMP) pseudo keyboard\n");
177 adbinfo
.siServiceRtPtr
= (Ptr
)0;
178 adbinfo
.siDataAreaAddr
= (Ptr
)0;
181 #endif /* NWSKBD > 0 */
183 printf("extended keyboard\n");
190 printf("extended keyboard (ISO layout)\n");
196 printf("keyboard II\n");
199 printf("keyboard II (ISO layout)\n");
202 printf("PowerBook keyboard\n");
205 printf("PowerBook keyboard (ISO layout)\n");
208 printf("adjustable keypad\n");
211 #endif /* NWSKBD > 0 */
214 printf("adjustable keyboard\n");
217 printf("adjustable keyboard (ISO layout)\n");
220 printf("adjustable keyboard (Japanese layout)\n");
222 case ADB_PBEXTISOKBD
:
223 printf("PowerBook extended keyboard (ISO layout)\n");
225 case ADB_PBEXTJAPKBD
:
226 printf("PowerBook extended keyboard (Japanese layout)\n");
229 printf("keyboard II (Japanese layout)\n");
232 printf("PowerBook extended keyboard\n");
235 printf("extended keyboard\n");
241 printf("PowerBook keyboard (Japanese layout)\n");
244 printf("mapped device (%d)\n", sc
->handler_id
);
247 #endif /* NWSKBD > 0 */
250 error
= SetADBInfo(&adbinfo
, sc
->adbaddr
);
253 printf("akbd: returned %d from SetADBInfo\n", error
);
257 if (akbd_is_console() && wskbd_eligible
)
258 a
.console
= (++akbd_console_initted
== 1);
261 a
.keymap
= &akbd_keymapdata
;
262 a
.accessops
= &akbd_accessops
;
265 sc
->sc_wskbddev
= config_found(self
, &a
, wskbddevprint
);
271 * Handle putting the keyboard data received from the ADB into
272 * an ADB event record.
275 kbd_adbcomplete(uint8_t *buffer
, void *data_area
, int adb_command
)
278 struct akbd_softc
*ksc
;
284 printf("adb: transaction completion\n");
287 adbaddr
= ADB_CMDADDR(adb_command
);
288 ksc
= (struct akbd_softc
*)data_area
;
290 event
.addr
= adbaddr
;
291 event
.hand_id
= ksc
->handler_id
;
292 event
.def_addr
= ksc
->origaddr
;
293 event
.byte_count
= buffer
[0];
294 memcpy(event
.bytes
, buffer
+ 1, event
.byte_count
);
298 printf("akbd: from %d at %d (org %d) %d:", event
.addr
,
299 event
.hand_id
, event
.def_addr
, buffer
[0]);
300 for (i
= 1; i
<= buffer
[0]; i
++)
301 printf(" %x", buffer
[i
]);
306 microtime(&event
.timestamp
);
308 kbd_processevent(&event
, ksc
);
312 * Given a keyboard ADB event, record the keycodes and call the key
313 * repeat handler, optionally passing the event through the mouse
314 * button emulation handler first.
317 kbd_processevent(adb_event_t
*event
, struct akbd_softc
*ksc
)
319 adb_event_t new_event
;
322 new_event
.u
.k
.key
= event
->bytes
[0];
323 new_event
.bytes
[1] = 0xff;
325 if (adb_polling
|| !aed_input(&new_event
))
328 if (ksc
->sc_wskbddev
!= NULL
) /* wskbd is attached? */
329 kbd_intr(&new_event
, ksc
);
333 if (event
->bytes
[1] != 0xff) {
334 new_event
.u
.k
.key
= event
->bytes
[1];
335 new_event
.bytes
[0] = event
->bytes
[1];
336 new_event
.bytes
[1] = 0xff;
338 if (adb_polling
|| !aed_input(&new_event
))
341 if (ksc
->sc_wskbddev
!= NULL
) /* wskbd is attached? */
342 kbd_intr(&new_event
, ksc
);
352 * Get the actual hardware LED state and convert it to softc format.
358 u_char buffer
[9], leds
;
360 leds
= 0x00; /* all off */
363 cmd
= ADBTALK(addr
, 2);
364 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
) == 0 &&
366 leds
= ~(buffer
[2]) & 0x07;
372 * Set the keyboard LED's.
374 * Automatically translates from ioctl/softc format to the
375 * actual keyboard register format
378 setleds(struct akbd_softc
*ksc
, u_char leds
)
384 if ((leds
& 0x07) == (ksc
->sc_leds
& 0x07))
390 cmd
= ADBTALK(addr
, 2);
391 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
) || buffer
[0] == 0)
398 cmd
= ADBLISTEN(addr
, 2);
399 adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
);
402 cmd
= ADBTALK(addr
, 2);
403 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
) || buffer
[0] == 0)
406 ksc
->sc_leds
= ~((u_int8_t
)buffer
[2]) & 0x07;
408 if ((buffer
[2] & 0xf8) != leds
)
415 * Toggle all of the LED's on and off, just for show.
418 blinkleds(struct akbd_softc
*ksc
)
421 u_char blinkleds
, origleds
;
424 origleds
= getleds(addr
);
425 blinkleds
= LED_NUMLOCK
| LED_CAPSLOCK
| LED_SCROLL_LOCK
;
427 (void)setleds(ksc
, blinkleds
);
429 for (i
= 0; i
< 10000; i
++)
432 /* make sure that we restore the LED settings */
435 (void)setleds(ksc
, (u_char
)0x00);
436 } while (setleds(ksc
, (u_char
)0x00) && (i
-- > 0));
443 akbd_is_console(void)
445 extern struct mac68k_machine_S mac68k_machine
;
447 return ((mac68k_machine
.serial_console
& 0x03) == 0);
451 akbd_enable(void *v
, int on
)
457 akbd_set_leds(void *v
, int on
)
462 akbd_ioctl(void *v
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
467 *(int *)data
= 0; /* XXX */
469 case WSKBDIO_SETLEDS
:
471 case WSKBDIO_GETLEDS
:
475 case WSKBDIO_COMPLEXBELL
:
476 #define d ((struct wskbd_bell_data *)data)
477 mac68k_ring_bell(d
->pitch
, d
->period
* hz
/ 1000, 100);
478 /* comes in as msec, goes out as ticks; volume ignored */
487 static int polledkey
;
488 extern int adb_polling
;
491 kbd_intr(adb_event_t
*event
, struct akbd_softc
*sc
)
496 key
= event
->u
.k
.key
;
497 press
= ADBK_PRESS(key
);
498 val
= ADBK_KEYVAL(key
);
500 type
= press
? WSCONS_EVENT_KEY_DOWN
: WSCONS_EVENT_KEY_UP
;
502 if (key
== 185) { /* Caps Lock released */
503 type
= WSCONS_EVENT_KEY_DOWN
;
504 wskbd_input(sc
->sc_wskbddev
, type
, val
);
505 type
= WSCONS_EVENT_KEY_UP
;
511 wskbd_input(sc
->sc_wskbddev
, type
, val
);
519 wskbd_cnattach(&akbd_consops
, NULL
, &akbd_keymapdata
);
525 akbd_cngetc(void *v
, u_int
*type
, int *data
)
527 int intbits
, key
, press
, val
;
535 while (polledkey
== -1) {
536 intbits
= via_reg(VIA1
, vIFR
);
538 if (intbits
& V1IF_ADBRDY
) {
540 via_reg(VIA1
, vIFR
) = V1IF_ADBRDY
;
542 if (intbits
& 0x10) {
544 via_reg(VIA1
, vIFR
) = 0x10;
552 press
= ADBK_PRESS(key
);
553 val
= ADBK_KEYVAL(key
);
556 *type
= press
? WSCONS_EVENT_KEY_DOWN
: WSCONS_EVENT_KEY_UP
;
560 akbd_cnpollc(void *v
, int on
)