xref: /netbsd-src/sys/arch/mac68k/dev/aed.c (revision 37b34d511dea595d3ba03a661cf3b775038ea5f8)
1 /*	$NetBSD: aed.c,v 1.14 2002/10/02 05:36:37 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 "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 #include <sys/conf.h>
44 
45 #include <machine/autoconf.h>
46 #include <machine/cpu.h>
47 #include <machine/keyboard.h>
48 
49 #include <mac68k/mac68k/macrom.h>
50 #include <mac68k/dev/adbvar.h>
51 #include <mac68k/dev/aedvar.h>
52 #include <mac68k/dev/akbdvar.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  * Local variables.
67  */
68 static struct aed_softc *aed_sc = NULL;
69 static int aed_options = 0 | AED_MSEMUL;
70 
71 /* Driver definition */
72 CFATTACH_DECL(aed, sizeof(struct aed_softc),
73     aedmatch, aedattach, NULL, NULL);
74 
75 extern struct cfdriver aed_cd;
76 
77 dev_type_open(aedopen);
78 dev_type_close(aedclose);
79 dev_type_read(aedread);
80 dev_type_ioctl(aedioctl);
81 dev_type_poll(aedpoll);
82 
83 const struct cdevsw aed_cdevsw = {
84 	aedopen, aedclose, aedread, nullwrite, aedioctl,
85 	nostop, notty, aedpoll, nommap,
86 };
87 
88 static int
89 aedmatch(parent, cf, aux)
90 	struct device *parent;
91 	struct cfdata *cf;
92 	void *aux;
93 {
94 	struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
95 	static int aed_matched = 0;
96 
97 	/* Allow only one instance. */
98         if ((aa_args->origaddr == 0) && (!aed_matched)) {
99 		aed_matched = 1;
100                 return (1);
101         } else
102                 return (0);
103 }
104 
105 static void
106 aedattach(parent, self, aux)
107 	struct device *parent, *self;
108 	void   *aux;
109 {
110 	struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
111 	struct aed_softc *sc = (struct aed_softc *)self;
112 
113 	callout_init(&sc->sc_repeat_ch);
114 
115 	sc->origaddr = aa_args->origaddr;
116 	sc->adbaddr = aa_args->adbaddr;
117 	sc->handler_id = aa_args->handler_id;
118 
119 	sc->sc_evq_tail = 0;
120 	sc->sc_evq_len = 0;
121 
122 	sc->sc_rptdelay = 20;
123 	sc->sc_rptinterval = 6;
124 	sc->sc_repeating = -1;          /* not repeating */
125 
126 	/* Pull in the options flags. */
127 	sc->sc_options = (sc->sc_dev.dv_cfdata->cf_flags | aed_options);
128 
129 	sc->sc_ioproc = NULL;
130 
131 	sc->sc_buttons = 0;
132 
133 	sc->sc_open = 0;
134 
135 	aed_sc = sc;
136 
137 	printf("ADB Event device\n");
138 
139 	return;
140 }
141 
142 /*
143  * Given a keyboard ADB event, record the keycode and call the key
144  * repeat handler, optionally passing the event through the mouse
145  * button emulation handler first.  Pass mouse events directly to
146  * the handoff function.
147  */
148 int
149 aed_input(event)
150         adb_event_t *event;
151 {
152         adb_event_t new_event = *event;
153 	int rv = aed_sc->sc_open;
154 
155 	switch (event->def_addr) {
156 	case ADBADDR_KBD:
157 		if (aed_sc->sc_options & AED_MSEMUL)
158 			aed_emulate_mouse(&new_event);
159 		else
160 			aed_dokeyupdown(&new_event);
161 		break;
162 	case ADBADDR_MS:
163 		new_event.u.m.buttons |= aed_sc->sc_buttons;
164 		aed_handoff(&new_event);
165 		break;
166 	default:                /* God only knows. */
167 #ifdef DIAGNOSTIC
168 		panic("aed: received event from unsupported device!");
169 #endif
170 		rv = 0;
171 		break;
172 	}
173 
174 	return (rv);
175 }
176 
177 /*
178  * Handles mouse button emulation via the keyboard.  If the emulation
179  * modifier key is down, left and right arrows will generate 2nd and
180  * 3rd mouse button events while the 1, 2, and 3 keys will generate
181  * the corresponding mouse button event.
182  */
183 static void
184 aed_emulate_mouse(event)
185 	adb_event_t *event;
186 {
187 	static int emulmodkey_down = 0;
188 	adb_event_t new_event;
189 
190 	if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) {
191 		emulmodkey_down = 1;
192 	} else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) {
193 		/* key up */
194 		emulmodkey_down = 0;
195 		if (aed_sc->sc_buttons & 0xfe) {
196 			aed_sc->sc_buttons &= 1;
197 			new_event.def_addr = ADBADDR_MS;
198 			new_event.u.m.buttons = aed_sc->sc_buttons;
199 			new_event.u.m.dx = new_event.u.m.dy = 0;
200 			microtime(&new_event.timestamp);
201 			aed_handoff(&new_event);
202 		}
203 	} else if (emulmodkey_down) {
204 		switch(event->u.k.key) {
205 #ifdef ALTXBUTTONS
206 		case ADBK_KEYDOWN(ADBK_1):
207 			aed_sc->sc_buttons |= 1;	/* left down */
208 			new_event.def_addr = ADBADDR_MS;
209 			new_event.u.m.buttons = aed_sc->sc_buttons;
210 			new_event.u.m.dx = new_event.u.m.dy = 0;
211 			microtime(&new_event.timestamp);
212 			aed_handoff(&new_event);
213 			break;
214 		case ADBK_KEYUP(ADBK_1):
215 			aed_sc->sc_buttons &= ~1;	/* left up */
216 			new_event.def_addr = ADBADDR_MS;
217 			new_event.u.m.buttons = aed_sc->sc_buttons;
218 			new_event.u.m.dx = new_event.u.m.dy = 0;
219 			microtime(&new_event.timestamp);
220 			aed_handoff(&new_event);
221 			break;
222 #endif
223 		case ADBK_KEYDOWN(ADBK_LEFT):
224 #ifdef ALTXBUTTONS
225 		case ADBK_KEYDOWN(ADBK_2):
226 #endif
227 			aed_sc->sc_buttons |= 2;	/* middle down */
228 			new_event.def_addr = ADBADDR_MS;
229 			new_event.u.m.buttons = aed_sc->sc_buttons;
230 			new_event.u.m.dx = new_event.u.m.dy = 0;
231 			microtime(&new_event.timestamp);
232 			aed_handoff(&new_event);
233 			break;
234 		case ADBK_KEYUP(ADBK_LEFT):
235 #ifdef ALTXBUTTONS
236 		case ADBK_KEYUP(ADBK_2):
237 #endif
238 			aed_sc->sc_buttons &= ~2;	/* middle up */
239 			new_event.def_addr = ADBADDR_MS;
240 			new_event.u.m.buttons = aed_sc->sc_buttons;
241 			new_event.u.m.dx = new_event.u.m.dy = 0;
242 			microtime(&new_event.timestamp);
243 			aed_handoff(&new_event);
244 			break;
245 		case ADBK_KEYDOWN(ADBK_RIGHT):
246 #ifdef ALTXBUTTONS
247 		case ADBK_KEYDOWN(ADBK_3):
248 #endif
249 			aed_sc->sc_buttons |= 4;	/* right down */
250 			new_event.def_addr = ADBADDR_MS;
251 			new_event.u.m.buttons = aed_sc->sc_buttons;
252 			new_event.u.m.dx = new_event.u.m.dy = 0;
253 			microtime(&new_event.timestamp);
254 			aed_handoff(&new_event);
255 			break;
256 		case ADBK_KEYUP(ADBK_RIGHT):
257 #ifdef ALTXBUTTONS
258 		case ADBK_KEYUP(ADBK_3):
259 #endif
260 			aed_sc->sc_buttons &= ~4;	/* right up */
261 			new_event.def_addr = ADBADDR_MS;
262 			new_event.u.m.buttons = aed_sc->sc_buttons;
263 			new_event.u.m.dx = new_event.u.m.dy = 0;
264 			microtime(&new_event.timestamp);
265 			aed_handoff(&new_event);
266 			break;
267 		case ADBK_KEYUP(ADBK_SHIFT):
268 		case ADBK_KEYDOWN(ADBK_SHIFT):
269 		case ADBK_KEYUP(ADBK_CONTROL):
270 		case ADBK_KEYDOWN(ADBK_CONTROL):
271 		case ADBK_KEYUP(ADBK_FLOWER):
272 		case ADBK_KEYDOWN(ADBK_FLOWER):
273 			/* ctrl, shift, cmd */
274 			aed_dokeyupdown(event);
275 			break;
276 		default:
277 			if (event->u.k.key & 0x80)
278 				/* ignore keyup */
279 				break;
280 
281 			/* key down */
282 			new_event = *event;
283 
284 			/* send option-down */
285 			new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION);
286 			new_event.bytes[0] = new_event.u.k.key;
287 			microtime(&new_event.timestamp);
288 			aed_dokeyupdown(&new_event);
289 
290 			/* send key-down */
291 			new_event.u.k.key = event->bytes[0];
292 			new_event.bytes[0] = new_event.u.k.key;
293 			microtime(&new_event.timestamp);
294 			aed_dokeyupdown(&new_event);
295 
296 			/* send key-up */
297 			new_event.u.k.key =
298 				ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0]));
299 			microtime(&new_event.timestamp);
300 			new_event.bytes[0] = new_event.u.k.key;
301 			aed_dokeyupdown(&new_event);
302 
303 			/* send option-up */
304 			new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION);
305 			new_event.bytes[0] = new_event.u.k.key;
306 			microtime(&new_event.timestamp);
307 			aed_dokeyupdown(&new_event);
308 			break;
309 		}
310 	} else {
311 		aed_dokeyupdown(event);
312 	}
313 }
314 
315 /*
316  * Keyboard autorepeat timeout function.  Sends key up/down events
317  * for the repeating key and schedules the next call at sc_rptinterval
318  * ticks in the future.
319  */
320 static void
321 aed_kbdrpt(kstate)
322 	void *kstate;
323 {
324 	struct aed_softc *aed_sc = (struct aed_softc *)kstate;
325 
326 	aed_sc->sc_rptevent.bytes[0] |= 0x80;
327 	microtime(&aed_sc->sc_rptevent.timestamp);
328 	aed_handoff(&aed_sc->sc_rptevent);	/* do key up */
329 
330 	aed_sc->sc_rptevent.bytes[0] &= 0x7f;
331 	microtime(&aed_sc->sc_rptevent.timestamp);
332 	aed_handoff(&aed_sc->sc_rptevent);	/* do key down */
333 
334 	if (aed_sc->sc_repeating == aed_sc->sc_rptevent.u.k.key) {
335 		callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptinterval,
336 		    aed_kbdrpt, kstate);
337 	}
338 }
339 
340 
341 /*
342  * Cancels the currently repeating key event if there is one, schedules
343  * a new repeating key event if needed, and hands the event off to the
344  * appropriate subsystem.
345  */
346 static void
347 aed_dokeyupdown(event)
348 	adb_event_t *event;
349 {
350 	int     kbd_key;
351 
352 	kbd_key = ADBK_KEYVAL(event->u.k.key);
353 	if (ADBK_PRESS(event->u.k.key) && keyboard[kbd_key][0] != 0) {
354 		/* ignore shift & control */
355 		if (aed_sc->sc_repeating != -1) {
356 			callout_stop(&aed_sc->sc_repeat_ch);
357 		}
358 		aed_sc->sc_rptevent = *event;
359 		aed_sc->sc_repeating = kbd_key;
360 		callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptdelay,
361 		    aed_kbdrpt, (void *)aed_sc);
362 	} else {
363 		if (aed_sc->sc_repeating != -1) {
364 			aed_sc->sc_repeating = -1;
365 			callout_stop(&aed_sc->sc_repeat_ch);
366 		}
367 		aed_sc->sc_rptevent = *event;
368 	}
369 	aed_handoff(event);
370 }
371 
372 /*
373  * Place the event in the event queue if a requesting device is open
374  * and we are not polling, otherwise, pass it up to the console driver.
375  */
376 static void
377 aed_handoff(event)
378 	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(event)
389     adb_event_t *event;
390 {
391 	int     s;
392 
393 	s = spladb();
394 
395 #ifdef DIAGNOSTIC
396 	if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS)
397 		panic("adb: event queue tail is out of bounds");
398 
399 	if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS)
400 		panic("adb: event queue len is out of bounds");
401 #endif
402 
403 	if (aed_sc->sc_evq_len == AED_MAX_EVENTS) {
404 		splx(s);
405 		return;		/* Oh, well... */
406 	}
407 	aed_sc->sc_evq[(aed_sc->sc_evq_len + aed_sc->sc_evq_tail) %
408 	    AED_MAX_EVENTS] = *event;
409 	aed_sc->sc_evq_len++;
410 
411 	selwakeup(&aed_sc->sc_selinfo);
412 	if (aed_sc->sc_ioproc)
413 		psignal(aed_sc->sc_ioproc, SIGIO);
414 
415 	splx(s);
416 }
417 
418 int
419 aedopen(dev, flag, mode, p)
420     dev_t dev;
421     int flag, mode;
422     struct proc *p;
423 {
424 	int unit;
425 	int error = 0;
426 	int s;
427 
428 	unit = minor(dev);
429 
430 	if (unit != 0)
431 		return (ENXIO);
432 
433 	s = spladb();
434 	if (aed_sc->sc_open) {
435 		splx(s);
436 		return (EBUSY);
437 	}
438 	aed_sc->sc_evq_tail = 0;
439 	aed_sc->sc_evq_len = 0;
440 	aed_sc->sc_open = 1;
441 	aed_sc->sc_ioproc = p;
442 	splx(s);
443 
444 	return (error);
445 }
446 
447 
448 int
449 aedclose(dev, flag, mode, p)
450     dev_t dev;
451     int flag, mode;
452     struct proc *p;
453 {
454 	int s = spladb();
455 
456 	aed_sc->sc_open = 0;
457 	aed_sc->sc_ioproc = NULL;
458 	splx(s);
459 
460 	return (0);
461 }
462 
463 
464 int
465 aedread(dev, uio, flag)
466     dev_t dev;
467     struct uio *uio;
468     int flag;
469 {
470 	int s, error;
471 	int willfit;
472 	int total;
473 	int firstmove;
474 	int moremove;
475 
476 	if (uio->uio_resid < sizeof(adb_event_t))
477 		return (EMSGSIZE);	/* close enough. */
478 
479 	s = spladb();
480 	if (aed_sc->sc_evq_len == 0) {
481 		splx(s);
482 		return (0);
483 	}
484 	willfit = howmany(uio->uio_resid, sizeof(adb_event_t));
485 	total = (aed_sc->sc_evq_len < willfit) ? aed_sc->sc_evq_len : willfit;
486 
487 	firstmove = (aed_sc->sc_evq_tail + total > AED_MAX_EVENTS)
488 	    ? (AED_MAX_EVENTS - aed_sc->sc_evq_tail) : total;
489 
490 	error = uiomove((caddr_t) & aed_sc->sc_evq[aed_sc->sc_evq_tail],
491 	    firstmove * sizeof(adb_event_t), uio);
492 	if (error) {
493 		splx(s);
494 		return (error);
495 	}
496 	moremove = total - firstmove;
497 
498 	if (moremove > 0) {
499 		error = uiomove((caddr_t) & aed_sc->sc_evq[0],
500 		    moremove * sizeof(adb_event_t), uio);
501 		if (error) {
502 			splx(s);
503 			return (error);
504 		}
505 	}
506 	aed_sc->sc_evq_tail = (aed_sc->sc_evq_tail + total) % AED_MAX_EVENTS;
507 	aed_sc->sc_evq_len -= total;
508 	splx(s);
509 	return (0);
510 }
511 
512 int
513 aedioctl(dev, cmd, data, flag, p)
514     dev_t dev;
515     u_long cmd;
516     caddr_t data;
517     int flag;
518     struct proc *p;
519 {
520 	switch (cmd) {
521 	case ADBIOC_DEVSINFO: {
522 		adb_devinfo_t *di;
523 		ADBDataBlock adbdata;
524 		int totaldevs;
525 		int adbaddr;
526 		int i;
527 
528 		di = (void *)data;
529 
530 		/* Initialize to no devices */
531 		for (i = 0; i < 16; i++)
532 			di->dev[i].addr = -1;
533 
534 		totaldevs = CountADBs();
535 		for (i = 1; i <= totaldevs; i++) {
536 			adbaddr = GetIndADB(&adbdata, i);
537 			di->dev[adbaddr].addr = adbaddr;
538 			di->dev[adbaddr].default_addr = (int)(adbdata.origADBAddr);
539 			di->dev[adbaddr].handler_id = (int)(adbdata.devType);
540 			}
541 
542 		/* Must call ADB Manager to get devices now */
543 		break;
544 	}
545 
546 	case ADBIOC_GETREPEAT:{
547 		adb_rptinfo_t *ri;
548 
549 		ri = (void *)data;
550 		ri->delay_ticks = aed_sc->sc_rptdelay;
551 		ri->interval_ticks = aed_sc->sc_rptinterval;
552 		break;
553 	}
554 
555 	case ADBIOC_SETREPEAT:{
556 		adb_rptinfo_t *ri;
557 
558 		ri = (void *) data;
559 		aed_sc->sc_rptdelay = ri->delay_ticks;
560 		aed_sc->sc_rptinterval = ri->interval_ticks;
561 		break;
562 	}
563 
564 	case ADBIOC_RESET:
565 		/* Do nothing for now */
566 		break;
567 
568 	case ADBIOC_LISTENCMD:{
569 		adb_listencmd_t *lc;
570 
571 		lc = (void *)data;
572 	}
573 
574 	default:
575 		return (EINVAL);
576 	}
577 	return (0);
578 }
579 
580 
581 int
582 aedpoll(dev, events, p)
583 	dev_t dev;
584 	int events;
585 	struct proc *p;
586 {
587 	int s, revents;
588 
589 	revents = events & (POLLOUT | POLLWRNORM);
590 
591 	if ((events & (POLLIN | POLLRDNORM)) == 0)
592 		return (revents);
593 
594 	s = spladb();
595 	if (aed_sc->sc_evq_len > 0)
596 		revents |= events & (POLLIN | POLLRDNORM);
597 	else
598 		selrecord(p, &aed_sc->sc_selinfo);
599 	splx(s);
600 
601 	return (revents);
602 }
603