/*
* Copyright (C) 1994 Bradley A. Grantham
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Pull in the options flags. */
sc->sc_options = (device_cfdata(self)->cf_flags | aed_options);
sc->sc_ioproc = NULL;
sc->sc_buttons = 0;
sc->sc_open = 0;
aed_sc = sc;
printf("ADB Event device\n");
return;
}
/*
* Given a keyboard ADB event, record the keycode and call the key
* repeat handler, optionally passing the event through the mouse
* button emulation handler first. Pass mouse events directly to
* the handoff function.
*/
void
aed_input(adb_event_t *event)
{
adb_event_t new_event = *event;
switch (event->def_addr) {
case ADBADDR_KBD:
if (aed_sc->sc_options & AED_MSEMUL) {
rv = aed_emulate_mouse(&new_event);
} else
aed_dokeyupdown(&new_event);
break;
case ADBADDR_MS:
event->u.m.buttons |= aed_sc->sc_buttons;
new_event.u.m.buttons |= aed_sc->sc_buttons;
aed_handoff(&new_event);
break;
default: /* God only knows. */
#ifdef DIAGNOSTIC
panic("aed: received event from unsupported device!");
#endif
break;
}
}
/*
* Handles mouse button emulation via the keyboard. If the emulation
* modifier key is down, left and right arrows will generate 2nd and
* 3rd mouse button events while the 1, 2, and 3 keys will generate
* the corresponding mouse button event.
*/
static int
aed_emulate_mouse(adb_event_t *event)
{
static int emulmodkey_down = 0;
adb_event_t new_event;
int result = 0;
if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) {
emulmodkey_down = 1;
} else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) {
/* key up */
emulmodkey_down = 0;
if (aed_sc->sc_buttons & 0xfe) {
aed_sc->sc_buttons &= 1;
new_event.def_addr = ADBADDR_MS;
new_event.u.m.buttons = aed_sc->sc_buttons;
new_event.u.m.dx = new_event.u.m.dy = 0;
microtime(&new_event.timestamp);
aed_handoff(&new_event);
}
} else if (emulmodkey_down) {
switch(event->u.k.key) {
#ifdef ALTXBUTTONS
case ADBK_KEYDOWN(ADBK_1):
result = 1;
aed_sc->sc_buttons |= 1; /* left down */
new_event.def_addr = ADBADDR_MS;
new_event.u.m.buttons = aed_sc->sc_buttons;
new_event.u.m.dx = new_event.u.m.dy = 0;
microtime(&new_event.timestamp);
aed_handoff(&new_event);
break;
case ADBK_KEYUP(ADBK_1):
result = 1;
aed_sc->sc_buttons &= ~1; /* left up */
new_event.def_addr = ADBADDR_MS;
new_event.u.m.buttons = aed_sc->sc_buttons;
new_event.u.m.dx = new_event.u.m.dy = 0;
microtime(&new_event.timestamp);
aed_handoff(&new_event);
break;
#endif
case ADBK_KEYDOWN(ADBK_LEFT):
#ifdef ALTXBUTTONS
case ADBK_KEYDOWN(ADBK_2):
#endif
result = 1;
aed_sc->sc_buttons |= 2; /* middle down */
new_event.def_addr = ADBADDR_MS;
new_event.u.m.buttons = aed_sc->sc_buttons;
new_event.u.m.dx = new_event.u.m.dy = 0;
microtime(&new_event.timestamp);
aed_handoff(&new_event);
break;
case ADBK_KEYUP(ADBK_LEFT):
#ifdef ALTXBUTTONS
case ADBK_KEYUP(ADBK_2):
#endif
result = 1;
aed_sc->sc_buttons &= ~2; /* middle up */
new_event.def_addr = ADBADDR_MS;
new_event.u.m.buttons = aed_sc->sc_buttons;
new_event.u.m.dx = new_event.u.m.dy = 0;
microtime(&new_event.timestamp);
aed_handoff(&new_event);
break;
case ADBK_KEYDOWN(ADBK_RIGHT):
#ifdef ALTXBUTTONS
case ADBK_KEYDOWN(ADBK_3):
#endif
result = 1;
aed_sc->sc_buttons |= 4; /* right down */
new_event.def_addr = ADBADDR_MS;
new_event.u.m.buttons = aed_sc->sc_buttons;
new_event.u.m.dx = new_event.u.m.dy = 0;
microtime(&new_event.timestamp);
aed_handoff(&new_event);
break;
case ADBK_KEYUP(ADBK_RIGHT):
#ifdef ALTXBUTTONS
case ADBK_KEYUP(ADBK_3):
#endif
result = 1;
aed_sc->sc_buttons &= ~4; /* right up */
new_event.def_addr = ADBADDR_MS;
new_event.u.m.buttons = aed_sc->sc_buttons;
new_event.u.m.dx = new_event.u.m.dy = 0;
microtime(&new_event.timestamp);
aed_handoff(&new_event);
break;
case ADBK_KEYUP(ADBK_SHIFT):
case ADBK_KEYDOWN(ADBK_SHIFT):
case ADBK_KEYUP(ADBK_CONTROL):
case ADBK_KEYDOWN(ADBK_CONTROL):
case ADBK_KEYUP(ADBK_FLOWER):
case ADBK_KEYDOWN(ADBK_FLOWER):
/* ctrl, shift, cmd */
aed_dokeyupdown(event);
break;
default:
if (event->u.k.key & 0x80)
/* ignore keyup */
break;
/*
* Keyboard autorepeat timeout function. Sends key up/down events
* for the repeating key and schedules the next call at sc_rptinterval
* ticks in the future.
*/
static void
aed_kbdrpt(void *kstate)
{
struct aed_softc *sc = (struct aed_softc *)kstate;
sc->sc_rptevent.bytes[0] |= 0x80;
microtime(&sc->sc_rptevent.timestamp);
aed_handoff(&sc->sc_rptevent); /* do key up */
sc->sc_rptevent.bytes[0] &= 0x7f;
microtime(&sc->sc_rptevent.timestamp);
aed_handoff(&sc->sc_rptevent); /* do key down */
/*
* Cancels the currently repeating key event if there is one, schedules
* a new repeating key event if needed, and hands the event off to the
* appropriate subsystem.
*/
static void
aed_dokeyupdown(adb_event_t *event)
{
int kbd_key;
/*
* Place the event in the event queue if a requesting device is open
* and we are not polling.
*/
static void
aed_handoff(adb_event_t *event)
{
if (aed_sc->sc_open && !adb_polling)
aed_enqevent(event);
}
/*
* Place the event in the event queue and wakeup any waiting processes.
*/
static void
aed_enqevent(adb_event_t *event)
{
int s;
s = spladb();
#ifdef DIAGNOSTIC
if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS)
panic("adb: event queue tail is out of bounds");
if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS)
panic("adb: event queue len is out of bounds");
#endif
int
aedioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
{
switch (cmd) {
case ADBIOCDEVSINFO: {
adb_devinfo_t *di;
ADBDataBlock adbdata;
int totaldevs;
int adbaddr;
int i;
di = (void *)data;
/* Initialize to no devices */
for (i = 0; i < 16; i++)
di->dev[i].addr = -1;
totaldevs = CountADBs();
for (i = 1; i <= totaldevs; i++) {
adbaddr = GetIndADB(&adbdata, i);
di->dev[adbaddr].addr = adbaddr;
di->dev[adbaddr].default_addr = (int)(adbdata.origADBAddr);
di->dev[adbaddr].handler_id = (int)(adbdata.devType);
}
/* Must call ADB Manager to get devices now */
break;
}