From fcde3ac6f3a5906ed429f896090076d22269d50c Mon Sep 17 00:00:00 2001 From: macallan Date: Wed, 17 Jan 2007 23:20:16 +0000 Subject: [PATCH] new, simplified ADB drivers --- sys/dev/adb/adb_bus.c | 282 +++++++++++++++ sys/dev/adb/adb_kbd.c | 661 ++++++++++++++++++++++++++++++++++ sys/dev/adb/adb_keymap.h | 431 ++++++++++++++++++++++ sys/dev/adb/adb_ms.c | 750 +++++++++++++++++++++++++++++++++++++++ sys/dev/adb/adbvar.h | 68 ++++ sys/dev/adb/files.adb | 23 ++ 6 files changed, 2215 insertions(+) create mode 100644 sys/dev/adb/adb_bus.c create mode 100644 sys/dev/adb/adb_kbd.c create mode 100644 sys/dev/adb/adb_keymap.h create mode 100644 sys/dev/adb/adb_ms.c create mode 100644 sys/dev/adb/adbvar.h create mode 100644 sys/dev/adb/files.adb diff --git a/sys/dev/adb/adb_bus.c b/sys/dev/adb/adb_bus.c new file mode 100644 index 000000000000..2e0c8d95bfab --- /dev/null +++ b/sys/dev/adb/adb_bus.c @@ -0,0 +1,282 @@ +/* $NetBSD: adb_bus.c,v 1.1 2007/01/17 23:20:16 macallan Exp $ */ + +/*- + * Copyright (c) 2006 Michael Lorenz + * 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. + * 3. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: adb_bus.c,v 1.1 2007/01/17 23:20:16 macallan Exp $"); + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "adbdebug.h" + +#ifdef ADB_DEBUG +#define DPRINTF printf +#else +#define DPRINTF while (0) printf +#endif + +static int nadb_match(struct device *, struct cfdata *, void *); +static void nadb_attach(struct device *, struct device *, void *); + +struct nadb_softc { + struct device sc_dev; + struct adb_bus_accessops *sc_ops; + uint32_t sc_msg; + uint32_t sc_event; + struct adb_device sc_devtable[16]; + int sc_free; /* highest free address */ + int sc_len; /* length of received message */ + uint8_t sc_data[16]; +}; + +CFATTACH_DECL(nadb, sizeof(struct nadb_softc), + nadb_match, nadb_attach, NULL, NULL); + +static void nadb_init(struct device *); +static void nadb_handler(void *, int, uint8_t *); +static void nadb_send_sync(void *, int, int, uint8_t *); +static int nadb_register(struct nadb_softc *, int, int, int); +static void nadb_remove(struct nadb_softc *, int); +static int nadb_devprint(void *, const char *); + +static int +nadb_match(struct device *parent, struct cfdata *cf, void *aux) +{ + + return 1; +} + +static void +nadb_attach(struct device *parent, struct device *us, void *aux) +{ + struct nadb_softc *sc = (struct nadb_softc *)us; + struct adb_bus_accessops *ops = aux; + + sc->sc_ops = ops; + sc->sc_ops->set_handler(sc->sc_ops->cookie, nadb_handler, sc); + + config_interrupts(us, nadb_init); +} + +static void +nadb_init(struct device *dev) +{ + struct nadb_softc *sc = (struct nadb_softc *)dev; + struct adb_attach_args aaa; + int i, last_moved_up, devmask = 0; + uint8_t cmd[2]; + + sc->sc_free = 15; + for (i = 0; i < 16; i++) { + sc->sc_devtable[i].original_addr = 0; + sc->sc_devtable[i].current_addr = 0; + sc->sc_devtable[i].handler_id = 0; + sc->sc_devtable[i].cookie = NULL; + sc->sc_devtable[i].handler = NULL; + } + + /* bus reset (?) */ + //nadb_send_sync(sc, 0, 0, NULL); + //delay(200000); + + /* + * scan only addresses 1 - 7 + * if something responds move it to >7 and see if something else is + * there. If not move the previous one back. + * XXX we don't check for collisions if we use up all addresses >7 + */ + for (i = 1; i < 8; i++) { + DPRINTF("\n%d: ", i); + last_moved_up = 0; + nadb_send_sync(sc, ADBTALK(i, 3), 0, NULL); + /* found something? */ + while (sc->sc_len > 2) { + /* something answered, so move it up */ + + DPRINTF("Found a device on address %d\n", i); + cmd[0] = sc->sc_free | 0x60; + cmd[1] = 0xfe; + nadb_send_sync(sc, ADBLISTEN(i, 3), 2, cmd); + + /* see if it really moved */ + nadb_send_sync(sc, ADBTALK(sc->sc_free, 3), 0, NULL); + if (sc->sc_len > 2) { + /* ok */ + DPRINTF("moved it to %d\n", sc->sc_free); + nadb_register(sc, sc->sc_free, i, sc->sc_data[3]); + last_moved_up = sc->sc_free; + sc->sc_free--; + } + /* see if something else is there */ + nadb_send_sync(sc, ADBTALK(i, 3), 0, NULL); + } + if (last_moved_up != 0) { + /* move last one back to original address */ + cmd[0] = i | 0x60; + cmd[1] = 0xfe; + nadb_send_sync(sc, ADBLISTEN(last_moved_up, 3), 2, cmd); + + nadb_send_sync(sc, ADBTALK(i, 3), 0, NULL); + if (sc->sc_len > 2) { + DPRINTF("moved %d back to %d\n", last_moved_up, i); + nadb_remove(sc, last_moved_up); + nadb_register(sc, i, i, sc->sc_data[3]); + sc->sc_free = last_moved_up; + } + } + } + + /* now attach the buggers we've found */ + aaa.ops = sc->sc_ops; + for (i = 0; i < 16; i++) { + if (sc->sc_devtable[i].current_addr != 0) { + DPRINTF("dev: %d %d %02x\n", + sc->sc_devtable[i].current_addr, + sc->sc_devtable[i].original_addr, + sc->sc_devtable[i].handler_id); + aaa.dev = &sc->sc_devtable[i]; + if (config_found(&sc->sc_dev, &aaa, nadb_devprint)) { + devmask |= (1 << i); + } else { + printf(" not configured\n"); + } + } + } + /* now enable autopolling */ + DPRINTF("devmask: %04x\n", devmask); + sc->sc_ops->autopoll(sc->sc_ops->cookie, devmask); +} + +int +nadb_print(void *aux, const char *what) +{ + + printf(": Apple Desktop Bus\n"); + return 0; +} + +static int +nadb_devprint(void *aux, const char *what) +{ + struct adb_attach_args *aaa = aux; + + switch(aaa->dev->original_addr) { + case 2: + printf(": ADB Keyboard"); + break; + case 3: + printf(": ADB relative pointing device"); + break; + default: + printf(": something from address %d:%02x", + aaa->dev->original_addr, + aaa->dev->handler_id); + break; + } + return 0; +} + +static void +nadb_handler(void *cookie, int len, uint8_t *data) +{ + struct nadb_softc *sc = cookie; + struct adb_device *dev; + int addr; + +#ifdef ADB_DEBUG + int i; + printf("adb:"); + for (i = 0; i < len; i++) { + printf(" %02x", data[i]); + } + printf("\n"); +#endif + + addr = data[1] >> 4; + dev = &sc->sc_devtable[addr]; + if ((dev->current_addr != 0) && (dev->handler != NULL)) { + + dev->handler(dev->cookie, len, data); + } else { + sc->sc_msg = 1; + sc->sc_len = len; + memcpy(sc->sc_data, data, len); + wakeup(&sc->sc_event); + } +} + +static void +nadb_send_sync(void *cookie, int command, int len, uint8_t *data) +{ + struct nadb_softc *sc = cookie; + + sc->sc_msg = 0; + sc->sc_ops->send(sc->sc_ops->cookie, 0, command, len, data); + while (sc->sc_msg == 0) { + tsleep(&sc->sc_event, 0, "adb_send", 100); + } +} + +static int +nadb_register(struct nadb_softc *sc, int current, int orig, int handler) +{ + struct adb_device *dev; + + if ((current > 0) && (current < 16)) { + dev = &sc->sc_devtable[current]; + if (dev->current_addr != 0) + /* in use! */ + return -1; + dev->current_addr = current; + dev->original_addr = orig; + dev->handler_id = handler; + return 0; + } + return -1; +} + +static void +nadb_remove(struct nadb_softc *sc, int addr) +{ + + if ((addr > 0) && (addr < 16)) { + sc->sc_devtable[addr].current_addr = 0; + sc->sc_devtable[addr].original_addr = 0; + sc->sc_devtable[addr].handler_id = 0; + } +} diff --git a/sys/dev/adb/adb_kbd.c b/sys/dev/adb/adb_kbd.c new file mode 100644 index 000000000000..0f114665cceb --- /dev/null +++ b/sys/dev/adb/adb_kbd.c @@ -0,0 +1,661 @@ +/* $NetBSD: adb_kbd.c,v 1.1 2007/01/17 23:20:16 macallan Exp $ */ + +/* + * Copyright (C) 1998 Colin Wood + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Colin Wood. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: adb_kbd.c,v 1.1 2007/01/17 23:20:16 macallan Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#define KEYBOARD_ARRAY +#include +#include + +#include +#include + +#include "adbdebug.h" + +struct adbkbd_softc { + struct device sc_dev; + struct adb_device *sc_adbdev; + struct adb_bus_accessops *sc_ops; + struct device *sc_wskbddev; + struct device *sc_wsmousedev; + int sc_leds; + int sc_have_led_control; + int sc_msg_len; + int sc_event; + int sc_poll; + int sc_polled_chars; + int sc_trans[3]; + int sc_capslock; +#ifdef WSDISPLAY_COMPAT_RAWKBD + int sc_rawkbd; +#endif + uint8_t sc_buffer[16]; + uint8_t sc_pollbuf[16]; + uint8_t sc_us; +}; + +/* + * Function declarations. + */ +static int adbkbd_match(struct device *, struct cfdata *, void *); +static void adbkbd_attach(struct device *, struct device *, void *); + +static void adbkbd_initleds(struct adbkbd_softc *); +static void adbkbd_keys(struct adbkbd_softc *, uint8_t, uint8_t); +static inline void adbkbd_key(struct adbkbd_softc *, uint8_t); +static int adbkbd_wait(struct adbkbd_softc *, int); + +/* Driver definition. */ +CFATTACH_DECL(adbkbd, sizeof(struct adbkbd_softc), + adbkbd_match, adbkbd_attach, NULL, NULL); + +extern struct cfdriver akbd_cd; + +static int adbkbd_enable(void *, int); +static int adbkbd_ioctl(void *, u_long, caddr_t, int, struct lwp *); +static void adbkbd_set_leds(void *, int); +static void adbkbd_handler(void *, int, uint8_t *); + +struct wskbd_accessops adbkbd_accessops = { + adbkbd_enable, + adbkbd_set_leds, + adbkbd_ioctl, +}; + +static void adbkbd_cngetc(void *, u_int *, int *); +static void adbkbd_cnpollc(void *, int); + +struct wskbd_consops adbkbd_consops = { + adbkbd_cngetc, + adbkbd_cnpollc, +}; + +struct wskbd_mapdata adbkbd_keymapdata = { + akbd_keydesctab, +#ifdef AKBD_LAYOUT + AKBD_LAYOUT, +#else + KB_US, +#endif +}; + +static int adbkms_enable(void *); +static int adbkms_ioctl(void *, u_long, caddr_t, int, struct lwp *); +static void adbkms_disable(void *); + +const struct wsmouse_accessops adbkms_accessops = { + adbkms_enable, + adbkms_ioctl, + adbkms_disable, +}; + +static int adbkbd_sysctl_button(SYSCTLFN_ARGS); +static void adbkbd_setup_sysctl(struct adbkbd_softc *); + +#ifdef ADBKBD_DEBUG +#define DPRINTF printf +#else +#define DPRINTF while (0) printf +#endif + +static int adbkbd_is_console = 0; +static int adbkbd_console_attached = 0; + +static int +adbkbd_match(parent, cf, aux) + struct device *parent; + struct cfdata *cf; + void *aux; +{ + struct adb_attach_args *aaa = aux; + + if (aaa->dev->original_addr == ADBADDR_KBD) + return 1; + else + return 0; +} + +static void +adbkbd_attach(struct device *parent, struct device *self, void *aux) +{ + struct adbkbd_softc *sc = (struct adbkbd_softc *)self; + struct adb_attach_args *aaa = aux; + short cmd; + struct wskbddev_attach_args a; + struct wsmousedev_attach_args am; + + sc->sc_ops = aaa->ops; + sc->sc_adbdev = aaa->dev; + sc->sc_adbdev->cookie = sc; + sc->sc_adbdev->handler = adbkbd_handler; + sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0); + + sc->sc_leds = 0; /* initially off */ + sc->sc_have_led_control = 0; + sc->sc_msg_len = 0; + sc->sc_poll = 0; + sc->sc_capslock = 0; + sc->sc_trans[1] = 103; /* F11 */ + sc->sc_trans[2] = 111; /* F12 */ + + printf(" addr %d ", sc->sc_adbdev->current_addr); + + switch (sc->sc_adbdev->handler_id) { + case ADB_STDKBD: + printf("standard keyboard\n"); + break; + case ADB_ISOKBD: + printf("standard keyboard (ISO layout)\n"); + break; + case ADB_EXTKBD: + cmd = ADBTALK(sc->sc_adbdev->current_addr, 1); + sc->sc_msg_len = 0; + sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); + adbkbd_wait(sc, 10); + + /* Ignore Logitech MouseMan/Trackman pseudo keyboard */ + /* XXX needs testing */ + if (sc->sc_buffer[2] == 0x9a && sc->sc_buffer[3] == 0x20) { + printf("Mouseman (non-EMP) pseudo keyboard\n"); + return; + } else if (sc->sc_buffer[2] == 0x9a && + sc->sc_buffer[3] == 0x21) { + printf("Trackman (non-EMP) pseudo keyboard\n"); + return; + } else { + printf("extended keyboard\n"); + adbkbd_initleds(sc); + } + break; + case ADB_EXTISOKBD: + printf("extended keyboard (ISO layout)\n"); + adbkbd_initleds(sc); + break; + case ADB_KBDII: + printf("keyboard II\n"); + break; + case ADB_ISOKBDII: + printf("keyboard II (ISO layout)\n"); + break; + case ADB_PBKBD: + printf("PowerBook keyboard\n"); + break; + case ADB_PBISOKBD: + printf("PowerBook keyboard (ISO layout)\n"); + break; + case ADB_ADJKPD: + printf("adjustable keypad\n"); + break; + case ADB_ADJKBD: + printf("adjustable keyboard\n"); + break; + case ADB_ADJISOKBD: + printf("adjustable keyboard (ISO layout)\n"); + break; + case ADB_ADJJAPKBD: + printf("adjustable keyboard (Japanese layout)\n"); + break; + case ADB_PBEXTISOKBD: + printf("PowerBook extended keyboard (ISO layout)\n"); + break; + case ADB_PBEXTJAPKBD: + printf("PowerBook extended keyboard (Japanese layout)\n"); + break; + case ADB_JPKBDII: + printf("keyboard II (Japanese layout)\n"); + break; + case ADB_PBEXTKBD: + printf("PowerBook extended keyboard\n"); + break; + case ADB_DESIGNKBD: + printf("extended keyboard\n"); + adbkbd_initleds(sc); + break; + case ADB_PBJPKBD: + printf("PowerBook keyboard (Japanese layout)\n"); + break; + case ADB_PBG3KBD: + printf("PowerBook G3 keyboard\n"); + break; + case ADB_PBG3JPKBD: + printf("PowerBook G3 keyboard (Japanese layout)\n"); + break; + case ADB_IBOOKKBD: + printf("iBook keyboard\n"); + break; + default: + printf("mapped device (%d)\n", sc->sc_adbdev->handler_id); + break; + } + + if (adbkbd_is_console && (adbkbd_console_attached == 0)) { + wskbd_cnattach(&adbkbd_consops, sc, &adbkbd_keymapdata); + adbkbd_console_attached = 1; + a.console = 1; + } else { + a.console = 0; + } + a.keymap = &adbkbd_keymapdata; + a.accessops = &adbkbd_accessops; + a.accesscookie = sc; + + sc->sc_wskbddev = config_found_ia(self, "wskbddev", &a, wskbddevprint); + + /* attach the mouse device */ + am.accessops = &adbkms_accessops; + am.accesscookie = sc; + sc->sc_wsmousedev = config_found_ia(self, "wsmousedev", &am, wsmousedevprint); + + if (sc->sc_wsmousedev != NULL) + adbkbd_setup_sysctl(sc); +} + +static void +adbkbd_handler(void *cookie, int len, uint8_t *data) +{ + struct adbkbd_softc *sc = cookie; + +#ifdef ADBKBD_DEBUG + int i; + printf("%s: %02x - ", sc->sc_dev.dv_xname, sc->sc_us); + for (i = 0; i < len; i++) { + printf(" %02x", data[i]); + } + printf("\n"); +#endif + if (len >= 2) { + if (data[1] == sc->sc_us) { + adbkbd_keys(sc, data[2], data[3]); + return; + } else { + memcpy(sc->sc_buffer, data, len); + } + sc->sc_msg_len = len; + wakeup(&sc->sc_event); + } else { + DPRINTF("bogus message\n"); + } +} + +static int +adbkbd_wait(struct adbkbd_softc *sc, int timeout) +{ + int cnt = 0; + + if (sc->sc_poll) { + while (sc->sc_msg_len == 0) { + sc->sc_ops->poll(sc->sc_ops->cookie); + } + } else { + while ((sc->sc_msg_len == 0) && (cnt < timeout)) { + tsleep(&sc->sc_event, 0, "adbkbdio", hz); + cnt++; + } + } + return (sc->sc_msg_len > 0); +} + +static void +adbkbd_keys(struct adbkbd_softc *sc, uint8_t k1, uint8_t k2) +{ + /* keyboard event processing */ + DPRINTF("[%02x %02x]", k1, k2); + if (((k1 == k2) && (k1 == 0x7f)) || (k1 == 0x7e)) { + /* power button, handle separately */ +#ifdef ADBKBD_POWER_PANIC + panic("power button pressed"); +#endif + } else { + adbkbd_key(sc, k1); + if (k2 != 0xff) + adbkbd_key(sc, k2); + } +} + +static inline void +adbkbd_key(struct adbkbd_softc *sc, uint8_t k) +{ + + if (sc->sc_poll) { + if (sc->sc_polled_chars >= 16) { + printf("%s: polling buffer is full\n", + sc->sc_dev.dv_xname); + } + sc->sc_pollbuf[sc->sc_polled_chars] = k; + sc->sc_polled_chars++; + return; + } + + /* translate some keys to mouse events */ + if (sc->sc_wsmousedev != NULL) { + if (ADBK_KEYVAL(k) == sc->sc_trans[1]) { + wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 2 : 0, + 0, 0, 0, 0, + WSMOUSE_INPUT_DELTA); + return; + } + if (ADBK_KEYVAL(k) == sc->sc_trans[2]) { + wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 4 : 0, + 0, 0, 0, 0, + WSMOUSE_INPUT_DELTA); + return; + } + } +#ifdef WSDISPLAY_COMPAT_RAWKBD + if (sc->sc_rawkbd) { + char cbuf[2]; + int s; + int j = 0; + int c = keyboard[ADBK_KEYVAL(k)][3] + + if (k & 0x80) + cbuf[j++] = 0xe0; + + cbuf[j++] = (c & 0x7f) | (ADBK_PRESS(k)? 0 : 0x80); + + s = spltty(); + wskbd_rawinput(sc->sc_wskbddev, cbuf, j); + splx(s); + } else { +#endif + + if (ADBK_KEYVAL(k) == 0x39) { + /* caps lock - send up and down */ + if (ADBK_PRESS(k) != sc->sc_capslock) { + sc->sc_capslock = ADBK_PRESS(k); + wskbd_input(sc->sc_wskbddev, + WSCONS_EVENT_KEY_DOWN, 0x39); + wskbd_input(sc->sc_wskbddev, + WSCONS_EVENT_KEY_UP, 0x39); + } + } else { + /* normal event */ + int type; + + type = ADBK_PRESS(k) ? + WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP; + wskbd_input(sc->sc_wskbddev, type, ADBK_KEYVAL(k)); + } +#ifdef WSDISPLAY_COMPAT_RAWKBD + } +#endif +} + +/* + * Set the keyboard LED's. + * + * Automatically translates from ioctl/softc format to the + * actual keyboard register format + */ +static void +adbkbd_set_leds(void *cookie, int leds) +{ + struct adbkbd_softc *sc = cookie; + int aleds; + short cmd; + uint8_t buffer[2]; + + DPRINTF("adbkbd_set_leds: %02x\n", leds); + if ((leds & 0x07) == (sc->sc_leds & 0x07)) + return; + + if (sc->sc_have_led_control) { + + aleds = (~leds & 0x04) | 3; + if (leds & 1) + aleds &= ~2; + if (leds & 2) + aleds &= ~1; + + buffer[0] = 0xff; + buffer[1] = aleds | 0xf8; + + cmd = ADBLISTEN(sc->sc_adbdev->current_addr, 2); + sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 2, buffer); + } + + sc->sc_leds = leds & 7; +} + +static void +adbkbd_initleds(struct adbkbd_softc *sc) +{ + short cmd; + + /* talk R2 */ + cmd = ADBTALK(sc->sc_adbdev->current_addr, 2); + sc->sc_msg_len = 0; + sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); + if (!adbkbd_wait(sc, 10)) { + printf("unable to read LED state\n"); + return; + } + sc->sc_have_led_control = 1; + DPRINTF("have LED control\n"); + return; +} + +static int +adbkbd_enable(void *v, int on) +{ + return 0; +} + +static int +adbkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct lwp *l) +{ + struct adbkbd_softc *sc = (struct adbkbd_softc *) v; + + switch (cmd) { + + case WSKBDIO_GTYPE: + *(int *)data = WSKBD_TYPE_ADB; + return 0; + case WSKBDIO_SETLEDS: + adbkbd_set_leds(sc, *(int *)data); + return 0; + case WSKBDIO_GETLEDS: + *(int *)data = sc->sc_leds; + return 0; +#ifdef WSDISPLAY_COMPAT_RAWKBD + case WSKBDIO_SETMODE: + sc->sc_rawkbd = *(int *)data == WSKBD_RAW; + return 0; +#endif + } + + return EPASSTHROUGH; +} + +int +adbkbd_cnattach() +{ + + adbkbd_is_console = 1; + return 0; +} + +static void +adbkbd_cngetc(void *v, u_int *type, int *data) +{ + struct adbkbd_softc *sc = v; + int key, press, val; + int s; + + s = splhigh(); + + KASSERT(sc->sc_poll); + + DPRINTF("polling..."); + while (sc->sc_polled_chars == 0) { + sc->sc_ops->poll(sc->sc_ops->cookie); + } + DPRINTF(" got one\n"); + splx(s); + + key = sc->sc_pollbuf[0]; + sc->sc_polled_chars--; + memmove(sc->sc_pollbuf, sc->sc_pollbuf + 1, + sc->sc_polled_chars); + + press = ADBK_PRESS(key); + val = ADBK_KEYVAL(key); + + *data = val; + *type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP; +} + +static void +adbkbd_cnpollc(void *v, int on) +{ + struct adbkbd_softc *sc = v; + + sc->sc_poll = on; + if (!on) { + int i; + + /* feed the poll buffer's content to wskbd */ + for (i = 0; i < sc->sc_polled_chars; i++) { + adbkbd_key(sc, sc->sc_pollbuf[i]); + } + sc->sc_polled_chars = 0; + } +} + +/* stuff for the pseudo mouse */ +static int +adbkms_enable(void *v) +{ + return 0; +} + +static int +adbkms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct lwp *l) +{ + + switch (cmd) { + case WSMOUSEIO_GTYPE: + *(u_int *)data = WSMOUSE_TYPE_PSEUDO; + break; + + default: + return (EPASSTHROUGH); + } + return (0); +} + +static void +adbkms_disable(void *v) +{ +} + +static void +adbkbd_setup_sysctl(struct adbkbd_softc *sc) +{ + struct sysctlnode *node, *me; + int ret; + + DPRINTF("%s: sysctl setup\n", sc->sc_dev.dv_xname); + ret = sysctl_createv(NULL, 0, NULL, (const struct sysctlnode **)&me, + CTLFLAG_READWRITE, + CTLTYPE_NODE, sc->sc_dev.dv_xname, NULL, + NULL, 0, NULL, 0, + CTL_MACHDEP, CTL_CREATE, CTL_EOL); + + ret = sysctl_createv(NULL, 0, NULL, + (const struct sysctlnode **)&node, + CTLFLAG_READWRITE | CTLFLAG_OWNDESC | CTLFLAG_IMMEDIATE, + CTLTYPE_INT, "middle", "middle mouse button", adbkbd_sysctl_button, + 1, NULL, 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL); + node->sysctl_data = sc; + + ret = sysctl_createv(NULL, 0, NULL, + (const struct sysctlnode **)&node, + CTLFLAG_READWRITE | CTLFLAG_OWNDESC | CTLFLAG_IMMEDIATE, + CTLTYPE_INT, "right", "right mouse button", adbkbd_sysctl_button, + 2, NULL, 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL); + node->sysctl_data = sc; +} + +static int +adbkbd_sysctl_button(SYSCTLFN_ARGS) +{ + struct sysctlnode node = *rnode; + struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data; + const int *np = newp; + int btn = node.sysctl_idata, reg; + + DPRINTF("adbkbd_sysctl_button %d\n", btn); + node.sysctl_idata = sc->sc_trans[btn]; + reg = sc->sc_trans[btn]; + if (np) { + /* we're asked to write */ + node.sysctl_data = ® + if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { + + sc->sc_trans[btn] = node.sysctl_idata; + return 0; + } + return EINVAL; + } else { + node.sysctl_size = 4; + return (sysctl_lookup(SYSCTLFN_CALL(&node))); + } +} + +SYSCTL_SETUP(sysctl_adbkbdtrans_setup, "adbkbd translator setup") +{ + + sysctl_createv(NULL, 0, NULL, NULL, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "machdep", NULL, + NULL, 0, NULL, 0, + CTL_MACHDEP, CTL_EOL); +} diff --git a/sys/dev/adb/adb_keymap.h b/sys/dev/adb/adb_keymap.h new file mode 100644 index 000000000000..7e67a9070b27 --- /dev/null +++ b/sys/dev/adb/adb_keymap.h @@ -0,0 +1,431 @@ +/* $NetBSD: adb_keymap.h,v 1.1 2007/01/17 23:20:16 macallan Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Juergen Hannken-Illjes. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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. + */ + +/* XXX This list is incomplete. */ + +#define KC(n) KS_KEYCODE(n) + +static const keysym_t akbd_keydesc_us[] = { +/* pos command normal shifted */ + KC(0), KS_a, + KC(1), KS_s, + KC(2), KS_d, + KC(3), KS_f, + KC(4), KS_h, + KC(5), KS_g, + KC(6), KS_z, + KC(7), KS_x, + KC(8), KS_c, + KC(9), KS_v, + KC(10), KS_paragraph, + KC(11), KS_b, + KC(12), KS_q, + KC(13), KS_w, + KC(14), KS_e, + KC(15), KS_r, + KC(16), KS_y, + KC(17), KS_t, + KC(18), KS_1, KS_exclam, + KC(19), KS_2, KS_at, + KC(20), KS_3, KS_numbersign, + KC(21), KS_4, KS_dollar, + KC(22), KS_6, KS_asciicircum, + KC(23), KS_5, KS_percent, + KC(24), KS_equal, KS_plus, + KC(25), KS_9, KS_parenleft, + KC(26), KS_7, KS_ampersand, + KC(27), KS_minus, KS_underscore, + KC(28), KS_8, KS_asterisk, + KC(29), KS_0, KS_parenright, + KC(30), KS_bracketright, KS_braceright, + KC(31), KS_o, + KC(32), KS_u, + KC(33), KS_bracketleft, KS_braceleft, + KC(34), KS_i, + KC(35), KS_p, + KC(36), KS_Return, + KC(37), KS_l, + KC(38), KS_j, + KC(39), KS_apostrophe, KS_quotedbl, + KC(40), KS_k, + KC(41), KS_semicolon, KS_colon, + KC(42), KS_backslash, KS_bar, + KC(43), KS_comma, KS_less, + KC(44), KS_slash, KS_question, + KC(45), KS_n, + KC(46), KS_m, + KC(47), KS_period, KS_greater, + KC(48), KS_Tab, + KC(49), KS_space, + KC(50), KS_grave, KS_asciitilde, + KC(51), KS_Delete, + KC(52), KS_KP_Enter, /* Pretend this is alt-R ? */ + KC(53), KS_Escape, + KC(54), KS_Control_L, + KC(55), KS_Cmd, /* Command */ + KC(56), KS_Shift_L, + KC(57), KS_Caps_Lock, + KC(58), KS_Cmd1, /* Option */ + KC(59), KS_Left, + KC(60), KS_Right, + KC(61), KS_Down, + KC(62), KS_Up, + + KC(65), KS_KP_Decimal, + KC(67), KS_KP_Multiply, + KC(69), KS_KP_Add, + KC(71), KS_Num_Lock, + KC(75), KS_KP_Divide, + KC(76), KS_KP_Enter, + KC(78), KS_KP_Subtract, + + KC(81), KS_KP_Equal, + KC(82), KS_KP_Insert, KS_KP_0, + KC(83), KS_KP_End, KS_KP_1, + KC(84), KS_KP_Down, KS_KP_2, + KC(85), KS_KP_Next, KS_KP_3, + KC(86), KS_KP_Left, KS_KP_4, + KC(87), KS_KP_Begin, KS_KP_5, + KC(88), KS_KP_Right, KS_KP_6, + KC(89), KS_KP_Home, KS_KP_7, + + KC(91), KS_KP_Up, KS_KP_8, + KC(92), KS_KP_Prior, KS_KP_9, + + KC(95), KS_KP_Delete, KS_KP_Decimal, + KC(96), KS_Cmd_Screen4, KS_f5, + KC(97), KS_Cmd_Screen5, KS_f6, + KC(98), KS_Cmd_Screen6, KS_f7, + KC(99), KS_Cmd_Screen2, KS_f3, + KC(100),KS_Cmd_Screen7, KS_f8, + + KC(101),KS_Cmd_Screen8, KS_f9, + + KC(103), KS_f11, + + KC(105), KS_Print_Screen, + KC(106), KS_KP_Enter, + KC(107), KS_Hold_Screen, + + KC(109),KS_Cmd_Screen9, KS_f10, + + KC(111), KS_f12, + + KC(113), KS_Pause, + KC(114), KS_Insert, + KC(115), KS_Home, + KC(116), KS_Prior, + KC(117), KS_Delete, /* BackSpace */ + KC(118),KS_Cmd_Screen3, KS_f4, + KC(119), KS_End, + KC(120),KS_Cmd_Screen1, KS_f2, + KC(121), KS_Next, + KC(122),KS_Cmd_Screen0, KS_f1, + + KC(127), KS_Cmd_Debugger, +}; + +static const keysym_t akbd_keydesc_fr[] = { +/* pos normal shifted altgr shift-altgr */ + KC(0), KS_q, + KC(1), KS_s, KS_S, KS_Ograve, + KC(4), KS_h, KS_H, KS_Igrave, KS_Icircumflex, + KC(6), KS_w, KS_W, KS_less, KS_greater, + KC(8), KS_c, KS_C, KS_copyright, KS_cent, + KC(10), KS_at, KS_numbersign, + KC(11), KS_b, KS_B, KS_ssharp, + KC(12), KS_a, KS_A, KS_ae, KS_AE, + KC(13), KS_z, KS_Z, KS_Acircumflex, KS_Aring, + KC(14), KS_e, KS_E, KS_ecircumflex, KS_Ecircumflex, + KC(15), KS_r, KS_R, KS_registered, /* Euro */ + KC(16), KS_y, KS_Y, KS_Uacute, + KC(18), KS_ampersand, KS_1, KS_voidSymbol, KS_dead_acute, + KC(19), KS_eacute, KS_2, KS_ediaeresis, + KC(20), KS_quotedbl, KS_3, + KC(21), KS_apostrophe, KS_4, KS_braceleft, KS_bracketleft, + KC(22), KS_section, KS_6, KS_paragraph, + KC(23), KS_parenleft, KS_5, KS_braceleft, KS_bracketleft, + KC(24), KS_minus, KS_underscore, KS_braceright, + KC(25), KS_ccedilla, KS_9, KS_Ccedilla, KS_Agrave, + KC(26), KS_egrave, KS_7, KS_guillemotleft,KS_guillemotright, + KC(27), KS_parenright, KS_degree, KS_braceright, KS_bracketright, + KC(28), KS_exclam, KS_8, KS_exclamdown, KS_Ucircumflex, + KC(29), KS_agrave, KS_0, KS_oslash, + KC(30), KS_dollar, KS_asterisk, KS_comma, KS_yen, + KC(33), KS_dead_circumflex, KS_dead_diaeresis,KS_ocircumflex,KS_Ocircumflex, + KC(34), KS_i, KS_I, KS_icircumflex, KS_Icircumflex, + KC(37), KS_l, KS_L, KS_notsign, KS_bar, + KC(38), KS_j, KS_J, KS_Idiaeresis, KS_Igrave, + KC(39), KS_ugrave, KS_percent, KS_Ugrave, + KC(40), KS_k, KS_K, KS_Egrave, KS_Ediaeresis, + KC(41), KS_m, KS_M, KS_mu, KS_Ograve, + KC(42), KS_dead_grave, KS_sterling, KS_at, KS_numbersign, + KC(43), KS_semicolon, KS_period, + KC(44), KS_equal, KS_plus, KS_voidSymbol, KS_plusminus, + KC(45), KS_n, KS_N, KS_dead_tilde, + KC(46), KS_comma, KS_question, KS_voidSymbol, KS_questiondown, + KC(47), KS_colon, KS_slash, KS_division, KS_backslash, + KC(50), KS_less, KS_greater, + KC(52), KS_Alt_R, + KC(55), KS_Meta_L, /* Command */ + KC(58), KS_Mode_switch, KS_Multi_key, /* Option */ +}; + +static const keysym_t akbd_keydesc_fr_nodead[] = { + KC(18), KS_ampersand, KS_1, KS_voidSymbol, KS_acute, + KC(33), KS_asciicircum, KS_diaeresis, KS_ocircumflex, KS_Ocircumflex, + KC(42), KS_grave, KS_sterling, KS_at, KS_numbersign, + KC(45), KS_n, KS_N, KS_asciitilde, +}; + +static const keysym_t akbd_keydesc_jp[] = { +/* pos command normal shifted */ + KC(19), KS_2, KS_quotedbl, + KC(22), KS_6, KS_ampersand, + KC(24), KS_asciicircum, KS_asciitilde, + KC(25), KS_9, KS_parenright, + KC(26), KS_7, KS_apostrophe, + KC(27), KS_minus, KS_equal, + KC(28), KS_8, KS_parenleft, + KC(29), KS_0, + KC(30), KS_bracketleft, KS_braceleft, + KC(33), KS_at, KS_grave, + KC(39), KS_colon, KS_asterisk, + + KC(41), KS_semicolon, KS_plus, + KC(42), KS_bracketright,KS_braceright, + KC(93), KS_backslash, KS_bar, + KC(94), KS_underscore, +}; + +static const keysym_t akbd_keydesc_uk[] = { +/* pos normal shifted altgr shift-altgr */ + KC(10), KS_section, KS_plusminus, + KC(20), KS_3, KS_sterling, KS_numbersign, + KC(52), KS_KP_Enter, + KC(58), KS_Mode_switch, KS_Multi_key, /* Option */ +}; + +static const keysym_t akbd_keydesc_sv[] = { +/* pos normal shifted altgr shift-altgr */ + KC(10), KS_section, KS_degree, + KC(19), KS_2, KS_quotedbl, KS_at, + KC(21), KS_4, KS_dollar, + KC(22), KS_6, KS_ampersand, + KC(24), KS_dead_acute, KS_dead_grave, + KC(25), KS_9, KS_parenright, KS_bracketright, + KC(26), KS_7, KS_slash, KS_braceleft, + KC(27), KS_plus, KS_question, KS_backslash, + KC(28), KS_8, KS_parenleft, KS_bracketleft, + KC(29), KS_0, KS_equal, KS_braceright, + KC(30), KS_dead_diaeresis,KS_dead_circumflex,KS_dead_tilde, + KC(33), KS_aring, + KC(39), KS_adiaeresis, + KC(41), KS_odiaeresis, + KC(42), KS_apostrophe, KS_asterisk, + KC(43), KS_comma, KS_semicolon, + KC(44), KS_minus, KS_underscore, + KC(47), KS_period, KS_colon, + KC(50), KS_less, KS_greater, KS_bar, + KC(58), KS_Mode_switch,KS_Multi_key, +}; + +static const keysym_t akbd_keydesc_sv_nodead[] = { +/* pos normal shifted altgr shift-altgr */ + KC(24), KS_apostrophe, KS_grave, + KC(30), KS_diaeresis, KS_asciicircum, KS_asciitilde, +}; + +static const keysym_t akbd_keydesc_de[] = { +/* pos normal shifted altgr shift-altgr */ + KC(0), KS_a, KS_A, KS_aring, KS_Aring, + KC(1), KS_s, KS_S, KS_voidSymbol, KS_Iacute, + KC(3), KS_f, KS_F, KS_voidSymbol, KS_Idiaeresis, + KC(4), KS_h, KS_H, KS_ordfeminine, KS_Oacute, + KC(5), KS_g, KS_G, KS_copyright, KS_Igrave, + KC(6), KS_y, KS_Y, KS_yen, + KC(7), KS_x, KS_X, KS_voidSymbol, KS_Ugrave, + KC(8), KS_c, KS_C, KS_ccedilla, KS_Ccedilla, + KC(10), KS_dead_circumflex,KS_degree, + KC(12), KS_q, KS_Q, KS_guillemotleft,KS_guillemotright, + KC(15), KS_r, KS_R, KS_registered, KS_cedilla, + KC(16), KS_z, KS_Z, + KC(18), KS_1, KS_exclam, KS_exclamdown, KS_notsign, + KC(19), KS_2, KS_quotedbl, + KC(20), KS_3, KS_section, KS_paragraph, KS_numbersign, + KC(21), KS_4, KS_dollar, KS_cent, KS_sterling, + KC(22), KS_6, KS_ampersand, KS_bracketright,KS_dead_circumflex, + KC(23), KS_5, KS_percent, KS_bracketleft, + KC(24), KS_dead_acute, KS_dead_grave, KS_apostrophe, + KC(25), KS_9, KS_parenright, KS_braceright, KS_periodcentered, + KC(26), KS_7, KS_slash, KS_bar, KS_backslash, + KC(27), KS_ssharp, KS_question, KS_questiondown, + KC(28), KS_8, KS_parenleft, KS_braceleft, + KC(29), KS_0, KS_equal, KS_voidSymbol, KS_macron, + KC(30), KS_plus, KS_asterisk, KS_plusminus, + KC(31), KS_o, KS_O, KS_oslash, KS_Ooblique, + KC(32), KS_u, KS_U, KS_dead_diaeresis,KS_Aacute, + KC(33), KS_udiaeresis, KS_Udiaeresis, KS_voidSymbol, KS_degree, + KC(34), KS_i, KS_I, KS_voidSymbol, KS_Ucircumflex, + KC(37), KS_l, KS_L, KS_at, + KC(38), KS_j, KS_J, KS_masculine, + KC(39), KS_adiaeresis, KS_Adiaeresis, KS_ae, KS_AE, + KC(41), KS_odiaeresis, KS_Odiaeresis, + KC(42), KS_numbersign, KS_apostrophe, + KC(43), KS_comma, KS_semicolon, + KC(44), KS_minus, KS_underscore, + KC(45), KS_n, KS_N, KS_dead_tilde, + KC(46), KS_m, KS_M, KS_mu, + KC(47), KS_period, KS_colon, + KC(50), KS_less, KS_greater, + KC(52), KS_Multi_key, + KC(58), KS_Mode_switch, +}; + +static const keysym_t akbd_keydesc_de_nodead[] = { +/* pos normal shifted altgr shift-altgr */ + KC(10), KS_asciicircum, KS_degree, + KC(22), KS_6, KS_ampersand, KS_bracketright,KS_asciicircum, + KC(24), KS_acute, KS_grave, KS_apostrophe, + KC(32), KS_u, KS_U, KS_diaeresis, KS_Aacute, + KC(45), KS_n, KS_N, KS_asciitilde, +}; + +static const keysym_t akbd_keydesc_sf[] = { +/* pos normal shifted altgr shift-altgr */ + KC(6), KS_y, + KC(10), KS_paragraph, KS_degree, + KC(16), KS_z, + KC(18), KS_plus, KS_1, + KC(19), KS_quotedbl, KS_2, + KC(20), KS_asterisk, KS_3, + KC(21), KS_ccedilla, KS_4, KS_Ccedilla, + KC(22), KS_ampersand, KS_6, + KC(23), KS_percent, KS_5, + KC(24), KS_dead_circumflex,KS_grave, + KC(25), KS_parenright, KS_9, + KC(26), KS_slash, KS_7, + KC(27), KS_apostrophe, KS_question, + KC(28), KS_parenleft, KS_8, + KC(29), KS_equal, KS_0, + KC(30), KS_dead_diaeresis,KS_exclam, + KC(33), KS_egrave, KS_udiaeresis, + KC(39), KS_agrave, KS_adiaeresis, + KC(41), KS_eacute, KS_odiaeresis, + KC(42), KS_dollar, KS_sterling, + KC(43), KS_period, KS_colon, + KC(46), KS_comma, KS_semicolon, + KC(47), KS_minus, KS_underscore, + KC(50), KS_less, KS_greater, +}; + +static const keysym_t akbd_keydesc_es[] = { +/* pos normal shifted altgr shift-altgr */ + KC(10), KS_degree, KS_ordfeminine, KS_backslash, + KC(18), KS_1, KS_exclam, KS_bar, + KC(19), KS_2, KS_quotedbl, KS_at, + KC(20), KS_3, KS_periodcentered, KS_numbersign, + KC(21), KS_4, KS_dollar, KS_asciitilde, + KC(22), KS_6, KS_ampersand, KS_notsign, + KC(23), KS_5, KS_percent, + KC(24), KS_exclamdown, KS_questiondown, + KC(25), KS_9, KS_parenright, + KC(26), KS_7, KS_slash, + KC(27), KS_apostrophe, KS_question, + KC(28), KS_8, KS_parenleft, + KC(29), KS_0, KS_equal, + KC(30), KS_plus, KS_asterisk, KS_bracketright, + KC(33), KS_dead_grave, KS_dead_circumflex, KS_bracketleft, + KC(39), KS_dead_acute, KS_dead_diaeresis, KS_braceleft, + KC(41), KS_ntilde, + KC(42), KS_ccedilla, KS_Ccedilla, KS_braceright, + KC(43), KS_comma, KS_semicolon, + KC(44), KS_minus, KS_underscore, + KC(47), KS_period, KS_colon, + KC(50), KS_less, KS_greater, + KC(55), KS_Alt_L, /* Command */ + KC(58), KS_Mode_switch, KS_Multi_key, /* Option */ +}; + +static const keysym_t akbd_keydesc_pt[] = { +/* pos normal shifted altgr shift-altgr */ + KC(7), KS_x, KS_X, KS_guillemotleft, KS_guillemotright, + KC(10), KS_section, KS_plusminus, + KC(19), KS_2, KS_quotedbl, KS_at, + KC(20), KS_3, KS_numbersign, KS_sterling, + KC(22), KS_6, KS_ampersand, + KC(24), KS_plus, KS_asterisk, + KC(25), KS_9, KS_parenright, KS_bracketright, KS_braceright, + KC(26), KS_7, KS_slash, + KC(27), KS_apostrophe, KS_question, + KC(28), KS_8, KS_parenleft, KS_bracketleft, KS_braceleft, + KC(29), KS_0, KS_equal, + KC(30), KS_dead_acute, KS_dead_grave, + KC(33), KS_masculine, KS_ordfeminine, + KC(39), KS_dead_tilde, KS_dead_circumflex, + KC(41), KS_ccedilla, KS_Ccedilla, + KC(43), KS_comma, KS_semicolon, + KC(44), KS_minus, KS_underscore, + KC(47), KS_period, KS_colon, + KC(50), KS_less, KS_greater, + KC(58), KS_Mode_switch, + KC(81), KS_KP_Equal, +}; + +#define KBD_MAP(name, base, map) \ + { name, base, sizeof(map)/sizeof(keysym_t), map } + +static const struct wscons_keydesc akbd_keydesctab[] = { + KBD_MAP(KB_US, 0, akbd_keydesc_us), + KBD_MAP(KB_FR, KB_US, akbd_keydesc_fr), + KBD_MAP(KB_JP, KB_US, akbd_keydesc_jp), + KBD_MAP(KB_FR | KB_NODEAD, KB_FR, akbd_keydesc_fr_nodead), + KBD_MAP(KB_SF, KB_US, akbd_keydesc_sf), + KBD_MAP(KB_SV, KB_US, akbd_keydesc_sv), + KBD_MAP(KB_SV | KB_NODEAD, KB_SV, akbd_keydesc_sv_nodead), + KBD_MAP(KB_DE, KB_US, akbd_keydesc_de), + KBD_MAP(KB_DE | KB_NODEAD, KB_DE, akbd_keydesc_de_nodead), + KBD_MAP(KB_UK, KB_US, akbd_keydesc_uk), + KBD_MAP(KB_ES, KB_US, akbd_keydesc_es), + KBD_MAP(KB_PT, KB_US, akbd_keydesc_pt), + {0, 0, 0, 0} +}; + +#undef KBD_MAP +#undef KC + diff --git a/sys/dev/adb/adb_ms.c b/sys/dev/adb/adb_ms.c new file mode 100644 index 000000000000..32d753f2a5c8 --- /dev/null +++ b/sys/dev/adb/adb_ms.c @@ -0,0 +1,750 @@ +/* $NetBSD: adb_ms.c,v 1.1 2007/01/17 23:20:16 macallan Exp $ */ + +/* + * Copyright (C) 1998 Colin Wood + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Colin Wood. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: adb_ms.c,v 1.1 2007/01/17 23:20:16 macallan Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include "adbdebug.h" + +#ifdef ADBMS_DEBUG +#define DPRINTF printf +#else +#define DPRINTF while (0) printf +#endif + +/* + * State info, per mouse instance. + */ +struct adbms_softc { + struct device sc_dev; + struct adb_device *sc_adbdev; + struct adb_bus_accessops *sc_ops; + + /* Extended Mouse Protocol info, faked for non-EMP mice */ + u_int8_t sc_class; /* mouse class (mouse, trackball) */ + u_int8_t sc_buttons; /* number of buttons */ + u_int32_t sc_res; /* mouse resolution (dpi) */ + char sc_devid[5]; /* device indentifier */ + uint8_t sc_us; /* cmd to watch for */ + int sc_mb; /* current button state */ + struct device *sc_wsmousedev; + /* helpers for trackpads */ + int sc_down; + /* + * trackpad protocol variant. Known so far: + * 2 buttons - PowerBook 3400, single events on button 3 and 4 indicate + * finger down and up + * 4 buttons - iBook G4, button 6 indicates finger down, button 4 is + * always down + */ + int sc_x, sc_y; + /* buffers */ + int sc_poll; + int sc_msg_len; + int sc_event; + uint8_t sc_buffer[16]; +}; + +/* EMP device classes */ +#define MSCLASS_TABLET 0 +#define MSCLASS_MOUSE 1 +#define MSCLASS_TRACKBALL 2 +#define MSCLASS_TRACKPAD 3 + +/* + * Function declarations. + */ +static int adbms_match(struct device *, struct cfdata *, void *); +static void adbms_attach(struct device *, struct device *, void *); +static void ems_init(struct adbms_softc *); +//static void ms_processevent(adb_event_t *event, struct adbms_softc *); +static void init_trackpad(struct adbms_softc *); +static void adbms_init_mouse(struct adbms_softc *); +static void adbms_init_turbo(struct adbms_softc *); +static void adbms_init_uspeed(struct adbms_softc *); +static void adbms_process_event(struct adbms_softc *, int, uint8_t *); +static int adbms_send_sync(struct adbms_softc *, uint8_t, int, uint8_t *); + +/* Driver definition. */ +CFATTACH_DECL(adbms, sizeof(struct adbms_softc), + adbms_match, adbms_attach, NULL, NULL); + +static int adbms_enable(void *); +static int adbms_ioctl(void *, u_long, caddr_t, int, struct lwp *); +static void adbms_disable(void *); + +/* + * handle tapping the trackpad + * different pads report different button counts and use slightly different + * protocols + */ +static void adbms_mangle_2(struct adbms_softc *, int); +static void adbms_mangle_4(struct adbms_softc *, int); +static void adbms_handler(void *, int, uint8_t *); +static int adbms_wait(struct adbms_softc *, int); + +const struct wsmouse_accessops adbms_accessops = { + adbms_enable, + adbms_ioctl, + adbms_disable, +}; + +static int +adbms_match(struct device *parent, struct cfdata *cf, void *aux) +{ + struct adb_attach_args *aaa = aux; + + if (aaa->dev->original_addr == ADBADDR_MS) + return 1; + else + return 0; +} + +static void +adbms_attach(struct device *parent, struct device *self, void *aux) +{ + struct adbms_softc *sc = (struct adbms_softc *)self; + struct adb_attach_args *aaa = aux; + struct wsmousedev_attach_args a; + + sc->sc_ops = aaa->ops; + sc->sc_adbdev = aaa->dev; + sc->sc_adbdev->cookie = sc; + sc->sc_adbdev->handler = adbms_handler; + sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0); + printf(" addr %d ", sc->sc_adbdev->current_addr); + + sc->sc_class = MSCLASS_MOUSE; + sc->sc_buttons = 1; + sc->sc_res = 100; + sc->sc_devid[0] = 0; + sc->sc_devid[4] = 0; + sc->sc_poll = 0; + sc->sc_msg_len = 0; + + ems_init(sc); + + /* print out the type of mouse we have */ + switch (sc->sc_adbdev->handler_id) { + case ADBMS_100DPI: + printf("%d-button, %d dpi mouse\n", sc->sc_buttons, + (int)(sc->sc_res)); + break; + case ADBMS_200DPI: + sc->sc_res = 200; + printf("%d-button, %d dpi mouse\n", sc->sc_buttons, + (int)(sc->sc_res)); + break; + case ADBMS_MSA3: + printf("Mouse Systems A3 mouse, %d-button, %d dpi\n", + sc->sc_buttons, (int)(sc->sc_res)); + break; + case ADBMS_USPEED: + printf("MicroSpeed mouse, default parameters\n"); + break; + case ADBMS_UCONTOUR: + printf("Contour mouse, default parameters\n"); + break; + case ADBMS_TURBO: + printf("Kensington Turbo Mouse\n"); + break; + case ADBMS_EXTENDED: + if (sc->sc_devid[0] == '\0') { + printf("Logitech "); + switch (sc->sc_class) { + case MSCLASS_MOUSE: + printf("MouseMan (non-EMP) mouse"); + break; + case MSCLASS_TRACKBALL: + printf("TrackMan (non-EMP) trackball"); + break; + default: + printf("non-EMP relative positioning device"); + break; + } + printf("\n"); + } else { + printf("EMP "); + switch (sc->sc_class) { + case MSCLASS_TABLET: + printf("tablet"); + break; + case MSCLASS_MOUSE: + printf("mouse"); + break; + case MSCLASS_TRACKBALL: + printf("trackball"); + break; + case MSCLASS_TRACKPAD: + printf("trackpad"); + init_trackpad(sc); + break; + default: + printf("unknown device"); + break; + } + printf(" <%s> %d-button, %d dpi\n", sc->sc_devid, + sc->sc_buttons, (int)(sc->sc_res)); + } + break; + default: + printf("relative positioning device (mouse?) (%d)\n", + sc->sc_adbdev->handler_id); + break; + } + + a.accessops = &adbms_accessops; + a.accesscookie = sc; + sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); +} + + +/* + * Initialize extended mouse support -- probes devices as described + * in Inside Macintosh: Devices, Chapter 5 "ADB Manager". + * + * Extended Mouse Protocol is documented in TechNote HW1: + * "ADB - The Untold Story: Space Aliens Ate My Mouse" + * + * Supports: Extended Mouse Protocol, MicroSpeed Mouse Deluxe, + * Mouse Systems A^3 Mouse, Logitech non-EMP MouseMan + */ +void +ems_init(struct adbms_softc *sc) +{ + + DPRINTF("ems_init %d\n", sc->sc_adbdev->handler_id); + + switch (sc->sc_adbdev->handler_id) { + case ADBMS_USPEED: + case ADBMS_UCONTOUR: + adbms_init_uspeed(sc); + return; + case ADBMS_TURBO: + adbms_init_turbo(sc); + return; + case ADBMS_100DPI: + case ADBMS_200DPI: + adbms_init_mouse(sc); + } +} + +static void +adbms_init_uspeed(struct adbms_softc *sc) +{ + uint8_t cmd, addr, buffer[4]; + + addr = sc->sc_adbdev->current_addr; + + /* Found MicroSpeed Mouse Deluxe Mac or Contour Mouse */ + cmd = ADBLISTEN(addr, 1); + + /* + * To setup the MicroSpeed or the Contour, it appears + * that we can send the following command to the mouse + * and then expect data back in the form: + * buffer[0] = 4 (bytes) + * buffer[1], buffer[2] as std. mouse + * buffer[3] = buffer[4] = 0xff when no buttons + * are down. When button N down, bit N is clear. + * buffer[4]'s locking mask enables a + * click to toggle the button down state--sort of + * like the "Easy Access" shift/control/etc. keys. + * buffer[3]'s alternative speed mask enables using + * different speed when the corr. button is down + */ + buffer[0] = 0x00; /* Alternative speed */ + buffer[1] = 0x00; /* speed = maximum */ + buffer[2] = 0x10; /* enable extended protocol, + * lower bits = alt. speed mask + * = 0000b + */ + buffer[3] = 0x07; /* Locking mask = 0000b, + * enable buttons = 0111b + */ + adbms_send_sync(sc, cmd, 4, buffer); + + sc->sc_buttons = 3; + sc->sc_res = 200; +} + +static void +adbms_init_turbo(struct adbms_softc *sc) +{ + uint8_t addr; + + /* Found Kensington Turbo Mouse */ + static u_char data1[] = + { 0xe7, 0x8c, 0, 0, 0, 0xff, 0xff, 0x94 }; + static u_char data2[] = + { 0xa5, 0x14, 0, 0, 0x69, 0xff, 0xff, 0x27 }; + + addr = sc->sc_adbdev->current_addr; + + adbms_send_sync(sc, ADBFLUSH(addr), 0, NULL); + adbms_send_sync(sc, ADBLISTEN(addr, 2), 8, data1); + adbms_send_sync(sc, ADBFLUSH(addr), 0, NULL); + adbms_send_sync(sc, ADBLISTEN(addr, 2), 8, data2); +} + +static void +adbms_init_mouse(struct adbms_softc *sc) +{ + int len; + uint8_t cmd, addr, buffer[16]; + + addr = sc->sc_adbdev->current_addr; + /* found a mouse */ + cmd = ADBTALK(addr, 3); + if (!adbms_send_sync(sc, cmd, 0, NULL)) { +#ifdef ADBMS_DEBUG + printf("adb: ems_init timed out\n"); +#endif + return; + } + + /* Attempt to initialize Extended Mouse Protocol */ + len = sc->sc_msg_len; + memcpy(buffer, sc->sc_buffer, len); + DPRINTF("buffer: %02x %02x\n", buffer[0], buffer[1]); + buffer[1] = 4; /* make handler ID 4 */ + cmd = ADBLISTEN(addr, 3); + if (!adbms_send_sync(sc, cmd, len, buffer)) { +#ifdef ADBMS_DEBUG + printf("adb: ems_init timed out\n"); +#endif + return; + } + + /* + * Check to see if successful, if not + * try to initialize it as other types + */ + cmd = ADBTALK(addr, 3); + if (!adbms_send_sync(sc, cmd, 0, NULL)) { + DPRINTF("timeout checking for EMP switch\n"); + return; + } + DPRINTF("new handler ID: %02x\n", sc->sc_buffer[1]); + if (sc->sc_buffer[1] == ADBMS_EXTENDED) { + sc->sc_adbdev->handler_id = ADBMS_EXTENDED; + cmd = ADBTALK(addr, 1); + if(!adbms_send_sync(sc, cmd, 0, NULL)) { + DPRINTF("adb: ems_init timed out\n"); + return; + } + + len = sc->sc_msg_len; + memcpy(buffer, sc->sc_buffer, len); + + if (sc->sc_msg_len == 8) { + /* we have a true EMP device */ +#ifdef ADB_PRINT_EMP + + printf("EMP: %02x %02x %02x %02x %02x %02x %02x %02x\n", + buffer[0], buffer[1], buffer[2], buffer[3], + buffer[4], buffer[5], buffer[6], buffer[7]); +#endif + sc->sc_class = buffer[6]; + sc->sc_buttons = buffer[7]; + sc->sc_res = (int)*(short *)&buffer[4]; + memcpy(sc->sc_devid, &(buffer[0]), 4); + } else if (buffer[0] == 0x9a && + ((buffer[1] == 0x20) || (buffer[1] == 0x21))) { + /* + * Set up non-EMP Mouseman/Trackman to put + * button bits in 3rd byte instead of sending + * via pseudo keyboard device. + */ + if (buffer[1] == 0x21) + sc->sc_class = MSCLASS_TRACKBALL; + else + sc->sc_class = MSCLASS_MOUSE; + + cmd = ADBLISTEN(addr, 1); + buffer[0]=0x00; + buffer[1]=0x81; + adbms_send_sync(sc, cmd, 2, buffer); + + cmd = ADBLISTEN(addr, 1); + buffer[0]=0x01; + buffer[1]=0x81; + adbms_send_sync(sc, cmd, 2, buffer); + + cmd = ADBLISTEN(addr, 1); + buffer[0]=0x02; + buffer[1]=0x81; + adbms_send_sync(sc, cmd, 2, buffer); + + cmd = ADBLISTEN(addr, 1); + buffer[0]=0x03; + buffer[1]=0x38; + adbms_send_sync(sc, cmd, 2, buffer); + + sc->sc_buttons = 3; + sc->sc_res = 400; + } + } else { + /* Attempt to initialize as an A3 mouse */ + buffer[1] = 0x03; /* make handler ID 3 */ + cmd = ADBLISTEN(addr, 3); + if (!adbms_send_sync(sc, cmd, len, buffer)) { +#ifdef ADBMS_DEBUG + printf("adb: ems_init timed out\n"); +#endif + return; + } + + /* + * Check to see if successful, if not + * try to initialize it as other types + */ + cmd = ADBTALK(addr, 3); + if(adbms_send_sync(sc, cmd, 0, NULL)) { + len = sc->sc_msg_len; + memcpy(buffer, sc->sc_buffer, len); + if (buffer[1] == ADBMS_MSA3) { + sc->sc_adbdev->handler_id = ADBMS_MSA3; + /* Initialize as above */ + cmd = ADBLISTEN(addr, 2); + /* listen 2 */ + buffer[0] = 0x00; + /* Irrelevant, buffer has 0x77 */ + buffer[2] = 0x07; + /* + * enable 3 button mode = 0111b, + * speed = normal + */ + adbms_send_sync(sc, cmd, 3, buffer); + sc->sc_buttons = 3; + sc->sc_res = 300; + } + } + } +} + +static void +adbms_handler(void *cookie, int len, uint8_t *data) +{ + struct adbms_softc *sc = cookie; + +#ifdef ADBMS_DEBUG + int i; + printf("%s: %02x - ", sc->sc_dev.dv_xname, sc->sc_us); + for (i = 0; i < len; i++) { + printf(" %02x", data[i]); + } + printf("\n"); +#endif + if (len >= 2) { + memcpy(sc->sc_buffer, &data[2], len - 2); + sc->sc_msg_len = len - 2; + if (data[1] == sc->sc_us) { + /* make sense of the mouse message */ + adbms_process_event(sc, sc->sc_msg_len, sc->sc_buffer); + return; + } + wakeup(&sc->sc_event); + } else { + DPRINTF("bogus message\n"); + } +} + +static void +adbms_process_event(struct adbms_softc *sc, int len, uint8_t *buffer) +{ + int buttons = 0, mask, dx, dy, i; + int button_bit = 1; + + if ((sc->sc_adbdev->handler_id == ADBMS_EXTENDED) && (sc->sc_devid[0] == 0)) { + /* massage the data to look like EMP data */ + if ((buffer[2] & 0x04) == 0x04) + buffer[0] &= 0x7f; + else + buffer[0] |= 0x80; + if ((buffer[2] & 0x02) == 0x02) + buffer[1] &= 0x7f; + else + buffer[1] |= 0x80; + if ((buffer[2] & 0x01) == 0x01) + buffer[2] = 0x00; + else + buffer[2] = 0x80; + } + + switch (sc->sc_adbdev->handler_id) { + case ADBMS_USPEED: + case ADBMS_UCONTOUR: + /* MicroSpeed mouse and Contour mouse */ + if (len == 4) + buttons = (~buffer[3]) & 0xff; + else + buttons = (buffer[1] & 0x80) ? 0 : 1; + break; + case ADBMS_MSA3: + /* Mouse Systems A3 mouse */ + if (len == 3) + buttons = (~buffer[2]) & 0x07; + else + buttons = (buffer[0] & 0x80) ? 0 : 1; + break; + default: + /* Classic Mouse Protocol (up to 2 buttons) */ + for (i = 0; i < 2; i++, button_bit <<= 1) + /* 0 when button down */ + if (!(buffer[i] & 0x80)) + buttons |= button_bit; + else + buttons &= ~button_bit; + /* Extended Protocol (up to 6 more buttons) */ + for (mask = 0x80; i < len; + i += (mask == 0x80), button_bit <<= 1) { + /* 0 when button down */ + if (!(buffer[i] & mask)) + buttons |= button_bit; + else + buttons &= ~button_bit; + mask = ((mask >> 4) & 0xf) + | ((mask & 0xf) << 4); + } + break; + } + + dx = ((int)(buffer[1] & 0x3f)) - ((buffer[1] & 0x40) ? 64 : 0); + dy = ((int)(buffer[0] & 0x3f)) - ((buffer[0] & 0x40) ? 64 : 0); + + if (sc->sc_class == MSCLASS_TRACKPAD) { + + if (sc->sc_down) { + /* finger is down - collect motion data */ + sc->sc_x += dx; + sc->sc_y += dy; + } + DPRINTF("buttons: %02x\n", buttons); + switch (sc->sc_buttons) { + case 2: + buttons |= ((buttons & 2) >> 1); + adbms_mangle_2(sc, buttons); + break; + case 4: + adbms_mangle_4(sc, buttons); + break; + } + /* filter the pseudo-buttons out */ + buttons &= 1; + } + + if (sc->sc_wsmousedev) + wsmouse_input(sc->sc_wsmousedev, sc->sc_mb | buttons, + dx, -dy, 0, 0, + WSMOUSE_INPUT_DELTA); +#if NAED > 0 + aed_input(&new_event); +#endif +} + +static void +adbms_mangle_2(struct adbms_softc *sc, int buttons) +{ + + if (buttons & 4) { + /* finger down on pad */ + if (sc->sc_down == 0) { + sc->sc_down = 1; + sc->sc_x = 0; + sc->sc_y = 0; + } + } + if (buttons & 8) { + /* finger up */ + if (sc->sc_down) { + if (((sc->sc_x * sc->sc_x + + sc->sc_y * sc->sc_y) < 20) && + (sc->sc_wsmousedev)) { + /* + * if there wasn't much movement between + * finger down and up again we assume + * someone tapped the pad and we just + * send a mouse button event + */ + wsmouse_input(sc->sc_wsmousedev, + 1, 0, 0, 0, 0, WSMOUSE_INPUT_DELTA); + } + sc->sc_down = 0; + } + } +} + +static void +adbms_mangle_4(struct adbms_softc *sc, int buttons) +{ + + if (buttons & 0x20) { + /* finger down on pad */ + if (sc->sc_down == 0) { + sc->sc_down = 1; + sc->sc_x = 0; + sc->sc_y = 0; + } + } + if ((buttons & 0x20) == 0) { + /* finger up */ + if (sc->sc_down) { + if (((sc->sc_x * sc->sc_x + + sc->sc_y * sc->sc_y) < 20) && + (sc->sc_wsmousedev)) { + /* + * if there wasn't much movement between + * finger down and up again we assume + * someone tapped the pad and we just + * send a mouse button event + */ + wsmouse_input(sc->sc_wsmousedev, + 1, 0, 0, 0, 0, WSMOUSE_INPUT_DELTA); + } + sc->sc_down = 0; + } + } +} + +static int +adbms_enable(void *v) +{ + return 0; +} + +static int +adbms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct lwp *l) +{ + + switch (cmd) { + case WSMOUSEIO_GTYPE: + *(u_int *)data = WSMOUSE_TYPE_ADB; + break; + + default: + return (EPASSTHROUGH); + } + return (0); +} + +static void +adbms_disable(void *v) +{ +} + +static void +init_trackpad(struct adbms_softc *sc) +{ + int cmd, addr; + uint8_t buffer[16]; + uint8_t b2[] = {0x99, 0x94, 0x19, 0xff, 0xb2, 0x8a, 0x1b, 0x50}; + + addr = sc->sc_adbdev->current_addr; + cmd = ADBTALK(addr, 1); + if (!adbms_send_sync(sc, cmd, 0, NULL)) + return; + + if (sc->sc_msg_len != 8) + return; + + memcpy(buffer, sc->sc_buffer, 8); + + /* now whack the pad */ + cmd = ADBLISTEN(addr, 1); + buffer[6] = 0x0d; + adbms_send_sync(sc, cmd, 8, buffer); + + delay(1000); + cmd = ADBLISTEN(addr, 2); + adbms_send_sync(sc, cmd, 8, b2); + + delay(1000); + cmd = ADBLISTEN(addr, 1); + buffer[6] = 0x03; + adbms_send_sync(sc, cmd, 8, buffer); + + cmd = ADBFLUSH(addr); + adbms_send_sync(sc, cmd, 0, NULL); + delay(1000); +} + +static int +adbms_wait(struct adbms_softc *sc, int timeout) +{ + int cnt = 0; + + if (sc->sc_poll) { + while (sc->sc_msg_len == -1) { + sc->sc_ops->poll(sc->sc_ops->cookie); + } + } else { + while ((sc->sc_msg_len == -1) && (cnt < timeout)) { + tsleep(&sc->sc_event, 0, "adbkbdio", hz); + cnt++; + } + } + return (sc->sc_msg_len > 0); +} + +static int +adbms_send_sync(struct adbms_softc *sc, uint8_t cmd, int len, uint8_t *msg) +{ + int i; + + sc->sc_msg_len = -1; + DPRINTF("send: %02x", cmd); + for (i = 0; i < len; i++) + DPRINTF(" %02x", msg[i]); + DPRINTF("\n"); + sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, len, msg); + adbms_wait(sc, 1000); + return (sc->sc_msg_len != -1); +} diff --git a/sys/dev/adb/adbvar.h b/sys/dev/adb/adbvar.h new file mode 100644 index 000000000000..7c731c41b3e2 --- /dev/null +++ b/sys/dev/adb/adbvar.h @@ -0,0 +1,68 @@ +/* $NetBSD: adbvar.h,v 1.1 2007/01/17 23:20:16 macallan Exp $ */ + +/*- + * Copyright (c) 2006 Michael Lorenz + * 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. + * 3. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: adbvar.h,v 1.1 2007/01/17 23:20:16 macallan Exp $"); + +#ifndef ADBVAR_H +#define ADBVAR_H + +#define ADB_CMDADDR(cmd) ((u_int8_t)((cmd) & 0xf0) >> 4) +#define ADBFLUSH(dev) ((((u_int8_t)(dev) & 0x0f) << 4) | 0x01) +#define ADBLISTEN(dev, reg) ((((u_int8_t)(dev) & 0x0f) << 4) | 0x08 | (reg)) +#define ADBTALK(dev, reg) ((((u_int8_t)(dev) & 0x0f) << 4) | 0x0c | (reg)) + +struct adb_bus_accessops { + void *cookie; + /* cookie, poll, address/command, length, data */ + int (*send)(void *, int, int, int, uint8_t *); + void (*poll)(void *); + void (*autopoll)(void *, int); /* bitmask of ADB addresses to poll */ + int (*set_handler)(void *, void (*)(void *, int, uint8_t *), void *); +}; + +struct adb_device { + void *cookie; + void (*handler)(void *, int, uint8_t *); + int current_addr; + int original_addr; + int handler_id; +}; + +struct adb_attach_args { + struct adb_bus_accessops *ops; + struct adb_device *dev; +}; + +int nadb_print(void *, const char *); + + +#endif /* ADBVAR_H */ diff --git a/sys/dev/adb/files.adb b/sys/dev/adb/files.adb new file mode 100644 index 000000000000..61fc8ef24ed2 --- /dev/null +++ b/sys/dev/adb/files.adb @@ -0,0 +1,23 @@ +# +# $NetBSD: files.adb,v 1.1 2007/01/17 23:20:16 macallan Exp $ +# +# Apple Desktop Bus protocol and drivers + +defflag adbdebug.h ADB_DEBUG +defflag adbdebug.h ADBKBD_DEBUG +defflag adbdebug.h ADBMS_DEBUG +defflag adbdebug.h ADBKBD_POWER_PANIC + +define adb_bus {} + +device nadb {} +attach nadb at adb_bus +file dev/adb/adb_bus.c nadb needs-flag + +device adbkbd : wskbddev, wsmousedev +attach adbkbd at nadb +file dev/adb/adb_kbd.c adbkbd needs-flag + +device adbms : wsmousedev +attach adbms at nadb +file dev/adb/adb_ms.c adbms needs-flag