xref: /netbsd-src/sys/arch/macppc/dev/aed.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: aed.c,v 1.16 2005/12/11 12:18:03 christos 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.16 2005/12/11 12:18:03 christos 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 = (sc->sc_dev.dv_cfdata->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