aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hidp
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2009-08-22 17:22:15 -0400
committerMarcel Holtmann <marcel@holtmann.org>2009-08-22 17:22:15 -0400
commitedad63886993d18ab800c49f6587a93432ef8b35 (patch)
tree3513335d25e260daed72ecc0bdf19b0fd8bdcac2 /net/bluetooth/hidp
parent9eba32b86d17ef87131fa0bce43c614904ab5781 (diff)
Bluetooth: Let HIDP grab the device reference for connections
The core exports the hci_conn_hold_device() and hci_conn_put_device() functions for device reference of connections. Use this to ensure that the uevents from the parent are send after the child ones. Based on a report by Brian Rogers <brian@xyzw.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/hidp')
-rw-r--r--net/bluetooth/hidp/core.c62
-rw-r--r--net/bluetooth/hidp/hidp.h2
2 files changed, 43 insertions, 21 deletions
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index f912d6537180..09bedeb5579c 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -93,10 +93,14 @@ static void __hidp_link_session(struct hidp_session *session)
93{ 93{
94 __module_get(THIS_MODULE); 94 __module_get(THIS_MODULE);
95 list_add(&session->list, &hidp_session_list); 95 list_add(&session->list, &hidp_session_list);
96
97 hci_conn_hold_device(session->conn);
96} 98}
97 99
98static void __hidp_unlink_session(struct hidp_session *session) 100static void __hidp_unlink_session(struct hidp_session *session)
99{ 101{
102 hci_conn_put_device(session->conn);
103
100 list_del(&session->list); 104 list_del(&session->list);
101 module_put(THIS_MODULE); 105 module_put(THIS_MODULE);
102} 106}
@@ -577,7 +581,9 @@ static int hidp_session(void *arg)
577 hidinput_disconnect(session->hid); 581 hidinput_disconnect(session->hid);
578 if (session->hid->claimed & HID_CLAIMED_HIDRAW) 582 if (session->hid->claimed & HID_CLAIMED_HIDRAW)
579 hidraw_disconnect(session->hid); 583 hidraw_disconnect(session->hid);
584
580 hid_destroy_device(session->hid); 585 hid_destroy_device(session->hid);
586 session->hid = NULL;
581 } 587 }
582 588
583 /* Wakeup user-space polling for socket errors */ 589 /* Wakeup user-space polling for socket errors */
@@ -605,25 +611,27 @@ static struct device *hidp_get_device(struct hidp_session *session)
605{ 611{
606 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src; 612 bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
607 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst; 613 bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
614 struct device *device = NULL;
608 struct hci_dev *hdev; 615 struct hci_dev *hdev;
609 struct hci_conn *conn;
610 616
611 hdev = hci_get_route(dst, src); 617 hdev = hci_get_route(dst, src);
612 if (!hdev) 618 if (!hdev)
613 return NULL; 619 return NULL;
614 620
615 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); 621 session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
622 if (session->conn)
623 device = &session->conn->dev;
616 624
617 hci_dev_put(hdev); 625 hci_dev_put(hdev);
618 626
619 return conn ? &conn->dev : NULL; 627 return device;
620} 628}
621 629
622static int hidp_setup_input(struct hidp_session *session, 630static int hidp_setup_input(struct hidp_session *session,
623 struct hidp_connadd_req *req) 631 struct hidp_connadd_req *req)
624{ 632{
625 struct input_dev *input; 633 struct input_dev *input;
626 int i; 634 int err, i;
627 635
628 input = input_allocate_device(); 636 input = input_allocate_device();
629 if (!input) 637 if (!input)
@@ -670,7 +678,13 @@ static int hidp_setup_input(struct hidp_session *session,
670 678
671 input->event = hidp_input_event; 679 input->event = hidp_input_event;
672 680
673 return input_register_device(input); 681 err = input_register_device(input);
682 if (err < 0) {
683 hci_conn_put_device(session->conn);
684 return err;
685 }
686
687 return 0;
674} 688}
675 689
676static int hidp_open(struct hid_device *hid) 690static int hidp_open(struct hid_device *hid)
@@ -752,13 +766,11 @@ static int hidp_setup_hid(struct hidp_session *session,
752{ 766{
753 struct hid_device *hid; 767 struct hid_device *hid;
754 bdaddr_t src, dst; 768 bdaddr_t src, dst;
755 int ret; 769 int err;
756 770
757 hid = hid_allocate_device(); 771 hid = hid_allocate_device();
758 if (IS_ERR(hid)) { 772 if (IS_ERR(hid))
759 ret = PTR_ERR(session->hid); 773 return PTR_ERR(session->hid);
760 goto err;
761 }
762 774
763 session->hid = hid; 775 session->hid = hid;
764 session->req = req; 776 session->req = req;
@@ -780,16 +792,17 @@ static int hidp_setup_hid(struct hidp_session *session,
780 hid->dev.parent = hidp_get_device(session); 792 hid->dev.parent = hidp_get_device(session);
781 hid->ll_driver = &hidp_hid_driver; 793 hid->ll_driver = &hidp_hid_driver;
782 794
783 ret = hid_add_device(hid); 795 err = hid_add_device(hid);
784 if (ret) 796 if (err < 0)
785 goto err_hid; 797 goto failed;
786 798
787 return 0; 799 return 0;
788err_hid: 800
801failed:
789 hid_destroy_device(hid); 802 hid_destroy_device(hid);
790 session->hid = NULL; 803 session->hid = NULL;
791err: 804
792 return ret; 805 return err;
793} 806}
794 807
795int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) 808int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
@@ -839,13 +852,13 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
839 if (req->rd_size > 0) { 852 if (req->rd_size > 0) {
840 err = hidp_setup_hid(session, req); 853 err = hidp_setup_hid(session, req);
841 if (err && err != -ENODEV) 854 if (err && err != -ENODEV)
842 goto err_skb; 855 goto purge;
843 } 856 }
844 857
845 if (!session->hid) { 858 if (!session->hid) {
846 err = hidp_setup_input(session, req); 859 err = hidp_setup_input(session, req);
847 if (err < 0) 860 if (err < 0)
848 goto err_skb; 861 goto purge;
849 } 862 }
850 863
851 __hidp_link_session(session); 864 __hidp_link_session(session);
@@ -873,13 +886,20 @@ unlink:
873 886
874 __hidp_unlink_session(session); 887 __hidp_unlink_session(session);
875 888
876 if (session->input) 889 if (session->input) {
877 input_unregister_device(session->input); 890 input_unregister_device(session->input);
878 if (session->hid) 891 session->input = NULL;
892 }
893
894 if (session->hid) {
879 hid_destroy_device(session->hid); 895 hid_destroy_device(session->hid);
880err_skb: 896 session->hid = NULL;
897 }
898
899purge:
881 skb_queue_purge(&session->ctrl_transmit); 900 skb_queue_purge(&session->ctrl_transmit);
882 skb_queue_purge(&session->intr_transmit); 901 skb_queue_purge(&session->intr_transmit);
902
883failed: 903failed:
884 up_write(&hidp_session_sem); 904 up_write(&hidp_session_sem);
885 905
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index e503c89057ad..faf3d74c3586 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -126,6 +126,8 @@ int hidp_get_conninfo(struct hidp_conninfo *ci);
126struct hidp_session { 126struct hidp_session {
127 struct list_head list; 127 struct list_head list;
128 128
129 struct hci_conn *conn;
130
129 struct socket *ctrl_sock; 131 struct socket *ctrl_sock;
130 struct socket *intr_sock; 132 struct socket *intr_sock;
131 133