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