diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2009-08-22 17:22:15 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-08-22 17:22:15 -0400 |
commit | edad63886993d18ab800c49f6587a93432ef8b35 (patch) | |
tree | 3513335d25e260daed72ecc0bdf19b0fd8bdcac2 /net/bluetooth | |
parent | 9eba32b86d17ef87131fa0bce43c614904ab5781 (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')
-rw-r--r-- | net/bluetooth/hidp/core.c | 62 | ||||
-rw-r--r-- | net/bluetooth/hidp/hidp.h | 2 |
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 | ||
98 | static void __hidp_unlink_session(struct hidp_session *session) | 100 | static 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 | ||
622 | static int hidp_setup_input(struct hidp_session *session, | 630 | static 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 | ||
676 | static int hidp_open(struct hid_device *hid) | 690 | static 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; |
788 | err_hid: | 800 | |
801 | failed: | ||
789 | hid_destroy_device(hid); | 802 | hid_destroy_device(hid); |
790 | session->hid = NULL; | 803 | session->hid = NULL; |
791 | err: | 804 | |
792 | return ret; | 805 | return err; |
793 | } | 806 | } |
794 | 807 | ||
795 | int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) | 808 | int 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); |
880 | err_skb: | 896 | session->hid = NULL; |
897 | } | ||
898 | |||
899 | purge: | ||
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 | |||
883 | failed: | 903 | failed: |
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); | |||
126 | struct hidp_session { | 126 | struct 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 | ||