summaryrefslogtreecommitdiff
path: root/sys/netbt/hci_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netbt/hci_event.c')
-rw-r--r--sys/netbt/hci_event.c328
1 files changed, 231 insertions, 97 deletions
diff --git a/sys/netbt/hci_event.c b/sys/netbt/hci_event.c
index b4be8a5aff4..e512521cab7 100644
--- a/sys/netbt/hci_event.c
+++ b/sys/netbt/hci_event.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: hci_event.c,v 1.6 2007/10/01 16:39:30 krw Exp $ */
-/* $NetBSD: hci_event.c,v 1.6 2007/04/21 06:15:23 plunky Exp $ */
+/* $OpenBSD: hci_event.c,v 1.7 2008/02/24 21:34:48 uwe Exp $ */
+/* $NetBSD: hci_event.c,v 1.14 2008/02/10 17:40:54 plunky Exp $ */
/*-
* Copyright (c) 2005 Iain Hibbert.
@@ -31,8 +31,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
@@ -45,6 +43,7 @@
#include <netbt/sco.h>
static void hci_event_inquiry_result(struct hci_unit *, struct mbuf *);
+static void hci_event_rssi_result(struct hci_unit *, struct mbuf *);
static void hci_event_command_status(struct hci_unit *, struct mbuf *);
static void hci_event_command_compl(struct hci_unit *, struct mbuf *);
static void hci_event_con_compl(struct hci_unit *, struct mbuf *);
@@ -54,13 +53,16 @@ static void hci_event_num_compl_pkts(struct hci_unit *, struct mbuf *);
static void hci_event_auth_compl(struct hci_unit *, struct mbuf *);
static void hci_event_encryption_change(struct hci_unit *, struct mbuf *);
static void hci_event_change_con_link_key_compl(struct hci_unit *, struct mbuf *);
+static void hci_event_read_clock_offset_compl(struct hci_unit *, struct mbuf *);
static void hci_cmd_read_bdaddr(struct hci_unit *, struct mbuf *);
static void hci_cmd_read_buffer_size(struct hci_unit *, struct mbuf *);
static void hci_cmd_read_local_features(struct hci_unit *, struct mbuf *);
+static void hci_cmd_read_local_ver(struct hci_unit *, struct mbuf *);
+static void hci_cmd_read_local_commands(struct hci_unit *, struct mbuf *);
static void hci_cmd_reset(struct hci_unit *, struct mbuf *);
#ifdef BLUETOOTH_DEBUG
-int bluetooth_debug = 0;
+int bluetooth_debug;
static const char *hci_eventnames[] = {
/* 0x00 */ "NULL",
@@ -98,7 +100,33 @@ static const char *hci_eventnames[] = {
/* 0x20 */ "PAGE SCAN REP MODE CHANGE",
/* 0x21 */ "FLOW SPECIFICATION COMPLETE",
/* 0x22 */ "RSSI RESULT",
-/* 0x23 */ "READ REMOTE EXT FEATURES"
+/* 0x23 */ "READ REMOTE EXT FEATURES",
+/* 0x24 */ "UNKNOWN",
+/* 0x25 */ "UNKNOWN",
+/* 0x26 */ "UNKNOWN",
+/* 0x27 */ "UNKNOWN",
+/* 0x28 */ "UNKNOWN",
+/* 0x29 */ "UNKNOWN",
+/* 0x2a */ "UNKNOWN",
+/* 0x2b */ "UNKNOWN",
+/* 0x2c */ "SCO CON COMPLETE",
+/* 0x2d */ "SCO CON CHANGED",
+/* 0x2e */ "SNIFF SUBRATING",
+/* 0x2f */ "EXTENDED INQUIRY RESULT",
+/* 0x30 */ "ENCRYPTION KEY REFRESH",
+/* 0x31 */ "IO CAPABILITY REQUEST",
+/* 0x32 */ "IO CAPABILITY RESPONSE",
+/* 0x33 */ "USER CONFIRM REQUEST",
+/* 0x34 */ "USER PASSKEY REQUEST",
+/* 0x35 */ "REMOTE OOB DATA REQUEST",
+/* 0x36 */ "SIMPLE PAIRING COMPLETE",
+/* 0x37 */ "UNKNOWN",
+/* 0x38 */ "LINK SUPERVISION TIMEOUT CHANGED",
+/* 0x39 */ "ENHANCED FLUSH COMPLETE",
+/* 0x3a */ "UNKNOWN",
+/* 0x3b */ "USER PASSKEY NOTIFICATION",
+/* 0x3c */ "KEYPRESS NOTIFICATION",
+/* 0x3d */ "REMOTE HOST FEATURES NOTIFICATION",
};
static const char *
@@ -109,12 +137,6 @@ hci_eventstr(unsigned int event)
return hci_eventnames[event];
switch (event) {
- case HCI_EVENT_SCO_CON_COMPL: /* 0x2c */
- return "SCO CON COMPLETE";
-
- case HCI_EVENT_SCO_CON_CHANGED: /* 0x2d */
- return "SCO CON CHANGED";
-
case HCI_EVENT_BT_LOGO: /* 0xfe */
return "BT_LOGO";
@@ -122,7 +144,7 @@ hci_eventstr(unsigned int event)
return "VENDOR";
}
- return "UNRECOGNISED";
+ return "UNKNOWN";
}
#endif /* BLUETOOTH_DEBUG */
@@ -132,7 +154,6 @@ hci_eventstr(unsigned int event)
* We will free the mbuf at the end, no need for any sub
* functions to handle that. We kind of assume that the
* device sends us valid events.
- * XXX "kind of"? This needs to be fixed.
*/
void
hci_event(struct mbuf *m, struct hci_unit *unit)
@@ -147,7 +168,8 @@ hci_event(struct mbuf *m, struct hci_unit *unit)
KASSERT(hdr.type == HCI_EVENT_PKT);
- DPRINTFN(1, "(%s) event %s\n", unit->hci_devname, hci_eventstr(hdr.event));
+ DPRINTFN(1, "(%s) event %s\n",
+ device_xname(unit->hci_dev), hci_eventstr(hdr.event));
switch(hdr.event) {
case HCI_EVENT_COMMAND_STATUS:
@@ -166,6 +188,10 @@ hci_event(struct mbuf *m, struct hci_unit *unit)
hci_event_inquiry_result(unit, m);
break;
+ case HCI_EVENT_RSSI_RESULT:
+ hci_event_rssi_result(unit, m);
+ break;
+
case HCI_EVENT_CON_COMPL:
hci_event_con_compl(unit, m);
break;
@@ -190,39 +216,11 @@ hci_event(struct mbuf *m, struct hci_unit *unit)
hci_event_change_con_link_key_compl(unit, m);
break;
- case HCI_EVENT_SCO_CON_COMPL:
- case HCI_EVENT_INQUIRY_COMPL:
- case HCI_EVENT_REMOTE_NAME_REQ_COMPL:
- case HCI_EVENT_MASTER_LINK_KEY_COMPL:
- case HCI_EVENT_READ_REMOTE_FEATURES_COMPL:
- case HCI_EVENT_READ_REMOTE_VER_INFO_COMPL:
- case HCI_EVENT_QOS_SETUP_COMPL:
- case HCI_EVENT_HARDWARE_ERROR:
- case HCI_EVENT_FLUSH_OCCUR:
- case HCI_EVENT_ROLE_CHANGE:
- case HCI_EVENT_MODE_CHANGE:
- case HCI_EVENT_RETURN_LINK_KEYS:
- case HCI_EVENT_PIN_CODE_REQ:
- case HCI_EVENT_LINK_KEY_REQ:
- case HCI_EVENT_LINK_KEY_NOTIFICATION:
- case HCI_EVENT_LOOPBACK_COMMAND:
- case HCI_EVENT_DATA_BUFFER_OVERFLOW:
- case HCI_EVENT_MAX_SLOT_CHANGE:
case HCI_EVENT_READ_CLOCK_OFFSET_COMPL:
- case HCI_EVENT_CON_PKT_TYPE_CHANGED:
- case HCI_EVENT_QOS_VIOLATION:
- case HCI_EVENT_PAGE_SCAN_MODE_CHANGE:
- case HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE:
- case HCI_EVENT_FLOW_SPECIFICATION_COMPL:
- case HCI_EVENT_RSSI_RESULT:
- case HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES:
- case HCI_EVENT_SCO_CON_CHANGED:
- case HCI_EVENT_BT_LOGO:
- case HCI_EVENT_VENDOR:
+ hci_event_read_clock_offset_compl(unit, m);
break;
default:
- UNKNOWN(hdr.event);
break;
}
@@ -246,11 +244,16 @@ hci_event_command_status(struct hci_unit *unit, struct mbuf *m)
m_adj(m, sizeof(ep));
DPRINTFN(1, "(%s) opcode (%03x|%04x) status = 0x%x num_cmd_pkts = %d\n",
- unit->hci_devname,
+ device_xname(unit->hci_dev),
HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)),
ep.status,
ep.num_cmd_pkts);
+ if (ep.status > 0)
+ printf("%s: CommandStatus opcode (%03x|%04x) failed (status=0x%02x)\n",
+ device_xname(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)),
+ HCI_OCF(letoh16(ep.opcode)), ep.status);
+
unit->hci_num_cmd_pkts = ep.num_cmd_pkts;
/*
@@ -261,7 +264,7 @@ hci_event_command_status(struct hci_unit *unit, struct mbuf *m)
switch (ep.status) {
case 0x12: /* Invalid HCI command parameters */
DPRINTF("(%s) Invalid HCI command parameters\n",
- unit->hci_devname);
+ device_xname(unit->hci_dev));
while ((link = hci_link_lookup_state(unit,
HCI_LINK_ACL, HCI_LINK_WAIT_CONNECT)) != NULL)
hci_link_free(link, ECONNABORTED);
@@ -288,15 +291,26 @@ static void
hci_event_command_compl(struct hci_unit *unit, struct mbuf *m)
{
hci_command_compl_ep ep;
+ hci_status_rp rp;
KASSERT(m->m_pkthdr.len >= sizeof(ep));
m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
m_adj(m, sizeof(ep));
DPRINTFN(1, "(%s) opcode (%03x|%04x) num_cmd_pkts = %d\n",
- unit->hci_devname,
- HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)),
- ep.num_cmd_pkts);
+ device_xname(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)),
+ HCI_OCF(letoh16(ep.opcode)), ep.num_cmd_pkts);
+
+ /*
+ * I am not sure if this is completely correct, it is not guaranteed
+ * that a command_complete packet will contain the status though most
+ * do seem to.
+ */
+ m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
+ if (rp.status > 0)
+ printf("%s: CommandComplete opcode (%03x|%04x) failed (status=0x%02x)\n",
+ device_xname(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)),
+ HCI_OCF(letoh16(ep.opcode)), rp.status);
unit->hci_num_cmd_pkts = ep.num_cmd_pkts;
@@ -316,6 +330,14 @@ hci_event_command_compl(struct hci_unit *unit, struct mbuf *m)
hci_cmd_read_local_features(unit, m);
break;
+ case HCI_CMD_READ_LOCAL_VER:
+ hci_cmd_read_local_ver(unit, m);
+ break;
+
+ case HCI_CMD_READ_LOCAL_COMMANDS:
+ hci_cmd_read_local_commands(unit, m);
+ break;
+
case HCI_CMD_RESET:
hci_cmd_reset(unit, m);
break;
@@ -372,9 +394,9 @@ hci_event_num_compl_pkts(struct hci_unit *unit, struct mbuf *m)
} else {
/* XXX need to issue Read_Buffer_Size or Reset? */
printf("%s: unknown handle %d! "
- "(losing track of %d packet buffer%s)\n",
- unit->hci_devname, handle,
- num, (num == 1 ? "" : "s"));
+ "(losing track of %d packet buffer%s)\n",
+ device_xname(unit->hci_dev), handle,
+ num, (num == 1 ? "" : "s"));
}
}
@@ -415,42 +437,68 @@ static void
hci_event_inquiry_result(struct hci_unit *unit, struct mbuf *m)
{
hci_inquiry_result_ep ep;
+ hci_inquiry_response ir;
struct hci_memo *memo;
- bdaddr_t bdaddr;
KASSERT(m->m_pkthdr.len >= sizeof(ep));
m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
m_adj(m, sizeof(ep));
- DPRINTFN(1, "%d response%s\n", ep.num_responses,
- (ep.num_responses == 1 ? "" : "s"));
+ DPRINTFN(1, "(%s) %d response%s\n", device_xname(unit->hci_dev),
+ ep.num_responses, (ep.num_responses == 1 ? "" : "s"));
while(ep.num_responses--) {
- m_copydata(m, 0, sizeof(bdaddr_t), (caddr_t)&bdaddr);
+ KASSERT(m->m_pkthdr.len >= sizeof(ir));
+ m_copydata(m, 0, sizeof(ir), (caddr_t)&ir);
+ m_adj(m, sizeof(ir));
DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
- bdaddr.b[5], bdaddr.b[4], bdaddr.b[3],
- bdaddr.b[2], bdaddr.b[1], bdaddr.b[0]);
-
- memo = hci_memo_find(unit, &bdaddr);
- if (memo == NULL) {
- memo = malloc(sizeof(*memo), M_BLUETOOTH,
- M_NOWAIT | M_ZERO);
- if (memo == NULL) {
- DPRINTFN(0, "out of memo memory!\n");
- break;
- }
-
- LIST_INSERT_HEAD(&unit->hci_memos, memo, next);
+ ir.bdaddr.b[5], ir.bdaddr.b[4], ir.bdaddr.b[3],
+ ir.bdaddr.b[2], ir.bdaddr.b[1], ir.bdaddr.b[0]);
+
+ memo = hci_memo_new(unit, &ir.bdaddr);
+ if (memo != NULL) {
+ memo->page_scan_rep_mode = ir.page_scan_rep_mode;
+ memo->page_scan_mode = ir.page_scan_mode;
+ memo->clock_offset = ir.clock_offset;
}
+ }
+}
- microtime(&memo->time);
- m_copydata(m, 0, sizeof(hci_inquiry_response),
- (caddr_t)&memo->response);
- m_adj(m, sizeof(hci_inquiry_response));
+/*
+ * Inquiry Result with RSSI
+ *
+ * as above but different packet when RSSI result is enabled
+ */
+static void
+hci_event_rssi_result(struct hci_unit *unit, struct mbuf *m)
+{
+ hci_rssi_result_ep ep;
+ hci_rssi_response rr;
+ struct hci_memo *memo;
+
+ KASSERT(m->m_pkthdr.len >= sizeof(ep));
+ m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
+ m_adj(m, sizeof(ep));
+
+ DPRINTFN(1, "%d response%s\n", ep.num_responses,
+ (ep.num_responses == 1 ? "" : "s"));
+
+ while(ep.num_responses--) {
+ KASSERT(m->m_pkthdr.len >= sizeof(rr));
+ m_copydata(m, 0, sizeof(rr), (caddr_t)&rr);
+ m_adj(m, sizeof(rr));
- memo->response.clock_offset =
- letoh16(memo->response.clock_offset);
+ DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
+ rr.bdaddr.b[5], rr.bdaddr.b[4], rr.bdaddr.b[3],
+ rr.bdaddr.b[2], rr.bdaddr.b[1], rr.bdaddr.b[0]);
+
+ memo = hci_memo_new(unit, &rr.bdaddr);
+ if (memo != NULL) {
+ memo->page_scan_rep_mode = rr.page_scan_rep_mode;
+ memo->page_scan_mode = 0;
+ memo->clock_offset = rr.clock_offset;
+ }
}
}
@@ -475,7 +523,7 @@ hci_event_con_compl(struct hci_unit *unit, struct mbuf *m)
DPRINTFN(1, "(%s) %s connection complete for "
"%02x:%02x:%02x:%02x:%02x:%02x status %#x\n",
- unit->hci_devname,
+ device_xname(unit->hci_dev),
(ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"),
ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
@@ -535,7 +583,13 @@ hci_event_con_compl(struct hci_unit *unit, struct mbuf *m)
&cp, sizeof(cp));
if (err)
printf("%s: Warning, could not write link policy\n",
- unit->hci_devname);
+ device_xname(unit->hci_dev));
+
+ err = hci_send_cmd(unit, HCI_CMD_READ_CLOCK_OFFSET,
+ &cp.con_handle, sizeof(cp.con_handle));
+ if (err)
+ printf("%s: Warning, could not read clock offset\n",
+ device_xname(unit->hci_dev));
err = hci_acl_setmode(link);
if (err == EINPROGRESS)
@@ -565,7 +619,8 @@ hci_event_discon_compl(struct hci_unit *unit, struct mbuf *m)
ep.con_handle = letoh16(ep.con_handle);
- DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
+ DPRINTFN(1, "(%s) handle #%d, status=0x%x\n",
+ device_xname(unit->hci_dev), ep.con_handle, ep.status);
link = hci_link_lookup_handle(unit, HCI_CON_HANDLE(ep.con_handle));
if (link)
@@ -590,12 +645,13 @@ hci_event_con_req(struct hci_unit *unit, struct mbuf *m)
m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
m_adj(m, sizeof(ep));
- DPRINTFN(1, "bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
+ DPRINTFN(1, "(%s) bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
"class %2.2x%2.2x%2.2x type %s\n",
- ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
- ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
- ep.uclass[0], ep.uclass[1], ep.uclass[2],
- ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO");
+ device_xname(unit->hci_dev),
+ ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
+ ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
+ ep.uclass[0], ep.uclass[1], ep.uclass[2],
+ ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO");
if (ep.link_type == HCI_LINK_ACL)
link = hci_acl_newconn(unit, &ep.bdaddr);
@@ -639,7 +695,8 @@ hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m)
ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
- DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
+ DPRINTFN(1, "(%s) handle #%d, status=0x%x\n",
+ device_xname(unit->hci_dev), ep.con_handle, ep.status);
link = hci_link_lookup_handle(unit, ep.con_handle);
if (link == NULL || link->hl_type != HCI_LINK_ACL)
@@ -681,8 +738,9 @@ hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m)
ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
- DPRINTFN(1, "handle #%d, status=0x%x, encryption_enable=0x%x\n",
- ep.con_handle, ep.status, ep.encryption_enable);
+ DPRINTFN(1, "(%s) handle #%d, status=0x%x, encryption_enable=0x%x\n",
+ device_xname(unit->hci_dev), ep.con_handle, ep.status,
+ ep.encryption_enable);
link = hci_link_lookup_handle(unit, ep.con_handle);
if (link == NULL || link->hl_type != HCI_LINK_ACL)
@@ -725,7 +783,8 @@ hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m)
ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
- DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
+ DPRINTFN(1, "(%s) handle #%d, status=0x%x\n",
+ device_xname(unit->hci_dev), ep.con_handle, ep.status);
link = hci_link_lookup_handle(unit, ep.con_handle);
if (link == NULL || link->hl_type != HCI_LINK_ACL)
@@ -748,13 +807,40 @@ hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m)
}
/*
+ * Read Clock Offset Complete
+ *
+ * We keep a note of the clock offset of remote devices when a
+ * link is made, in order to facilitate reconnections to the device
+ */
+static void
+hci_event_read_clock_offset_compl(struct hci_unit *unit, struct mbuf *m)
+{
+ hci_read_clock_offset_compl_ep ep;
+ struct hci_link *link;
+
+ KASSERT(m->m_pkthdr.len >= sizeof(ep));
+ m_copydata(m, 0, sizeof(ep), (caddr_t)&ep);
+ m_adj(m, sizeof(ep));
+
+ DPRINTFN(1, "handle #%d, offset=%u, status=0x%x\n",
+ letoh16(ep.con_handle), letoh16(ep.clock_offset), ep.status);
+
+ ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
+ link = hci_link_lookup_handle(unit, ep.con_handle);
+
+ if (ep.status != 0 || link == NULL)
+ return;
+
+ link->hl_clock = ep.clock_offset;
+}
+
+/*
* process results of read_bdaddr command_complete event
*/
static void
hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m)
{
hci_read_bdaddr_rp rp;
- int s;
KASSERT(m->m_pkthdr.len >= sizeof(rp));
m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
@@ -768,9 +854,7 @@ hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m)
bdaddr_copy(&unit->hci_bdaddr, &rp.bdaddr);
- s = splraiseipl(unit->hci_ipl);
unit->hci_flags &= ~BTF_INIT_BDADDR;
- splx(s);
wakeup(unit);
}
@@ -782,7 +866,6 @@ static void
hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m)
{
hci_read_buffer_size_rp rp;
- int s;
KASSERT(m->m_pkthdr.len >= sizeof(rp));
m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
@@ -799,9 +882,7 @@ hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m)
unit->hci_max_sco_size = rp.max_sco_size;
unit->hci_num_sco_pkts = letoh16(rp.num_sco_pkts);
- s = splraiseipl(unit->hci_ipl);
unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE;
- splx(s);
wakeup(unit);
}
@@ -813,7 +894,6 @@ static void
hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m)
{
hci_read_local_features_rp rp;
- int s;
KASSERT(m->m_pkthdr.len >= sizeof(rp));
m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
@@ -890,18 +970,69 @@ hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m)
/* XXX what do 2MBPS/3MBPS/3SLOT eSCO mean? */
- s = splraiseipl(unit->hci_ipl);
unit->hci_flags &= ~BTF_INIT_FEATURES;
- splx(s);
wakeup(unit);
DPRINTFN(1, "%s: lmp_mask %4.4x, acl_mask %4.4x, sco_mask %4.4x\n",
- unit->hci_devname, unit->hci_lmp_mask,
+ device_xname(unit->hci_dev), unit->hci_lmp_mask,
unit->hci_acl_mask, unit->hci_sco_mask);
}
/*
+ * process results of read_local_ver command_complete event
+ *
+ * reading local supported commands is only supported from 1.2 spec
+ */
+static void
+hci_cmd_read_local_ver(struct hci_unit *unit, struct mbuf *m)
+{
+ hci_read_local_ver_rp rp;
+
+ KASSERT(m->m_pkthdr.len >= sizeof(rp));
+ m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
+ m_adj(m, sizeof(rp));
+
+ if (rp.status != 0)
+ return;
+
+ if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0)
+ return;
+
+ if (rp.hci_version < HCI_SPEC_V12) {
+ unit->hci_flags &= ~BTF_INIT_COMMANDS;
+ wakeup(unit);
+ return;
+ }
+
+ hci_send_cmd(unit, HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0);
+}
+
+/*
+ * process results of read_local_commands command_complete event
+ */
+static void
+hci_cmd_read_local_commands(struct hci_unit *unit, struct mbuf *m)
+{
+ hci_read_local_commands_rp rp;
+
+ KASSERT(m->m_pkthdr.len >= sizeof(rp));
+ m_copydata(m, 0, sizeof(rp), (caddr_t)&rp);
+ m_adj(m, sizeof(rp));
+
+ if (rp.status != 0)
+ return;
+
+ if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0)
+ return;
+
+ unit->hci_flags &= ~BTF_INIT_COMMANDS;
+ memcpy(unit->hci_cmds, rp.commands, HCI_COMMANDS_SIZE);
+
+ wakeup(unit);
+}
+
+/*
* process results of reset command_complete event
*
* This has killed all the connections, so close down anything we have left,
@@ -945,4 +1076,7 @@ hci_cmd_reset(struct hci_unit *unit, struct mbuf *m)
if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_FEATURES, NULL, 0))
return;
+
+ if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_VER, NULL, 0))
+ return;
}