diff options
| author | Jiri Slaby <jirislaby@gmail.com> | 2008-05-16 05:49:16 -0400 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2008-10-14 17:50:48 -0400 |
| commit | c500c9714011edab021591340042787722db9cf0 (patch) | |
| tree | d6bb0fe483c9f1c71c3d757e9c13d261ca01cd5f /net/bluetooth/hidp/core.c | |
| parent | 85cdaf524b7ddab627e7d15405693f2511ef7505 (diff) | |
HID: hid, make parsing event driven
Next step for complete hid bus, this patch includes:
- call parser either from probe or from hid-core if there is no probe.
- add ll_driver structure and centralize some stuff there (open, close...)
- split and merge usb_hid_configure and hid_probe into several functions
to allow hooks/fixes between them
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'net/bluetooth/hidp/core.c')
| -rw-r--r-- | net/bluetooth/hidp/core.c | 191 |
1 files changed, 109 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) | |||
| 623 | static int hidp_setup_input(struct hidp_session *session, | 623 | static 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 | ||
| 707 | static 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 | |||
| 736 | static 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 | |||
| 755 | static 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 | |||
| 767 | static 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 | |||
| 701 | static int hidp_setup_hid(struct hidp_session *session, | 776 | static 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; | ||
| 814 | err_hid: | ||
| 815 | hid_destroy_device(hid); | ||
| 816 | session->hid = NULL; | ||
| 817 | err: | ||
| 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 | |||
| 879 | failed: | ||
| 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); |
| 906 | err_skb: | ||
| 907 | skb_queue_purge(&session->ctrl_transmit); | ||
| 908 | skb_queue_purge(&session->intr_transmit); | ||
| 909 | failed: | ||
| 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); |
