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