aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/Kconfig14
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-sensor-hub.c695
-rw-r--r--include/linux/hid-sensor-hub.h160
-rw-r--r--include/linux/hid-sensor-ids.h112
5 files changed, 982 insertions, 0 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index fbf49503508d..f8d314060853 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -690,6 +690,20 @@ config HID_ZYDACRON
690 ---help--- 690 ---help---
691 Support for Zydacron remote control. 691 Support for Zydacron remote control.
692 692
693config HID_SENSOR_HUB
694 tristate "HID Sensors framework support"
695 depends on USB_HID
696 select MFD_CORE
697 default n
698 -- help---
699 Support for HID Sensor framework. This creates a MFD instance
700 for a sensor hub and identifies all the sensors connected to it.
701 Each sensor is registered as a MFD cell, so that sensor specific
702 processing can be done in a separate driver. Each sensor
703 drivers can use the service provided by this driver to register
704 for events and handle data streams. Each sensor driver can format
705 data and present to user mode using input or IIO interface.
706
693endmenu 707endmenu
694 708
695endif # HID 709endif # HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index f975485f88b2..1173d7af20e8 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -91,6 +91,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
91obj-$(CONFIG_HID_WACOM) += hid-wacom.o 91obj-$(CONFIG_HID_WACOM) += hid-wacom.o
92obj-$(CONFIG_HID_WALTOP) += hid-waltop.o 92obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
93obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o 93obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
94obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
94 95
95obj-$(CONFIG_USB_HID) += usbhid/ 96obj-$(CONFIG_USB_HID) += usbhid/
96obj-$(CONFIG_USB_MOUSE) += usbhid/ 97obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
new file mode 100644
index 000000000000..34a35ba95fc1
--- /dev/null
+++ b/drivers/hid/hid-sensor-hub.c
@@ -0,0 +1,695 @@
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_KERNEL);
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 if (report_id < 0)
218 return -EINVAL;
219
220 mutex_lock(&data->mutex);
221 report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
222 if (!report || (field_index >= report->maxfield)) {
223 ret = -EINVAL;
224 goto done_proc;
225 }
226 hid_set_field(report->field[field_index], 0, value);
227 usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT);
228 usbhid_wait_io(hsdev->hdev);
229
230done_proc:
231 mutex_unlock(&data->mutex);
232
233 return ret;
234}
235EXPORT_SYMBOL_GPL(sensor_hub_set_feature);
236
237int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
238 u32 field_index, s32 *value)
239{
240 struct hid_report *report;
241 struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
242 int ret = 0;
243
244 if (report_id < 0)
245 return -EINVAL;
246
247 mutex_lock(&data->mutex);
248 report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
249 if (!report || (field_index >= report->maxfield)) {
250 ret = -EINVAL;
251 goto done_proc;
252 }
253 usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
254 usbhid_wait_io(hsdev->hdev);
255 *value = report->field[field_index]->value[0];
256
257done_proc:
258 mutex_unlock(&data->mutex);
259
260 return ret;
261}
262EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
263
264
265int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
266 u32 usage_id,
267 u32 attr_usage_id, u32 report_id)
268{
269 struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
270 unsigned long flags;
271 struct hid_report *report;
272 int ret_val = 0;
273
274 if (report_id < 0)
275 return -EINVAL;
276
277 mutex_lock(&data->mutex);
278 memset(&data->pending, 0, sizeof(data->pending));
279 init_completion(&data->pending.ready);
280 data->pending.usage_id = usage_id;
281 data->pending.attr_usage_id = attr_usage_id;
282 data->pending.raw_size = 0;
283
284 spin_lock_irqsave(&data->lock, flags);
285 data->pending.status = true;
286 report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
287 if (!report) {
288 spin_unlock_irqrestore(&data->lock, flags);
289 goto err_free;
290 }
291 usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
292 spin_unlock_irqrestore(&data->lock, flags);
293 wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
294 switch (data->pending.raw_size) {
295 case 1:
296 ret_val = *(u8 *)data->pending.raw_data;
297 break;
298 case 2:
299 ret_val = *(u16 *)data->pending.raw_data;
300 break;
301 case 4:
302 ret_val = *(u32 *)data->pending.raw_data;
303 break;
304 default:
305 ret_val = 0;
306 }
307 kfree(data->pending.raw_data);
308
309err_free:
310 data->pending.status = false;
311 mutex_unlock(&data->mutex);
312
313 return ret_val;
314}
315EXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value);
316
317int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
318 u8 type,
319 u32 usage_id,
320 u32 attr_usage_id,
321 struct hid_sensor_hub_attribute_info *info)
322{
323 int ret = -1;
324 int i, j;
325 int collection_index = -1;
326 struct hid_report *report;
327 struct hid_field *field;
328 struct hid_report_enum *report_enum;
329 struct hid_device *hdev = hsdev->hdev;
330
331 /* Initialize with defaults */
332 info->usage_id = usage_id;
333 info->attrib_id = attr_usage_id;
334 info->report_id = -1;
335 info->index = -1;
336 info->units = -1;
337 info->unit_expo = -1;
338
339 for (i = 0; i < hdev->maxcollection; ++i) {
340 struct hid_collection *collection = &hdev->collection[i];
341 if (usage_id == collection->usage) {
342 collection_index = i;
343 break;
344 }
345 }
346 if (collection_index == -1)
347 goto err_ret;
348
349 report_enum = &hdev->report_enum[type];
350 list_for_each_entry(report, &report_enum->report_list, list) {
351 for (i = 0; i < report->maxfield; ++i) {
352 field = report->field[i];
353 if (field->physical == usage_id &&
354 field->logical == attr_usage_id) {
355 sensor_hub_fill_attr_info(info, i, report->id,
356 field->unit, field->unit_exponent,
357 field->report_size);
358 ret = 0;
359 } else {
360 for (j = 0; j < field->maxusage; ++j) {
361 if (field->usage[j].hid ==
362 attr_usage_id &&
363 field->usage[j].collection_index ==
364 collection_index) {
365 sensor_hub_fill_attr_info(info,
366 i, report->id,
367 field->unit,
368 field->unit_exponent,
369 field->report_size);
370 ret = 0;
371 break;
372 }
373 }
374 }
375 if (ret == 0)
376 break;
377 }
378 }
379
380err_ret:
381 return ret;
382}
383EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info);
384
385#ifdef CONFIG_PM
386static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message)
387{
388 struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
389 struct hid_sensor_hub_callbacks_list *callback;
390
391 hid_dbg(hdev, " sensor_hub_suspend\n");
392 spin_lock(&pdata->dyn_callback_lock);
393 list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
394 if (callback->usage_callback->suspend)
395 callback->usage_callback->suspend(
396 pdata->hsdev, callback->priv);
397 }
398 spin_unlock(&pdata->dyn_callback_lock);
399
400 return 0;
401}
402
403static int sensor_hub_resume(struct hid_device *hdev)
404{
405 struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
406 struct hid_sensor_hub_callbacks_list *callback;
407
408 hid_dbg(hdev, " sensor_hub_resume\n");
409 spin_lock(&pdata->dyn_callback_lock);
410 list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
411 if (callback->usage_callback->resume)
412 callback->usage_callback->resume(
413 pdata->hsdev, callback->priv);
414 }
415 spin_unlock(&pdata->dyn_callback_lock);
416
417 return 0;
418}
419
420static int sensor_hub_reset_resume(struct hid_device *hdev)
421{
422 return 0;
423}
424#endif
425/*
426 * Handle raw report as sent by device
427 */
428static int sensor_hub_raw_event(struct hid_device *hdev,
429 struct hid_report *report, u8 *raw_data, int size)
430{
431 int i;
432 u8 *ptr;
433 int sz;
434 struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
435 unsigned long flags;
436 struct hid_sensor_hub_callbacks *callback = NULL;
437 struct hid_collection *collection = NULL;
438 void *priv = NULL;
439
440 hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
441 report->id, size, report->type);
442 hid_dbg(hdev, "maxfield:%d\n", report->maxfield);
443 if (report->type != HID_INPUT_REPORT)
444 return 1;
445
446 ptr = raw_data;
447 ptr++; /*Skip report id*/
448
449 if (!report)
450 goto err_report;
451
452 spin_lock_irqsave(&pdata->lock, flags);
453
454 for (i = 0; i < report->maxfield; ++i) {
455
456 hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n",
457 i, report->field[i]->usage->collection_index,
458 report->field[i]->usage->hid,
459 report->field[i]->report_size/8);
460
461 sz = report->field[i]->report_size/8;
462 if (pdata->pending.status && pdata->pending.attr_usage_id ==
463 report->field[i]->usage->hid) {
464 hid_dbg(hdev, "data was pending ...\n");
465 pdata->pending.raw_data = kmalloc(sz, GFP_KERNEL);
466 if (pdata->pending.raw_data) {
467 memcpy(pdata->pending.raw_data, ptr, sz);
468 pdata->pending.raw_size = sz;
469 } else
470 pdata->pending.raw_size = 0;
471 complete(&pdata->pending.ready);
472 }
473 collection = &hdev->collection[
474 report->field[i]->usage->collection_index];
475 hid_dbg(hdev, "collection->usage %x\n",
476 collection->usage);
477 callback = sensor_hub_get_callback(pdata->hsdev->hdev,
478 report->field[i]->physical,
479 &priv);
480 if (callback && callback->capture_sample) {
481 if (report->field[i]->logical)
482 callback->capture_sample(pdata->hsdev,
483 report->field[i]->logical, sz, ptr,
484 callback->pdev);
485 else
486 callback->capture_sample(pdata->hsdev,
487 report->field[i]->usage->hid, sz, ptr,
488 callback->pdev);
489 }
490 ptr += sz;
491 }
492 if (callback && collection && callback->send_event)
493 callback->send_event(pdata->hsdev, collection->usage,
494 callback->pdev);
495 spin_unlock_irqrestore(&pdata->lock, flags);
496
497err_report:
498 return 1;
499}
500
501static int sensor_hub_probe(struct hid_device *hdev,
502 const struct hid_device_id *id)
503{
504 int ret;
505 struct sensor_hub_data *sd;
506 int i;
507 char *name;
508 struct hid_report *report;
509 struct hid_report_enum *report_enum;
510 struct hid_field *field;
511 int dev_cnt;
512
513 sd = kzalloc(sizeof(struct sensor_hub_data), GFP_KERNEL);
514 if (!sd) {
515 hid_err(hdev, "cannot allocate Sensor data\n");
516 return -ENOMEM;
517 }
518 sd->hsdev = kzalloc(sizeof(struct hid_sensor_hub_device), GFP_KERNEL);
519 if (!sd->hsdev) {
520 hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
521 ret = -ENOMEM;
522 goto err_free_hub;
523 }
524 hid_set_drvdata(hdev, sd);
525 sd->hsdev->hdev = hdev;
526 sd->hsdev->vendor_id = hdev->vendor;
527 sd->hsdev->product_id = hdev->product;
528 spin_lock_init(&sd->lock);
529 spin_lock_init(&sd->dyn_callback_lock);
530 mutex_init(&sd->mutex);
531 ret = hid_parse(hdev);
532 if (ret) {
533 hid_err(hdev, "parse failed\n");
534 goto err_free;
535 }
536 if (sensor_hub_check_for_sensor_page(hdev) < 0) {
537 hid_err(hdev, "sensor page not found\n");
538 goto err_free;
539 }
540 INIT_LIST_HEAD(&hdev->inputs);
541
542 hdev->claimed = HID_CLAIMED_INPUT;
543 ret = hid_hw_start(hdev, 0);
544 if (ret) {
545 hid_err(hdev, "hw start failed\n");
546 goto err_free;
547 }
548 ret = hid_hw_open(hdev);
549 if (ret) {
550 hid_err(hdev, "failed to open input interrupt pipe\n");
551 goto err_stop_hw;
552 }
553
554 INIT_LIST_HEAD(&sd->dyn_callback_list);
555 sd->hid_sensor_client_cnt = 0;
556 report_enum = &hdev->report_enum[HID_INPUT_REPORT];
557
558 dev_cnt = sensor_hub_get_physical_device_count(report_enum);
559 if (dev_cnt > HID_MAX_PHY_DEVICES) {
560 hid_err(hdev, "Invalid Physical device count\n");
561 ret = -EINVAL;
562 goto err_close;
563 }
564 sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt *
565 sizeof(struct mfd_cell),
566 GFP_KERNEL);
567 if (sd->hid_sensor_hub_client_devs == NULL) {
568 hid_err(hdev,
569 "Failed to allocate memory for mfd cells\n");
570 ret = -ENOMEM;
571 goto err_close;
572 }
573 list_for_each_entry(report, &report_enum->report_list, list) {
574 hid_dbg(hdev, "Report id:%x\n", report->id);
575 field = report->field[0];
576 if (report->maxfield && field &&
577 field->physical) {
578 name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x",
579 field->physical);
580 if (name == NULL) {
581 hid_err(hdev,
582 "Failed MFD device name\n");
583 ret = -ENOMEM;
584 goto err_free_cells;
585 }
586 sd->hid_sensor_hub_client_devs[
587 sd->hid_sensor_client_cnt].name = name;
588 sd->hid_sensor_hub_client_devs[
589 sd->hid_sensor_client_cnt].platform_data =
590 sd->hsdev;
591 sd->hid_sensor_hub_client_devs[
592 sd->hid_sensor_client_cnt].pdata_size =
593 sizeof(*sd->hsdev);
594 hid_dbg(hdev, "Adding %s:%p\n", name, sd);
595 sd->hid_sensor_client_cnt++;
596 }
597 }
598 ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
599 sd->hid_sensor_client_cnt, NULL, 0);
600 if (ret < 0)
601 goto err_free_names;
602
603 return ret;
604
605err_free_names:
606 for (i = 0; i < sd->hid_sensor_client_cnt ; ++i)
607 kfree(sd->hid_sensor_hub_client_devs[i].name);
608err_free_cells:
609 kfree(sd->hid_sensor_hub_client_devs);
610err_close:
611 hid_hw_stop(hdev);
612 hid_hw_close(hdev);
613err_stop_hw:
614 hid_hw_stop(hdev);
615err_free:
616 kfree(sd->hsdev);
617err_free_hub:
618 kfree(sd);
619
620 return ret;
621}
622
623static void sensor_hub_remove(struct hid_device *hdev)
624{
625 struct sensor_hub_data *data = hid_get_drvdata(hdev);
626 unsigned long flags;
627 int i;
628
629 hid_dbg(hdev, " hardware removed\n");
630 hdev->claimed &= ~HID_CLAIMED_INPUT;
631 hid_hw_stop(hdev);
632 hid_hw_close(hdev);
633 spin_lock_irqsave(&data->lock, flags);
634 if (data->pending.status)
635 complete(&data->pending.ready);
636 spin_unlock_irqrestore(&data->lock, flags);
637 mfd_remove_devices(&hdev->dev);
638 for (i = 0; i < data->hid_sensor_client_cnt ; ++i)
639 kfree(data->hid_sensor_hub_client_devs[i].name);
640 kfree(data->hid_sensor_hub_client_devs);
641 hid_set_drvdata(hdev, NULL);
642 mutex_destroy(&data->mutex);
643 kfree(data->hsdev);
644 kfree(data);
645}
646
647static const struct hid_device_id sensor_hub_devices[] = {
648 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
649 USB_DEVICE_ID_SENSOR_HUB_1020) },
650 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
651 USB_DEVICE_ID_SENSOR_HUB_1020) },
652 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
653 USB_DEVICE_ID_SENSOR_HUB_09FA) },
654 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
655 USB_DEVICE_ID_SENSOR_HUB_09FA) },
656 { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
657 USB_DEVICE_ID_SENSOR_HUB_7014) },
658 { }
659};
660MODULE_DEVICE_TABLE(hid, sensor_hub_devices);
661
662static const struct hid_usage_id sensor_hub_grabbed_usages[] = {
663 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
664 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
665};
666
667static struct hid_driver sensor_hub_driver = {
668 .name = "hid-sensor-hub",
669 .id_table = sensor_hub_devices,
670 .probe = sensor_hub_probe,
671 .remove = sensor_hub_remove,
672 .raw_event = sensor_hub_raw_event,
673#ifdef CONFIG_PM
674 .suspend = sensor_hub_suspend,
675 .resume = sensor_hub_resume,
676 .reset_resume = sensor_hub_reset_resume,
677#endif
678};
679
680static int __init sensor_hub_init(void)
681{
682 return hid_register_driver(&sensor_hub_driver);
683}
684
685static void __exit sensor_hub_exit(void)
686{
687 hid_unregister_driver(&sensor_hub_driver);
688}
689
690module_init(sensor_hub_init);
691module_exit(sensor_hub_exit);
692
693MODULE_DESCRIPTION("HID Sensor Hub driver");
694MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
695MODULE_LICENSE("GPL");
diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h
new file mode 100644
index 000000000000..0aa5f4c42ae6
--- /dev/null
+++ b/include/linux/hid-sensor-hub.h
@@ -0,0 +1,160 @@
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#ifndef _HID_SENSORS_HUB_H
20#define _HID_SENSORS_HUB_H
21
22#include <linux/hid.h>
23#include <linux/hid-sensor-ids.h>
24
25/**
26 * struct hid_sensor_hub_attribute_info - Attribute info
27 * @usage_id: Parent usage id of a physical device.
28 * @attrib_id: Attribute id for this attribute.
29 * @report_id: Report id in which this information resides.
30 * @index: Field index in the report.
31 * @units: Measurment unit for this attribute.
32 * @unit_expo: Exponent used in the data.
33 * @size: Size in bytes for data size.
34 */
35struct hid_sensor_hub_attribute_info {
36 u32 usage_id;
37 u32 attrib_id;
38 s32 report_id;
39 s32 index;
40 s32 units;
41 s32 unit_expo;
42 s32 size;
43};
44
45/**
46 * struct hid_sensor_hub_device - Stores the hub instance data
47 * @hdev: Stores the hid instance.
48 * @vendor_id: Vendor id of hub device.
49 * @product_id: Product id of hub device.
50 */
51struct hid_sensor_hub_device {
52 struct hid_device *hdev;
53 u32 vendor_id;
54 u32 product_id;
55};
56
57/**
58 * struct hid_sensor_hub_callbacks - Client callback functions
59 * @pdev: Platform device instance of the client driver.
60 * @suspend: Suspend callback.
61 * @resume: Resume callback.
62 * @capture_sample: Callback to get a sample.
63 * @send_event: Send notification to indicate all samples are
64 * captured, process and send event
65 */
66struct hid_sensor_hub_callbacks {
67 struct platform_device *pdev;
68 int (*suspend)(struct hid_sensor_hub_device *hsdev, void *priv);
69 int (*resume)(struct hid_sensor_hub_device *hsdev, void *priv);
70 int (*capture_sample)(struct hid_sensor_hub_device *hsdev,
71 u32 usage_id, size_t raw_len, char *raw_data,
72 void *priv);
73 int (*send_event)(struct hid_sensor_hub_device *hsdev, u32 usage_id,
74 void *priv);
75};
76
77/* Registration functions */
78
79/**
80* sensor_hub_register_callback() - Register client callbacks
81* @hsdev: Hub device instance.
82* @usage_id: Usage id of the client (E.g. 0x200076 for Gyro).
83* @usage_callback: Callback function storage
84*
85* Used to register callbacks by client processing drivers. Sensor
86* hub core driver will call these callbacks to offload processing
87* of data streams and notifications.
88*/
89int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
90 u32 usage_id,
91 struct hid_sensor_hub_callbacks *usage_callback);
92
93/**
94* sensor_hub_remove_callback() - Remove client callbacks
95* @hsdev: Hub device instance.
96* @usage_id: Usage id of the client (E.g. 0x200076 for Gyro).
97*
98* If there is a callback registred, this call will remove that
99* callbacks, so that it will stop data and event notifications.
100*/
101int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
102 u32 usage_id);
103
104
105/* Hid sensor hub core interfaces */
106
107/**
108* sensor_hub_input_get_attribute_info() - Get an attribute information
109* @hsdev: Hub device instance.
110* @type: Type of this attribute, input/output/feature
111* @usage_id: Attribute usage id of parent physical device as per spec
112* @attr_usage_id: Attribute usage id as per spec
113* @info: return information about attribute after parsing report
114*
115* Parses report and returns the attribute information such as report id,
116* field index, units and exponet etc.
117*/
118int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
119 u8 type,
120 u32 usage_id, u32 attr_usage_id,
121 struct hid_sensor_hub_attribute_info *info);
122
123/**
124* sensor_hub_input_attr_get_raw_value() - Synchronous read request
125* @usage_id: Attribute usage id of parent physical device as per spec
126* @attr_usage_id: Attribute usage id as per spec
127* @report_id: Report id to look for
128*
129* Issues a synchronous read request for an input attribute. Returns
130* data upto 32 bits. Since client can get events, so this call should
131* not be used for data paths, this will impact performance.
132*/
133
134int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
135 u32 usage_id,
136 u32 attr_usage_id, u32 report_id);
137/**
138* sensor_hub_set_feature() - Feature set request
139* @report_id: Report id to look for
140* @field_index: Field index inside a report
141* @value: Value to set
142*
143* Used to set a field in feature report. For example this can set polling
144* interval, sensitivity, activate/deactivate state.
145*/
146int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
147 u32 field_index, s32 value);
148
149/**
150* sensor_hub_get_feature() - Feature get request
151* @report_id: Report id to look for
152* @field_index: Field index inside a report
153* @value: Place holder for return value
154*
155* Used to get a field in feature report. For example this can get polling
156* interval, sensitivity, activate/deactivate state.
157*/
158int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
159 u32 field_index, s32 *value);
160#endif
diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h
new file mode 100644
index 000000000000..ca8d7e94eb3c
--- /dev/null
+++ b/include/linux/hid-sensor-ids.h
@@ -0,0 +1,112 @@
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#ifndef _HID_SENSORS_IDS_H
20#define _HID_SENSORS_IDS_H
21
22#define HID_UP_SENSOR 0x00200000
23#define HID_MAX_PHY_DEVICES 0xFF
24
25/* Accel 3D (200073) */
26#define HID_USAGE_SENSOR_ACCEL_3D 0x200073
27#define HID_USAGE_SENSOR_ACCEL_X_AXIS 0x200453
28#define HID_USAGE_SENSOR_ACCEL_Y_AXIS 0x200454
29#define HID_USAGE_SENSOR_ACCEL_Z_AXIS 0x200455
30
31/* ALS (200041) */
32#define HID_USAGE_SENSOR_ALS 0x200041
33#define HID_USAGE_SENSOR_LIGHT_ILLUM 0x2004d1
34
35/* Gyro 3D: (200076) */
36#define HID_USAGE_SENSOR_GYRO_3D 0x200076
37#define HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS 0x200457
38#define HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS 0x200458
39#define HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS 0x200459
40
41/*ORIENTATION: Compass 3D: (200083) */
42#define HID_USAGE_SENSOR_COMPASS_3D 0x200083
43#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING 0x200471
44#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING_X 0x200472
45#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING_Y 0x200473
46#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING_Z 0x200474
47
48#define HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH 0x200475
49#define HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH 0x200476
50#define HID_USAGE_SENSOR_ORIENT_MAGN_NORTH 0x200477
51#define HID_USAGE_SENSOR_ORIENT_TRUE_NORTH 0x200478
52
53#define HID_USAGE_SENSOR_ORIENT_DISTANCE 0x200479
54#define HID_USAGE_SENSOR_ORIENT_DISTANCE_X 0x20047A
55#define HID_USAGE_SENSOR_ORIENT_DISTANCE_Y 0x20047B
56#define HID_USAGE_SENSOR_ORIENT_DISTANCE_Z 0x20047C
57#define HID_USAGE_SENSOR_ORIENT_DISTANCE_OUT_OF_RANGE 0x20047D
58#define HID_USAGE_SENSOR_ORIENT_TILT 0x20047E
59#define HID_USAGE_SENSOR_ORIENT_TILT_X 0x20047F
60#define HID_USAGE_SENSOR_ORIENT_TILT_Y 0x200480
61#define HID_USAGE_SENSOR_ORIENT_TILT_Z 0x200481
62#define HID_USAGE_SENSOR_ORIENT_ROTATION_MATRIX 0x200482
63#define HID_USAGE_SENSOR_ORIENT_QUATERNION 0x200483
64#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX 0x200484
65
66#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS 0x200485
67#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS 0x200486
68#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS 0x200487
69
70/* Units */
71#define HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED 0x00
72#define HID_USAGE_SENSOR_UNITS_LUX 0x01
73#define HID_USAGE_SENSOR_UNITS_KELVIN 0x01000100
74#define HID_USAGE_SENSOR_UNITS_FAHRENHEIT 0x03000100
75#define HID_USAGE_SENSOR_UNITS_PASCAL 0xF1E1
76#define HID_USAGE_SENSOR_UNITS_NEWTON 0x11E1
77#define HID_USAGE_SENSOR_UNITS_METERS_PER_SECOND 0x11F0
78#define HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD 0x11E0
79#define HID_USAGE_SENSOR_UNITS_FARAD 0xE14F2000
80#define HID_USAGE_SENSOR_UNITS_AMPERE 0x01001000
81#define HID_USAGE_SENSOR_UNITS_WATT 0x21d1
82#define HID_USAGE_SENSOR_UNITS_HENRY 0x21E1E000
83#define HID_USAGE_SENSOR_UNITS_OHM 0x21D1E000
84#define HID_USAGE_SENSOR_UNITS_VOLT 0x21D1F000
85#define HID_USAGE_SENSOR_UNITS_HERTZ 0x01F0
86#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SEC_SQRD 0x14E0
87#define HID_USAGE_SENSOR_UNITS_RADIANS 0x12
88#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND 0x12F0
89#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SEC_SQRD 0x12E0
90#define HID_USAGE_SENSOR_UNITS_SECOND 0x0110
91#define HID_USAGE_SENSOR_UNITS_GAUSS 0x01E1F000
92#define HID_USAGE_SENSOR_UNITS_GRAM 0x0101
93#define HID_USAGE_SENSOR_UNITS_CENTIMETER 0x11
94#define HID_USAGE_SENSOR_UNITS_G 0x1A
95#define HID_USAGE_SENSOR_UNITS_MILLISECOND 0x19
96#define HID_USAGE_SENSOR_UNITS_PERCENT 0x17
97#define HID_USAGE_SENSOR_UNITS_DEGREES 0x14
98#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND 0x15
99
100/* Common selectors */
101#define HID_USAGE_SENSOR_PROP_REPORT_INTERVAL 0x20030E
102#define HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS 0x20030F
103#define HID_USAGE_SENSOR_PROP_SENSITIVITY_RANGE_PCT 0x200310
104#define HID_USAGE_SENSOR_PROP_SENSITIVITY_REL_PCT 0x200311
105#define HID_USAGE_SENSOR_PROP_ACCURACY 0x200312
106#define HID_USAGE_SENSOR_PROP_RESOLUTION 0x200313
107#define HID_USAGE_SENSOR_PROP_RANGE_MAXIMUM 0x200314
108#define HID_USAGE_SENSOR_PROP_RANGE_MINIMUM 0x200315
109#define HID_USAGE_SENSOR_PROP_REPORT_STATE 0x200316
110#define HID_USAGE_SENSOR_PROY_POWER_STATE 0x200319
111
112#endif