summaryrefslogtreecommitdiff
path: root/sys/netbt/hci_event.c
diff options
context:
space:
mode:
authorUwe Stuehler <uwe@cvs.openbsd.org>2008-11-22 04:42:59 +0000
committerUwe Stuehler <uwe@cvs.openbsd.org>2008-11-22 04:42:59 +0000
commitee43d395f23778051691eb4bfc357fa8a319dc36 (patch)
tree39f64994e1dc4a1a4688f1cd259f7a4ac2a1fa41 /sys/netbt/hci_event.c
parent40b98550b7357a09aad4dfe870e508bc05f03705 (diff)
Sync bluetooth with NetBSD
Diffstat (limited to 'sys/netbt/hci_event.c')
-rw-r--r--sys/netbt/hci_event.c113
1 files changed, 71 insertions, 42 deletions
diff --git a/sys/netbt/hci_event.c b/sys/netbt/hci_event.c
index e512521cab7..0c408e777b4 100644
--- a/sys/netbt/hci_event.c
+++ b/sys/netbt/hci_event.c
@@ -1,5 +1,5 @@
-/* $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 $ */
+/* $OpenBSD: hci_event.c,v 1.8 2008/11/22 04:42:58 uwe Exp $ */
+/* $NetBSD: hci_event.c,v 1.18 2008/04/24 11:38:37 ad Exp $ */
/*-
* Copyright (c) 2005 Iain Hibbert.
@@ -60,6 +60,7 @@ 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 *);
+static void hci_cmd_create_con(struct hci_unit *unit, uint8_t status);
#ifdef BLUETOOTH_DEBUG
int bluetooth_debug;
@@ -230,62 +231,53 @@ hci_event(struct mbuf *m, struct hci_unit *unit)
/*
* Command Status
*
- * Update our record of num_cmd_pkts then post-process any pending commands
- * and optionally restart cmd output on the unit.
+ * Restart command queue and post-process any pending commands
*/
static void
hci_event_command_status(struct hci_unit *unit, struct mbuf *m)
{
hci_command_status_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));
+ ep.opcode = letoh16(ep.opcode);
+
DPRINTFN(1, "(%s) opcode (%03x|%04x) status = 0x%x num_cmd_pkts = %d\n",
device_xname(unit->hci_dev),
- HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)),
+ HCI_OGF(ep.opcode), HCI_OCF(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;
+ hci_num_cmds(unit, ep.num_cmd_pkts);
/*
* post processing of pending commands
*/
- switch(letoh16(ep.opcode)) {
+ switch(ep.opcode) {
case HCI_CMD_CREATE_CON:
- switch (ep.status) {
- case 0x12: /* Invalid HCI command parameters */
- DPRINTF("(%s) Invalid HCI command parameters\n",
- 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);
- break;
- }
- break;
- default:
+ hci_cmd_create_con(unit, ep.status);
break;
- }
- while (unit->hci_num_cmd_pkts > 0 && !IF_IS_EMPTY(&unit->hci_cmdwait)) {
- IF_DEQUEUE(&unit->hci_cmdwait, m);
- hci_output_cmd(unit, m);
+ default:
+ if (ep.status == 0)
+ break;
+
+ DPRINTFN(1,
+ "CommandStatus opcode (%03x|%04x) failed (status=0x%02x)\n",
+ device_xname(unit->hci_dev),
+ HCI_OGF(ep.opcode), HCI_OCF(ep.opcode),
+ ep.status);
+
+ break;
}
}
/*
* Command Complete
*
- * Update our record of num_cmd_pkts then handle the completed command,
- * and optionally restart cmd output on the unit.
+ * Restart command queue and handle the completed command
*/
static void
hci_event_command_compl(struct hci_unit *unit, struct mbuf *m)
@@ -301,6 +293,8 @@ hci_event_command_compl(struct hci_unit *unit, struct mbuf *m)
device_xname(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)),
HCI_OCF(letoh16(ep.opcode)), ep.num_cmd_pkts);
+ hci_num_cmds(unit, 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
@@ -312,8 +306,6 @@ hci_event_command_compl(struct hci_unit *unit, struct mbuf *m)
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;
-
/*
* post processing of completed commands
*/
@@ -345,11 +337,6 @@ hci_event_command_compl(struct hci_unit *unit, struct mbuf *m)
default:
break;
}
-
- while (unit->hci_num_cmd_pkts > 0 && !IF_IS_EMPTY(&unit->hci_cmdwait)) {
- IF_DEQUEUE(&unit->hci_cmdwait, m);
- hci_output_cmd(unit, m);
- }
}
/*
@@ -856,7 +843,7 @@ hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m)
unit->hci_flags &= ~BTF_INIT_BDADDR;
- wakeup(unit);
+ wakeup(&unit->hci_init);
}
/*
@@ -884,7 +871,7 @@ hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m)
unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE;
- wakeup(unit);
+ wakeup(&unit->hci_init);
}
/*
@@ -972,7 +959,7 @@ hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m)
unit->hci_flags &= ~BTF_INIT_FEATURES;
- wakeup(unit);
+ wakeup(&unit->hci_init);
DPRINTFN(1, "%s: lmp_mask %4.4x, acl_mask %4.4x, sco_mask %4.4x\n",
device_xname(unit->hci_dev), unit->hci_lmp_mask,
@@ -1001,7 +988,7 @@ hci_cmd_read_local_ver(struct hci_unit *unit, struct mbuf *m)
if (rp.hci_version < HCI_SPEC_V12) {
unit->hci_flags &= ~BTF_INIT_COMMANDS;
- wakeup(unit);
+ wakeup(&unit->hci_init);
return;
}
@@ -1029,7 +1016,7 @@ hci_cmd_read_local_commands(struct hci_unit *unit, struct mbuf *m)
unit->hci_flags &= ~BTF_INIT_COMMANDS;
memcpy(unit->hci_cmds, rp.commands, HCI_COMMANDS_SIZE);
- wakeup(unit);
+ wakeup(&unit->hci_init);
}
/*
@@ -1080,3 +1067,45 @@ hci_cmd_reset(struct hci_unit *unit, struct mbuf *m)
if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_VER, NULL, 0))
return;
}
+
+/*
+ * process command_status event for create_con command
+ *
+ * a "Create Connection" command can sometimes fail to start for whatever
+ * reason and the command_status event returns failure but we get no
+ * indication of which connection failed (for instance in the case where
+ * we tried to open too many connections all at once) So, we keep a flag
+ * on the link to indicate pending status until the command_status event
+ * is returned to help us decide which needs to be failed.
+ *
+ * since created links are inserted at the tail of hci_links, we know that
+ * the first pending link we find will be the one that this command status
+ * refers to.
+ */
+static void
+hci_cmd_create_con(struct hci_unit *unit, uint8_t status)
+{
+ struct hci_link *link;
+
+ TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
+ if ((link->hl_flags & HCI_LINK_CREATE_CON) == 0)
+ continue;
+
+ link->hl_flags &= ~HCI_LINK_CREATE_CON;
+
+ switch(status) {
+ case 0x00: /* success */
+ break;
+
+ case 0x0c: /* "Command Disallowed" */
+ hci_link_free(link, EBUSY);
+ break;
+
+ default: /* some other trouble */
+ hci_link_free(link, /*EPROTO*/ECONNABORTED);
+ break;
+ }
+
+ return;
+ }
+}