diff options
Diffstat (limited to 'drivers/hid/hid-sensor-hub.c')
| -rw-r--r-- | drivers/hid/hid-sensor-hub.c | 481 |
1 files changed, 276 insertions, 205 deletions
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index d9d73e9163e..e244e449cbb 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -18,8 +18,6 @@ */ #include <linux/device.h> #include <linux/hid.h> -#include <linux/usb.h> -#include "usbhid/usbhid.h" #include <linux/module.h> #include <linux/slab.h> #include <linux/mfd/core.h> @@ -28,6 +26,8 @@ #include <linux/hid-sensor-hub.h> #include "hid-ids.h" +#define HID_SENSOR_HUB_ENUM_QUIRK 0x01 + /** * struct sensor_hub_pending - Synchronous read pending information * @status: Pending status true/false. @@ -56,9 +56,9 @@ struct sensor_hub_pending { * @dyn_callback_lock: spin lock to protect callback list * @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance. * @hid_sensor_client_cnt: Number of MFD cells, (no of sensors attached). + * @ref_cnt: Number of MFD clients have opened this device */ struct sensor_hub_data { - struct hid_sensor_hub_device *hsdev; struct mutex mutex; spinlock_t lock; struct sensor_hub_pending pending; @@ -66,6 +66,8 @@ struct sensor_hub_data { spinlock_t dyn_callback_lock; struct mfd_cell *hid_sensor_hub_client_devs; int hid_sensor_client_cnt; + unsigned long quirks; + int ref_cnt; }; /** @@ -78,27 +80,11 @@ struct sensor_hub_data { struct hid_sensor_hub_callbacks_list { struct list_head list; u32 usage_id; + struct hid_sensor_hub_device *hsdev; struct hid_sensor_hub_callbacks *usage_callback; void *priv; }; -static int sensor_hub_check_for_sensor_page(struct hid_device *hdev) -{ - int i; - int ret = -EINVAL; - - for (i = 0; i < hdev->maxcollection; i++) { - struct hid_collection *col = &hdev->collection[i]; - if (col->type == HID_COLLECTION_PHYSICAL && - (col->usage & HID_USAGE_PAGE) == HID_UP_SENSOR) { - ret = 0; - break; - } - } - - return ret; -} - static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev, int dir) { @@ -113,45 +99,52 @@ static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev, return NULL; } -static int sensor_hub_get_physical_device_count( - struct hid_report_enum *report_enum) +static int sensor_hub_get_physical_device_count(struct hid_device *hdev) { - struct hid_report *report; - struct hid_field *field; - int cnt = 0; + int i; + int count = 0; - list_for_each_entry(report, &report_enum->report_list, list) { - field = report->field[0]; - if (report->maxfield && field && - field->physical) - cnt++; + for (i = 0; i < hdev->maxcollection; ++i) { + struct hid_collection *collection = &hdev->collection[i]; + if (collection->type == HID_COLLECTION_PHYSICAL) + ++count; } - return cnt; + return count; } static void sensor_hub_fill_attr_info( struct hid_sensor_hub_attribute_info *info, - s32 index, s32 report_id, s32 units, s32 unit_expo, s32 size) + s32 index, s32 report_id, struct hid_field *field) { info->index = index; info->report_id = report_id; - info->units = units; - info->unit_expo = unit_expo; - info->size = size/8; + info->units = field->unit; + info->unit_expo = field->unit_exponent; + info->size = (field->report_size * field->report_count)/8; + info->logical_minimum = field->logical_minimum; + info->logical_maximum = field->logical_maximum; } static struct hid_sensor_hub_callbacks *sensor_hub_get_callback( struct hid_device *hdev, - u32 usage_id, void **priv) + u32 usage_id, + int collection_index, + struct hid_sensor_hub_device **hsdev, + void **priv) { struct hid_sensor_hub_callbacks_list *callback; struct sensor_hub_data *pdata = hid_get_drvdata(hdev); spin_lock(&pdata->dyn_callback_lock); list_for_each_entry(callback, &pdata->dyn_callback_list, list) - if (callback->usage_id == usage_id) { + if (callback->usage_id == usage_id && + (collection_index >= + callback->hsdev->start_collection_index) && + (collection_index < + callback->hsdev->end_collection_index)) { *priv = callback->priv; + *hsdev = callback->hsdev; spin_unlock(&pdata->dyn_callback_lock); return callback->usage_callback; } @@ -166,23 +159,26 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, { struct hid_sensor_hub_callbacks_list *callback; struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); + unsigned long flags; - spin_lock(&pdata->dyn_callback_lock); + spin_lock_irqsave(&pdata->dyn_callback_lock, flags); list_for_each_entry(callback, &pdata->dyn_callback_list, list) - if (callback->usage_id == usage_id) { - spin_unlock(&pdata->dyn_callback_lock); + if (callback->usage_id == usage_id && + callback->hsdev == hsdev) { + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return -EINVAL; } callback = kzalloc(sizeof(*callback), GFP_ATOMIC); if (!callback) { - spin_unlock(&pdata->dyn_callback_lock); + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return -ENOMEM; } + callback->hsdev = hsdev; callback->usage_callback = usage_callback; callback->usage_id = usage_id; callback->priv = NULL; list_add_tail(&callback->list, &pdata->dyn_callback_list); - spin_unlock(&pdata->dyn_callback_lock); + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return 0; } @@ -193,15 +189,17 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, { struct hid_sensor_hub_callbacks_list *callback; struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); + unsigned long flags; - spin_lock(&pdata->dyn_callback_lock); + spin_lock_irqsave(&pdata->dyn_callback_lock, flags); list_for_each_entry(callback, &pdata->dyn_callback_list, list) - if (callback->usage_id == usage_id) { + if (callback->usage_id == usage_id && + callback->hsdev == hsdev) { list_del(&callback->list); kfree(callback); break; } - spin_unlock(&pdata->dyn_callback_lock); + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return 0; } @@ -211,18 +209,18 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, u32 field_index, s32 value) { struct hid_report *report; - struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); int ret = 0; mutex_lock(&data->mutex); report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); - if (!report || (field_index >= report->maxfield)) { + if (!report || (field_index >= report->maxfield)) { ret = -EINVAL; goto done_proc; } hid_set_field(report->field[field_index], 0, value); - usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT); - usbhid_wait_io(hsdev->hdev); + hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT); + hid_hw_wait(hsdev->hdev); done_proc: mutex_unlock(&data->mutex); @@ -235,17 +233,18 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, u32 field_index, s32 *value) { struct hid_report *report; - struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); int ret = 0; mutex_lock(&data->mutex); report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); - if (!report || (field_index >= report->maxfield)) { + if (!report || (field_index >= report->maxfield) || + report->field[field_index]->report_count < 1) { ret = -EINVAL; goto done_proc; } - usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN); - usbhid_wait_io(hsdev->hdev); + hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); + hid_hw_wait(hsdev->hdev); *value = report->field[field_index]->value[0]; done_proc: @@ -260,7 +259,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, u32 usage_id, u32 attr_usage_id, u32 report_id) { - struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); unsigned long flags; struct hid_report *report; int ret_val = 0; @@ -274,13 +273,12 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, spin_lock_irqsave(&data->lock, flags); data->pending.status = true; + spin_unlock_irqrestore(&data->lock, flags); report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT); - if (!report) { - spin_unlock_irqrestore(&data->lock, flags); + if (!report) goto err_free; - } - usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN); - spin_unlock_irqrestore(&data->lock, flags); + + hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5); switch (data->pending.raw_size) { case 1: @@ -305,6 +303,28 @@ err_free: } EXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value); +int hid_sensor_get_usage_index(struct hid_sensor_hub_device *hsdev, + u32 report_id, int field_index, u32 usage_id) +{ + struct hid_report *report; + struct hid_field *field; + int i; + + report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); + if (!report || (field_index >= report->maxfield)) + goto done_proc; + + field = report->field[field_index]; + for (i = 0; i < field->maxusage; ++i) { + if (field->usage[i].hid == usage_id) + return field->usage[i].usage_index; + } + +done_proc: + return -EINVAL; +} +EXPORT_SYMBOL_GPL(hid_sensor_get_usage_index); + int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, u8 type, u32 usage_id, @@ -312,8 +332,7 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, struct hid_sensor_hub_attribute_info *info) { int ret = -1; - int i, j; - int collection_index = -1; + int i; struct hid_report *report; struct hid_field *field; struct hid_report_enum *report_enum; @@ -321,54 +340,37 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, /* Initialize with defaults */ info->usage_id = usage_id; - info->attrib_id = attr_usage_id; + info->attrib_id = attr_usage_id; info->report_id = -1; info->index = -1; info->units = -1; info->unit_expo = -1; - for (i = 0; i < hdev->maxcollection; ++i) { - struct hid_collection *collection = &hdev->collection[i]; - if (usage_id == collection->usage) { - collection_index = i; - break; - } - } - if (collection_index == -1) - goto err_ret; - report_enum = &hdev->report_enum[type]; list_for_each_entry(report, &report_enum->report_list, list) { for (i = 0; i < report->maxfield; ++i) { field = report->field[i]; - if (field->physical == usage_id && - field->logical == attr_usage_id) { - sensor_hub_fill_attr_info(info, i, report->id, - field->unit, field->unit_exponent, - field->report_size); - ret = 0; - } else { - for (j = 0; j < field->maxusage; ++j) { - if (field->usage[j].hid == - attr_usage_id && - field->usage[j].collection_index == - collection_index) { - sensor_hub_fill_attr_info(info, - i, report->id, - field->unit, - field->unit_exponent, - field->report_size); - ret = 0; - break; - } + if (field->maxusage) { + if (field->physical == usage_id && + (field->logical == attr_usage_id || + field->usage[0].hid == + attr_usage_id) && + (field->usage[0].collection_index >= + hsdev->start_collection_index) && + (field->usage[0].collection_index < + hsdev->end_collection_index)) { + + sensor_hub_fill_attr_info(info, i, + report->id, + field); + ret = 0; + break; } } - if (ret == 0) - break; } + } -err_ret: return ret; } EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info); @@ -376,34 +378,36 @@ EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info); #ifdef CONFIG_PM static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message) { - struct sensor_hub_data *pdata = hid_get_drvdata(hdev); + struct sensor_hub_data *pdata = hid_get_drvdata(hdev); struct hid_sensor_hub_callbacks_list *callback; + unsigned long flags; hid_dbg(hdev, " sensor_hub_suspend\n"); - spin_lock(&pdata->dyn_callback_lock); + spin_lock_irqsave(&pdata->dyn_callback_lock, flags); list_for_each_entry(callback, &pdata->dyn_callback_list, list) { if (callback->usage_callback->suspend) callback->usage_callback->suspend( - pdata->hsdev, callback->priv); + callback->hsdev, callback->priv); } - spin_unlock(&pdata->dyn_callback_lock); + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return 0; } static int sensor_hub_resume(struct hid_device *hdev) { - struct sensor_hub_data *pdata = hid_get_drvdata(hdev); + struct sensor_hub_data *pdata = hid_get_drvdata(hdev); struct hid_sensor_hub_callbacks_list *callback; + unsigned long flags; hid_dbg(hdev, " sensor_hub_resume\n"); - spin_lock(&pdata->dyn_callback_lock); + spin_lock_irqsave(&pdata->dyn_callback_lock, flags); list_for_each_entry(callback, &pdata->dyn_callback_list, list) { if (callback->usage_callback->resume) callback->usage_callback->resume( - pdata->hsdev, callback->priv); + callback->hsdev, callback->priv); } - spin_unlock(&pdata->dyn_callback_lock); + spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); return 0; } @@ -413,6 +417,7 @@ static int sensor_hub_reset_resume(struct hid_device *hdev) return 0; } #endif + /* * Handle raw report as sent by device */ @@ -427,6 +432,7 @@ static int sensor_hub_raw_event(struct hid_device *hdev, struct hid_sensor_hub_callbacks *callback = NULL; struct hid_collection *collection = NULL; void *priv = NULL; + struct hid_sensor_hub_device *hsdev = NULL; hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n", report->id, size, report->type); @@ -435,29 +441,25 @@ static int sensor_hub_raw_event(struct hid_device *hdev, return 1; ptr = raw_data; - ptr++; /*Skip report id*/ - - if (!report) - goto err_report; + ptr++; /* Skip report id */ spin_lock_irqsave(&pdata->lock, flags); for (i = 0; i < report->maxfield; ++i) { - hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n", i, report->field[i]->usage->collection_index, report->field[i]->usage->hid, - report->field[i]->report_size/8); - - sz = report->field[i]->report_size/8; + (report->field[i]->report_size * + report->field[i]->report_count)/8); + sz = (report->field[i]->report_size * + report->field[i]->report_count)/8; if (pdata->pending.status && pdata->pending.attr_usage_id == report->field[i]->usage->hid) { hid_dbg(hdev, "data was pending ...\n"); - pdata->pending.raw_data = kmalloc(sz, GFP_ATOMIC); - if (pdata->pending.raw_data) { - memcpy(pdata->pending.raw_data, ptr, sz); - pdata->pending.raw_size = sz; - } else + pdata->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC); + if (pdata->pending.raw_data) + pdata->pending.raw_size = sz; + else pdata->pending.raw_size = 0; complete(&pdata->pending.ready); } @@ -465,30 +467,99 @@ static int sensor_hub_raw_event(struct hid_device *hdev, report->field[i]->usage->collection_index]; hid_dbg(hdev, "collection->usage %x\n", collection->usage); - callback = sensor_hub_get_callback(pdata->hsdev->hdev, - report->field[i]->physical, - &priv); + + callback = sensor_hub_get_callback(hdev, + report->field[i]->physical, + report->field[i]->usage[0].collection_index, + &hsdev, &priv); + if (callback && callback->capture_sample) { if (report->field[i]->logical) - callback->capture_sample(pdata->hsdev, + callback->capture_sample(hsdev, report->field[i]->logical, sz, ptr, callback->pdev); else - callback->capture_sample(pdata->hsdev, + callback->capture_sample(hsdev, report->field[i]->usage->hid, sz, ptr, callback->pdev); } ptr += sz; } if (callback && collection && callback->send_event) - callback->send_event(pdata->hsdev, collection->usage, + callback->send_event(hsdev, collection->usage, callback->pdev); spin_unlock_irqrestore(&pdata->lock, flags); -err_report: return 1; } +int sensor_hub_device_open(struct hid_sensor_hub_device *hsdev) +{ + int ret = 0; + struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + + mutex_lock(&data->mutex); + if (!data->ref_cnt) { + ret = hid_hw_open(hsdev->hdev); + if (ret) { + hid_err(hsdev->hdev, "failed to open hid device\n"); + mutex_unlock(&data->mutex); + return ret; + } + } + data->ref_cnt++; + mutex_unlock(&data->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(sensor_hub_device_open); + +void sensor_hub_device_close(struct hid_sensor_hub_device *hsdev) +{ + struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + + mutex_lock(&data->mutex); + data->ref_cnt--; + if (!data->ref_cnt) + hid_hw_close(hsdev->hdev); + mutex_unlock(&data->mutex); +} +EXPORT_SYMBOL_GPL(sensor_hub_device_close); + +static __u8 *sensor_hub_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + int index; + struct sensor_hub_data *sd = hid_get_drvdata(hdev); + unsigned char report_block[] = { + 0x0a, 0x16, 0x03, 0x15, 0x00, 0x25, 0x05}; + unsigned char power_block[] = { + 0x0a, 0x19, 0x03, 0x15, 0x00, 0x25, 0x05}; + + if (!(sd->quirks & HID_SENSOR_HUB_ENUM_QUIRK)) { + hid_dbg(hdev, "No Enum quirks\n"); + return rdesc; + } + + /* Looks for power and report state usage id and force to 1 */ + for (index = 0; index < *rsize; ++index) { + if (((*rsize - index) > sizeof(report_block)) && + !memcmp(&rdesc[index], report_block, + sizeof(report_block))) { + rdesc[index + 4] = 0x01; + index += sizeof(report_block); + } + if (((*rsize - index) > sizeof(power_block)) && + !memcmp(&rdesc[index], power_block, + sizeof(power_block))) { + rdesc[index + 4] = 0x01; + index += sizeof(power_block); + } + } + + return rdesc; +} + static int sensor_hub_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -496,60 +567,42 @@ static int sensor_hub_probe(struct hid_device *hdev, struct sensor_hub_data *sd; int i; char *name; - struct hid_report *report; - struct hid_report_enum *report_enum; - struct hid_field *field; int dev_cnt; + struct hid_sensor_hub_device *hsdev; + struct hid_sensor_hub_device *last_hsdev = NULL; - sd = kzalloc(sizeof(struct sensor_hub_data), GFP_KERNEL); + sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL); if (!sd) { hid_err(hdev, "cannot allocate Sensor data\n"); return -ENOMEM; } - sd->hsdev = kzalloc(sizeof(struct hid_sensor_hub_device), GFP_KERNEL); - if (!sd->hsdev) { - hid_err(hdev, "cannot allocate hid_sensor_hub_device\n"); - ret = -ENOMEM; - goto err_free_hub; - } + hid_set_drvdata(hdev, sd); - sd->hsdev->hdev = hdev; - sd->hsdev->vendor_id = hdev->vendor; - sd->hsdev->product_id = hdev->product; + sd->quirks = id->driver_data; + spin_lock_init(&sd->lock); spin_lock_init(&sd->dyn_callback_lock); mutex_init(&sd->mutex); ret = hid_parse(hdev); if (ret) { hid_err(hdev, "parse failed\n"); - goto err_free; - } - if (sensor_hub_check_for_sensor_page(hdev) < 0) { - hid_err(hdev, "sensor page not found\n"); - goto err_free; + return ret; } INIT_LIST_HEAD(&hdev->inputs); ret = hid_hw_start(hdev, 0); if (ret) { hid_err(hdev, "hw start failed\n"); - goto err_free; - } - ret = hid_hw_open(hdev); - if (ret) { - hid_err(hdev, "failed to open input interrupt pipe\n"); - goto err_stop_hw; + return ret; } - INIT_LIST_HEAD(&sd->dyn_callback_list); sd->hid_sensor_client_cnt = 0; - report_enum = &hdev->report_enum[HID_INPUT_REPORT]; - dev_cnt = sensor_hub_get_physical_device_count(report_enum); + dev_cnt = sensor_hub_get_physical_device_count(hdev); if (dev_cnt > HID_MAX_PHY_DEVICES) { hid_err(hdev, "Invalid Physical device count\n"); ret = -EINVAL; - goto err_close; + goto err_stop_hw; } sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt * sizeof(struct mfd_cell), @@ -557,51 +610,69 @@ static int sensor_hub_probe(struct hid_device *hdev, if (sd->hid_sensor_hub_client_devs == NULL) { hid_err(hdev, "Failed to allocate memory for mfd cells\n"); ret = -ENOMEM; - goto err_close; + goto err_stop_hw; } - list_for_each_entry(report, &report_enum->report_list, list) { - hid_dbg(hdev, "Report id:%x\n", report->id); - field = report->field[0]; - if (report->maxfield && field && - field->physical) { + + for (i = 0; i < hdev->maxcollection; ++i) { + struct hid_collection *collection = &hdev->collection[i]; + + if (collection->type == HID_COLLECTION_PHYSICAL) { + + hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL); + if (!hsdev) { + hid_err(hdev, "cannot allocate hid_sensor_hub_device\n"); + ret = -ENOMEM; + goto err_no_mem; + } + hsdev->hdev = hdev; + hsdev->vendor_id = hdev->vendor; + hsdev->product_id = hdev->product; + hsdev->start_collection_index = i; + if (last_hsdev) + last_hsdev->end_collection_index = i; + last_hsdev = hsdev; name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x", - field->physical); - if (name == NULL) { + collection->usage); + if (name == NULL) { hid_err(hdev, "Failed MFD device name\n"); ret = -ENOMEM; - goto err_free_names; + kfree(hsdev); + goto err_no_mem; } sd->hid_sensor_hub_client_devs[ + sd->hid_sensor_client_cnt].id = + PLATFORM_DEVID_AUTO; + sd->hid_sensor_hub_client_devs[ sd->hid_sensor_client_cnt].name = name; sd->hid_sensor_hub_client_devs[ sd->hid_sensor_client_cnt].platform_data = - sd->hsdev; + hsdev; sd->hid_sensor_hub_client_devs[ sd->hid_sensor_client_cnt].pdata_size = - sizeof(*sd->hsdev); - hid_dbg(hdev, "Adding %s:%p\n", name, sd); + sizeof(*hsdev); + hid_dbg(hdev, "Adding %s:%d\n", name, + hsdev->start_collection_index); sd->hid_sensor_client_cnt++; } } + if (last_hsdev) + last_hsdev->end_collection_index = i; + ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs, sd->hid_sensor_client_cnt, NULL, 0, NULL); if (ret < 0) - goto err_free_names; + goto err_no_mem; return ret; -err_free_names: - for (i = 0; i < sd->hid_sensor_client_cnt ; ++i) +err_no_mem: + for (i = 0; i < sd->hid_sensor_client_cnt; ++i) { kfree(sd->hid_sensor_hub_client_devs[i].name); + kfree(sd->hid_sensor_hub_client_devs[i].platform_data); + } kfree(sd->hid_sensor_hub_client_devs); -err_close: - hid_hw_close(hdev); err_stop_hw: hid_hw_stop(hdev); -err_free: - kfree(sd->hsdev); -err_free_hub: - kfree(sd); return ret; } @@ -620,60 +691,60 @@ static void sensor_hub_remove(struct hid_device *hdev) complete(&data->pending.ready); spin_unlock_irqrestore(&data->lock, flags); mfd_remove_devices(&hdev->dev); - for (i = 0; i < data->hid_sensor_client_cnt ; ++i) + for (i = 0; i < data->hid_sensor_client_cnt; ++i) { kfree(data->hid_sensor_hub_client_devs[i].name); + kfree(data->hid_sensor_hub_client_devs[i].platform_data); + } kfree(data->hid_sensor_hub_client_devs); hid_set_drvdata(hdev, NULL); mutex_destroy(&data->mutex); - kfree(data->hsdev); - kfree(data); } static const struct hid_device_id sensor_hub_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, - USB_DEVICE_ID_SENSOR_HUB_1020) }, - { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, - USB_DEVICE_ID_SENSOR_HUB_1020) }, - { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, - USB_DEVICE_ID_SENSOR_HUB_09FA) }, - { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, - USB_DEVICE_ID_SENSOR_HUB_09FA) }, - { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, - USB_DEVICE_ID_SENSOR_HUB_7014) }, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_0, + USB_DEVICE_ID_INTEL_HID_SENSOR_0), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1, + USB_DEVICE_ID_INTEL_HID_SENSOR_0), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1, + USB_DEVICE_ID_INTEL_HID_SENSOR_1), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT, + USB_DEVICE_ID_MS_SURFACE_PRO_2), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT, + USB_DEVICE_ID_MS_TOUCH_COVER_2), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT, + USB_DEVICE_ID_MS_TYPE_COVER_2), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0, + USB_DEVICE_ID_STM_HID_SENSOR_1), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_TEXAS_INSTRUMENTS, + USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID, + HID_ANY_ID) }, { } }; MODULE_DEVICE_TABLE(hid, sensor_hub_devices); -static const struct hid_usage_id sensor_hub_grabbed_usages[] = { - { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, - { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 } -}; - static struct hid_driver sensor_hub_driver = { .name = "hid-sensor-hub", .id_table = sensor_hub_devices, .probe = sensor_hub_probe, .remove = sensor_hub_remove, .raw_event = sensor_hub_raw_event, + .report_fixup = sensor_hub_report_fixup, #ifdef CONFIG_PM .suspend = sensor_hub_suspend, - .resume = sensor_hub_resume, - .reset_resume = sensor_hub_reset_resume, + .resume = sensor_hub_resume, + .reset_resume = sensor_hub_reset_resume, #endif }; - -static int __init sensor_hub_init(void) -{ - return hid_register_driver(&sensor_hub_driver); -} - -static void __exit sensor_hub_exit(void) -{ - hid_unregister_driver(&sensor_hub_driver); -} - -module_init(sensor_hub_init); -module_exit(sensor_hub_exit); +module_hid_driver(sensor_hub_driver); MODULE_DESCRIPTION("HID Sensor Hub driver"); MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); |
