xref: /netbsd-src/sys/arch/mac68k/dev/aed.c (revision bada23909e740596d0a3785a73bd3583a9807fb8)
1 /*	$NetBSD: aed.c,v 1.7 1999/02/16 01:08:16 ender 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 "opt_adb.h"
34 
35 #include <sys/param.h>
36 #include <sys/device.h>
37 #include <sys/fcntl.h>
38 #include <sys/poll.h>
39 #include <sys/select.h>
40 #include <sys/proc.h>
41 #include <sys/signalvar.h>
42 #include <sys/systm.h>
43 
44 #include <machine/autoconf.h>
45 #include <machine/cpu.h>
46 #include <machine/keyboard.h>
47 
48 #include <mac68k/mac68k/macrom.h>
49 #include <mac68k/dev/adbvar.h>
50 #include <mac68k/dev/aedvar.h>
51 #include <mac68k/dev/itevar.h>
52 #include <mac68k/dev/kbdvar.h>
53 
54 /*
55  * Function declarations.
56  */
57 static int	aedmatch __P((struct device *, struct cfdata *, void *));
58 static void	aedattach __P((struct device *, struct device *, void *));
59 static void	aed_emulate_mouse __P((adb_event_t *event));
60 static void	aed_kbdrpt __P((void *kstate));
61 static void	aed_dokeyupdown __P((adb_event_t *event));
62 static void	aed_handoff __P((adb_event_t *event));
63 static void	aed_enqevent __P((adb_event_t *event));
64 
65 /*
66  * Global variables.
67  */
68 extern int ite_polling;			/* Are we polling?  (Debugger mode) */
69 
70 /*
71  * Local variables.
72  */
73 static struct aed_softc *aed_sc = NULL;
74 static int aed_options = 0 | AED_MSEMUL;
75 
76 /* Driver definition */
77 struct cfattach aed_ca = {
78 	sizeof(struct aed_softc), aedmatch, aedattach
79 };
80 
81 extern struct cfdriver aed_cd;
82 
83 static int
84 aedmatch(parent, cf, aux)
85 	struct device *parent;
86 	struct cfdata *cf;
87 	void *aux;
88 {
89 	struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
90 	static int aed_matched = 0;
91 
92 	/* Allow only one instance. */
93         if ((aa_args->origaddr == 0) && (!aed_matched)) {
94 		aed_matched = 1;
95                 return (1);
96         } else
97                 return (0);
98 }
99 
100 static void
101 aedattach(parent, self, aux)
102 	struct device *parent, *self;
103 	void   *aux;
104 {
105 	struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
106 	struct aed_softc *sc = (struct aed_softc *)self;
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 		timeout(aed_kbdrpt, kstate, aed_sc->sc_rptinterval);
326 	}
327 }
328 
329 
330 /*
331  * Cancels the currently repeating key event if there is one, schedules
332  * a new repeating key event if needed, and hands the event off to the
333  * appropriate subsystem.
334  */
335 static void
336 aed_dokeyupdown(event)
337 	adb_event_t *event;
338 {
339 	int     kbd_key;
340 
341 	kbd_key = ADBK_KEYVAL(event->u.k.key);
342 	if (ADBK_PRESS(event->u.k.key) && keyboard[kbd_key][0] != 0) {
343 		/* ignore shift & control */
344 		if (aed_sc->sc_repeating != -1) {
345 			untimeout(aed_kbdrpt, (void *)aed_sc);
346 		}
347 		aed_sc->sc_rptevent = *event;
348 		aed_sc->sc_repeating = kbd_key;
349 		timeout(aed_kbdrpt, (void *)aed_sc, aed_sc->sc_rptdelay);
350 	} else {
351 		if (aed_sc->sc_repeating != -1) {
352 			aed_sc->sc_repeating = -1;
353 			untimeout(aed_kbdrpt, (void *)aed_sc);
354 		}
355 		aed_sc->sc_rptevent = *event;
356 	}
357 	aed_handoff(event);
358 }
359 
360 /*
361  * Place the event in the event queue if a requesting device is open
362  * and we are not polling, otherwise, pass it up to the console driver.
363  */
364 static void
365 aed_handoff(event)
366 	adb_event_t *event;
367 {
368 	if (aed_sc->sc_open && !ite_polling)
369 		aed_enqevent(event);
370 	else {
371 		if (event->def_addr == 2)
372 			ite_intr(event);
373 	}
374 }
375 
376 /*
377  * Place the event in the event queue and wakeup any waiting processes.
378  */
379 static void
380 aed_enqevent(event)
381     adb_event_t *event;
382 {
383 	int     s;
384 
385 	s = spladb();
386 
387 #ifdef DIAGNOSTIC
388 	if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS)
389 		panic("adb: event queue tail is out of bounds");
390 
391 	if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS)
392 		panic("adb: event queue len is out of bounds");
393 #endif
394 
395 	if (aed_sc->sc_evq_len == AED_MAX_EVENTS) {
396 		splx(s);
397 		return;		/* Oh, well... */
398 	}
399 	aed_sc->sc_evq[(aed_sc->sc_evq_len + aed_sc->sc_evq_tail) %
400 	    AED_MAX_EVENTS] = *event;
401 	aed_sc->sc_evq_len++;
402 
403 	selwakeup(&aed_sc->sc_selinfo);
404 	if (aed_sc->sc_ioproc)
405 		psignal(aed_sc->sc_ioproc, SIGIO);
406 
407 	splx(s);
408 }
409 
410 int
411 aedopen(dev, flag, mode, p)
412     dev_t dev;
413     int flag, mode;
414     struct proc *p;
415 {
416 	int unit;
417 	int error = 0;
418 	int s;
419 
420 	unit = minor(dev);
421 
422 	if (unit != 0)
423 		return (ENXIO);
424 
425 	s = spladb();
426 	if (aed_sc->sc_open) {
427 		splx(s);
428 		return (EBUSY);
429 	}
430 	aed_sc->sc_evq_tail = 0;
431 	aed_sc->sc_evq_len = 0;
432 	aed_sc->sc_open = 1;
433 	aed_sc->sc_ioproc = p;
434 	splx(s);
435 
436 	return (error);
437 }
438 
439 
440 int
441 aedclose(dev, flag, mode, p)
442     dev_t dev;
443     int flag, mode;
444     struct proc *p;
445 {
446 	int s = spladb();
447 
448 	aed_sc->sc_open = 0;
449 	aed_sc->sc_ioproc = NULL;
450 	splx(s);
451 
452 	return (0);
453 }
454 
455 
456 int
457 aedread(dev, uio, flag)
458     dev_t dev;
459     struct uio *uio;
460     int flag;
461 {
462 	int s, error;
463 	int willfit;
464 	int total;
465 	int firstmove;
466 	int moremove;
467 
468 	if (uio->uio_resid < sizeof(adb_event_t))
469 		return (EMSGSIZE);	/* close enough. */
470 
471 	s = spladb();
472 	if (aed_sc->sc_evq_len == 0) {
473 		splx(s);
474 		return (0);
475 	}
476 	willfit = howmany(uio->uio_resid, sizeof(adb_event_t));
477 	total = (aed_sc->sc_evq_len < willfit) ? aed_sc->sc_evq_len : willfit;
478 
479 	firstmove = (aed_sc->sc_evq_tail + total > AED_MAX_EVENTS)
480 	    ? (AED_MAX_EVENTS - aed_sc->sc_evq_tail) : total;
481 
482 	error = uiomove((caddr_t) & aed_sc->sc_evq[aed_sc->sc_evq_tail],
483 	    firstmove * sizeof(adb_event_t), uio);
484 	if (error) {
485 		splx(s);
486 		return (error);
487 	}
488 	moremove = total - firstmove;
489 
490 	if (moremove > 0) {
491 		error = uiomove((caddr_t) & aed_sc->sc_evq[0],
492 		    moremove * sizeof(adb_event_t), uio);
493 		if (error) {
494 			splx(s);
495 			return (error);
496 		}
497 	}
498 	aed_sc->sc_evq_tail = (aed_sc->sc_evq_tail + total) % AED_MAX_EVENTS;
499 	aed_sc->sc_evq_len -= total;
500 	splx(s);
501 	return (0);
502 }
503 
504 
505 int
506 aedwrite(dev, uio, flag)
507     dev_t dev;
508     struct uio *uio;
509     int flag;
510 {
511 	return 0;
512 }
513 
514 
515 int
516 aedioctl(dev, cmd, data, flag, p)
517     dev_t dev;
518     int cmd;
519     caddr_t data;
520     int flag;
521     struct proc *p;
522 {
523 	switch (cmd) {
524 	case ADBIOC_DEVSINFO: {
525 		adb_devinfo_t *di;
526 		ADBDataBlock adbdata;
527 		int totaldevs;
528 		int adbaddr;
529 		int i;
530 
531 		di = (void *)data;
532 
533 		/* Initialize to no devices */
534 		for (i = 0; i < 16; i++)
535 			di->dev[i].addr = -1;
536 
537 		totaldevs = CountADBs();
538 		for (i = 1; i <= totaldevs; i++) {
539 			adbaddr = GetIndADB(&adbdata, i);
540 			di->dev[adbaddr].addr = adbaddr;
541 			di->dev[adbaddr].default_addr = (int)(adbdata.origADBAddr);
542 			di->dev[adbaddr].handler_id = (int)(adbdata.devType);
543 			}
544 
545 		/* Must call ADB Manager to get devices now */
546 		break;
547 	}
548 
549 	case ADBIOC_GETREPEAT:{
550 		adb_rptinfo_t *ri;
551 
552 		ri = (void *)data;
553 		ri->delay_ticks = aed_sc->sc_rptdelay;
554 		ri->interval_ticks = aed_sc->sc_rptinterval;
555 		break;
556 	}
557 
558 	case ADBIOC_SETREPEAT:{
559 		adb_rptinfo_t *ri;
560 
561 		ri = (void *) data;
562 		aed_sc->sc_rptdelay = ri->delay_ticks;
563 		aed_sc->sc_rptinterval = ri->interval_ticks;
564 		break;
565 	}
566 
567 	case ADBIOC_RESET:
568 		/* Do nothing for now */
569 		break;
570 
571 	case ADBIOC_LISTENCMD:{
572 		adb_listencmd_t *lc;
573 
574 		lc = (void *)data;
575 	}
576 
577 	default:
578 		return (EINVAL);
579 	}
580 	return (0);
581 }
582 
583 
584 int
585 aedpoll(dev, events, p)
586 	dev_t dev;
587 	int events;
588 	struct proc *p;
589 {
590 	int s, revents;
591 
592 	revents = events & (POLLOUT | POLLWRNORM);
593 
594 	if ((events & (POLLIN | POLLRDNORM)) == 0)
595 		return (revents);
596 
597 	s = spladb();
598 	if (aed_sc->sc_evq_len > 0)
599 		revents |= events & (POLLIN | POLLRDNORM);
600 	else
601 		selrecord(p, &aed_sc->sc_selinfo);
602 	splx(s);
603 
604 	return (revents);
605 }
606