aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-sensor-hub.c
diff options
context:
space:
mode:
authorSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>2014-01-14 12:30:20 -0500
committerJiri Kosina <jkosina@suse.cz>2014-01-16 16:52:34 -0500
commit875e36f8a2ce6cfc2010af6c91fb5351bd530d48 (patch)
treee60e74a4a63523753003e647d4a2e5a877457f91 /drivers/hid/hid-sensor-hub.c
parent1008ebb61e01e3152901b4c5f58bd01a60ed115b (diff)
HID: hid-sensor-hub: Fix buggy report descriptors
This addresses regression caused by commit id "751d17e23a9f7" iio: hid-sensors: Fix power and report state. This commit removed a quirk, to change the enumeration base to 1 from 0 based on an CONFIG paramter. There was objection to add more changes under this quirk, instead suggested to add an HID quirk. But there is no easy way to add HID qurik as the reports are not properly using collection class. The solution was to use logical minimum, which is a correct way. There were changes done in firmware to address this. Unfortunately some devices, still use old FW and can't be upgraded to newer version on Linux devices as there is no FW upgrade tool available for Linux devices. So we need to fix report descriptors, for such devices. This will not have any impact, if the FW uses logical 1 as minimum. In this patch we look for usage id for "power and report state", and modify logical minimum value to 1. Background on enum: In the original HID sensor hub firmwares all Named array enums were to 0-based. But the most recent hub implemented as 1-based, because of the implementation by one of the major OS vendor. Using logical minimum for the field as the base of enum. So we add logical minimum to the selector values before setting those fields. Some sensor hub FWs already changed logical minimum from 0 to 1 to reflect this and hope every other vendor will follow. There is no easy way to add a common HID quirk for NAry elements, even if the standard specifies these field as NAry, the collection used to describe selectors is still just "logical". Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-sensor-hub.c')
-rw-r--r--drivers/hid/hid-sensor-hub.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 8fab82829f8b..46f4480035bc 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -26,6 +26,8 @@
26#include <linux/hid-sensor-hub.h> 26#include <linux/hid-sensor-hub.h>
27#include "hid-ids.h" 27#include "hid-ids.h"
28 28
29#define HID_SENSOR_HUB_ENUM_QUIRK 0x01
30
29/** 31/**
30 * struct sensor_hub_pending - Synchronous read pending information 32 * struct sensor_hub_pending - Synchronous read pending information
31 * @status: Pending status true/false. 33 * @status: Pending status true/false.
@@ -64,6 +66,7 @@ struct sensor_hub_data {
64 spinlock_t dyn_callback_lock; 66 spinlock_t dyn_callback_lock;
65 struct mfd_cell *hid_sensor_hub_client_devs; 67 struct mfd_cell *hid_sensor_hub_client_devs;
66 int hid_sensor_client_cnt; 68 int hid_sensor_client_cnt;
69 unsigned long quirks;
67}; 70};
68 71
69/** 72/**
@@ -497,6 +500,40 @@ void sensor_hub_device_close(struct hid_sensor_hub_device *hsdev)
497} 500}
498EXPORT_SYMBOL_GPL(sensor_hub_device_close); 501EXPORT_SYMBOL_GPL(sensor_hub_device_close);
499 502
503static __u8 *sensor_hub_report_fixup(struct hid_device *hdev, __u8 *rdesc,
504 unsigned int *rsize)
505{
506 int index;
507 struct sensor_hub_data *sd = hid_get_drvdata(hdev);
508 unsigned char report_block[] = {
509 0x0a, 0x16, 0x03, 0x15, 0x00, 0x25, 0x05};
510 unsigned char power_block[] = {
511 0x0a, 0x19, 0x03, 0x15, 0x00, 0x25, 0x05};
512
513 if (!(sd->quirks & HID_SENSOR_HUB_ENUM_QUIRK)) {
514 hid_dbg(hdev, "No Enum quirks\n");
515 return rdesc;
516 }
517
518 /* Looks for power and report state usage id and force to 1 */
519 for (index = 0; index < *rsize; ++index) {
520 if (((*rsize - index) > sizeof(report_block)) &&
521 !memcmp(&rdesc[index], report_block,
522 sizeof(report_block))) {
523 rdesc[index + 4] = 0x01;
524 index += sizeof(report_block);
525 }
526 if (((*rsize - index) > sizeof(power_block)) &&
527 !memcmp(&rdesc[index], power_block,
528 sizeof(power_block))) {
529 rdesc[index + 4] = 0x01;
530 index += sizeof(power_block);
531 }
532 }
533
534 return rdesc;
535}
536
500static int sensor_hub_probe(struct hid_device *hdev, 537static int sensor_hub_probe(struct hid_device *hdev,
501 const struct hid_device_id *id) 538 const struct hid_device_id *id)
502{ 539{
@@ -520,6 +557,7 @@ static int sensor_hub_probe(struct hid_device *hdev,
520 return -ENOMEM; 557 return -ENOMEM;
521 } 558 }
522 hid_set_drvdata(hdev, sd); 559 hid_set_drvdata(hdev, sd);
560 sd->quirks = id->driver_data;
523 sd->hsdev->hdev = hdev; 561 sd->hsdev->hdev = hdev;
524 sd->hsdev->vendor_id = hdev->vendor; 562 sd->hsdev->vendor_id = hdev->vendor;
525 sd->hsdev->product_id = hdev->product; 563 sd->hsdev->product_id = hdev->product;
@@ -621,6 +659,12 @@ static void sensor_hub_remove(struct hid_device *hdev)
621} 659}
622 660
623static const struct hid_device_id sensor_hub_devices[] = { 661static const struct hid_device_id sensor_hub_devices[] = {
662 { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_0,
663 USB_DEVICE_ID_INTEL_HID_SENSOR),
664 .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
665 { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1,
666 USB_DEVICE_ID_INTEL_HID_SENSOR),
667 .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
624 { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID, 668 { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
625 HID_ANY_ID) }, 669 HID_ANY_ID) },
626 { } 670 { }
@@ -633,6 +677,7 @@ static struct hid_driver sensor_hub_driver = {
633 .probe = sensor_hub_probe, 677 .probe = sensor_hub_probe,
634 .remove = sensor_hub_remove, 678 .remove = sensor_hub_remove,
635 .raw_event = sensor_hub_raw_event, 679 .raw_event = sensor_hub_raw_event,
680 .report_fixup = sensor_hub_report_fixup,
636#ifdef CONFIG_PM 681#ifdef CONFIG_PM
637 .suspend = sensor_hub_suspend, 682 .suspend = sensor_hub_suspend,
638 .resume = sensor_hub_resume, 683 .resume = sensor_hub_resume,