summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/bluetooth/btdev.h68
-rw-r--r--sys/dev/bluetooth/bthidev.c801
-rw-r--r--sys/dev/bluetooth/bthidev.h22
-rw-r--r--sys/dev/bluetooth/btkbd.c28
-rw-r--r--sys/dev/bluetooth/btms.c21
-rw-r--r--sys/dev/bluetooth/files.bluetooth21
-rw-r--r--sys/dev/usb/usbhid.h5
-rw-r--r--sys/dev/wscons/wsconsio.h4
-rw-r--r--sys/sys/malloc.h7
9 files changed, 916 insertions, 61 deletions
diff --git a/sys/dev/bluetooth/btdev.h b/sys/dev/bluetooth/btdev.h
index f284bfc548e..e158b9598e6 100644
--- a/sys/dev/bluetooth/btdev.h
+++ b/sys/dev/bluetooth/btdev.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: btdev.h,v 1.2 2007/07/27 20:22:12 xsa Exp $ */
-/* $NetBSD: btdev.h,v 1.6 2007/04/21 06:15:22 plunky Exp $ */
+/* $OpenBSD: btdev.h,v 1.3 2007/09/01 17:06:26 xsa Exp $ */
+/* $NetBSD: btdev.h,v 1.1 2006/06/19 15:44:45 gdamore Exp $ */
/*-
* Copyright (c) 2006 Itronix Inc.
@@ -35,25 +35,63 @@
#ifndef _DEV_BLUETOOTH_BTDEV_H_
#define _DEV_BLUETOOTH_BTDEV_H_
+/*
+ * Bluetooth Device attach arguments (from userland)
+ */
+struct btdev_attach_args {
+ bdaddr_t bd_laddr; /* local address */
+ bdaddr_t bd_raddr; /* remote address */
+ uint16_t bd_type; /* device type */
+
+ union {
+ struct { /* HID arguments */
+ uint16_t hid_flags;/* HID flags */
+ uint16_t hid_ctl; /* control PSM */
+ uint16_t hid_int; /* interrupt PSM */
+ void *hid_desc; /* HID descriptor */
+ uint16_t hid_dlen; /* descriptor length */
+ } bdd_hid;
+
+ struct { /* HSET arguments */
+ uint8_t hset_channel; /* RFCOMM channel */
+ uint8_t hset_mtu; /* SCO mtu */
+ } bdd_hset;
+
+ struct { /* Advance Audio arguments */
+ } bdd_a2dp;
+ } bdd;
+};
+
+#define bd_hid bdd.bdd_hid
+#define bd_hset bdd.bdd_hset
+#define bd_a2dp bdd.bdd_a2dp
+
+/* btdev type */
+#define BTDEV_HID 0x0001
+#define BTDEV_HSET 0x0002
+
+/* bthid flags */
+#define BTHID_INITIATE (1 << 0) /* normally initiate */
+#define BTHID_CONNECT (1 << 1) /* initiate connect */
+
/* 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"
+#define BTDEV_ATTACH _IOW('b', 14, struct btdev_attach_args)
+#define BTDEV_DETACH _IOW('b', 15, bdaddr_t)
#ifdef _KERNEL
+
+/*
+ * Bluetooth device header
+ */
struct btdev {
- struct device sc_dev;
+ struct device sc_dev; /* system device */
+ bdaddr_t sc_addr; /* device bdaddr */
+
LIST_ENTRY(btdev) sc_next;
};
+
+#define btdev_name(d) (((struct btdev *)(d))->sc_dev.dv_xname)
+
#endif /* _KERNEL */
#endif /* _DEV_BLUETOOTH_BTDEV_H_ */
diff --git a/sys/dev/bluetooth/bthidev.c b/sys/dev/bluetooth/bthidev.c
new file mode 100644
index 00000000000..4304f6cc02b
--- /dev/null
+++ b/sys/dev/bluetooth/bthidev.c
@@ -0,0 +1,801 @@
+/* $OpenBSD: bthidev.c,v 1.1 2007/09/01 17:06:26 xsa Exp $ */
+/* $NetBSD: bthidev.c,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.
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+
+#include <netbt/bluetooth.h>
+#include <netbt/l2cap.h>
+
+#include <dev/usb/hid.h>
+#include <dev/bluetooth/btdev.h>
+#include <dev/bluetooth/bthid.h>
+#include <dev/bluetooth/bthidev.h>
+
+#define MAX_DESCRIPTOR_LEN 1024 /* sanity check */
+
+/* bthidev softc */
+struct bthidev_softc {
+ struct btdev sc_btdev; /* device+ */
+ uint16_t sc_state;
+ uint16_t sc_flags;
+
+ bdaddr_t sc_laddr; /* local address */
+ bdaddr_t sc_raddr; /* remote address */
+
+ void *sc_desc; /* HID descriptor */
+ int sc_dlen; /* descriptor length */
+
+ uint16_t sc_ctlpsm; /* control PSM */
+ struct l2cap_channel *sc_ctl; /* control channel */
+ struct l2cap_channel *sc_ctl_l; /* control listen */
+
+ uint16_t sc_intpsm; /* interrupt PSM */
+ struct l2cap_channel *sc_int; /* interrupt channel */
+ struct l2cap_channel *sc_int_l; /* interrupt listen */
+
+ LIST_HEAD(,bthidev) sc_list; /* child list */
+
+ struct timeout sc_reconnect;
+ int sc_attempts; /* connection attempts */
+};
+
+/* device state */
+#define BTHID_CLOSED 0
+#define BTHID_WAIT_CTL 1
+#define BTHID_WAIT_INT 2
+#define BTHID_OPEN 3
+#define BTHID_DETACHING 4
+
+#define BTHID_RETRY_INTERVAL 5 /* seconds between connection attempts */
+
+void bthidev_timeout(void *);
+int bthidev_listen(struct bthidev_softc *);
+int bthidev_connect(struct bthidev_softc *);
+int bthidev_output(struct bthidev *, uint8_t *, int);
+void bthidev_null(struct bthidev *, uint8_t *, int);
+
+int bthidev_match(struct device *, void *, void *);
+void bthidev_attach(struct device *, struct device *, void *);
+int bthidev_detach(struct device *, int);
+int bthidev_print(void *, const char *);
+
+int bthidevsubmatch(struct device *parent, void *, void *);
+
+struct cfdriver bthidev_cd = {
+ NULL, "bthidev", DV_DULL
+};
+
+const struct cfattach bthidev_ca = {
+ sizeof(struct bthidev_softc),
+ bthidev_match,
+ bthidev_attach,
+ bthidev_detach,
+};
+
+/* bluetooth(9) protocol methods for L2CAP */
+void bthidev_connecting(void *);
+void bthidev_ctl_connected(void *);
+void bthidev_int_connected(void *);
+void bthidev_ctl_disconnected(void *, int);
+void bthidev_int_disconnected(void *, int);
+void *bthidev_ctl_newconn(void *, struct sockaddr_bt *,
+ struct sockaddr_bt *);
+void *bthidev_int_newconn(void *, struct sockaddr_bt *,
+ struct sockaddr_bt *);
+void bthidev_complete(void *, int);
+void bthidev_input(void *, struct mbuf *);
+
+const struct btproto bthidev_ctl_proto = {
+ bthidev_connecting,
+ bthidev_ctl_connected,
+ bthidev_ctl_disconnected,
+ bthidev_ctl_newconn,
+ bthidev_complete,
+ NULL,
+ bthidev_input,
+};
+
+const struct btproto bthidev_int_proto = {
+ bthidev_connecting,
+ bthidev_int_connected,
+ bthidev_int_disconnected,
+ bthidev_int_newconn,
+ bthidev_complete,
+ NULL,
+ bthidev_input,
+};
+
+
+int
+bthidev_match(struct device *self, void *match, void *aux)
+{
+ struct btdev_attach_args *bda = (struct btdev_attach_args *)aux;
+
+ if (bda->bd_type != BTDEV_HID
+ || L2CAP_PSM_INVALID(bda->bd_hid.hid_ctl)
+ || L2CAP_PSM_INVALID(bda->bd_hid.hid_int)
+ || bda->bd_hid.hid_desc == NULL
+ || bda->bd_hid.hid_dlen == 0
+ || bda->bd_hid.hid_dlen > MAX_DESCRIPTOR_LEN)
+ return 0;
+
+ return 1;
+}
+
+void
+bthidev_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct bthidev_softc *sc = (struct bthidev_softc *)self;
+ struct btdev_attach_args *bda = (struct btdev_attach_args *)aux;
+ struct bthidev_attach_args bha;
+ struct bthidev *dev;
+ struct hid_data *d;
+ struct hid_item h;
+ int maxid, rep, s;
+
+ /*
+ * Init softc
+ */
+ LIST_INIT(&sc->sc_list);
+ timeout_set(&sc->sc_reconnect, bthidev_timeout, sc);
+ sc->sc_state = BTHID_CLOSED;
+
+ /*
+ * copy in our configuration info
+ */
+ bdaddr_copy(&sc->sc_laddr, &bda->bd_laddr);
+ bdaddr_copy(&sc->sc_raddr, &bda->bd_raddr);
+
+ sc->sc_ctlpsm = bda->bd_hid.hid_ctl;
+ sc->sc_intpsm = bda->bd_hid.hid_int;
+
+ sc->sc_flags = bda->bd_hid.hid_flags;
+ if (sc->sc_flags & BTHID_INITIATE)
+ sc->sc_flags |= BTHID_CONNECT;
+
+ sc->sc_dlen = bda->bd_hid.hid_dlen;
+ sc->sc_desc = malloc(bda->bd_hid.hid_dlen, M_BTHIDEV, M_WAITOK);
+ if (sc->sc_desc == NULL) {
+ printf(" no memory\n");
+ return;
+ }
+ copyin(bda->bd_hid.hid_desc, sc->sc_desc, bda->bd_hid.hid_dlen);
+
+ /*
+ * Parse the descriptor and attach child devices, one per report.
+ */
+ maxid = -1;
+ h.report_ID = 0;
+ d = hid_start_parse(sc->sc_desc, sc->sc_dlen, hid_none);
+ while (hid_get_item(d, &h)) {
+ if (h.report_ID > maxid)
+ maxid = h.report_ID;
+ }
+ hid_end_parse(d);
+
+ if (maxid < 0) {
+ printf(" no reports found\n");
+ return;
+ }
+
+ printf("\n");
+
+ for (rep = 0 ; rep <= maxid ; rep++) {
+ if (hid_report_size(sc->sc_desc, sc->sc_dlen, hid_feature, rep) == 0
+ && hid_report_size(sc->sc_desc, sc->sc_dlen, hid_input, rep) == 0
+ && hid_report_size(sc->sc_desc, sc->sc_dlen, hid_output, rep) == 0)
+ continue;
+
+ bha.ba_desc = sc->sc_desc;
+ bha.ba_dlen = sc->sc_dlen;
+ bha.ba_input = bthidev_null;
+ bha.ba_feature = bthidev_null;
+ bha.ba_output = bthidev_output;
+ bha.ba_id = rep;
+
+ dev = (struct bthidev *)config_found_sm(self, &bha,
+ bthidev_print, bthidevsubmatch);
+ if (dev != NULL) {
+ dev->sc_parent = &sc->sc_btdev;
+ dev->sc_id = rep;
+ dev->sc_input = bha.ba_input;
+ dev->sc_feature = bha.ba_feature;
+ LIST_INSERT_HEAD(&sc->sc_list, dev, sc_next);
+ }
+ }
+
+ /*
+ * start bluetooth connections
+ */
+ s = splsoftnet();
+ if ((sc->sc_flags & BTHID_INITIATE) == 0)
+ bthidev_listen(sc);
+
+ if (sc->sc_flags & BTHID_CONNECT)
+ bthidev_connect(sc);
+ splx(s);
+}
+
+int
+bthidev_detach(struct device *self, int flags)
+{
+ struct bthidev_softc *sc = (struct bthidev_softc *)self;
+ struct bthidev *dev;
+ int s;
+
+ s = splsoftnet();
+ sc->sc_flags = 0; /* disable reconnecting */
+
+ /* release interrupt listen */
+ if (sc->sc_int_l != NULL) {
+ l2cap_detach(&sc->sc_int_l);
+ sc->sc_int_l = NULL;
+ }
+
+ /* release control listen */
+ if (sc->sc_ctl_l != NULL) {
+ l2cap_detach(&sc->sc_ctl_l);
+ sc->sc_ctl_l = NULL;
+ }
+
+ /* close interrupt channel */
+ if (sc->sc_int != NULL) {
+ l2cap_disconnect(sc->sc_int, 0);
+ l2cap_detach(&sc->sc_int);
+ sc->sc_int = NULL;
+ }
+
+ /* close control channel */
+ if (sc->sc_ctl != NULL) {
+ l2cap_disconnect(sc->sc_ctl, 0);
+ l2cap_detach(&sc->sc_ctl);
+ sc->sc_ctl = NULL;
+ }
+
+ sc->sc_state = BTHID_DETACHING;
+ timeout_del(&sc->sc_reconnect);
+
+ splx(s);
+
+ /* detach children */
+ while ((dev = LIST_FIRST(&sc->sc_list)) != NULL) {
+ LIST_REMOVE(dev, sc_next);
+ config_detach(&dev->sc_dev, flags);
+ }
+
+ /* release descriptor */
+ if (sc->sc_desc != NULL) {
+ free(sc->sc_desc, M_BTHIDEV);
+ sc->sc_desc = NULL;
+ }
+ return 0;
+}
+
+int
+bthidev_print(void *aux, const char *pnp)
+{
+ struct bthidev_attach_args *ba = aux;
+
+ if (pnp != NULL)
+ printf("%s:", pnp);
+
+ if (ba->ba_id > 0)
+ printf(" reportid %d", ba->ba_id);
+
+ return UNCONF;
+}
+
+int
+bthidevsubmatch(struct device *parent, void *match, void *aux)
+{
+ struct bthidev_attach_args *ba = aux;
+ struct cfdata *cf = match;
+
+ if (cf->bthidevcf_reportid != BTHIDEV_UNK_REPORTID &&
+ cf->bthidevcf_reportid != ba->ba_id)
+ return (0);
+
+ return ((*cf->cf_attach->ca_match)(parent, cf, aux));
+}
+
+
+/*****************************************************************************
+ *
+ * bluetooth(4) HID attach/detach routines
+ */
+
+/*
+ * callouts are scheduled to initiate outgoing connections
+ * after the connection has been lost.
+ */
+void
+bthidev_timeout(void *arg)
+{
+ struct bthidev_softc *sc = arg;
+ int s, err;
+
+ s = splsoftnet();
+
+ switch (sc->sc_state) {
+ case BTHID_CLOSED:
+ sc->sc_flags |= BTHID_CONNECT;
+ err = bthidev_connect(sc);
+ if (err)
+ printf("%s: connect failed (%d)\n",
+ sc->sc_btdev.sc_dev.dv_xname, err);
+ break;
+
+ case BTHID_WAIT_CTL:
+ break;
+
+ case BTHID_WAIT_INT:
+ break;
+
+ case BTHID_OPEN:
+ break;
+
+ case BTHID_DETACHING:
+ wakeup(sc);
+ break;
+
+ default:
+ break;
+ }
+ splx(s);
+}
+
+/*
+ * listen for our device
+ */
+int
+bthidev_listen(struct bthidev_softc *sc)
+{
+ struct sockaddr_bt sa;
+ int err;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.bt_len = sizeof(sa);
+ sa.bt_family = AF_BLUETOOTH;
+ bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr);
+
+ /*
+ * Listen on control PSM
+ */
+ err = l2cap_attach(&sc->sc_ctl_l, &bthidev_ctl_proto, sc);
+ if (err)
+ return err;
+
+ sa.bt_psm = sc->sc_ctlpsm;
+ err = l2cap_bind(sc->sc_ctl_l, &sa);
+ if (err)
+ return err;
+
+ err = l2cap_listen(sc->sc_ctl_l);
+ if (err)
+ return err;
+
+ /*
+ * Listen on interrupt PSM
+ */
+ err = l2cap_attach(&sc->sc_int_l, &bthidev_int_proto, sc);
+ if (err)
+ return err;
+
+ sa.bt_psm = sc->sc_intpsm;
+ err = l2cap_bind(sc->sc_int_l, &sa);
+ if (err)
+ return err;
+
+ err = l2cap_listen(sc->sc_int_l);
+ if (err)
+ return err;
+
+ sc->sc_state = BTHID_WAIT_CTL;
+ return 0;
+}
+
+/*
+ * start connecting to our device
+ */
+int
+bthidev_connect(struct bthidev_softc *sc)
+{
+ struct sockaddr_bt sa;
+ int err;
+
+ if (sc->sc_attempts++ > 0)
+ printf("%s: connect (#%d)\n",
+ sc->sc_btdev.sc_dev.dv_xname, sc->sc_attempts);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.bt_len = sizeof(sa);
+ sa.bt_family = AF_BLUETOOTH;
+
+ err = l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc);
+ if (err) {
+ printf("%s: l2cap_attach failed (%d)\n",
+ sc->sc_btdev.sc_dev.dv_xname, err);
+ return err;
+ }
+
+ bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr);
+ err = l2cap_bind(sc->sc_ctl, &sa);
+ if (err) {
+ printf("%s: l2cap_bind failed (%d)\n",
+ sc->sc_btdev.sc_dev.dv_xname, err);
+ return err;
+ }
+
+ sa.bt_psm = sc->sc_ctlpsm;
+ bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr);
+ err = l2cap_connect(sc->sc_ctl, &sa);
+ if (err) {
+ printf("%s: l2cap_connect failed (%d)\n",
+ sc->sc_btdev.sc_dev.dv_xname, err);
+ return err;
+ }
+
+ sc->sc_state = BTHID_WAIT_CTL;
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * bluetooth(9) callback methods for L2CAP
+ *
+ * All these are called from Bluetooth Protocol code, in a soft
+ * interrupt context at IPL_SOFTNET.
+ */
+
+void
+bthidev_connecting(void *arg)
+{
+
+ /* dont care */
+}
+
+void
+bthidev_ctl_connected(void *arg)
+{
+ struct sockaddr_bt sa;
+ struct bthidev_softc *sc = arg;
+ int err;
+
+ if (sc->sc_state != BTHID_WAIT_CTL)
+ return;
+
+ KASSERT(sc->sc_ctl != NULL);
+ KASSERT(sc->sc_int == NULL);
+
+ if (sc->sc_flags & BTHID_CONNECT) {
+ /* initiate connect on interrupt PSM */
+ err = l2cap_attach(&sc->sc_int, &bthidev_int_proto, sc);
+ if (err)
+ goto fail;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.bt_len = sizeof(sa);
+ sa.bt_family = AF_BLUETOOTH;
+ bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr);
+
+ err = l2cap_bind(sc->sc_int, &sa);
+ if (err)
+ goto fail;
+
+ sa.bt_psm = sc->sc_intpsm;
+ bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr);
+ err = l2cap_connect(sc->sc_int, &sa);
+ if (err)
+ goto fail;
+ }
+
+ sc->sc_state = BTHID_WAIT_INT;
+ return;
+
+fail:
+ l2cap_detach(&sc->sc_ctl);
+ sc->sc_ctl = NULL;
+ printf("%s: connect failed (%d)\n",
+ sc->sc_btdev.sc_dev.dv_xname, err);
+}
+
+void
+bthidev_int_connected(void *arg)
+{
+ struct bthidev_softc *sc = arg;
+
+ if (sc->sc_state != BTHID_WAIT_INT)
+ return;
+
+ KASSERT(sc->sc_ctl != NULL);
+ KASSERT(sc->sc_int != NULL);
+
+ sc->sc_attempts = 0;
+ sc->sc_flags &= ~BTHID_CONNECT;
+ sc->sc_state = BTHID_OPEN;
+
+ printf("%s: connected\n", sc->sc_btdev.sc_dev.dv_xname);
+}
+
+/*
+ * Disconnected
+ *
+ * Depending on our state, this could mean several things, but essentially
+ * we are lost.
+ */
+void
+bthidev_ctl_disconnected(void *arg, int err)
+{
+ struct bthidev_softc *sc = arg;
+
+ if (sc->sc_ctl != NULL) {
+ l2cap_detach(&sc->sc_ctl);
+ sc->sc_ctl = NULL;
+ }
+
+ sc->sc_state = BTHID_CLOSED;
+
+ if (sc->sc_int == NULL) {
+ printf("%s: disconnected\n", sc->sc_btdev.sc_dev.dv_xname);
+
+ if (sc->sc_flags & BTHID_INITIATE)
+ timeout_add(&sc->sc_reconnect,
+ BTHID_RETRY_INTERVAL * hz);
+ else
+ sc->sc_state = BTHID_WAIT_CTL;
+ }
+}
+
+void
+bthidev_int_disconnected(void *arg, int err)
+{
+ struct bthidev_softc *sc = arg;
+
+ if (sc->sc_int != NULL) {
+ l2cap_detach(&sc->sc_int);
+ sc->sc_int = NULL;
+ }
+
+ sc->sc_state = BTHID_CLOSED;
+
+ if (sc->sc_ctl == NULL) {
+ printf("%s: disconnected\n", sc->sc_btdev.sc_dev.dv_xname);
+
+ if (sc->sc_flags & BTHID_INITIATE)
+ timeout_add(&sc->sc_reconnect,
+ BTHID_RETRY_INTERVAL * hz);
+ else
+ sc->sc_state = BTHID_WAIT_CTL;
+ }
+}
+
+/*
+ * New Connections
+ *
+ * We give a new L2CAP handle back if this matches the BDADDR we are
+ * listening for and we are in the right state. bthidev_connected will
+ * be called when the connection is open, so nothing else to do here
+ */
+void *
+bthidev_ctl_newconn(void *arg, struct sockaddr_bt *laddr,
+ struct sockaddr_bt *raddr)
+{
+ struct bthidev_softc *sc = arg;
+
+ if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0
+ || (sc->sc_flags & BTHID_INITIATE)
+ || sc->sc_state != BTHID_WAIT_CTL
+ || sc->sc_ctl != NULL
+ || sc->sc_int != NULL)
+ return NULL;
+
+ l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc);
+ return sc->sc_ctl;
+}
+
+void *
+bthidev_int_newconn(void *arg, struct sockaddr_bt *laddr,
+ struct sockaddr_bt *raddr)
+{
+ struct bthidev_softc *sc = arg;
+
+ if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0
+ || (sc->sc_flags & BTHID_INITIATE)
+ || sc->sc_state != BTHID_WAIT_INT
+ || sc->sc_ctl == NULL
+ || sc->sc_int != NULL)
+ return NULL;
+
+ l2cap_attach(&sc->sc_int, &bthidev_int_proto, sc);
+ return sc->sc_int;
+}
+
+void
+bthidev_complete(void *arg, int count)
+{
+
+ /* dont care */
+}
+
+/*
+ * Receive reports from the protocol stack.
+ */
+void
+bthidev_input(void *arg, struct mbuf *m)
+{
+ struct bthidev_softc *sc = arg;
+ struct bthidev *dev;
+ uint8_t *data;
+ int len;
+
+ if (sc->sc_state != BTHID_OPEN)
+ goto release;
+
+ if (m->m_pkthdr.len > m->m_len)
+ printf("%s: truncating HID report\n",
+ sc->sc_btdev.sc_dev.dv_xname);
+
+ len = m->m_len;
+ data = mtod(m, uint8_t *);
+
+ if (BTHID_TYPE(data[0]) == BTHID_DATA) {
+ /*
+ * data[0] == type / parameter
+ * data[1] == id
+ * data[2..len] == report
+ */
+ if (len < 3)
+ goto release;
+
+ LIST_FOREACH(dev, &sc->sc_list, sc_next) {
+ if (data[1] == dev->sc_id) {
+ switch (BTHID_DATA_PARAM(data[0])) {
+ case BTHID_DATA_INPUT:
+ (*dev->sc_input)(dev, data + 2, len - 2);
+ break;
+
+ case BTHID_DATA_FEATURE:
+ (*dev->sc_feature)(dev, data + 2, len - 2);
+ break;
+
+ default:
+ break;
+ }
+
+ goto release;
+ }
+ }
+ printf("%s: report id %d, len = %d ignored\n",
+ sc->sc_btdev.sc_dev.dv_xname, data[1], len - 2);
+
+ goto release;
+ }
+
+ if (BTHID_TYPE(data[0]) == BTHID_CONTROL) {
+ if (len < 1)
+ goto release;
+
+ if (BTHID_DATA_PARAM(data[0]) == BTHID_CONTROL_UNPLUG) {
+ printf("%s: unplugged\n",
+ sc->sc_btdev.sc_dev.dv_xname);
+
+ /* close interrupt channel */
+ if (sc->sc_int != NULL) {
+ l2cap_disconnect(sc->sc_int, 0);
+ l2cap_detach(&sc->sc_int);
+ sc->sc_int = NULL;
+ }
+
+ /* close control channel */
+ if (sc->sc_ctl != NULL) {
+ l2cap_disconnect(sc->sc_ctl, 0);
+ l2cap_detach(&sc->sc_ctl);
+ sc->sc_ctl = NULL;
+ }
+ }
+
+ goto release;
+ }
+
+release:
+ m_freem(m);
+}
+
+/*****************************************************************************
+ *
+ * IO routines
+ */
+
+void
+bthidev_null(struct bthidev *dev, uint8_t *report, int len)
+{
+
+ /*
+ * empty routine just in case the device
+ * provided no method to handle this report
+ */
+}
+
+int
+bthidev_output(struct bthidev *dev, uint8_t *report, int rlen)
+{
+ struct bthidev_softc *sc = (struct bthidev_softc *)dev->sc_parent;
+ struct mbuf *m;
+ int s, err;
+
+ if (sc == NULL || sc->sc_state != BTHID_OPEN)
+ return ENOTCONN;
+
+ KASSERT(sc->sc_ctl != NULL);
+ KASSERT(sc->sc_int != NULL);
+
+ if (rlen == 0 || report == NULL)
+ return 0;
+
+ if (rlen > MHLEN - 2) {
+ printf("%s: output report too long (%d)!\n",
+ sc->sc_btdev.sc_dev.dv_xname, rlen);
+
+ return EMSGSIZE;
+ }
+
+ m = m_gethdr(M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return ENOMEM;
+
+ /*
+ * data[0] = type / parameter
+ * data[1] = id
+ * data[2..N] = report
+ */
+ mtod(m, uint8_t *)[0] = (uint8_t)((BTHID_DATA << 4) | BTHID_DATA_OUTPUT);
+ mtod(m, uint8_t *)[1] = dev->sc_id;
+ memcpy(mtod(m, uint8_t *) + 2, report, rlen);
+ m->m_pkthdr.len = m->m_len = rlen + 2;
+
+ s = splsoftnet();
+ err = l2cap_send(sc->sc_int, m);
+ splx(s);
+
+ return err;
+}
diff --git a/sys/dev/bluetooth/bthidev.h b/sys/dev/bluetooth/bthidev.h
index 15fa38ab672..76765bfaf6d 100644
--- a/sys/dev/bluetooth/bthidev.h
+++ b/sys/dev/bluetooth/bthidev.h
@@ -1,5 +1,5 @@
-/* $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 $ */
+/* $OpenBSD: bthidev.h,v 1.2 2007/09/01 17:06:26 xsa Exp $ */
+/* $NetBSD: bthidev.h,v 1.1 2006/06/19 15:44:45 gdamore Exp $ */
/*-
* Copyright (c) 2006 Itronix Inc.
@@ -35,17 +35,15 @@
#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"
+#define BTHIDBUSCF_REPORTID 0
+#define BTHIDBUSCF_REPORTID_DEFAULT -1
+
+#define bthidevcf_reportid cf_loc[BTHIDBUSCF_REPORTID]
+#define BTHIDEV_UNK_REPORTID BTHIDBUSCF_REPORTID_DEFAULT
-#ifdef _KERNEL
-/* HID device header */
struct bthidev {
struct device sc_dev;
- struct device *sc_parent;
+ struct btdev *sc_parent;
int sc_id; /* report id */
int sc_len; /* report len */
@@ -59,9 +57,8 @@ struct bthidev {
LIST_ENTRY(bthidev) sc_next;
};
-/* HID device attach arguments */
struct bthidev_attach_args {
- const void *ba_desc; /* descriptor */
+ void *ba_desc; /* descriptor */
int ba_dlen; /* descriptor length */
int ba_id; /* report id */
@@ -72,6 +69,5 @@ struct bthidev_attach_args {
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
index cd5958a2d86..0d65a8efc18 100644
--- a/sys/dev/bluetooth/btkbd.c
+++ b/sys/dev/bluetooth/btkbd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: btkbd.c,v 1.1 2007/07/27 16:52:24 gwk Exp $ */
+/* $OpenBSD: btkbd.c,v 1.2 2007/09/01 17:06:26 xsa Exp $ */
/* $NetBSD: btkbd.c,v 1.7 2007/07/09 21:00:31 ad Exp $ */
/*-
@@ -107,7 +107,7 @@ struct btkbd_softc {
#endif
};
-int btkbd_match(struct device *, struct cfdata *, void *);
+int btkbd_match(struct device *, void *, void *);
void btkbd_attach(struct device *, struct device *, void *);
int btkbd_detach(struct device *, int);
@@ -124,7 +124,7 @@ const struct cfattach btkbd_ca = {
int btkbd_enable(void *, int);
void btkbd_set_leds(void *, int);
-int btkbd_ioctl(void *, unsigned long, void *, int, struct lwp *);
+int btkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
const struct wskbd_accessops btkbd_accessops = {
btkbd_enable,
@@ -150,7 +150,7 @@ const struct wskbd_mapdata btkbd_keymapdata = {
void btkbd_input(struct bthidev *, uint8_t *, int);
/* internal prototypes */
-const char *btkbd_parse_desc(struct btkbd_softc *, int, const void *, int);
+const char *btkbd_parse_desc(struct btkbd_softc *, int, void *, int);
#ifdef WSDISPLAY_COMPAT_RAWKBD
#ifdef BTKBD_REPEAT
@@ -160,7 +160,7 @@ void btkbd_repeat(void *);
int
-btkbd_match(struct device *self, struct cfdata *cfdata, void *aux)
+btkbd_match(struct device *self, void *match, void *aux)
{
struct bthidev_attach_args *ba = aux;
@@ -226,7 +226,7 @@ btkbd_detach(struct device *self, int flags)
}
const char *
-btkbd_parse_desc(struct btkbd_softc *sc, int id, const void *desc, int dlen)
+btkbd_parse_desc(struct btkbd_softc *sc, int id, void *desc, int dlen)
{
struct hid_data *d;
struct hid_item h;
@@ -326,22 +326,22 @@ btkbd_set_leds(void *self, int leds)
}
int
-btkbd_ioctl(void *self, unsigned long cmd, void *data, int flag, struct lwp *l)
+btkbd_ioctl(void *self, u_long cmd, caddr_t data, int flag, struct proc *p)
{
struct btkbd_softc *sc = (struct btkbd_softc *)self;
switch (cmd) {
case WSKBDIO_GTYPE:
*(int *)data = WSKBD_TYPE_BLUETOOTH;
- break;
+ return 0;
case WSKBDIO_SETLEDS:
btkbd_set_leds(sc, *(int *)data);
- break;
+ return 0;
case WSKBDIO_GETLEDS:
*(int *)data = sc->sc_leds;
- break;
+ return 0;
#ifdef WSDISPLAY_COMPAT_RAWKBD
case WSKBDIO_SETMODE:
@@ -349,14 +349,10 @@ btkbd_ioctl(void *self, unsigned long cmd, void *data, int flag, struct lwp *l)
#ifdef BTKBD_REPEAT
timeout_del(&sc->sc_repeat);
#endif
- break;
+ return 0;
#endif
-
- default:
- return EPASSTHROUGH;
}
-
- return 0;
+ return -1;
}
#ifdef WSDISPLAY_COMPAT_RAWKBD
diff --git a/sys/dev/bluetooth/btms.c b/sys/dev/bluetooth/btms.c
index fa49dcc570e..bfbd43fbbaa 100644
--- a/sys/dev/bluetooth/btms.c
+++ b/sys/dev/bluetooth/btms.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: btms.c,v 1.1 2007/07/27 16:52:24 gwk Exp $ */
+/* $OpenBSD: btms.c,v 1.2 2007/09/01 17:06:26 xsa Exp $ */
/* $NetBSD: btms.c,v 1.6 2007/03/04 06:01:45 christos Exp $ */
/*-
@@ -81,7 +81,7 @@ struct btms_softc {
#define BTMS_HASZ (1 << 1) /* has Z direction */
#define BTMS_HASW (1 << 2) /* has W direction */
-int btms_match(struct device *, struct cfdata *, void *);
+int btms_match(struct device *, void *, void *);
void btms_attach(struct device *, struct device *, void *);
int btms_detach(struct device *, int);
@@ -98,7 +98,7 @@ const struct cfattach btms_ca = {
/* wsmouse(4) accessops */
int btms_enable(void *);
-int btms_ioctl(void *, unsigned long, void *, int, struct lwp *);
+int btms_ioctl(void *, u_long, caddr_t, int, struct proc *);
void btms_disable(void *);
const struct wsmouse_accessops btms_accessops = {
@@ -108,11 +108,11 @@ const struct wsmouse_accessops btms_accessops = {
};
/* bthid methods */
-void btms_input(struct bthidev *, uint8_t *, int);
+void btms_input(struct bthidev *, uint8_t *, int);
int
-btms_match(struct device *parent, struct cfdata *match, void *aux)
+btms_match(struct device *parent, void *match, void *aux)
{
struct bthidev_attach_args *ba = aux;
@@ -257,20 +257,17 @@ btms_enable(void *self)
}
int
-btms_ioctl(void *self, unsigned long cmd, void *data, int flag, struct lwp *l)
+btms_ioctl(void *self, u_long cmd, caddr_t data, int flag, struct proc *p)
{
/* struct btms_softc *sc = (struct btms_softc *)self; */
switch (cmd) {
case WSMOUSEIO_GTYPE:
- *(uint *)data = WSMOUSE_TYPE_BLUETOOTH;
- break;
-
- default:
- return EPASSTHROUGH;
+ *(u_int *)data = WSMOUSE_TYPE_BLUETOOTH;
+ return 0;
}
- return 0;
+ return -1;
}
void
diff --git a/sys/dev/bluetooth/files.bluetooth b/sys/dev/bluetooth/files.bluetooth
index e32ab21f4ae..4de928086af 100644
--- a/sys/dev/bluetooth/files.bluetooth
+++ b/sys/dev/bluetooth/files.bluetooth
@@ -1,4 +1,4 @@
-# $OpenBSD: files.bluetooth,v 1.4 2007/07/23 22:42:27 mk Exp $
+# $OpenBSD: files.bluetooth,v 1.5 2007/09/01 17:06:26 xsa Exp $
#
# Config file and device description for machine-independent Bluetooth code.
# Included by ports that support Bluetooth host controllers.
@@ -6,3 +6,22 @@
device bthub {}
attach bthub at btbus
file dev/bluetooth/bthub.c bthub needs-flag
+
+# HID
+# HID "bus"
+define bthidbus {[ reportid = -1 ]}
+
+# HID Device
+device bthidev: bluetooth, bthidbus, hid
+attach bthidev at bthub
+file dev/bluetooth/bthidev.c bthidev
+
+# HID Mice
+device btms: hid, wsmousedev
+attach btms at bthidbus
+file dev/bluetooth/btms.c btms
+
+# HID Keyboard
+device btkbd: hid, wskbddev
+attach btkbd at bthidbus
+file dev/bluetooth/btkbd.c btkbd
diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h
index 1ce0cd31cbf..dad6a50b29b 100644
--- a/sys/dev/usb/usbhid.h
+++ b/sys/dev/usb/usbhid.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbhid.h,v 1.9 2007/06/09 11:06:53 mbalmer Exp $ */
+/* $OpenBSD: usbhid.h,v 1.10 2007/09/01 17:06:26 xsa Exp $ */
/* $NetBSD: usbhid.h,v 1.11 2001/12/28 00:20:24 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbhid.h,v 1.7 1999/11/17 22:33:51 n_hibma Exp $ */
@@ -172,6 +172,9 @@ typedef struct usb_hid_descriptor {
#define HUD_LED_COMPOSE 0x0004
#define HUD_LED_KANA 0x0005
+/* Usages, Consumer */
+#define HUC_AC_PAN 0x0238
+
#define HID_USAGE2(p, u) (((p) << 16) | u)
#define HID_GET_USAGE(u) ((u) & 0xffff)
#define HID_GET_USAGE_PAGE(u) (((u) >> 16) & 0xffff)
diff --git a/sys/dev/wscons/wsconsio.h b/sys/dev/wscons/wsconsio.h
index 7bd7c4d95b6..3ac638ab784 100644
--- a/sys/dev/wscons/wsconsio.h
+++ b/sys/dev/wscons/wsconsio.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: wsconsio.h,v 1.45 2007/05/08 20:38:20 robert Exp $ */
+/* $OpenBSD: wsconsio.h,v 1.46 2007/09/01 17:06:26 xsa Exp $ */
/* $NetBSD: wsconsio.h,v 1.74 2005/04/28 07:15:44 martin Exp $ */
/*
@@ -122,6 +122,7 @@ struct wscons_event {
#define WSKBD_TYPE_LUNA 15 /* OMRON Luna */
#define WSKBD_TYPE_ZAURUS 16 /* Sharp Zaurus */
#define WSKBD_TYPE_DOMAIN 17 /* Apollo Domain */
+#define WSKBD_TYPE_BLUETOOTH 18 /* Bluetooth keyboard */
/* Manipulate the keyboard bell. */
struct wskbd_bell_data {
@@ -203,6 +204,7 @@ struct wskbd_map_data {
#define WSMOUSE_TYPE_HIL 10 /* HP HIL */
#define WSMOUSE_TYPE_LUNA 11 /* OMRON Luna */
#define WSMOUSE_TYPE_DOMAIN 12 /* Apollo Domain */
+#define WSMOUSE_TYPE_BLUETOOTH 13 /* Bluetooth mouse */
/* Set resolution. Not applicable to all mouse types. */
#define WSMOUSEIO_SRES _IOW('W', 33, u_int)
diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h
index e965a9853d2..f30406b0100 100644
--- a/sys/sys/malloc.h
+++ b/sys/sys/malloc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: malloc.h,v 1.85 2007/06/17 20:06:10 jasper Exp $ */
+/* $OpenBSD: malloc.h,v 1.86 2007/09/01 17:06:26 xsa Exp $ */
/* $NetBSD: malloc.h,v 1.39 1998/07/12 19:52:01 augustss Exp $ */
/*
@@ -176,7 +176,9 @@
#define M_UDFFENTRY 141 /* UDF file entry */
#define M_UDFFID 142 /* UDF file id */
-#define M_LAST 143 /* Must be last type + 1 */
+#define M_BTHIDEV 143 /* Bluetooth HID */
+
+#define M_LAST 144 /* Must be last type + 1 */
#define INITKMEMNAMES { \
"free", /* 0 M_FREE */ \
@@ -307,6 +309,7 @@
"UDF mount", /* 140 M_UDFMOUNT */ \
"UDF file entry", /* 141 M_UDFFENTRY */ \
"UDF file id", /* 142 M_UDFFID */ \
+ "Bluetooth HID", /* 143 M_BTHIDEV */ \
}
struct kmemstats {