diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/Kconfig | 2 | ||||
-rw-r--r-- | drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 83 | ||||
-rw-r--r-- | drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 4 | ||||
-rw-r--r-- | drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c | 4 | ||||
-rw-r--r-- | drivers/hid/hid-apple.c | 321 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 280 | ||||
-rw-r--r-- | drivers/hid/hid-elo.c | 6 | ||||
-rw-r--r-- | drivers/hid/hid-google-hammer.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 9 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 364 | ||||
-rw-r--r-- | drivers/hid/hid-logitech-dj.c | 1 | ||||
-rw-r--r-- | drivers/hid/hid-nintendo.c | 4 | ||||
-rw-r--r-- | drivers/hid/hid-quirks.c | 17 | ||||
-rw-r--r-- | drivers/hid/hid-thrustmaster.c | 8 | ||||
-rw-r--r-- | drivers/hid/hid-vivaldi.c | 2 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid-of-goodix.c | 28 | ||||
-rw-r--r-- | drivers/hid/intel-ish-hid/ishtp-fw-loader.c | 29 |
17 files changed, 968 insertions, 196 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index f5544157576c..9c0e45f56d84 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -128,6 +128,8 @@ config HID_ACRUX_FF config HID_APPLE tristate "Apple {i,Power,Mac}Books" depends on HID + depends on LEDS_CLASS + depends on NEW_LEDS default !EXPERT help Support for some Apple devices which less or more break diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index 2503be0253d3..6b5fd90b0bd1 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -37,11 +37,11 @@ static int amd_sfh_wait_response_v2(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_ { union cmd_response cmd_resp; - /* Get response with status within a max of 800 ms timeout */ + /* Get response with status within a max of 1600 ms timeout */ if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp, (cmd_resp.response_v2.response == sensor_sts && cmd_resp.response_v2.status == 0 && (sid == 0xff || - cmd_resp.response_v2.sensor_id == sid)), 500, 800000)) + cmd_resp.response_v2.sensor_id == sid)), 500, 1600000)) return cmd_resp.response_v2.response; return SENSOR_DISABLED; @@ -53,6 +53,7 @@ static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sen cmd_base.ul = 0; cmd_base.cmd_v2.cmd_id = ENABLE_SENSOR; + cmd_base.cmd_v2.intr_disable = 1; cmd_base.cmd_v2.period = info.period; cmd_base.cmd_v2.sensor_id = info.sensor_idx; cmd_base.cmd_v2.length = 16; @@ -70,6 +71,7 @@ static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx) cmd_base.ul = 0; cmd_base.cmd_v2.cmd_id = DISABLE_SENSOR; + cmd_base.cmd_v2.intr_disable = 1; cmd_base.cmd_v2.period = 0; cmd_base.cmd_v2.sensor_id = sensor_idx; cmd_base.cmd_v2.length = 16; @@ -83,12 +85,51 @@ static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata) union sfh_cmd_base cmd_base; cmd_base.cmd_v2.cmd_id = STOP_ALL_SENSORS; + cmd_base.cmd_v2.intr_disable = 1; cmd_base.cmd_v2.period = 0; cmd_base.cmd_v2.sensor_id = 0; writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); } +static void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata) +{ + if (readl(privdata->mmio + AMD_P2C_MSG(4))) { + writel(0, privdata->mmio + AMD_P2C_MSG(4)); + writel(0xf, privdata->mmio + AMD_P2C_MSG(5)); + } +} + +static void amd_sfh_clear_intr(struct amd_mp2_dev *privdata) +{ + if (privdata->mp2_ops->clear_intr) + privdata->mp2_ops->clear_intr(privdata); +} + +static irqreturn_t amd_sfh_irq_handler(int irq, void *data) +{ + amd_sfh_clear_intr(data); + + return IRQ_HANDLED; +} + +static int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata) +{ + int rc; + + pci_intx(privdata->pdev, true); + + rc = devm_request_irq(&privdata->pdev->dev, privdata->pdev->irq, + amd_sfh_irq_handler, 0, DRIVER_NAME, privdata); + if (rc) { + dev_err(&privdata->pdev->dev, "failed to request irq %d err=%d\n", + privdata->pdev->irq, rc); + return rc; + } + + return 0; +} + void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) { union sfh_cmd_param cmd_param; @@ -193,6 +234,8 @@ static void amd_mp2_pci_remove(void *privdata) struct amd_mp2_dev *mp2 = privdata; amd_sfh_hid_client_deinit(privdata); mp2->mp2_ops->stop_all(mp2); + pci_intx(mp2->pdev, false); + amd_sfh_clear_intr(mp2); } static const struct amd_mp2_ops amd_sfh_ops_v2 = { @@ -200,6 +243,8 @@ static const struct amd_mp2_ops amd_sfh_ops_v2 = { .stop = amd_stop_sensor_v2, .stop_all = amd_stop_all_sensor_v2, .response = amd_sfh_wait_response_v2, + .clear_intr = amd_sfh_clear_intr_v2, + .init_intr = amd_sfh_irq_init_v2, }; static const struct amd_mp2_ops amd_sfh_ops = { @@ -225,6 +270,14 @@ static void mp2_select_ops(struct amd_mp2_dev *privdata) } } +static int amd_sfh_irq_init(struct amd_mp2_dev *privdata) +{ + if (privdata->mp2_ops->init_intr) + return privdata->mp2_ops->init_intr(privdata); + + return 0; +} + static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct amd_mp2_dev *privdata; @@ -248,11 +301,8 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i pci_set_master(pdev); rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (rc) { - rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, "failed to set DMA mask\n"); - return rc; - } + dev_err(&pdev->dev, "failed to set DMA mask\n"); + return rc; } privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL); @@ -261,9 +311,20 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i mp2_select_ops(privdata); + rc = amd_sfh_irq_init(privdata); + if (rc) { + dev_err(&pdev->dev, "amd_sfh_irq_init failed\n"); + return rc; + } + rc = amd_sfh_hid_client_init(privdata); - if (rc) + if (rc) { + amd_sfh_clear_intr(privdata); + dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n"); return rc; + } + + amd_sfh_clear_intr(privdata); return devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata); } @@ -290,6 +351,9 @@ static int __maybe_unused amd_mp2_pci_resume(struct device *dev) } } + schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); + amd_sfh_clear_intr(mp2); + return 0; } @@ -312,6 +376,9 @@ static int __maybe_unused amd_mp2_pci_suspend(struct device *dev) } } + cancel_delayed_work_sync(&cl_data->work_buffer); + amd_sfh_clear_intr(mp2); + return 0; } diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h index ae30e059f847..97b99861fae2 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h @@ -49,7 +49,7 @@ union sfh_cmd_base { } s; struct { u32 cmd_id : 4; - u32 intr_enable : 1; + u32 intr_disable : 1; u32 rsvd1 : 3; u32 length : 7; u32 mem_type : 1; @@ -141,5 +141,7 @@ struct amd_mp2_ops { void (*stop)(struct amd_mp2_dev *privdata, u16 sensor_idx); void (*stop_all)(struct amd_mp2_dev *privdata); int (*response)(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts); + void (*clear_intr)(struct amd_mp2_dev *privdata); + int (*init_intr)(struct amd_mp2_dev *privdata); }; #endif diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c index be41f83b0289..76095bd53c65 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c @@ -27,6 +27,7 @@ #define HID_USAGE_SENSOR_STATE_READY_ENUM 0x02 #define HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM 0x05 #define HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM 0x04 +#define ILLUMINANCE_MASK GENMASK(14, 0) int get_report_descriptor(int sensor_idx, u8 *rep_desc) { @@ -246,7 +247,8 @@ u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_ get_common_inputs(&als_input.common_property, report_id); /* For ALS ,V2 Platforms uses C2P_MSG5 register instead of DRAM access method */ if (supported_input == V2_STATUS) - als_input.illuminance_value = (int)readl(privdata->mmio + AMD_C2P_MSG(5)); + als_input.illuminance_value = + readl(privdata->mmio + AMD_C2P_MSG(5)) & ILLUMINANCE_MASK; else als_input.illuminance_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 24802a4a636e..0cf35caee9fa 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -7,6 +7,7 @@ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc * Copyright (c) 2006-2007 Jiri Kosina * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> + * Copyright (c) 2019 Paul Pawlowski <paul@mrarm.io> */ /* @@ -33,6 +34,7 @@ /* BIT(7) reserved, was: APPLE_IGNORE_HIDINPUT */ #define APPLE_NUMLOCK_EMULATION BIT(8) #define APPLE_RDESC_BATTERY BIT(9) +#define APPLE_BACKLIGHT_CTL BIT(10) #define APPLE_FLAG_FKEY 0x01 @@ -61,6 +63,12 @@ MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. " "(For people who want to keep PC keyboard muscle memory. " "[0] = as-is, Mac layout, 1 = swapped, PC layout)"); +struct apple_sc_backlight { + struct led_classdev cdev; + struct hid_device *hdev; + unsigned short backlight_off, backlight_on_min, backlight_on_max; +}; + struct apple_sc { struct hid_device *hdev; unsigned long quirks; @@ -68,6 +76,7 @@ struct apple_sc { unsigned int fn_found; DECLARE_BITMAP(pressed_numlock, KEY_CNT); struct timer_list battery_timer; + struct apple_sc_backlight *backlight; }; struct apple_key_translation { @@ -76,6 +85,61 @@ struct apple_key_translation { u8 flags; }; +static const struct apple_key_translation magic_keyboard_alu_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_ENTER, KEY_INSERT }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY }, + { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY }, + { KEY_F6, KEY_NUMLOCK, APPLE_FLAG_FKEY }, + { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; + +static const struct apple_key_translation magic_keyboard_2015_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_ENTER, KEY_INSERT }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY }, + { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY }, + { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; + +struct apple_backlight_config_report { + u8 report_id; + u8 version; + u16 backlight_off, backlight_on_min, backlight_on_max; +}; + +struct apple_backlight_set_report { + u8 report_id; + u8 version; + u16 backlight; + u16 rate; +}; + + static const struct apple_key_translation apple2021_fn_keys[] = { { KEY_BACKSPACE, KEY_DELETE }, { KEY_ENTER, KEY_INSERT }, @@ -119,6 +183,51 @@ static const struct apple_key_translation macbookair_fn_keys[] = { { } }; +static const struct apple_key_translation macbookpro_no_esc_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_ENTER, KEY_INSERT }, + { KEY_GRAVE, KEY_ESC }, + { KEY_1, KEY_F1 }, + { KEY_2, KEY_F2 }, + { KEY_3, KEY_F3 }, + { KEY_4, KEY_F4 }, + { KEY_5, KEY_F5 }, + { KEY_6, KEY_F6 }, + { KEY_7, KEY_F7 }, + { KEY_8, KEY_F8 }, + { KEY_9, KEY_F9 }, + { KEY_0, KEY_F10 }, + { KEY_MINUS, KEY_F11 }, + { KEY_EQUAL, KEY_F12 }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; + +static const struct apple_key_translation macbookpro_dedicated_esc_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_ENTER, KEY_INSERT }, + { KEY_1, KEY_F1 }, + { KEY_2, KEY_F2 }, + { KEY_3, KEY_F3 }, + { KEY_4, KEY_F4 }, + { KEY_5, KEY_F5 }, + { KEY_6, KEY_F6 }, + { KEY_7, KEY_F7 }, + { KEY_8, KEY_F8 }, + { KEY_9, KEY_F9 }, + { KEY_0, KEY_F10 }, + { KEY_MINUS, KEY_F11 }, + { KEY_EQUAL, KEY_F12 }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; + static const struct apple_key_translation apple_fn_keys[] = { { KEY_BACKSPACE, KEY_DELETE }, { KEY_ENTER, KEY_INSERT }, @@ -202,6 +311,15 @@ static const struct apple_key_translation swapped_fn_leftctrl_keys[] = { { } }; +static inline void apple_setup_key_translation(struct input_dev *input, + const struct apple_key_translation *table) +{ + const struct apple_key_translation *trans; + + for (trans = table; trans->from; trans++) + set_bit(trans->to, input->keybit); +} + static const struct apple_key_translation *apple_find_translation( const struct apple_key_translation *table, u16 from) { @@ -242,10 +360,34 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, } if (fnmode) { - if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 || - hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 || - hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021) + if (hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI || + hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO || + hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS || + hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI || + hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO || + hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS || + hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI || + hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO || + hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) + table = magic_keyboard_alu_fn_keys; + else if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015 || + hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015) + table = magic_keyboard_2015_fn_keys; + else if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 || + hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 || + hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021) table = apple2021_fn_keys; + else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 || + hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 || + hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213) + table = macbookpro_no_esc_fn_keys; + else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K || + hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 || + hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F) + table = macbookpro_dedicated_esc_fn_keys; + else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K || + hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K) + table = apple_fn_keys; else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) table = macbookair_fn_keys; @@ -452,30 +594,21 @@ static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc, static void apple_setup_input(struct input_dev *input) { - const struct apple_key_translation *trans; - set_bit(KEY_NUMLOCK, input->keybit); /* Enable all needed keys */ - for (trans = apple_fn_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = powerbook_fn_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = powerbook_numlock_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = apple_iso_keyboard; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = apple2021_fn_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - if (swap_fn_leftctrl) { - for (trans = swapped_fn_leftctrl_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - } + apple_setup_key_translation(input, apple_fn_keys); + apple_setup_key_translation(input, powerbook_fn_keys); + apple_setup_key_translation(input, powerbook_numlock_keys); + apple_setup_key_translation(input, apple_iso_keyboard); + apple_setup_key_translation(input, magic_keyboard_alu_fn_keys); + apple_setup_key_translation(input, magic_keyboard_2015_fn_keys); + apple_setup_key_translation(input, apple2021_fn_keys); + apple_setup_key_translation(input, macbookpro_no_esc_fn_keys); + apple_setup_key_translation(input, macbookpro_dedicated_esc_fn_keys); + + if (swap_fn_leftctrl) + apple_setup_key_translation(input, swapped_fn_leftctrl_keys); } static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi, @@ -530,6 +663,105 @@ static int apple_input_configured(struct hid_device *hdev, return 0; } +static bool apple_backlight_check_support(struct hid_device *hdev) +{ + int i; + unsigned int hid; + struct hid_report *report; + + list_for_each_entry(report, &hdev->report_enum[HID_INPUT_REPORT].report_list, list) { + for (i = 0; i < report->maxfield; i++) { + hid = report->field[i]->usage->hid; + if ((hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR && (hid & HID_USAGE) == 0xf) + return true; + } + } + + return false; +} + +static int apple_backlight_set(struct hid_device *hdev, u16 value, u16 rate) +{ + int ret = 0; + struct apple_backlight_set_report *rep; + + rep = kmalloc(sizeof(*rep), GFP_KERNEL); + if (rep == NULL) + return -ENOMEM; + + rep->report_id = 0xB0; + rep->version = 1; + rep->backlight = value; + rep->rate = rate; + + ret = hid_hw_raw_request(hdev, 0xB0u, (u8 *) rep, sizeof(*rep), + HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); + + kfree(rep); + return ret; +} + +static int apple_backlight_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct apple_sc_backlight *backlight = container_of(led_cdev, + struct apple_sc_backlight, cdev); + + return apple_backlight_set(backlight->hdev, brightness, 0); +} + +static int apple_backlight_init(struct hid_device *hdev) +{ + int ret; + struct apple_sc *asc = hid_get_drvdata(hdev); + struct apple_backlight_config_report *rep; + + if (!apple_backlight_check_support(hdev)) + return -EINVAL; + + rep = kmalloc(0x200, GFP_KERNEL); + if (rep == NULL) + return -ENOMEM; + + ret = hid_hw_raw_request(hdev, 0xBFu, (u8 *) rep, sizeof(*rep), + HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + if (ret < 0) { + hid_err(hdev, "backlight request failed: %d\n", ret); + goto cleanup_and_exit; + } + if (ret < 8 || rep->version != 1) { + hid_err(hdev, "backlight config struct: bad version %i\n", rep->version); + ret = -EINVAL; + goto cleanup_and_exit; + } + + hid_dbg(hdev, "backlight config: off=%u, on_min=%u, on_max=%u\n", + rep->backlight_off, rep->backlight_on_min, rep->backlight_on_max); + + asc->backlight = devm_kzalloc(&hdev->dev, sizeof(*asc->backlight), GFP_KERNEL); + if (!asc->backlight) { + ret = -ENOMEM; + goto cleanup_and_exit; + } + + asc->backlight->hdev = hdev; + asc->backlight->cdev.name = "apple::kbd_backlight"; + asc->backlight->cdev.max_brightness = rep->backlight_on_max; + asc->backlight->cdev.brightness_set_blocking = apple_backlight_led_set; + + ret = apple_backlight_set(hdev, 0, 0); + if (ret < 0) { + hid_err(hdev, "backlight set request failed: %d\n", ret); + goto cleanup_and_exit; + } + + ret = devm_led_classdev_register(&hdev->dev, &asc->backlight->cdev); + +cleanup_and_exit: + kfree(rep); + return ret; +} + static int apple_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -565,6 +797,9 @@ static int apple_probe(struct hid_device *hdev, jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS)); apple_fetch_battery(hdev); + if (quirks & APPLE_BACKLIGHT_CTL) + apple_backlight_init(hdev); + return 0; } @@ -691,51 +926,67 @@ static const struct hid_device_id apple_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI), .driver_data = APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO), - .driver_data = APPLE_HAS_FN }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI), .driver_data = APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO), - .driver_data = APPLE_HAS_FN }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI), .driver_data = APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO), - .driver_data = APPLE_HAS_FN }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI), .driver_data = APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO), - .driver_data = APPLE_HAS_FN }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI), .driver_data = APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO), - .driver_data = APPLE_HAS_FN }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI), .driver_data = APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO), - .driver_data = APPLE_HAS_FN }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { 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 }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI), .driver_data = APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO), - .driver_data = APPLE_HAS_FN }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K), + .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132), + .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680), + .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213), + .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F), + .driver_data = APPLE_HAS_FN }, { 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), @@ -748,15 +999,15 @@ static const struct hid_device_id apple_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021), - .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021), - .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021), - .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f1aed5bbd000..db925794fbe6 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -81,6 +81,7 @@ struct hid_report *hid_register_report(struct hid_device *device, report_enum->report_id_hash[id] = report; list_add_tail(&report->list, &report_enum->report_list); + INIT_LIST_HEAD(&report->field_entry_list); return report; } @@ -101,7 +102,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned field = kzalloc((sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + - usages * sizeof(unsigned)), GFP_KERNEL); + 3 * usages * sizeof(unsigned int)), GFP_KERNEL); if (!field) return NULL; @@ -109,6 +110,8 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned report->field[field->index] = field; field->usage = (struct hid_usage *)(field + 1); field->value = (s32 *)(field->usage + usages); + field->new_value = (s32 *)(field->value + usages); + field->usages_priorities = (s32 *)(field->new_value + usages); field->report = report; return field; @@ -656,6 +659,8 @@ static void hid_free_report(struct hid_report *report) { unsigned n; + kfree(report->field_entries); + for (n = 0; n < report->maxfield; n++) kfree(report->field[n]); kfree(report); @@ -1525,25 +1530,41 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, } /* - * Analyse a received field, and fetch the data from it. The field - * content is stored for next report processing (we do differential - * reporting to the layer). + * Checks if the given value is valid within this field */ +static inline int hid_array_value_is_valid(struct hid_field *field, + __s32 value) +{ + __s32 min = field->logical_minimum; -static void hid_input_field(struct hid_device *hid, struct hid_field *field, - __u8 *data, int interrupt) + /* + * Value needs to be between logical min and max, and + * (value - min) is used as an index in the usage array. + * This array is of size field->maxusage + */ + return value >= min && + value <= field->logical_maximum && + value - min < field->maxusage; +} + +/* + * Fetch the field from the data. The field content is stored for next + * report processing (we do differential reporting to the layer). + */ +static void hid_input_fetch_field(struct hid_device *hid, + struct hid_field *field, + __u8 *data) { unsigned n; unsigned count = field->report_count; unsigned offset = field->report_offset; unsigned size = field->report_size; __s32 min = field->logical_minimum; - __s32 max = field->logical_maximum; __s32 *value; - value = kmalloc_array(count, sizeof(__s32), GFP_ATOMIC); - if (!value) - return; + value = field->new_value; + memset(value, 0, count * sizeof(__s32)); + field->ignored = false; for (n = 0; n < count; n++) { @@ -1554,35 +1575,228 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, /* Ignore report if ErrorRollOver */ if (!(field->flags & HID_MAIN_ITEM_VARIABLE) && - value[n] >= min && value[n] <= max && - value[n] - min < field->maxusage && - field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) - goto exit; + hid_array_value_is_valid(field, value[n]) && + field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) { + field->ignored = true; + return; + } } +} + +/* + * Process a received variable field. + */ + +static void hid_input_var_field(struct hid_device *hid, + struct hid_field *field, + int interrupt) +{ + unsigned int count = field->report_count; + __s32 *value = field->new_value; + unsigned int n; + + for (n = 0; n < count; n++) + hid_process_event(hid, + field, + &field->usage[n], + value[n], + interrupt); + + memcpy(field->value, value, count * sizeof(__s32)); +} + +/* + * Process a received array field. The field content is stored for + * next report processing (we do differential reporting to the layer). + */ + +static void hid_input_array_field(struct hid_device *hid, + struct hid_field *field, + int interrupt) +{ + unsigned int n; + unsigned int count = field->report_count; + __s32 min = field->logical_minimum; + __s32 *value; + + value = field->new_value; + + /* ErrorRollOver */ + if (field->ignored) + return; for (n = 0; n < count; n++) { + if (hid_array_value_is_valid(field, field->value[n]) && + search(value, field->value[n], count)) + hid_process_event(hid, + field, + &field->usage[field->value[n] - min], + 0, + interrupt); + + if (hid_array_value_is_valid(field, value[n]) && + search(field->value, value[n], count)) + hid_process_event(hid, + field, + &field->usage[value[n] - min], + 1, + interrupt); + } - if (HID_MAIN_ITEM_VARIABLE & field->flags) { - hid_process_event(hid, field, &field->usage[n], value[n], interrupt); - continue; + memcpy(field->value, value, count * sizeof(__s32)); +} + +/* + * Analyse a received report, and fetch the data from it. The field + * content is stored for next report processing (we do differential + * reporting to the layer). + */ +static void hid_process_report(struct hid_device *hid, + struct hid_report *report, + __u8 *data, + int interrupt) +{ + unsigned int a; + struct hid_field_entry *entry; + struct hid_field *field; + + /* first retrieve all incoming values in data */ + for (a = 0; a < report->maxfield; a++) + hid_input_fetch_field(hid, field = report->field[a], data); + + if (!list_empty(&report->field_entry_list)) { + /* INPUT_REPORT, we have a priority list of fields */ + list_for_each_entry(entry, + &report->field_entry_list, + list) { + field = entry->field; + + if (field->flags & HID_MAIN_ITEM_VARIABLE) + hid_process_event(hid, + field, + &field->usage[entry->index], + field->new_value[entry->index], + interrupt); + else + hid_input_array_field(hid, field, interrupt); } - if (field->value[n] >= min && field->value[n] <= max - && field->value[n] - min < field->maxusage - && field->usage[field->value[n] - min].hid - && search(value, field->value[n], count)) - hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); + /* we need to do the memcpy at the end for var items */ + for (a = 0; a < report->maxfield; a++) { + field = report->field[a]; - if (value[n] >= min && value[n] <= max - && value[n] - min < field->maxusage - && field->usage[value[n] - min].hid - && search(field->value, value[n], count)) - hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); + if (field->flags & HID_MAIN_ITEM_VARIABLE) + memcpy(field->value, field->new_value, + field->report_count * sizeof(__s32)); + } + } else { + /* FEATURE_REPORT, regular processing */ + for (a = 0; a < report->maxfield; a++) { + field = report->field[a]; + + if (field->flags & HID_MAIN_ITEM_VARIABLE) + hid_input_var_field(hid, field, interrupt); + else + hid_input_array_field(hid, field, interrupt); + } } +} - memcpy(field->value, value, count * sizeof(__s32)); -exit: - kfree(value); +/* + * Insert a given usage_index in a field in the list + * of processed usages in the report. + * + * The elements of lower priority score are processed + * first. + */ +static void __hid_insert_field_entry(struct hid_device *hid, + struct hid_report *report, + struct hid_field_entry *entry, + struct hid_field *field, + unsigned int usage_index) +{ + struct hid_field_entry *next; + + entry->field = field; + entry->index = usage_index; + entry->priority = field->usages_priorities[usage_index]; + + /* insert the element at the correct position */ + list_for_each_entry(next, + &report->field_entry_list, + list) { + /* + * the priority of our element is strictly higher + * than the next one, insert it before + */ + if (entry->priority > next->priority) { + list_add_tail(&entry->list, &next->list); + return; + } + } + + /* lowest priority score: insert at the end */ + list_add_tail(&entry->list, &report->field_entry_list); +} + +static void hid_report_process_ordering(struct hid_device *hid, + struct hid_report *report) +{ + struct hid_field *field; + struct hid_field_entry *entries; + unsigned int a, u, usages; + unsigned int count = 0; + + /* count the number of individual fields in the report */ + for (a = 0; a < report->maxfield; a++) { + field = report->field[a]; + + if (field->flags & HID_MAIN_ITEM_VARIABLE) + count += field->report_count; + else + count++; + } + + /* allocate the memory to process the fields */ + entries = kcalloc(count, sizeof(*entries), GFP_KERNEL); + if (!entries) + return; + + report->field_entries = entries; + + /* + * walk through all fields in the report and + * store them by priority order in report->field_entry_list + * + * - Var elements are individualized (field + usage_index) + * - Arrays are taken as one, we can not chose an order for them + */ + usages = 0; + for (a = 0; a < report->maxfield; a++) { + field = report->field[a]; + + if (field->flags & HID_MAIN_ITEM_VARIABLE) { + for (u = 0; u < field->report_count; u++) { + __hid_insert_field_entry(hid, report, + &entries[usages], + field, u); + usages++; + } + } else { + __hid_insert_field_entry(hid, report, &entries[usages], + field, 0); + usages++; + } + } +} + +static void hid_process_ordering(struct hid_device *hid) +{ + struct hid_report *report; + struct hid_report_enum *report_enum = &hid->report_enum[HID_INPUT_REPORT]; + + list_for_each_entry(report, &report_enum->report_list, list) + hid_report_process_ordering(hid, report); } /* @@ -1746,7 +1960,6 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, struct hid_report_enum *report_enum = hid->report_enum + type; struct hid_report *report; struct hid_driver *hdrv; - unsigned int a; u32 rsize, csize = size; u8 *cdata = data; int ret = 0; @@ -1782,8 +1995,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, } if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) { - for (a = 0; a < report->maxfield; a++) - hid_input_field(hid, report->field[a], cdata, interrupt); + hid_process_report(hid, report, cdata, interrupt); hdrv = hid->driver; if (hdrv && hdrv->report) hdrv->report(hid, report); @@ -1970,6 +2182,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) return -ENODEV; } + hid_process_ordering(hdev); + if ((hdev->claimed & HID_CLAIMED_INPUT) && (connect_mask & HID_CONNECT_FF) && hdev->ff_init) hdev->ff_init(hdev); diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c index 8e960d7b233b..2876cb6a7dca 100644 --- a/drivers/hid/hid-elo.c +++ b/drivers/hid/hid-elo.c @@ -228,7 +228,6 @@ static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct elo_priv *priv; int ret; - struct usb_device *udev; if (!hid_is_usb(hdev)) return -EINVAL; @@ -238,8 +237,7 @@ static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id) return -ENOMEM; INIT_DELAYED_WORK(&priv->work, elo_work); - udev = interface_to_usbdev(to_usb_interface(hdev->dev.parent)); - priv->usbdev = usb_get_dev(udev); + priv->usbdev = interface_to_usbdev(to_usb_interface(hdev->dev.parent)); hid_set_drvdata(hdev, priv); @@ -270,8 +268,6 @@ static void elo_remove(struct hid_device *hdev) { struct elo_priv *priv = hid_get_drvdata(hdev); - usb_put_dev(priv->usbdev); - hid_hw_stop(hdev); cancel_delayed_work_sync(&priv->work); kfree(priv); diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c index 0403beb3104b..ddbe0de177e2 100644 --- a/drivers/hid/hid-google-hammer.c +++ b/drivers/hid/hid-google-hammer.c @@ -58,7 +58,7 @@ static int cbas_ec_query_base(struct cros_ec_device *ec_dev, bool get_state, struct cros_ec_command *msg; int ret; - msg = kzalloc(sizeof(*msg) + max(sizeof(u32), sizeof(*params)), + msg = kzalloc(struct_size(msg, data, max(sizeof(u32), sizeof(*params))), GFP_KERNEL); if (!msg) return -ENOMEM; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 85975031389b..6c2a36b16ed2 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -167,6 +167,14 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI 0x0272 #define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO 0x0273 #define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS 0x0274 +#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K 0x027a +#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 0x027b +#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 0x027c +#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213 0x027d +#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K 0x027e +#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 0x027f +#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K 0x0280 +#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F 0x0340 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b #define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 @@ -1370,6 +1378,7 @@ #define USB_VENDOR_ID_UGTIZER 0x2179 #define USB_DEVICE_ID_UGTIZER_TABLET_GP0610 0x0053 #define USB_DEVICE_ID_UGTIZER_TABLET_GT5040 0x0077 +#define USB_DEVICE_ID_UGTIZER_TABLET_WP5540 0x0004 #define USB_VENDOR_ID_VIEWSONIC 0x0543 #define USB_DEVICE_ID_VIEWSONIC_PD1011 0xe621 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 112901d2d8d2..56d4e91c4750 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -48,6 +48,51 @@ static const struct { __s32 y; } hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; +struct usage_priority { + __u32 usage; /* the HID usage associated */ + bool global; /* we assume all usages to be slotted, + * unless global + */ + unsigned int slot_overwrite; /* for globals: allows to set the usage + * before or after the slots + */ +}; + +/* + * hid-input will convert this list into priorities: + * the first element will have the highest priority + * (the length of the following array) and the last + * element the lowest (1). + * + * hid-input will then shift the priority by 8 bits to leave some space + * in case drivers want to interleave other fields. + * + * To accommodate slotted devices, the slot priority is + * defined in the next 8 bits (defined by 0xff - slot). + * + * If drivers want to add fields before those, hid-input will + * leave out the first 8 bits of the priority value. + * + * This still leaves us 65535 individual priority values. + */ +static const struct usage_priority hidinput_usages_priorities[] = { + { /* Eraser (eraser touching) must always come before tipswitch */ + .usage = HID_DG_ERASER, + }, + { /* Invert must always come before In Range */ + .usage = HID_DG_INVERT, + }, + { /* Is the tip of the tool touching? */ + .usage = HID_DG_TIPSWITCH, + }, + { /* Tip Pressure might emulate tip switch */ + .usage = HID_DG_TIPPRESSURE, + }, + { /* In Range needs to come after the other tool states */ + .usage = HID_DG_INRANGE, + }, +}; + #define map_abs(c) hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c)) #define map_rel(c) hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c)) #define map_key(c) hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c)) @@ -586,11 +631,13 @@ static bool hidinput_field_in_collection(struct hid_device *device, struct hid_f } static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, - struct hid_usage *usage) + struct hid_usage *usage, unsigned int usage_index) { struct input_dev *input = hidinput->input; struct hid_device *device = input_get_drvdata(input); + const struct usage_priority *usage_priority = NULL; int max = 0, code; + unsigned int i = 0; unsigned long *bit = NULL; field->hidinput = hidinput; @@ -608,6 +655,28 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel goto ignore; } + /* assign a priority based on the static list declared here */ + for (i = 0; i < ARRAY_SIZE(hidinput_usages_priorities); i++) { + if (usage->hid == hidinput_usages_priorities[i].usage) { + usage_priority = &hidinput_usages_priorities[i]; + + field->usages_priorities[usage_index] = + (ARRAY_SIZE(hidinput_usages_priorities) - i) << 8; + break; + } + } + + /* + * For slotted devices, we need to also add the slot index + * in the priority. + */ + if (usage_priority && usage_priority->global) + field->usages_priorities[usage_index] |= + usage_priority->slot_overwrite; + else + field->usages_priorities[usage_index] |= + (0xff - field->slot_idx) << 16; + if (device->driver->input_mapping) { int ret = device->driver->input_mapping(device, hidinput, field, usage, &bit, &max); @@ -828,10 +897,31 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel break; case 0x32: /* InRange */ - switch (field->physical & 0xff) { - case 0x21: map_key(BTN_TOOL_MOUSE); break; - case 0x22: map_key(BTN_TOOL_FINGER); break; - default: map_key(BTN_TOOL_PEN); break; + switch (field->physical) { + case HID_DG_PUCK: + map_key(BTN_TOOL_MOUSE); + break; + case HID_DG_FINGER: + map_key(BTN_TOOL_FINGER); + break; + default: + /* + * If the physical is not given, + * rely on the application. + */ + if (!field->physical) { + switch (field->application) { + case HID_DG_TOUCHSCREEN: + case HID_DG_TOUCHPAD: + map_key_clear(BTN_TOOL_FINGER); + break; + default: + map_key_clear(BTN_TOOL_PEN); + } + } else { + map_key(BTN_TOOL_PEN); + } + break; } break; @@ -1315,9 +1405,38 @@ static void hidinput_handle_scroll(struct hid_usage *usage, input_event(input, EV_REL, usage->code, hi_res); } +static void hid_report_release_tool(struct hid_report *report, struct input_dev *input, + unsigned int tool) +{ + /* if the given tool is not currently reported, ignore */ + if (!test_bit(tool, input->key)) + return; + + /* + * if the given tool was previously set, release it, + * release any TOUCH and send an EV_SYN + */ + input_event(input, EV_KEY, BTN_TOUCH, 0); + input_event(input, EV_KEY, tool, 0); + input_event(input, EV_SYN, SYN_REPORT, 0); + + report->tool = 0; +} + +static void hid_report_set_tool(struct hid_report *report, struct input_dev *input, + unsigned int new_tool) +{ + if (report->tool != new_tool) + hid_report_release_tool(report, input, report->tool); + + input_event(input, EV_KEY, new_tool, 1); + report->tool = new_tool; +} + void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct input_dev *input; + struct hid_report *report = field->report; unsigned *quirks = &hid->quirks; if (!usage->type) @@ -1333,12 +1452,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct input = field->hidinput->input; - if (usage->type == EV_ABS && - (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) || - ((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))) { - value = field->logical_maximum - value; - } - if (usage->hat_min < usage->hat_max || usage->hat_dir) { int hat_dir = usage->hat_dir; if (!hat_dir) @@ -1349,61 +1462,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; } - if (usage->hid == HID_DG_INVERT) { - *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT); - return; - } - - if (usage->hid == HID_DG_INRANGE) { - if (value) { - input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1); - return; - } - input_event(input, usage->type, usage->code, 0); - input_event(input, usage->type, BTN_TOOL_RUBBER, 0); - return; - } - - if (usage->hid == HID_DG_TIPPRESSURE && (*quirks & HID_QUIRK_NOTOUCH)) { - int a = field->logical_minimum; - int b = field->logical_maximum; - input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3)); - } - - if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */ - dbg_hid("Maximum Effects - %d\n",value); - return; - } - - if (usage->hid == (HID_UP_PID | 0x7fUL)) { - dbg_hid("PID Pool Report\n"); - return; - } - - if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ - return; - - if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES || - usage->code == REL_HWHEEL_HI_RES)) { - hidinput_handle_scroll(usage, input, value); - return; - } - - if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && - (usage->code == ABS_VOLUME)) { - int count = abs(value); - int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN; - int i; - - for (i = 0; i < count; i++) { - input_event(input, EV_KEY, direction, 1); - input_sync(input); - input_event(input, EV_KEY, direction, 0); - input_sync(input); - } - return; - } - /* * Ignore out-of-range values as per HID specification, * section 5.10 and 6.2.25, when NULL state bit is present. @@ -1416,7 +1474,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct * don't specify logical min and max. */ if ((field->flags & HID_MAIN_ITEM_VARIABLE) && - (field->logical_minimum < field->logical_maximum)) { + field->logical_minimum < field->logical_maximum) { if (field->flags & HID_MAIN_ITEM_NULL_STATE && (value < field->logical_minimum || value > field->logical_maximum)) { @@ -1428,6 +1486,123 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct field->logical_maximum); } + switch (usage->hid) { + case HID_DG_ERASER: + report->tool_active |= !!value; + + /* + * if eraser is set, we must enforce BTN_TOOL_RUBBER + * to accommodate for devices not following the spec. + */ + if (value) + hid_report_set_tool(report, input, BTN_TOOL_RUBBER); + else if (report->tool != BTN_TOOL_RUBBER) + /* value is off, tool is not rubber, ignore */ + return; + + /* let hid-input set BTN_TOUCH */ + break; + + case HID_DG_INVERT: + report->tool_active |= !!value; + + /* + * If invert is set, we store BTN_TOOL_RUBBER. + */ + if (value) + hid_report_set_tool(report, input, BTN_TOOL_RUBBER); + else if (!report->tool_active) + /* tool_active not set means Invert and Eraser are not set */ + hid_report_release_tool(report, input, BTN_TOOL_RUBBER); + + /* no further processing */ + return; + + case HID_DG_INRANGE: + report->tool_active |= !!value; + + if (report->tool_active) { + /* + * if tool is not set but is marked as active, + * assume ours + */ + if (!report->tool) + hid_report_set_tool(report, input, usage->code); + } else { + hid_report_release_tool(report, input, usage->code); + } + + /* reset tool_active for the next event */ + report->tool_active = false; + + /* no further processing */ + return; + + case HID_DG_TIPSWITCH: + report->tool_active |= !!value; + + /* if tool is set to RUBBER we should ignore the current value */ + if (report->tool == BTN_TOOL_RUBBER) + return; + + break; + + case HID_DG_TIPPRESSURE: + if (*quirks & HID_QUIRK_NOTOUCH) { + int a = field->logical_minimum; + int b = field->logical_maximum; + + if (value > a + ((b - a) >> 3)) { + input_event(input, EV_KEY, BTN_TOUCH, 1); + report->tool_active = true; + } + } + break; + + case HID_UP_PID | 0x83UL: /* Simultaneous Effects Max */ + dbg_hid("Maximum Effects - %d\n",value); + return; + + case HID_UP_PID | 0x7fUL: + dbg_hid("PID Pool Report\n"); + return; + } + + switch (usage->type) { + case EV_KEY: + if (usage->code == 0) /* Key 0 is "unassigned", not KEY_UNKNOWN */ + return; + break; + + case EV_REL: + if (usage->code == REL_WHEEL_HI_RES || + usage->code == REL_HWHEEL_HI_RES) { + hidinput_handle_scroll(usage, input, value); + return; + } + break; + + case EV_ABS: + if ((field->flags & HID_MAIN_ITEM_RELATIVE) && + usage->code == ABS_VOLUME) { + int count = abs(value); + int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN; + int i; + + for (i = 0; i < count; i++) { + input_event(input, EV_KEY, direction, 1); + input_sync(input); + input_event(input, EV_KEY, direction, 0); + input_sync(input); + } + return; + + } else if (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) || + ((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y)) + value = field->logical_maximum - value; + break; + } + /* * Ignore reports for absolute data if the data didn't change. This is * not only an optimization but also fixes 'dead' key reports. Some @@ -1930,12 +2105,63 @@ static struct hid_input *hidinput_match_application(struct hid_report *report) static inline void hidinput_configure_usages(struct hid_input *hidinput, struct hid_report *report) { - int i, j; + int i, j, k; + int first_field_index = 0; + int slot_collection_index = -1; + int prev_collection_index = -1; + unsigned int slot_idx = 0; + struct hid_field *field; + + /* + * First tag all the fields that are part of a slot, + * a slot needs to have one Contact ID in the collection + */ + for (i = 0; i < report->maxfield; i++) { + field = report->field[i]; + + /* ignore fields without usage */ + if (field->maxusage < 1) + continue; + + /* + * janitoring when collection_index changes + */ + if (prev_collection_index != field->usage->collection_index) { + prev_collection_index = field->usage->collection_index; + first_field_index = i; + } + + /* + * if we already found a Contact ID in the collection, + * tag and continue to the next. + */ + if (slot_collection_index == field->usage->collection_index) { + field->slot_idx = slot_idx; + continue; + } + + /* check if the current field has Contact ID */ + for (j = 0; j < field->maxusage; j++) { + if (field->usage[j].hid == HID_DG_CONTACTID) { + slot_collection_index = field->usage->collection_index; + slot_idx++; + + /* + * mark all previous fields and this one in the + * current collection to be slotted. + */ + for (k = first_field_index; k <= i; k++) + report->field[k]->slot_idx = slot_idx; + break; + } + } + } for (i = 0; i < report->maxfield; i++) for (j = 0; j < report->field[i]->maxusage; j++) hidinput_configure_usage(hidinput, report->field[i], - report->field[i]->usage + j); + report->field[i]->usage + j, + j); } /* diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 7106b921b53c..c358778e070b 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -1068,6 +1068,7 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, workitem.reports_supported |= STD_KEYBOARD; break; case 0x0f: + case 0x11: device_type = "eQUAD Lightspeed 1.2"; logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem); workitem.reports_supported |= STD_KEYBOARD; diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index b6a9a0f3966e..2204de889739 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -2128,6 +2128,10 @@ static int nintendo_hid_probe(struct hid_device *hdev, spin_lock_init(&ctlr->lock); ctlr->rumble_queue = alloc_workqueue("hid-nintendo-rumble_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); + if (!ctlr->rumble_queue) { + ret = -ENOMEM; + goto err; + } INIT_WORK(&ctlr->rumble_worker, joycon_rumble_worker); ret = hid_parse(hdev); diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 9af1dc8ae3a2..dc67717d2dab 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -187,6 +187,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60), HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_WP5540), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET), HID_QUIRK_MULTI_INPUT }, @@ -294,6 +295,14 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F) }, { 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) }, @@ -929,6 +938,14 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F) }, { 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) }, { } diff --git a/drivers/hid/hid-thrustmaster.c b/drivers/hid/hid-thrustmaster.c index 03b935ff02d5..c3e6d69fdfbd 100644 --- a/drivers/hid/hid-thrustmaster.c +++ b/drivers/hid/hid-thrustmaster.c @@ -64,7 +64,9 @@ struct tm_wheel_info { */ static const struct tm_wheel_info tm_wheels_infos[] = { {0x0306, 0x0006, "Thrustmaster T150RS"}, + {0x0200, 0x0005, "Thrustmaster T300RS (Missing Attachment)"}, {0x0206, 0x0005, "Thrustmaster T300RS"}, + {0x0209, 0x0005, "Thrustmaster T300RS (Open Wheel Attachment)"}, {0x0204, 0x0005, "Thrustmaster T300 Ferrari Alcantara Edition"}, {0x0002, 0x0002, "Thrustmaster T500RS"} //{0x0407, 0x0001, "Thrustmaster TMX"} @@ -158,6 +160,12 @@ static void thrustmaster_interrupts(struct hid_device *hdev) return; } + if (usbif->cur_altsetting->desc.bNumEndpoints < 2) { + kfree(send_buf); + hid_err(hdev, "Wrong number of endpoints?\n"); + return; + } + ep = &usbif->cur_altsetting->endpoint[1]; b_ep = ep->desc.bEndpointAddress; diff --git a/drivers/hid/hid-vivaldi.c b/drivers/hid/hid-vivaldi.c index efa6140915f4..42ceb2058a09 100644 --- a/drivers/hid/hid-vivaldi.c +++ b/drivers/hid/hid-vivaldi.c @@ -144,7 +144,7 @@ out: static int vivaldi_input_configured(struct hid_device *hdev, struct hid_input *hidinput) { - return sysfs_create_group(&hdev->dev.kobj, &input_attribute_group); + return devm_device_add_group(&hdev->dev, &input_attribute_group); } static const struct hid_device_id vivaldi_table[] = { diff --git a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c index b4dad66fa954..ec6c73f75ffe 100644 --- a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c +++ b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c @@ -27,7 +27,6 @@ struct i2c_hid_of_goodix { struct regulator *vdd; struct notifier_block nb; - struct mutex regulator_mutex; struct gpio_desc *reset_gpio; const struct goodix_i2c_hid_timing_data *timings; }; @@ -67,8 +66,6 @@ static int ihid_goodix_vdd_notify(struct notifier_block *nb, container_of(nb, struct i2c_hid_of_goodix, nb); int ret = NOTIFY_OK; - mutex_lock(&ihid_goodix->regulator_mutex); - switch (event) { case REGULATOR_EVENT_PRE_DISABLE: gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1); @@ -87,8 +84,6 @@ static int ihid_goodix_vdd_notify(struct notifier_block *nb, break; } - mutex_unlock(&ihid_goodix->regulator_mutex); - return ret; } @@ -102,8 +97,6 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client, if (!ihid_goodix) return -ENOMEM; - mutex_init(&ihid_goodix->regulator_mutex); - ihid_goodix->ops.power_up = goodix_i2c_hid_power_up; ihid_goodix->ops.power_down = goodix_i2c_hid_power_down; @@ -130,25 +123,28 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client, * long. Holding the controller in reset apparently draws extra * power. */ - mutex_lock(&ihid_goodix->regulator_mutex); ihid_goodix->nb.notifier_call = ihid_goodix_vdd_notify; ret = devm_regulator_register_notifier(ihid_goodix->vdd, &ihid_goodix->nb); - if (ret) { - mutex_unlock(&ihid_goodix->regulator_mutex); + if (ret) return dev_err_probe(&client->dev, ret, "regulator notifier request failed\n"); - } /* * If someone else is holding the regulator on (or the regulator is * an always-on one) we might never be told to deassert reset. Do it - * now. Here we'll assume that someone else might have _just - * barely_ turned the regulator on so we'll do the full - * "post_power_delay" just in case. + * now... and temporarily bump the regulator reference count just to + * make sure it is impossible for this to race with our own notifier! + * We also assume that someone else might have _just barely_ turned + * the regulator on so we'll do the full "post_power_delay" just in + * case. */ - if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd)) + if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd)) { + ret = regulator_enable(ihid_goodix->vdd); + if (ret) + return ret; goodix_i2c_hid_deassert_reset(ihid_goodix, true); - mutex_unlock(&ihid_goodix->regulator_mutex); + regulator_disable(ihid_goodix->vdd); + } return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001, 0); } diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c index e24988586710..16aa030af845 100644 --- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c +++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c @@ -661,21 +661,12 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data, */ payload_max_size &= ~(L1_CACHE_BYTES - 1); - dma_buf = kmalloc(payload_max_size, GFP_KERNEL | GFP_DMA32); + dma_buf = dma_alloc_coherent(devc, payload_max_size, &dma_buf_phy, GFP_KERNEL); if (!dma_buf) { client_data->flag_retry = true; return -ENOMEM; } - dma_buf_phy = dma_map_single(devc, dma_buf, payload_max_size, - DMA_TO_DEVICE); - if (dma_mapping_error(devc, dma_buf_phy)) { - dev_err(cl_data_to_dev(client_data), "DMA map failed\n"); - client_data->flag_retry = true; - rv = -ENOMEM; - goto end_err_dma_buf_release; - } - ldr_xfer_dma_frag.fragment.hdr.command = LOADER_CMD_XFER_FRAGMENT; ldr_xfer_dma_frag.fragment.xfer_mode = LOADER_XFER_MODE_DIRECT_DMA; ldr_xfer_dma_frag.ddr_phys_addr = (u64)dma_buf_phy; @@ -695,14 +686,7 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data, ldr_xfer_dma_frag.fragment.size = fragment_size; memcpy(dma_buf, &fw->data[fragment_offset], fragment_size); - dma_sync_single_for_device(devc, dma_buf_phy, - payload_max_size, - DMA_TO_DEVICE); - - /* - * Flush cache here because the dma_sync_single_for_device() - * does not do for x86. - */ + /* Flush cache to be sure the data is in main memory. */ clflush_cache_range(dma_buf, payload_max_size); dev_dbg(cl_data_to_dev(client_data), @@ -725,15 +709,8 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data, fragment_offset += fragment_size; } - dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE); - kfree(dma_buf); - return 0; - end_err_resp_buf_release: - /* Free ISH buffer if not done already, in error case */ - dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE); -end_err_dma_buf_release: - kfree(dma_buf); + dma_free_coherent(devc, payload_max_size, dma_buf, dma_buf_phy); return rv; } |