struct hci_dev *hdev = file->private_data;
char buf[3];
- buf[0] = test_bit(HCI_DUT_MODE, &hdev->dbg_flags) ? 'Y': 'N';
+ buf[0] = hci_dev_test_flag(hdev, HCI_DUT_MODE) ? 'Y': 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
if (strtobool(buf, &enable))
return -EINVAL;
- if (enable == test_bit(HCI_DUT_MODE, &hdev->dbg_flags))
+ if (enable == hci_dev_test_flag(hdev, HCI_DUT_MODE))
return -EALREADY;
hci_req_lock(hdev);
if (err < 0)
return err;
- change_bit(HCI_DUT_MODE, &hdev->dbg_flags);
+ hci_dev_change_flag(hdev, HCI_DUT_MODE);
return count;
}
/* ---- HCI requests ---- */
-static void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode)
+static void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
+ struct sk_buff *skb)
{
BT_DBG("%s result 0x%2.2x", hdev->name, result);
if (hdev->req_status == HCI_REQ_PEND) {
hdev->req_result = result;
hdev->req_status = HCI_REQ_DONE;
+ if (skb)
+ hdev->req_skb = skb_get(skb);
wake_up_interruptible(&hdev->req_wait_q);
}
}
}
}
-static struct sk_buff *hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
- u8 event)
-{
- struct hci_ev_cmd_complete *ev;
- struct hci_event_hdr *hdr;
- struct sk_buff *skb;
-
- hci_dev_lock(hdev);
-
- skb = hdev->recv_evt;
- hdev->recv_evt = NULL;
-
- hci_dev_unlock(hdev);
-
- if (!skb)
- return ERR_PTR(-ENODATA);
-
- if (skb->len < sizeof(*hdr)) {
- BT_ERR("Too short HCI event");
- goto failed;
- }
-
- hdr = (void *) skb->data;
- skb_pull(skb, HCI_EVENT_HDR_SIZE);
-
- if (event) {
- if (hdr->evt != event)
- goto failed;
- return skb;
- }
-
- if (hdr->evt != HCI_EV_CMD_COMPLETE) {
- BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt);
- goto failed;
- }
-
- if (skb->len < sizeof(*ev)) {
- BT_ERR("Too short cmd_complete event");
- goto failed;
- }
-
- ev = (void *) skb->data;
- skb_pull(skb, sizeof(*ev));
-
- if (opcode == __le16_to_cpu(ev->opcode))
- return skb;
-
- BT_DBG("opcode doesn't match (0x%2.2x != 0x%2.2x)", opcode,
- __le16_to_cpu(ev->opcode));
-
-failed:
- kfree_skb(skb);
- return ERR_PTR(-ENODATA);
-}
-
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u8 event, u32 timeout)
{
DECLARE_WAITQUEUE(wait, current);
struct hci_request req;
+ struct sk_buff *skb;
int err = 0;
BT_DBG("%s", hdev->name);
add_wait_queue(&hdev->req_wait_q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
- err = hci_req_run(&req, hci_req_sync_complete);
+ err = hci_req_run_skb(&req, hci_req_sync_complete);
if (err < 0) {
remove_wait_queue(&hdev->req_wait_q, &wait);
set_current_state(TASK_RUNNING);
}
hdev->req_status = hdev->req_result = 0;
+ skb = hdev->req_skb;
+ hdev->req_skb = NULL;
BT_DBG("%s end: err %d", hdev->name, err);
- if (err < 0)
+ if (err < 0) {
+ kfree_skb(skb);
return ERR_PTR(err);
+ }
- return hci_get_cmd_complete(hdev, opcode, event);
+ if (!skb)
+ return ERR_PTR(-ENODATA);
+
+ return skb;
}
EXPORT_SYMBOL(__hci_cmd_sync_ev);
add_wait_queue(&hdev->req_wait_q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
- err = hci_req_run(&req, hci_req_sync_complete);
+ err = hci_req_run_skb(&req, hci_req_sync_complete);
if (err < 0) {
hdev->req_status = 0;
hdev->sent_cmd = NULL;
}
- kfree_skb(hdev->recv_evt);
- hdev->recv_evt = NULL;
-
/* After this point our queues are empty
* and no tasks are scheduled. */
hdev->close(hdev);
{
/* General inquiry access code (GIAC) */
u8 lap[3] = { 0x33, 0x8b, 0x9e };
- struct hci_request req;
struct hci_cp_inquiry cp;
int err;
break;
case DISCOV_TYPE_INTERLEAVED:
- hci_req_init(&req, hdev);
+ hci_dev_lock(hdev);
- memset(&cp, 0, sizeof(cp));
- memcpy(&cp.lap, lap, sizeof(cp.lap));
- cp.length = DISCOV_INTERLEAVED_INQUIRY_LEN;
- hci_req_add(&req, HCI_OP_INQUIRY, sizeof(cp), &cp);
+ if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
+ &hdev->quirks)) {
+ /* If we were running LE only scan, change discovery
+ * state. If we were running both LE and BR/EDR inquiry
+ * simultaneously, and BR/EDR inquiry is already
+ * finished, stop discovery, otherwise BR/EDR inquiry
+ * will stop discovery when finished.
+ */
+ if (!test_bit(HCI_INQUIRY, &hdev->flags))
+ hci_discovery_set_state(hdev,
+ DISCOVERY_STOPPED);
+ } else {
+ struct hci_request req;
- hci_dev_lock(hdev);
+ hci_inquiry_cache_flush(hdev);
- hci_inquiry_cache_flush(hdev);
+ hci_req_init(&req, hdev);
- err = hci_req_run(&req, inquiry_complete);
- if (err) {
- BT_ERR("Inquiry request failed: err %d", err);
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+ memset(&cp, 0, sizeof(cp));
+ memcpy(&cp.lap, lap, sizeof(cp.lap));
+ cp.length = DISCOV_INTERLEAVED_INQUIRY_LEN;
+ hci_req_add(&req, HCI_OP_INQUIRY, sizeof(cp), &cp);
+
+ err = hci_req_run(&req, inquiry_complete);
+ if (err) {
+ BT_ERR("Inquiry request failed: err %d", err);
+ hci_discovery_set_state(hdev,
+ DISCOVERY_STOPPED);
+ }
}
hci_dev_unlock(hdev);
void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 *bdaddr_type)
{
- if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) ||
+ if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
!bacmp(&hdev->bdaddr, BDADDR_ANY) ||
(!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
bacmp(&hdev->static_addr, BDADDR_ANY))) {
hci_init_sysfs(hdev);
discovery_init(hdev);
+ adv_info_init(hdev);
return hdev;
}
/* Unregister HCI device */
void hci_unregister_dev(struct hci_dev *hdev)
{
- int i, id;
+ int id;
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
hci_dev_do_close(hdev);
- for (i = 0; i < NUM_REASSEMBLY; i++)
- kfree_skb(hdev->reassembly[i]);
-
cancel_work_sync(&hdev->power_on);
if (!test_bit(HCI_INIT, &hdev->flags) &&
}
EXPORT_SYMBOL(hci_recv_frame);
-static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
- int count, __u8 index)
-{
- int len = 0;
- int hlen = 0;
- int remain = count;
- struct sk_buff *skb;
- struct bt_skb_cb *scb;
-
- if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ||
- index >= NUM_REASSEMBLY)
- return -EILSEQ;
-
- skb = hdev->reassembly[index];
-
- if (!skb) {
- switch (type) {
- case HCI_ACLDATA_PKT:
- len = HCI_MAX_FRAME_SIZE;
- hlen = HCI_ACL_HDR_SIZE;
- break;
- case HCI_EVENT_PKT:
- len = HCI_MAX_EVENT_SIZE;
- hlen = HCI_EVENT_HDR_SIZE;
- break;
- case HCI_SCODATA_PKT:
- len = HCI_MAX_SCO_SIZE;
- hlen = HCI_SCO_HDR_SIZE;
- break;
- }
-
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- scb = (void *) skb->cb;
- scb->expect = hlen;
- scb->pkt_type = type;
-
- hdev->reassembly[index] = skb;
- }
-
- while (count) {
- scb = (void *) skb->cb;
- len = min_t(uint, scb->expect, count);
-
- memcpy(skb_put(skb, len), data, len);
-
- count -= len;
- data += len;
- scb->expect -= len;
- remain = count;
-
- switch (type) {
- case HCI_EVENT_PKT:
- if (skb->len == HCI_EVENT_HDR_SIZE) {
- struct hci_event_hdr *h = hci_event_hdr(skb);
- scb->expect = h->plen;
-
- if (skb_tailroom(skb) < scb->expect) {
- kfree_skb(skb);
- hdev->reassembly[index] = NULL;
- return -ENOMEM;
- }
- }
- break;
-
- case HCI_ACLDATA_PKT:
- if (skb->len == HCI_ACL_HDR_SIZE) {
- struct hci_acl_hdr *h = hci_acl_hdr(skb);
- scb->expect = __le16_to_cpu(h->dlen);
-
- if (skb_tailroom(skb) < scb->expect) {
- kfree_skb(skb);
- hdev->reassembly[index] = NULL;
- return -ENOMEM;
- }
- }
- break;
-
- case HCI_SCODATA_PKT:
- if (skb->len == HCI_SCO_HDR_SIZE) {
- struct hci_sco_hdr *h = hci_sco_hdr(skb);
- scb->expect = h->dlen;
-
- if (skb_tailroom(skb) < scb->expect) {
- kfree_skb(skb);
- hdev->reassembly[index] = NULL;
- return -ENOMEM;
- }
- }
- break;
- }
-
- if (scb->expect == 0) {
- /* Complete frame */
-
- bt_cb(skb)->pkt_type = type;
- hci_recv_frame(hdev, skb);
-
- hdev->reassembly[index] = NULL;
- return remain;
- }
- }
-
- return remain;
-}
-
-#define STREAM_REASSEMBLY 0
-
-int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
-{
- int type;
- int rem = 0;
-
- while (count) {
- struct sk_buff *skb = hdev->reassembly[STREAM_REASSEMBLY];
-
- if (!skb) {
- struct { char type; } *pkt;
-
- /* Start of the frame */
- pkt = data;
- type = pkt->type;
-
- data++;
- count--;
- } else
- type = bt_cb(skb)->pkt_type;
-
- rem = hci_reassembly(hdev, type, data, count,
- STREAM_REASSEMBLY);
- if (rem < 0)
- return rem;
-
- data += (count - rem);
- count = rem;
- }
-
- return rem;
-}
-EXPORT_SYMBOL(hci_recv_stream_fragment);
-
/* ---- Interface to upper protocols ---- */
int hci_register_cb(struct hci_cb *cb)
}
}
-bool hci_req_pending(struct hci_dev *hdev)
-{
- return (hdev->req_status == HCI_REQ_PEND);
-}
-
/* Send HCI command */
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
const void *param)
/* Stand-alone HCI commands must be flagged as
* single-command requests.
*/
- bt_cb(skb)->req_start = 1;
+ bt_cb(skb)->req.start = true;
skb_queue_tail(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
if (!skb)
return true;
- return bt_cb(skb)->req_start;
+ return bt_cb(skb)->req.start;
}
static void hci_resend_last(struct hci_dev *hdev)
queue_work(hdev->workqueue, &hdev->cmd_work);
}
-void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status)
+void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status,
+ hci_req_complete_t *req_complete,
+ hci_req_complete_skb_t *req_complete_skb)
{
- hci_req_complete_t req_complete = NULL;
struct sk_buff *skb;
unsigned long flags;
* callback would be found in hdev->sent_cmd instead of the
* command queue (hdev->cmd_q).
*/
- if (hdev->sent_cmd) {
- req_complete = bt_cb(hdev->sent_cmd)->req_complete;
-
- if (req_complete) {
- /* We must set the complete callback to NULL to
- * avoid calling the callback more than once if
- * this function gets called again.
- */
- bt_cb(hdev->sent_cmd)->req_complete = NULL;
+ if (bt_cb(hdev->sent_cmd)->req.complete) {
+ *req_complete = bt_cb(hdev->sent_cmd)->req.complete;
+ return;
+ }
- goto call_complete;
- }
+ if (bt_cb(hdev->sent_cmd)->req.complete_skb) {
+ *req_complete_skb = bt_cb(hdev->sent_cmd)->req.complete_skb;
+ return;
}
/* Remove all pending commands belonging to this request */
spin_lock_irqsave(&hdev->cmd_q.lock, flags);
while ((skb = __skb_dequeue(&hdev->cmd_q))) {
- if (bt_cb(skb)->req_start) {
+ if (bt_cb(skb)->req.start) {
__skb_queue_head(&hdev->cmd_q, skb);
break;
}
- req_complete = bt_cb(skb)->req_complete;
+ *req_complete = bt_cb(skb)->req.complete;
+ *req_complete_skb = bt_cb(skb)->req.complete_skb;
kfree_skb(skb);
}
spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
-
-call_complete:
- if (req_complete)
- req_complete(hdev, status, status ? opcode : HCI_OP_NOP);
}
static void hci_rx_work(struct work_struct *work)