aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 15:11:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 15:11:39 -0400
commitdef7cb8cd4e3258db88050eaaca5438bcc3dafca (patch)
tree23fcf90ddc98acec07bb115c2f7740c21cf44a84 /drivers/hid
parent06d2fe153b9b35e57221e35831a26918f462db68 (diff)
parente1878957b4676a17cf398f7f5723b365e9a2ca48 (diff)
Merge tag 'staging-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging tree update from Greg Kroah-Hartman: "Here is the big staging tree update for the 3.7-rc1 merge window. There are a few patches in here that are outside of the staging area, namely HID and IIO patches, but all of them have been acked by the relevant subsystem maintainers. The IIO stuff is still coming in through this tree as it hasn't entirely moved out of the staging tree, but is almost there. Other than that, there wa a ton of work on the comedi drivers to make them more readable and the correct style. Doing that removed a lot of code, but we added a new driver to the staging tree, so we didn't end up with a net reduction this time around: 662 files changed, 51649 insertions(+), 26582 deletions(-) All of these patches have been in the linux-next tree already. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" * tag 'staging-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1094 commits) staging: comedi: jr3_pci: fix iomem dereference staging: comedi: drivers: use comedi_fc.h cmdtest helpers Staging: winbond: usb_free_urb(NULL) is safe Staging: winbond: checkpatch cleanup Staging: winbond: Removed undesired spaces, lines and tabs Staging: winbond: Typo corrections in comments Staging: winbond: Changed c99 comments to c89 comments staging: r8712u: Do not queue cloned skb staging: comedi: ni_mio_common: always lock in ni_ai_poll() staging: comedi: s626: add FIXME comment staging: comedi: s626: don't dereference insn->data staging: comedi: s526: fix if() check in s526_gpct_winsn() staging: comedi: s626: cleanup comments in s626_initialize() staging: comedi: s626: remove clear of kzalloc'ed data staging: comedi: s626: remove 'WDInterval' from private data staging: comedi: s626: remove 'ChargeEnabled' from private data staging: comedi: s626: remove 'IsBoardRevA' comment staging: comedi: s626: #if 0 out the "SAA7146 BUG WORKAROUND" staging: comedi: s626: remove 'allocatedBuf' from private data staging: comedi: s626: add final attach message ...
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/Kconfig14
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-core.c5
-rw-r--r--drivers/hid/hid-ids.h6
-rw-r--r--drivers/hid/hid-sensor-hub.c680
5 files changed, 706 insertions, 0 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 2af774ad1060..1630150ad2b1 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -708,6 +708,20 @@ config HID_ZYDACRON
708 ---help--- 708 ---help---
709 Support for Zydacron remote control. 709 Support for Zydacron remote control.
710 710
711config HID_SENSOR_HUB
712 tristate "HID Sensors framework support"
713 depends on USB_HID
714 select MFD_CORE
715 default n
716 -- help---
717 Support for HID Sensor framework. This creates a MFD instance
718 for a sensor hub and identifies all the sensors connected to it.
719 Each sensor is registered as a MFD cell, so that sensor specific
720 processing can be done in a separate driver. Each sensor
721 drivers can use the service provided by this driver to register
722 for events and handle data streams. Each sensor driver can format
723 data and present to user mode using input or IIO interface.
724
711endmenu 725endmenu
712 726
713endif # HID 727endif # HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 5a3690ff9bf2..cef68ca859d3 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -112,6 +112,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
112obj-$(CONFIG_HID_WACOM) += hid-wacom.o 112obj-$(CONFIG_HID_WACOM) += hid-wacom.o
113obj-$(CONFIG_HID_WALTOP) += hid-waltop.o 113obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
114obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o 114obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
115obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
115 116
116obj-$(CONFIG_USB_HID) += usbhid/ 117obj-$(CONFIG_USB_HID) += usbhid/
117obj-$(CONFIG_USB_MOUSE) += usbhid/ 118obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 2cd6880b6b17..bd3971bf31bf 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1568,6 +1568,10 @@ static const struct hid_device_id hid_have_special_driver[] = {
1568 { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, 1568 { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
1569 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, 1569 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
1570 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, 1570 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
1571 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_1020) },
1572 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_09FA) },
1573 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_1020) },
1574 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_09FA) },
1571 { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, 1575 { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
1572 { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, 1576 { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
1573 { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, 1577 { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
@@ -1665,6 +1669,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1665 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, 1669 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
1666 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, 1670 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
1667 { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, 1671 { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
1672 { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_SENSOR_HUB_7014) },
1668 { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, 1673 { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
1669 { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, 1674 { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
1670 { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) }, 1675 { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index ca4d83e6e387..269b50912a4a 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -429,6 +429,11 @@
429#define USB_VENDOR_ID_IMATION 0x0718 429#define USB_VENDOR_ID_IMATION 0x0718
430#define USB_DEVICE_ID_DISC_STAKKA 0xd000 430#define USB_DEVICE_ID_DISC_STAKKA 0xd000
431 431
432#define USB_VENDOR_ID_INTEL_8086 0x8086
433#define USB_VENDOR_ID_INTEL_8087 0x8087
434#define USB_DEVICE_ID_SENSOR_HUB_1020 0x1020
435#define USB_DEVICE_ID_SENSOR_HUB_09FA 0x09FA
436
432#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615 437#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
433#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070 438#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
434 439
@@ -706,6 +711,7 @@
706 711
707#define USB_VENDOR_ID_STANTUM_STM 0x0483 712#define USB_VENDOR_ID_STANTUM_STM 0x0483
708#define USB_DEVICE_ID_MTP_STM 0x3261 713#define USB_DEVICE_ID_MTP_STM 0x3261
714#define USB_DEVICE_ID_SENSOR_HUB_7014 0x7014
709 715
710#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403 716#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403
711#define USB_DEVICE_ID_MTP_SITRONIX 0x5001 717#define USB_DEVICE_ID_MTP_SITRONIX 0x5001
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
new file mode 100644
index 000000000000..d9d73e9163eb
--- /dev/null
+++ b/drivers/hid/hid-sensor-hub.c
@@ -0,0 +1,680 @@
1/*
2 * HID Sensors Driver
3 * Copyright (c) 2012, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 */
19#include <linux/device.h>
20#include <linux/hid.h>
21#include <linux/usb.h>
22#include "usbhid/usbhid.h"
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/mfd/core.h>
26#include <linux/list.h>
27#include <linux/hid-sensor-ids.h>
28#include <linux/hid-sensor-hub.h>
29#include "hid-ids.h"
30
31/**
32 * struct sensor_hub_pending - Synchronous read pending information
33 * @status: Pending status true/false.
34 * @ready: Completion synchronization data.
35 * @usage_id: Usage id for physical device, E.g. Gyro usage id.
36 * @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro.
37 * @raw_size: Response size for a read request.
38 * @raw_data: Place holder for received response.
39 */
40struct sensor_hub_pending {
41 bool status;
42 struct completion ready;
43 u32 usage_id;
44 u32 attr_usage_id;
45 int raw_size;
46 u8 *raw_data;
47};
48
49/**
50 * struct sensor_hub_data - Hold a instance data for a HID hub device
51 * @hsdev: Stored hid instance for current hub device.
52 * @mutex: Mutex to serialize synchronous request.
53 * @lock: Spin lock to protect pending request structure.
54 * @pending: Holds information of pending sync read request.
55 * @dyn_callback_list: Holds callback function
56 * @dyn_callback_lock: spin lock to protect callback list
57 * @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance.
58 * @hid_sensor_client_cnt: Number of MFD cells, (no of sensors attached).
59 */
60struct sensor_hub_data {
61 struct hid_sensor_hub_device *hsdev;
62 struct mutex mutex;
63 spinlock_t lock;
64 struct sensor_hub_pending pending;
65 struct list_head dyn_callback_list;
66 spinlock_t dyn_callback_lock;
67 struct mfd_cell *hid_sensor_hub_client_devs;
68 int hid_sensor_client_cnt;
69};
70
71/**
72 * struct hid_sensor_hub_callbacks_list - Stores callback list
73 * @list: list head.
74 * @usage_id: usage id for a physical device.
75 * @usage_callback: Stores registered callback functions.
76 * @priv: Private data for a physical device.
77 */
78struct hid_sensor_hub_callbacks_list {
79 struct list_head list;
80 u32 usage_id;
81 struct hid_sensor_hub_callbacks *usage_callback;
82 void *priv;
83};
84
85static int sensor_hub_check_for_sensor_page(struct hid_device *hdev)
86{
87 int i;
88 int ret = -EINVAL;
89
90 for (i = 0; i < hdev->maxcollection; i++) {
91 struct hid_collection *col = &hdev->collection[i];
92 if (col->type == HID_COLLECTION_PHYSICAL &&
93 (col->usage & HID_USAGE_PAGE) == HID_UP_SENSOR) {
94 ret = 0;
95 break;
96 }
97 }
98
99 return ret;
100}
101
102static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev,
103 int dir)
104{
105 struct hid_report *report;
106
107 list_for_each_entry(report, &hdev->report_enum[dir].report_list, list) {
108 if (report->id == id)
109 return report;
110 }
111 hid_warn(hdev, "No report with id 0x%x found\n", id);
112
113 return NULL;
114}
115
116static int sensor_hub_get_physical_device_count(
117 struct hid_report_enum *report_enum)
118{
119 struct hid_report *report;
120 struct hid_field *field;
121 int cnt = 0;
122
123 list_for_each_entry(report, &report_enum->report_list, list) {
124 field = report->field[0];
125 if (report->maxfield && field &&
126 field->physical)
127 cnt++;
128 }
129
130 return cnt;
131}
132
133static void sensor_hub_fill_attr_info(
134 struct hid_sensor_hub_attribute_info *info,
135 s32 index, s32 report_id, s32 units, s32 unit_expo, s32 size)
136{
137 info->index = index;
138 info->report_id = report_id;
139 info->units = units;
140 info->unit_expo = unit_expo;
141 info->size = size/8;
142}
143
144static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
145 struct hid_device *hdev,
146 u32 usage_id, void **priv)
147{
148 struct hid_sensor_hub_callbacks_list *callback;
149 struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
150
151 spin_lock(&pdata->dyn_callback_lock);
152 list_for_each_entry(callback, &pdata->dyn_callback_list, list)
153 if (callback->usage_id == usage_id) {
154 *priv = callback->priv;
155 spin_unlock(&pdata->dyn_callback_lock);
156 return callback->usage_callback;
157 }
158 spin_unlock(&pdata->dyn_callback_lock);
159
160 return NULL;
161}
162
163int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
164 u32 usage_id,
165 struct hid_sensor_hub_callbacks *usage_callback)
166{
167 struct hid_sensor_hub_callbacks_list *callback;
168 struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev);
169
170 spin_lock(&pdata->dyn_callback_lock);
171 list_for_each_entry(callback, &pdata->dyn_callback_list, list)
172 if (callback->usage_id == usage_id) {
173 spin_unlock(&pdata->dyn_callback_lock);
174 return -EINVAL;
175 }
176 callback = kzalloc(sizeof(*callback), GFP_ATOMIC);
177 if (!callback) {
178 spin_unlock(&pdata->dyn_callback_lock);
179 return -ENOMEM;
180 }
181 callback->usage_callback = usage_callback;
182 callback->usage_id = usage_id;
183 callback->priv = NULL;
184 list_add_tail(&callback->list, &pdata->dyn_callback_list);
185 spin_unlock(&pdata->dyn_callback_lock);
186
187 return 0;
188}
189EXPORT_SYMBOL_GPL(sensor_hub_register_callback);
190
191int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
192 u32 usage_id)
193{
194 struct hid_sensor_hub_callbacks_list *callback;
195 struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev);
196
197 spin_lock(&pdata->dyn_callback_lock);
198 list_for_each_entry(callback, &pdata->dyn_callback_list, list)
199 if (callback->usage_id == usage_id) {
200 list_del(&callback->list);
201 kfree(callback);
202 break;
203 }
204 spin_unlock(&pdata->dyn_callback_lock);
205
206 return 0;
207}
208EXPORT_SYMBOL_GPL(sensor_hub_remove_callback);
209
210int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
211 u32 field_index, s32 value)
212{
213 struct hid_report *report;
214 struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
215 int ret = 0;
216
217 mutex_lock(&data->mutex);
218 report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
219 if (!report || (field_index >= report->maxfield)) {
220 ret = -EINVAL;
221 goto done_proc;
222 }
223 hid_set_field(report->field[field_index], 0, value);
224 usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT);
225 usbhid_wait_io(hsdev->hdev);
226
227done_proc:
228 mutex_unlock(&data->mutex);
229
230 return ret;
231}
232EXPORT_SYMBOL_GPL(sensor_hub_set_feature);
233
234int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
235 u32 field_index, s32 *value)
236{
237 struct hid_report *report;
238 struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
239 int ret = 0;
240
241 mutex_lock(&data->mutex);
242 report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
243 if (!report || (field_index >= report->maxfield)) {
244 ret = -EINVAL;
245 goto done_proc;
246 }
247 usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
248 usbhid_wait_io(hsdev->hdev);
249 *value = report->field[field_index]->value[0];
250
251done_proc:
252 mutex_unlock(&data->mutex);
253
254 return ret;
255}
256EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
257
258
259int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
260 u32 usage_id,
261 u32 attr_usage_id, u32 report_id)
262{
263 struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
264 unsigned long flags;
265 struct hid_report *report;
266 int ret_val = 0;
267
268 mutex_lock(&data->mutex);
269 memset(&data->pending, 0, sizeof(data->pending));
270 init_completion(&data->pending.ready);
271 data->pending.usage_id = usage_id;
272 data->pending.attr_usage_id = attr_usage_id;
273 data->pending.raw_size = 0;
274
275 spin_lock_irqsave(&data->lock, flags);
276 data->pending.status = true;
277 report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
278 if (!report) {
279 spin_unlock_irqrestore(&data->lock, flags);
280 goto err_free;
281 }
282 usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
283 spin_unlock_irqrestore(&data->lock, flags);
284 wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
285 switch (data->pending.raw_size) {
286 case 1:
287 ret_val = *(u8 *)data->pending.raw_data;
288 break;
289 case 2:
290 ret_val = *(u16 *)data->pending.raw_data;
291 break;
292 case 4:
293 ret_val = *(u32 *)data->pending.raw_data;
294 break;
295 default:
296 ret_val = 0;
297 }
298 kfree(data->pending.raw_data);
299
300err_free:
301 data->pending.status = false;
302 mutex_unlock(&data->mutex);
303
304 return ret_val;
305}
306EXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value);
307
308int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
309 u8 type,
310 u32 usage_id,
311 u32 attr_usage_id,
312 struct hid_sensor_hub_attribute_info *info)
313{
314 int ret = -1;
315 int i, j;
316 int collection_index = -1;
317 struct hid_report *report;
318 struct hid_field *field;
319 struct hid_report_enum *report_enum;
320 struct hid_device *hdev = hsdev->hdev;
321
322 /* Initialize with defaults */
323 info->usage_id = usage_id;
324 info->attrib_id = attr_usage_id;
325 info->report_id = -1;
326 info->index = -1;
327 info->units = -1;
328 info->unit_expo = -1;
329
330 for (i = 0; i < hdev->maxcollection; ++i) {
331 struct hid_collection *collection = &hdev->collection[i];
332 if (usage_id == collection->usage) {
333 collection_index = i;
334 break;
335 }
336 }
337 if (collection_index == -1)
338 goto err_ret;
339
340 report_enum = &hdev->report_enum[type];
341 list_for_each_entry(report, &report_enum->report_list, list) {
342 for (i = 0; i < report->maxfield; ++i) {
343 field = report->field[i];
344 if (field->physical == usage_id &&
345 field->logical == attr_usage_id) {
346 sensor_hub_fill_attr_info(info, i, report->id,
347 field->unit, field->unit_exponent,
348 field->report_size);
349 ret = 0;
350 } else {
351 for (j = 0; j < field->maxusage; ++j) {
352 if (field->usage[j].hid ==
353 attr_usage_id &&
354 field->usage[j].collection_index ==
355 collection_index) {
356 sensor_hub_fill_attr_info(info,
357 i, report->id,
358 field->unit,
359 field->unit_exponent,
360 field->report_size);
361 ret = 0;
362 break;
363 }
364 }
365 }
366 if (ret == 0)
367 break;
368 }
369 }
370
371err_ret:
372 return ret;
373}
374EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info);
375
376#ifdef CONFIG_PM
377static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message)
378{
379 struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
380 struct hid_sensor_hub_callbacks_list *callback;
381
382 hid_dbg(hdev, " sensor_hub_suspend\n");
383 spin_lock(&pdata->dyn_callback_lock);
384 list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
385 if (callback->usage_callback->suspend)
386 callback->usage_callback->suspend(
387 pdata->hsdev, callback->priv);
388 }
389 spin_unlock(&pdata->dyn_callback_lock);
390
391 return 0;
392}
393
394static int sensor_hub_resume(struct hid_device *hdev)
395{
396 struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
397 struct hid_sensor_hub_callbacks_list *callback;
398
399 hid_dbg(hdev, " sensor_hub_resume\n");
400 spin_lock(&pdata->dyn_callback_lock);
401 list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
402 if (callback->usage_callback->resume)
403 callback->usage_callback->resume(
404 pdata->hsdev, callback->priv);
405 }
406 spin_unlock(&pdata->dyn_callback_lock);
407
408 return 0;
409}
410
411static int sensor_hub_reset_resume(struct hid_device *hdev)
412{
413 return 0;
414}
415#endif
416/*
417 * Handle raw report as sent by device
418 */
419static int sensor_hub_raw_event(struct hid_device *hdev,
420 struct hid_report *report, u8 *raw_data, int size)
421{
422 int i;
423 u8 *ptr;
424 int sz;
425 struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
426 unsigned long flags;
427 struct hid_sensor_hub_callbacks *callback = NULL;
428 struct hid_collection *collection = NULL;
429 void *priv = NULL;
430
431 hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
432 report->id, size, report->type);
433 hid_dbg(hdev, "maxfield:%d\n", report->maxfield);
434 if (report->type != HID_INPUT_REPORT)
435 return 1;
436
437 ptr = raw_data;
438 ptr++; /*Skip report id*/
439
440 if (!report)
441 goto err_report;
442
443 spin_lock_irqsave(&pdata->lock, flags);
444
445 for (i = 0; i < report->maxfield; ++i) {
446
447 hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n",
448 i, report->field[i]->usage->collection_index,
449 report->field[i]->usage->hid,
450 report->field[i]->report_size/8);
451
452 sz = report->field[i]->report_size/8;
453 if (pdata->pending.status && pdata->pending.attr_usage_id ==
454 report->field[i]->usage->hid) {
455 hid_dbg(hdev, "data was pending ...\n");
456 pdata->pending.raw_data = kmalloc(sz, GFP_ATOMIC);
457 if (pdata->pending.raw_data) {
458 memcpy(pdata->pending.raw_data, ptr, sz);
459 pdata->pending.raw_size = sz;
460 } else
461 pdata->pending.raw_size = 0;
462 complete(&pdata->pending.ready);
463 }
464 collection = &hdev->collection[
465 report->field[i]->usage->collection_index];
466 hid_dbg(hdev, "collection->usage %x\n",
467 collection->usage);
468 callback = sensor_hub_get_callback(pdata->hsdev->hdev,
469 report->field[i]->physical,
470 &priv);
471 if (callback && callback->capture_sample) {
472 if (report->field[i]->logical)
473 callback->capture_sample(pdata->hsdev,
474 report->field[i]->logical, sz, ptr,
475 callback->pdev);
476 else
477 callback->capture_sample(pdata->hsdev,
478 report->field[i]->usage->hid, sz, ptr,
479 callback->pdev);
480 }
481 ptr += sz;
482 }
483 if (callback && collection && callback->send_event)
484 callback->send_event(pdata->hsdev, collection->usage,
485 callback->pdev);
486 spin_unlock_irqrestore(&pdata->lock, flags);
487
488err_report:
489 return 1;
490}
491
492static int sensor_hub_probe(struct hid_device *hdev,
493 const struct hid_device_id *id)
494{
495 int ret;
496 struct sensor_hub_data *sd;
497 int i;
498 char *name;
499 struct hid_report *report;
500 struct hid_report_enum *report_enum;
501 struct hid_field *field;
502 int dev_cnt;
503
504 sd = kzalloc(sizeof(struct sensor_hub_data), GFP_KERNEL);
505 if (!sd) {
506 hid_err(hdev, "cannot allocate Sensor data\n");
507 return -ENOMEM;
508 }
509 sd->hsdev = kzalloc(sizeof(struct hid_sensor_hub_device), GFP_KERNEL);
510 if (!sd->hsdev) {
511 hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
512 ret = -ENOMEM;
513 goto err_free_hub;
514 }
515 hid_set_drvdata(hdev, sd);
516 sd->hsdev->hdev = hdev;
517 sd->hsdev->vendor_id = hdev->vendor;
518 sd->hsdev->product_id = hdev->product;
519 spin_lock_init(&sd->lock);
520 spin_lock_init(&sd->dyn_callback_lock);
521 mutex_init(&sd->mutex);
522 ret = hid_parse(hdev);
523 if (ret) {
524 hid_err(hdev, "parse failed\n");
525 goto err_free;
526 }
527 if (sensor_hub_check_for_sensor_page(hdev) < 0) {
528 hid_err(hdev, "sensor page not found\n");
529 goto err_free;
530 }
531 INIT_LIST_HEAD(&hdev->inputs);
532
533 ret = hid_hw_start(hdev, 0);
534 if (ret) {
535 hid_err(hdev, "hw start failed\n");
536 goto err_free;
537 }
538 ret = hid_hw_open(hdev);
539 if (ret) {
540 hid_err(hdev, "failed to open input interrupt pipe\n");
541 goto err_stop_hw;
542 }
543
544 INIT_LIST_HEAD(&sd->dyn_callback_list);
545 sd->hid_sensor_client_cnt = 0;
546 report_enum = &hdev->report_enum[HID_INPUT_REPORT];
547
548 dev_cnt = sensor_hub_get_physical_device_count(report_enum);
549 if (dev_cnt > HID_MAX_PHY_DEVICES) {
550 hid_err(hdev, "Invalid Physical device count\n");
551 ret = -EINVAL;
552 goto err_close;
553 }
554 sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt *
555 sizeof(struct mfd_cell),
556 GFP_KERNEL);
557 if (sd->hid_sensor_hub_client_devs == NULL) {
558 hid_err(hdev, "Failed to allocate memory for mfd cells\n");
559 ret = -ENOMEM;
560 goto err_close;
561 }
562 list_for_each_entry(report, &report_enum->report_list, list) {
563 hid_dbg(hdev, "Report id:%x\n", report->id);
564 field = report->field[0];
565 if (report->maxfield && field &&
566 field->physical) {
567 name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x",
568 field->physical);
569 if (name == NULL) {
570 hid_err(hdev, "Failed MFD device name\n");
571 ret = -ENOMEM;
572 goto err_free_names;
573 }
574 sd->hid_sensor_hub_client_devs[
575 sd->hid_sensor_client_cnt].name = name;
576 sd->hid_sensor_hub_client_devs[
577 sd->hid_sensor_client_cnt].platform_data =
578 sd->hsdev;
579 sd->hid_sensor_hub_client_devs[
580 sd->hid_sensor_client_cnt].pdata_size =
581 sizeof(*sd->hsdev);
582 hid_dbg(hdev, "Adding %s:%p\n", name, sd);
583 sd->hid_sensor_client_cnt++;
584 }
585 }
586 ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
587 sd->hid_sensor_client_cnt, NULL, 0, NULL);
588 if (ret < 0)
589 goto err_free_names;
590
591 return ret;
592
593err_free_names:
594 for (i = 0; i < sd->hid_sensor_client_cnt ; ++i)
595 kfree(sd->hid_sensor_hub_client_devs[i].name);
596 kfree(sd->hid_sensor_hub_client_devs);
597err_close:
598 hid_hw_close(hdev);
599err_stop_hw:
600 hid_hw_stop(hdev);
601err_free:
602 kfree(sd->hsdev);
603err_free_hub:
604 kfree(sd);
605
606 return ret;
607}
608
609static void sensor_hub_remove(struct hid_device *hdev)
610{
611 struct sensor_hub_data *data = hid_get_drvdata(hdev);
612 unsigned long flags;
613 int i;
614
615 hid_dbg(hdev, " hardware removed\n");
616 hid_hw_close(hdev);
617 hid_hw_stop(hdev);
618 spin_lock_irqsave(&data->lock, flags);
619 if (data->pending.status)
620 complete(&data->pending.ready);
621 spin_unlock_irqrestore(&data->lock, flags);
622 mfd_remove_devices(&hdev->dev);
623 for (i = 0; i < data->hid_sensor_client_cnt ; ++i)
624 kfree(data->hid_sensor_hub_client_devs[i].name);
625 kfree(data->hid_sensor_hub_client_devs);
626 hid_set_drvdata(hdev, NULL);
627 mutex_destroy(&data->mutex);
628 kfree(data->hsdev);
629 kfree(data);
630}
631
632static const struct hid_device_id sensor_hub_devices[] = {
633 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
634 USB_DEVICE_ID_SENSOR_HUB_1020) },
635 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
636 USB_DEVICE_ID_SENSOR_HUB_1020) },
637 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
638 USB_DEVICE_ID_SENSOR_HUB_09FA) },
639 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
640 USB_DEVICE_ID_SENSOR_HUB_09FA) },
641 { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
642 USB_DEVICE_ID_SENSOR_HUB_7014) },
643 { }
644};
645MODULE_DEVICE_TABLE(hid, sensor_hub_devices);
646
647static const struct hid_usage_id sensor_hub_grabbed_usages[] = {
648 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
649 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
650};
651
652static struct hid_driver sensor_hub_driver = {
653 .name = "hid-sensor-hub",
654 .id_table = sensor_hub_devices,
655 .probe = sensor_hub_probe,
656 .remove = sensor_hub_remove,
657 .raw_event = sensor_hub_raw_event,
658#ifdef CONFIG_PM
659 .suspend = sensor_hub_suspend,
660 .resume = sensor_hub_resume,
661 .reset_resume = sensor_hub_reset_resume,
662#endif
663};
664
665static int __init sensor_hub_init(void)
666{
667 return hid_register_driver(&sensor_hub_driver);
668}
669
670static void __exit sensor_hub_exit(void)
671{
672 hid_unregister_driver(&sensor_hub_driver);
673}
674
675module_init(sensor_hub_init);
676module_exit(sensor_hub_exit);
677
678MODULE_DESCRIPTION("HID Sensor Hub driver");
679MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
680MODULE_LICENSE("GPL");