diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-04 14:39:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-04 14:39:00 -0400 |
commit | 3366dd9fa887ebbda4872e9554f853eaeda764be (patch) | |
tree | d1bb553325b276e9d2a1bce99f3e64834b46866b /net/bluetooth | |
parent | 697a067f1ec67f2f8dfafd0a1b95a46997a11f32 (diff) | |
parent | 21796b39c9e876a46a353a4a9ff9881766a7c176 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina:
- HID battery handling cleanup by David Herrmann
- ELO 4000/4500 driver, which has been finally ported to be proper HID
driver by Jiri Slaby
- ps3remote driver functionality is now provided by generic sony
driver, by Jiri Kosina
- PS2/3 Buzz controllers support, by Colin Leitner
- rework of wiimote driver including full extensions hotpluggin
support, sub-device modularization and speaker support by David
Herrmann
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (55 commits)
HID: wacom: Intuos4 battery charging changes
HID: i2c-hid: support sending HID output reports using the output register
HID: kye: Add report fixup for Genius Gila Gaming mouse
HID: wiimote: support Nintendo Wii U Pro Controller
Input: make gamepad API keycodes more clear
input: document gamepad API and add extra keycodes
HID: explain out-of-range check better
HID: fix false positive out of range values
HID: wiimote: fix coccinelle warnings
HID: roccat: check cdev_add return value
HID: fold ps3remote driver into generic Sony driver
HID: hyperv: convert alloc+memcpy to memdup
HID: core: fix reporting of raw events
HID: wiimote: discard invalid EXT data reports
HID: wiimote: fix classic controller parsing
HID: wiimote: init EXT/MP during device detection
HID: wiimote: fix DRM debug-attr to correctly parse input
HID: wiimote: add MP quirks
HID: wiimote: remove old static extension support
HID: wiimote: add "bboard_calib" attribute
...
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hidp/core.c | 56 | ||||
-rw-r--r-- | net/bluetooth/hidp/hidp.h | 2 |
2 files changed, 49 insertions, 9 deletions
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 940f5acb6694..46c6a148f0b3 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c | |||
@@ -851,6 +851,29 @@ static void hidp_session_dev_del(struct hidp_session *session) | |||
851 | } | 851 | } |
852 | 852 | ||
853 | /* | 853 | /* |
854 | * Asynchronous device registration | ||
855 | * HID device drivers might want to perform I/O during initialization to | ||
856 | * detect device types. Therefore, call device registration in a separate | ||
857 | * worker so the HIDP thread can schedule I/O operations. | ||
858 | * Note that this must be called after the worker thread was initialized | ||
859 | * successfully. This will then add the devices and increase session state | ||
860 | * on success, otherwise it will terminate the session thread. | ||
861 | */ | ||
862 | static void hidp_session_dev_work(struct work_struct *work) | ||
863 | { | ||
864 | struct hidp_session *session = container_of(work, | ||
865 | struct hidp_session, | ||
866 | dev_init); | ||
867 | int ret; | ||
868 | |||
869 | ret = hidp_session_dev_add(session); | ||
870 | if (!ret) | ||
871 | atomic_inc(&session->state); | ||
872 | else | ||
873 | hidp_session_terminate(session); | ||
874 | } | ||
875 | |||
876 | /* | ||
854 | * Create new session object | 877 | * Create new session object |
855 | * Allocate session object, initialize static fields, copy input data into the | 878 | * Allocate session object, initialize static fields, copy input data into the |
856 | * object and take a reference to all sub-objects. | 879 | * object and take a reference to all sub-objects. |
@@ -897,6 +920,7 @@ static int hidp_session_new(struct hidp_session **out, const bdaddr_t *bdaddr, | |||
897 | session->idle_to = req->idle_to; | 920 | session->idle_to = req->idle_to; |
898 | 921 | ||
899 | /* device management */ | 922 | /* device management */ |
923 | INIT_WORK(&session->dev_init, hidp_session_dev_work); | ||
900 | setup_timer(&session->timer, hidp_idle_timeout, | 924 | setup_timer(&session->timer, hidp_idle_timeout, |
901 | (unsigned long)session); | 925 | (unsigned long)session); |
902 | 926 | ||
@@ -1035,8 +1059,8 @@ static void hidp_session_terminate(struct hidp_session *session) | |||
1035 | * Probe HIDP session | 1059 | * Probe HIDP session |
1036 | * This is called from the l2cap_conn core when our l2cap_user object is bound | 1060 | * This is called from the l2cap_conn core when our l2cap_user object is bound |
1037 | * to the hci-connection. We get the session via the \user object and can now | 1061 | * to the hci-connection. We get the session via the \user object and can now |
1038 | * start the session thread, register the HID/input devices and link it into | 1062 | * start the session thread, link it into the global session list and |
1039 | * the global session list. | 1063 | * schedule HID/input device registration. |
1040 | * The global session-list owns its own reference to the session object so you | 1064 | * The global session-list owns its own reference to the session object so you |
1041 | * can drop your own reference after registering the l2cap_user object. | 1065 | * can drop your own reference after registering the l2cap_user object. |
1042 | */ | 1066 | */ |
@@ -1058,21 +1082,30 @@ static int hidp_session_probe(struct l2cap_conn *conn, | |||
1058 | goto out_unlock; | 1082 | goto out_unlock; |
1059 | } | 1083 | } |
1060 | 1084 | ||
1085 | if (session->input) { | ||
1086 | ret = hidp_session_dev_add(session); | ||
1087 | if (ret) | ||
1088 | goto out_unlock; | ||
1089 | } | ||
1090 | |||
1061 | ret = hidp_session_start_sync(session); | 1091 | ret = hidp_session_start_sync(session); |
1062 | if (ret) | 1092 | if (ret) |
1063 | goto out_unlock; | 1093 | goto out_del; |
1064 | 1094 | ||
1065 | ret = hidp_session_dev_add(session); | 1095 | /* HID device registration is async to allow I/O during probe */ |
1066 | if (ret) | 1096 | if (session->input) |
1067 | goto out_stop; | 1097 | atomic_inc(&session->state); |
1098 | else | ||
1099 | schedule_work(&session->dev_init); | ||
1068 | 1100 | ||
1069 | hidp_session_get(session); | 1101 | hidp_session_get(session); |
1070 | list_add(&session->list, &hidp_session_list); | 1102 | list_add(&session->list, &hidp_session_list); |
1071 | ret = 0; | 1103 | ret = 0; |
1072 | goto out_unlock; | 1104 | goto out_unlock; |
1073 | 1105 | ||
1074 | out_stop: | 1106 | out_del: |
1075 | hidp_session_terminate(session); | 1107 | if (session->input) |
1108 | hidp_session_dev_del(session); | ||
1076 | out_unlock: | 1109 | out_unlock: |
1077 | up_write(&hidp_session_sem); | 1110 | up_write(&hidp_session_sem); |
1078 | return ret; | 1111 | return ret; |
@@ -1102,7 +1135,12 @@ static void hidp_session_remove(struct l2cap_conn *conn, | |||
1102 | down_write(&hidp_session_sem); | 1135 | down_write(&hidp_session_sem); |
1103 | 1136 | ||
1104 | hidp_session_terminate(session); | 1137 | hidp_session_terminate(session); |
1105 | hidp_session_dev_del(session); | 1138 | |
1139 | cancel_work_sync(&session->dev_init); | ||
1140 | if (session->input || | ||
1141 | atomic_read(&session->state) > HIDP_SESSION_PREPARING) | ||
1142 | hidp_session_dev_del(session); | ||
1143 | |||
1106 | list_del(&session->list); | 1144 | list_del(&session->list); |
1107 | 1145 | ||
1108 | up_write(&hidp_session_sem); | 1146 | up_write(&hidp_session_sem); |
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index 6162ce8606ac..9e6cc3553105 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h | |||
@@ -128,6 +128,7 @@ int hidp_get_conninfo(struct hidp_conninfo *ci); | |||
128 | 128 | ||
129 | enum hidp_session_state { | 129 | enum hidp_session_state { |
130 | HIDP_SESSION_IDLING, | 130 | HIDP_SESSION_IDLING, |
131 | HIDP_SESSION_PREPARING, | ||
131 | HIDP_SESSION_RUNNING, | 132 | HIDP_SESSION_RUNNING, |
132 | }; | 133 | }; |
133 | 134 | ||
@@ -156,6 +157,7 @@ struct hidp_session { | |||
156 | unsigned long idle_to; | 157 | unsigned long idle_to; |
157 | 158 | ||
158 | /* device management */ | 159 | /* device management */ |
160 | struct work_struct dev_init; | ||
159 | struct input_dev *input; | 161 | struct input_dev *input; |
160 | struct hid_device *hid; | 162 | struct hid_device *hid; |
161 | struct timer_list timer; | 163 | struct timer_list timer; |