diff options
Diffstat (limited to 'net/bluetooth/hidp/core.c')
-rw-r--r-- | net/bluetooth/hidp/core.c | 119 |
1 files changed, 60 insertions, 59 deletions
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 18e7f5a43dc..fc6ec1e7265 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c | |||
@@ -243,6 +243,39 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb) | |||
243 | input_sync(dev); | 243 | input_sync(dev); |
244 | } | 244 | } |
245 | 245 | ||
246 | static int __hidp_send_ctrl_message(struct hidp_session *session, | ||
247 | unsigned char hdr, unsigned char *data, int size) | ||
248 | { | ||
249 | struct sk_buff *skb; | ||
250 | |||
251 | BT_DBG("session %p data %p size %d", session, data, size); | ||
252 | |||
253 | if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) { | ||
254 | BT_ERR("Can't allocate memory for new frame"); | ||
255 | return -ENOMEM; | ||
256 | } | ||
257 | |||
258 | *skb_put(skb, 1) = hdr; | ||
259 | if (data && size > 0) | ||
260 | memcpy(skb_put(skb, size), data, size); | ||
261 | |||
262 | skb_queue_tail(&session->ctrl_transmit, skb); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static inline int hidp_send_ctrl_message(struct hidp_session *session, | ||
268 | unsigned char hdr, unsigned char *data, int size) | ||
269 | { | ||
270 | int err; | ||
271 | |||
272 | err = __hidp_send_ctrl_message(session, hdr, data, size); | ||
273 | |||
274 | hidp_schedule(session); | ||
275 | |||
276 | return err; | ||
277 | } | ||
278 | |||
246 | static int hidp_queue_report(struct hidp_session *session, | 279 | static int hidp_queue_report(struct hidp_session *session, |
247 | unsigned char *data, int size) | 280 | unsigned char *data, int size) |
248 | { | 281 | { |
@@ -282,7 +315,9 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep | |||
282 | 315 | ||
283 | static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count) | 316 | static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count) |
284 | { | 317 | { |
285 | if (hidp_queue_report(hid->driver_data, data, count)) | 318 | if (hidp_send_ctrl_message(hid->driver_data, |
319 | HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE, | ||
320 | data, count)) | ||
286 | return -ENOMEM; | 321 | return -ENOMEM; |
287 | return count; | 322 | return count; |
288 | } | 323 | } |
@@ -307,39 +342,6 @@ static inline void hidp_del_timer(struct hidp_session *session) | |||
307 | del_timer(&session->timer); | 342 | del_timer(&session->timer); |
308 | } | 343 | } |
309 | 344 | ||
310 | static int __hidp_send_ctrl_message(struct hidp_session *session, | ||
311 | unsigned char hdr, unsigned char *data, int size) | ||
312 | { | ||
313 | struct sk_buff *skb; | ||
314 | |||
315 | BT_DBG("session %p data %p size %d", session, data, size); | ||
316 | |||
317 | if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) { | ||
318 | BT_ERR("Can't allocate memory for new frame"); | ||
319 | return -ENOMEM; | ||
320 | } | ||
321 | |||
322 | *skb_put(skb, 1) = hdr; | ||
323 | if (data && size > 0) | ||
324 | memcpy(skb_put(skb, size), data, size); | ||
325 | |||
326 | skb_queue_tail(&session->ctrl_transmit, skb); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static inline int hidp_send_ctrl_message(struct hidp_session *session, | ||
332 | unsigned char hdr, unsigned char *data, int size) | ||
333 | { | ||
334 | int err; | ||
335 | |||
336 | err = __hidp_send_ctrl_message(session, hdr, data, size); | ||
337 | |||
338 | hidp_schedule(session); | ||
339 | |||
340 | return err; | ||
341 | } | ||
342 | |||
343 | static void hidp_process_handshake(struct hidp_session *session, | 345 | static void hidp_process_handshake(struct hidp_session *session, |
344 | unsigned char param) | 346 | unsigned char param) |
345 | { | 347 | { |
@@ -701,29 +703,9 @@ static void hidp_close(struct hid_device *hid) | |||
701 | static int hidp_parse(struct hid_device *hid) | 703 | static int hidp_parse(struct hid_device *hid) |
702 | { | 704 | { |
703 | struct hidp_session *session = hid->driver_data; | 705 | struct hidp_session *session = hid->driver_data; |
704 | struct hidp_connadd_req *req = session->req; | ||
705 | unsigned char *buf; | ||
706 | int ret; | ||
707 | |||
708 | buf = kmalloc(req->rd_size, GFP_KERNEL); | ||
709 | if (!buf) | ||
710 | return -ENOMEM; | ||
711 | |||
712 | if (copy_from_user(buf, req->rd_data, req->rd_size)) { | ||
713 | kfree(buf); | ||
714 | return -EFAULT; | ||
715 | } | ||
716 | |||
717 | ret = hid_parse_report(session->hid, buf, req->rd_size); | ||
718 | |||
719 | kfree(buf); | ||
720 | |||
721 | if (ret) | ||
722 | return ret; | ||
723 | 706 | ||
724 | session->req = NULL; | 707 | return hid_parse_report(session->hid, session->rd_data, |
725 | 708 | session->rd_size); | |
726 | return 0; | ||
727 | } | 709 | } |
728 | 710 | ||
729 | static int hidp_start(struct hid_device *hid) | 711 | static int hidp_start(struct hid_device *hid) |
@@ -768,12 +750,24 @@ static int hidp_setup_hid(struct hidp_session *session, | |||
768 | bdaddr_t src, dst; | 750 | bdaddr_t src, dst; |
769 | int err; | 751 | int err; |
770 | 752 | ||
753 | session->rd_data = kzalloc(req->rd_size, GFP_KERNEL); | ||
754 | if (!session->rd_data) | ||
755 | return -ENOMEM; | ||
756 | |||
757 | if (copy_from_user(session->rd_data, req->rd_data, req->rd_size)) { | ||
758 | err = -EFAULT; | ||
759 | goto fault; | ||
760 | } | ||
761 | session->rd_size = req->rd_size; | ||
762 | |||
771 | hid = hid_allocate_device(); | 763 | hid = hid_allocate_device(); |
772 | if (IS_ERR(hid)) | 764 | if (IS_ERR(hid)) { |
773 | return PTR_ERR(hid); | 765 | err = PTR_ERR(hid); |
766 | goto fault; | ||
767 | } | ||
774 | 768 | ||
775 | session->hid = hid; | 769 | session->hid = hid; |
776 | session->req = req; | 770 | |
777 | hid->driver_data = session; | 771 | hid->driver_data = session; |
778 | 772 | ||
779 | baswap(&src, &bt_sk(session->ctrl_sock->sk)->src); | 773 | baswap(&src, &bt_sk(session->ctrl_sock->sk)->src); |
@@ -804,6 +798,10 @@ failed: | |||
804 | hid_destroy_device(hid); | 798 | hid_destroy_device(hid); |
805 | session->hid = NULL; | 799 | session->hid = NULL; |
806 | 800 | ||
801 | fault: | ||
802 | kfree(session->rd_data); | ||
803 | session->rd_data = NULL; | ||
804 | |||
807 | return err; | 805 | return err; |
808 | } | 806 | } |
809 | 807 | ||
@@ -898,6 +896,9 @@ unlink: | |||
898 | session->hid = NULL; | 896 | session->hid = NULL; |
899 | } | 897 | } |
900 | 898 | ||
899 | kfree(session->rd_data); | ||
900 | session->rd_data = NULL; | ||
901 | |||
901 | purge: | 902 | purge: |
902 | skb_queue_purge(&session->ctrl_transmit); | 903 | skb_queue_purge(&session->ctrl_transmit); |
903 | skb_queue_purge(&session->intr_transmit); | 904 | skb_queue_purge(&session->intr_transmit); |