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