xref: /netbsd/sys/arch/mac68k/dev/aed.c (revision bf9ec67e)
1 /*	$NetBSD: aed.c,v 1.10 2000/03/23 06:39:56 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 
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/akbdvar.h>
52 
53 /*
54  * Function declarations.
55  */
56 static int	aedmatch __P((struct device *, struct cfdata *, void *));
57 static void	aedattach __P((struct device *, struct device *, void *));
58 static void	aed_emulate_mouse __P((adb_event_t *event));
59 static void	aed_kbdrpt __P((void *kstate));
60 static void	aed_dokeyupdown __P((adb_event_t *event));
61 static void	aed_handoff __P((adb_event_t *event));
62 static void	aed_enqevent __P((adb_event_t *event));
63 
64 /*
65  * Local variables.
66  */
67 static struct aed_softc *aed_sc = NULL;
68 static int aed_options = 0 | AED_MSEMUL;
69 
70 /* Driver definition */
71 struct cfattach aed_ca = {
72 	sizeof(struct aed_softc), aedmatch, aedattach
73 };
74 
75 extern struct cfdriver aed_cd;
76 
77 static int
78 aedmatch(parent, cf, aux)
79 	struct device *parent;
80 	struct cfdata *cf;
81 	void *aux;
82 {
83 	struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
84 	static int aed_matched = 0;
85 
86 	/* Allow only one instance. */
87         if ((aa_args->origaddr == 0) && (!aed_matched)) {
88 		aed_matched = 1;
89                 return (1);
90         } else
91                 return (0);
92 }
93 
94 static void
95 aedattach(parent, self, aux)
96 	struct device *parent, *self;
97 	void   *aux;
98 {
99 	struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
100 	struct aed_softc *sc = (struct aed_softc *)self;
101 
102 	callout_init(&sc->sc_repeat_ch);
103 
104 	sc->origaddr = aa_args->origaddr;
105 	sc->adbaddr = aa_args->adbaddr;
106 	sc->handler_id = aa_args->handler_id;
107 
108 	sc->sc_evq_tail = 0;
109 	sc->sc_evq_len = 0;
110 
111 	sc->sc_rptdelay = 20;
112 	sc->sc_rptinterval = 6;
113 	sc->sc_repeating = -1;          /* not repeating */
114 
115 	/* Pull in the options flags. */
116 	sc->sc_options = (sc->sc_dev.dv_cfdata->cf_flags | aed_options);
117 
118 	sc->sc_ioproc = NULL;
119 
120 	sc->sc_buttons = 0;
121 
122 	sc->sc_open = 0;
123 
124 	aed_sc = sc;
125 
126 	printf("ADB Event device\n");
127 
128 	return;
129 }
130 
131 /*
132  * Given a keyboard ADB event, record the keycode and call the key
133  * repeat handler, optionally passing the event through the mouse
134  * button emulation handler first.  Pass mouse events directly to
135  * the handoff function.
136  */
137 int
138 aed_input(event)
139         adb_event_t *event;
140 {
141         adb_event_t new_event = *event;
142 	int rv = aed_sc->sc_open;
143 
144 	switch (event->def_addr) {
145 	case ADBADDR_KBD:
146 		if (aed_sc->sc_options & AED_MSEMUL)
147 			aed_emulate_mouse(&new_event);
148 		else
149 			aed_dokeyupdown(&new_event);
150 		break;
151 	case ADBADDR_MS:
152 		new_event.u.m.buttons |= aed_sc->sc_buttons;
153 		aed_handoff(&new_event);
154 		break;
155 	default:                /* God only knows. */
156 #ifdef DIAGNOSTIC
157 		panic("aed: received event from unsupported device!\n");
158 #endif
159 		rv = 0;
160 		break;
161 	}
162 
163 	return (rv);
164 }
165 
166 /*
167  * Handles mouse button emulation via the keyboard.  If the emulation
168  * modifier key is down, left and right arrows will generate 2nd and
169  * 3rd mouse button events while the 1, 2, and 3 keys will generate
170  * the corresponding mouse button event.
171  */
172 static void
173 aed_emulate_mouse(event)
174 	adb_event_t *event;
175 {
176 	static int emulmodkey_down = 0;
177 	adb_event_t new_event;
178 
179 	if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) {
180 		emulmodkey_down = 1;
181 	} else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) {
182 		/* key up */
183 		emulmodkey_down = 0;
184 		if (aed_sc->sc_buttons & 0xfe) {
185 			aed_sc->sc_buttons &= 1;
186 			new_event.def_addr = ADBADDR_MS;
187 			new_event.u.m.buttons = aed_sc->sc_buttons;
188 			new_event.u.m.dx = new_event.u.m.dy = 0;
189 			microtime(&new_event.timestamp);
190 			aed_handoff(&new_event);
191 		}
192 	} else if (emulmodkey_down) {
193 		switch(event->u.k.key) {
194 #ifdef ALTXBUTTONS
195 		case ADBK_KEYDOWN(ADBK_1):
196 			aed_sc->sc_buttons |= 1;	/* left down */
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 			break;
203 		case ADBK_KEYUP(ADBK_1):
204 			aed_sc->sc_buttons &= ~1;	/* left up */
205 			new_event.def_addr = ADBADDR_MS;
206 			new_event.u.m.buttons = aed_sc->sc_buttons;
207 			new_event.u.m.dx = new_event.u.m.dy = 0;
208 			microtime(&new_event.timestamp);
209 			aed_handoff(&new_event);
210 			break;
211 #endif
212 		case ADBK_KEYDOWN(ADBK_LEFT):
213 #ifdef ALTXBUTTONS
214 		case ADBK_KEYDOWN(ADBK_2):
215 #endif
216 			aed_sc->sc_buttons |= 2;	/* middle down */
217 			new_event.def_addr = ADBADDR_MS;
218 			new_event.u.m.buttons = aed_sc->sc_buttons;
219 			new_event.u.m.dx = new_event.u.m.dy = 0;
220 			microtime(&new_event.timestamp);
221 			aed_handoff(&new_event);
222 			break;
223 		case ADBK_KEYUP(ADBK_LEFT):
224 #ifdef ALTXBUTTONS
225 		case ADBK_KEYUP(ADBK_2):
226 #endif
227 			aed_sc->sc_buttons &= ~2;	/* middle up */
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_KEYDOWN(ADBK_RIGHT):
235 #ifdef ALTXBUTTONS
236 		case ADBK_KEYDOWN(ADBK_3):
237 #endif
238 			aed_sc->sc_buttons |= 4;	/* right down */
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_KEYUP(ADBK_RIGHT):
246 #ifdef ALTXBUTTONS
247 		case ADBK_KEYUP(ADBK_3):
248 #endif
249 			aed_sc->sc_buttons &= ~4;	/* right up */
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_SHIFT):
257 		case ADBK_KEYDOWN(ADBK_SHIFT):
258 		case ADBK_KEYUP(ADBK_CONTROL):
259 		case ADBK_KEYDOWN(ADBK_CONTROL):
260 		case ADBK_KEYUP(ADBK_FLOWER):
261 		case ADBK_KEYDOWN(ADBK_FLOWER):
262 			/* ctrl, shift, cmd */
263 			aed_dokeyupdown(event);
264 			break;
265 		default:
266 			if (event->u.k.key & 0x80)
267 				/* ignore keyup */
268 				break;
269 
270 			/* key down */
271 			new_event = *event;
272 
273 			/* send option-down */
274 			new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION);
275 			new_event.bytes[0] = new_event.u.k.key;
276 			microtime(&new_event.timestamp);
277 			aed_dokeyupdown(&new_event);
278 
279 			/* send key-down */
280 			new_event.u.k.key = event->bytes[0];
281 			new_event.bytes[0] = new_event.u.k.key;
282 			microtime(&new_event.timestamp);
283 			aed_dokeyupdown(&new_event);
284 
285 			/* send key-up */
286 			new_event.u.k.key =
287 				ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0]));
288 			microtime(&new_event.timestamp);
289 			new_event.bytes[0] = new_event.u.k.key;
290 			aed_dokeyupdown(&new_event);
291 
292 			/* send option-up */
293 			new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION);
294 			new_event.bytes[0] = new_event.u.k.key;
295 			microtime(&new_event.timestamp);
296 			aed_dokeyupdown(&new_event);
297 			break;
298 		}
299 	} else {
300 		aed_dokeyupdown(event);
301 	}
302 }
303 
304 /*
305  * Keyboard autorepeat timeout function.  Sends key up/down events
306  * for the repeating key and schedules the next call at sc_rptinterval
307  * ticks in the future.
308  */
309 static void
310 aed_kbdrpt(kstate)
311 	void *kstate;
312 {
313 	struct aed_softc *aed_sc = (struct aed_softc *)kstate;
314 
315 	aed_sc->sc_rptevent.bytes[0] |= 0x80;
316 	microtime(&aed_sc->sc_rptevent.timestamp);
317 	aed_handoff(&aed_sc->sc_rptevent);	/* do key up */
318 
319 	aed_sc->sc_rptevent.bytes[0] &= 0x7f;
320 	microtime(&aed_sc->sc_rptevent.timestamp);
321 	aed_handoff(&aed_sc->sc_rptevent);	/* do key down */
322 
323 	if (aed_sc->sc_repeating == aed_sc->sc_rptevent.u.k.key) {
324 		callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptinterval,
325 		    aed_kbdrpt, kstate);
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 			callout_stop(&aed_sc->sc_repeat_ch);
346 		}
347 		aed_sc->sc_rptevent = *event;
348 		aed_sc->sc_repeating = kbd_key;
349 		callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptdelay,
350 		    aed_kbdrpt, (void *)aed_sc);
351 	} else {
352 		if (aed_sc->sc_repeating != -1) {
353 			aed_sc->sc_repeating = -1;
354 			callout_stop(&aed_sc->sc_repeat_ch);
355 		}
356 		aed_sc->sc_rptevent = *event;
357 	}
358 	aed_handoff(event);
359 }
360 
361 /*
362  * Place the event in the event queue if a requesting device is open
363  * and we are not polling, otherwise, pass it up to the console driver.
364  */
365 static void
366 aed_handoff(event)
367 	adb_event_t *event;
368 {
369 	if (aed_sc->sc_open && !adb_polling)
370 		aed_enqevent(event);
371 }
372 
373 /*
374  * Place the event in the event queue and wakeup any waiting processes.
375  */
376 static void
377 aed_enqevent(event)
378     adb_event_t *event;
379 {
380 	int     s;
381 
382 	s = spladb();
383 
384 #ifdef DIAGNOSTIC
385 	if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS)
386 		panic("adb: event queue tail is out of bounds");
387 
388 	if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS)
389 		panic("adb: event queue len is out of bounds");
390 #endif
391 
392 	if (aed_sc->sc_evq_len == AED_MAX_EVENTS) {
393 		splx(s);
394 		return;		/* Oh, well... */
395 	}
396 	aed_sc->sc_evq[(aed_sc->sc_evq_len + aed_sc->sc_evq_tail) %
397 	    AED_MAX_EVENTS] = *event;
398 	aed_sc->sc_evq_len++;
399 
400 	selwakeup(&aed_sc->sc_selinfo);
401 	if (aed_sc->sc_ioproc)
402 		psignal(aed_sc->sc_ioproc, SIGIO);
403 
404 	splx(s);
405 }
406 
407 int
408 aedopen(dev, flag, mode, p)
409     dev_t dev;
410     int flag, mode;
411     struct proc *p;
412 {
413 	int unit;
414 	int error = 0;
415 	int s;
416 
417 	unit = minor(dev);
418 
419 	if (unit != 0)
420 		return (ENXIO);
421 
422 	s = spladb();
423 	if (aed_sc->sc_open) {
424 		splx(s);
425 		return (EBUSY);
426 	}
427 	aed_sc->sc_evq_tail = 0;
428 	aed_sc->sc_evq_len = 0;
429 	aed_sc->sc_open = 1;
430 	aed_sc->sc_ioproc = p;
431 	splx(s);
432 
433 	return (error);
434 }
435 
436 
437 int
438 aedclose(dev, flag, mode, p)
439     dev_t dev;
440     int flag, mode;
441     struct proc *p;
442 {
443 	int s = spladb();
444 
445 	aed_sc->sc_open = 0;
446 	aed_sc->sc_ioproc = NULL;
447 	splx(s);
448 
449 	return (0);
450 }
451 
452 
453 int
454 aedread(dev, uio, flag)
455     dev_t dev;
456     struct uio *uio;
457     int flag;
458 {
459 	int s, error;
460 	int willfit;
461 	int total;
462 	int firstmove;
463 	int moremove;
464 
465 	if (uio->uio_resid < sizeof(adb_event_t))
466 		return (EMSGSIZE);	/* close enough. */
467 
468 	s = spladb();
469 	if (aed_sc->sc_evq_len == 0) {
470 		splx(s);
471 		return (0);
472 	}
473 	willfit = howmany(uio->uio_resid, sizeof(adb_event_t));
474 	total = (aed_sc->sc_evq_len < willfit) ? aed_sc->sc_evq_len : willfit;
475 
476 	firstmove = (aed_sc->sc_evq_tail + total > AED_MAX_EVENTS)
477 	    ? (AED_MAX_EVENTS - aed_sc->sc_evq_tail) : total;
478 
479 	error = uiomove((caddr_t) & aed_sc->sc_evq[aed_sc->sc_evq_tail],
480 	    firstmove * sizeof(adb_event_t), uio);
481 	if (error) {
482 		splx(s);
483 		return (error);
484 	}
485 	moremove = total - firstmove;
486 
487 	if (moremove > 0) {
488 		error = uiomove((caddr_t) & aed_sc->sc_evq[0],
489 		    moremove * sizeof(adb_event_t), uio);
490 		if (error) {
491 			splx(s);
492 			return (error);
493 		}
494 	}
495 	aed_sc->sc_evq_tail = (aed_sc->sc_evq_tail + total) % AED_MAX_EVENTS;
496 	aed_sc->sc_evq_len -= total;
497 	splx(s);
498 	return (0);
499 }
500 
501 
502 int
503 aedwrite(dev, uio, flag)
504     dev_t dev;
505     struct uio *uio;
506     int flag;
507 {
508 	return 0;
509 }
510 
511 
512 int
513 aedioctl(dev, cmd, data, flag, p)
514     dev_t dev;
515     int 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