aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hidp/core.c191
-rw-r--r--net/bluetooth/hidp/hidp.h2
2 files changed, 111 insertions, 82 deletions
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 56a51f91591a..d8029cfcd452 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -623,9 +623,15 @@ static struct device *hidp_get_device(struct hidp_session *session)
623static int hidp_setup_input(struct hidp_session *session, 623static int hidp_setup_input(struct hidp_session *session,
624 struct hidp_connadd_req *req) 624 struct hidp_connadd_req *req)
625{ 625{
626 struct input_dev *input = session->input; 626 struct input_dev *input;
627 int i; 627 int i;
628 628
629 input = input_allocate_device();
630 if (!input)
631 return -ENOMEM;
632
633 session->input = input;
634
629 input_set_drvdata(input, session); 635 input_set_drvdata(input, session);
630 636
631 input->name = "Bluetooth HID Boot Protocol Device"; 637 input->name = "Bluetooth HID Boot Protocol Device";
@@ -698,55 +704,117 @@ static void hidp_setup_quirks(struct hid_device *hid)
698 hid->quirks = hidp_blacklist[n].quirks; 704 hid->quirks = hidp_blacklist[n].quirks;
699} 705}
700 706
707static int hidp_parse(struct hid_device *hid)
708{
709 struct hidp_session *session = hid->driver_data;
710 struct hidp_connadd_req *req = session->req;
711 unsigned char *buf;
712 int ret;
713
714 buf = kmalloc(req->rd_size, GFP_KERNEL);
715 if (!buf)
716 return -ENOMEM;
717
718 if (copy_from_user(buf, req->rd_data, req->rd_size)) {
719 kfree(buf);
720 return -EFAULT;
721 }
722
723 ret = hid_parse_report(session->hid, buf, req->rd_size);
724
725 kfree(buf);
726
727 if (ret)
728 return ret;
729
730 session->req = NULL;
731
732 hidp_setup_quirks(hid);
733 return 0;
734}
735
736static int hidp_start(struct hid_device *hid)
737{
738 struct hidp_session *session = hid->driver_data;
739 struct hid_report *report;
740
741 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
742 report_list, list)
743 hidp_send_report(session, report);
744
745 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
746 report_list, list)
747 hidp_send_report(session, report);
748
749 if (hidinput_connect(hid) == 0)
750 hid->claimed |= HID_CLAIMED_INPUT;
751
752 return 0;
753}
754
755static void hidp_stop(struct hid_device *hid)
756{
757 struct hidp_session *session = hid->driver_data;
758
759 skb_queue_purge(&session->ctrl_transmit);
760 skb_queue_purge(&session->intr_transmit);
761
762 if (hid->claimed & HID_CLAIMED_INPUT)
763 hidinput_disconnect(hid);
764 hid->claimed = 0;
765}
766
767static struct hid_ll_driver hidp_hid_driver = {
768 .parse = hidp_parse,
769 .start = hidp_start,
770 .stop = hidp_stop,
771 .open = hidp_open,
772 .close = hidp_close,
773 .hidinput_input_event = hidp_hidinput_event,
774};
775
701static int hidp_setup_hid(struct hidp_session *session, 776static int hidp_setup_hid(struct hidp_session *session,
702 struct hidp_connadd_req *req) 777 struct hidp_connadd_req *req)
703{ 778{
704 struct hid_device *hid = session->hid; 779 struct hid_device *hid;
705 struct hid_report *report;
706 bdaddr_t src, dst; 780 bdaddr_t src, dst;
707 int ret; 781 int ret;
708 782
709 baswap(&src, &bt_sk(session->ctrl_sock->sk)->src); 783 hid = hid_allocate_device();
710 baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst); 784 if (IS_ERR(hid)) {
785 ret = PTR_ERR(session->hid);
786 goto err;
787 }
711 788
789 session->hid = hid;
790 session->req = req;
712 hid->driver_data = session; 791 hid->driver_data = session;
713 792
714 hid->country = req->country; 793 baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
794 baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
715 795
716 hid->bus = BUS_BLUETOOTH; 796 hid->bus = BUS_BLUETOOTH;
717 hid->vendor = req->vendor; 797 hid->vendor = req->vendor;
718 hid->product = req->product; 798 hid->product = req->product;
719 hid->version = req->version; 799 hid->version = req->version;
800 hid->country = req->country;
720 801
721 strncpy(hid->name, req->name, 128); 802 strncpy(hid->name, req->name, 128);
722 strncpy(hid->phys, batostr(&src), 64); 803 strncpy(hid->phys, batostr(&src), 64);
723 strncpy(hid->uniq, batostr(&dst), 64); 804 strncpy(hid->uniq, batostr(&dst), 64);
724 805
725 hid->dev.parent = hidp_get_device(session); 806 hid->dev.parent = hidp_get_device(session);
726 807 hid->ll_driver = &hidp_hid_driver;
727 hid->hid_open = hidp_open;
728 hid->hid_close = hidp_close;
729
730 hid->hidinput_input_event = hidp_hidinput_event;
731
732 hidp_setup_quirks(hid);
733
734 list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
735 hidp_send_report(session, report);
736
737 list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
738 hidp_send_report(session, report);
739
740 if (hidinput_connect(hid) == 0)
741 hid->claimed |= HID_CLAIMED_INPUT;
742 808
743 ret = hid_add_device(hid); 809 ret = hid_add_device(hid);
744 if (ret) { 810 if (ret)
745 if (hid->claimed & HID_CLAIMED_INPUT) 811 goto err_hid;
746 hidinput_disconnect(hid);
747 skb_queue_purge(&session->intr_transmit);
748 }
749 812
813 return 0;
814err_hid:
815 hid_destroy_device(hid);
816 session->hid = NULL;
817err:
750 return ret; 818 return ret;
751} 819}
752 820
@@ -767,46 +835,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
767 835
768 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size); 836 BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
769 837
770 if (req->rd_size > 0) {
771 unsigned char *buf = kmalloc(req->rd_size, GFP_KERNEL);
772
773 if (!buf) {
774 kfree(session);
775 return -ENOMEM;
776 }
777
778 if (copy_from_user(buf, req->rd_data, req->rd_size)) {
779 kfree(buf);
780 kfree(session);
781 return -EFAULT;
782 }
783
784 session->hid = hid_allocate_device();
785 if (IS_ERR(session->hid)) {
786 kfree(buf);
787 kfree(session);
788 return PTR_ERR(session->hid);
789 }
790
791 err = hid_parse_report(session->hid, buf, req->rd_size);
792
793 kfree(buf);
794
795 if (err) {
796 hid_destroy_device(session->hid);
797 kfree(session);
798 return -EINVAL;
799 }
800 }
801
802 if (!session->hid) {
803 session->input = input_allocate_device();
804 if (!session->input) {
805 kfree(session);
806 return -ENOMEM;
807 }
808 }
809
810 down_write(&hidp_session_sem); 838 down_write(&hidp_session_sem);
811 839
812 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst); 840 s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
@@ -834,16 +862,16 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
834 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); 862 session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
835 session->idle_to = req->idle_to; 863 session->idle_to = req->idle_to;
836 864
837 if (session->input) { 865 if (req->rd_size > 0) {
838 err = hidp_setup_input(session, req);
839 if (err < 0)
840 goto failed;
841 }
842
843 if (session->hid) {
844 err = hidp_setup_hid(session, req); 866 err = hidp_setup_hid(session, req);
845 if (err) 867 if (err)
846 goto failed; 868 goto err_skb;
869 }
870
871 if (!session->hid) {
872 err = hidp_setup_input(session, req);
873 if (err < 0)
874 goto err_skb;
847 } 875 }
848 876
849 __hidp_link_session(session); 877 __hidp_link_session(session);
@@ -871,16 +899,15 @@ unlink:
871 899
872 __hidp_unlink_session(session); 900 __hidp_unlink_session(session);
873 901
874 if (session->input) { 902 if (session->input)
875 input_unregister_device(session->input); 903 input_unregister_device(session->input);
876 session->input = NULL; /* don't try to free it here */
877 }
878
879failed:
880 up_write(&hidp_session_sem);
881
882 if (session->hid) 904 if (session->hid)
883 hid_destroy_device(session->hid); 905 hid_destroy_device(session->hid);
906err_skb:
907 skb_queue_purge(&session->ctrl_transmit);
908 skb_queue_purge(&session->intr_transmit);
909failed:
910 up_write(&hidp_session_sem);
884 911
885 input_free_device(session->input); 912 input_free_device(session->input);
886 kfree(session); 913 kfree(session);
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index 343fb0566b3e..e503c89057ad 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -151,6 +151,8 @@ struct hidp_session {
151 151
152 struct sk_buff_head ctrl_transmit; 152 struct sk_buff_head ctrl_transmit;
153 struct sk_buff_head intr_transmit; 153 struct sk_buff_head intr_transmit;
154
155 struct hidp_connadd_req *req;
154}; 156};
155 157
156static inline void hidp_schedule(struct hidp_session *session) 158static inline void hidp_schedule(struct hidp_session *session)