akbd.c revision 1.1 1 /* $NetBSD: akbd.c,v 1.1 1998/10/13 11:21:21 tsubai Exp $ */
2
3 /*
4 * Copyright (C) 1998 Colin Wood
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
20 *
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.
31 */
32
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/fcntl.h>
36 #include <sys/poll.h>
37 #include <sys/select.h>
38 #include <sys/proc.h>
39 #include <sys/signalvar.h>
40 #include <sys/systm.h>
41
42 #include <machine/autoconf.h>
43
44 #include <macppc/dev/adbvar.h>
45 #include <macppc/dev/aedvar.h>
46 #include <macppc/dev/akbdvar.h>
47 #include <macppc/dev/amsvar.h>
48
49 /*
50 * Function declarations.
51 */
52 static int kbdmatch __P((struct device *, struct cfdata *, void *));
53 static void kbdattach __P((struct device *, struct device *, void *));
54 void kbd_adbcomplete __P((caddr_t buffer, caddr_t data_area, int adb_command));
55 static void kbd_processevent __P((adb_event_t *event, struct kbd_softc *));
56 #ifdef notyet
57 static u_char getleds __P((int));
58 static int setleds __P((struct kbd_softc *, u_char));
59 static void blinkleds __P((struct kbd_softc *));
60 #endif
61
62 /*
63 * Local variables.
64 */
65 static volatile int kbd_done; /* Did ADBOp() complete? */
66
67 /* Driver definition. */
68 struct cfattach akbd_ca = {
69 sizeof(struct kbd_softc), kbdmatch, kbdattach
70 };
71
72 extern struct cfdriver kbd_cd;
73
74 static int
75 kbdmatch(parent, cf, aux)
76 struct device *parent;
77 struct cfdata *cf;
78 void *aux;
79 {
80 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
81
82 if (aa_args->origaddr == ADBADDR_KBD)
83 return 1;
84 else
85 return 0;
86 }
87
88 static void
89 kbdattach(parent, self, aux)
90 struct device *parent, *self;
91 void *aux;
92 {
93 ADBSetInfoBlock adbinfo;
94 struct kbd_softc *sc = (struct kbd_softc *)self;
95 struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
96 int count, error;
97 short cmd;
98 u_char buffer[9];
99
100 sc->origaddr = aa_args->origaddr;
101 sc->adbaddr = aa_args->adbaddr;
102 sc->handler_id = aa_args->handler_id;
103
104 sc->sc_leds = (u_int8_t)0x00; /* initially off */
105
106 adbinfo.siServiceRtPtr = (Ptr)kbd_adbcomplete;
107 adbinfo.siDataAreaAddr = (caddr_t)sc;
108
109 switch (sc->handler_id) {
110 case ADB_STDKBD:
111 printf("standard keyboard\n");
112 break;
113 case ADB_ISOKBD:
114 printf("standard keyboard (ISO layout)\n");
115 break;
116 case ADB_EXTKBD:
117 kbd_done = 0;
118 cmd = (((sc->adbaddr << 4) & 0xf0) | 0x0d ); /* talk R1 */
119 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
120 (Ptr)&kbd_done, cmd);
121
122 /* Wait until done, but no more than 2 secs */
123 count = 40000;
124 while (!kbd_done && count-- > 0)
125 delay(50);
126
127 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */
128 if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x20) {
129 printf("Mouseman (non-EMP) pseudo keyboard\n");
130 adbinfo.siServiceRtPtr = (Ptr)0;
131 adbinfo.siDataAreaAddr = (Ptr)0;
132 } else if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x21) {
133 printf("Trackman (non-EMP) pseudo keyboard\n");
134 adbinfo.siServiceRtPtr = (Ptr)0;
135 adbinfo.siDataAreaAddr = (Ptr)0;
136 } else {
137 printf("extended keyboard\n");
138 #ifdef notyet
139 blinkleds(sc);
140 #endif
141 }
142 break;
143 case ADB_EXTISOKBD:
144 printf("extended keyboard (ISO layout)\n");
145 #ifdef notyet
146 blinkleds(sc);
147 #endif
148 break;
149 case ADB_KBDII:
150 printf("keyboard II\n");
151 break;
152 case ADB_ISOKBDII:
153 printf("keyboard II (ISO layout)\n");
154 break;
155 case ADB_PBKBD:
156 printf("PowerBook keyboard\n");
157 break;
158 case ADB_PBISOKBD:
159 printf("PowerBook keyboard (ISO layout)\n");
160 break;
161 case ADB_ADJKPD:
162 printf("adjustable keypad\n");
163 break;
164 case ADB_ADJKBD:
165 printf("adjustable keyboard\n");
166 break;
167 case ADB_ADJISOKBD:
168 printf("adjustable keyboard (ISO layout)\n");
169 break;
170 case ADB_ADJJAPKBD:
171 printf("adjustable keyboard (Japanese layout)\n");
172 break;
173 case ADB_PBEXTISOKBD:
174 printf("PowerBook extended keyboard (ISO layout)\n");
175 break;
176 case ADB_PBEXTJAPKBD:
177 printf("PowerBook extended keyboard (Japanese layout)\n");
178 break;
179 case ADB_JISKBDII:
180 printf("keyboard II (Japanese layout)\n");
181 break;
182 case ADB_PBEXTKBD:
183 printf("PowerBook extended keyboard\n");
184 break;
185 case ADB_DESIGNKBD:
186 printf("extended keyboard\n");
187 #ifdef notyet
188 blinkleds(sc);
189 #endif
190 break;
191 default:
192 printf("mapped device (%d)\n", sc->handler_id);
193 break;
194 }
195 error = SetADBInfo(&adbinfo, sc->adbaddr);
196 #ifdef ADB_DEBUG
197 if (adb_debug)
198 printf("kbd: returned %d from SetADBInfo\n", error);
199 #endif
200 return;
201 }
202
203
204 /*
205 * Handle putting the keyboard data received from the ADB into
206 * an ADB event record.
207 */
208 void
209 kbd_adbcomplete(buffer, data_area, adb_command)
210 caddr_t buffer;
211 caddr_t data_area;
212 int adb_command;
213 {
214 adb_event_t event;
215 struct kbd_softc *ksc;
216 int adbaddr;
217 #ifdef ADB_DEBUG
218 int i;
219
220 if (adb_debug)
221 printf("adb: transaction completion\n");
222 #endif
223
224 adbaddr = (adb_command & 0xf0) >> 4;
225 ksc = (struct kbd_softc *)data_area;
226
227 event.addr = adbaddr;
228 event.hand_id = ksc->handler_id;
229 event.def_addr = ksc->origaddr;
230 event.byte_count = buffer[0];
231 memcpy(event.bytes, buffer + 1, event.byte_count);
232
233 #ifdef ADB_DEBUG
234 if (adb_debug) {
235 printf("kbd: from %d at %d (org %d) %d:", event.addr,
236 event.hand_id, event.def_addr, buffer[0]);
237 for (i = 1; i <= buffer[0]; i++)
238 printf(" %x", buffer[i]);
239 printf("\n");
240 }
241 #endif
242
243 microtime(&event.timestamp);
244
245 kbd_processevent(&event, ksc);
246 }
247
248 /*
249 * Given a keyboard ADB event, record the keycodes and call the key
250 * repeat handler, optionally passing the event through the mouse
251 * button emulation handler first.
252 */
253 static void
254 kbd_processevent(event, ksc)
255 adb_event_t *event;
256 struct kbd_softc *ksc;
257 {
258 adb_event_t new_event;
259
260 new_event = *event;
261 new_event.u.k.key = event->bytes[0];
262 new_event.bytes[1] = 0xff;
263 aed_input(&new_event);
264 if (event->bytes[1] != 0xff) {
265 new_event.u.k.key = event->bytes[1];
266 new_event.bytes[0] = event->bytes[1];
267 new_event.bytes[1] = 0xff;
268 aed_input(&new_event);
269 }
270
271 }
272
273 #ifdef notyet
274 /*
275 * Get the actual hardware LED state and convert it to softc format.
276 */
277 static u_char
278 getleds(addr)
279 int addr;
280 {
281 short cmd;
282 u_char buffer[9], leds;
283
284 leds = 0x00; /* all off */
285 buffer[0] = 0;
286 kbd_done = 0;
287
288 /* talk R2 */
289 cmd = ((addr & 0xf) << 4) | 0x0c | 0x02;
290 ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
291 while (!kbd_done)
292 /* busy-wait until done */ ;
293
294 if (buffer[0] > 0)
295 leds = ~(buffer[2]) & 0x07;
296
297 return (leds);
298 }
299
300 /*
301 * Set the keyboard LED's.
302 *
303 * Automatically translates from ioctl/softc format to the
304 * actual keyboard register format
305 */
306 static int
307 setleds(ksc, leds)
308 struct kbd_softc *ksc;
309 u_char leds;
310 {
311 int addr;
312 short cmd;
313 u_char buffer[9];
314
315 if ((leds & 0x07) == (ksc->sc_leds & 0x07))
316 return (0);
317
318 addr = (int)ksc->adbaddr;
319 buffer[0] = 0;
320 kbd_done = 0;
321
322 /* talk R2 */
323 cmd = ((addr & 0xf) << 4) | 0x0c | 0x02;
324 ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
325 while (!kbd_done)
326 /* busy-wait until done */ ;
327
328 if (buffer[0] == 0)
329 return (EIO);
330
331 leds = ~leds & 0x07;
332 buffer[2] &= 0xf8;
333 buffer[2] |= leds;
334
335 /* listen R2 */
336 cmd = ((addr & 0xf) << 4) | 0x08 | 0x02;
337 ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
338 while (!kbd_done)
339 /* busy-wait until done */ ;
340
341 /* talk R2 */
342 cmd = ((addr & 0xf) << 4) | 0x0c | 0x02;
343 ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
344 while (!kbd_done)
345 /* busy-wait until done */ ;
346
347 if (buffer[0] == 0)
348 return (EIO);
349
350 ksc->sc_leds = ~((u_int8_t)buffer[2]) & 0x07;
351
352 if ((buffer[2] & 0xf8) != leds)
353 return (EIO);
354 else
355 return (0);
356 }
357
358 /*
359 * Toggle all of the LED's on and off, just for show.
360 */
361 static void
362 blinkleds(ksc)
363 struct kbd_softc *ksc;
364 {
365 int addr, i;
366 u_char blinkleds, origleds;
367
368 addr = (int)ksc->adbaddr;
369 origleds = getleds(addr);
370 blinkleds = LED_NUMLOCK | LED_CAPSLOCK | LED_SCROLL_LOCK;
371
372 (void)setleds(ksc, blinkleds);
373
374 for (i = 0; i < 10000; i++)
375 delay(50);
376
377 /* make sure that we restore the LED settings */
378 i = 10;
379 do {
380 (void)setleds(ksc, (u_char)0x00);
381 } while (setleds(ksc, (u_char)0x00) && (i-- > 0));
382
383 return;
384 }
385 #endif
386
387 #if 0
388 int
389 kbdioctl(dev, cmd, data, flag, p)
390 dev_t dev;
391 int cmd;
392 caddr_t data;
393 int flag;
394 struct proc *p;
395 {
396 struct kbd_softc *ksc;
397 int error = 0;
398
399 ksc = kbd_cd.cd_devs[minor(dev)];
400
401 switch (cmd) {
402 case KIOCTYPE: /* Get keyboard type */
403 *(u_int8_t *)data = ksc->handler_id;
404 case KIOCSLED:
405 error = setleds(ksc, *(u_char *)data);
406 break;
407 case KIOCGLED:
408 *(u_int8_t *)data = ksc->sc_leds;
409 break;
410 default:
411 error = (EINVAL);
412 }
413 return (error);
414 }
415 #endif
416