162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * HID driver for some microsoft "special" devices 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 1999 Andreas Gal 662306a36Sopenharmony_ci * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 762306a36Sopenharmony_ci * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 862306a36Sopenharmony_ci * Copyright (c) 2006-2007 Jiri Kosina 962306a36Sopenharmony_ci * Copyright (c) 2008 Jiri Slaby 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/device.h> 1662306a36Sopenharmony_ci#include <linux/input.h> 1762306a36Sopenharmony_ci#include <linux/hid.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "hid-ids.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define MS_HIDINPUT BIT(0) 2362306a36Sopenharmony_ci#define MS_ERGONOMY BIT(1) 2462306a36Sopenharmony_ci#define MS_PRESENTER BIT(2) 2562306a36Sopenharmony_ci#define MS_RDESC BIT(3) 2662306a36Sopenharmony_ci#define MS_NOGET BIT(4) 2762306a36Sopenharmony_ci#define MS_DUPLICATE_USAGES BIT(5) 2862306a36Sopenharmony_ci#define MS_SURFACE_DIAL BIT(6) 2962306a36Sopenharmony_ci#define MS_QUIRK_FF BIT(7) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct ms_data { 3262306a36Sopenharmony_ci unsigned long quirks; 3362306a36Sopenharmony_ci struct hid_device *hdev; 3462306a36Sopenharmony_ci struct work_struct ff_worker; 3562306a36Sopenharmony_ci __u8 strong; 3662306a36Sopenharmony_ci __u8 weak; 3762306a36Sopenharmony_ci void *output_report_dmabuf; 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define XB1S_FF_REPORT 3 4162306a36Sopenharmony_ci#define ENABLE_WEAK BIT(0) 4262306a36Sopenharmony_ci#define ENABLE_STRONG BIT(1) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cienum { 4562306a36Sopenharmony_ci MAGNITUDE_STRONG = 2, 4662306a36Sopenharmony_ci MAGNITUDE_WEAK, 4762306a36Sopenharmony_ci MAGNITUDE_NUM 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistruct xb1s_ff_report { 5162306a36Sopenharmony_ci __u8 report_id; 5262306a36Sopenharmony_ci __u8 enable; 5362306a36Sopenharmony_ci __u8 magnitude[MAGNITUDE_NUM]; 5462306a36Sopenharmony_ci __u8 duration_10ms; 5562306a36Sopenharmony_ci __u8 start_delay_10ms; 5662306a36Sopenharmony_ci __u8 loop_count; 5762306a36Sopenharmony_ci} __packed; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, 6062306a36Sopenharmony_ci unsigned int *rsize) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct ms_data *ms = hid_get_drvdata(hdev); 6362306a36Sopenharmony_ci unsigned long quirks = ms->quirks; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* 6662306a36Sopenharmony_ci * Microsoft Wireless Desktop Receiver (Model 1028) has 6762306a36Sopenharmony_ci * 'Usage Min/Max' where it ought to have 'Physical Min/Max' 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ci if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 && 7062306a36Sopenharmony_ci rdesc[559] == 0x29) { 7162306a36Sopenharmony_ci hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n"); 7262306a36Sopenharmony_ci rdesc[557] = 0x35; 7362306a36Sopenharmony_ci rdesc[559] = 0x45; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci return rdesc; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define ms_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ 7962306a36Sopenharmony_ci EV_KEY, (c)) 8062306a36Sopenharmony_cistatic int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage, 8162306a36Sopenharmony_ci unsigned long **bit, int *max) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct input_dev *input = hi->input; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) { 8662306a36Sopenharmony_ci switch (usage->hid & HID_USAGE) { 8762306a36Sopenharmony_ci /* 8862306a36Sopenharmony_ci * Microsoft uses these 2 reserved usage ids for 2 keys on 8962306a36Sopenharmony_ci * the MS office kb labelled "Office Home" and "Task Pane". 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci case 0x29d: 9262306a36Sopenharmony_ci ms_map_key_clear(KEY_PROG1); 9362306a36Sopenharmony_ci return 1; 9462306a36Sopenharmony_ci case 0x29e: 9562306a36Sopenharmony_ci ms_map_key_clear(KEY_PROG2); 9662306a36Sopenharmony_ci return 1; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci switch (usage->hid & HID_USAGE) { 10562306a36Sopenharmony_ci case 0xfd06: ms_map_key_clear(KEY_CHAT); break; 10662306a36Sopenharmony_ci case 0xfd07: ms_map_key_clear(KEY_PHONE); break; 10762306a36Sopenharmony_ci case 0xff00: 10862306a36Sopenharmony_ci /* Special keypad keys */ 10962306a36Sopenharmony_ci ms_map_key_clear(KEY_KPEQUAL); 11062306a36Sopenharmony_ci set_bit(KEY_KPLEFTPAREN, input->keybit); 11162306a36Sopenharmony_ci set_bit(KEY_KPRIGHTPAREN, input->keybit); 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci case 0xff01: 11462306a36Sopenharmony_ci /* Scroll wheel */ 11562306a36Sopenharmony_ci hid_map_usage_clear(hi, usage, bit, max, EV_REL, REL_WHEEL); 11662306a36Sopenharmony_ci break; 11762306a36Sopenharmony_ci case 0xff02: 11862306a36Sopenharmony_ci /* 11962306a36Sopenharmony_ci * This byte contains a copy of the modifier keys byte of a 12062306a36Sopenharmony_ci * standard hid keyboard report, as send by interface 0 12162306a36Sopenharmony_ci * (this usage is found on interface 1). 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * This byte only gets send when another key in the same report 12462306a36Sopenharmony_ci * changes state, and as such is useless, ignore it. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci return -1; 12762306a36Sopenharmony_ci case 0xff05: 12862306a36Sopenharmony_ci set_bit(EV_REP, input->evbit); 12962306a36Sopenharmony_ci ms_map_key_clear(KEY_F13); 13062306a36Sopenharmony_ci set_bit(KEY_F14, input->keybit); 13162306a36Sopenharmony_ci set_bit(KEY_F15, input->keybit); 13262306a36Sopenharmony_ci set_bit(KEY_F16, input->keybit); 13362306a36Sopenharmony_ci set_bit(KEY_F17, input->keybit); 13462306a36Sopenharmony_ci set_bit(KEY_F18, input->keybit); 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci default: 13762306a36Sopenharmony_ci return 0; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci return 1; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage, 14362306a36Sopenharmony_ci unsigned long **bit, int *max) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci set_bit(EV_REP, hi->input->evbit); 14962306a36Sopenharmony_ci switch (usage->hid & HID_USAGE) { 15062306a36Sopenharmony_ci case 0xfd08: ms_map_key_clear(KEY_FORWARD); break; 15162306a36Sopenharmony_ci case 0xfd09: ms_map_key_clear(KEY_BACK); break; 15262306a36Sopenharmony_ci case 0xfd0b: ms_map_key_clear(KEY_PLAYPAUSE); break; 15362306a36Sopenharmony_ci case 0xfd0e: ms_map_key_clear(KEY_CLOSE); break; 15462306a36Sopenharmony_ci case 0xfd0f: ms_map_key_clear(KEY_PLAY); break; 15562306a36Sopenharmony_ci default: 15662306a36Sopenharmony_ci return 0; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci return 1; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int ms_surface_dial_quirk(struct hid_input *hi, struct hid_field *field, 16262306a36Sopenharmony_ci struct hid_usage *usage, unsigned long **bit, int *max) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci switch (usage->hid & HID_USAGE_PAGE) { 16562306a36Sopenharmony_ci case 0xff070000: 16662306a36Sopenharmony_ci case HID_UP_DIGITIZER: 16762306a36Sopenharmony_ci /* ignore those axis */ 16862306a36Sopenharmony_ci return -1; 16962306a36Sopenharmony_ci case HID_UP_GENDESK: 17062306a36Sopenharmony_ci switch (usage->hid) { 17162306a36Sopenharmony_ci case HID_GD_X: 17262306a36Sopenharmony_ci case HID_GD_Y: 17362306a36Sopenharmony_ci case HID_GD_RFKILL_BTN: 17462306a36Sopenharmony_ci /* ignore those axis */ 17562306a36Sopenharmony_ci return -1; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi, 18362306a36Sopenharmony_ci struct hid_field *field, struct hid_usage *usage, 18462306a36Sopenharmony_ci unsigned long **bit, int *max) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct ms_data *ms = hid_get_drvdata(hdev); 18762306a36Sopenharmony_ci unsigned long quirks = ms->quirks; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (quirks & MS_ERGONOMY) { 19062306a36Sopenharmony_ci int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max); 19162306a36Sopenharmony_ci if (ret) 19262306a36Sopenharmony_ci return ret; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if ((quirks & MS_PRESENTER) && 19662306a36Sopenharmony_ci ms_presenter_8k_quirk(hi, usage, bit, max)) 19762306a36Sopenharmony_ci return 1; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (quirks & MS_SURFACE_DIAL) { 20062306a36Sopenharmony_ci int ret = ms_surface_dial_quirk(hi, field, usage, bit, max); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (ret) 20362306a36Sopenharmony_ci return ret; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic int ms_input_mapped(struct hid_device *hdev, struct hid_input *hi, 21062306a36Sopenharmony_ci struct hid_field *field, struct hid_usage *usage, 21162306a36Sopenharmony_ci unsigned long **bit, int *max) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct ms_data *ms = hid_get_drvdata(hdev); 21462306a36Sopenharmony_ci unsigned long quirks = ms->quirks; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (quirks & MS_DUPLICATE_USAGES) 21762306a36Sopenharmony_ci clear_bit(usage->code, *bit); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return 0; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic int ms_event(struct hid_device *hdev, struct hid_field *field, 22362306a36Sopenharmony_ci struct hid_usage *usage, __s32 value) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct ms_data *ms = hid_get_drvdata(hdev); 22662306a36Sopenharmony_ci unsigned long quirks = ms->quirks; 22762306a36Sopenharmony_ci struct input_dev *input; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || 23062306a36Sopenharmony_ci !usage->type) 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci input = field->hidinput->input; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* Handling MS keyboards special buttons */ 23662306a36Sopenharmony_ci if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff00)) { 23762306a36Sopenharmony_ci /* Special keypad keys */ 23862306a36Sopenharmony_ci input_report_key(input, KEY_KPEQUAL, value & 0x01); 23962306a36Sopenharmony_ci input_report_key(input, KEY_KPLEFTPAREN, value & 0x02); 24062306a36Sopenharmony_ci input_report_key(input, KEY_KPRIGHTPAREN, value & 0x04); 24162306a36Sopenharmony_ci return 1; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff01)) { 24562306a36Sopenharmony_ci /* Scroll wheel */ 24662306a36Sopenharmony_ci int step = ((value & 0x60) >> 5) + 1; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci switch (value & 0x1f) { 24962306a36Sopenharmony_ci case 0x01: 25062306a36Sopenharmony_ci input_report_rel(input, REL_WHEEL, step); 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci case 0x1f: 25362306a36Sopenharmony_ci input_report_rel(input, REL_WHEEL, -step); 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci return 1; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff05)) { 26062306a36Sopenharmony_ci static unsigned int last_key = 0; 26162306a36Sopenharmony_ci unsigned int key = 0; 26262306a36Sopenharmony_ci switch (value) { 26362306a36Sopenharmony_ci case 0x01: key = KEY_F14; break; 26462306a36Sopenharmony_ci case 0x02: key = KEY_F15; break; 26562306a36Sopenharmony_ci case 0x04: key = KEY_F16; break; 26662306a36Sopenharmony_ci case 0x08: key = KEY_F17; break; 26762306a36Sopenharmony_ci case 0x10: key = KEY_F18; break; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci if (key) { 27062306a36Sopenharmony_ci input_event(input, usage->type, key, 1); 27162306a36Sopenharmony_ci last_key = key; 27262306a36Sopenharmony_ci } else 27362306a36Sopenharmony_ci input_event(input, usage->type, last_key, 0); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return 1; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic void ms_ff_worker(struct work_struct *work) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct ms_data *ms = container_of(work, struct ms_data, ff_worker); 28462306a36Sopenharmony_ci struct hid_device *hdev = ms->hdev; 28562306a36Sopenharmony_ci struct xb1s_ff_report *r = ms->output_report_dmabuf; 28662306a36Sopenharmony_ci int ret; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci memset(r, 0, sizeof(*r)); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci r->report_id = XB1S_FF_REPORT; 29162306a36Sopenharmony_ci r->enable = ENABLE_WEAK | ENABLE_STRONG; 29262306a36Sopenharmony_ci /* 29362306a36Sopenharmony_ci * Specifying maximum duration and maximum loop count should 29462306a36Sopenharmony_ci * cover maximum duration of a single effect, which is 65536 29562306a36Sopenharmony_ci * ms 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ci r->duration_10ms = U8_MAX; 29862306a36Sopenharmony_ci r->loop_count = U8_MAX; 29962306a36Sopenharmony_ci r->magnitude[MAGNITUDE_STRONG] = ms->strong; /* left actuator */ 30062306a36Sopenharmony_ci r->magnitude[MAGNITUDE_WEAK] = ms->weak; /* right actuator */ 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ret = hid_hw_output_report(hdev, (__u8 *)r, sizeof(*r)); 30362306a36Sopenharmony_ci if (ret < 0) 30462306a36Sopenharmony_ci hid_warn(hdev, "failed to send FF report\n"); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int ms_play_effect(struct input_dev *dev, void *data, 30862306a36Sopenharmony_ci struct ff_effect *effect) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct hid_device *hid = input_get_drvdata(dev); 31162306a36Sopenharmony_ci struct ms_data *ms = hid_get_drvdata(hid); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (effect->type != FF_RUMBLE) 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* 31762306a36Sopenharmony_ci * Magnitude is 0..100 so scale the 16-bit input here 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ci ms->strong = ((u32) effect->u.rumble.strong_magnitude * 100) / U16_MAX; 32062306a36Sopenharmony_ci ms->weak = ((u32) effect->u.rumble.weak_magnitude * 100) / U16_MAX; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci schedule_work(&ms->ff_worker); 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int ms_init_ff(struct hid_device *hdev) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct hid_input *hidinput; 32962306a36Sopenharmony_ci struct input_dev *input_dev; 33062306a36Sopenharmony_ci struct ms_data *ms = hid_get_drvdata(hdev); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (list_empty(&hdev->inputs)) { 33362306a36Sopenharmony_ci hid_err(hdev, "no inputs found\n"); 33462306a36Sopenharmony_ci return -ENODEV; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci hidinput = list_entry(hdev->inputs.next, struct hid_input, list); 33762306a36Sopenharmony_ci input_dev = hidinput->input; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (!(ms->quirks & MS_QUIRK_FF)) 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci ms->hdev = hdev; 34362306a36Sopenharmony_ci INIT_WORK(&ms->ff_worker, ms_ff_worker); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci ms->output_report_dmabuf = devm_kzalloc(&hdev->dev, 34662306a36Sopenharmony_ci sizeof(struct xb1s_ff_report), 34762306a36Sopenharmony_ci GFP_KERNEL); 34862306a36Sopenharmony_ci if (ms->output_report_dmabuf == NULL) 34962306a36Sopenharmony_ci return -ENOMEM; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci input_set_capability(input_dev, EV_FF, FF_RUMBLE); 35262306a36Sopenharmony_ci return input_ff_create_memless(input_dev, NULL, ms_play_effect); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void ms_remove_ff(struct hid_device *hdev) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct ms_data *ms = hid_get_drvdata(hdev); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (!(ms->quirks & MS_QUIRK_FF)) 36062306a36Sopenharmony_ci return; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci cancel_work_sync(&ms->ff_worker); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int ms_probe(struct hid_device *hdev, const struct hid_device_id *id) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci unsigned long quirks = id->driver_data; 36862306a36Sopenharmony_ci struct ms_data *ms; 36962306a36Sopenharmony_ci int ret; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci ms = devm_kzalloc(&hdev->dev, sizeof(*ms), GFP_KERNEL); 37262306a36Sopenharmony_ci if (ms == NULL) 37362306a36Sopenharmony_ci return -ENOMEM; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ms->quirks = quirks; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci hid_set_drvdata(hdev, ms); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (quirks & MS_NOGET) 38062306a36Sopenharmony_ci hdev->quirks |= HID_QUIRK_NOGET; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (quirks & MS_SURFACE_DIAL) 38362306a36Sopenharmony_ci hdev->quirks |= HID_QUIRK_INPUT_PER_APP; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci ret = hid_parse(hdev); 38662306a36Sopenharmony_ci if (ret) { 38762306a36Sopenharmony_ci hid_err(hdev, "parse failed\n"); 38862306a36Sopenharmony_ci goto err_free; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & MS_HIDINPUT) ? 39262306a36Sopenharmony_ci HID_CONNECT_HIDINPUT_FORCE : 0)); 39362306a36Sopenharmony_ci if (ret) { 39462306a36Sopenharmony_ci hid_err(hdev, "hw start failed\n"); 39562306a36Sopenharmony_ci goto err_free; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ret = ms_init_ff(hdev); 39962306a36Sopenharmony_ci if (ret) 40062306a36Sopenharmony_ci hid_err(hdev, "could not initialize ff, continuing anyway"); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_cierr_free: 40462306a36Sopenharmony_ci return ret; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void ms_remove(struct hid_device *hdev) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci hid_hw_stop(hdev); 41062306a36Sopenharmony_ci ms_remove_ff(hdev); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic const struct hid_device_id ms_devices[] = { 41462306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV), 41562306a36Sopenharmony_ci .driver_data = MS_HIDINPUT }, 41662306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB), 41762306a36Sopenharmony_ci .driver_data = MS_ERGONOMY }, 41862306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K), 41962306a36Sopenharmony_ci .driver_data = MS_ERGONOMY }, 42062306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP), 42162306a36Sopenharmony_ci .driver_data = MS_ERGONOMY }, 42262306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K), 42362306a36Sopenharmony_ci .driver_data = MS_ERGONOMY }, 42462306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K), 42562306a36Sopenharmony_ci .driver_data = MS_ERGONOMY | MS_RDESC }, 42662306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB), 42762306a36Sopenharmony_ci .driver_data = MS_PRESENTER }, 42862306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K), 42962306a36Sopenharmony_ci .driver_data = MS_ERGONOMY }, 43062306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K), 43162306a36Sopenharmony_ci .driver_data = MS_ERGONOMY }, 43262306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600), 43362306a36Sopenharmony_ci .driver_data = MS_ERGONOMY }, 43462306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1), 43562306a36Sopenharmony_ci .driver_data = MS_ERGONOMY }, 43662306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0), 43762306a36Sopenharmony_ci .driver_data = MS_NOGET }, 43862306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), 43962306a36Sopenharmony_ci .driver_data = MS_DUPLICATE_USAGES }, 44062306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), 44162306a36Sopenharmony_ci .driver_data = MS_HIDINPUT }, 44262306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD), 44362306a36Sopenharmony_ci .driver_data = MS_ERGONOMY}, 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), 44662306a36Sopenharmony_ci .driver_data = MS_PRESENTER }, 44762306a36Sopenharmony_ci { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, 0x091B), 44862306a36Sopenharmony_ci .driver_data = MS_SURFACE_DIAL }, 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_CONTROLLER_MODEL_1708), 45162306a36Sopenharmony_ci .driver_data = MS_QUIRK_FF }, 45262306a36Sopenharmony_ci { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_CONTROLLER_MODEL_1708_BLE), 45362306a36Sopenharmony_ci .driver_data = MS_QUIRK_FF }, 45462306a36Sopenharmony_ci { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_CONTROLLER_MODEL_1914), 45562306a36Sopenharmony_ci .driver_data = MS_QUIRK_FF }, 45662306a36Sopenharmony_ci { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_CONTROLLER_MODEL_1797), 45762306a36Sopenharmony_ci .driver_data = MS_QUIRK_FF }, 45862306a36Sopenharmony_ci { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_CONTROLLER_MODEL_1797_BLE), 45962306a36Sopenharmony_ci .driver_data = MS_QUIRK_FF }, 46062306a36Sopenharmony_ci { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS), 46162306a36Sopenharmony_ci .driver_data = MS_QUIRK_FF }, 46262306a36Sopenharmony_ci { } 46362306a36Sopenharmony_ci}; 46462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(hid, ms_devices); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic struct hid_driver ms_driver = { 46762306a36Sopenharmony_ci .name = "microsoft", 46862306a36Sopenharmony_ci .id_table = ms_devices, 46962306a36Sopenharmony_ci .report_fixup = ms_report_fixup, 47062306a36Sopenharmony_ci .input_mapping = ms_input_mapping, 47162306a36Sopenharmony_ci .input_mapped = ms_input_mapped, 47262306a36Sopenharmony_ci .event = ms_event, 47362306a36Sopenharmony_ci .probe = ms_probe, 47462306a36Sopenharmony_ci .remove = ms_remove, 47562306a36Sopenharmony_ci}; 47662306a36Sopenharmony_cimodule_hid_driver(ms_driver); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 479