Bluetooth: Add request cmd_complete and cmd_status functions
This patch introduces functions to process the HCI request state when receiving HCI Command Status or Command Complete events. Some HCI commands, like Inquiry do not result in a Command complete event so special handling is needed for them. Inquiry is a particularly important one since it is the only forseeable "non-cmd_complete" command that will make good use of the request functionality, and its completion is either indicated by an Inquiry Complete event of a successful Command Complete for HCI_Inquiry_Cancel. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
This commit is contained in:
parent
11714b3d7a
commit
9238f36a5a
@ -1049,6 +1049,8 @@ struct hci_request {
|
||||
void hci_req_init(struct hci_request *req, struct hci_dev *hdev);
|
||||
int hci_req_run(struct hci_request *req, hci_req_complete_t complete);
|
||||
int hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param);
|
||||
void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status);
|
||||
void hci_req_cmd_status(struct hci_dev *hdev, u16 opcode, u8 status);
|
||||
|
||||
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
|
||||
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
|
||||
|
@ -3208,6 +3208,91 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static bool hci_req_is_complete(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = skb_peek(&hdev->cmd_q);
|
||||
if (!skb)
|
||||
return true;
|
||||
|
||||
return bt_cb(skb)->req.start;
|
||||
}
|
||||
|
||||
void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status)
|
||||
{
|
||||
hci_req_complete_t req_complete = NULL;
|
||||
struct sk_buff *skb;
|
||||
unsigned long flags;
|
||||
|
||||
BT_DBG("opcode 0x%04x status 0x%02x", opcode, status);
|
||||
|
||||
/* Check that the completed command really matches the last one
|
||||
* that was sent.
|
||||
*/
|
||||
if (!hci_sent_cmd_data(hdev, opcode))
|
||||
return;
|
||||
|
||||
/* If the command succeeded and there's still more commands in
|
||||
* this request the request is not yet complete.
|
||||
*/
|
||||
if (!status && !hci_req_is_complete(hdev))
|
||||
return;
|
||||
|
||||
/* If this was the last command in a request the complete
|
||||
* 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)
|
||||
goto call_complete;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
__skb_queue_head(&hdev->cmd_q, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
req_complete = bt_cb(skb)->req.complete;
|
||||
kfree_skb(skb);
|
||||
}
|
||||
spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
|
||||
|
||||
call_complete:
|
||||
if (req_complete)
|
||||
req_complete(hdev, status);
|
||||
}
|
||||
|
||||
void hci_req_cmd_status(struct hci_dev *hdev, u16 opcode, u8 status)
|
||||
{
|
||||
hci_req_complete_t req_complete = NULL;
|
||||
|
||||
BT_DBG("opcode 0x%04x status 0x%02x", opcode, status);
|
||||
|
||||
if (status) {
|
||||
hci_req_cmd_complete(hdev, opcode, status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* No need to handle success status if there are more commands */
|
||||
if (!hci_req_is_complete(hdev))
|
||||
return;
|
||||
|
||||
if (hdev->sent_cmd)
|
||||
req_complete = bt_cb(hdev->sent_cmd)->req.complete;
|
||||
|
||||
/* If the request doesn't have a complete callback or there
|
||||
* are other commands/requests in the hdev queue we consider
|
||||
* this request as completed.
|
||||
*/
|
||||
if (!req_complete || !skb_queue_empty(&hdev->cmd_q))
|
||||
hci_req_cmd_complete(hdev, opcode, status);
|
||||
}
|
||||
|
||||
static void hci_rx_work(struct work_struct *work)
|
||||
{
|
||||
struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
|
||||
|
@ -53,6 +53,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
hci_req_cmd_complete(hdev, HCI_OP_INQUIRY, status);
|
||||
hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
|
||||
|
||||
hci_conn_check_pending(hdev);
|
||||
@ -1692,6 +1693,7 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
hci_req_cmd_complete(hdev, HCI_OP_INQUIRY, status);
|
||||
hci_req_complete(hdev, HCI_OP_INQUIRY, status);
|
||||
|
||||
hci_conn_check_pending(hdev);
|
||||
@ -2254,6 +2256,7 @@ static void hci_qos_setup_complete_evt(struct hci_dev *hdev,
|
||||
static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_cmd_complete *ev = (void *) skb->data;
|
||||
u8 status = skb->data[sizeof(*ev)];
|
||||
__u16 opcode;
|
||||
|
||||
skb_pull(skb, sizeof(*ev));
|
||||
@ -2497,6 +2500,8 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
if (ev->opcode != HCI_OP_NOP)
|
||||
del_timer(&hdev->cmd_timer);
|
||||
|
||||
hci_req_cmd_complete(hdev, ev->opcode, status);
|
||||
|
||||
if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
|
||||
atomic_set(&hdev->cmd_cnt, 1);
|
||||
if (!skb_queue_empty(&hdev->cmd_q))
|
||||
@ -2590,6 +2595,8 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
if (ev->opcode != HCI_OP_NOP)
|
||||
del_timer(&hdev->cmd_timer);
|
||||
|
||||
hci_req_cmd_status(hdev, ev->opcode, ev->status);
|
||||
|
||||
if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
|
||||
atomic_set(&hdev->cmd_cnt, 1);
|
||||
if (!skb_queue_empty(&hdev->cmd_q))
|
||||
|
Loading…
Reference in New Issue
Block a user