diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hid/hid-apple.c | 3 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 4 | ||||
-rw-r--r-- | drivers/hid/hid-hyperv.c | 11 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 12 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 5 | ||||
-rw-r--r-- | drivers/hid/hid-lg4ff.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-microsoft.c | 78 | ||||
-rw-r--r-- | drivers/hid/hid-multitouch.c | 286 | ||||
-rw-r--r-- | drivers/hid/hid-sensor-hub.c | 220 | ||||
-rw-r--r-- | drivers/hid/hid-sony.c | 6 | ||||
-rw-r--r-- | drivers/hid/hidraw.c | 4 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 68 | ||||
-rw-r--r-- | drivers/hid/uhid.c | 78 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 1 | ||||
-rw-r--r-- | drivers/iio/common/hid-sensors/hid-sensor-trigger.c | 39 |
15 files changed, 515 insertions, 302 deletions
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 497558127bb3..f822fd2a1ada 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -469,6 +469,9 @@ static const struct hid_device_id apple_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index ddb981db08bd..dbe548b22b2a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1719,6 +1719,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_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) }, { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, @@ -1820,6 +1821,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index 0658cc4578fe..f52dbcb7133b 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -157,6 +157,7 @@ struct mousevsc_dev { u32 report_desc_size; struct hv_input_dev_info hid_dev_info; struct hid_device *hid_device; + u8 input_buf[HID_MAX_BUFFER_SIZE]; }; @@ -256,6 +257,7 @@ static void mousevsc_on_receive(struct hv_device *device, struct synthhid_msg *hid_msg; struct mousevsc_dev *input_dev = hv_get_drvdata(device); struct synthhid_input_report *input_report; + size_t len; pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet + (packet->offset8 << 3)); @@ -300,9 +302,12 @@ static void mousevsc_on_receive(struct hv_device *device, (struct synthhid_input_report *)pipe_msg->data; if (!input_dev->init_complete) break; - hid_input_report(input_dev->hid_device, - HID_INPUT_REPORT, input_report->buffer, - input_report->header.size, 1); + + len = min(input_report->header.size, + (u32)sizeof(input_dev->input_buf)); + memcpy(input_dev->input_buf, input_report->buffer, len); + hid_input_report(input_dev->hid_device, HID_INPUT_REPORT, + input_dev->input_buf, len, 1); break; default: pr_err("unsupported hid msg type - type %d len %d", diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 239f29c1c85c..548c1a519593 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -67,6 +67,9 @@ #define USB_VENDOR_ID_ALPS 0x0433 #define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 +#define USB_VENDOR_ID_ANTON 0x1130 +#define USB_DEVICE_ID_ANTON_TOUCH_PAD 0x3101 + #define USB_VENDOR_ID_APPLE 0x05ac #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 #define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d @@ -135,6 +138,7 @@ #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256 +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS 0x0257 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291 #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292 @@ -240,6 +244,7 @@ #define USB_VENDOR_ID_CYGNAL 0x10c4 #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a +#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9 #define USB_DEVICE_ID_CYGNAL_CP2112 0xea90 #define USB_VENDOR_ID_CYPRESS 0x04b4 @@ -450,6 +455,9 @@ #define USB_VENDOR_ID_INTEL_1 0x8087 #define USB_DEVICE_ID_INTEL_HID_SENSOR 0x09fa +#define USB_VENDOR_ID_STM_0 0x0483 +#define USB_DEVICE_ID_STM_HID_SENSOR 0x91d1 + #define USB_VENDOR_ID_ION 0x15e4 #define USB_DEVICE_ID_ICADE 0x0132 @@ -610,6 +618,7 @@ #define USB_VENDOR_ID_MICROSOFT 0x045e #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b +#define USB_DEVICE_ID_MS_OFFICE_KB 0x0048 #define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d #define USB_DEVICE_ID_MS_NE4K 0x00db #define USB_DEVICE_ID_MS_NE4K_JP 0x00dc @@ -618,6 +627,8 @@ #define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713 #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730 #define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c +#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 +#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 #define USB_VENDOR_ID_MOJO 0x8282 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 @@ -643,6 +654,7 @@ #define USB_VENDOR_ID_NEXIO 0x1870 #define USB_DEVICE_ID_NEXIO_MULTITOUCH_420 0x010d +#define USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750 0x0110 #define USB_VENDOR_ID_NEXTWINDOW 0x1926 #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index f5aef792f13b..e7e8b19a9284 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -789,10 +789,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x199: map_key_clear(KEY_CHAT); break; case 0x19c: map_key_clear(KEY_LOGOFF); break; case 0x19e: map_key_clear(KEY_COFFEE); break; + case 0x1a3: map_key_clear(KEY_NEXT); break; + case 0x1a4: map_key_clear(KEY_PREVIOUS); break; case 0x1a6: map_key_clear(KEY_HELP); break; case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; case 0x1ab: map_key_clear(KEY_SPELLCHECK); break; case 0x1ae: map_key_clear(KEY_KEYBOARD); break; + case 0x1b4: map_key_clear(KEY_FILE); break; case 0x1b6: map_key_clear(KEY_IMAGES); break; case 0x1b7: map_key_clear(KEY_AUDIO); break; case 0x1b8: map_key_clear(KEY_VIDEO); break; @@ -1178,7 +1181,7 @@ static void hidinput_led_worker(struct work_struct *work) /* fall back to generic raw-output-report */ len = ((report->size - 1) >> 3) + 1 + (report->id > 0); - buf = kmalloc(len, GFP_KERNEL); + buf = hid_alloc_report_buf(report, GFP_KERNEL); if (!buf) return; diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index befe0e336471..24883b4d1a49 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -43,6 +43,7 @@ #define G25_REV_MIN 0x22 #define G27_REV_MAJ 0x12 #define G27_REV_MIN 0x38 +#define G27_2_REV_MIN 0x39 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev) @@ -130,6 +131,7 @@ static const struct lg4ff_usb_revision lg4ff_revs[] = { {DFP_REV_MAJ, DFP_REV_MIN, &native_dfp}, /* Driving Force Pro */ {G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */ {G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */ + {G27_REV_MAJ, G27_2_REV_MIN, &native_g27}, /* G27 v2 */ }; /* Recalculates X axis value accordingly to currently selected range */ diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index c6ef6eed3091..6fd58175a291 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -62,9 +62,48 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage, { struct input_dev *input = hi->input; + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) { + switch (usage->hid & HID_USAGE) { + /* + * Microsoft uses these 2 reserved usage ids for 2 keys on + * the MS office kb labelled "Office Home" and "Task Pane". + */ + case 0x29d: + ms_map_key_clear(KEY_PROG1); + return 1; + case 0x29e: + ms_map_key_clear(KEY_PROG2); + return 1; + } + return 0; + } + + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) + return 0; + switch (usage->hid & HID_USAGE) { case 0xfd06: ms_map_key_clear(KEY_CHAT); break; case 0xfd07: ms_map_key_clear(KEY_PHONE); break; + case 0xff00: + /* Special keypad keys */ + ms_map_key_clear(KEY_KPEQUAL); + set_bit(KEY_KPLEFTPAREN, input->keybit); + set_bit(KEY_KPRIGHTPAREN, input->keybit); + break; + case 0xff01: + /* Scroll wheel */ + hid_map_usage_clear(hi, usage, bit, max, EV_REL, REL_WHEEL); + break; + case 0xff02: + /* + * This byte contains a copy of the modifier keys byte of a + * standard hid keyboard report, as send by interface 0 + * (this usage is found on interface 1). + * + * This byte only gets send when another key in the same report + * changes state, and as such is useless, ignore it. + */ + return -1; case 0xff05: set_bit(EV_REP, input->evbit); ms_map_key_clear(KEY_F13); @@ -83,6 +122,9 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage, static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage, unsigned long **bit, int *max) { + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) + return 0; + set_bit(EV_REP, hi->input->evbit); switch (usage->hid & HID_USAGE) { case 0xfd08: ms_map_key_clear(KEY_FORWARD); break; @@ -102,9 +144,6 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi, { unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); - if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) - return 0; - if (quirks & MS_ERGONOMY) { int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max); if (ret) @@ -134,14 +173,39 @@ static int ms_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) { unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); + struct input_dev *input; if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || !usage->type) return 0; + input = field->hidinput->input; + /* Handling MS keyboards special buttons */ + if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff00)) { + /* Special keypad keys */ + input_report_key(input, KEY_KPEQUAL, value & 0x01); + input_report_key(input, KEY_KPLEFTPAREN, value & 0x02); + input_report_key(input, KEY_KPRIGHTPAREN, value & 0x04); + return 1; + } + + if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff01)) { + /* Scroll wheel */ + int step = ((value & 0x60) >> 5) + 1; + + switch (value & 0x1f) { + case 0x01: + input_report_rel(input, REL_WHEEL, step); + break; + case 0x1f: + input_report_rel(input, REL_WHEEL, -step); + break; + } + return 1; + } + if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff05)) { - struct input_dev *input = field->hidinput->input; static unsigned int last_key = 0; unsigned int key = 0; switch (value) { @@ -194,6 +258,8 @@ err_free: static const struct hid_device_id ms_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV), .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB), + .driver_data = MS_ERGONOMY }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K), .driver_data = MS_ERGONOMY }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP), @@ -208,6 +274,10 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), .driver_data = MS_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2), + .driver_data = 0 }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), + .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), .driver_data = MS_PRESENTER }, diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index f134d73beca1..35278e43c7a4 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -68,6 +68,9 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_HOVERING (1 << 11) #define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12) +#define MT_INPUTMODE_TOUCHSCREEN 0x02 +#define MT_INPUTMODE_TOUCHPAD 0x03 + struct mt_slot { __s32 x, y, cx, cy, p, w, h; __s32 contactid; /* the device ContactID assigned to this slot */ @@ -84,6 +87,7 @@ struct mt_class { __s32 sn_pressure; /* Signal/noise ratio for pressure events */ __u8 maxcontacts; bool is_indirect; /* true for touchpads */ + bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */ }; struct mt_fields { @@ -100,11 +104,11 @@ struct mt_device { int cc_value_index; /* contact count value index in the field */ unsigned last_slot_field; /* the last field of a slot */ unsigned mt_report_id; /* the report ID of the multitouch device */ - unsigned pen_report_id; /* the report ID of the pen device */ __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ __s16 inputmode_index; /* InputMode HID feature index in the report */ __s16 maxcontact_report_id; /* Maximum Contact Number HID feature, -1 if non-existent */ + __u8 inputmode_value; /* InputMode HID feature value */ __u8 num_received; /* how many contacts we received */ __u8 num_expected; /* expected last contact index */ __u8 maxcontacts; @@ -128,16 +132,17 @@ static void mt_post_parse(struct mt_device *td); #define MT_CLS_CONFIDENCE_MINUS_ONE 0x0005 #define MT_CLS_DUAL_INRANGE_CONTACTID 0x0006 #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007 -#define MT_CLS_DUAL_NSMU_CONTACTID 0x0008 +/* reserved 0x0008 */ #define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 #define MT_CLS_NSMU 0x000a -#define MT_CLS_DUAL_CONTACT_NUMBER 0x0010 -#define MT_CLS_DUAL_CONTACT_ID 0x0011 +/* reserved 0x0010 */ +/* reserved 0x0011 */ #define MT_CLS_WIN_8 0x0012 +#define MT_CLS_EXPORT_ALL_INPUTS 0x0013 /* vendor specific classes */ #define MT_CLS_3M 0x0101 -#define MT_CLS_CYPRESS 0x0102 +/* reserved 0x0102 */ #define MT_CLS_EGALAX 0x0103 #define MT_CLS_EGALAX_SERIAL 0x0104 #define MT_CLS_TOPSEED 0x0105 @@ -189,28 +194,18 @@ static struct mt_class mt_classes[] = { .quirks = MT_QUIRK_VALID_IS_INRANGE | MT_QUIRK_SLOT_IS_CONTACTNUMBER, .maxcontacts = 2 }, - { .name = MT_CLS_DUAL_NSMU_CONTACTID, - .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | - MT_QUIRK_SLOT_IS_CONTACTID, - .maxcontacts = 2 }, { .name = MT_CLS_INRANGE_CONTACTNUMBER, .quirks = MT_QUIRK_VALID_IS_INRANGE | MT_QUIRK_SLOT_IS_CONTACTNUMBER }, - { .name = MT_CLS_DUAL_CONTACT_NUMBER, - .quirks = MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE | - MT_QUIRK_SLOT_IS_CONTACTNUMBER, - .maxcontacts = 2 }, - { .name = MT_CLS_DUAL_CONTACT_ID, - .quirks = MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE | - MT_QUIRK_SLOT_IS_CONTACTID, - .maxcontacts = 2 }, { .name = MT_CLS_WIN_8, .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | MT_QUIRK_CONTACT_CNT_ACCURATE }, + { .name = MT_CLS_EXPORT_ALL_INPUTS, + .quirks = MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + .export_all_inputs = true }, /* * vendor specific classes @@ -223,10 +218,6 @@ static struct mt_class mt_classes[] = { .sn_height = 128, .maxcontacts = 60, }, - { .name = MT_CLS_CYPRESS, - .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | - MT_QUIRK_CYPRESS, - .maxcontacts = 10 }, { .name = MT_CLS_EGALAX, .quirks = MT_QUIRK_SLOT_IS_CONTACTID | MT_QUIRK_VALID_IS_INRANGE, @@ -360,45 +351,6 @@ static void mt_store_field(struct hid_usage *usage, struct mt_device *td, f->usages[f->length++] = usage->hid; } -static int mt_pen_input_mapping(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - struct mt_device *td = hid_get_drvdata(hdev); - - td->pen_report_id = field->report->id; - - return 0; -} - -static int mt_pen_input_mapped(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - return 0; -} - -static int mt_pen_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value) -{ - /* let hid-input handle it */ - return 0; -} - -static void mt_pen_report(struct hid_device *hid, struct hid_report *report) -{ - struct hid_field *field = report->field[0]; - - input_sync(field->hidinput->input); -} - -static void mt_pen_input_configured(struct hid_device *hdev, - struct hid_input *hi) -{ - /* force BTN_STYLUS to allow tablet matching in udev */ - __set_bit(BTN_STYLUS, hi->input->keybit); -} - static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) @@ -415,8 +367,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, * Model touchscreens providing buttons as touchpads. */ if (field->application == HID_DG_TOUCHPAD || - (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) + (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { td->mt_flags |= INPUT_MT_POINTER; + td->inputmode_value = MT_INPUTMODE_TOUCHPAD; + } if (usage->usage_index) prev_usage = &field->usage[usage->usage_index - 1]; @@ -776,28 +730,52 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - /* Only map fields from TouchScreen or TouchPad collections. - * We need to ignore fields that belong to other collections - * such as Mouse that might have the same GenericDesktop usages. */ - if (field->application != HID_DG_TOUCHSCREEN && + struct mt_device *td = hid_get_drvdata(hdev); + + /* + * If mtclass.export_all_inputs is not set, only map fields from + * TouchScreen or TouchPad collections. We need to ignore fields + * that belong to other collections such as Mouse that might have + * the same GenericDesktop usages. + */ + if (!td->mtclass.export_all_inputs && + field->application != HID_DG_TOUCHSCREEN && field->application != HID_DG_PEN && field->application != HID_DG_TOUCHPAD) return -1; + /* + * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" + * for the stylus. + */ if (field->physical == HID_DG_STYLUS) - return mt_pen_input_mapping(hdev, hi, field, usage, bit, max); + return 0; + + if (field->application == HID_DG_TOUCHSCREEN || + field->application == HID_DG_TOUCHPAD) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max); - return mt_touch_input_mapping(hdev, hi, field, usage, bit, max); + /* let hid-core decide for the others */ + return 0; } static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { + /* + * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" + * for the stylus. + */ if (field->physical == HID_DG_STYLUS) - return mt_pen_input_mapped(hdev, hi, field, usage, bit, max); + return 0; + + if (field->application == HID_DG_TOUCHSCREEN || + field->application == HID_DG_TOUCHPAD) + return mt_touch_input_mapped(hdev, hi, field, usage, bit, max); - return mt_touch_input_mapped(hdev, hi, field, usage, bit, max); + /* let hid-core decide for the others */ + return 0; } static int mt_event(struct hid_device *hid, struct hid_field *field, @@ -808,25 +786,22 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, if (field->report->id == td->mt_report_id) return mt_touch_event(hid, field, usage, value); - if (field->report->id == td->pen_report_id) - return mt_pen_event(hid, field, usage, value); - - /* ignore other reports */ - return 1; + return 0; } static void mt_report(struct hid_device *hid, struct hid_report *report) { struct mt_device *td = hid_get_drvdata(hid); + struct hid_field *field = report->field[0]; if (!(hid->claimed & HID_CLAIMED_INPUT)) return; if (report->id == td->mt_report_id) - mt_touch_report(hid, report); + return mt_touch_report(hid, report); - if (report->id == td->pen_report_id) - mt_pen_report(hid, report); + if (field && field->hidinput && field->hidinput->input) + input_sync(field->hidinput->input); } static void mt_set_input_mode(struct hid_device *hdev) @@ -841,7 +816,7 @@ static void mt_set_input_mode(struct hid_device *hdev) re = &(hdev->report_enum[HID_FEATURE_REPORT]); r = re->report_id_hash[td->inputmode]; if (r) { - r->field[0]->value[td->inputmode_index] = 0x02; + r->field[0]->value[td->inputmode_index] = td->inputmode_value; hid_hw_request(hdev, r, HID_REQ_SET_REPORT); } } @@ -907,13 +882,49 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) struct mt_device *td = hid_get_drvdata(hdev); char *name; const char *suffix = NULL; + struct hid_field *field = hi->report->field[0]; if (hi->report->id == td->mt_report_id) mt_touch_input_configured(hdev, hi); + /* + * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" + * for the stylus. Check this first, and then rely on the application + * field. + */ if (hi->report->field[0]->physical == HID_DG_STYLUS) { suffix = "Pen"; - mt_pen_input_configured(hdev, hi); + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + } else { + switch (field->application) { + case HID_GD_KEYBOARD: + suffix = "Keyboard"; + break; + case HID_GD_KEYPAD: + suffix = "Keypad"; + break; + case HID_GD_MOUSE: + suffix = "Mouse"; + break; + case HID_DG_STYLUS: + suffix = "Pen"; + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; + case HID_DG_TOUCHSCREEN: + /* we do not set suffix = "Touchscreen" */ + break; + case HID_GD_SYSTEM_CONTROL: + suffix = "System Control"; + break; + case HID_CP_CONSUMER_CONTROL: + suffix = "Consumer Control"; + break; + default: + suffix = "UNKNOWN"; + break; + } } if (suffix) { @@ -973,9 +984,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->mtclass = *mtclass; td->inputmode = -1; td->maxcontact_report_id = -1; + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; td->cc_index = -1; td->mt_report_id = -1; - td->pen_report_id = -1; hid_set_drvdata(hdev, td); td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields), @@ -1034,6 +1045,12 @@ static void mt_remove(struct hid_device *hdev) hid_hw_stop(hdev); } +/* + * This list contains only: + * - VID/PID of products not working with the default multitouch handling + * - 2 generic rules. + * So there is no point in adding here any device with MT_CLS_DEFAULT. + */ static const struct hid_device_id mt_devices[] = { /* 3M panels */ @@ -1047,33 +1064,25 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M3266) }, - /* ActionStar panels */ - { .driver_data = MT_CLS_NSMU, - MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, - USB_DEVICE_ID_ACTIONSTAR_1011) }, + /* Anton devices */ + { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, + MT_USB_DEVICE(USB_VENDOR_ID_ANTON, + USB_DEVICE_ID_ANTON_TOUCH_PAD) }, /* Atmel panels */ { .driver_data = MT_CLS_SERIAL, MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, - USB_DEVICE_ID_ATMEL_MULTITOUCH) }, - { .driver_data = MT_CLS_SERIAL, - MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) }, /* Baanto multitouch devices */ { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_BAANTO, USB_DEVICE_ID_BAANTO_MT_190W2) }, + /* Cando panels */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, MT_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, - { .driver_data = MT_CLS_DUAL_CONTACT_NUMBER, - MT_USB_DEVICE(USB_VENDOR_ID_CANDO, - USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, - { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, - MT_USB_DEVICE(USB_VENDOR_ID_CANDO, - USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, MT_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, @@ -1088,16 +1097,6 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) }, - /* Cypress panel */ - { .driver_data = MT_CLS_CYPRESS, - HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, - USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, - - /* Data Modul easyMaxTouch */ - { .driver_data = MT_CLS_DEFAULT, - MT_USB_DEVICE(USB_VENDOR_ID_DATA_MODUL, - USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH) }, - /* eGalax devices (resistive) */ { .driver_data = MT_CLS_EGALAX, MT_USB_DEVICE(USB_VENDOR_ID_DWAV, @@ -1156,16 +1155,16 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, - /* Elo TouchSystems IntelliTouch Plus panel */ - { .driver_data = MT_CLS_DUAL_CONTACT_ID, - MT_USB_DEVICE(USB_VENDOR_ID_ELO, - USB_DEVICE_ID_ELO_TS2515) }, - /* Flatfrog Panels */ { .driver_data = MT_CLS_FLATFROG, MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, USB_DEVICE_ID_MULTITOUCH_3200) }, + /* FocalTech Panels */ + { .driver_data = MT_CLS_SERIAL, + MT_USB_DEVICE(USB_VENDOR_ID_CYGNAL, + USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH) }, + /* GeneralTouch panel */ { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, @@ -1204,37 +1203,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) }, - /* Ideacom panel */ - { .driver_data = MT_CLS_SERIAL, - MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM, - USB_DEVICE_ID_IDEACOM_IDC6650) }, - { .driver_data = MT_CLS_SERIAL, - MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM, - USB_DEVICE_ID_IDEACOM_IDC6651) }, - /* Ilitek dual touch panel */ { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) }, - /* IRTOUCH panels */ - { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, - MT_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, - USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, - - /* LG Display panels */ - { .driver_data = MT_CLS_DEFAULT, - MT_USB_DEVICE(USB_VENDOR_ID_LG, - USB_DEVICE_ID_LG_MULTITOUCH) }, - - /* Lumio panels */ - { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, - MT_USB_DEVICE(USB_VENDOR_ID_LUMIO, - USB_DEVICE_ID_CRYSTALTOUCH) }, - { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, - MT_USB_DEVICE(USB_VENDOR_ID_LUMIO, - USB_DEVICE_ID_CRYSTALTOUCH_DUAL) }, - /* MosArt panels */ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, MT_USB_DEVICE(USB_VENDOR_ID_ASUS, @@ -1246,11 +1219,6 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, - /* Nexio panels */ - { .driver_data = MT_CLS_DEFAULT, - MT_USB_DEVICE(USB_VENDOR_ID_NEXIO, - USB_DEVICE_ID_NEXIO_MULTITOUCH_420)}, - /* Panasonic panels */ { .driver_data = MT_CLS_PANASONIC, MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, @@ -1264,11 +1232,6 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_PCT) }, - /* PenMount panels */ - { .driver_data = MT_CLS_CONFIDENCE, - MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, - USB_DEVICE_ID_PENMOUNT_PCI) }, - /* PixArt optical touch screen */ { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, MT_USB_DEVICE(USB_VENDOR_ID_PIXART, @@ -1282,44 +1245,18 @@ static const struct hid_device_id mt_devices[] = { /* PixCir-based panels */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, - MT_USB_DEVICE(USB_VENDOR_ID_HANVON, - USB_DEVICE_ID_HANVON_MULTITOUCH) }, - { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, MT_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, /* Quanta-based panels */ { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, - USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, - { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, - MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) }, - { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, - MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, - USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) }, - - /* SiS panels */ - { .driver_data = MT_CLS_DEFAULT, - HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, - USB_DEVICE_ID_SIS9200_TOUCH) }, - { .driver_data = MT_CLS_DEFAULT, - HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, - USB_DEVICE_ID_SIS817_TOUCH) }, - { .driver_data = MT_CLS_DEFAULT, - HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, - USB_DEVICE_ID_SIS1030_TOUCH) }, /* Stantum panels */ { .driver_data = MT_CLS_CONFIDENCE, - MT_USB_DEVICE(USB_VENDOR_ID_STANTUM, - USB_DEVICE_ID_MTP)}, - { .driver_data = MT_CLS_CONFIDENCE, MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM)}, - { .driver_data = MT_CLS_DEFAULT, - MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, - USB_DEVICE_ID_MTP_SITRONIX)}, /* TopSeed panels */ { .driver_data = MT_CLS_TOPSEED, @@ -1378,11 +1315,6 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, - /* Zytronic panels */ - { .driver_data = MT_CLS_SERIAL, - MT_USB_DEVICE(USB_VENDOR_ID_ZYTRONIC, - USB_DEVICE_ID_ZYTRONIC_ZXY100) }, - /* Generic MT device */ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) }, diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 46f4480035bc..5182031f7b52 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -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; @@ -67,6 +67,7 @@ struct sensor_hub_data { struct mfd_cell *hid_sensor_hub_client_devs; int hid_sensor_client_cnt; unsigned long quirks; + int ref_cnt; }; /** @@ -79,6 +80,7 @@ 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; }; @@ -97,20 +99,18 @@ 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( @@ -128,15 +128,23 @@ static void sensor_hub_fill_attr_info( 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; } @@ -154,7 +162,8 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, 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 && + callback->hsdev == hsdev) { spin_unlock(&pdata->dyn_callback_lock); return -EINVAL; } @@ -163,6 +172,7 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, spin_unlock(&pdata->dyn_callback_lock); return -ENOMEM; } + callback->hsdev = hsdev; callback->usage_callback = usage_callback; callback->usage_id = usage_id; callback->priv = NULL; @@ -181,7 +191,8 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, 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 && + callback->hsdev == hsdev) { list_del(&callback->list); kfree(callback); break; @@ -260,13 +271,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; - } + hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); - spin_unlock_irqrestore(&data->lock, flags); wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5); switch (data->pending.raw_size) { case 1: @@ -291,6 +301,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, @@ -298,8 +330,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; @@ -313,44 +344,31 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, 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); - 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); - 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); @@ -366,7 +384,7 @@ static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message) 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); @@ -383,7 +401,7 @@ static int sensor_hub_resume(struct hid_device *hdev) 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); @@ -410,6 +428,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); @@ -444,23 +463,26 @@ 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); @@ -473,7 +495,7 @@ int sensor_hub_device_open(struct hid_sensor_hub_device *hsdev) struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); mutex_lock(&data->mutex); - if (!hsdev->ref_cnt) { + if (!data->ref_cnt) { ret = hid_hw_open(hsdev->hdev); if (ret) { hid_err(hsdev->hdev, "failed to open hid device\n"); @@ -481,7 +503,7 @@ int sensor_hub_device_open(struct hid_sensor_hub_device *hsdev) return ret; } } - hsdev->ref_cnt++; + data->ref_cnt++; mutex_unlock(&data->mutex); return ret; @@ -493,8 +515,8 @@ 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); - hsdev->ref_cnt--; - if (!hsdev->ref_cnt) + data->ref_cnt--; + if (!data->ref_cnt) hid_hw_close(hsdev->hdev); mutex_unlock(&data->mutex); } @@ -541,26 +563,19 @@ 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 = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL); if (!sd) { hid_err(hdev, "cannot allocate Sensor data\n"); return -ENOMEM; } - sd->hsdev = devm_kzalloc(&hdev->dev, sizeof(*sd->hsdev), GFP_KERNEL); - if (!sd->hsdev) { - hid_err(hdev, "cannot allocate hid_sensor_hub_device\n"); - return -ENOMEM; - } + hid_set_drvdata(hdev, sd); sd->quirks = id->driver_data; - sd->hsdev->hdev = hdev; - sd->hsdev->vendor_id = hdev->vendor; - sd->hsdev->product_id = hdev->product; + spin_lock_init(&sd->lock); spin_lock_init(&sd->dyn_callback_lock); mutex_init(&sd->mutex); @@ -578,9 +593,8 @@ static int sensor_hub_probe(struct hid_device *hdev, } 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; @@ -594,42 +608,63 @@ static int sensor_hub_probe(struct hid_device *hdev, ret = -ENOMEM; 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); + collection->usage); if (name == NULL) { hid_err(hdev, "Failed MFD device name\n"); ret = -ENOMEM; - goto err_free_names; + goto err_no_mem; } sd->hid_sensor_hub_client_devs[ - sd->hid_sensor_client_cnt].id = PLATFORM_DEVID_AUTO; + 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_stop_hw: hid_hw_stop(hdev); @@ -651,8 +686,10 @@ 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); @@ -665,6 +702,9 @@ static const struct hid_device_id sensor_hub_devices[] = { { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1, USB_DEVICE_ID_INTEL_HID_SENSOR), .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), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID, HID_ANY_ID) }, { } diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 908de2789219..4d348c069981 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1680,6 +1680,10 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_stop; } + if (sc->quirks & SONY_FF_SUPPORT) { + ret = sony_init_ff(hdev); + if (ret < 0) + goto err_stop; if (sc->quirks & SONY_BATTERY_SUPPORT) { ret = sony_battery_probe(sc); if (ret < 0) @@ -1721,6 +1725,8 @@ static void sony_remove(struct hid_device *hdev) if (sc->quirks & SONY_LED_SUPPORT) sony_leds_remove(hdev); + if (sc->worker_initialized) + cancel_work_sync(&sc->state_worker); if (sc->quirks & SONY_BATTERY_SUPPORT) { hid_hw_close(hdev); sony_battery_remove(sc); diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index ffa648ce002e..9c2d7c23f296 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -331,13 +331,13 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit) hid_hw_close(hidraw->hid); wake_up_interruptible(&hidraw->wait); } + device_destroy(hidraw_class, + MKDEV(hidraw_major, hidraw->minor)); } else { --hidraw->open; } if (!hidraw->open) { if (!hidraw->exist) { - device_destroy(hidraw_class, - MKDEV(hidraw_major, hidraw->minor)); hidraw_table[hidraw->minor] = NULL; kfree(hidraw); } else { diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 2de2b8e22462..8c52a07d5652 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -25,6 +25,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/device.h> #include <linux/wait.h> #include <linux/err.h> @@ -467,10 +468,18 @@ static void i2c_hid_init_reports(struct hid_device *hid) return; } + /* + * The device must be powered on while we fetch initial reports + * from it. + */ + pm_runtime_get_sync(&client->dev); + list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) i2c_hid_init_report(report, inbuf, ihid->bufsize); + pm_runtime_put(&client->dev); + kfree(inbuf); } @@ -709,8 +718,8 @@ static int i2c_hid_open(struct hid_device *hid) mutex_lock(&i2c_hid_open_mut); if (!hid->open++) { - ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); - if (ret) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { hid->open--; goto done; } @@ -718,7 +727,7 @@ static int i2c_hid_open(struct hid_device *hid) } done: mutex_unlock(&i2c_hid_open_mut); - return ret; + return ret < 0 ? ret : 0; } static void i2c_hid_close(struct hid_device *hid) @@ -735,7 +744,7 @@ static void i2c_hid_close(struct hid_device *hid) clear_bit(I2C_HID_STARTED, &ihid->flags); /* Save some power */ - i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); + pm_runtime_put(&client->dev); } mutex_unlock(&i2c_hid_open_mut); } @@ -744,19 +753,18 @@ static int i2c_hid_power(struct hid_device *hid, int lvl) { struct i2c_client *client = hid->driver_data; struct i2c_hid *ihid = i2c_get_clientdata(client); - int ret = 0; i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl); switch (lvl) { case PM_HINT_FULLON: - ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); + pm_runtime_get_sync(&client->dev); break; case PM_HINT_NORMAL: - ret = i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); + pm_runtime_put(&client->dev); break; } - return ret; + return 0; } static struct hid_ll_driver i2c_hid_ll_driver = { @@ -994,13 +1002,17 @@ static int i2c_hid_probe(struct i2c_client *client, if (ret < 0) goto err; + pm_runtime_get_noresume(&client->dev); + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + ret = i2c_hid_fetch_hid_descriptor(ihid); if (ret < 0) - goto err; + goto err_pm; ret = i2c_hid_init_irq(client); if (ret < 0) - goto err; + goto err_pm; hid = hid_allocate_device(); if (IS_ERR(hid)) { @@ -1029,6 +1041,7 @@ static int i2c_hid_probe(struct i2c_client *client, goto err_mem_free; } + pm_runtime_put(&client->dev); return 0; err_mem_free: @@ -1037,6 +1050,10 @@ err_mem_free: err_irq: free_irq(client->irq, ihid); +err_pm: + pm_runtime_put_noidle(&client->dev); + pm_runtime_disable(&client->dev); + err: i2c_hid_free_buffers(ihid); kfree(ihid); @@ -1048,6 +1065,11 @@ static int i2c_hid_remove(struct i2c_client *client) struct i2c_hid *ihid = i2c_get_clientdata(client); struct hid_device *hid; + pm_runtime_get_sync(&client->dev); + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + hid = ihid->hid; hid_destroy_device(hid); @@ -1093,7 +1115,31 @@ static int i2c_hid_resume(struct device *dev) } #endif -static SIMPLE_DEV_PM_OPS(i2c_hid_pm, i2c_hid_suspend, i2c_hid_resume); +#ifdef CONFIG_PM_RUNTIME +static int i2c_hid_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); + disable_irq(client->irq); + return 0; +} + +static int i2c_hid_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + + enable_irq(client->irq); + i2c_hid_set_power(client, I2C_HID_PWR_ON); + return 0; +} +#endif + +static const struct dev_pm_ops i2c_hid_pm = { + SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_suspend, i2c_hid_resume) + SET_RUNTIME_PM_OPS(i2c_hid_runtime_suspend, i2c_hid_runtime_resume, + NULL) +}; static const struct i2c_device_id i2c_hid_id_table[] = { { "hid", 0 }, diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 7ed79be2686a..0d078c32db4f 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -428,6 +428,67 @@ err_free: return ret; } +static int uhid_dev_create2(struct uhid_device *uhid, + const struct uhid_event *ev) +{ + struct hid_device *hid; + int ret; + + if (uhid->running) + return -EALREADY; + + uhid->rd_size = ev->u.create2.rd_size; + if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE) + return -EINVAL; + + uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL); + if (!uhid->rd_data) + return -ENOMEM; + + memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size); + + hid = hid_allocate_device(); + if (IS_ERR(hid)) { + ret = PTR_ERR(hid); + goto err_free; + } + + strncpy(hid->name, ev->u.create2.name, 127); + hid->name[127] = 0; + strncpy(hid->phys, ev->u.create2.phys, 63); + hid->phys[63] = 0; + strncpy(hid->uniq, ev->u.create2.uniq, 63); + hid->uniq[63] = 0; + + hid->ll_driver = &uhid_hid_driver; + hid->bus = ev->u.create2.bus; + hid->vendor = ev->u.create2.vendor; + hid->product = ev->u.create2.product; + hid->version = ev->u.create2.version; + hid->country = ev->u.create2.country; + hid->driver_data = uhid; + hid->dev.parent = uhid_misc.this_device; + + uhid->hid = hid; + uhid->running = true; + + ret = hid_add_device(hid); + if (ret) { + hid_err(hid, "Cannot register HID device\n"); + goto err_hid; + } + + return 0; + +err_hid: + hid_destroy_device(hid); + uhid->hid = NULL; + uhid->running = false; +err_free: + kfree(uhid->rd_data); + return ret; +} + static int uhid_dev_destroy(struct uhid_device *uhid) { if (!uhid->running) @@ -456,6 +517,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev) return 0; } +static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev) +{ + if (!uhid->running) + return -EINVAL; + + hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data, + min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0); + + return 0; +} + static int uhid_dev_feature_answer(struct uhid_device *uhid, struct uhid_event *ev) { @@ -592,12 +664,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer, case UHID_CREATE: ret = uhid_dev_create(uhid, &uhid->input_buf); break; + case UHID_CREATE2: + ret = uhid_dev_create2(uhid, &uhid->input_buf); + break; case UHID_DESTROY: ret = uhid_dev_destroy(uhid); break; case UHID_INPUT: ret = uhid_dev_input(uhid, &uhid->input_buf); break; + case UHID_INPUT2: + ret = uhid_dev_input2(uhid, &uhid->input_buf); + break; case UHID_FEATURE_ANSWER: ret = uhid_dev_feature_answer(uhid, &uhid->input_buf); break; diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 175ec0afb70c..dbd83878ff99 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -74,6 +74,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 7dcf83998e6f..dbefbdaf7cd1 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -38,29 +38,40 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, if (state) { if (sensor_hub_device_open(st->hsdev)) return -EIO; - state_val = - HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM; - report_val = - HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM; - + state_val = hid_sensor_get_usage_index(st->hsdev, + st->power_state.report_id, + st->power_state.index, + HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM); + report_val = hid_sensor_get_usage_index(st->hsdev, + st->report_state.report_id, + st->report_state.index, + HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM); } else { sensor_hub_device_close(st->hsdev); - state_val = - HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM; - report_val = - HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM; + state_val = hid_sensor_get_usage_index(st->hsdev, + st->power_state.report_id, + st->power_state.index, + HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM); + report_val = hid_sensor_get_usage_index(st->hsdev, + st->report_state.report_id, + st->report_state.index, + HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM); } - st->data_ready = state; - state_val += st->power_state.logical_minimum; - report_val += st->report_state.logical_minimum; - sensor_hub_set_feature(st->hsdev, st->power_state.report_id, + + if (state_val >= 0) { + state_val += st->power_state.logical_minimum; + sensor_hub_set_feature(st->hsdev, st->power_state.report_id, st->power_state.index, (s32)state_val); + } - sensor_hub_set_feature(st->hsdev, st->report_state.report_id, + if (report_val >= 0) { + report_val += st->report_state.logical_minimum; + sensor_hub_set_feature(st->hsdev, st->report_state.report_id, st->report_state.index, (s32)report_val); + } return 0; } |