diff options
-rw-r--r-- | include/net/bluetooth/hci_core.h | 3 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 102 |
2 files changed, 105 insertions, 0 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 89eda2ef2380..755743d508aa 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -1057,6 +1057,9 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete); | |||
1057 | void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param); | 1057 | void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param); |
1058 | void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status); | 1058 | void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status); |
1059 | 1059 | ||
1060 | struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen, | ||
1061 | void *param, u32 timeout); | ||
1062 | |||
1060 | int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); | 1063 | int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); |
1061 | void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); | 1064 | void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); |
1062 | void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); | 1065 | void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7c323bd112ff..8b2d543fb143 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -79,6 +79,108 @@ static void hci_req_cancel(struct hci_dev *hdev, int err) | |||
79 | } | 79 | } |
80 | } | 80 | } |
81 | 81 | ||
82 | struct sk_buff *hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode) | ||
83 | { | ||
84 | struct hci_ev_cmd_complete *ev; | ||
85 | struct hci_event_hdr *hdr; | ||
86 | struct sk_buff *skb; | ||
87 | |||
88 | hci_dev_lock(hdev); | ||
89 | |||
90 | skb = hdev->recv_evt; | ||
91 | hdev->recv_evt = NULL; | ||
92 | |||
93 | hci_dev_unlock(hdev); | ||
94 | |||
95 | if (!skb) | ||
96 | return ERR_PTR(-ENODATA); | ||
97 | |||
98 | if (skb->len < sizeof(*hdr)) { | ||
99 | BT_ERR("Too short HCI event"); | ||
100 | goto failed; | ||
101 | } | ||
102 | |||
103 | hdr = (void *) skb->data; | ||
104 | skb_pull(skb, HCI_EVENT_HDR_SIZE); | ||
105 | |||
106 | if (hdr->evt != HCI_EV_CMD_COMPLETE) { | ||
107 | BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt); | ||
108 | goto failed; | ||
109 | } | ||
110 | |||
111 | if (skb->len < sizeof(*ev)) { | ||
112 | BT_ERR("Too short cmd_complete event"); | ||
113 | goto failed; | ||
114 | } | ||
115 | |||
116 | ev = (void *) skb->data; | ||
117 | skb_pull(skb, sizeof(*ev)); | ||
118 | |||
119 | if (opcode == __le16_to_cpu(ev->opcode)) | ||
120 | return skb; | ||
121 | |||
122 | BT_DBG("opcode doesn't match (0x%2.2x != 0x%2.2x)", opcode, | ||
123 | __le16_to_cpu(ev->opcode)); | ||
124 | |||
125 | failed: | ||
126 | kfree_skb(skb); | ||
127 | return ERR_PTR(-ENODATA); | ||
128 | } | ||
129 | |||
130 | struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen, | ||
131 | void *param, u32 timeout) | ||
132 | { | ||
133 | DECLARE_WAITQUEUE(wait, current); | ||
134 | struct hci_request req; | ||
135 | int err = 0; | ||
136 | |||
137 | BT_DBG("%s", hdev->name); | ||
138 | |||
139 | hci_req_init(&req, hdev); | ||
140 | |||
141 | hci_req_add(&req, opcode, plen, param); | ||
142 | |||
143 | hdev->req_status = HCI_REQ_PEND; | ||
144 | |||
145 | err = hci_req_run(&req, hci_req_sync_complete); | ||
146 | if (err < 0) | ||
147 | return ERR_PTR(err); | ||
148 | |||
149 | add_wait_queue(&hdev->req_wait_q, &wait); | ||
150 | set_current_state(TASK_INTERRUPTIBLE); | ||
151 | |||
152 | schedule_timeout(timeout); | ||
153 | |||
154 | remove_wait_queue(&hdev->req_wait_q, &wait); | ||
155 | |||
156 | if (signal_pending(current)) | ||
157 | return ERR_PTR(-EINTR); | ||
158 | |||
159 | switch (hdev->req_status) { | ||
160 | case HCI_REQ_DONE: | ||
161 | err = -bt_to_errno(hdev->req_result); | ||
162 | break; | ||
163 | |||
164 | case HCI_REQ_CANCELED: | ||
165 | err = -hdev->req_result; | ||
166 | break; | ||
167 | |||
168 | default: | ||
169 | err = -ETIMEDOUT; | ||
170 | break; | ||
171 | } | ||
172 | |||
173 | hdev->req_status = hdev->req_result = 0; | ||
174 | |||
175 | BT_DBG("%s end: err %d", hdev->name, err); | ||
176 | |||
177 | if (err < 0) | ||
178 | return ERR_PTR(err); | ||
179 | |||
180 | return hci_get_cmd_complete(hdev, opcode); | ||
181 | } | ||
182 | EXPORT_SYMBOL(__hci_cmd_sync); | ||
183 | |||
82 | /* Execute request and wait for completion. */ | 184 | /* Execute request and wait for completion. */ |
83 | static int __hci_req_sync(struct hci_dev *hdev, | 185 | static int __hci_req_sync(struct hci_dev *hdev, |
84 | void (*func)(struct hci_request *req, | 186 | void (*func)(struct hci_request *req, |