Home | History | Annotate | Line # | Download | only in dev
aed.c revision 1.5
      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