aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-04 14:39:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-04 14:39:00 -0400
commit3366dd9fa887ebbda4872e9554f853eaeda764be (patch)
treed1bb553325b276e9d2a1bce99f3e64834b46866b /net/bluetooth
parent697a067f1ec67f2f8dfafd0a1b95a46997a11f32 (diff)
parent21796b39c9e876a46a353a4a9ff9881766a7c176 (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.c56
-rw-r--r--net/bluetooth/hidp/hidp.h2
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 */
862static 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
1074out_stop: 1106out_del:
1075 hidp_session_terminate(session); 1107 if (session->input)
1108 hidp_session_dev_del(session);
1076out_unlock: 1109out_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
129enum hidp_session_state { 129enum 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;