unsigned int connect_mask = HID_CONNECT_DEFAULT;
int ret;
--- ---- asc = kzalloc(sizeof(*asc), GFP_KERNEL);
+++ ++++ asc = devm_kzalloc(&hdev->dev, sizeof(*asc), GFP_KERNEL);
if (asc == NULL) {
hid_err(hdev, "can't alloc apple descriptor\n");
return -ENOMEM;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
--- ---- goto err_free;
+++ ++++ return ret;
}
if (quirks & APPLE_HIDDEV)
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
hid_err(hdev, "hw start failed\n");
--- ---- goto err_free;
+++ ++++ return ret;
}
return 0;
--- ----err_free:
--- ---- kfree(asc);
--- ---- return ret;
--- ----}
--- ----
--- ----static void apple_remove(struct hid_device *hdev)
--- ----{
--- ---- hid_hw_stop(hdev);
--- ---- kfree(hid_get_drvdata(hdev));
}
static const struct hid_device_id apple_devices[] = {
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
++++ + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
++++ + .driver_data = APPLE_HAS_FN },
++++ + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
++++ + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
++++ + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
++++ + .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
.id_table = apple_devices,
.report_fixup = apple_report_fixup,
.probe = apple_probe,
--- ---- .remove = apple_remove,
.event = apple_event,
.input_mapping = apple_input_mapping,
.input_mapped = apple_input_mapped,
struct hid_report_enum *report_enum = device->report_enum + type;
struct hid_report *report;
++++++ + if (id >= HID_MAX_IDS)
++++++ + return NULL;
if (report_enum->report_id_hash[id])
return report_enum->report_id_hash[id];
case HID_GLOBAL_ITEM_TAG_REPORT_ID:
parser->global.report_id = item_udata(item);
------ - if (parser->global.report_id == 0) {
------ - hid_err(parser->device, "report_id 0 is invalid\n");
++++++ + if (parser->global.report_id == 0 ||
++++++ + parser->global.report_id >= HID_MAX_IDS) {
++++++ + hid_err(parser->device, "report_id %u is invalid\n",
++++++ + parser->global.report_id);
return -1;
}
return 0;
}
parser->local.delimiter_depth--;
}
------ return 1;
++++++ return 0;
case HID_LOCAL_ITEM_TAG_USAGE:
for (i = 0; i < HID_REPORT_TYPES; i++) {
struct hid_report_enum *report_enum = device->report_enum + i;
------ - for (j = 0; j < 256; j++) {
++++++ + for (j = 0; j < HID_MAX_IDS; j++) {
struct hid_report *report = report_enum->report_id_hash[j];
if (report)
hid_free_report(report);
return NULL;
}
--- ----static void hid_scan_usage(struct hid_device *hid, u32 usage)
+++ ++++static void hid_scan_input_usage(struct hid_parser *parser, u32 usage)
{
+++ ++++ struct hid_device *hid = parser->device;
+++ ++++
if (usage == HID_DG_CONTACTID)
hid->group = HID_GROUP_MULTITOUCH;
}
+++ ++++static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
+++ ++++{
+++ ++++ if (usage == 0xff0000c5 && parser->global.report_count == 256 &&
+++ ++++ parser->global.report_size == 8)
+++ ++++ parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
+++ ++++}
+++ ++++
+++ ++++static void hid_scan_collection(struct hid_parser *parser, unsigned type)
+++ ++++{
+++ ++++ struct hid_device *hid = parser->device;
+++ ++++
+++ ++++ if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
+++ ++++ type == HID_COLLECTION_PHYSICAL)
+++ ++++ hid->group = HID_GROUP_SENSOR_HUB;
+++ ++++}
+++ ++++
+++ ++++static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
+++ ++++{
+++ ++++ __u32 data;
+++ ++++ int i;
+++ ++++
+++ ++++ data = item_udata(item);
+++ ++++
+++ ++++ switch (item->tag) {
+++ ++++ case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+++ ++++ hid_scan_collection(parser, data & 0xff);
+++ ++++ break;
+++ ++++ case HID_MAIN_ITEM_TAG_END_COLLECTION:
+++ ++++ break;
+++ ++++ case HID_MAIN_ITEM_TAG_INPUT:
+++ ++++ for (i = 0; i < parser->local.usage_index; i++)
+++ ++++ hid_scan_input_usage(parser, parser->local.usage[i]);
+++ ++++ break;
+++ ++++ case HID_MAIN_ITEM_TAG_OUTPUT:
+++ ++++ break;
+++ ++++ case HID_MAIN_ITEM_TAG_FEATURE:
+++ ++++ for (i = 0; i < parser->local.usage_index; i++)
+++ ++++ hid_scan_feature_usage(parser, parser->local.usage[i]);
+++ ++++ break;
+++ ++++ }
+++ ++++
+++ ++++ /* Reset the local parser environment */
+++ ++++ memset(&parser->local, 0, sizeof(parser->local));
+++ ++++
+++ ++++ return 0;
+++ ++++}
+++ ++++
/*
* Scan a report descriptor before the device is added to the bus.
* Sets device groups and other properties that determine what driver
*/
static int hid_scan_report(struct hid_device *hid)
{
--- ---- unsigned int page = 0, delim = 0;
+++ ++++ struct hid_parser *parser;
+++ ++++ struct hid_item item;
__u8 *start = hid->dev_rdesc;
__u8 *end = start + hid->dev_rsize;
--- ---- unsigned int u, u_min = 0, u_max = 0;
--- ---- struct hid_item item;
+++ ++++ static int (*dispatch_type[])(struct hid_parser *parser,
+++ ++++ struct hid_item *item) = {
+++ ++++ hid_scan_main,
+++ ++++ hid_parser_global,
+++ ++++ hid_parser_local,
+++ ++++ hid_parser_reserved
+++ ++++ };
+++ +++
+++ ++++ parser = vzalloc(sizeof(struct hid_parser));
+++ ++++ if (!parser)
+++ ++++ return -ENOMEM;
+
+++ ++++ parser->device = hid;
hid->group = HID_GROUP_GENERIC;
--- ---- while ((start = fetch_item(start, end, &item)) != NULL) {
--- ---- if (item.format != HID_ITEM_FORMAT_SHORT)
--- ---- return -EINVAL;
--- ---- if (item.type == HID_ITEM_TYPE_GLOBAL) {
--- ---- if (item.tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE)
--- ---- page = item_udata(&item) << 16;
--- ---- } else if (item.type == HID_ITEM_TYPE_LOCAL) {
--- ---- if (delim > 1)
--- ---- break;
--- ---- u = item_udata(&item);
--- ---- if (item.size <= 2)
--- ---- u += page;
--- ---- switch (item.tag) {
--- ---- case HID_LOCAL_ITEM_TAG_DELIMITER:
--- ---- delim += !!u;
--- ---- break;
--- ---- case HID_LOCAL_ITEM_TAG_USAGE:
--- ---- hid_scan_usage(hid, u);
--- ---- break;
--- ---- case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
--- ---- u_min = u;
--- ---- break;
--- ---- case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
--- ---- u_max = u;
--- ---- for (u = u_min; u <= u_max; u++)
--- ---- hid_scan_usage(hid, u);
--- ---- break;
--- ---- }
--- ---- } else if (page == HID_UP_SENSOR &&
--- ---- item.type == HID_ITEM_TYPE_MAIN &&
--- ---- item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION &&
--- ---- (item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL)
--- ---- hid->group = HID_GROUP_SENSOR_HUB;
--- ---- }
+++ ++++ /*
+++ ++++ * The parsing is simpler than the one in hid_open_report() as we should
+++ ++++ * be robust against hid errors. Those errors will be raised by
+++ ++++ * hid_open_report() anyway.
+++ ++++ */
+++ ++++ while ((start = fetch_item(start, end, &item)) != NULL)
+++ ++++ dispatch_type[item.type](parser, &item);
+++ ++++
+++ ++++ /*
+++ ++++ * Handle special flags set during scanning.
+++ ++++ */
+++ ++++ if ((parser->scan_flags & HID_SCAN_FLAG_MT_WIN_8) &&
+++ ++++ (hid->group == HID_GROUP_MULTITOUCH))
+++ ++++ hid->group = HID_GROUP_MULTITOUCH_WIN_8;
+++ ++++
+++ ++++ vfree(parser);
return 0;
}
}
/*
------ * Create a report.
++++++ * Create a report. 'data' has to be allocated using
++++++ * hid_alloc_report_buf() so that it has proper size.
*/
void hid_output_report(struct hid_report *report, __u8 *data)
}
EXPORT_SYMBOL_GPL(hid_output_report);
++++++ /*
++++++ * Allocator for buffer that is going to be passed to hid_output_report()
++++++ */
++++++ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
++++++ {
++++++ /*
++++++ * 7 extra bytes are necessary to achieve proper functionality
++++++ * of implement() working on 8 byte chunks
++++++ */
++++++
++++++ int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
++++++
++++++ return kmalloc(len, flags);
++++++ }
++++++ EXPORT_SYMBOL_GPL(hid_alloc_report_buf);
++++++
/*
* Set a field value. The report this field belongs to has to be
* created and transferred to the device, to set this value in the
int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
{
------ - unsigned size = field->report_size;
++++++ + unsigned size;
++++++ +
++++++ + if (!field)
++++++ + return -1;
++++++ +
++++++ + size = field->report_size;
hid_dump_input(field->report->device, field->usage + offset, value);
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
++++ + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
++++ + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
++++ + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
++++++ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
++++++ + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
++++++ { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
++++ + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
++++ + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
++++ + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ }
{
struct hid_device *dev = container_of(psy, struct hid_device, battery);
int ret = 0;
------ - __u8 buf[2] = {};
++++++ + __u8 *buf;
switch (prop) {
case POWER_SUPPLY_PROP_PRESENT:
break;
case POWER_SUPPLY_PROP_CAPACITY:
++++++ +
++++++ + buf = kmalloc(2 * sizeof(__u8), GFP_KERNEL);
++++++ + if (!buf) {
++++++ + ret = -ENOMEM;
++++++ + break;
++++++ + }
ret = dev->hid_get_raw_report(dev, dev->battery_report_id,
------ - buf, sizeof(buf),
++++++ + buf, 2,
dev->battery_report_type);
if (ret != 2) {
ret = -ENODATA;
++++++ + kfree(buf);
break;
}
ret = 0;
buf[1] <= dev->battery_max)
val->intval = (100 * (buf[1] - dev->battery_min)) /
(dev->battery_max - dev->battery_min);
++++++ + kfree(buf);
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
}
EXPORT_SYMBOL_GPL(hidinput_count_leds);
++++ +++static void hidinput_led_worker(struct work_struct *work)
++++ +++{
++++ +++ struct hid_device *hid = container_of(work, struct hid_device,
++++ +++ led_work);
++++ +++ struct hid_field *field;
++++ +++ struct hid_report *report;
++++ +++ int len;
++++ +++ __u8 *buf;
++++ +++
++++ +++ field = hidinput_get_led_field(hid);
++++ +++ if (!field)
++++ +++ return;
++++ +++
++++ +++ /*
++++ +++ * field->report is accessed unlocked regarding HID core. So there might
++++ +++ * be another incoming SET-LED request from user-space, which changes
++++ +++ * the LED state while we assemble our outgoing buffer. However, this
++++ +++ * doesn't matter as hid_output_report() correctly converts it into a
++++ +++ * boolean value no matter what information is currently set on the LED
++++ +++ * field (even garbage). So the remote device will always get a valid
++++ +++ * request.
++++ +++ * And in case we send a wrong value, a next led worker is spawned
++++ +++ * for every SET-LED request so the following worker will send the
++++ +++ * correct value, guaranteed!
++++ +++ */
++++ +++
++++ +++ report = field->report;
++++ +++
++++ +++ /* use custom SET_REPORT request if possible (asynchronous) */
++++ +++ if (hid->ll_driver->request)
++++ +++ return hid->ll_driver->request(hid, report, HID_REQ_SET_REPORT);
++++ +++
++++ +++ /* fall back to generic raw-output-report */
++++ +++ len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
++++ +++ buf = kmalloc(len, GFP_KERNEL);
++++ +++ if (!buf)
++++ +++ return;
++++ +++
++++ +++ hid_output_report(report, buf);
++++ +++ /* synchronous output report */
++++ +++ hid->hid_output_raw_report(hid, buf, len, HID_OUTPUT_REPORT);
++++ +++ kfree(buf);
++++ +++}
++++ +++
++++ +++static int hidinput_input_event(struct input_dev *dev, unsigned int type,
++++ +++ unsigned int code, int value)
++++ +++{
++++ +++ struct hid_device *hid = input_get_drvdata(dev);
++++ +++ struct hid_field *field;
++++ +++ int offset;
++++ +++
++++ +++ if (type == EV_FF)
++++ +++ return input_ff_event(dev, type, code, value);
++++ +++
++++ +++ if (type != EV_LED)
++++ +++ return -1;
++++ +++
++++ +++ if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
++++ +++ hid_warn(dev, "event field not found\n");
++++ +++ return -1;
++++ +++ }
++++ +++
++++ +++ hid_set_field(field, offset, value);
++++ +++
++++ +++ schedule_work(&hid->led_work);
++++ +++ return 0;
++++ +++}
++++ +++
static int hidinput_open(struct input_dev *dev)
{
struct hid_device *hid = input_get_drvdata(dev);
}
input_set_drvdata(input_dev, hid);
---- --- input_dev->event = hid->ll_driver->hidinput_input_event;
++++ +++ if (hid->ll_driver->hidinput_input_event)
++++ +++ input_dev->event = hid->ll_driver->hidinput_input_event;
++++ +++ else if (hid->ll_driver->request || hid->hid_output_raw_report)
++++ +++ input_dev->event = hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
input_dev->setkeycode = hidinput_setkeycode;
int i, j, k;
INIT_LIST_HEAD(&hid->inputs);
++++ +++ INIT_WORK(&hid->led_work, hidinput_led_worker);
if (!force) {
for (i = 0; i < hid->maxcollection; i++) {
input_unregister_device(hidinput->input);
kfree(hidinput);
}
++++ +++
++++ +++ /* led_work is spawned by input_dev callbacks, but doesn't access the
++++ +++ * parent input_dev at all. Once all input devices are removed, we
++++ +++ * know that led_work will never get restarted, so we can cancel it
++++ +++ * synchronously and are safe. */
++++ +++ cancel_work_sync(&hid->led_work);
}
EXPORT_SYMBOL_GPL(hidinput_disconnect);
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
size_t count,
unsigned char report_type);
++++ +static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
struct dj_report *dj_report)
if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
SPFUNCTION_DEVICE_LIST_EMPTY) {
dbg_hid("%s: device list is empty\n", __func__);
++++ + djrcv_dev->querying_devices = false;
return;
}
return;
}
++++ + if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
++++ + /* The device is already known. No need to reallocate it. */
++++ + dbg_hid("%s: device is already known\n", __func__);
++++ + return;
++++ + }
++++ +
dj_hiddev = hid_allocate_device();
if (IS_ERR(dj_hiddev)) {
dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
struct dj_report dj_report;
unsigned long flags;
int count;
++++ + int retval;
dbg_hid("%s\n", __func__);
logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
break;
default:
++++ + /* A normal report (i. e. not belonging to a pair/unpair notification)
++++ + * arriving here, means that the report arrived but we did not have a
++++ + * paired dj_device associated to the report's device_index, this
++++ + * means that the original "device paired" notification corresponding
++++ + * to this dj_device never arrived to this driver. The reason is that
++++ + * hid-core discards all packets coming from a device while probe() is
++++ + * executing. */
++++ + if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
++++ + /* ok, we don't know the device, just re-ask the
++++ + * receiver for the list of connected devices. */
++++ + retval = logi_dj_recv_query_paired_devices(djrcv_dev);
++++ + if (!retval) {
++++ + /* everything went fine, so just leave */
++++ + break;
++++ + }
++++ + dev_err(&djrcv_dev->hdev->dev,
++++ + "%s:logi_dj_recv_query_paired_devices "
++++ + "error:%d\n", __func__, retval);
++++ + }
dbg_hid("%s: unexpected report type\n", __func__);
}
}
if (!djdev) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index);
++++ + kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
++++ +
++++ + if (schedule_work(&djrcv_dev->work) == 0) {
++++ + dbg_hid("%s: did not schedule the work item, was already "
++++ + "queued\n", __func__);
++++ + }
return;
}
if (dj_device == NULL) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index);
++++ + kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
++++ +
++++ + if (schedule_work(&djrcv_dev->work) == 0) {
++++ + dbg_hid("%s: did not schedule the work item, was already "
++++ + "queued\n", __func__);
++++ + }
return;
}
struct dj_report *dj_report;
int retval;
++++ + /* no need to protect djrcv_dev->querying_devices */
++++ + if (djrcv_dev->querying_devices)
++++ + return 0;
++++ +
dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
if (!dj_report)
return -ENOMEM;
return retval;
}
++++ +
static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
unsigned timeout)
{
struct hid_field *field;
struct hid_report *report;
------ unsigned char data[8];
++++++ unsigned char *data;
int offset;
dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
return -1;
}
hid_set_field(field, offset, value);
++++++
++++++ data = hid_alloc_report_buf(field->report, GFP_ATOMIC);
++++++ if (!data) {
++++++ dev_warn(&dev->dev, "failed to allocate report buf memory\n");
++++++ return -1;
++++++ }
++++++
hid_output_report(field->report, &data[0]);
output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
------ return 0;
++++++ kfree(data);
++++++ return 0;
}
static int logi_dj_ll_start(struct hid_device *hid)
}
/* This is enabling the polling urb on the IN endpoint */
-- ----- retval = hdev->ll_driver->open(hdev);
++ +++++ retval = hid_hw_open(hdev);
if (retval < 0) {
-- ----- dev_err(&hdev->dev, "%s:hdev->ll_driver->open returned "
-- ----- "error:%d\n", __func__, retval);
++ +++++ dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
++ +++++ __func__, retval);
goto llopen_failed;
}
return retval;
logi_dj_recv_query_paired_devices_failed:
-- ----- hdev->ll_driver->close(hdev);
++ +++++ hid_hw_close(hdev);
llopen_failed:
switch_to_dj_mode_fail:
cancel_work_sync(&djrcv_dev->work);
-- ----- hdev->ll_driver->close(hdev);
++ +++++ hid_hw_close(hdev);
hid_hw_stop(hdev);
/* I suppose that at this point the only context that can access
static unsigned int scroll_speed = 32;
static int param_set_scroll_speed(const char *val, struct kernel_param *kp) {
unsigned long speed;
------ if (!val || strict_strtoul(val, 0, &speed) || speed > 63)
++++++ if (!val || kstrtoul(val, 0, &speed) || speed > 63)
return -EINVAL;
scroll_speed = speed;
return 0;
struct hid_report *report;
int ret;
--- ---- msc = kzalloc(sizeof(*msc), GFP_KERNEL);
+++ ++++ msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL);
if (msc == NULL) {
hid_err(hdev, "can't alloc magicmouse descriptor\n");
return -ENOMEM;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "magicmouse hid parse failed\n");
--- ---- goto err_free;
+++ ++++ return ret;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "magicmouse hw start failed\n");
--- ---- goto err_free;
+++ ++++ return ret;
}
if (!msc->input) {
return 0;
err_stop_hw:
hid_hw_stop(hdev);
--- ----err_free:
--- ---- kfree(msc);
return ret;
}
--- ----static void magicmouse_remove(struct hid_device *hdev)
--- ----{
--- ---- struct magicmouse_sc *msc = hid_get_drvdata(hdev);
--- ----
--- ---- hid_hw_stop(hdev);
--- ---- kfree(msc);
--- ----}
--- ----
static const struct hid_device_id magic_mice[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
.name = "magicmouse",
.id_table = magic_mice,
.probe = magicmouse_probe,
--- ---- .remove = magicmouse_remove,
.raw_event = magicmouse_raw_event,
.input_mapping = magicmouse_input_mapping,
.input_configured = magicmouse_input_configured,
if (sc->quirks & PS3REMOTE)
return ps3remote_mapping(hdev, hi, field, usage, bit, max);
---- - return -1;
++++ + /* Let hid-core decide for the others */
++++ + return 0;
}
/*
struct sony_sc *sc;
unsigned int connect_mask = HID_CONNECT_DEFAULT;
--- ---- sc = kzalloc(sizeof(*sc), GFP_KERNEL);
+++ ++++ sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL);
if (sc == NULL) {
hid_err(hdev, "can't alloc sony descriptor\n");
return -ENOMEM;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
--- ---- goto err_free;
+++ ++++ return ret;
}
if (sc->quirks & VAIO_RDESC_CONSTANT)
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
hid_err(hdev, "hw start failed\n");
--- ---- goto err_free;
+++ ++++ return ret;
}
if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
return 0;
err_stop:
hid_hw_stop(hdev);
--- ----err_free:
--- ---- kfree(sc);
return ret;
}
buzz_remove(hdev);
hid_hw_stop(hdev);
--- ---- kfree(sc);
}
static const struct hid_device_id sony_devices[] = {
#include <linux/hid.h>
#include <linux/mutex.h>
#include <linux/acpi.h>
+ ++++++#include <linux/of.h>
#include <linux/i2c/i2c-hid.h>
return ret;
}
---- ---static int i2c_hid_hidinput_input_event(struct input_dev *dev,
---- --- unsigned int type, unsigned int code, int value)
---- ---{
---- --- struct hid_device *hid = input_get_drvdata(dev);
---- --- struct hid_field *field;
---- --- int offset;
---- ---
---- --- if (type == EV_FF)
---- --- return input_ff_event(dev, type, code, value);
---- ---
---- --- if (type != EV_LED)
---- --- return -1;
---- ---
---- --- offset = hidinput_find_field(hid, type, code, &field);
---- ---
---- --- if (offset == -1) {
---- --- hid_warn(dev, "event field not found\n");
---- --- return -1;
---- --- }
---- ---
---- --- return hid_set_field(field, offset, value);
---- ---}
---- ---
static struct hid_ll_driver i2c_hid_ll_driver = {
.parse = i2c_hid_parse,
.start = i2c_hid_start,
.close = i2c_hid_close,
.power = i2c_hid_power,
.request = i2c_hid_request,
---- --- .hidinput_input_event = i2c_hid_hidinput_input_event,
};
static int i2c_hid_init_irq(struct i2c_client *client)
* bytes 2-3 -> bcdVersion (has to be 1.00) */
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, 4);
------ i2c_hid_dbg(ihid, "%s, ihid->hdesc_buffer: %*ph\n",
------ __func__, 4, ihid->hdesc_buffer);
++++++ i2c_hid_dbg(ihid, "%s, ihid->hdesc_buffer: %4ph\n", __func__,
++++++ ihid->hdesc_buffer);
if (ret) {
dev_err(&client->dev,
params[1].integer.value = 1;
params[2].type = ACPI_TYPE_INTEGER;
params[2].integer.value = 1; /* HID function */
------- params[3].type = ACPI_TYPE_INTEGER;
------- params[3].integer.value = 0;
+++++++ params[3].type = ACPI_TYPE_PACKAGE;
+++++++ params[3].package.count = 0;
+++++++ params[3].package.elements = NULL;
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf))) {
dev_err(&client->dev, "device _DSM execution failed\n");
}
#endif
+ ++++++#ifdef CONFIG_OF
+ ++++++static int i2c_hid_of_probe(struct i2c_client *client,
+ ++++++ struct i2c_hid_platform_data *pdata)
+ ++++++{
+ ++++++ struct device *dev = &client->dev;
+ ++++++ u32 val;
+ ++++++ int ret;
+ ++++++
+ ++++++ ret = of_property_read_u32(dev->of_node, "hid-descr-addr", &val);
+ ++++++ if (ret) {
+ ++++++ dev_err(&client->dev, "HID register address not provided\n");
+ ++++++ return -ENODEV;
+ ++++++ }
+ ++++++ if (val >> 16) {
+ ++++++ dev_err(&client->dev, "Bad HID register address: 0x%08x\n",
+ ++++++ val);
+ ++++++ return -EINVAL;
+ ++++++ }
+ ++++++ pdata->hid_descriptor_address = val;
+ ++++++
+ ++++++ return 0;
+ ++++++}
+ ++++++
+ ++++++static const struct of_device_id i2c_hid_of_match[] = {
+ ++++++ { .compatible = "hid-over-i2c" },
+ ++++++ {},
+ ++++++};
+ ++++++MODULE_DEVICE_TABLE(of, i2c_hid_of_match);
+ ++++++#else
+ ++++++static inline int i2c_hid_of_probe(struct i2c_client *client,
+ ++++++ struct i2c_hid_platform_data *pdata)
+ ++++++{
+ ++++++ return -ENODEV;
+ ++++++}
+ ++++++#endif
+ ++++++
static int i2c_hid_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
if (!ihid)
return -ENOMEM;
- ------ if (!platform_data) {
+ ++++++ if (client->dev.of_node) {
+ ++++++ ret = i2c_hid_of_probe(client, &ihid->pdata);
+ ++++++ if (ret)
+ ++++++ goto err;
+ ++++++ } else if (!platform_data) {
ret = i2c_hid_acpi_pdata(client, &ihid->pdata);
if (ret) {
dev_err(&client->dev,
.owner = THIS_MODULE,
.pm = &i2c_hid_pm,
.acpi_match_table = ACPI_PTR(i2c_hid_acpi_match),
+ ++++++ .of_match_table = of_match_ptr(i2c_hid_of_match),
},
.probe = i2c_hid_probe,
uhid_queue_event(uhid, UHID_CLOSE);
}
---- ---static int uhid_hid_input(struct input_dev *input, unsigned int type,
---- --- unsigned int code, int value)
---- ---{
---- --- struct hid_device *hid = input_get_drvdata(input);
---- --- struct uhid_device *uhid = hid->driver_data;
---- --- unsigned long flags;
---- --- struct uhid_event *ev;
---- ---
---- --- ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
---- --- if (!ev)
---- --- return -ENOMEM;
---- ---
---- --- ev->type = UHID_OUTPUT_EV;
---- --- ev->u.output_ev.type = type;
---- --- ev->u.output_ev.code = code;
---- --- ev->u.output_ev.value = value;
---- ---
---- --- spin_lock_irqsave(&uhid->qlock, flags);
---- --- uhid_queue(uhid, ev);
---- --- spin_unlock_irqrestore(&uhid->qlock, flags);
---- ---
---- --- return 0;
---- ---}
---- ---
static int uhid_hid_parse(struct hid_device *hid)
{
struct uhid_device *uhid = hid->driver_data;
.stop = uhid_hid_stop,
.open = uhid_hid_open,
.close = uhid_hid_close,
---- --- .hidinput_input_event = uhid_hid_input,
.parse = uhid_hid_parse,
};
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
++++++ +MODULE_ALIAS("devname:" UHID_NAME);
{
int head;
struct usbhid_device *usbhid = hid->driver_data;
------ int len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
return;
return;
}
------ usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
++++++ usbhid->out[usbhid->outhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
if (!usbhid->out[usbhid->outhead].raw_report) {
hid_warn(hid, "output queueing failed\n");
return;
}
if (dir == USB_DIR_OUT) {
------ usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
++++++ usbhid->ctrl[usbhid->ctrlhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
hid_warn(hid, "control queueing failed\n");
return;
spin_unlock_irqrestore(&usbhid->lock, flags);
}
---- ---/* Workqueue routine to send requests to change LEDs */
---- ---static void hid_led(struct work_struct *work)
---- ---{
---- --- struct usbhid_device *usbhid =
---- --- container_of(work, struct usbhid_device, led_work);
---- --- struct hid_device *hid = usbhid->hid;
---- --- struct hid_field *field;
---- --- unsigned long flags;
---- ---
---- --- field = hidinput_get_led_field(hid);
---- --- if (!field) {
---- --- hid_warn(hid, "LED event field not found\n");
---- --- return;
---- --- }
---- ---
---- --- spin_lock_irqsave(&usbhid->lock, flags);
---- --- if (!test_bit(HID_DISCONNECTED, &usbhid->iofl)) {
---- --- usbhid->ledcount = hidinput_count_leds(hid);
---- --- hid_dbg(usbhid->hid, "New ledcount = %u\n", usbhid->ledcount);
---- --- __usbhid_submit_report(hid, field->report, USB_DIR_OUT);
---- --- }
---- --- spin_unlock_irqrestore(&usbhid->lock, flags);
---- ---}
---- ---
---- ---static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
---- ---{
---- --- struct hid_device *hid = input_get_drvdata(dev);
---- --- struct usbhid_device *usbhid = hid->driver_data;
---- --- struct hid_field *field;
---- --- unsigned long flags;
---- --- int offset;
---- ---
---- --- if (type == EV_FF)
---- --- return input_ff_event(dev, type, code, value);
---- ---
---- --- if (type != EV_LED)
---- --- return -1;
---- ---
---- --- if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
---- --- hid_warn(dev, "event field not found\n");
---- --- return -1;
---- --- }
---- ---
---- --- spin_lock_irqsave(&usbhid->lock, flags);
---- --- hid_set_field(field, offset, value);
---- --- spin_unlock_irqrestore(&usbhid->lock, flags);
---- ---
---- --- /*
---- --- * Defer performing requested LED action.
---- --- * This is more likely gather all LED changes into a single URB.
---- --- */
---- --- schedule_work(&usbhid->led_work);
---- ---
---- --- return 0;
---- ---}
---- ---
static int usbhid_wait_io(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
{
struct hid_report *report;
struct usbhid_device *usbhid = hid->driver_data;
+++ ++++ struct hid_report_enum *report_enum;
int err, ret;
--- ---- list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
--- ---- usbhid_submit_report(hid, report, USB_DIR_IN);
+++ ++++ if (!(hid->quirks & HID_QUIRK_NO_INIT_INPUT_REPORTS)) {
+++ ++++ report_enum = &hid->report_enum[HID_INPUT_REPORT];
+++ ++++ list_for_each_entry(report, &report_enum->report_list, list)
+++ ++++ usbhid_submit_report(hid, report, USB_DIR_IN);
+++ ++++ }
--- ---- list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
+++ ++++ report_enum = &hid->report_enum[HID_FEATURE_REPORT];
+++ ++++ list_for_each_entry(report, &report_enum->report_list, list)
usbhid_submit_report(hid, report, USB_DIR_IN);
err = 0;
return -1;
}
---- ---void usbhid_set_leds(struct hid_device *hid)
++++ +++static void usbhid_set_leds(struct hid_device *hid)
{
struct hid_field *field;
int offset;
usbhid_submit_report(hid, field->report, USB_DIR_OUT);
}
}
---- ---EXPORT_SYMBOL_GPL(usbhid_set_leds);
/*
* Traverse the supplied list of reports and find the longest
.open = usbhid_open,
.close = usbhid_close,
.power = usbhid_power,
---- --- .hidinput_input_event = usb_hidinput_input_event,
.request = usbhid_request,
.wait = usbhid_wait_io,
.idle = usbhid_idle,
setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
spin_lock_init(&usbhid->lock);
---- --- INIT_WORK(&usbhid->led_work, hid_led);
---- ---
ret = hid_add_device(hid);
if (ret) {
if (ret != -ENODEV)
{
del_timer_sync(&usbhid->io_retry);
cancel_work_sync(&usbhid->reset_work);
---- --- cancel_work_sync(&usbhid->led_work);
}
static void hid_cease_io(struct usbhid_device *usbhid)
struct usbhid_device *usbhid = hid->driver_data;
int status = 0;
bool driver_suspended = false;
++++ +++ unsigned int ledcount;
if (PMSG_IS_AUTO(message)) {
++++ +++ ledcount = hidinput_count_leds(hid);
spin_lock_irq(&usbhid->lock); /* Sync with error handler */
if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
&& !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
&& !test_bit(HID_OUT_RUNNING, &usbhid->iofl)
&& !test_bit(HID_CTRL_RUNNING, &usbhid->iofl)
&& !test_bit(HID_KEYS_PRESSED, &usbhid->iofl)
---- --- && (!usbhid->ledcount || ignoreled))
++++ +++ && (!ledcount || ignoreled))
{
set_bit(HID_SUSPENDED, &usbhid->iofl);
spin_unlock_irq(&usbhid->lock);
#define HID_OUTPUT_REPORT 1
#define HID_FEATURE_REPORT 2
++++++ +#define HID_REPORT_TYPES 3
++++++ +
/*
* HID connect requests
*/
#define HID_QUIRK_MULTI_INPUT 0x00000040
#define HID_QUIRK_HIDINPUT_FORCE 0x00000080
#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100
+++ ++++#define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
#define HID_GROUP_GENERIC 0x0001
#define HID_GROUP_MULTITOUCH 0x0002
#define HID_GROUP_SENSOR_HUB 0x0003
+++ ++++#define HID_GROUP_MULTITOUCH_WIN_8 0x0004
/*
* This is the global environment of the parser. This information is
struct hid_device *device; /* associated device */
};
++++++ +#define HID_MAX_IDS 256
++++++ +
struct hid_report_enum {
unsigned numbered;
struct list_head report_list;
------ - struct hid_report *report_id_hash[256];
++++++ + struct hid_report *report_id_hash[HID_MAX_IDS];
};
------ -#define HID_REPORT_TYPES 3
------ -
#define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */
#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */
#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */
enum hid_type type; /* device type (mouse, kbd, ...) */
unsigned country; /* HID country */
struct hid_report_enum report_enum[HID_REPORT_TYPES];
++++ +++ struct work_struct led_work; /* delayed LED worker */
struct semaphore driver_lock; /* protects the current driver, except during input */
struct semaphore driver_input_lock; /* protects the current driver */
#define HID_GLOBAL_STACK_SIZE 4
#define HID_COLLECTION_STACK_SIZE 4
+++ ++++#define HID_SCAN_FLAG_MT_WIN_8 0x00000001
+++ ++++
struct hid_parser {
struct hid_global global;
struct hid_global global_stack[HID_GLOBAL_STACK_SIZE];
unsigned collection_stack[HID_COLLECTION_STACK_SIZE];
unsigned collection_stack_ptr;
struct hid_device *device;
+++ ++++ unsigned scan_flags;
};
struct hid_class_descriptor {
unsigned int hidinput_count_leds(struct hid_device *hid);
__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);
void hid_output_report(struct hid_report *report, __u8 *data);
++++++ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
int usbhid_quirks_init(char **quirks_param);
void usbhid_quirks_exit(void);
---- ---void usbhid_set_leds(struct hid_device *hid);
#ifdef CONFIG_HID_PID
int hid_pidff_init(struct hid_device *hid);
#define INPUT_DEVICE_ID_KEY_MIN_INTERESTING 0x71
#define INPUT_DEVICE_ID_KEY_MAX 0x2ff
#define INPUT_DEVICE_ID_REL_MAX 0x0f
------- #define INPUT_DEVICE_ID_ABS_MAX 0x3f
+++++++ #define INPUT_DEVICE_ID_ABS_MAX 0x4f
#define INPUT_DEVICE_ID_MSC_MAX 0x07
#define INPUT_DEVICE_ID_LED_MAX 0x0f
#define INPUT_DEVICE_ID_SND_MAX 0x07
__u16 vendor;
__u16 coreid;
__u8 revision;
---- -};
++++ + __u8 __pad;
++++ +} __attribute__((packed, aligned(2)));
#define SSB_DEVICE(_vendor, _coreid, _revision) \
{ .vendor = _vendor, .coreid = _coreid, .revision = _revision, }
#define SSB_DEVTABLE_END \
__u16 id;
__u8 rev;
__u8 class;
---- -};
++++ +} __attribute__((packed,aligned(2)));
#define BCMA_CORE(_manuf, _id, _rev, _class) \
{ .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, }
#define BCMA_CORETABLE_END \