Annotation of sys/dev/adb/akbd.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: akbd.c,v 1.6 2007/03/13 20:56:56 miod Exp $ */
2: /* $NetBSD: akbd.c,v 1.17 2005/01/15 16:00:59 chs Exp $ */
3:
4: /*
5: * Copyright (C) 1998 Colin Wood
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by Colin Wood.
19: * 4. The name of the author may not be used to endorse or promote products
20: * derived from this software without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: */
33:
34: #include <sys/param.h>
35: #include <sys/timeout.h>
36: #include <sys/kernel.h>
37: #include <sys/device.h>
38: #include <sys/systm.h>
39:
40: #include <dev/wscons/wsconsio.h>
41: #include <dev/wscons/wskbdvar.h>
42: #include <dev/wscons/wsksymdef.h>
43: #include <dev/wscons/wsksymvar.h>
44:
45: #include <machine/autoconf.h>
46: #include <machine/cpu.h>
47:
48: #include <dev/adb/adb.h>
49: #include <dev/adb/akbdmap.h>
50: #include <dev/adb/akbdvar.h>
51:
52: #ifdef WSDISPLAY_COMPAT_RAWKBD
53: #define KEYBOARD_ARRAY
54: #endif
55: #include <dev/adb/keyboard.h>
56:
57: /*
58: * Function declarations.
59: */
60: int akbdmatch(struct device *, void *, void *);
61: void akbdattach(struct device *, struct device *, void *);
62:
63: /* Driver definition. */
64: struct cfattach akbd_ca = {
65: sizeof(struct akbd_softc), akbdmatch, akbdattach
66: };
67: struct cfdriver akbd_cd = {
68: NULL, "akbd", DV_DULL
69: };
70:
71: int akbd_enable(void *, int);
72: void akbd_set_leds(void *, int);
73: int akbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
74:
75:
76: struct wskbd_accessops akbd_accessops = {
77: akbd_enable,
78: akbd_set_leds,
79: akbd_ioctl,
80: };
81:
82: struct wskbd_mapdata akbd_keymapdata = {
83: akbd_keydesctab,
84: #ifdef AKBD_LAYOUT
85: AKBD_LAYOUT,
86: #else
87: KB_US,
88: #endif
89: };
90:
91: void akbd_adbcomplete(caddr_t, caddr_t, int);
92: void akbd_capslockwrapper(struct akbd_softc *, int);
93: void akbd_input(struct akbd_softc *, int);
94: void akbd_processevent(struct akbd_softc *, adb_event_t *);
95: void akbd_rawrepeat(void *v);
96: #ifdef notyet
97: u_char getleds(int);
98: int setleds(struct akbd_softc *, u_char);
99: void blinkleds(struct akbd_softc *);
100: #endif
101:
102: int
103: akbdmatch(struct device *parent, void *vcf, void *aux)
104: {
105: struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
106:
107: if (aa_args->origaddr == ADBADDR_KBD)
108: return (1);
109: else
110: return (0);
111: }
112:
113: void
114: akbdattach(struct device *parent, struct device *self, void *aux)
115: {
116: ADBSetInfoBlock adbinfo;
117: struct akbd_softc *sc = (struct akbd_softc *)self;
118: struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
119: int error, kbd_done;
120: short cmd;
121: u_char buffer[9];
122: struct wskbddev_attach_args a;
123: static int akbd_console_initted;
124: int wskbd_eligible = 1;
125:
126: sc->origaddr = aa_args->origaddr;
127: sc->adbaddr = aa_args->adbaddr;
128: sc->handler_id = aa_args->handler_id;
129:
130: sc->sc_leds = (u_int8_t)0x00; /* initially off */
131: sc->sc_caps = 0;
132:
133: adbinfo.siServiceRtPtr = (Ptr)akbd_adbcomplete;
134: adbinfo.siDataAreaAddr = (caddr_t)sc;
135:
136: printf(": ");
137: switch (sc->handler_id) {
138: case ADB_STDKBD:
139: printf("standard keyboard\n");
140: break;
141: case ADB_ISOKBD:
142: printf("standard keyboard (ISO layout)\n");
143: break;
144: case ADB_EXTKBD:
145: cmd = ADBTALK(sc->adbaddr, 1);
146: kbd_done =
147: (adb_op_sync((Ptr)buffer, cmd) == 0);
148:
149: /* Ignore Logitech MouseMan/Trackman pseudo keyboard */
150: if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x20) {
151: printf("Mouseman (non-EMP) pseudo keyboard\n");
152: adbinfo.siServiceRtPtr = (Ptr)0;
153: adbinfo.siDataAreaAddr = (Ptr)0;
154: wskbd_eligible = 0;
155: } else if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x21) {
156: printf("Trackman (non-EMP) pseudo keyboard\n");
157: adbinfo.siServiceRtPtr = (Ptr)0;
158: adbinfo.siDataAreaAddr = (Ptr)0;
159: wskbd_eligible = 0;
160: } else {
161: printf("extended keyboard\n");
162: #ifdef notyet
163: blinkleds(sc);
164: #endif
165: }
166: break;
167: case ADB_EXTISOKBD:
168: printf("extended keyboard (ISO layout)\n");
169: #ifdef notyet
170: blinkleds(sc);
171: #endif
172: break;
173: case ADB_KBDII:
174: printf("keyboard II\n");
175: break;
176: case ADB_ISOKBDII:
177: printf("keyboard II (ISO layout)\n");
178: break;
179: case ADB_PBKBD:
180: printf("PowerBook keyboard\n");
181: break;
182: case ADB_PBISOKBD:
183: printf("PowerBook keyboard (ISO layout)\n");
184: break;
185: case ADB_ADJKPD:
186: printf("adjustable keypad\n");
187: wskbd_eligible = 0;
188: break;
189: case ADB_ADJKBD:
190: printf("adjustable keyboard\n");
191: break;
192: case ADB_ADJISOKBD:
193: printf("adjustable keyboard (ISO layout)\n");
194: break;
195: case ADB_ADJJAPKBD:
196: printf("adjustable keyboard (Japanese layout)\n");
197: break;
198: case ADB_PBEXTISOKBD:
199: printf("PowerBook extended keyboard (ISO layout)\n");
200: break;
201: case ADB_PBEXTJAPKBD:
202: printf("PowerBook extended keyboard (Japanese layout)\n");
203: break;
204: case ADB_JPKBDII:
205: printf("keyboard II (Japanese layout)\n");
206: break;
207: case ADB_PBEXTKBD:
208: printf("PowerBook extended keyboard\n");
209: break;
210: case ADB_DESIGNKBD:
211: printf("extended keyboard\n");
212: #ifdef notyet
213: blinkleds(sc);
214: #endif
215: break;
216: case ADB_PBJPKBD:
217: printf("PowerBook keyboard (Japanese layout)\n");
218: break;
219: case ADB_PBG3JPKBD:
220: printf("PowerBook G3 keyboard (Japanese layout)\n");
221: break;
222: case ADB_PBG4KBD:
223: printf("PowerBook G4 keyboard (Inverted T)\n");
224: break;
225: case ADB_IBITISOKBD:
226: printf("iBook keyboard with inverted T (ISO layout)\n");
227: break;
228: default:
229: printf("mapped device (%d)\n", sc->handler_id);
230: #if 0
231: wskbd_eligible = 0;
232: #endif
233: break;
234: }
235: error = set_adb_info(&adbinfo, sc->adbaddr);
236: #ifdef ADB_DEBUG
237: if (adb_debug)
238: printf("akbd: returned %d from set_adb_info\n", error);
239: #endif
240:
241: #ifdef WSDISPLAY_COMPAT_RAWKBD
242: timeout_set(&sc->sc_rawrepeat_ch, akbd_rawrepeat, sc);
243: #endif
244:
245: if (akbd_is_console() && wskbd_eligible)
246: a.console = (++akbd_console_initted == 1);
247: else
248: a.console = 0;
249: a.keymap = &akbd_keymapdata;
250: a.accessops = &akbd_accessops;
251: a.accesscookie = sc;
252:
253: sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
254: }
255:
256:
257: /*
258: * Handle putting the keyboard data received from the ADB into
259: * an ADB event record.
260: */
261: void
262: akbd_adbcomplete(caddr_t buffer, caddr_t data_area, int adb_command)
263: {
264: adb_event_t event;
265: struct akbd_softc *sc;
266: int adbaddr;
267: #ifdef ADB_DEBUG
268: int i;
269:
270: if (adb_debug)
271: printf("adb: transaction completion\n");
272: #endif
273:
274: adbaddr = ADB_CMDADDR(adb_command);
275: sc = (struct akbd_softc *)data_area;
276:
277: event.byte_count = buffer[0];
278: memcpy(event.bytes, buffer + 1, event.byte_count);
279:
280: #ifdef ADB_DEBUG
281: if (adb_debug) {
282: printf("akbd: from %d at %d (org %d) %d:", adbaddr,
283: sc->handler_id, sc->origaddr, buffer[0]);
284: for (i = 1; i <= buffer[0]; i++)
285: printf(" %x", buffer[i]);
286: printf("\n");
287: }
288: #endif
289:
290: if (sc->sc_wskbddev != NULL)
291: akbd_processevent(sc, &event);
292: }
293:
294: #ifdef notyet
295: /*
296: * Get the actual hardware LED state and convert it to softc format.
297: */
298: u_char
299: getleds(int addr)
300: {
301: short cmd;
302: u_char buffer[9], leds;
303:
304: leds = 0x00; /* all off */
305: buffer[0] = 0;
306:
307: cmd = ADBTALK(addr, 2);
308: if (adb_op_sync((Ptr)buffer, cmd) == 0 &&
309: buffer[0] > 0)
310: leds = ~(buffer[2]) & 0x07;
311:
312: return (leds);
313: }
314:
315: /*
316: * Set the keyboard LED's.
317: *
318: * Automatically translates from ioctl/softc format to the
319: * actual keyboard register format
320: */
321: int
322: setleds(struct akbd_softc *sc, u_char leds)
323: {
324: int addr;
325: short cmd;
326: u_char buffer[9];
327:
328: addr = sc->adbaddr;
329: buffer[0] = 0;
330:
331: cmd = ADBTALK(addr, 2);
332: if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0)
333: return (EIO);
334:
335: leds = ~leds & 0x07;
336: buffer[2] &= 0xf8;
337: buffer[2] |= leds;
338:
339: cmd = ADBLISTEN(addr, 2);
340: adb_op_sync((Ptr)buffer, cmd);
341:
342: /* talk R2 */
343: cmd = ADBTALK(addr, 2);
344: if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0)
345: return (EIO);
346:
347: if ((buffer[2] & 0xf8) != leds)
348: return (EIO);
349: else
350: return (0);
351: }
352:
353: /*
354: * Toggle all of the LED's on and off, just for show.
355: */
356: void
357: blinkleds(struct akbd_softc *sc)
358: {
359: u_char origleds;
360:
361: origleds = getleds(sc->adbaddr);
362: setleds(sc, LED_NUMLOCK | LED_CAPSLOCK | LED_SCROLL_LOCK);
363: delay(400000);
364: setleds(sc, origleds);
365:
366: if (origleds & LED_NUMLOCK)
367: sc->sc_leds |= WSKBD_LED_NUM;
368: if (origleds & LED_CAPSLOCK)
369: sc->sc_leds |= WSKBD_LED_CAPS;
370: if (origleds & LED_SCROLL_LOCK)
371: sc->sc_leds |= WSKBD_LED_SCROLL;
372: }
373: #endif
374:
375: int
376: akbd_enable(void *v, int on)
377: {
378: return 0;
379: }
380:
381: void
382: akbd_set_leds(void *v, int on)
383: {
384: #ifdef notyet
385: struct akbd_softc *sc = v;
386: int leds;
387:
388: if (sc->sc_extended) {
389: if (sc->sc_leds == on)
390: return;
391:
392: leds = 0;
393: if (on & WSKBD_LED_NUM)
394: leds |= LED_NUMLOCK;
395: if (on & WSKBD_LED_CAPS)
396: leds |= LED_CAPSLOCK;
397: if (on & WSKBD_LED_SCROLL)
398: leds |= LED_SCROLL_LOCK;
399:
400: setleds(sc, leds);
401: }
402: #endif
403: }
404:
405: int
406: akbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
407: {
408: struct akbd_softc *sc = v;
409:
410: switch (cmd) {
411:
412: case WSKBDIO_GTYPE:
413: *(int *)data = WSKBD_TYPE_ADB;
414: return 0;
415: case WSKBDIO_SETLEDS:
416: akbd_set_leds(v, *(int *)data);
417: return 0;
418: case WSKBDIO_GETLEDS:
419: *(int *)data = sc->sc_leds;
420: return 0;
421: #ifdef WSDISPLAY_COMPAT_RAWKBD
422: case WSKBDIO_SETMODE:
423: sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
424: timeout_del(&sc->sc_rawrepeat_ch);
425: return (0);
426: #endif
427:
428: #ifdef mac68k /* XXX not worth creating akbd_machdep_ioctl() */
429: case WSKBDIO_BELL:
430: case WSKBDIO_COMPLEXBELL:
431: #define d ((struct wskbd_bell_data *)data)
432: mac68k_ring_bell(d->pitch, d->period * hz / 1000, d->volume);
433: #undef d
434: return (0);
435: #endif
436:
437: default:
438: return (-1);
439: }
440: }
441:
442: #ifdef WSDISPLAY_COMPAT_RAWKBD
443: void
444: akbd_rawrepeat(void *v)
445: {
446: struct akbd_softc *sc = v;
447: int s;
448:
449: s = spltty();
450: wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
451: splx(s);
452: timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000);
453: }
454: #endif
455:
456: /*
457: * The ``caps lock'' key is special: since on earlier keyboards, the physical
458: * key stays down when pressed, we will get a notification of the key press,
459: * but not of the key release. Then, when it is pressed again, we will not get
460: * a notification of the key press, but will see the key release.
461: *
462: * This is not exactly true. We see the missing release and press events both
463: * as the release of the power (reset) key.
464: *
465: * To avoid confusing them with real power key presses, we maintain two
466: * states for the caps lock key: logically down (from wscons' point of view),
467: * and ``physically'' down (from the adb messages point of view), to ignore
468: * the power key. But since one may press the power key while the caps lock
469: * is held down, we also have to remember the state of the power key... this
470: * is quite messy.
471: */
472:
473: /*
474: * Values for caps lock state machine
475: */
476: #define CL_DOWN_ADB 0x01
477: #define CL_DOWN_LOGICAL 0x02
478: #define CL_DOWN_RESET 0x04
479:
480: /*
481: * Given a keyboard ADB event, decode the keycodes and pass them to wskbd.
482: */
483: void
484: akbd_processevent(struct akbd_softc *sc, adb_event_t *event)
485: {
486: switch (event->byte_count) {
487: case 1:
488: akbd_capslockwrapper(sc, event->bytes[0]);
489: break;
490: case 2:
491: /*
492: * The reset (or power) key sends 0x7f7f on press and
493: * 0xffff on release, and we ignore it.
494: */
495: if (event->bytes[0] == event->bytes[1] &&
496: ADBK_KEYVAL(event->bytes[0]) == ADBK_RESET) {
497: if (event->bytes[0] == ADBK_KEYDOWN(ADBK_RESET))
498: SET(sc->sc_caps, CL_DOWN_RESET);
499: else {
500: if (ISSET(sc->sc_caps, CL_DOWN_RESET))
501: CLR(sc->sc_caps, CL_DOWN_RESET);
502: else if (ISSET(sc->sc_caps, CL_DOWN_ADB)) {
503: akbd_input(sc, ISSET(sc->sc_caps,
504: CL_DOWN_LOGICAL) ?
505: ADBK_KEYDOWN(ADBK_CAPSLOCK) :
506: ADBK_KEYUP(ADBK_CAPSLOCK));
507: sc->sc_caps ^= CL_DOWN_LOGICAL;
508: }
509: }
510: } else {
511: akbd_capslockwrapper(sc, event->bytes[0]);
512: akbd_capslockwrapper(sc, event->bytes[1]);
513: }
514: break;
515: default:
516: #ifdef DIAGNOSTIC
517: printf("%s: unexpected message length %d\n",
518: sc->sc_dev.dv_xname, event->byte_count);
519: #endif
520: break;
521: }
522:
523: }
524:
525: void
526: akbd_capslockwrapper(struct akbd_softc *sc, int key)
527: {
528: if (ADBK_KEYVAL(key) == ADBK_CAPSLOCK)
529: sc->sc_caps ^= CL_DOWN_ADB;
530:
531: if (key != 0xff)
532: akbd_input(sc, key);
533: }
534:
535: int adb_polledkey;
536: void
537: akbd_input(struct akbd_softc *sc, int key)
538: {
539: int press, val;
540: int type;
541:
542: press = ADBK_PRESS(key);
543: val = ADBK_KEYVAL(key);
544:
545: type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
546:
547: if (adb_polling) {
548: adb_polledkey = key;
549: #ifdef WSDISPLAY_COMPAT_RAWKBD
550: } else if (sc->sc_rawkbd) {
551: char cbuf[MAXKEYS *2];
552: int c, j, s;
553: int npress;
554:
555: j = npress = 0;
556:
557: c = keyboard[val];
558: if (c == 0) {
559: return; /* XXX */
560: }
561: if (c & 0x80)
562: cbuf[j++] = 0xe0;
563: cbuf[j] = c & 0x7f;
564: if (type == WSCONS_EVENT_KEY_UP) {
565: cbuf[j] |= 0x80;
566: } else {
567: /* this only records last key pressed */
568: if (c & 0x80)
569: sc->sc_rep[npress++] = 0xe0;
570: sc->sc_rep[npress++] = c & 0x7f;
571: }
572: j++;
573: s = spltty();
574: wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
575: splx(s);
576: timeout_del(&sc->sc_rawrepeat_ch);
577: sc->sc_nrep = npress;
578: if (npress != 0)
579: timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAY1/1000);
580: #endif
581: } else {
582: wskbd_input(sc->sc_wskbddev, type, val);
583: }
584: }
CVSweb