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