aed.c revision 1.1 1 /* $NetBSD: aed.c,v 1.1 1998/10/13 11:21:21 tsubai Exp $ */
2
3 /*
4 * Copyright (C) 1994 Bradley A. Grantham
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 Bradley A. Grantham.
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 #include <machine/cpu.h>
44 #include <machine/keyboard.h>
45
46 #include <macppc/dev/adbvar.h>
47 #include <macppc/dev/aedvar.h>
48 #include <macppc/dev/akbdvar.h>
49
50 #define spladb splhigh
51
52 /*
53 * Function declarations.
54 */
55 static int aedmatch __P((struct device *, struct cfdata *, void *));
56 static void aedattach __P((struct device *, struct device *, void *));
57 static void aed_emulate_mouse __P((adb_event_t *event));
58 static void aed_kbdrpt __P((void *kstate));
59 static void aed_dokeyupdown __P((adb_event_t *event));
60 static void aed_handoff __P((adb_event_t *event));
61 static void aed_enqevent __P((adb_event_t *event));
62
63 /*
64 * Global variables.
65 */
66 extern int adb_polling; /* Are we polling? (Debugger mode) */
67
68 /*
69 * Local variables.
70 */
71 static struct aed_softc * aed_sc = NULL;
72 static int aed_options = 0 | AED_MSEMUL;
73
74 /* Driver definition */
75 struct cfattach aed_ca = {
76 sizeof(struct aed_softc), aedmatch, aedattach
77 };
78
79 extern struct cfdriver aed_cd;
80
81 static int
82 aedmatch(parent, cf, aux)
83 struct device *parent;
84 struct cfdata *cf;
85 void *aux;
86 {
87 struct adb_attach_args * aa_args = (struct adb_attach_args *)aux;
88 static int aed_matched = 0;
89
90 /* Allow only one instance. */
91 if ((aa_args->origaddr == 0) && (!aed_matched)) {
92 aed_matched = 1;
93 return (1);
94 } else
95 return (0);
96 }
97
98 static void
99 aedattach(parent, self, aux)
100 struct device *parent, *self;
101 void *aux;
102 {
103 struct adb_attach_args * aa_args = (struct adb_attach_args *)aux;
104 struct aed_softc *sc = (struct aed_softc *)self;
105
106 sc->origaddr = aa_args->origaddr;
107 sc->adbaddr = aa_args->adbaddr;
108 sc->handler_id = aa_args->handler_id;
109
110 sc->sc_evq_tail = 0;
111 sc->sc_evq_len = 0;
112
113 sc->sc_rptdelay = 20;
114 sc->sc_rptinterval = 6;
115 sc->sc_repeating = -1; /* not repeating */
116
117 /* Pull in the options flags. */
118 sc->sc_options = (sc->sc_dev.dv_cfdata->cf_flags | aed_options);
119
120 sc->sc_ioproc = NULL;
121
122 sc->sc_buttons = 0;
123
124 sc->sc_open = 0;
125
126 aed_sc = sc;
127
128 printf("ADB Event device\n");
129
130 return;
131 }
132
133 /*
134 * Given a keyboard ADB event, record the keycode and call the key
135 * repeat handler, optionally passing the event through the mouse
136 * button emulation handler first. Pass mouse events directly to
137 * the handoff function.
138 */
139 void
140 aed_input(event)
141 adb_event_t *event;
142 {
143 adb_event_t new_event = *event;
144
145 switch (event->def_addr) {
146 case ADBADDR_KBD:
147 if (aed_sc->sc_options & AED_MSEMUL)
148 aed_emulate_mouse(&new_event);
149 else
150 aed_dokeyupdown(&new_event);
151 break;
152 case ADBADDR_MS:
153 aed_handoff(&new_event);
154 break;
155 default: /* God only knows. */
156 #ifdef DIAGNOSTIC
157 panic("aed: received event from unsupported device!\n");
158 #endif
159 break;
160 }
161
162 }
163
164 /*
165 * Handles mouse button emulation via the keyboard. If the emulation
166 * modifier key is down, left and right arrows will generate 2nd and
167 * 3rd mouse button events while the 1, 2, and 3 keys will generate
168 * the corresponding mouse button event.
169 */
170 static void
171 aed_emulate_mouse(event)
172 adb_event_t *event;
173 {
174 static int emulmodkey_down = 0;
175 adb_event_t new_event;
176
177 if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) {
178 emulmodkey_down = 1;
179 } else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) {
180 /* key up */
181 emulmodkey_down = 0;
182 if (aed_sc->sc_buttons & 0xfe) {
183 aed_sc->sc_buttons &= 1;
184 new_event.def_addr = ADBADDR_MS;
185 new_event.u.m.buttons = aed_sc->sc_buttons;
186 new_event.u.m.dx = new_event.u.m.dy = 0;
187 microtime(&new_event.timestamp);
188 aed_handoff(&new_event);
189 }
190 } else if (emulmodkey_down) {
191 switch(event->u.k.key) {
192 #ifdef ALTXBUTTONS
193 case ADBK_KEYDOWN(ADBK_1):
194 aed_sc->sc_buttons |= 1; /* left down */
195 new_event.def_addr = ADBADDR_MS;
196 new_event.u.m.buttons = aed_sc->sc_buttons;
197 new_event.u.m.dx = new_event.u.m.dy = 0;
198 microtime(&new_event.timestamp);
199 aed_handoff(&new_event);
200 break;
201 case ADBK_KEYUP(ADBK_1):
202 aed_c->sc_buttons &= ~1; /* left up */
203 new_event.def_addr = ADBADDR_MS;
204 new_event.u.m.buttons = aed_sc->sc_buttons;
205 new_event.u.m.dx = new_event.u.m.dy = 0;
206 microtime(&new_event.timestamp);
207 aed_handoff(&new_event);
208 break;
209 #endif
210 case ADBK_KEYDOWN(ADBK_LEFT):
211 #ifdef ALTXBUTTONS
212 case ADBK_KEYDOWN(ADBK_2):
213 #endif
214 aed_sc->sc_buttons |= 2; /* middle down */
215 new_event.def_addr = ADBADDR_MS;
216 new_event.u.m.buttons = aed_sc->sc_buttons;
217 new_event.u.m.dx = new_event.u.m.dy = 0;
218 microtime(&new_event.timestamp);
219 aed_handoff(&new_event);
220 break;
221 case ADBK_KEYUP(ADBK_LEFT):
222 #ifdef ALTXBUTTONS
223 case ADBK_KEYUP(ADBK_2):
224 #endif
225 aed_sc->sc_buttons &= ~2; /* middle up */
226 new_event.def_addr = ADBADDR_MS;
227 new_event.u.m.buttons = aed_sc->sc_buttons;
228 new_event.u.m.dx = new_event.u.m.dy = 0;
229 microtime(&new_event.timestamp);
230 aed_handoff(&new_event);
231 break;
232 case ADBK_KEYDOWN(ADBK_RIGHT):
233 #ifdef ALTXBUTTONS
234 case ADBK_KEYDOWN(ADBK_3):
235 #endif
236 aed_sc->sc_buttons |= 4; /* right down */
237 new_event.def_addr = ADBADDR_MS;
238 new_event.u.m.buttons = aed_sc->sc_buttons;
239 new_event.u.m.dx = new_event.u.m.dy = 0;
240 microtime(&new_event.timestamp);
241 aed_handoff(&new_event);
242 break;
243 case ADBK_KEYUP(ADBK_RIGHT):
244 case ADBK_KEYUP(ADBK_3):
245 aed_sc->sc_buttons &= ~4; /* right up */
246 new_event.def_addr = ADBADDR_MS;
247 new_event.u.m.buttons = aed_sc->sc_buttons;
248 new_event.u.m.dx = new_event.u.m.dy = 0;
249 microtime(&new_event.timestamp);
250 aed_handoff(&new_event);
251 break;
252 case ADBK_KEYVAL(ADBK_SHIFT):
253 case ADBK_KEYVAL(ADBK_CONTROL):
254 case ADBK_KEYVAL(ADBK_FLOWER):
255 /* ctrl, shift, cmd */
256 aed_dokeyupdown(event);
257 break;
258 default:
259 if (event->u.k.key & 0x80)
260 /* ignore keyup */
261 break;
262
263 /* key down */
264 new_event = *event;
265
266 /* send option-down */
267 new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION);
268 new_event.bytes[0] = new_event.u.k.key;
269 microtime(&new_event.timestamp);
270 aed_dokeyupdown(&new_event);
271
272 /* send key-down */
273 new_event.u.k.key = event->bytes[0];
274 new_event.bytes[0] = new_event.u.k.key;
275 microtime(&new_event.timestamp);
276 aed_dokeyupdown(&new_event);
277
278 /* send key-up */
279 new_event.u.k.key =
280 ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0]));
281 microtime(&new_event.timestamp);
282 new_event.bytes[0] = new_event.u.k.key;
283 aed_dokeyupdown(&new_event);
284
285 /* send option-up */
286 new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION);
287 new_event.bytes[0] = new_event.u.k.key;
288 microtime(&new_event.timestamp);
289 aed_dokeyupdown(&new_event);
290 break;
291 }
292 } else {
293 aed_dokeyupdown(event);
294 }
295 }
296
297 /*
298 * Keyboard autorepeat timeout function. Sends key up/down events
299 * for the repeating key and schedules the next call at sc_rptinterval
300 * ticks in the future.
301 */
302 static void
303 aed_kbdrpt(kstate)
304 void *kstate;
305 {
306 struct aed_softc * aed_sc = (struct aed_softc *)kstate;
307
308 aed_sc->sc_rptevent.bytes[0] |= 0x80;
309 microtime(&aed_sc->sc_rptevent.timestamp);
310 aed_handoff(&aed_sc->sc_rptevent); /* do key up */
311
312 aed_sc->sc_rptevent.bytes[0] &= 0x7f;
313 microtime(&aed_sc->sc_rptevent.timestamp);
314 aed_handoff(&aed_sc->sc_rptevent); /* do key down */
315
316 if (aed_sc->sc_repeating == aed_sc->sc_rptevent.u.k.key) {
317 timeout(aed_kbdrpt, kstate, aed_sc->sc_rptinterval);
318 }
319 }
320
321
322 /*
323 * Cancels the currently repeating key event if there is one, schedules
324 * a new repeating key event if needed, and hands the event off to the
325 * appropriate subsystem.
326 */
327 static void
328 aed_dokeyupdown(event)
329 adb_event_t *event;
330 {
331 int kbd_key;
332
333 kbd_key = ADBK_KEYVAL(event->u.k.key);
334 if (ADBK_PRESS(event->u.k.key) && keyboard[kbd_key][0] != 0) {
335 /* ignore shift & control */
336 if (aed_sc->sc_repeating != -1) {
337 untimeout(aed_kbdrpt, (void *)aed_sc);
338 }
339 aed_sc->sc_rptevent = *event;
340 aed_sc->sc_repeating = kbd_key;
341 timeout(aed_kbdrpt, (void *)aed_sc, aed_sc->sc_rptdelay);
342 } else {
343 if (aed_sc->sc_repeating != -1) {
344 aed_sc->sc_repeating = -1;
345 untimeout(aed_kbdrpt, (void *)aed_sc);
346 }
347 aed_sc->sc_rptevent = *event;
348 }
349 aed_handoff(event);
350 }
351
352 /*
353 * Place the event in the event queue if a requesting device is open
354 * and we are not polling, otherwise, pass it up to the console driver.
355 */
356 static void
357 aed_handoff(event)
358 adb_event_t *event;
359 {
360 if (aed_sc->sc_open && !adb_polling)
361 aed_enqevent(event);
362 else {
363 if (event->def_addr == 2)
364 adb_intr(event);
365 }
366 }
367
368 /*
369 * Place the event in the event queue and wakeup any waiting processes.
370 */
371 static void
372 aed_enqevent(event)
373 adb_event_t *event;
374 {
375 int s;
376
377 s = spladb();
378
379 #ifdef DIAGNOSTIC
380 if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS)
381 panic("adb: event queue tail is out of bounds");
382
383 if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS)
384 panic("adb: event queue len is out of bounds");
385 #endif
386
387 if (aed_sc->sc_evq_len == AED_MAX_EVENTS) {
388 splx(s);
389 return; /* Oh, well... */
390 }
391 aed_sc->sc_evq[(aed_sc->sc_evq_len + aed_sc->sc_evq_tail) %
392 AED_MAX_EVENTS] = *event;
393 aed_sc->sc_evq_len++;
394
395 selwakeup(&aed_sc->sc_selinfo);
396 if (aed_sc->sc_ioproc)
397 psignal(aed_sc->sc_ioproc, SIGIO);
398
399 splx(s);
400 }
401
402 int
403 aedopen(dev, flag, mode, p)
404 dev_t dev;
405 int flag, mode;
406 struct proc *p;
407 {
408 int unit;
409 int error = 0;
410 int s;
411
412 unit = minor(dev);
413
414 if (unit != 0)
415 return (ENXIO);
416
417 s = spladb();
418 if (aed_sc->sc_open) {
419 splx(s);
420 return (EBUSY);
421 }
422 aed_sc->sc_evq_tail = 0;
423 aed_sc->sc_evq_len = 0;
424 aed_sc->sc_open = 1;
425 aed_sc->sc_ioproc = p;
426 splx(s);
427
428 return (error);
429 }
430
431
432 int
433 aedclose(dev, flag, mode, p)
434 dev_t dev;
435 int flag, mode;
436 struct proc *p;
437 {
438 int s = spladb();
439
440 aed_sc->sc_open = 0;
441 aed_sc->sc_ioproc = NULL;
442 splx(s);
443
444 return (0);
445 }
446
447
448 int
449 aedread(dev, uio, flag)
450 dev_t dev;
451 struct uio *uio;
452 int flag;
453 {
454 int s, error;
455 int willfit;
456 int total;
457 int firstmove;
458 int moremove;
459
460 if (uio->uio_resid < sizeof(adb_event_t))
461 return (EMSGSIZE); /* close enough. */
462
463 s = spladb();
464 if (aed_sc->sc_evq_len == 0) {
465 splx(s);
466 return (0);
467 }
468 willfit = howmany(uio->uio_resid, sizeof(adb_event_t));
469 total = (aed_sc->sc_evq_len < willfit) ? aed_sc->sc_evq_len : willfit;
470
471 firstmove = (aed_sc->sc_evq_tail + total > AED_MAX_EVENTS)
472 ? (AED_MAX_EVENTS - aed_sc->sc_evq_tail) : total;
473
474 error = uiomove((caddr_t) & aed_sc->sc_evq[aed_sc->sc_evq_tail],
475 firstmove * sizeof(adb_event_t), uio);
476 if (error) {
477 splx(s);
478 return (error);
479 }
480 moremove = total - firstmove;
481
482 if (moremove > 0) {
483 error = uiomove((caddr_t) & aed_sc->sc_evq[0],
484 moremove * sizeof(adb_event_t), uio);
485 if (error) {
486 splx(s);
487 return (error);
488 }
489 }
490 aed_sc->sc_evq_tail = (aed_sc->sc_evq_tail + total) % AED_MAX_EVENTS;
491 aed_sc->sc_evq_len -= total;
492 splx(s);
493 return (0);
494 }
495
496
497 int
498 aedwrite(dev, uio, flag)
499 dev_t dev;
500 struct uio *uio;
501 int flag;
502 {
503 return 0;
504 }
505
506
507 int
508 aedioctl(dev, cmd, data, flag, p)
509 dev_t dev;
510 int cmd;
511 caddr_t data;
512 int flag;
513 struct proc *p;
514 {
515 switch (cmd) {
516 case ADBIOCDEVSINFO: {
517 adb_devinfo_t *di;
518 ADBDataBlock adbdata;
519 int totaldevs;
520 int adbaddr;
521 int i;
522
523 di = (void *)data;
524
525 /* Initialize to no devices */
526 for (i = 0; i < 16; i++)
527 di->dev[i].addr = -1;
528
529 totaldevs = CountADBs();
530 for (i = 1; i <= totaldevs; i++) {
531 adbaddr = GetIndADB(&adbdata, i);
532 di->dev[adbaddr].addr = adbaddr;
533 di->dev[adbaddr].default_addr = adbdata.origADBAddr;
534 di->dev[adbaddr].handler_id = adbdata.devType;
535 }
536
537 /* Must call ADB Manager to get devices now */
538 break;
539 }
540
541 case ADBIOCGETREPEAT:{
542 adb_rptinfo_t *ri;
543
544 ri = (void *)data;
545 ri->delay_ticks = aed_sc->sc_rptdelay;
546 ri->interval_ticks = aed_sc->sc_rptinterval;
547 break;
548 }
549
550 case ADBIOCSETREPEAT:{
551 adb_rptinfo_t *ri;
552
553 ri = (void *) data;
554 aed_sc->sc_rptdelay = ri->delay_ticks;
555 aed_sc->sc_rptinterval = ri->interval_ticks;
556 break;
557 }
558
559 case ADBIOCRESET:
560 /* Do nothing for now */
561 break;
562
563 case ADBIOCLISTENCMD:{
564 adb_listencmd_t *lc;
565
566 lc = (void *)data;
567 }
568
569 default:
570 return (EINVAL);
571 }
572 return (0);
573 }
574
575
576 int
577 aedpoll(dev, events, p)
578 dev_t dev;
579 int events;
580 struct proc *p;
581 {
582 int s, revents;
583
584 revents = events & (POLLOUT | POLLWRNORM);
585
586 if ((events & (POLLIN | POLLRDNORM)) == 0)
587 return (revents);
588
589 s = spladb();
590 if (aed_sc->sc_evq_len > 0)
591 revents |= events & (POLLIN | POLLRDNORM);
592 else
593 selrecord(p, &aed_sc->sc_selinfo);
594 splx(s);
595
596 return (revents);
597 }
598