xref: /netbsd/sys/arch/macppc/dev/aed.c (revision bf9ec67e)
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