xref: /openbsd-src/sys/dev/adb/akbd.c (revision c1cc27a74adfab431ed95c467b02b6c4875726e1)
1*c1cc27a7Sgkoehler /*	$OpenBSD: akbd.c,v 1.16 2022/10/21 22:42:36 gkoehler Exp $	*/
2305d9e87Smiod /*	$NetBSD: akbd.c,v 1.17 2005/01/15 16:00:59 chs Exp $	*/
3305d9e87Smiod 
4305d9e87Smiod /*
5305d9e87Smiod  * Copyright (C) 1998	Colin Wood
6305d9e87Smiod  * All rights reserved.
7305d9e87Smiod  *
8305d9e87Smiod  * Redistribution and use in source and binary forms, with or without
9305d9e87Smiod  * modification, are permitted provided that the following conditions
10305d9e87Smiod  * are met:
11305d9e87Smiod  * 1. Redistributions of source code must retain the above copyright
12305d9e87Smiod  *    notice, this list of conditions and the following disclaimer.
13305d9e87Smiod  * 2. Redistributions in binary form must reproduce the above copyright
14305d9e87Smiod  *    notice, this list of conditions and the following disclaimer in the
15305d9e87Smiod  *    documentation and/or other materials provided with the distribution.
16305d9e87Smiod  * 3. All advertising materials mentioning features or use of this software
17305d9e87Smiod  *    must display the following acknowledgement:
18305d9e87Smiod  *	This product includes software developed by Colin Wood.
19305d9e87Smiod  * 4. The name of the author may not be used to endorse or promote products
20305d9e87Smiod  *    derived from this software without specific prior written permission.
21305d9e87Smiod  *
22305d9e87Smiod  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23305d9e87Smiod  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24305d9e87Smiod  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25305d9e87Smiod  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26305d9e87Smiod  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27305d9e87Smiod  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28305d9e87Smiod  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29305d9e87Smiod  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30305d9e87Smiod  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31305d9e87Smiod  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32305d9e87Smiod  */
33305d9e87Smiod 
34305d9e87Smiod #include <sys/param.h>
35305d9e87Smiod #include <sys/timeout.h>
36305d9e87Smiod #include <sys/kernel.h>
37305d9e87Smiod #include <sys/device.h>
38305d9e87Smiod #include <sys/systm.h>
39305d9e87Smiod 
40305d9e87Smiod #include <dev/wscons/wsconsio.h>
41305d9e87Smiod #include <dev/wscons/wskbdvar.h>
42305d9e87Smiod #include <dev/wscons/wsksymdef.h>
43305d9e87Smiod #include <dev/wscons/wsksymvar.h>
44305d9e87Smiod 
45305d9e87Smiod #include <machine/autoconf.h>
46305d9e87Smiod #include <machine/cpu.h>
47305d9e87Smiod 
48305d9e87Smiod #include <dev/adb/adb.h>
49305d9e87Smiod #include <dev/adb/akbdmap.h>
50305d9e87Smiod #include <dev/adb/akbdvar.h>
51305d9e87Smiod #include <dev/adb/keyboard.h>
52305d9e87Smiod 
53305d9e87Smiod /*
54305d9e87Smiod  * Function declarations.
55305d9e87Smiod  */
56305d9e87Smiod int	akbdmatch(struct device *, void *, void *);
57305d9e87Smiod void	akbdattach(struct device *, struct device *, void *);
58305d9e87Smiod 
59305d9e87Smiod /* Driver definition. */
60471aeecfSnaddy const struct cfattach akbd_ca = {
61305d9e87Smiod 	sizeof(struct akbd_softc), akbdmatch, akbdattach
62305d9e87Smiod };
63305d9e87Smiod struct cfdriver akbd_cd = {
64305d9e87Smiod 	NULL, "akbd", DV_DULL
65305d9e87Smiod };
66305d9e87Smiod 
67305d9e87Smiod int	akbd_enable(void *, int);
68305d9e87Smiod void	akbd_set_leds(void *, int);
69305d9e87Smiod int	akbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
70305d9e87Smiod 
71305d9e87Smiod 
72305d9e87Smiod struct wskbd_accessops akbd_accessops = {
73305d9e87Smiod 	akbd_enable,
74305d9e87Smiod 	akbd_set_leds,
75305d9e87Smiod 	akbd_ioctl,
76305d9e87Smiod };
77305d9e87Smiod 
78305d9e87Smiod struct wskbd_mapdata akbd_keymapdata = {
79305d9e87Smiod 	akbd_keydesctab,
80305d9e87Smiod #ifdef AKBD_LAYOUT
81305d9e87Smiod 	AKBD_LAYOUT,
82305d9e87Smiod #else
83c8b0a2fbSmiod 	KB_US | KB_DEFAULT,
84305d9e87Smiod #endif
85305d9e87Smiod };
86305d9e87Smiod 
87a1387c96Smiod void	akbd_adbcomplete(caddr_t, caddr_t, int);
88a1387c96Smiod void	akbd_capslockwrapper(struct akbd_softc *, int);
89a1387c96Smiod void	akbd_input(struct akbd_softc *, int);
90a1387c96Smiod void	akbd_processevent(struct akbd_softc *, adb_event_t *);
91a1387c96Smiod #ifdef notyet
92a1387c96Smiod u_char	getleds(int);
93a1387c96Smiod int	setleds(struct akbd_softc *, u_char);
94a1387c96Smiod void	blinkleds(struct akbd_softc *);
95a1387c96Smiod #endif
96a1387c96Smiod 
97305d9e87Smiod int
akbdmatch(struct device * parent,void * vcf,void * aux)98305d9e87Smiod akbdmatch(struct device *parent, void *vcf, void *aux)
99305d9e87Smiod {
100305d9e87Smiod 	struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
101305d9e87Smiod 
1024425d974Smiod 	if (strcmp(aa_args->name, adb_device_name) != 0)
1034425d974Smiod 		return (0);
1044425d974Smiod 
105305d9e87Smiod 	if (aa_args->origaddr == ADBADDR_KBD)
106a1387c96Smiod 		return (1);
107305d9e87Smiod 	else
108a1387c96Smiod 		return (0);
109305d9e87Smiod }
110305d9e87Smiod 
111305d9e87Smiod void
akbdattach(struct device * parent,struct device * self,void * aux)112305d9e87Smiod akbdattach(struct device *parent, struct device *self, void *aux)
113305d9e87Smiod {
114305d9e87Smiod 	ADBSetInfoBlock adbinfo;
115305d9e87Smiod 	struct akbd_softc *sc = (struct akbd_softc *)self;
116305d9e87Smiod 	struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
117305d9e87Smiod 	int error, kbd_done;
118305d9e87Smiod 	short cmd;
119305d9e87Smiod 	u_char buffer[9];
120305d9e87Smiod 	struct wskbddev_attach_args a;
121305d9e87Smiod 	static int akbd_console_initted;
122305d9e87Smiod 	int wskbd_eligible = 1;
123305d9e87Smiod 
124305d9e87Smiod 	sc->origaddr = aa_args->origaddr;
125305d9e87Smiod 	sc->adbaddr = aa_args->adbaddr;
126305d9e87Smiod 	sc->handler_id = aa_args->handler_id;
127305d9e87Smiod 
128305d9e87Smiod 	sc->sc_leds = (u_int8_t)0x00;	/* initially off */
12971b69b65Smiod 	sc->sc_caps = 0;
1309b089153Smpi 	sc->sc_iso = 0;
131305d9e87Smiod 
132a1387c96Smiod 	adbinfo.siServiceRtPtr = (Ptr)akbd_adbcomplete;
133305d9e87Smiod 	adbinfo.siDataAreaAddr = (caddr_t)sc;
134305d9e87Smiod 
135305d9e87Smiod 	printf(": ");
136305d9e87Smiod 	switch (sc->handler_id) {
137305d9e87Smiod 	case ADB_STDKBD:
138305d9e87Smiod 		printf("standard keyboard\n");
139305d9e87Smiod 		break;
140305d9e87Smiod 	case ADB_ISOKBD:
141305d9e87Smiod 		printf("standard keyboard (ISO layout)\n");
1429b089153Smpi 		sc->sc_iso = 1;
143305d9e87Smiod 		break;
144305d9e87Smiod 	case ADB_EXTKBD:
145305d9e87Smiod 		cmd = ADBTALK(sc->adbaddr, 1);
146305d9e87Smiod 		kbd_done =
14774a0040aSmiod 		    (adb_op_sync((Ptr)buffer, cmd) == 0);
148305d9e87Smiod 
149305d9e87Smiod 		/* Ignore Logitech MouseMan/Trackman pseudo keyboard */
150305d9e87Smiod 		if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x20) {
151305d9e87Smiod 			printf("Mouseman (non-EMP) pseudo keyboard\n");
152305d9e87Smiod 			adbinfo.siServiceRtPtr = (Ptr)0;
153305d9e87Smiod 			adbinfo.siDataAreaAddr = (Ptr)0;
154305d9e87Smiod 			wskbd_eligible = 0;
155305d9e87Smiod 		} else if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x21) {
156305d9e87Smiod 			printf("Trackman (non-EMP) pseudo keyboard\n");
157305d9e87Smiod 			adbinfo.siServiceRtPtr = (Ptr)0;
158305d9e87Smiod 			adbinfo.siDataAreaAddr = (Ptr)0;
159305d9e87Smiod 			wskbd_eligible = 0;
160305d9e87Smiod 		} else {
161305d9e87Smiod 			printf("extended keyboard\n");
162305d9e87Smiod #ifdef notyet
163305d9e87Smiod 			blinkleds(sc);
164305d9e87Smiod #endif
165305d9e87Smiod 		}
166305d9e87Smiod 		break;
167305d9e87Smiod 	case ADB_EXTISOKBD:
168305d9e87Smiod 		printf("extended keyboard (ISO layout)\n");
1699b089153Smpi 		sc->sc_iso = 1;
170305d9e87Smiod #ifdef notyet
171305d9e87Smiod 		blinkleds(sc);
172305d9e87Smiod #endif
173305d9e87Smiod 		break;
174305d9e87Smiod 	case ADB_KBDII:
175305d9e87Smiod 		printf("keyboard II\n");
176305d9e87Smiod 		break;
177305d9e87Smiod 	case ADB_ISOKBDII:
178305d9e87Smiod 		printf("keyboard II (ISO layout)\n");
1799b089153Smpi 		sc->sc_iso = 1;
180305d9e87Smiod 		break;
181305d9e87Smiod 	case ADB_PBKBD:
182305d9e87Smiod 		printf("PowerBook keyboard\n");
183305d9e87Smiod 		break;
184305d9e87Smiod 	case ADB_PBISOKBD:
185305d9e87Smiod 		printf("PowerBook keyboard (ISO layout)\n");
1869b089153Smpi 		sc->sc_iso = 1;
187305d9e87Smiod 		break;
188305d9e87Smiod 	case ADB_ADJKPD:
189305d9e87Smiod 		printf("adjustable keypad\n");
190305d9e87Smiod 		wskbd_eligible = 0;
191305d9e87Smiod 		break;
192305d9e87Smiod 	case ADB_ADJKBD:
193305d9e87Smiod 		printf("adjustable keyboard\n");
194305d9e87Smiod 		break;
195305d9e87Smiod 	case ADB_ADJISOKBD:
196305d9e87Smiod 		printf("adjustable keyboard (ISO layout)\n");
1979b089153Smpi 		sc->sc_iso = 1;
198305d9e87Smiod 		break;
199305d9e87Smiod 	case ADB_ADJJAPKBD:
200305d9e87Smiod 		printf("adjustable keyboard (Japanese layout)\n");
201305d9e87Smiod 		break;
202305d9e87Smiod 	case ADB_PBEXTISOKBD:
203305d9e87Smiod 		printf("PowerBook extended keyboard (ISO layout)\n");
2049b089153Smpi 		sc->sc_iso = 1;
205305d9e87Smiod 		break;
206305d9e87Smiod 	case ADB_PBEXTJAPKBD:
207305d9e87Smiod 		printf("PowerBook extended keyboard (Japanese layout)\n");
208305d9e87Smiod 		break;
209305d9e87Smiod 	case ADB_JPKBDII:
210305d9e87Smiod 		printf("keyboard II (Japanese layout)\n");
211305d9e87Smiod 		break;
212305d9e87Smiod 	case ADB_PBEXTKBD:
213305d9e87Smiod 		printf("PowerBook extended keyboard\n");
214305d9e87Smiod 		break;
215305d9e87Smiod 	case ADB_DESIGNKBD:
216305d9e87Smiod 		printf("extended keyboard\n");
217305d9e87Smiod #ifdef notyet
218305d9e87Smiod 		blinkleds(sc);
219305d9e87Smiod #endif
220305d9e87Smiod 		break;
221305d9e87Smiod 	case ADB_PBJPKBD:
222305d9e87Smiod 		printf("PowerBook keyboard (Japanese layout)\n");
223305d9e87Smiod 		break;
224305d9e87Smiod 	case ADB_PBG3JPKBD:
225305d9e87Smiod 		printf("PowerBook G3 keyboard (Japanese layout)\n");
226305d9e87Smiod 		break;
227305d9e87Smiod 	case ADB_PBG4KBD:
228305d9e87Smiod 		printf("PowerBook G4 keyboard (Inverted T)\n");
229305d9e87Smiod 		break;
230305d9e87Smiod 	case ADB_IBITISOKBD:
231305d9e87Smiod 		printf("iBook keyboard with inverted T (ISO layout)\n");
2329b089153Smpi 		sc->sc_iso = 1;
233305d9e87Smiod 		break;
234305d9e87Smiod 	default:
235305d9e87Smiod 		printf("mapped device (%d)\n", sc->handler_id);
236fa8f4641Smiod #if 0
237305d9e87Smiod 		wskbd_eligible = 0;
238fa8f4641Smiod #endif
239305d9e87Smiod 		break;
240305d9e87Smiod 	}
241305d9e87Smiod 	error = set_adb_info(&adbinfo, sc->adbaddr);
242305d9e87Smiod #ifdef ADB_DEBUG
243305d9e87Smiod 	if (adb_debug)
244305d9e87Smiod 		printf("akbd: returned %d from set_adb_info\n", error);
245305d9e87Smiod #endif
246305d9e87Smiod 
247305d9e87Smiod 	if (akbd_is_console() && wskbd_eligible)
248305d9e87Smiod 		a.console = (++akbd_console_initted == 1);
249305d9e87Smiod 	else
250305d9e87Smiod 		a.console = 0;
251305d9e87Smiod 	a.keymap = &akbd_keymapdata;
252305d9e87Smiod 	a.accessops = &akbd_accessops;
253305d9e87Smiod 	a.accesscookie = sc;
254305d9e87Smiod 
255305d9e87Smiod 	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
256305d9e87Smiod }
257305d9e87Smiod 
258305d9e87Smiod 
259305d9e87Smiod /*
260305d9e87Smiod  * Handle putting the keyboard data received from the ADB into
261305d9e87Smiod  * an ADB event record.
262305d9e87Smiod  */
263305d9e87Smiod void
akbd_adbcomplete(caddr_t buffer,caddr_t data_area,int adb_command)264a1387c96Smiod akbd_adbcomplete(caddr_t buffer, caddr_t data_area, int adb_command)
265305d9e87Smiod {
266305d9e87Smiod 	adb_event_t event;
267a1387c96Smiod 	struct akbd_softc *sc;
268305d9e87Smiod 	int adbaddr;
269305d9e87Smiod #ifdef ADB_DEBUG
270305d9e87Smiod 	int i;
271305d9e87Smiod 
272305d9e87Smiod 	if (adb_debug)
273305d9e87Smiod 		printf("adb: transaction completion\n");
274305d9e87Smiod #endif
275305d9e87Smiod 
276305d9e87Smiod 	adbaddr = ADB_CMDADDR(adb_command);
277a1387c96Smiod 	sc = (struct akbd_softc *)data_area;
278305d9e87Smiod 
279305d9e87Smiod 	event.byte_count = buffer[0];
280305d9e87Smiod 	memcpy(event.bytes, buffer + 1, event.byte_count);
281305d9e87Smiod 
282305d9e87Smiod #ifdef ADB_DEBUG
283305d9e87Smiod 	if (adb_debug) {
284a1387c96Smiod 		printf("akbd: from %d at %d (org %d) %d:", adbaddr,
285a1387c96Smiod 		    sc->handler_id, sc->origaddr, buffer[0]);
286305d9e87Smiod 		for (i = 1; i <= buffer[0]; i++)
287305d9e87Smiod 			printf(" %x", buffer[i]);
288305d9e87Smiod 		printf("\n");
289305d9e87Smiod 	}
290305d9e87Smiod #endif
291305d9e87Smiod 
292a1387c96Smiod 	if (sc->sc_wskbddev != NULL)
293a1387c96Smiod 		akbd_processevent(sc, &event);
294305d9e87Smiod }
295305d9e87Smiod 
296305d9e87Smiod #ifdef notyet
297305d9e87Smiod /*
298305d9e87Smiod  * Get the actual hardware LED state and convert it to softc format.
299305d9e87Smiod  */
300305d9e87Smiod u_char
getleds(int addr)301305d9e87Smiod getleds(int addr)
302305d9e87Smiod {
303305d9e87Smiod 	short cmd;
304305d9e87Smiod 	u_char buffer[9], leds;
305305d9e87Smiod 
306305d9e87Smiod 	leds = 0x00;	/* all off */
307305d9e87Smiod 	buffer[0] = 0;
308305d9e87Smiod 
309305d9e87Smiod 	cmd = ADBTALK(addr, 2);
31074a0040aSmiod 	if (adb_op_sync((Ptr)buffer, cmd) == 0 &&
311305d9e87Smiod 	    buffer[0] > 0)
312305d9e87Smiod 		leds = ~(buffer[2]) & 0x07;
313305d9e87Smiod 
314305d9e87Smiod 	return (leds);
315305d9e87Smiod }
316305d9e87Smiod 
317305d9e87Smiod /*
318305d9e87Smiod  * Set the keyboard LED's.
319305d9e87Smiod  *
320305d9e87Smiod  * Automatically translates from ioctl/softc format to the
321305d9e87Smiod  * actual keyboard register format
322305d9e87Smiod  */
323305d9e87Smiod int
setleds(struct akbd_softc * sc,u_char leds)324a1387c96Smiod setleds(struct akbd_softc *sc, u_char leds)
325305d9e87Smiod {
326305d9e87Smiod 	int addr;
327305d9e87Smiod 	short cmd;
328305d9e87Smiod 	u_char buffer[9];
329305d9e87Smiod 
330a1387c96Smiod 	addr = sc->adbaddr;
331305d9e87Smiod 	buffer[0] = 0;
332305d9e87Smiod 
333305d9e87Smiod 	cmd = ADBTALK(addr, 2);
33474a0040aSmiod 	if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0)
335305d9e87Smiod 		return (EIO);
336305d9e87Smiod 
337305d9e87Smiod 	leds = ~leds & 0x07;
338305d9e87Smiod 	buffer[2] &= 0xf8;
339305d9e87Smiod 	buffer[2] |= leds;
340305d9e87Smiod 
341305d9e87Smiod 	cmd = ADBLISTEN(addr, 2);
34274a0040aSmiod 	adb_op_sync((Ptr)buffer, cmd);
343305d9e87Smiod 
344305d9e87Smiod 	/* talk R2 */
345305d9e87Smiod 	cmd = ADBTALK(addr, 2);
34674a0040aSmiod 	if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0)
347305d9e87Smiod 		return (EIO);
348305d9e87Smiod 
349305d9e87Smiod 	if ((buffer[2] & 0xf8) != leds)
350305d9e87Smiod 		return (EIO);
351305d9e87Smiod 	else
352305d9e87Smiod 		return (0);
353305d9e87Smiod }
354305d9e87Smiod 
355305d9e87Smiod /*
356305d9e87Smiod  * Toggle all of the LED's on and off, just for show.
357305d9e87Smiod  */
358305d9e87Smiod void
blinkleds(struct akbd_softc * sc)359a1387c96Smiod blinkleds(struct akbd_softc *sc)
360305d9e87Smiod {
361a1387c96Smiod 	u_char origleds;
362305d9e87Smiod 
363a1387c96Smiod 	origleds = getleds(sc->adbaddr);
364a1387c96Smiod 	setleds(sc, LED_NUMLOCK | LED_CAPSLOCK | LED_SCROLL_LOCK);
365a1387c96Smiod 	delay(400000);
366a1387c96Smiod 	setleds(sc, origleds);
367305d9e87Smiod 
368a1387c96Smiod 	if (origleds & LED_NUMLOCK)
369a1387c96Smiod 		sc->sc_leds |= WSKBD_LED_NUM;
370a1387c96Smiod 	if (origleds & LED_CAPSLOCK)
371a1387c96Smiod 		sc->sc_leds |= WSKBD_LED_CAPS;
372a1387c96Smiod 	if (origleds & LED_SCROLL_LOCK)
373a1387c96Smiod 		sc->sc_leds |= WSKBD_LED_SCROLL;
374305d9e87Smiod }
375305d9e87Smiod #endif
376305d9e87Smiod 
377305d9e87Smiod int
akbd_enable(void * v,int on)378305d9e87Smiod akbd_enable(void *v, int on)
379305d9e87Smiod {
380305d9e87Smiod 	return 0;
381305d9e87Smiod }
382305d9e87Smiod 
383305d9e87Smiod void
akbd_set_leds(void * v,int on)384305d9e87Smiod akbd_set_leds(void *v, int on)
385305d9e87Smiod {
386a1387c96Smiod #ifdef notyet
387a1387c96Smiod 	struct akbd_softc *sc = v;
388a1387c96Smiod 	int leds;
389a1387c96Smiod 
390a1387c96Smiod 	if (sc->sc_extended) {
391a1387c96Smiod 		if (sc->sc_leds == on)
392a1387c96Smiod 			return;
393a1387c96Smiod 
394a1387c96Smiod 		leds = 0;
395a1387c96Smiod 		if (on & WSKBD_LED_NUM)
396a1387c96Smiod 			leds |= LED_NUMLOCK;
397a1387c96Smiod 		if (on & WSKBD_LED_CAPS)
398a1387c96Smiod 			leds |= LED_CAPSLOCK;
399a1387c96Smiod 		if (on & WSKBD_LED_SCROLL)
400a1387c96Smiod 			leds |= LED_SCROLL_LOCK;
401a1387c96Smiod 
402a1387c96Smiod 		setleds(sc, leds);
403a1387c96Smiod 	}
404a1387c96Smiod #endif
405305d9e87Smiod }
406305d9e87Smiod 
407305d9e87Smiod int
akbd_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)408305d9e87Smiod akbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
409305d9e87Smiod {
410305d9e87Smiod 	struct akbd_softc *sc = v;
411305d9e87Smiod 
412305d9e87Smiod 	switch (cmd) {
413305d9e87Smiod 
414305d9e87Smiod 	case WSKBDIO_GTYPE:
415305d9e87Smiod 		*(int *)data = WSKBD_TYPE_ADB;
416305d9e87Smiod 		return 0;
417305d9e87Smiod 	case WSKBDIO_SETLEDS:
418a1387c96Smiod 		akbd_set_leds(v, *(int *)data);
419305d9e87Smiod 		return 0;
420305d9e87Smiod 	case WSKBDIO_GETLEDS:
421a1387c96Smiod 		*(int *)data = sc->sc_leds;
422305d9e87Smiod 		return 0;
423305d9e87Smiod #ifdef WSDISPLAY_COMPAT_RAWKBD
424305d9e87Smiod 	case WSKBDIO_SETMODE:
425305d9e87Smiod 		sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
426305d9e87Smiod 		return (0);
427305d9e87Smiod #endif
428305d9e87Smiod 	default:
429305d9e87Smiod 		return (-1);
430305d9e87Smiod 	}
431305d9e87Smiod }
432305d9e87Smiod 
433305d9e87Smiod /*
43471b69b65Smiod  * The ``caps lock'' key is special: since on earlier keyboards, the physical
43571b69b65Smiod  * key stays down when pressed, we will get a notification of the key press,
43671b69b65Smiod  * but not of the key release. Then, when it is pressed again, we will not get
43771b69b65Smiod  * a notification of the key press, but will see the key release.
43871b69b65Smiod  *
43971b69b65Smiod  * This is not exactly true. We see the missing release and press events both
44071b69b65Smiod  * as the release of the power (reset) key.
44171b69b65Smiod  *
44271b69b65Smiod  * To avoid confusing them with real power key presses, we maintain two
44371b69b65Smiod  * states for the caps lock key: logically down (from wscons' point of view),
44471b69b65Smiod  * and ``physically'' down (from the adb messages point of view), to ignore
44571b69b65Smiod  * the power key. But since one may press the power key while the caps lock
44671b69b65Smiod  * is held down, we also have to remember the state of the power key... this
44771b69b65Smiod  * is quite messy.
44871b69b65Smiod  */
44971b69b65Smiod 
45071b69b65Smiod /*
45171b69b65Smiod  * Values for caps lock state machine
45271b69b65Smiod  */
45371b69b65Smiod #define	CL_DOWN_ADB	0x01
45471b69b65Smiod #define	CL_DOWN_LOGICAL	0x02
45571b69b65Smiod #define	CL_DOWN_RESET	0x04
45671b69b65Smiod 
45771b69b65Smiod /*
458a1387c96Smiod  * Given a keyboard ADB event, decode the keycodes and pass them to wskbd.
459305d9e87Smiod  */
460a1387c96Smiod void
akbd_processevent(struct akbd_softc * sc,adb_event_t * event)461a1387c96Smiod akbd_processevent(struct akbd_softc *sc, adb_event_t *event)
462a1387c96Smiod {
463a1387c96Smiod 	switch (event->byte_count) {
464a1387c96Smiod 	case 1:
465a1387c96Smiod 		akbd_capslockwrapper(sc, event->bytes[0]);
466a1387c96Smiod 		break;
467a1387c96Smiod 	case 2:
468a1387c96Smiod 		/*
469a1387c96Smiod 		 * The reset (or power) key sends 0x7f7f on press and
470*c1cc27a7Sgkoehler 		 * 0xffff on release.
471a1387c96Smiod 		 */
472a1387c96Smiod 		if (event->bytes[0] == event->bytes[1] &&
47371b69b65Smiod 		    ADBK_KEYVAL(event->bytes[0]) == ADBK_RESET) {
474*c1cc27a7Sgkoehler 			if (event->bytes[0] == ADBK_KEYDOWN(ADBK_RESET)) {
47571b69b65Smiod 				SET(sc->sc_caps, CL_DOWN_RESET);
476*c1cc27a7Sgkoehler 				adb_power_button_intr();
477*c1cc27a7Sgkoehler 			} else {
47871b69b65Smiod 				if (ISSET(sc->sc_caps, CL_DOWN_RESET))
47971b69b65Smiod 					CLR(sc->sc_caps, CL_DOWN_RESET);
48071b69b65Smiod 				else if (ISSET(sc->sc_caps, CL_DOWN_ADB)) {
48171b69b65Smiod 					akbd_input(sc, ISSET(sc->sc_caps,
48271b69b65Smiod 					    CL_DOWN_LOGICAL) ?
48371b69b65Smiod 					      ADBK_KEYDOWN(ADBK_CAPSLOCK) :
48471b69b65Smiod 					      ADBK_KEYUP(ADBK_CAPSLOCK));
48571b69b65Smiod 					sc->sc_caps ^= CL_DOWN_LOGICAL;
48671b69b65Smiod 				}
48771b69b65Smiod 			}
48871b69b65Smiod 		} else {
489a1387c96Smiod 			akbd_capslockwrapper(sc, event->bytes[0]);
490a1387c96Smiod 			akbd_capslockwrapper(sc, event->bytes[1]);
49171b69b65Smiod 		}
492a1387c96Smiod 		break;
493a1387c96Smiod 	default:
494a1387c96Smiod #ifdef DIAGNOSTIC
495a1387c96Smiod 		printf("%s: unexpected message length %d\n",
496a1387c96Smiod 		    sc->sc_dev.dv_xname, event->byte_count);
497a1387c96Smiod #endif
498a1387c96Smiod 		break;
499a1387c96Smiod 	}
500305d9e87Smiod 
501a1387c96Smiod }
502a1387c96Smiod 
503a1387c96Smiod void
akbd_capslockwrapper(struct akbd_softc * sc,int key)504a1387c96Smiod akbd_capslockwrapper(struct akbd_softc *sc, int key)
505a1387c96Smiod {
50671b69b65Smiod 	if (ADBK_KEYVAL(key) == ADBK_CAPSLOCK)
50771b69b65Smiod 		sc->sc_caps ^= CL_DOWN_ADB;
50871b69b65Smiod 
509a1387c96Smiod 	if (key != 0xff)
510a1387c96Smiod 		akbd_input(sc, key);
511305d9e87Smiod }
512305d9e87Smiod 
5139b089153Smpi static inline int
akbd_iso_swap(int keycode)5149b089153Smpi akbd_iso_swap(int keycode)
5159b089153Smpi {
5169b089153Smpi 	switch (keycode) {
5179b089153Smpi 	case 10:
5189b089153Smpi 		return (50);
5199b089153Smpi 	case 50:
5209b089153Smpi 		return (10);
5219b089153Smpi 	default:
5229b089153Smpi 		return (keycode);
5239b089153Smpi 	}
5249b089153Smpi }
5259b089153Smpi 
526a1387c96Smiod int adb_polledkey;
527a1387c96Smiod void
akbd_input(struct akbd_softc * sc,int key)528a1387c96Smiod akbd_input(struct akbd_softc *sc, int key)
529a1387c96Smiod {
530a1387c96Smiod 	int press, val;
531a1387c96Smiod 	int type;
532a1387c96Smiod 
533305d9e87Smiod 	press = ADBK_PRESS(key);
534305d9e87Smiod 	val = ADBK_KEYVAL(key);
535305d9e87Smiod 
5369b089153Smpi 	if (sc->sc_iso)
5379b089153Smpi 		val = akbd_iso_swap(val);
5389b089153Smpi 
539305d9e87Smiod 	type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
540305d9e87Smiod 
541305d9e87Smiod 	if (adb_polling) {
542305d9e87Smiod 		adb_polledkey = key;
543305d9e87Smiod #ifdef WSDISPLAY_COMPAT_RAWKBD
544305d9e87Smiod 	} else if (sc->sc_rawkbd) {
5457ce15ad7Sshadchin 		char cbuf[2];
546305d9e87Smiod 		int c, j, s;
547305d9e87Smiod 
5487ce15ad7Sshadchin 		j = 0;
549305d9e87Smiod 
5504937d641Smiod 		c = keyboard[val];
551305d9e87Smiod 		if (c == 0) {
552a1387c96Smiod 			return; /* XXX */
553305d9e87Smiod 		}
554305d9e87Smiod 		if (c & 0x80)
555305d9e87Smiod 			cbuf[j++] = 0xe0;
556305d9e87Smiod 		cbuf[j] = c & 0x7f;
5577ce15ad7Sshadchin 		if (type == WSCONS_EVENT_KEY_UP)
558305d9e87Smiod 			cbuf[j] |= 0x80;
559305d9e87Smiod 		j++;
560305d9e87Smiod 		s = spltty();
561305d9e87Smiod 		wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
562305d9e87Smiod 		splx(s);
563305d9e87Smiod #endif
564305d9e87Smiod 	} else {
565305d9e87Smiod 		wskbd_input(sc->sc_wskbddev, type, val);
566305d9e87Smiod 	}
567305d9e87Smiod }
568