aed.c revision 1.5 1 /* $NetBSD: aed.c,v 1.5 2000/03/23 06:40:33 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/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 callout_init(&sc->sc_repeat_ch);
107
108 sc->origaddr = aa_args->origaddr;
109 sc->adbaddr = aa_args->adbaddr;
110 sc->handler_id = aa_args->handler_id;
111
112 sc->sc_evq_tail = 0;
113 sc->sc_evq_len = 0;
114
115 sc->sc_rptdelay = 20;
116 sc->sc_rptinterval = 6;
117 sc->sc_repeating = -1; /* not repeating */
118
119 /* Pull in the options flags. */
120 sc->sc_options = (sc->sc_dev.dv_cfdata->cf_flags | aed_options);
121
122 sc->sc_ioproc = NULL;
123
124 sc->sc_buttons = 0;
125
126 sc->sc_open = 0;
127
128 aed_sc = sc;
129
130 printf("ADB Event device\n");
131
132 return;
133 }
134
135 /*
136 * Given a keyboard ADB event, record the keycode and call the key
137 * repeat handler, optionally passing the event through the mouse
138 * button emulation handler first. Pass mouse events directly to
139 * the handoff function.
140 */
141 void
142 aed_input(event)
143 adb_event_t *event;
144 {
145 adb_event_t new_event = *event;
146
147 switch (event->def_addr) {
148 case ADBADDR_KBD:
149 if (aed_sc->sc_options & AED_MSEMUL)
150 aed_emulate_mouse(&new_event);
151 else
152 aed_dokeyupdown(&new_event);
153 break;
154 case ADBADDR_MS:
155 new_event.u.m.buttons |= aed_sc->sc_buttons;
156 aed_handoff(&new_event);
157 break;
158 default: /* God only knows. */
159 #ifdef DIAGNOSTIC
160 panic("aed: received event from unsupported device!\n");
161 #endif
162 break;
163 }
164
165 }
166
167 /*
168 * Handles mouse button emulation via the keyboard. If the emulation
169 * modifier key is down, left and right arrows will generate 2nd and
170 * 3rd mouse button events while the 1, 2, and 3 keys will generate
171 * the corresponding mouse button event.
172 */
173 static void
174 aed_emulate_mouse(event)
175 adb_event_t *event;
176 {
177 static int emulmodkey_down = 0;
178 adb_event_t new_event;
179
180 if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) {
181 emulmodkey_down = 1;
182 } else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) {
183 /* key up */
184 emulmodkey_down = 0;
185 if (aed_sc->sc_buttons & 0xfe) {
186 aed_sc->sc_buttons &= 1;
187 new_event.def_addr = ADBADDR_MS;
188 new_event.u.m.buttons = aed_sc->sc_buttons;
189 new_event.u.m.dx = new_event.u.m.dy = 0;
190 microtime(&new_event.timestamp);
191 aed_handoff(&new_event);
192 }
193 } else if (emulmodkey_down) {
194 switch(event->u.k.key) {
195 #ifdef ALTXBUTTONS
196 case ADBK_KEYDOWN(ADBK_1):
197 aed_sc->sc_buttons |= 1; /* left down */
198 new_event.def_addr = ADBADDR_MS;
199 new_event.u.m.buttons = aed_sc->sc_buttons;
200 new_event.u.m.dx = new_event.u.m.dy = 0;
201 microtime(&new_event.timestamp);
202 aed_handoff(&new_event);
203 break;
204 case ADBK_KEYUP(ADBK_1):
205 aed_sc->sc_buttons &= ~1; /* left up */
206 new_event.def_addr = ADBADDR_MS;
207 new_event.u.m.buttons = aed_sc->sc_buttons;
208 new_event.u.m.dx = new_event.u.m.dy = 0;
209 microtime(&new_event.timestamp);
210 aed_handoff(&new_event);
211 break;
212 #endif
213 case ADBK_KEYDOWN(ADBK_LEFT):
214 #ifdef ALTXBUTTONS
215 case ADBK_KEYDOWN(ADBK_2):
216 #endif
217 aed_sc->sc_buttons |= 2; /* middle down */
218 new_event.def_addr = ADBADDR_MS;
219 new_event.u.m.buttons = aed_sc->sc_buttons;
220 new_event.u.m.dx = new_event.u.m.dy = 0;
221 microtime(&new_event.timestamp);
222 aed_handoff(&new_event);
223 break;
224 case ADBK_KEYUP(ADBK_LEFT):
225 #ifdef ALTXBUTTONS
226 case ADBK_KEYUP(ADBK_2):
227 #endif
228 aed_sc->sc_buttons &= ~2; /* middle up */
229 new_event.def_addr = ADBADDR_MS;
230 new_event.u.m.buttons = aed_sc->sc_buttons;
231 new_event.u.m.dx = new_event.u.m.dy = 0;
232 microtime(&new_event.timestamp);
233 aed_handoff(&new_event);
234 break;
235 case ADBK_KEYDOWN(ADBK_RIGHT):
236 #ifdef ALTXBUTTONS
237 case ADBK_KEYDOWN(ADBK_3):
238 #endif
239 aed_sc->sc_buttons |= 4; /* right down */
240 new_event.def_addr = ADBADDR_MS;
241 new_event.u.m.buttons = aed_sc->sc_buttons;
242 new_event.u.m.dx = new_event.u.m.dy = 0;
243 microtime(&new_event.timestamp);
244 aed_handoff(&new_event);
245 break;
246 case ADBK_KEYUP(ADBK_RIGHT):
247 #ifdef ALTXBUTTONS
248 case ADBK_KEYUP(ADBK_3):
249 #endif
250 aed_sc->sc_buttons &= ~4; /* right up */
251 new_event.def_addr = ADBADDR_MS;
252 new_event.u.m.buttons = aed_sc->sc_buttons;
253 new_event.u.m.dx = new_event.u.m.dy = 0;
254 microtime(&new_event.timestamp);
255 aed_handoff(&new_event);
256 break;
257 case ADBK_KEYUP(ADBK_SHIFT):
258 case ADBK_KEYDOWN(ADBK_SHIFT):
259 case ADBK_KEYUP(ADBK_CONTROL):
260 case ADBK_KEYDOWN(ADBK_CONTROL):
261 case ADBK_KEYUP(ADBK_FLOWER):
262 case ADBK_KEYDOWN(ADBK_FLOWER):
263 /* ctrl, shift, cmd */
264 aed_dokeyupdown(event);
265 break;
266 default:
267 if (event->u.k.key & 0x80)
268 /* ignore keyup */
269 break;
270
271 /* key down */
272 new_event = *event;
273
274 /* send option-down */
275 new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION);
276 new_event.bytes[0] = new_event.u.k.key;
277 microtime(&new_event.timestamp);
278 aed_dokeyupdown(&new_event);
279
280 /* send key-down */
281 new_event.u.k.key = event->bytes[0];
282 new_event.bytes[0] = new_event.u.k.key;
283 microtime(&new_event.timestamp);
284 aed_dokeyupdown(&new_event);
285
286 /* send key-up */
287 new_event.u.k.key =
288 ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0]));
289 microtime(&new_event.timestamp);
290 new_event.bytes[0] = new_event.u.k.key;
291 aed_dokeyupdown(&new_event);
292
293 /* send option-up */
294 new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION);
295 new_event.bytes[0] = new_event.u.k.key;
296 microtime(&new_event.timestamp);
297 aed_dokeyupdown(&new_event);
298 break;
299 }
300 } else {
301 aed_dokeyupdown(event);
302 }
303 }
304
305 /*
306 * Keyboard autorepeat timeout function. Sends key up/down events
307 * for the repeating key and schedules the next call at sc_rptinterval
308 * ticks in the future.
309 */
310 static void
311 aed_kbdrpt(kstate)
312 void *kstate;
313 {
314 struct aed_softc *aed_sc = (struct aed_softc *)kstate;
315
316 aed_sc->sc_rptevent.bytes[0] |= 0x80;
317 microtime(&aed_sc->sc_rptevent.timestamp);
318 aed_handoff(&aed_sc->sc_rptevent); /* do key up */
319
320 aed_sc->sc_rptevent.bytes[0] &= 0x7f;
321 microtime(&aed_sc->sc_rptevent.timestamp);
322 aed_handoff(&aed_sc->sc_rptevent); /* do key down */
323
324 if (aed_sc->sc_repeating == aed_sc->sc_rptevent.u.k.key) {
325 callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptinterval,
326 aed_kbdrpt, kstate);
327 }
328 }
329
330
331 /*
332 * Cancels the currently repeating key event if there is one, schedules
333 * a new repeating key event if needed, and hands the event off to the
334 * appropriate subsystem.
335 */
336 static void
337 aed_dokeyupdown(event)
338 adb_event_t *event;
339 {
340 int kbd_key;
341
342 kbd_key = ADBK_KEYVAL(event->u.k.key);
343 if (ADBK_PRESS(event->u.k.key) && keyboard[kbd_key][0] != 0) {
344 /* ignore shift & control */
345 if (aed_sc->sc_repeating != -1) {
346 callout_stop(&aed_sc->sc_repeat_ch);
347 }
348 aed_sc->sc_rptevent = *event;
349 aed_sc->sc_repeating = kbd_key;
350 callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptdelay,
351 aed_kbdrpt, (void *)aed_sc);
352 } else {
353 if (aed_sc->sc_repeating != -1) {
354 aed_sc->sc_repeating = -1;
355 callout_stop(&aed_sc->sc_repeat_ch);
356 }
357 aed_sc->sc_rptevent = *event;
358 }
359 aed_handoff(event);
360 }
361
362 /*
363 * Place the event in the event queue if a requesting device is open
364 * and we are not polling.
365 */
366 static void
367 aed_handoff(event)
368 adb_event_t *event;
369 {
370 if (aed_sc->sc_open && !adb_polling)
371 aed_enqevent(event);
372 }
373
374 /*
375 * Place the event in the event queue and wakeup any waiting processes.
376 */
377 static void
378 aed_enqevent(event)
379 adb_event_t *event;
380 {
381 int s;
382
383 s = spladb();
384
385 #ifdef DIAGNOSTIC
386 if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS)
387 panic("adb: event queue tail is out of bounds");
388
389 if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS)
390 panic("adb: event queue len is out of bounds");
391 #endif
392
393 if (aed_sc->sc_evq_len == AED_MAX_EVENTS) {
394 splx(s);
395 return; /* Oh, well... */
396 }
397 aed_sc->sc_evq[(aed_sc->sc_evq_len + aed_sc->sc_evq_tail) %
398 AED_MAX_EVENTS] = *event;
399 aed_sc->sc_evq_len++;
400
401 selwakeup(&aed_sc->sc_selinfo);
402 if (aed_sc->sc_ioproc)
403 psignal(aed_sc->sc_ioproc, SIGIO);
404
405 splx(s);
406 }
407
408 int
409 aedopen(dev, flag, mode, p)
410 dev_t dev;
411 int flag, mode;
412 struct proc *p;
413 {
414 int unit;
415 int error = 0;
416 int s;
417
418 unit = minor(dev);
419
420 if (unit != 0)
421 return (ENXIO);
422
423 s = spladb();
424 if (aed_sc->sc_open) {
425 splx(s);
426 return (EBUSY);
427 }
428 aed_sc->sc_evq_tail = 0;
429 aed_sc->sc_evq_len = 0;
430 aed_sc->sc_open = 1;
431 aed_sc->sc_ioproc = p;
432 splx(s);
433
434 return (error);
435 }
436
437
438 int
439 aedclose(dev, flag, mode, p)
440 dev_t dev;
441 int flag, mode;
442 struct proc *p;
443 {
444 int s = spladb();
445
446 aed_sc->sc_open = 0;
447 aed_sc->sc_ioproc = NULL;
448 splx(s);
449
450 return (0);
451 }
452
453
454 int
455 aedread(dev, uio, flag)
456 dev_t dev;
457 struct uio *uio;
458 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((caddr_t) & 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((caddr_t) & 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
503 int
504 aedwrite(dev, uio, flag)
505 dev_t dev;
506 struct uio *uio;
507 int flag;
508 {
509 return 0;
510 }
511
512
513 int
514 aedioctl(dev, cmd, data, flag, p)
515 dev_t dev;
516 int cmd;
517 caddr_t data;
518 int flag;
519 struct proc *p;
520 {
521 switch (cmd) {
522 case ADBIOCDEVSINFO: {
523 adb_devinfo_t *di;
524 ADBDataBlock adbdata;
525 int totaldevs;
526 int adbaddr;
527 int i;
528
529 di = (void *)data;
530
531 /* Initialize to no devices */
532 for (i = 0; i < 16; i++)
533 di->dev[i].addr = -1;
534
535 totaldevs = CountADBs();
536 for (i = 1; i <= totaldevs; i++) {
537 adbaddr = GetIndADB(&adbdata, i);
538 di->dev[adbaddr].addr = adbaddr;
539 di->dev[adbaddr].default_addr = (int)(adbdata.origADBAddr);
540 di->dev[adbaddr].handler_id = (int)(adbdata.devType);
541 }
542
543 /* Must call ADB Manager to get devices now */
544 break;
545 }
546
547 case ADBIOCGETREPEAT:{
548 adb_rptinfo_t *ri;
549
550 ri = (void *)data;
551 ri->delay_ticks = aed_sc->sc_rptdelay;
552 ri->interval_ticks = aed_sc->sc_rptinterval;
553 break;
554 }
555
556 case ADBIOCSETREPEAT:{
557 adb_rptinfo_t *ri;
558
559 ri = (void *) data;
560 aed_sc->sc_rptdelay = ri->delay_ticks;
561 aed_sc->sc_rptinterval = ri->interval_ticks;
562 break;
563 }
564
565 case ADBIOCRESET:
566 /* Do nothing for now */
567 break;
568
569 case ADBIOCLISTENCMD:{
570 adb_listencmd_t *lc;
571
572 lc = (void *)data;
573 }
574
575 default:
576 return (EINVAL);
577 }
578 return (0);
579 }
580
581
582 int
583 aedpoll(dev, events, p)
584 dev_t dev;
585 int events;
586 struct proc *p;
587 {
588 int s, revents;
589
590 revents = events & (POLLOUT | POLLWRNORM);
591
592 if ((events & (POLLIN | POLLRDNORM)) == 0)
593 return (revents);
594
595 s = spladb();
596 if (aed_sc->sc_evq_len > 0)
597 revents |= events & (POLLIN | POLLRDNORM);
598 else
599 selrecord(p, &aed_sc->sc_selinfo);
600 splx(s);
601
602 return (revents);
603 }
604