diff options
author | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2007-07-27 16:52:25 +0000 |
---|---|---|
committer | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2007-07-27 16:52:25 +0000 |
commit | 618f49663432f1402262847be95ee45f6db23714 (patch) | |
tree | a1ac1ca1171d7d0c9139a97b34582aa392b0d44b /sys/dev | |
parent | 1c7596550822f967b125e358751560622173b1f7 (diff) |
Commiting for xsa@ who dosent want to for some reason. He has KNFed and
de-proplibed some of the netbsd bluetooth drives for HID devices
(mice and keyboards) they will however NOT BUILD YET as they lack the
glue device bthidev and our replacement for the problib.
no objections from uwe
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/bluetooth/btdev.h | 58 | ||||
-rw-r--r-- | sys/dev/bluetooth/bthid.h | 90 | ||||
-rw-r--r-- | sys/dev/bluetooth/bthidev.h | 77 | ||||
-rw-r--r-- | sys/dev/bluetooth/btkbd.c | 562 | ||||
-rw-r--r-- | sys/dev/bluetooth/btms.c | 317 |
5 files changed, 1104 insertions, 0 deletions
diff --git a/sys/dev/bluetooth/btdev.h b/sys/dev/bluetooth/btdev.h new file mode 100644 index 00000000000..bd9e0551db2 --- /dev/null +++ b/sys/dev/bluetooth/btdev.h @@ -0,0 +1,58 @@ +/* $NetBSD: btdev.h,v 1.6 2007/04/21 06:15:22 plunky Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Iain Hibbert for Itronix Inc. + * + * 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. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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. + */ + +#ifndef _DEV_BLUETOOTH_BTDEV_H_ +#define _DEV_BLUETOOTH_BTDEV_H_ + +/* btdev attach/detach ioctl's */ +#define BTDEV_ATTACH _IOW('b', 14, struct plistref) +#define BTDEV_DETACH _IOW('b', 15, struct plistref) + +/* btdev properties */ +#define BTDEVtype "device-type" +#define BTDEVladdr "local-bdaddr" +#define BTDEVraddr "remote-bdaddr" +#define BTDEVservice "service-name" +#define BTDEVmode "link-mode" +#define BTDEVauth "auth" +#define BTDEVencrypt "encrypt" +#define BTDEVsecure "secure" + +#ifdef _KERNEL +struct btdev { + struct device sc_dev; + LIST_ENTRY(btdev) sc_next; +}; +#endif /* _KERNEL */ + +#endif /* _DEV_BLUETOOTH_BTDEV_H_ */ diff --git a/sys/dev/bluetooth/bthid.h b/sys/dev/bluetooth/bthid.h new file mode 100644 index 00000000000..0b0e2046280 --- /dev/null +++ b/sys/dev/bluetooth/bthid.h @@ -0,0 +1,90 @@ +/* $OpenBSD: bthid.h,v 1.1 2007/07/27 16:52:24 gwk Exp $ */ +/* $NetBSD: bthid.h,v 1.1 2006/06/19 15:44:45 gdamore Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Iain Hibbert for Itronix Inc. + * + * 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. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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. + */ + +#ifndef _DEV_BLUETOOTH_BTHID_H_ +#define _DEV_BLUETOOTH_BTHID_H_ + +/* Transaction Types */ +#define BTHID_HANDSHAKE 0x0 +#define BTHID_CONTROL 0x1 +#define BTHID_GET_REPORT 0x4 +#define BTHID_SET_REPORT 0x5 +#define BTHID_GET_PROTOCOL 0x6 +#define BTHID_SET_PROTOCOL 0x7 +#define BTHID_GET_IDLE 0x8 +#define BTHID_SET_IDLE 0x9 +#define BTHID_DATA 0xa +#define BTHID_DATC 0xb + +#define BTHID_TYPE(b) (((b) & 0xf0) >> 4) + +/* HANDSHAKE Transaction Parameters */ +#define BTHID_HANDSHAKE_SUCCESS 0x0 +#define BTHID_HANDSHAKE_NOT_READY 0x1 +#define BTHID_HANDSHAKE_INVALID_ID 0x2 +#define BTHID_HANDSHAKE_UNSUPPORTED 0x3 +#define BTHID_HANDSHAKE_INVALID_PARAM 0x4 +#define BTHID_HANDSHAKE_UNKNOWN 0xe +#define BTHID_HANDSHAKE_FATAL 0xf + +#define BTHID_HANDSHAKE_PARAM(b) ((b) & 0x0f) + +/* HID_CONTROL Transaction Parameters */ +#define BTHID_CONTROL_NOP 0x0 +#define BTHID_CONTROL_HARD_RESET 0x1 +#define BTHID_CONTROL_SOFT_RESET 0x2 +#define BTHID_CONTROL_SUSPEND 0x3 +#define BTHID_CONTROL_RESUME 0x4 +#define BTHID_CONTROL_UNPLUG 0x5 + +#define BTHID_CONTROL_PARAM(b) ((b) & 0x0f) + +/* GET_REPORT Transaction Parameters */ +#define BTHID_CONTROL_SIZE 0x08 + +/* GET_PROTOCOL Transaction Parameters */ +#define BTHID_PROTOCOL_REPORT 0 +#define BTHID_PROTOCOL_BOOT 1 + +#define BTHID_PROTOCOL_PARAM(b) ((b) & 0x01) + +/* DATA, DATC Transaction Parameters */ +#define BTHID_DATA_OTHER 0 +#define BTHID_DATA_INPUT 1 +#define BTHID_DATA_OUTPUT 2 +#define BTHID_DATA_FEATURE 3 + +#define BTHID_DATA_PARAM(b) ((b) & 0x03) + +#endif /* _DEV_BLUETOOTH_BTHID_H_ */ diff --git a/sys/dev/bluetooth/bthidev.h b/sys/dev/bluetooth/bthidev.h new file mode 100644 index 00000000000..15fa38ab672 --- /dev/null +++ b/sys/dev/bluetooth/bthidev.h @@ -0,0 +1,77 @@ +/* $OpenBSD: bthidev.h,v 1.1 2007/07/27 16:52:24 gwk Exp $ */ +/* $NetBSD: bthidev.h,v 1.3 2006/09/10 15:45:56 plunky Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Iain Hibbert for Itronix Inc. + * + * 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. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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. + */ + +#ifndef _DEV_BLUETOOTH_BTHIDEV_H_ +#define _DEV_BLUETOOTH_BTHIDEV_H_ + +/* bthidev(4) properties */ +#define BTHIDEVcontrolpsm "control-psm" +#define BTHIDEVinterruptpsm "interrupt-psm" +#define BTHIDEVdescriptor "descriptor" +#define BTHIDEVreconnect "reconnect" + +#ifdef _KERNEL +/* HID device header */ +struct bthidev { + struct device sc_dev; + struct device *sc_parent; + + int sc_id; /* report id */ + int sc_len; /* report len */ + + void (*sc_input) /* input method */ + (struct bthidev *, uint8_t *, int); + + void (*sc_feature) /* feature method */ + (struct bthidev *, uint8_t *, int); + + LIST_ENTRY(bthidev) sc_next; +}; + +/* HID device attach arguments */ +struct bthidev_attach_args { + const void *ba_desc; /* descriptor */ + int ba_dlen; /* descriptor length */ + int ba_id; /* report id */ + + void (*ba_input) /* input method */ + (struct bthidev *, uint8_t *, int); + void (*ba_feature) /* feature method */ + (struct bthidev *, uint8_t *, int); + int (*ba_output) /* output method */ + (struct bthidev *, uint8_t *, int); +}; +#endif /* _KERNEL */ + +#endif /* _DEV_BLUETOOTH_BTHIDEV_H_ */ diff --git a/sys/dev/bluetooth/btkbd.c b/sys/dev/bluetooth/btkbd.c new file mode 100644 index 00000000000..cd5958a2d86 --- /dev/null +++ b/sys/dev/bluetooth/btkbd.c @@ -0,0 +1,562 @@ +/* $OpenBSD: btkbd.c,v 1.1 2007/07/27 16:52:24 gwk Exp $ */ +/* $NetBSD: btkbd.c,v 1.7 2007/07/09 21:00:31 ad Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Iain Hibbert for Itronix Inc. + * + * 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. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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. + */ + +/* + * based on dev/usb/ukbd.c + */ + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/systm.h> + +#include <netbt/bluetooth.h> + +#include <dev/bluetooth/bthid.h> +#include <dev/bluetooth/bthidev.h> + +#include <dev/usb/hid.h> +#include <dev/usb/usb.h> +#include <dev/usb/usbhid.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wskbdvar.h> +#include <dev/wscons/wsksymdef.h> +#include <dev/wscons/wsksymvar.h> + +#define MAXKEYCODE 6 +#define MAXMOD 8 /* max 32 */ +#define MAXKEYS (MAXMOD + (2 * MAXKEYCODE)) + +struct btkbd_data { + uint32_t modifiers; + uint8_t keycode[MAXKEYCODE]; +}; + +struct btkbd_mod { + uint32_t mask; + uint8_t key; +}; + +struct btkbd_softc { + struct bthidev sc_hidev; /* device+ */ + struct device *sc_wskbd; /* child */ + int sc_enabled; + + int (*sc_output) /* output method */ + (struct bthidev *, uint8_t *, int); + + /* stored data */ + struct btkbd_data sc_odata; + struct btkbd_data sc_ndata; + + /* input reports */ + int sc_nmod; + struct hid_location sc_modloc[MAXMOD]; + struct btkbd_mod sc_mods[MAXMOD]; + + int sc_nkeycode; + struct hid_location sc_keycodeloc; + + /* output reports */ + struct hid_location sc_numloc; + struct hid_location sc_capsloc; + struct hid_location sc_scroloc; + int sc_leds; + +#ifdef WSDISPLAY_COMPAT_RAWKBD + int sc_rawkbd; +#ifdef BTKBD_REPEAT + struct timeout sc_repeat; + int sc_nrep; + char sc_rep[MAXKEYS]; +#endif +#endif +}; + +int btkbd_match(struct device *, struct cfdata *, void *); +void btkbd_attach(struct device *, struct device *, void *); +int btkbd_detach(struct device *, int); + +struct cfdriver btkbd_cd = { + NULL, "btkbd", DV_DULL +}; + +const struct cfattach btkbd_ca = { + sizeof(struct btkbd_softc), + btkbd_match, + btkbd_attach, + btkbd_detach, +}; + +int btkbd_enable(void *, int); +void btkbd_set_leds(void *, int); +int btkbd_ioctl(void *, unsigned long, void *, int, struct lwp *); + +const struct wskbd_accessops btkbd_accessops = { + btkbd_enable, + btkbd_set_leds, + btkbd_ioctl +}; + +/* wskbd(4) keymap data */ +extern const struct wscons_keydesc ukbd_keydesctab[]; + +const struct wskbd_mapdata btkbd_keymapdata = { + ukbd_keydesctab, +#if defined(BTKBD_LAYOUT) + BTKBD_LAYOUT, +#elif defined(PCKBD_LAYOUT) + PCKBD_LAYOUT, +#else + KB_US, +#endif +}; + +/* bthid methods */ +void btkbd_input(struct bthidev *, uint8_t *, int); + +/* internal prototypes */ +const char *btkbd_parse_desc(struct btkbd_softc *, int, const void *, int); + +#ifdef WSDISPLAY_COMPAT_RAWKBD +#ifdef BTKBD_REPEAT +void btkbd_repeat(void *); +#endif +#endif + + +int +btkbd_match(struct device *self, struct cfdata *cfdata, void *aux) +{ + struct bthidev_attach_args *ba = aux; + + if (hid_is_collection(ba->ba_desc, ba->ba_dlen, ba->ba_id, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) + return 1; + + return 0; +} + +void +btkbd_attach(struct device *parent, struct device *self, void *aux) +{ + struct btkbd_softc *sc = (struct btkbd_softc *)self; + struct bthidev_attach_args *ba = aux; + struct wskbddev_attach_args wska; + const char *parserr; + + sc->sc_output = ba->ba_output; + ba->ba_input = btkbd_input; + + parserr = btkbd_parse_desc(sc, ba->ba_id, ba->ba_desc, ba->ba_dlen); + if (parserr != NULL) { + printf("%s\n", parserr); + return; + } + + printf("\n"); + +#ifdef WSDISPLAY_COMPAT_RAWKBD +#ifdef BTKBD_REPEAT + timeout_set(&sc->sc_repeat, NULL, NULL); + /* callout_setfunc(&sc->sc_repeat, btkbd_repeat, sc); */ +#endif +#endif + + wska.console = 0; + wska.keymap = &btkbd_keymapdata; + wska.accessops = &btkbd_accessops; + wska.accesscookie = sc; + + sc->sc_wskbd = config_found((struct device *)sc, &wska, wskbddevprint); +} + +int +btkbd_detach(struct device *self, int flags) +{ + struct btkbd_softc *sc = (struct btkbd_softc *)self; + int err = 0; + +#ifdef WSDISPLAY_COMPAT_RAWKBD +#ifdef BTKBD_REPEAT + timeout_del(&sc->sc_repeat); +#endif +#endif + + if (sc->sc_wskbd != NULL) { + err = config_detach(sc->sc_wskbd, flags); + sc->sc_wskbd = NULL; + } + + return err; +} + +const char * +btkbd_parse_desc(struct btkbd_softc *sc, int id, const void *desc, int dlen) +{ + struct hid_data *d; + struct hid_item h; + int imod; + + imod = 0; + sc->sc_nkeycode = 0; + d = hid_start_parse(desc, dlen, hid_input); + while (hid_get_item(d, &h)) { + if (h.kind != hid_input || (h.flags & HIO_CONST) || + HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD || + h.report_ID != id) + continue; + + if (h.flags & HIO_VARIABLE) { + if (h.loc.size != 1) + return ("bad modifier size"); + + /* Single item */ + if (imod < MAXMOD) { + sc->sc_modloc[imod] = h.loc; + sc->sc_mods[imod].mask = 1 << imod; + sc->sc_mods[imod].key = HID_GET_USAGE(h.usage); + imod++; + } else + return ("too many modifier keys"); + } else { + /* Array */ + if (h.loc.size != 8) + return ("key code size != 8"); + + if (h.loc.count > MAXKEYCODE) + return ("too many key codes"); + + if (h.loc.pos % 8 != 0) + return ("key codes not on byte boundary"); + + if (sc->sc_nkeycode != 0) + return ("multiple key code arrays\n"); + + sc->sc_keycodeloc = h.loc; + sc->sc_nkeycode = h.loc.count; + } + } + sc->sc_nmod = imod; + hid_end_parse(d); + + hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK), + id, hid_output, &sc->sc_numloc, NULL); + + hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK), + id, hid_output, &sc->sc_capsloc, NULL); + + hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK), + id, hid_output, &sc->sc_scroloc, NULL); + + return (NULL); +} + +int +btkbd_enable(void *self, int on) +{ + struct btkbd_softc *sc = (struct btkbd_softc *)self; + + sc->sc_enabled = on; + return 0; +} + +void +btkbd_set_leds(void *self, int leds) +{ + struct btkbd_softc *sc = (struct btkbd_softc *)self; + uint8_t report; + + if (sc->sc_leds == leds) + return; + + sc->sc_leds = leds; + + /* + * This is not totally correct, since we did not check the + * report size from the descriptor but for keyboards it should + * just be a single byte with the relevant bits set. + */ + report = 0; + if ((leds & WSKBD_LED_SCROLL) && sc->sc_scroloc.size == 1) + report |= 1 << sc->sc_scroloc.pos; + + if ((leds & WSKBD_LED_NUM) && sc->sc_numloc.size == 1) + report |= 1 << sc->sc_numloc.pos; + + if ((leds & WSKBD_LED_CAPS) && sc->sc_capsloc.size == 1) + report |= 1 << sc->sc_capsloc.pos; + + if (sc->sc_output) + (*sc->sc_output)(&sc->sc_hidev, &report, sizeof(report)); +} + +int +btkbd_ioctl(void *self, unsigned long cmd, void *data, int flag, struct lwp *l) +{ + struct btkbd_softc *sc = (struct btkbd_softc *)self; + + switch (cmd) { + case WSKBDIO_GTYPE: + *(int *)data = WSKBD_TYPE_BLUETOOTH; + break; + + case WSKBDIO_SETLEDS: + btkbd_set_leds(sc, *(int *)data); + break; + + case WSKBDIO_GETLEDS: + *(int *)data = sc->sc_leds; + break; + +#ifdef WSDISPLAY_COMPAT_RAWKBD + case WSKBDIO_SETMODE: + sc->sc_rawkbd = (*(int *)data == WSKBD_RAW); +#ifdef BTKBD_REPEAT + timeout_del(&sc->sc_repeat); +#endif + break; +#endif + + default: + return EPASSTHROUGH; + } + + return 0; +} + +#ifdef WSDISPLAY_COMPAT_RAWKBD +#define NN 0 /* no translation */ +/* + * Translate USB keycodes to US keyboard XT scancodes. + * Scancodes >= 0x80 represent EXTENDED keycodes. + * + * See http://www.microsoft.com/HWDEV/TECH/input/Scancode.asp + */ +const u_int8_t btkbd_trtab[256] = { + NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */ + 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */ + 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */ + 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */ + 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */ + 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */ + 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */ + 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xaa, 0x46, /* 40 - 47 */ + 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */ + 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */ + 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */ + 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, NN, 0x59, /* 60 - 67 */ + 0x5d, 0x5e, 0x5f, NN, NN, NN, NN, NN, /* 68 - 6f */ + NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7f */ + NN, NN, NN, NN, NN, 0x7e, NN, 0x73, /* 80 - 87 */ + 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN, /* 88 - 8f */ + NN, NN, 0x78, 0x77, 0x76, NN, NN, NN, /* 90 - 97 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9f */ + NN, NN, NN, NN, NN, NN, NN, NN, /* a0 - a7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* a8 - af */ + NN, NN, NN, NN, NN, NN, NN, NN, /* b0 - b7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* b8 - bf */ + NN, NN, NN, NN, NN, NN, NN, NN, /* c0 - c7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* c8 - cf */ + NN, NN, NN, NN, NN, NN, NN, NN, /* d0 - d7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* d8 - df */ + 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* e0 - e7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* e8 - ef */ + NN, NN, NN, NN, NN, NN, NN, NN, /* f0 - f7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* f8 - ff */ +}; +#endif + +#define KEY_ERROR 0x01 +#define PRESS 0x000 +#define RELEASE 0x100 +#define CODEMASK 0x0ff +#define ADDKEY(c) ibuf[nkeys++] = (c) +#define REP_DELAY1 400 +#define REP_DELAYN 100 + +void +btkbd_input(struct bthidev *self, uint8_t *data, int len) +{ + struct btkbd_softc *sc = (struct btkbd_softc *)self; + struct btkbd_data *ud = &sc->sc_ndata; + uint16_t ibuf[MAXKEYS]; + uint32_t mod, omod; + int nkeys, i, j; + int key; + int s; + + if (sc->sc_wskbd == NULL || sc->sc_enabled == 0) + return; + + /* extract key modifiers */ + ud->modifiers = 0; + for (i = 0 ; i < sc->sc_nmod ; i++) + if (hid_get_data(data, &sc->sc_modloc[i])) + ud->modifiers |= sc->sc_mods[i].mask; + + /* extract keycodes */ + memcpy(ud->keycode, data + (sc->sc_keycodeloc.pos / 8), + sc->sc_nkeycode); + + if (ud->keycode[0] == KEY_ERROR) + return; /* ignore */ + + nkeys = 0; + mod = ud->modifiers; + omod = sc->sc_odata.modifiers; + if (mod != omod) + for (i = 0 ; i < sc->sc_nmod ; i++) + if ((mod & sc->sc_mods[i].mask) != + (omod & sc->sc_mods[i].mask)) + ADDKEY(sc->sc_mods[i].key | + (mod & sc->sc_mods[i].mask + ? PRESS : RELEASE)); + + if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) { + /* Check for released keys. */ + for (i = 0 ; i < sc->sc_nkeycode ; i++) { + key = sc->sc_odata.keycode[i]; + if (key == 0) + continue; + + for (j = 0 ; j < sc->sc_nkeycode ; j++) + if (key == ud->keycode[j]) + goto rfound; + + ADDKEY(key | RELEASE); + + rfound: + ; + } + + /* Check for pressed keys. */ + for (i = 0 ; i < sc->sc_nkeycode ; i++) { + key = ud->keycode[i]; + if (key == 0) + continue; + + for (j = 0; j < sc->sc_nkeycode; j++) + if (key == sc->sc_odata.keycode[j]) + goto pfound; + + ADDKEY(key | PRESS); + pfound: + ; + } + } + sc->sc_odata = *ud; + + if (nkeys == 0) + return; + +#ifdef WSDISPLAY_COMPAT_RAWKBD + if (sc->sc_rawkbd) { + u_char cbuf[MAXKEYS * 2]; + int c; + int npress; + + for (npress = i = j = 0 ; i < nkeys ; i++) { + key = ibuf[i]; + c = btkbd_trtab[key & CODEMASK]; + if (c == NN) + continue; + + if (c & 0x80) + cbuf[j++] = 0xe0; + + cbuf[j] = c & 0x7f; + if (key & RELEASE) + cbuf[j] |= 0x80; +#ifdef BTKBD_REPEAT + else { + /* remember pressed keys for autorepeat */ + if (c & 0x80) + sc->sc_rep[npress++] = 0xe0; + + sc->sc_rep[npress++] = c & 0x7f; + } +#endif + + j++; + } + + s = spltty(); + wskbd_rawinput(sc->sc_wskbd, cbuf, j); + splx(s); +#ifdef BTKBD_REPEAT + timeout_del(&sc->sc_repeat); + if (npress != 0) { + sc->sc_nrep = npress; + timeout_del(&sc->sc_repeat); + timeout_set(&sc->sc_repeat, btkbd_repeat, sc); + timeout_add(&sc->sc_repeat, hz * REP_DELAY1 / 1000); + } +#endif + return; + } +#endif + + s = spltty(); + for (i = 0 ; i < nkeys ; i++) { + key = ibuf[i]; + wskbd_input(sc->sc_wskbd, + key & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN, + key & CODEMASK); + } + splx(s); +} + +#ifdef WSDISPLAY_COMPAT_RAWKBD +#ifdef BTKBD_REPEAT +void +btkbd_repeat(void *arg) +{ + struct btkbd_softc *sc = arg; + int s; + + s = spltty(); + wskbd_rawinput(sc->sc_wskbd, sc->sc_rep, sc->sc_nrep); + splx(s); + timeout_del(&sc->sc_repeat); + timeout_set(&sc->sc_repeat, btkbd_repeat, sc); + timeout_add(&sc->sc_repeat, hz * REP_DELAYN / 1000); +} +#endif +#endif diff --git a/sys/dev/bluetooth/btms.c b/sys/dev/bluetooth/btms.c new file mode 100644 index 00000000000..fa49dcc570e --- /dev/null +++ b/sys/dev/bluetooth/btms.c @@ -0,0 +1,317 @@ +/* $OpenBSD: btms.c,v 1.1 2007/07/27 16:52:24 gwk Exp $ */ +/* $NetBSD: btms.c,v 1.6 2007/03/04 06:01:45 christos Exp $ */ + +/*- + * Copyright (c) 2006 Itronix Inc. + * All rights reserved. + * + * Written by Iain Hibbert for Itronix Inc. + * + * 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. The name of Itronix Inc. may not be used to endorse + * or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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. + */ + +/* + * based on dev/usb/ums.c + */ + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/proc.h> +#include <sys/systm.h> + +#include <netbt/bluetooth.h> + +#include <dev/bluetooth/bthid.h> +#include <dev/bluetooth/bthidev.h> + +#include <dev/usb/hid.h> +#include <dev/usb/usb.h> +#include <dev/usb/usbhid.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsmousevar.h> + +#define MAX_BUTTONS 31 +#define BUTTON(n) (1 << (((n) == 1 || (n) == 2) ? 3 - (n) : (n))) +#define NOTMOUSE(f) (((f) & (HIO_CONST | HIO_RELATIVE)) != HIO_RELATIVE) + +struct btms_softc { + struct bthidev sc_hidev; /* device+ */ + + struct device *sc_wsmouse; /* child */ + int sc_enabled; + uint16_t sc_flags; + + /* locators */ + struct hid_location sc_loc_x; + struct hid_location sc_loc_y; + struct hid_location sc_loc_z; + struct hid_location sc_loc_w; + struct hid_location sc_loc_button[MAX_BUTTONS]; + + int sc_num_buttons; + uint32_t sc_buttons; +}; + +/* sc_flags */ +#define BTMS_REVZ (1 << 0) /* reverse Z direction */ +#define BTMS_HASZ (1 << 1) /* has Z direction */ +#define BTMS_HASW (1 << 2) /* has W direction */ + +int btms_match(struct device *, struct cfdata *, void *); +void btms_attach(struct device *, struct device *, void *); +int btms_detach(struct device *, int); + +struct cfdriver btms_cd = { + NULL, "btms", DV_DULL +}; + +const struct cfattach btms_ca = { + sizeof(struct btms_softc), + btms_match, + btms_attach, + btms_detach, +}; + +/* wsmouse(4) accessops */ +int btms_enable(void *); +int btms_ioctl(void *, unsigned long, void *, int, struct lwp *); +void btms_disable(void *); + +const struct wsmouse_accessops btms_accessops = { + btms_enable, + btms_ioctl, + btms_disable, +}; + +/* bthid methods */ +void btms_input(struct bthidev *, uint8_t *, int); + + +int +btms_match(struct device *parent, struct cfdata *match, void *aux) +{ + struct bthidev_attach_args *ba = aux; + + if (hid_is_collection(ba->ba_desc, ba->ba_dlen, ba->ba_id, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) + return 1; + + return 0; +} + +void +btms_attach(struct device *parent, struct device *self, void *aux) +{ + struct btms_softc *sc = (struct btms_softc *)self; + struct bthidev_attach_args *ba = aux; + struct wsmousedev_attach_args wsma; + struct hid_location *zloc; + uint32_t flags; + int i, hl; + + ba->ba_input = btms_input; + + /* control the horizontal */ + hl = hid_locate(ba->ba_desc, ba->ba_dlen, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), ba->ba_id, hid_input, + &sc->sc_loc_x, &flags); + + if (hl == 0 || NOTMOUSE(flags)) { + printf("\n%s: X report 0x%04x not supported\n", + sc->sc_hidev.sc_dev.dv_xname, flags); + + return; + } + + /* control the vertical */ + hl = hid_locate(ba->ba_desc, ba->ba_dlen, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), ba->ba_id, hid_input, + &sc->sc_loc_y, &flags); + + if (hl == 0 || NOTMOUSE(flags)) { + printf("\n%s: Y report 0x%04x not supported\n", + sc->sc_hidev.sc_dev.dv_xname, flags); + + return; + } + + /* Try the wheel first as the Z activator since it's tradition. */ + hl = hid_locate(ba->ba_desc, ba->ba_dlen, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), ba->ba_id, hid_input, + &sc->sc_loc_z, &flags); + + zloc = &sc->sc_loc_z; + if (hl) { + if (NOTMOUSE(flags)) { + printf("\n%s: Wheel report 0x%04x not supported\n", + sc->sc_hidev.sc_dev.dv_xname, flags); + + /* ignore Bad Z coord */ + sc->sc_loc_z.size = 0; + } else { + sc->sc_flags |= BTMS_HASZ; + /* Wheels need the Z axis reversed. */ + sc->sc_flags ^= BTMS_REVZ; + /* Put Z on the W coordinate */ + zloc = &sc->sc_loc_w; + } + } + + hl = hid_locate(ba->ba_desc, ba->ba_dlen, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), ba->ba_id, hid_input, + zloc, &flags); + + /* + * The horizontal component of the scrollball can also be given by + * Application Control Pan in the Consumer page, so if we didnt see + * any Z then check that. + */ + if (!hl) { + hl = hid_locate(ba->ba_desc, ba->ba_dlen, + HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN), ba->ba_id, hid_input, + zloc, &flags); + } + + if (hl) { + if (NOTMOUSE(flags)) + zloc->size = 0; /* ignore Z */ + else { + if (sc->sc_flags & BTMS_HASZ) + sc->sc_flags |= BTMS_HASW; + else + sc->sc_flags |= BTMS_HASZ; + } + } + + for (i = 1 ; i <= MAX_BUTTONS ; i++) { + hl = hid_locate(ba->ba_desc, ba->ba_dlen, + HID_USAGE2(HUP_BUTTON, i), ba->ba_id, hid_input, + &sc->sc_loc_button[i - 1], NULL); + + if (hl == 0) + break; + } + sc->sc_num_buttons = i - 1; + + printf(": %d button%s%s%s%s.\n", sc->sc_num_buttons, + sc->sc_num_buttons == 1 ? "" : "s", + sc->sc_flags & BTMS_HASW ? ", W" : "", + sc->sc_flags & BTMS_HASZ ? " and Z dir" : "", + sc->sc_flags & BTMS_HASW ? "s" : ""); + + wsma.accessops = &btms_accessops; + wsma.accesscookie = sc; + + sc->sc_wsmouse = config_found((struct device *)sc, + &wsma, wsmousedevprint); +} + +int +btms_detach(struct device *self, int flags) +{ + struct btms_softc *sc = (struct btms_softc *)self; + int err = 0; + + if (sc->sc_wsmouse != NULL) { + err = config_detach(sc->sc_wsmouse, flags); + sc->sc_wsmouse = NULL; + } + + return err; +} + +int +btms_enable(void *self) +{ + struct btms_softc *sc = (struct btms_softc *)self; + + if (sc->sc_enabled) + return EBUSY; + + sc->sc_enabled = 1; + return 0; +} + +int +btms_ioctl(void *self, unsigned long cmd, void *data, int flag, struct lwp *l) +{ + /* struct btms_softc *sc = (struct btms_softc *)self; */ + + switch (cmd) { + case WSMOUSEIO_GTYPE: + *(uint *)data = WSMOUSE_TYPE_BLUETOOTH; + break; + + default: + return EPASSTHROUGH; + } + + return 0; +} + +void +btms_disable(void *self) +{ + struct btms_softc *sc = (struct btms_softc *)self; + + sc->sc_enabled = 0; +} + +void +btms_input(struct bthidev *self, uint8_t *data, int len) +{ + struct btms_softc *sc = (struct btms_softc *)self; + int dx, dy, dz, dw; + uint32_t buttons; + int i, s; + + if (sc->sc_wsmouse == NULL || sc->sc_enabled == 0) + return; + + dx = hid_get_data(data, &sc->sc_loc_x); + dy = -hid_get_data(data, &sc->sc_loc_y); + dz = hid_get_data(data, &sc->sc_loc_z); + dw = hid_get_data(data, &sc->sc_loc_w); + + if (sc->sc_flags & BTMS_REVZ) + dz = -dz; + + buttons = 0; + for (i = 0 ; i < sc->sc_num_buttons ; i++) + if (hid_get_data(data, &sc->sc_loc_button[i])) + buttons |= BUTTON(i); + + if (dx != 0 || dy != 0 || dz != 0 || dw != 0 || + buttons != sc->sc_buttons) { + sc->sc_buttons = buttons; + + s = spltty(); + wsmouse_input(sc->sc_wsmouse, buttons, dx, dy, dz, dw, + WSMOUSE_INPUT_DELTA); + splx(s); + } +} |