From b283d0c353dee57869bdff59e0f01500f1316411 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 6 May 2019 20:03:46 -0700 Subject: Input: eeti_ts - read hardware state once after wakeup For systems in which the touch IRQ is acting as wakeup source, and that do not support level-driven interrupts, the interrupt controller might not latch the GPIO IRQ during sleep. In such cases, the interrupt will never occur again after resume, hence the touch screen appears dead. To fix this, check for the assertion of the attn gpio, and read form the controller once in the resume path to read the hardware status and to arm the IRQ again. Introduce a mutex to guard eeti_ts_read() against parallel invocations from different contexts. Signed-off-by: Daniel Mack Reported-by: Sven Neumann Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 71 +++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 15 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 7fe41965c5d1..b508d2693c0e 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -41,6 +41,7 @@ struct eeti_ts { struct input_dev *input; struct gpio_desc *attn_gpio; struct touchscreen_properties props; + struct mutex mutex; bool running; }; @@ -75,42 +76,80 @@ static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf) input_sync(eeti->input); } +static int eeti_ts_read(struct eeti_ts *eeti) +{ + int len, error; + char buf[6]; + + len = i2c_master_recv(eeti->client, buf, sizeof(buf)); + if (len != sizeof(buf)) { + error = len < 0 ? len : -EIO; + dev_err(&eeti->client->dev, + "failed to read touchscreen data: %d\n", + error); + return error; + } + + /* Motion packet */ + if (buf[0] & 0x80) + eeti_ts_report_event(eeti, buf); + + return 0; +} + static irqreturn_t eeti_ts_isr(int irq, void *dev_id) { struct eeti_ts *eeti = dev_id; - int len; int error; - char buf[6]; + + mutex_lock(&eeti->mutex); do { - len = i2c_master_recv(eeti->client, buf, sizeof(buf)); - if (len != sizeof(buf)) { - error = len < 0 ? len : -EIO; - dev_err(&eeti->client->dev, - "failed to read touchscreen data: %d\n", - error); + /* + * If we have attention GPIO, trust it. Otherwise we'll read + * once and exit. We assume that in this case we are using + * level triggered interrupt and it will get raised again + * if/when there is more data. + */ + if (eeti->attn_gpio && + !gpiod_get_value_cansleep(eeti->attn_gpio)) { break; } - if (buf[0] & 0x80) { - /* Motion packet */ - eeti_ts_report_event(eeti, buf); - } - } while (eeti->running && - eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)); + error = eeti_ts_read(eeti); + if (error) + break; + + } while (eeti->running && eeti->attn_gpio); + mutex_unlock(&eeti->mutex); return IRQ_HANDLED; } static void eeti_ts_start(struct eeti_ts *eeti) { + mutex_lock(&eeti->mutex); + eeti->running = true; - wmb(); enable_irq(eeti->client->irq); + + /* + * Kick the controller in case we are using edge interrupt and + * we missed our edge while interrupt was disabled. We expect + * the attention GPIO to be wired in this case. + */ + if (eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)) + eeti_ts_read(eeti); + + mutex_unlock(&eeti->mutex); } static void eeti_ts_stop(struct eeti_ts *eeti) { + /* + * Not locking here, just setting a flag and expect that the + * interrupt thread will notice the flag eventually. + */ eeti->running = false; wmb(); disable_irq(eeti->client->irq); @@ -153,6 +192,8 @@ static int eeti_ts_probe(struct i2c_client *client, return -ENOMEM; } + mutex_init(&eeti->mutex); + input = devm_input_allocate_device(dev); if (!input) { dev_err(dev, "Failed to allocate input device.\n"); -- cgit v1.2.3-59-g8ed1b From 6981a2356181083ffa6d566323546eb7894cd87b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 20 May 2019 21:58:58 -0700 Subject: Input: da9063_onkey - remove platform_data support There are no in-kernel users anymore, so remove this outdated interface. Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Acked-by: Steve Twiss Tested-by: Steve Twiss Reviewed-by: Geert Uytterhoeven Signed-off-by: Dmitry Torokhov --- drivers/input/misc/da9063_onkey.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c index 3e9c353d82ef..e3a273c74123 100644 --- a/drivers/input/misc/da9063_onkey.c +++ b/drivers/input/misc/da9063_onkey.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -201,8 +200,6 @@ static void da9063_cancel_poll(void *data) static int da9063_onkey_probe(struct platform_device *pdev) { - struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); - struct da9063_pdata *pdata = dev_get_platdata(da9063->dev); struct da9063_onkey *onkey; const struct of_device_id *match; int irq; @@ -229,12 +226,8 @@ static int da9063_onkey_probe(struct platform_device *pdev) return -ENXIO; } - if (pdata) - onkey->key_power = pdata->key_power; - else - onkey->key_power = - !of_property_read_bool(pdev->dev.of_node, - "dlg,disable-key-power"); + onkey->key_power = !of_property_read_bool(pdev->dev.of_node, + "dlg,disable-key-power"); onkey->input = devm_input_allocate_device(&pdev->dev); if (!onkey->input) { -- cgit v1.2.3-59-g8ed1b From 5f462872a192db55c278ac39da5e892cc23739a1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 20 May 2019 21:59:33 -0700 Subject: Input: da9063_onkey - convert header to SPDX Convert the header of the source file to SPDX. Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Acked-by: Steve Twiss Reviewed-by: Geert Uytterhoeven Signed-off-by: Dmitry Torokhov --- drivers/input/misc/da9063_onkey.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c index e3a273c74123..c06e067bd627 100644 --- a/drivers/input/misc/da9063_onkey.c +++ b/drivers/input/misc/da9063_onkey.c @@ -1,16 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * OnKey device driver for DA9063, DA9062 and DA9061 PMICs * Copyright (C) 2015 Dialog Semiconductor Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include -- cgit v1.2.3-59-g8ed1b From d8ea61c5af0ee615455130449186ac7b698155d9 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 20 May 2019 22:11:37 -0700 Subject: Input: imx_keypad - use devm_platform_ioremap_resource() to simplify code Use the new helper devm_platform_ioremap_resource() which wraps the platform_get_resource() and devm_ioremap_resource() together, to simplify the code. Signed-off-by: Anson Huang Reviewed-by: Mukesh Ojha Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/imx_keypad.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 539cb670de41..cf08f4acb191 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -422,7 +422,6 @@ static int imx_keypad_probe(struct platform_device *pdev) dev_get_platdata(&pdev->dev); struct imx_keypad *keypad; struct input_dev *input_dev; - struct resource *res; int irq, error, i, row, col; if (!keymap_data && !pdev->dev.of_node) { @@ -455,8 +454,7 @@ static int imx_keypad_probe(struct platform_device *pdev) timer_setup(&keypad->check_matrix_timer, imx_keypad_check_for_events, 0); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res); + keypad->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(keypad->mmio_base)) return PTR_ERR(keypad->mmio_base); -- cgit v1.2.3-59-g8ed1b From f1222f5ee2c0908a2c537f37174b91ff88cfe987 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 20 May 2019 22:12:43 -0700 Subject: Input: imx6ul_tsc - use devm_platform_ioremap_resource() to simplify code Use the new helper devm_platform_ioremap_resource() which wraps the platform_get_resource() and devm_ioremap_resource() together, to simplify the code. Signed-off-by: Anson Huang Reviewed-by: Mukesh Ojha Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imx6ul_tsc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index c10fc594f94d..e04eecd65bbb 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -364,8 +364,6 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct imx6ul_tsc *tsc; struct input_dev *input_dev; - struct resource *tsc_mem; - struct resource *adc_mem; int err; int tsc_irq; int adc_irq; @@ -403,16 +401,14 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) return err; } - tsc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - tsc->tsc_regs = devm_ioremap_resource(&pdev->dev, tsc_mem); + tsc->tsc_regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(tsc->tsc_regs)) { err = PTR_ERR(tsc->tsc_regs); dev_err(&pdev->dev, "failed to remap tsc memory: %d\n", err); return err; } - adc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - tsc->adc_regs = devm_ioremap_resource(&pdev->dev, adc_mem); + tsc->adc_regs = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(tsc->adc_regs)) { err = PTR_ERR(tsc->adc_regs); dev_err(&pdev->dev, "failed to remap adc memory: %d\n", err); -- cgit v1.2.3-59-g8ed1b From b62f97634aa9f61efb8e0935658c758140680c84 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 May 2019 13:45:21 -0700 Subject: Input: iqs5xx - remove redundant dev_set_drvdata call Calling i2c_set_clientdata() is enough. Signed-off-by: Axel Lin Acked-by: Jeff LaBundy Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs5xx.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index b832fe062645..158707897c2d 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -1054,8 +1054,6 @@ static int iqs5xx_probe(struct i2c_client *client, if (!iqs5xx) return -ENOMEM; - dev_set_drvdata(&client->dev, iqs5xx); - i2c_set_clientdata(client, iqs5xx); iqs5xx->client = client; -- cgit v1.2.3-59-g8ed1b From 37548659bb223563797584c752274b81326d3f3c Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 27 May 2019 18:24:28 -0700 Subject: Input: elantech - query the min/max information beforehand too For the latest generation of Elantech touchpads, we need to forward the min/max information from PS/2 to SMBus. Prepare this work by fetching the information before creating the SMBus companion device. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 160 +++++++++++++++++++---------------------- drivers/input/mouse/elantech.h | 5 ++ 2 files changed, 79 insertions(+), 86 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 530142b5a115..b551a65b0fe0 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -994,88 +994,6 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) return rc; } -static int elantech_set_range(struct psmouse *psmouse, - unsigned int *x_min, unsigned int *y_min, - unsigned int *x_max, unsigned int *y_max, - unsigned int *width) -{ - struct elantech_data *etd = psmouse->private; - struct elantech_device_info *info = &etd->info; - unsigned char param[3]; - unsigned char traces; - - switch (info->hw_version) { - case 1: - *x_min = ETP_XMIN_V1; - *y_min = ETP_YMIN_V1; - *x_max = ETP_XMAX_V1; - *y_max = ETP_YMAX_V1; - break; - - case 2: - if (info->fw_version == 0x020800 || - info->fw_version == 0x020b00 || - info->fw_version == 0x020030) { - *x_min = ETP_XMIN_V2; - *y_min = ETP_YMIN_V2; - *x_max = ETP_XMAX_V2; - *y_max = ETP_YMAX_V2; - } else { - int i; - int fixed_dpi; - - i = (info->fw_version > 0x020800 && - info->fw_version < 0x020900) ? 1 : 2; - - if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) - return -1; - - fixed_dpi = param[1] & 0x10; - - if (((info->fw_version >> 16) == 0x14) && fixed_dpi) { - if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) - return -1; - - *x_max = (info->capabilities[1] - i) * param[1] / 2; - *y_max = (info->capabilities[2] - i) * param[2] / 2; - } else if (info->fw_version == 0x040216) { - *x_max = 819; - *y_max = 405; - } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) { - *x_max = 900; - *y_max = 500; - } else { - *x_max = (info->capabilities[1] - i) * 64; - *y_max = (info->capabilities[2] - i) * 64; - } - } - break; - - case 3: - if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) - return -1; - - *x_max = (0x0f & param[0]) << 8 | param[1]; - *y_max = (0xf0 & param[0]) << 4 | param[2]; - break; - - case 4: - if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) - return -1; - - *x_max = (0x0f & param[0]) << 8 | param[1]; - *y_max = (0xf0 & param[0]) << 4 | param[2]; - traces = info->capabilities[1]; - if ((traces < 2) || (traces > *x_max)) - return -1; - - *width = *x_max / (traces - 1); - break; - } - - return 0; -} - /* * (value from firmware) * 10 + 790 = dpi * we also have to convert dpi to dots/mm (*10/254 to avoid floating point) @@ -1202,10 +1120,9 @@ static int elantech_set_input_params(struct psmouse *psmouse) struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; struct elantech_device_info *info = &etd->info; - unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0; - - if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width)) - return -1; + unsigned int x_min = info->x_min, y_min = info->y_min, + x_max = info->x_max, y_max = info->y_max, + width = info->width; __set_bit(INPUT_PROP_POINTER, dev->propbit); __set_bit(EV_KEY, dev->evbit); @@ -1689,6 +1606,7 @@ static int elantech_query_info(struct psmouse *psmouse, struct elantech_device_info *info) { unsigned char param[3]; + unsigned char traces; memset(info, 0, sizeof(*info)); @@ -1757,6 +1675,76 @@ static int elantech_query_info(struct psmouse *psmouse, } } + /* query range information */ + switch (info->hw_version) { + case 1: + info->x_min = ETP_XMIN_V1; + info->y_min = ETP_YMIN_V1; + info->x_max = ETP_XMAX_V1; + info->y_max = ETP_YMAX_V1; + break; + + case 2: + if (info->fw_version == 0x020800 || + info->fw_version == 0x020b00 || + info->fw_version == 0x020030) { + info->x_min = ETP_XMIN_V2; + info->y_min = ETP_YMIN_V2; + info->x_max = ETP_XMAX_V2; + info->y_max = ETP_YMAX_V2; + } else { + int i; + int fixed_dpi; + + i = (info->fw_version > 0x020800 && + info->fw_version < 0x020900) ? 1 : 2; + + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -EINVAL; + + fixed_dpi = param[1] & 0x10; + + if (((info->fw_version >> 16) == 0x14) && fixed_dpi) { + if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) + return -EINVAL; + + info->x_max = (info->capabilities[1] - i) * param[1] / 2; + info->y_max = (info->capabilities[2] - i) * param[2] / 2; + } else if (info->fw_version == 0x040216) { + info->x_max = 819; + info->y_max = 405; + } else if (info->fw_version == 0x040219 || info->fw_version == 0x040215) { + info->x_max = 900; + info->y_max = 500; + } else { + info->x_max = (info->capabilities[1] - i) * 64; + info->y_max = (info->capabilities[2] - i) * 64; + } + } + break; + + case 3: + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -EINVAL; + + info->x_max = (0x0f & param[0]) << 8 | param[1]; + info->y_max = (0xf0 & param[0]) << 4 | param[2]; + break; + + case 4: + if (info->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) + return -EINVAL; + + info->x_max = (0x0f & param[0]) << 8 | param[1]; + info->y_max = (0xf0 & param[0]) << 4 | param[2]; + traces = info->capabilities[1]; + if ((traces < 2) || (traces > info->x_max)) + return -EINVAL; + + info->width = info->x_max / (traces - 1); + break; + } + return 0; } diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index 119727085a60..194503ed59c5 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -144,8 +144,13 @@ struct elantech_device_info { unsigned char debug; unsigned char hw_version; unsigned int fw_version; + unsigned int x_min; + unsigned int y_min; + unsigned int x_max; + unsigned int y_max; unsigned int x_res; unsigned int y_res; + unsigned int width; unsigned int bus; bool paritycheck; bool jumpy_cursor; -- cgit v1.2.3-59-g8ed1b From 88463497dd1f64eef9f21c6bbd19acabd0d8f88e Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 27 May 2019 18:24:47 -0700 Subject: Input: elantech - add helper function elantech_is_buttonpad() We check for this bit all over the code, better have it defined once for all. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 93 ++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 44 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index b551a65b0fe0..d2829dc5999c 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -229,6 +229,52 @@ static void elantech_packet_dump(struct psmouse *psmouse) psmouse->pktsize, psmouse->packet); } +/* + * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in + * fw_version for this is based on the following fw_version & caps table: + * + * Laptop-model: fw_version: caps: buttons: + * Acer S3 0x461f00 10, 13, 0e clickpad + * Acer S7-392 0x581f01 50, 17, 0d clickpad + * Acer V5-131 0x461f02 01, 16, 0c clickpad + * Acer V5-551 0x461f00 ? clickpad + * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons + * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons + * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons + * Asus TP500LN 0x381f17 10, 14, 0e clickpad + * Asus X750JN 0x381f17 10, 14, 0e clickpad + * Asus UX31 0x361f00 20, 15, 0e clickpad + * Asus UX32VD 0x361f02 00, 15, 0e clickpad + * Avatar AVIU-145A2 0x361f00 ? clickpad + * Fujitsu CELSIUS H760 0x570f02 40, 14, 0c 3 hw buttons (**) + * Fujitsu CELSIUS H780 0x5d0f02 41, 16, 0d 3 hw buttons (**) + * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons + * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons + * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons + * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons + * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) + * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons + * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) + * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*) + * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons + * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad + * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad + * Samsung NP900X3E-A02 0x575f03 ? clickpad + * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad + * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons + * Samsung RF710 0x450f00 ? 2 hw buttons + * System76 Pangolin 0x250f01 ? 2 hw buttons + * (*) + 3 trackpoint buttons + * (**) + 0 trackpoint buttons + * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps + */ +static inline int elantech_is_buttonpad(struct elantech_device_info *info) +{ + return info->fw_version & 0x001000; +} + /* * Interpret complete data packets and report absolute mode input events for * hardware version 1. (4 byte packets) @@ -526,7 +572,7 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse, input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); /* For clickpads map both buttons to BTN_LEFT */ - if (etd->info.fw_version & 0x001000) + if (elantech_is_buttonpad(&etd->info)) input_report_key(dev, BTN_LEFT, packet[0] & 0x03); else psmouse_report_standard_buttons(dev, packet[0]); @@ -544,7 +590,7 @@ static void elantech_input_sync_v4(struct psmouse *psmouse) unsigned char *packet = psmouse->packet; /* For clickpads map both buttons to BTN_LEFT */ - if (etd->info.fw_version & 0x001000) + if (elantech_is_buttonpad(&etd->info)) input_report_key(dev, BTN_LEFT, packet[0] & 0x03); else psmouse_report_standard_buttons(dev, packet[0]); @@ -1020,53 +1066,12 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, return 0; } -/* - * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in - * fw_version for this is based on the following fw_version & caps table: - * - * Laptop-model: fw_version: caps: buttons: - * Acer S3 0x461f00 10, 13, 0e clickpad - * Acer S7-392 0x581f01 50, 17, 0d clickpad - * Acer V5-131 0x461f02 01, 16, 0c clickpad - * Acer V5-551 0x461f00 ? clickpad - * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons - * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons - * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons - * Asus TP500LN 0x381f17 10, 14, 0e clickpad - * Asus X750JN 0x381f17 10, 14, 0e clickpad - * Asus UX31 0x361f00 20, 15, 0e clickpad - * Asus UX32VD 0x361f02 00, 15, 0e clickpad - * Avatar AVIU-145A2 0x361f00 ? clickpad - * Fujitsu CELSIUS H760 0x570f02 40, 14, 0c 3 hw buttons (**) - * Fujitsu CELSIUS H780 0x5d0f02 41, 16, 0d 3 hw buttons (**) - * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons - * Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons - * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons - * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons - * Fujitsu LIFEBOOK E557 0x570f01 40, 14, 0c 2 hw buttons - * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons - * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) - * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons - * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) - * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*) - * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons - * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad - * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad - * Samsung NP900X3E-A02 0x575f03 ? clickpad - * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad - * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons - * Samsung RF710 0x450f00 ? 2 hw buttons - * System76 Pangolin 0x250f01 ? 2 hw buttons - * (*) + 3 trackpoint buttons - * (**) + 0 trackpoint buttons - * Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps - */ static void elantech_set_buttonpad_prop(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; struct elantech_data *etd = psmouse->private; - if (etd->info.fw_version & 0x001000) { + if (elantech_is_buttonpad(&etd->info)) { __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); __clear_bit(BTN_RIGHT, dev->keybit); } -- cgit v1.2.3-59-g8ed1b From fd1cf11f7130977d44fc19bf7ced63a4b6f1fc30 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 27 May 2019 18:33:33 -0700 Subject: Input: elantech - detect middle button based on firmware version Looks like the new generation of Lenovo machine also need to be added to the PnPID whitelist. This is definitively not going to scale, as there is nothing that tells us currently if a touchpad supports a true physical middle button. Consider that all new touchpads that are not clickpads (so matching ETP_NEW_IC_SMBUS_HOST_NOTIFY) are handling 3 physical buttons. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 18 ++++++------------ drivers/input/mouse/elantech.h | 1 + 2 files changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index d2829dc5999c..057a3cf01eec 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1107,16 +1107,6 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = { { } }; -static const char * const middle_button_pnp_ids[] = { - "LEN2131", /* ThinkPad P52 w/ NFC */ - "LEN2132", /* ThinkPad P52 */ - "LEN2133", /* ThinkPad P72 w/ NFC */ - "LEN2134", /* ThinkPad P72 */ - "LEN0407", - "LEN0408", - NULL -}; - /* * Set the appropriate event bits for the input subsystem */ @@ -1135,8 +1125,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) __clear_bit(EV_REL, dev->evbit); __set_bit(BTN_LEFT, dev->keybit); - if (dmi_check_system(elantech_dmi_has_middle_button) || - psmouse_matches_pnp_id(psmouse, middle_button_pnp_ids)) + if (info->has_middle_button) __set_bit(BTN_MIDDLE, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); @@ -1750,6 +1739,11 @@ static int elantech_query_info(struct psmouse *psmouse, break; } + /* check for the middle button: DMI matching or new v4 firmwares */ + info->has_middle_button = dmi_check_system(elantech_dmi_has_middle_button) || + (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version) && + !elantech_is_buttonpad(info)); + return 0; } diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index 194503ed59c5..16174b54ffc3 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -158,6 +158,7 @@ struct elantech_device_info { bool crc_enabled; bool set_hw_resolution; bool has_trackpoint; + bool has_middle_button; int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param); }; -- cgit v1.2.3-59-g8ed1b From e3a9a12906887aab3465bb34a1a5e436287b185d Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 27 May 2019 18:42:48 -0700 Subject: Input: elan_i2c - do not query the info if they are provided See the previous patch for a long explanation. TL;DR: the P52 and the t480s from Lenovo can't rely on I2C to fetch the information, so we need it from PS/2. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 56 +++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 12 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 2c0561e20b7f..3b78f58d80f5 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -366,27 +366,59 @@ static unsigned int elan_convert_resolution(u8 val) static int elan_query_device_parameters(struct elan_tp_data *data) { + struct i2c_client *client = data->client; unsigned int x_traces, y_traces; + u32 x_mm, y_mm; u8 hw_x_res, hw_y_res; int error; - error = data->ops->get_max(data->client, &data->max_x, &data->max_y); - if (error) - return error; - - error = data->ops->get_num_traces(data->client, &x_traces, &y_traces); - if (error) - return error; + if (device_property_read_u32(&client->dev, + "touchscreen-size-x", &data->max_x) || + device_property_read_u32(&client->dev, + "touchscreen-size-y", &data->max_y)) { + error = data->ops->get_max(data->client, + &data->max_x, + &data->max_y); + if (error) + return error; + } else { + /* size is the maximum + 1 */ + --data->max_x; + --data->max_y; + } + if (device_property_read_u32(&client->dev, + "elan,x_traces", + &x_traces) || + device_property_read_u32(&client->dev, + "elan,y_traces", + &y_traces)) { + error = data->ops->get_num_traces(data->client, + &x_traces, &y_traces); + if (error) + return error; + } data->width_x = data->max_x / x_traces; data->width_y = data->max_y / y_traces; - error = data->ops->get_resolution(data->client, &hw_x_res, &hw_y_res); - if (error) - return error; + if (device_property_read_u32(&client->dev, + "touchscreen-x-mm", &x_mm) || + device_property_read_u32(&client->dev, + "touchscreen-y-mm", &y_mm)) { + error = data->ops->get_resolution(data->client, + &hw_x_res, &hw_y_res); + if (error) + return error; + + data->x_res = elan_convert_resolution(hw_x_res); + data->y_res = elan_convert_resolution(hw_y_res); + } else { + data->x_res = (data->max_x + 1) / x_mm; + data->y_res = (data->max_y + 1) / y_mm; + } - data->x_res = elan_convert_resolution(hw_x_res); - data->y_res = elan_convert_resolution(hw_y_res); + if (device_property_read_bool(&client->dev, "elan,clickpad")) + data->clickpad = 1; return 0; } -- cgit v1.2.3-59-g8ed1b From 3abcc5329aecda19be1b9f91af51a257d23ccfe3 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 27 May 2019 18:43:49 -0700 Subject: Input: elantech/SMBus - export all capabilities from the PS/2 node The recent touchpads might not have all the information regarding the characteristics through the I2C port. On some Lenovo t480s, this results in the touchpad not being detected as a clickpad, and on the Lenovo P52, this results in a failure while fetching the resolution through I2C. We need to imitate the Windows behavior: fetch the data under PS/2, and limit the querries under I2C. This patch prepares this by exporting the info from PS/2. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 47 +++++++++++++++++++++++++++++++++++++----- drivers/input/mouse/elantech.h | 2 ++ 2 files changed, 44 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 057a3cf01eec..ca10fd97d9d5 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1736,6 +1736,15 @@ static int elantech_query_info(struct psmouse *psmouse, return -EINVAL; info->width = info->x_max / (traces - 1); + + /* column number of traces */ + info->x_traces = traces; + + /* row number of traces */ + traces = info->capabilities[2]; + if ((traces >= 2) && (traces <= info->y_max)) + info->y_traces = traces; + break; } @@ -1781,17 +1790,45 @@ static int elantech_create_smbus(struct psmouse *psmouse, struct elantech_device_info *info, bool leave_breadcrumbs) { - const struct property_entry i2c_properties[] = { - PROPERTY_ENTRY_BOOL("elan,trackpoint"), - { }, - }; + struct property_entry i2c_props[11] = {}; struct i2c_board_info smbus_board = { I2C_BOARD_INFO("elan_i2c", 0x15), .flags = I2C_CLIENT_HOST_NOTIFY, }; + unsigned int idx = 0; + + smbus_board.properties = i2c_props; + + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-x", + info->x_max + 1); + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-y", + info->y_max + 1); + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-x", + info->x_min); + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-min-y", + info->y_min); + if (info->x_res) + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-x-mm", + (info->x_max + 1) / info->x_res); + if (info->y_res) + i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-y-mm", + (info->y_max + 1) / info->y_res); if (info->has_trackpoint) - smbus_board.properties = i2c_properties; + i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,trackpoint"); + + if (info->has_middle_button) + i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,middle-button"); + + if (info->x_traces) + i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,x_traces", + info->x_traces); + if (info->y_traces) + i2c_props[idx++] = PROPERTY_ENTRY_U32("elan,y_traces", + info->y_traces); + + if (elantech_is_buttonpad(info)) + i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,clickpad"); return psmouse_smbus_init(psmouse, &smbus_board, NULL, 0, false, leave_breadcrumbs); diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index 16174b54ffc3..a7eaa62af6a0 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -150,6 +150,8 @@ struct elantech_device_info { unsigned int y_max; unsigned int x_res; unsigned int y_res; + unsigned int x_traces; + unsigned int y_traces; unsigned int width; unsigned int bus; bool paritycheck; -- cgit v1.2.3-59-g8ed1b From 140a79523e0a149b2501593e86fdb9cf7633b325 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 27 May 2019 18:44:40 -0700 Subject: Input: elan_i2c - handle physical middle button Some models have a middle button, we should export it as well. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 3b78f58d80f5..65cd325eabc3 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -99,6 +99,7 @@ struct elan_tp_data { u8 max_baseline; bool baseline_ready; u8 clickpad; + bool middle_button; }; static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count, @@ -420,6 +421,9 @@ static int elan_query_device_parameters(struct elan_tp_data *data) if (device_property_read_bool(&client->dev, "elan,clickpad")) data->clickpad = 1; + if (device_property_read_bool(&client->dev, "elan,middle-button")) + data->middle_button = true; + return 0; } @@ -958,8 +962,9 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet) finger_data += ETP_FINGER_DATA_LEN; } - input_report_key(input, BTN_LEFT, tp_info & 0x01); - input_report_key(input, BTN_RIGHT, tp_info & 0x02); + input_report_key(input, BTN_LEFT, tp_info & BIT(0)); + input_report_key(input, BTN_MIDDLE, tp_info & BIT(2)); + input_report_key(input, BTN_RIGHT, tp_info & BIT(1)); input_report_abs(input, ABS_DISTANCE, hover_event != 0); input_mt_report_pointer_emulation(input, true); input_sync(input); @@ -1093,10 +1098,13 @@ static int elan_setup_input_device(struct elan_tp_data *data) __set_bit(EV_ABS, input->evbit); __set_bit(INPUT_PROP_POINTER, input->propbit); - if (data->clickpad) + if (data->clickpad) { __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); - else + } else { __set_bit(BTN_RIGHT, input->keybit); + if (data->middle_button) + __set_bit(BTN_MIDDLE, input->keybit); + } __set_bit(BTN_LEFT, input->keybit); /* Set up ST parameters */ -- cgit v1.2.3-59-g8ed1b From 66f4c7765ad336c49243a4fd78de502fba5e9188 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 27 May 2019 18:45:29 -0700 Subject: Input: elantech - remove P52 and P72 from SMBus blacklist Both now works correctly over SMBus. Let's use this driver so we can update all five fingers every 8ms. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index ca10fd97d9d5..ea1ee0f44a65 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1779,10 +1779,6 @@ static const char * const i2c_blacklist_pnp_ids[] = { * These are known to not be working properly as bits are missing * in elan_i2c. */ - "LEN2131", /* ThinkPad P52 w/ NFC */ - "LEN2132", /* ThinkPad P52 */ - "LEN2133", /* ThinkPad P72 w/ NFC */ - "LEN2134", /* ThinkPad P72 */ NULL }; -- cgit v1.2.3-59-g8ed1b From b89a9f2f709a6ebeafb31069d87a1248022fc396 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sun, 26 May 2019 09:17:45 -0700 Subject: Input: synaptics-rmi4 - remove set but not used variable 'sensor_flags' Fixes gcc '-Wunused-but-set-variable' warning: drivers/input/rmi4/rmi_f12.c: In function rmi_f12_read_sensor_tuning: drivers/input/rmi4/rmi_f12.c:76:6: warning: variable sensor_flags set but not used [-Wunused-but-set-variable] It's not used since introduction in commit b43d2c1e9353 ("Input: synaptics-rmi4 - add support for F12") Signed-off-by: YueHaibing Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f12.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 5c7f48915779..3b7d7b940cab 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -73,7 +73,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) int pitch_y = 0; int rx_receivers = 0; int tx_receivers = 0; - int sensor_flags = 0; item = rmi_get_register_desc_item(&f12->control_reg_desc, 8); if (!item) { @@ -129,10 +128,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) offset += 2; } - if (rmi_register_desc_has_subpacket(item, 4)) { - sensor_flags = buf[offset]; + /* Skip over sensor flags */ + if (rmi_register_desc_has_subpacket(item, 4)) offset += 1; - } sensor->x_mm = (pitch_x * rx_receivers) >> 12; sensor->y_mm = (pitch_y * tx_receivers) >> 12; -- cgit v1.2.3-59-g8ed1b From b02f6b6b711b13f609e73ebb01b516cf080d9a0f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sun, 26 May 2019 09:19:02 -0700 Subject: Input: tca8418 - remove set but not used variable 'max_keys' Fixes gcc '-Wunused-but-set-variable' warning: drivers/input/keyboard/tca8418_keypad.c: In function tca8418_keypad_probe: drivers/input/keyboard/tca8418_keypad.c:269:24: warning: variable max_keys set but not used [-Wunused-but-set-variable] It's not used since commit 16ff7cb1848a ("Input: tca8418-keypad - switch to using managed resources") Signed-off-by: YueHaibing Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca8418_keypad.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 6da607d3b811..3bbd7e652533 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -266,7 +266,7 @@ static int tca8418_keypad_probe(struct i2c_client *client, struct tca8418_keypad *keypad_data; struct input_dev *input; u32 rows = 0, cols = 0; - int error, row_shift, max_keys; + int error, row_shift; u8 reg; /* Check i2c driver capabilities */ @@ -291,7 +291,6 @@ static int tca8418_keypad_probe(struct i2c_client *client, } row_shift = get_count_order(cols); - max_keys = rows << row_shift; /* Allocate memory for keypad_data and input device */ keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL); -- cgit v1.2.3-59-g8ed1b From 3d4149ec87fdab5006cb94f8ebe4720b1ee7e564 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sat, 22 Jun 2019 23:33:21 -0700 Subject: Input: gpio_keys_polled - use struct_size() in devm_kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct gpio_keys_polled_dev { ... struct gpio_keys_button_data data[0]; }; size = sizeof(struct gpio_keys_polled_dev) + count * sizeof(struct gpio_keys_button_data); instance = devm_kzalloc(dev, size, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = devm_kzalloc(dev, struct_size(instance, data, count), GFP_KERNEL); Notice that, in this case, variable size is not necessary, hence it is removed. This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys_polled.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index edc7262103b9..c4087be0c2e0 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -235,7 +235,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) struct gpio_keys_polled_dev *bdev; struct input_polled_dev *poll_dev; struct input_dev *input; - size_t size; int error; int i; @@ -250,9 +249,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) return -EINVAL; } - size = sizeof(struct gpio_keys_polled_dev) + - pdata->nbuttons * sizeof(struct gpio_keys_button_data); - bdev = devm_kzalloc(dev, size, GFP_KERNEL); + bdev = devm_kzalloc(dev, struct_size(bdev, data, pdata->nbuttons), + GFP_KERNEL); if (!bdev) { dev_err(dev, "no memory for private data\n"); return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 002cdb95dc398919bd37d3228c677a22c5ca1498 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 18 Jun 2019 17:17:13 -0700 Subject: Input: gpio_keys - use struct_size() in devm_kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct gpio_keys_drvdata { ... struct gpio_button_data data[0]; }; size = sizeof(struct gpio_keys_drvdata) + count * sizeof(struct gpio_button_data); instance = devm_kzalloc(dev, size, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = devm_kzalloc(dev, struct_size(instance, data, count), GFP_KERNEL); Notice that, in this case, variable size is not necessary, hence it is removed. This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 6cd199e8a370..c186c2552b04 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -774,7 +774,6 @@ static int gpio_keys_probe(struct platform_device *pdev) struct fwnode_handle *child = NULL; struct gpio_keys_drvdata *ddata; struct input_dev *input; - size_t size; int i, error; int wakeup = 0; @@ -784,9 +783,8 @@ static int gpio_keys_probe(struct platform_device *pdev) return PTR_ERR(pdata); } - size = sizeof(struct gpio_keys_drvdata) + - pdata->nbuttons * sizeof(struct gpio_button_data); - ddata = devm_kzalloc(dev, size, GFP_KERNEL); + ddata = devm_kzalloc(dev, struct_size(ddata, data, pdata->nbuttons), + GFP_KERNEL); if (!ddata) { dev_err(dev, "failed to allocate state\n"); return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From f7f3651e0887f536a6854dfcae0c21fc5463b733 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 24 Jul 2018 17:18:27 -0700 Subject: Input: iforce - remove "being used" silliness The kernel is supposed to handle multiple devices, static flags in packet handling code will never work. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-packets.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index c10169f4554e..91893c751524 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -149,12 +149,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) { struct input_dev *dev = iforce->dev; int i; - static int being_used = 0; - - if (being_used) - dev_warn(&iforce->dev->dev, - "re-entrant call to iforce_process %d\n", being_used); - being_used++; #ifdef CONFIG_JOYSTICK_IFORCE_232 if (HI(iforce->expect_packet) == HI(cmd)) { @@ -165,10 +159,8 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) #endif wake_up(&iforce->wait); - if (!iforce->type) { - being_used--; + if (!iforce->type) return; - } switch (HI(cmd)) { @@ -233,7 +225,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) } break; } - being_used--; } int iforce_get_id_packet(struct iforce *iforce, char *packet) -- cgit v1.2.3-59-g8ed1b From 38d107690df7f0826adb5b53f4e87676859ff0a6 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 26 Jul 2018 17:36:36 -0700 Subject: Input: iforce - introduce transport ops In order to tease apart the driver into core and transport modules, let's introduce transport operations and make "xmit" the very first one such operation. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-packets.c | 20 ++------------------ drivers/input/joystick/iforce/iforce-serio.c | 9 +++++++-- drivers/input/joystick/iforce/iforce-usb.c | 15 +++++++++++++-- drivers/input/joystick/iforce/iforce.h | 13 +++++++------ 4 files changed, 29 insertions(+), 28 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 91893c751524..b8ca9bdfdef8 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -91,25 +91,9 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) /* * If necessary, start the transmission */ - switch (iforce->bus) { - -#ifdef CONFIG_JOYSTICK_IFORCE_232 - case IFORCE_232: - if (empty) - iforce_serial_xmit(iforce); - break; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: + if (empty) + iforce->xport_ops->xmit(iforce); - if (iforce->usbdev && empty && - !test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { - - iforce_usb_xmit(iforce); - } - break; -#endif - } return 0; } diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index f4ba4a751fe0..c9469209f994 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -23,7 +23,7 @@ #include "iforce.h" -void iforce_serial_xmit(struct iforce *iforce) +static void iforce_serio_xmit(struct iforce *iforce) { unsigned char cs; int i; @@ -67,11 +67,15 @@ again: spin_unlock_irqrestore(&iforce->xmit_lock, flags); } +static const struct iforce_xport_ops iforce_serio_xport_ops = { + .xmit = iforce_serio_xmit, +}; + static void iforce_serio_write_wakeup(struct serio *serio) { struct iforce *iforce = serio_get_drvdata(serio); - iforce_serial_xmit(iforce); + iforce_serio_xmit(iforce); } static irqreturn_t iforce_serio_irq(struct serio *serio, @@ -129,6 +133,7 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) if (!iforce) return -ENOMEM; + iforce->xport_ops = &iforce_serio_xport_ops; iforce->bus = IFORCE_232; iforce->serio = serio; diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 78073259c9a1..d4f7f34db9a0 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -23,7 +23,7 @@ #include "iforce.h" -void iforce_usb_xmit(struct iforce *iforce) +static void __iforce_usb_xmit(struct iforce *iforce) { int n, c; unsigned long flags; @@ -69,6 +69,16 @@ void iforce_usb_xmit(struct iforce *iforce) spin_unlock_irqrestore(&iforce->xmit_lock, flags); } +static void iforce_usb_xmit(struct iforce *iforce) +{ + if (!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) + __iforce_usb_xmit(iforce); +} + +static const struct iforce_xport_ops iforce_usb_xport_ops = { + .xmit = iforce_usb_xmit, +}; + static void iforce_usb_irq(struct urb *urb) { struct iforce *iforce = urb->context; @@ -113,7 +123,7 @@ static void iforce_usb_out(struct urb *urb) return; } - iforce_usb_xmit(iforce); + __iforce_usb_xmit(iforce); wake_up(&iforce->wait); } @@ -155,6 +165,7 @@ static int iforce_usb_probe(struct usb_interface *intf, if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) goto fail; + iforce->xport_ops = &iforce_usb_xport_ops; iforce->bus = IFORCE_USB; iforce->usbdev = dev; iforce->intf = intf; diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index 0e9d01f8bcb6..2fea3be751ed 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -93,9 +93,16 @@ struct iforce_device { signed short *ff; }; +struct iforce; + +struct iforce_xport_ops { + void (*xmit)(struct iforce *iforce); +}; + struct iforce { struct input_dev *dev; /* Input device interface */ struct iforce_device *type; + const struct iforce_xport_ops *xport_ops; int bus; unsigned char data[IFORCE_MAX_LENGTH]; @@ -141,12 +148,6 @@ struct iforce { /* Public functions */ -/* iforce-serio.c */ -void iforce_serial_xmit(struct iforce *iforce); - -/* iforce-usb.c */ -void iforce_usb_xmit(struct iforce *iforce); - /* iforce-main.c */ int iforce_init_device(struct iforce *iforce); -- cgit v1.2.3-59-g8ed1b From 2a1433ff08a1b23e3003483ee2883d327f78db9e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 26 Jul 2018 17:49:34 -0700 Subject: Input: iforce - move get_id to the transport operations To avoid #ifdef-ing out parts of the code and having conditionals in normal control flow, let's define "get_id" transport method and move implementation into respective transport modules. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-packets.c | 64 -------------------------- drivers/input/joystick/iforce/iforce-serio.c | 17 +++++++ drivers/input/joystick/iforce/iforce-usb.c | 29 ++++++++++++ drivers/input/joystick/iforce/iforce.h | 6 ++- 4 files changed, 51 insertions(+), 65 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index b8ca9bdfdef8..e677562efc9a 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -210,67 +210,3 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) break; } } - -int iforce_get_id_packet(struct iforce *iforce, char *packet) -{ - switch (iforce->bus) { - - case IFORCE_USB: { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - int status; - - iforce->cr.bRequest = packet[0]; - iforce->ctrl->dev = iforce->usbdev; - - status = usb_submit_urb(iforce->ctrl, GFP_KERNEL); - if (status) { - dev_err(&iforce->intf->dev, - "usb_submit_urb failed %d\n", status); - return -1; - } - - wait_event_interruptible_timeout(iforce->wait, - iforce->ctrl->status != -EINPROGRESS, HZ); - - if (iforce->ctrl->status) { - dev_dbg(&iforce->intf->dev, - "iforce->ctrl->status = %d\n", - iforce->ctrl->status); - usb_unlink_urb(iforce->ctrl); - return -1; - } -#else - printk(KERN_DEBUG "iforce_get_id_packet: iforce->bus = USB!\n"); -#endif - } - break; - - case IFORCE_232: - -#ifdef CONFIG_JOYSTICK_IFORCE_232 - iforce->expect_packet = FF_CMD_QUERY; - iforce_send_packet(iforce, FF_CMD_QUERY, packet); - - wait_event_interruptible_timeout(iforce->wait, - !iforce->expect_packet, HZ); - - if (iforce->expect_packet) { - iforce->expect_packet = 0; - return -1; - } -#else - dev_err(&iforce->dev->dev, - "iforce_get_id_packet: iforce->bus = SERIO!\n"); -#endif - break; - - default: - dev_err(&iforce->dev->dev, - "iforce_get_id_packet: iforce->bus = %d\n", - iforce->bus); - break; - } - - return -(iforce->edata[0] != packet[0]); -} - diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index c9469209f994..fa45ce425d47 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -67,8 +67,25 @@ again: spin_unlock_irqrestore(&iforce->xmit_lock, flags); } +static int iforce_serio_get_id(struct iforce *iforce, u8 *packet) +{ + iforce->expect_packet = FF_CMD_QUERY; + iforce_send_packet(iforce, FF_CMD_QUERY, packet); + + wait_event_interruptible_timeout(iforce->wait, + !iforce->expect_packet, HZ); + + if (iforce->expect_packet) { + iforce->expect_packet = 0; + return -EIO; + } + + return -(iforce->edata[0] != packet[0]); +} + static const struct iforce_xport_ops iforce_serio_xport_ops = { .xmit = iforce_serio_xmit, + .get_id = iforce_serio_get_id, }; static void iforce_serio_write_wakeup(struct serio *serio) diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index d4f7f34db9a0..f7eeaad92602 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -75,8 +75,37 @@ static void iforce_usb_xmit(struct iforce *iforce) __iforce_usb_xmit(iforce); } +static int iforce_usb_get_id(struct iforce *iforce, u8 *packet) +{ + int status; + + iforce->cr.bRequest = packet[0]; + iforce->ctrl->dev = iforce->usbdev; + + status = usb_submit_urb(iforce->ctrl, GFP_KERNEL); + if (status) { + dev_err(&iforce->intf->dev, + "usb_submit_urb failed %d\n", status); + return -EIO; + } + + wait_event_interruptible_timeout(iforce->wait, + iforce->ctrl->status != -EINPROGRESS, HZ); + + if (iforce->ctrl->status) { + dev_dbg(&iforce->intf->dev, + "iforce->ctrl->status = %d\n", + iforce->ctrl->status); + usb_unlink_urb(iforce->ctrl); + return -EIO; + } + + return -(iforce->edata[0] != packet[0]); +} + static const struct iforce_xport_ops iforce_usb_xport_ops = { .xmit = iforce_usb_xmit, + .get_id = iforce_usb_get_id, }; static void iforce_usb_irq(struct urb *urb) diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index 2fea3be751ed..f6636230be31 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -97,6 +97,7 @@ struct iforce; struct iforce_xport_ops { void (*xmit)(struct iforce *iforce); + int (*get_id)(struct iforce *iforce, u8* id); }; struct iforce { @@ -146,6 +147,10 @@ struct iforce { /* Encode a time value */ #define TIME_SCALE(a) (a) +static inline int iforce_get_id_packet(struct iforce *iforce, u8* id) +{ + return iforce->xport_ops->get_id(iforce, id); +} /* Public functions */ /* iforce-main.c */ @@ -156,7 +161,6 @@ int iforce_control_playback(struct iforce*, u16 id, unsigned int); void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data); int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); void iforce_dump_packet(struct iforce *iforce, char *msg, u16 cmd, unsigned char *data); -int iforce_get_id_packet(struct iforce *iforce, char *packet); /* iforce-ff.c */ int iforce_upload_periodic(struct iforce *, struct ff_effect *, struct ff_effect *); -- cgit v1.2.3-59-g8ed1b From 9381758466f9939d84f6f70097c8883da9639379 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 3 Aug 2018 15:23:40 -0700 Subject: Input: iforce - move command completion handling to serio code Continue teasing apart protocol-specific bits from core into transport modules. This time move RS232-specific command completion handling from core to iforce-serio module. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-packets.c | 7 ------- drivers/input/joystick/iforce/iforce-serio.c | 12 +++++++++++- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index e677562efc9a..8a9a152bb595 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -134,13 +134,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) struct input_dev *dev = iforce->dev; int i; -#ifdef CONFIG_JOYSTICK_IFORCE_232 - if (HI(iforce->expect_packet) == HI(cmd)) { - iforce->expect_packet = 0; - iforce->ecmd = cmd; - memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); - } -#endif wake_up(&iforce->wait); if (!iforce->type) diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index fa45ce425d47..eca2f6eca7f0 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -130,7 +130,17 @@ static irqreturn_t iforce_serio_irq(struct serio *serio, } if (iforce->idx == iforce->len) { - iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); + u16 cmd = (iforce->id << 8) | iforce->idx; + + /* Handle command completion */ + if (HI(iforce->expect_packet) == HI(cmd)) { + iforce->expect_packet = 0; + iforce->ecmd = cmd; + memcpy(iforce->edata, iforce->data, IFORCE_MAX_LENGTH); + } + + iforce_process_packet(iforce, cmd, iforce->data); + iforce->pkt = 0; iforce->id = 0; iforce->len = 0; -- cgit v1.2.3-59-g8ed1b From 05ca38283afa5ad11de88395cf0b28c192766bc1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 3 Aug 2018 15:26:00 -0700 Subject: Input: iforce - introduce start and stop io transport ops Add start_io() and stop_io() transport methods so that core does not have to know the details. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-main.c | 25 ++----------------------- drivers/input/joystick/iforce/iforce-serio.c | 13 +++++++++++++ drivers/input/joystick/iforce/iforce-usb.c | 17 +++++++++++++++++ drivers/input/joystick/iforce/iforce.h | 2 ++ 4 files changed, 34 insertions(+), 23 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 58d5cfe46526..4401ca4a4c38 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -185,15 +185,7 @@ static int iforce_open(struct input_dev *dev) { struct iforce *iforce = input_get_drvdata(dev); - switch (iforce->bus) { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: - iforce->irq->dev = iforce->usbdev; - if (usb_submit_urb(iforce->irq, GFP_KERNEL)) - return -EIO; - break; -#endif - } + iforce->xport_ops->start_io(iforce); if (test_bit(EV_FF, dev->evbit)) { /* Enable force feedback */ @@ -226,20 +218,7 @@ static void iforce_close(struct input_dev *dev) !test_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)); } - switch (iforce->bus) { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: - usb_kill_urb(iforce->irq); - usb_kill_urb(iforce->out); - usb_kill_urb(iforce->ctrl); - break; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - case IFORCE_232: - //TODO: Wait for the last packets to be sent - break; -#endif - } + iforce->xport_ops->stop_io(iforce); } int iforce_init_device(struct iforce *iforce) diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index eca2f6eca7f0..afc7521b430d 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -83,9 +83,22 @@ static int iforce_serio_get_id(struct iforce *iforce, u8 *packet) return -(iforce->edata[0] != packet[0]); } +static int iforce_serio_start_io(struct iforce *iforce) +{ + /* No special handling required */ + return 0; +} + +static void iforce_serio_stop_io(struct iforce *iforce) +{ + //TODO: Wait for the last packets to be sent +} + static const struct iforce_xport_ops iforce_serio_xport_ops = { .xmit = iforce_serio_xmit, .get_id = iforce_serio_get_id, + .start_io = iforce_serio_start_io, + .stop_io = iforce_serio_stop_io, }; static void iforce_serio_write_wakeup(struct serio *serio) diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index f7eeaad92602..10b583b5fc82 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -103,9 +103,26 @@ static int iforce_usb_get_id(struct iforce *iforce, u8 *packet) return -(iforce->edata[0] != packet[0]); } +static int iforce_usb_start_io(struct iforce *iforce) +{ + if (usb_submit_urb(iforce->irq, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void iforce_usb_stop_io(struct iforce *iforce) +{ + usb_kill_urb(iforce->irq); + usb_kill_urb(iforce->out); + usb_kill_urb(iforce->ctrl); +} + static const struct iforce_xport_ops iforce_usb_xport_ops = { .xmit = iforce_usb_xmit, .get_id = iforce_usb_get_id, + .start_io = iforce_usb_start_io, + .stop_io = iforce_usb_stop_io, }; static void iforce_usb_irq(struct urb *urb) diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index f6636230be31..c020d61eccf2 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -98,6 +98,8 @@ struct iforce; struct iforce_xport_ops { void (*xmit)(struct iforce *iforce); int (*get_id)(struct iforce *iforce, u8* id); + int (*start_io)(struct iforce *iforce); + void (*stop_io)(struct iforce *iforce); }; struct iforce { -- cgit v1.2.3-59-g8ed1b From 501025df2e774ea840276e08d2a0aead606ffa52 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 3 Aug 2018 15:34:41 -0700 Subject: Input: iforce - add bus type and parent arguments to iforce_init_device() Note that the parent device for the USB-connected controllers is now USB interface instead of USB device. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-main.c | 19 ++++--------------- drivers/input/joystick/iforce/iforce-serio.c | 2 +- drivers/input/joystick/iforce/iforce-usb.c | 2 +- drivers/input/joystick/iforce/iforce.h | 3 ++- 4 files changed, 8 insertions(+), 18 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 4401ca4a4c38..894769d03df3 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -221,7 +221,8 @@ static void iforce_close(struct input_dev *dev) iforce->xport_ops->stop_io(iforce); } -int iforce_init_device(struct iforce *iforce) +int iforce_init_device(struct device *parent, u16 bustype, + struct iforce *iforce) { struct input_dev *input_dev; struct ff_device *ff; @@ -243,20 +244,8 @@ int iforce_init_device(struct iforce *iforce) * Input device fields. */ - switch (iforce->bus) { -#ifdef CONFIG_JOYSTICK_IFORCE_USB - case IFORCE_USB: - input_dev->id.bustype = BUS_USB; - input_dev->dev.parent = &iforce->usbdev->dev; - break; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - case IFORCE_232: - input_dev->id.bustype = BUS_RS232; - input_dev->dev.parent = &iforce->serio->dev; - break; -#endif - } + input_dev->id.bustype = bustype; + input_dev->dev.parent = parent; input_set_drvdata(input_dev, iforce); diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index afc7521b430d..b5dea273f98e 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -183,7 +183,7 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) if (err) goto fail1; - err = iforce_init_device(iforce); + err = iforce_init_device(&serio->dev, BUS_RS232, iforce); if (err) goto fail2; diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 10b583b5fc82..824df4273774 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -229,7 +229,7 @@ static int iforce_usb_probe(struct usb_interface *intf, usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce); - err = iforce_init_device(iforce); + err = iforce_init_device(&intf->dev, BUS_USB, iforce); if (err) goto fail; diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index c020d61eccf2..3ee9245a415b 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -156,7 +156,8 @@ static inline int iforce_get_id_packet(struct iforce *iforce, u8* id) /* Public functions */ /* iforce-main.c */ -int iforce_init_device(struct iforce *iforce); +int iforce_init_device(struct device *parent, u16 bustype, + struct iforce *iforce); /* iforce-packets.c */ int iforce_control_playback(struct iforce*, u16 id, unsigned int); -- cgit v1.2.3-59-g8ed1b From 81fd43132684605b21600fa5e27f23034e18dfd3 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 3 Aug 2018 16:27:45 -0700 Subject: Input: iforce - move transport data into transport modules This moves transport-specific data from main iforce structure into transport modules. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-serio.c | 96 ++++++++++++------- drivers/input/joystick/iforce/iforce-usb.c | 138 ++++++++++++++++----------- drivers/input/joystick/iforce/iforce.h | 14 +-- 3 files changed, 144 insertions(+), 104 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index b5dea273f98e..6ff1bbeeb494 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -23,8 +23,20 @@ #include "iforce.h" +struct iforce_serio { + struct iforce iforce; + + struct serio *serio; + int idx, pkt, len, id; + u8 csum; + u8 expect_packet; +}; + static void iforce_serio_xmit(struct iforce *iforce) { + struct iforce_serio *iforce_serio = container_of(iforce, + struct iforce_serio, + iforce); unsigned char cs; int i; unsigned long flags; @@ -45,19 +57,20 @@ again: cs = 0x2b; - serio_write(iforce->serio, 0x2b); + serio_write(iforce_serio->serio, 0x2b); - serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]); cs ^= iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { - serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + serio_write(iforce_serio->serio, + iforce->xmit.buf[iforce->xmit.tail]); cs ^= iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); } - serio_write(iforce->serio, cs); + serio_write(iforce_serio->serio, cs); if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) goto again; @@ -69,14 +82,18 @@ again: static int iforce_serio_get_id(struct iforce *iforce, u8 *packet) { - iforce->expect_packet = FF_CMD_QUERY; + struct iforce_serio *iforce_serio = container_of(iforce, + struct iforce_serio, + iforce); + + iforce_serio->expect_packet = HI(FF_CMD_QUERY); iforce_send_packet(iforce, FF_CMD_QUERY, packet); wait_event_interruptible_timeout(iforce->wait, - !iforce->expect_packet, HZ); + !iforce_serio->expect_packet, HZ); - if (iforce->expect_packet) { - iforce->expect_packet = 0; + if (iforce_serio->expect_packet) { + iforce_serio->expect_packet = 0; return -EIO; } @@ -111,54 +128,56 @@ static void iforce_serio_write_wakeup(struct serio *serio) static irqreturn_t iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) { - struct iforce *iforce = serio_get_drvdata(serio); + struct iforce_serio *iforce_serio = serio_get_drvdata(serio); + struct iforce *iforce = &iforce_serio->iforce; - if (!iforce->pkt) { + if (!iforce_serio->pkt) { if (data == 0x2b) - iforce->pkt = 1; + iforce_serio->pkt = 1; goto out; } - if (!iforce->id) { + if (!iforce_serio->id) { if (data > 3 && data != 0xff) - iforce->pkt = 0; + iforce_serio->pkt = 0; else - iforce->id = data; + iforce_serio->id = data; goto out; } - if (!iforce->len) { + if (!iforce_serio->len) { if (data > IFORCE_MAX_LENGTH) { - iforce->pkt = 0; - iforce->id = 0; + iforce_serio->pkt = 0; + iforce_serio->id = 0; } else { - iforce->len = data; + iforce_serio->len = data; } goto out; } - if (iforce->idx < iforce->len) { - iforce->csum += iforce->data[iforce->idx++] = data; + if (iforce_serio->idx < iforce_serio->len) { + iforce->data[iforce_serio->idx++] = data; + iforce_serio->csum += data; goto out; } - if (iforce->idx == iforce->len) { - u16 cmd = (iforce->id << 8) | iforce->idx; + if (iforce_serio->idx == iforce_serio->len) { + u16 cmd = (iforce_serio->id << 8) | iforce_serio->idx; /* Handle command completion */ - if (HI(iforce->expect_packet) == HI(cmd)) { - iforce->expect_packet = 0; + if (iforce_serio->expect_packet == iforce_serio->id) { + iforce_serio->expect_packet = 0; iforce->ecmd = cmd; memcpy(iforce->edata, iforce->data, IFORCE_MAX_LENGTH); } iforce_process_packet(iforce, cmd, iforce->data); - iforce->pkt = 0; - iforce->id = 0; - iforce->len = 0; - iforce->idx = 0; - iforce->csum = 0; + iforce_serio->pkt = 0; + iforce_serio->id = 0; + iforce_serio->len = 0; + iforce_serio->idx = 0; + iforce_serio->csum = 0; } out: return IRQ_HANDLED; @@ -166,18 +185,21 @@ out: static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) { + struct iforce_serio *iforce_serio; struct iforce *iforce; int err; - iforce = kzalloc(sizeof(struct iforce), GFP_KERNEL); - if (!iforce) + iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL); + if (!iforce_serio) return -ENOMEM; + iforce = &iforce_serio->iforce; + iforce->xport_ops = &iforce_serio_xport_ops; iforce->bus = IFORCE_232; - iforce->serio = serio; - serio_set_drvdata(serio, iforce); + iforce_serio->serio = serio; + serio_set_drvdata(serio, iforce_serio); err = serio_open(serio, drv); if (err) @@ -191,18 +213,18 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) fail2: serio_close(serio); fail1: serio_set_drvdata(serio, NULL); - kfree(iforce); + kfree(iforce_serio); return err; } static void iforce_serio_disconnect(struct serio *serio) { - struct iforce *iforce = serio_get_drvdata(serio); + struct iforce_serio *iforce_serio = serio_get_drvdata(serio); - input_unregister_device(iforce->dev); + input_unregister_device(iforce_serio->iforce.dev); serio_close(serio); serio_set_drvdata(serio, NULL); - kfree(iforce); + kfree(iforce_serio); } static const struct serio_device_id iforce_serio_ids[] = { diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 824df4273774..d4e7a24922cd 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -23,8 +23,19 @@ #include "iforce.h" +struct iforce_usb { + struct iforce iforce; + + struct usb_device *usbdev; + struct usb_interface *intf; + struct urb *irq, *out, *ctrl; + struct usb_ctrlrequest cr; +}; + static void __iforce_usb_xmit(struct iforce *iforce) { + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); int n, c; unsigned long flags; @@ -36,31 +47,32 @@ static void __iforce_usb_xmit(struct iforce *iforce) return; } - ((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; + ((char *)iforce_usb->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); n = iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); - iforce->out->transfer_buffer_length = n + 1; - iforce->out->dev = iforce->usbdev; + iforce_usb->out->transfer_buffer_length = n + 1; + iforce_usb->out->dev = iforce_usb->usbdev; /* Copy rest of data then */ c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE); if (n < c) c=n; - memcpy(iforce->out->transfer_buffer + 1, + memcpy(iforce_usb->out->transfer_buffer + 1, &iforce->xmit.buf[iforce->xmit.tail], c); if (n != c) { - memcpy(iforce->out->transfer_buffer + 1 + c, + memcpy(iforce_usb->out->transfer_buffer + 1 + c, &iforce->xmit.buf[0], n-c); } XMIT_INC(iforce->xmit.tail, n); - if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) { + if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) { clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); - dev_warn(&iforce->intf->dev, "usb_submit_urb failed %d\n", n); + dev_warn(&iforce_usb->intf->dev, + "usb_submit_urb failed %d\n", n); } /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended. @@ -77,26 +89,28 @@ static void iforce_usb_xmit(struct iforce *iforce) static int iforce_usb_get_id(struct iforce *iforce, u8 *packet) { + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); int status; - iforce->cr.bRequest = packet[0]; - iforce->ctrl->dev = iforce->usbdev; + iforce_usb->cr.bRequest = packet[0]; + iforce_usb->ctrl->dev = iforce_usb->usbdev; - status = usb_submit_urb(iforce->ctrl, GFP_KERNEL); + status = usb_submit_urb(iforce_usb->ctrl, GFP_KERNEL); if (status) { - dev_err(&iforce->intf->dev, + dev_err(&iforce_usb->intf->dev, "usb_submit_urb failed %d\n", status); return -EIO; } wait_event_interruptible_timeout(iforce->wait, - iforce->ctrl->status != -EINPROGRESS, HZ); + iforce_usb->ctrl->status != -EINPROGRESS, HZ); - if (iforce->ctrl->status) { - dev_dbg(&iforce->intf->dev, + if (iforce_usb->ctrl->status) { + dev_dbg(&iforce_usb->intf->dev, "iforce->ctrl->status = %d\n", - iforce->ctrl->status); - usb_unlink_urb(iforce->ctrl); + iforce_usb->ctrl->status); + usb_unlink_urb(iforce_usb->ctrl); return -EIO; } @@ -105,7 +119,10 @@ static int iforce_usb_get_id(struct iforce *iforce, u8 *packet) static int iforce_usb_start_io(struct iforce *iforce) { - if (usb_submit_urb(iforce->irq, GFP_KERNEL)) + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); + + if (usb_submit_urb(iforce_usb->irq, GFP_KERNEL)) return -EIO; return 0; @@ -113,9 +130,12 @@ static int iforce_usb_start_io(struct iforce *iforce) static void iforce_usb_stop_io(struct iforce *iforce) { - usb_kill_urb(iforce->irq); - usb_kill_urb(iforce->out); - usb_kill_urb(iforce->ctrl); + struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, + iforce); + + usb_kill_urb(iforce_usb->irq); + usb_kill_urb(iforce_usb->out); + usb_kill_urb(iforce_usb->ctrl); } static const struct iforce_xport_ops iforce_usb_xport_ops = { @@ -127,8 +147,9 @@ static const struct iforce_xport_ops iforce_usb_xport_ops = { static void iforce_usb_irq(struct urb *urb) { - struct iforce *iforce = urb->context; - struct device *dev = &iforce->intf->dev; + struct iforce_usb *iforce_usb = urb->context; + struct iforce *iforce = &iforce_usb->iforce; + struct device *dev = &iforce_usb->intf->dev; int status; switch (urb->status) { @@ -152,7 +173,7 @@ static void iforce_usb_irq(struct urb *urb) (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); exit: - status = usb_submit_urb (urb, GFP_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, status); @@ -160,11 +181,12 @@ exit: static void iforce_usb_out(struct urb *urb) { - struct iforce *iforce = urb->context; + struct iforce_usb *iforce_usb = urb->context; + struct iforce *iforce = &iforce_usb->iforce; if (urb->status) { clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); - dev_dbg(&iforce->intf->dev, "urb->status %d, exiting\n", + dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n", urb->status); return; } @@ -176,8 +198,12 @@ static void iforce_usb_out(struct urb *urb) static void iforce_usb_ctrl(struct urb *urb) { - struct iforce *iforce = urb->context; - if (urb->status) return; + struct iforce_usb *iforce_usb = urb->context; + struct iforce *iforce = &iforce_usb->iforce; + + if (urb->status) + return; + iforce->ecmd = 0xff00 | urb->actual_length; wake_up(&iforce->wait); } @@ -188,6 +214,7 @@ static int iforce_usb_probe(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface; struct usb_endpoint_descriptor *epirq, *epout; + struct iforce_usb *iforce_usb; struct iforce *iforce; int err = -ENOMEM; @@ -199,49 +226,52 @@ static int iforce_usb_probe(struct usb_interface *intf, epirq = &interface->endpoint[0].desc; epout = &interface->endpoint[1].desc; - if (!(iforce = kzalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) + if (!(iforce_usb = kzalloc(sizeof(*iforce_usb) + 32, GFP_KERNEL))) goto fail; - if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) + if (!(iforce_usb->irq = usb_alloc_urb(0, GFP_KERNEL))) goto fail; - if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) + if (!(iforce_usb->out = usb_alloc_urb(0, GFP_KERNEL))) goto fail; - if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) + if (!(iforce_usb->ctrl = usb_alloc_urb(0, GFP_KERNEL))) goto fail; + iforce = &iforce_usb->iforce; + iforce->xport_ops = &iforce_usb_xport_ops; iforce->bus = IFORCE_USB; - iforce->usbdev = dev; - iforce->intf = intf; - iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; - iforce->cr.wIndex = 0; - iforce->cr.wLength = cpu_to_le16(16); + iforce_usb->usbdev = dev; + iforce_usb->intf = intf; + + iforce_usb->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; + iforce_usb->cr.wIndex = 0; + iforce_usb->cr.wLength = cpu_to_le16(16); - usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), - iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); + usb_fill_int_urb(iforce_usb->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), + iforce->data, 16, iforce_usb_irq, iforce_usb, epirq->bInterval); - usb_fill_int_urb(iforce->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress), - iforce + 1, 32, iforce_usb_out, iforce, epout->bInterval); + usb_fill_int_urb(iforce_usb->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress), + iforce_usb + 1, 32, iforce_usb_out, iforce_usb, epout->bInterval); - usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), - (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce); + usb_fill_control_urb(iforce_usb->ctrl, dev, usb_rcvctrlpipe(dev, 0), + (void*) &iforce_usb->cr, iforce->edata, 16, iforce_usb_ctrl, iforce_usb); err = iforce_init_device(&intf->dev, BUS_USB, iforce); if (err) goto fail; - usb_set_intfdata(intf, iforce); + usb_set_intfdata(intf, iforce_usb); return 0; fail: - if (iforce) { - usb_free_urb(iforce->irq); - usb_free_urb(iforce->out); - usb_free_urb(iforce->ctrl); - kfree(iforce); + if (iforce_usb) { + usb_free_urb(iforce_usb->irq); + usb_free_urb(iforce_usb->out); + usb_free_urb(iforce_usb->ctrl); + kfree(iforce_usb); } return err; @@ -249,17 +279,17 @@ fail: static void iforce_usb_disconnect(struct usb_interface *intf) { - struct iforce *iforce = usb_get_intfdata(intf); + struct iforce_usb *iforce_usb = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); - input_unregister_device(iforce->dev); + input_unregister_device(iforce_usb->iforce.dev); - usb_free_urb(iforce->irq); - usb_free_urb(iforce->out); - usb_free_urb(iforce->ctrl); + usb_free_urb(iforce_usb->irq); + usb_free_urb(iforce_usb->out); + usb_free_urb(iforce_usb->ctrl); - kfree(iforce); + kfree(iforce_usb); } static const struct usb_device_id iforce_usb_ids[] = { diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index 3ee9245a415b..d9712c48ba74 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -111,19 +111,7 @@ struct iforce { unsigned char data[IFORCE_MAX_LENGTH]; unsigned char edata[IFORCE_MAX_LENGTH]; u16 ecmd; - u16 expect_packet; - -#ifdef CONFIG_JOYSTICK_IFORCE_232 - struct serio *serio; /* RS232 transfer */ - int idx, pkt, len, id; - unsigned char csum; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_USB - struct usb_device *usbdev; /* USB transfer */ - struct usb_interface *intf; - struct urb *irq, *out, *ctrl; - struct usb_ctrlrequest cr; -#endif + spinlock_t xmit_lock; /* Buffer used for asynchronous sending of bytes to the device */ struct circ_buf xmit; -- cgit v1.2.3-59-g8ed1b From 4f99de6d9d57d29b10f132490034aa21b7ba184f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 24 Jul 2018 17:32:24 -0700 Subject: Input: iforce - split into core and transport modules Now that we have moved enough transport details into separate source files we can change them into transport modules so that they are only loaded when needed. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/Kconfig | 8 +++--- drivers/input/joystick/iforce/Makefile | 7 +++--- drivers/input/joystick/iforce/iforce-main.c | 35 ++------------------------ drivers/input/joystick/iforce/iforce-packets.c | 2 ++ drivers/input/joystick/iforce/iforce-serio.c | 7 ++++++ drivers/input/joystick/iforce/iforce-usb.c | 7 ++++++ drivers/input/joystick/iforce/iforce.h | 2 -- 7 files changed, 25 insertions(+), 43 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/Kconfig b/drivers/input/joystick/iforce/Kconfig index ab4dbcbcbf50..55f6ae1da6b0 100644 --- a/drivers/input/joystick/iforce/Kconfig +++ b/drivers/input/joystick/iforce/Kconfig @@ -13,15 +13,15 @@ config JOYSTICK_IFORCE module will be called iforce. config JOYSTICK_IFORCE_USB - bool "I-Force USB joysticks and wheels" - depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB + tristate "I-Force USB joysticks and wheels" + depends on JOYSTICK_IFORCE && USB help Say Y here if you have an I-Force joystick or steering wheel connected to your USB port. config JOYSTICK_IFORCE_232 - bool "I-Force Serial joysticks and wheels" - depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || SERIO=y) && SERIO + tristate "I-Force Serial joysticks and wheels" + depends on JOYSTICK_IFORCE && SERIO help Say Y here if you have an I-Force joystick or steering wheel connected to your serial (COM) port. diff --git a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile index bc5bda22f15e..414075019a4f 100644 --- a/drivers/input/joystick/iforce/Makefile +++ b/drivers/input/joystick/iforce/Makefile @@ -4,8 +4,7 @@ # By Johann Deneux # -obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o - +obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o iforce-y := iforce-ff.o iforce-main.o iforce-packets.o -iforce-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o -iforce-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o +obj-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o +obj-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 894769d03df3..3a0698327c42 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -24,7 +24,7 @@ #include "iforce.h" MODULE_AUTHOR("Vojtech Pavlik , Johann Deneux "); -MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); +MODULE_DESCRIPTION("Core I-Force joysticks and wheels driver"); MODULE_LICENSE("GPL"); static signed short btn_joystick[] = @@ -411,35 +411,4 @@ int iforce_init_device(struct device *parent, u16 bustype, fail: input_free_device(input_dev); return error; } - -static int __init iforce_init(void) -{ - int err = 0; - -#ifdef CONFIG_JOYSTICK_IFORCE_USB - err = usb_register(&iforce_usb_driver); - if (err) - return err; -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - err = serio_register_driver(&iforce_serio_drv); -#ifdef CONFIG_JOYSTICK_IFORCE_USB - if (err) - usb_deregister(&iforce_usb_driver); -#endif -#endif - return err; -} - -static void __exit iforce_exit(void) -{ -#ifdef CONFIG_JOYSTICK_IFORCE_USB - usb_deregister(&iforce_usb_driver); -#endif -#ifdef CONFIG_JOYSTICK_IFORCE_232 - serio_unregister_driver(&iforce_serio_drv); -#endif -} - -module_init(iforce_init); -module_exit(iforce_exit); +EXPORT_SYMBOL(iforce_init_device); diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 8a9a152bb595..70db273e5045 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -96,6 +96,7 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) return 0; } +EXPORT_SYMBOL(iforce_send_packet); /* Start or stop an effect */ int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value) @@ -203,3 +204,4 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) break; } } +EXPORT_SYMBOL(iforce_process_packet); diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 6ff1bbeeb494..6c6411fbdc32 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -21,6 +21,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include "iforce.h" struct iforce_serio { @@ -250,3 +251,9 @@ struct serio_driver iforce_serio_drv = { .connect = iforce_serio_connect, .disconnect = iforce_serio_disconnect, }; + +module_serio_driver(iforce_serio_drv); + +MODULE_AUTHOR("Vojtech Pavlik , Johann Deneux "); +MODULE_DESCRIPTION("RS232 I-Force joysticks and wheels driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index d4e7a24922cd..9d635f01cf19 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -21,6 +21,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include "iforce.h" struct iforce_usb { @@ -316,3 +317,9 @@ struct usb_driver iforce_usb_driver = { .disconnect = iforce_usb_disconnect, .id_table = iforce_usb_ids, }; + +module_usb_driver(iforce_usb_driver); + +MODULE_AUTHOR("Vojtech Pavlik , Johann Deneux "); +MODULE_DESCRIPTION("USB I-Force joysticks and wheels driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index d9712c48ba74..3e3df83b9d77 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include #include -- cgit v1.2.3-59-g8ed1b From 4873586278258453bed94ffc04bfdc439197e86b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 9 Aug 2018 16:08:15 -0700 Subject: Input: iforce - use DMA-safe buffer when getting IDs from USB When working with USB devices we need to use DMA-safe buffers, and iforce->edata is not one. Let's rework the code to allocate temporary buffer (iforce_get_id() is called only during initialization so there is no reason to have permanent buffer) and use it. While at it, let's utilize usb_control_msg() API which simplifies code. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-usb.c | 68 ++++++++++-------------------- 1 file changed, 22 insertions(+), 46 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 9d635f01cf19..cefaa1c5abc7 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -29,8 +29,7 @@ struct iforce_usb { struct usb_device *usbdev; struct usb_interface *intf; - struct urb *irq, *out, *ctrl; - struct usb_ctrlrequest cr; + struct urb *irq, *out; }; static void __iforce_usb_xmit(struct iforce *iforce) @@ -92,30 +91,32 @@ static int iforce_usb_get_id(struct iforce *iforce, u8 *packet) { struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, iforce); + u8 *buf; int status; - iforce_usb->cr.bRequest = packet[0]; - iforce_usb->ctrl->dev = iforce_usb->usbdev; - - status = usb_submit_urb(iforce_usb->ctrl, GFP_KERNEL); - if (status) { + buf = kmalloc(IFORCE_MAX_LENGTH, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + status = usb_control_msg(iforce_usb->usbdev, + usb_rcvctrlpipe(iforce_usb->usbdev, 0), + packet[0], + USB_TYPE_VENDOR | USB_DIR_IN | + USB_RECIP_INTERFACE, + 0, 0, buf, IFORCE_MAX_LENGTH, HZ); + if (status < 0) { dev_err(&iforce_usb->intf->dev, - "usb_submit_urb failed %d\n", status); - return -EIO; - } - - wait_event_interruptible_timeout(iforce->wait, - iforce_usb->ctrl->status != -EINPROGRESS, HZ); - - if (iforce_usb->ctrl->status) { - dev_dbg(&iforce_usb->intf->dev, - "iforce->ctrl->status = %d\n", - iforce_usb->ctrl->status); - usb_unlink_urb(iforce_usb->ctrl); - return -EIO; + "usb_submit_urb failed: %d\n", status); + } else if (buf[0] != packet[0]) { + status = -EIO; + } else { + iforce->ecmd = 0xff00 | status; + memcpy(iforce->edata, buf, status); + status = 0; } - return -(iforce->edata[0] != packet[0]); + kfree(buf); + return status; } static int iforce_usb_start_io(struct iforce *iforce) @@ -136,7 +137,6 @@ static void iforce_usb_stop_io(struct iforce *iforce) usb_kill_urb(iforce_usb->irq); usb_kill_urb(iforce_usb->out); - usb_kill_urb(iforce_usb->ctrl); } static const struct iforce_xport_ops iforce_usb_xport_ops = { @@ -197,18 +197,6 @@ static void iforce_usb_out(struct urb *urb) wake_up(&iforce->wait); } -static void iforce_usb_ctrl(struct urb *urb) -{ - struct iforce_usb *iforce_usb = urb->context; - struct iforce *iforce = &iforce_usb->iforce; - - if (urb->status) - return; - - iforce->ecmd = 0xff00 | urb->actual_length; - wake_up(&iforce->wait); -} - static int iforce_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -236,9 +224,6 @@ static int iforce_usb_probe(struct usb_interface *intf, if (!(iforce_usb->out = usb_alloc_urb(0, GFP_KERNEL))) goto fail; - if (!(iforce_usb->ctrl = usb_alloc_urb(0, GFP_KERNEL))) - goto fail; - iforce = &iforce_usb->iforce; iforce->xport_ops = &iforce_usb_xport_ops; @@ -247,19 +232,12 @@ static int iforce_usb_probe(struct usb_interface *intf, iforce_usb->usbdev = dev; iforce_usb->intf = intf; - iforce_usb->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; - iforce_usb->cr.wIndex = 0; - iforce_usb->cr.wLength = cpu_to_le16(16); - usb_fill_int_urb(iforce_usb->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), iforce->data, 16, iforce_usb_irq, iforce_usb, epirq->bInterval); usb_fill_int_urb(iforce_usb->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress), iforce_usb + 1, 32, iforce_usb_out, iforce_usb, epout->bInterval); - usb_fill_control_urb(iforce_usb->ctrl, dev, usb_rcvctrlpipe(dev, 0), - (void*) &iforce_usb->cr, iforce->edata, 16, iforce_usb_ctrl, iforce_usb); - err = iforce_init_device(&intf->dev, BUS_USB, iforce); if (err) goto fail; @@ -271,7 +249,6 @@ fail: if (iforce_usb) { usb_free_urb(iforce_usb->irq); usb_free_urb(iforce_usb->out); - usb_free_urb(iforce_usb->ctrl); kfree(iforce_usb); } @@ -288,7 +265,6 @@ static void iforce_usb_disconnect(struct usb_interface *intf) usb_free_urb(iforce_usb->irq); usb_free_urb(iforce_usb->out); - usb_free_urb(iforce_usb->ctrl); kfree(iforce_usb); } -- cgit v1.2.3-59-g8ed1b From 43e61fc77fd1b1ee6c7e4989809e1d6b3fb65ad9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 9 Aug 2018 17:40:39 -0700 Subject: Input: iforce - update formatting of switch statements According to our coding style case labels in switch statements should be aligned with the switch keyword. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-ff.c | 18 ++-- drivers/input/joystick/iforce/iforce-main.c | 70 +++++++--------- drivers/input/joystick/iforce/iforce-packets.c | 112 +++++++++++++------------ 3 files changed, 100 insertions(+), 100 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c index 3536d5f5ad18..56973dd97fd6 100644 --- a/drivers/input/joystick/iforce/iforce-ff.c +++ b/drivers/input/joystick/iforce/iforce-ff.c @@ -384,12 +384,12 @@ int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, stru } switch (effect->u.periodic.waveform) { - case FF_SQUARE: wave_code = 0x20; break; - case FF_TRIANGLE: wave_code = 0x21; break; - case FF_SINE: wave_code = 0x22; break; - case FF_SAW_UP: wave_code = 0x23; break; - case FF_SAW_DOWN: wave_code = 0x24; break; - default: wave_code = 0x20; break; + case FF_SQUARE: wave_code = 0x20; break; + case FF_TRIANGLE: wave_code = 0x21; break; + case FF_SINE: wave_code = 0x22; break; + case FF_SAW_UP: wave_code = 0x23; break; + case FF_SAW_DOWN: wave_code = 0x24; break; + default: wave_code = 0x20; break; } if (!old || need_core(old, effect)) { @@ -488,9 +488,9 @@ int iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, str int core_err = 0; switch (effect->type) { - case FF_SPRING: type = 0x40; break; - case FF_DAMPER: type = 0x41; break; - default: return -1; + case FF_SPRING: type = 0x40; break; + case FF_DAMPER: type = 0x41; break; + default: return -1; } if (!old || need_condition_modifier(iforce, old, effect)) { diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 3a0698327c42..9964aa8b3cdc 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -132,22 +132,21 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, * Upload the effect */ switch (effect->type) { + case FF_PERIODIC: + ret = iforce_upload_periodic(iforce, effect, old); + break; - case FF_PERIODIC: - ret = iforce_upload_periodic(iforce, effect, old); - break; + case FF_CONSTANT: + ret = iforce_upload_constant(iforce, effect, old); + break; - case FF_CONSTANT: - ret = iforce_upload_constant(iforce, effect, old); - break; + case FF_SPRING: + case FF_DAMPER: + ret = iforce_upload_condition(iforce, effect, old); + break; - case FF_SPRING: - case FF_DAMPER: - ret = iforce_upload_condition(iforce, effect, old); - break; - - default: - return -EINVAL; + default: + return -EINVAL; } if (ret == 0) { @@ -351,34 +350,29 @@ int iforce_init_device(struct device *parent, u16 bustype, signed short t = iforce->type->abs[i]; switch (t) { + case ABS_X: + case ABS_Y: + case ABS_WHEEL: + input_set_abs_params(input_dev, t, -1920, 1920, 16, 128); + set_bit(t, input_dev->ffbit); + break; - case ABS_X: - case ABS_Y: - case ABS_WHEEL: - - input_set_abs_params(input_dev, t, -1920, 1920, 16, 128); - set_bit(t, input_dev->ffbit); - break; - - case ABS_THROTTLE: - case ABS_GAS: - case ABS_BRAKE: - - input_set_abs_params(input_dev, t, 0, 255, 0, 0); - break; - - case ABS_RUDDER: - - input_set_abs_params(input_dev, t, -128, 127, 0, 0); - break; + case ABS_THROTTLE: + case ABS_GAS: + case ABS_BRAKE: + input_set_abs_params(input_dev, t, 0, 255, 0, 0); + break; - case ABS_HAT0X: - case ABS_HAT0Y: - case ABS_HAT1X: - case ABS_HAT1Y: + case ABS_RUDDER: + input_set_abs_params(input_dev, t, -128, 127, 0, 0); + break; - input_set_abs_params(input_dev, t, -1, 1, 0, 0); - break; + case ABS_HAT0X: + case ABS_HAT0Y: + case ABS_HAT1X: + case ABS_HAT1Y: + input_set_abs_params(input_dev, t, -1, 1, 0, 0); + break; } } diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 70db273e5045..7aba2966454a 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -142,66 +142,72 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) switch (HI(cmd)) { - case 0x01: /* joystick position data */ - case 0x03: /* wheel position data */ - if (HI(cmd) == 1) { - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); - input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); - if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) - input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); - } else { - input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_GAS, 255 - data[2]); - input_report_abs(dev, ABS_BRAKE, 255 - data[3]); - } + case 0x01: /* joystick position data */ + case 0x03: /* wheel position data */ + if (HI(cmd) == 1) { + input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); + if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) + input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); + } else { + input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_GAS, 255 - data[2]); + input_report_abs(dev, ABS_BRAKE, 255 - data[3]); + } - input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); - input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); - - for (i = 0; iforce->type->btn[i] >= 0; i++) - input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); - - /* If there are untouched bits left, interpret them as the second hat */ - if (i <= 8) { - int btns = data[6]; - if (test_bit(ABS_HAT1X, dev->absbit)) { - if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1); - else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1); - else input_report_abs(dev, ABS_HAT1X, 0); - } - if (test_bit(ABS_HAT1Y, dev->absbit)) { - if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1); - else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1); - else input_report_abs(dev, ABS_HAT1Y, 0); - } + input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); + input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); + + for (i = 0; iforce->type->btn[i] >= 0; i++) + input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); + + /* If there are untouched bits left, interpret them as the second hat */ + if (i <= 8) { + int btns = data[6]; + if (test_bit(ABS_HAT1X, dev->absbit)) { + if (btns & 8) + input_report_abs(dev, ABS_HAT1X, -1); + else if (btns & 2) + input_report_abs(dev, ABS_HAT1X, 1); + else + input_report_abs(dev, ABS_HAT1X, 0); } + if (test_bit(ABS_HAT1Y, dev->absbit)) { + if (btns & 1) + input_report_abs(dev, ABS_HAT1Y, -1); + else if (btns & 4) + input_report_abs(dev, ABS_HAT1Y, 1); + else + input_report_abs(dev, ABS_HAT1Y, 0); + } + } - input_sync(dev); + input_sync(dev); - break; + break; - case 0x02: /* status report */ - input_report_key(dev, BTN_DEAD, data[0] & 0x02); - input_sync(dev); + case 0x02: /* status report */ + input_report_key(dev, BTN_DEAD, data[0] & 0x02); + input_sync(dev); - /* Check if an effect was just started or stopped */ - i = data[1] & 0x7f; - if (data[1] & 0x80) { - if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { - /* Report play event */ - input_report_ff_status(dev, i, FF_STATUS_PLAYING); - } - } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { - /* Report stop event */ - input_report_ff_status(dev, i, FF_STATUS_STOPPED); + /* Check if an effect was just started or stopped */ + i = data[1] & 0x7f; + if (data[1] & 0x80) { + if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report play event */ + input_report_ff_status(dev, i, FF_STATUS_PLAYING); } - if (LO(cmd) > 3) { - int j; - for (j = 3; j < LO(cmd); j += 2) - mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); - } - break; + } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report stop event */ + input_report_ff_status(dev, i, FF_STATUS_STOPPED); + } + if (LO(cmd) > 3) { + int j; + for (j = 3; j < LO(cmd); j += 2) + mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); + } + break; } } EXPORT_SYMBOL(iforce_process_packet); -- cgit v1.2.3-59-g8ed1b From 8a25e05890f155406171e8cb256177275bbf387f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 9 Aug 2018 17:41:40 -0700 Subject: Input: iforce - factor out hat handling when parsing packets This makes code clearer a bit. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-packets.c | 101 ++++++++++++++----------- 1 file changed, 57 insertions(+), 44 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 7aba2966454a..ffd1dd65deb8 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -130,11 +130,47 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) return -1; } -void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) +static void iforce_report_hats_buttons(struct iforce *iforce, u8 *data) { struct input_dev *dev = iforce->dev; int i; + input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); + input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); + + for (i = 0; iforce->type->btn[i] >= 0; i++) + input_report_key(dev, iforce->type->btn[i], + data[(i >> 3) + 5] & (1 << (i & 7))); + + /* If there are untouched bits left, interpret them as the second hat */ + if (i <= 8) { + u8 btns = data[6]; + + if (test_bit(ABS_HAT1X, dev->absbit)) { + if (btns & BIT(3)) + input_report_abs(dev, ABS_HAT1X, -1); + else if (btns & BIT(1)) + input_report_abs(dev, ABS_HAT1X, 1); + else + input_report_abs(dev, ABS_HAT1X, 0); + } + + if (test_bit(ABS_HAT1Y, dev->absbit)) { + if (btns & BIT(0)) + input_report_abs(dev, ABS_HAT1Y, -1); + else if (btns & BIT(2)) + input_report_abs(dev, ABS_HAT1Y, 1); + else + input_report_abs(dev, ABS_HAT1Y, 0); + } + } +} + +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) +{ + struct input_dev *dev = iforce->dev; + int i, j; + wake_up(&iforce->wait); if (!iforce->type) @@ -143,48 +179,26 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) switch (HI(cmd)) { case 0x01: /* joystick position data */ - case 0x03: /* wheel position data */ - if (HI(cmd) == 1) { - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); - input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); - if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) - input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); - } else { - input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_GAS, 255 - data[2]); - input_report_abs(dev, ABS_BRAKE, 255 - data[3]); - } + input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); - input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); - input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); - - for (i = 0; iforce->type->btn[i] >= 0; i++) - input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); - - /* If there are untouched bits left, interpret them as the second hat */ - if (i <= 8) { - int btns = data[6]; - if (test_bit(ABS_HAT1X, dev->absbit)) { - if (btns & 8) - input_report_abs(dev, ABS_HAT1X, -1); - else if (btns & 2) - input_report_abs(dev, ABS_HAT1X, 1); - else - input_report_abs(dev, ABS_HAT1X, 0); - } - if (test_bit(ABS_HAT1Y, dev->absbit)) { - if (btns & 1) - input_report_abs(dev, ABS_HAT1Y, -1); - else if (btns & 4) - input_report_abs(dev, ABS_HAT1Y, 1); - else - input_report_abs(dev, ABS_HAT1Y, 0); - } - } + if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) + input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); + + iforce_report_hats_buttons(iforce, data); input_sync(dev); + break; + case 0x03: /* wheel position data */ + input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_GAS, 255 - data[2]); + input_report_abs(dev, ABS_BRAKE, 255 - data[3]); + + iforce_report_hats_buttons(iforce, data); + + input_sync(dev); break; case 0x02: /* status report */ @@ -202,11 +216,10 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) /* Report stop event */ input_report_ff_status(dev, i, FF_STATUS_STOPPED); } - if (LO(cmd) > 3) { - int j; - for (j = 3; j < LO(cmd); j += 2) - mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); - } + + for (j = 3; j < LO(cmd); j += 2) + mark_core_as_ready(iforce, data[j] | (data[j + 1] << 8)); + break; } } -- cgit v1.2.3-59-g8ed1b From d3cc100069f945a392d6cde5ea326bb686418193 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 9 Aug 2018 17:50:39 -0700 Subject: Input: iforce - do not combine arguments for iforce_process_packet() Current code combines packet type and data length into single argument to iforce_process_packet() and then has to untangle it. It is much clearer to simply use separate arguments. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-packets.c | 9 +++++---- drivers/input/joystick/iforce/iforce-serio.c | 8 ++++---- drivers/input/joystick/iforce/iforce-usb.c | 4 ++-- drivers/input/joystick/iforce/iforce.h | 3 ++- 4 files changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index ffd1dd65deb8..35b7a5206977 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -166,7 +166,8 @@ static void iforce_report_hats_buttons(struct iforce *iforce, u8 *data) } } -void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) +void iforce_process_packet(struct iforce *iforce, + u8 packet_id, u8 *data, size_t len) { struct input_dev *dev = iforce->dev; int i, j; @@ -176,14 +177,14 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) if (!iforce->type) return; - switch (HI(cmd)) { + switch (packet_id) { case 0x01: /* joystick position data */ input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); - if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) + if (len >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); iforce_report_hats_buttons(iforce, data); @@ -217,7 +218,7 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) input_report_ff_status(dev, i, FF_STATUS_STOPPED); } - for (j = 3; j < LO(cmd); j += 2) + for (j = 3; j < len; j += 2) mark_core_as_ready(iforce, data[j] | (data[j + 1] << 8)); break; diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 6c6411fbdc32..f8bf7d2aa59f 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -163,16 +163,16 @@ static irqreturn_t iforce_serio_irq(struct serio *serio, } if (iforce_serio->idx == iforce_serio->len) { - u16 cmd = (iforce_serio->id << 8) | iforce_serio->idx; - /* Handle command completion */ if (iforce_serio->expect_packet == iforce_serio->id) { iforce_serio->expect_packet = 0; - iforce->ecmd = cmd; + iforce->ecmd = (iforce_serio->id << 8) | + iforce_serio->idx; memcpy(iforce->edata, iforce->data, IFORCE_MAX_LENGTH); } - iforce_process_packet(iforce, cmd, iforce->data); + iforce_process_packet(iforce, iforce_serio->id, + iforce->data, iforce_serio->len); iforce_serio->pkt = 0; iforce_serio->id = 0; diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index cefaa1c5abc7..b3743fde2a3a 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -170,8 +170,8 @@ static void iforce_usb_irq(struct urb *urb) goto exit; } - iforce_process_packet(iforce, - (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); + iforce_process_packet(iforce, iforce->data[0], + iforce->data + 1, urb->actual_length - 1); exit: status = usb_submit_urb(urb, GFP_ATOMIC); diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index 3e3df83b9d77..ce3c6aead8b6 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -147,7 +147,8 @@ int iforce_init_device(struct device *parent, u16 bustype, /* iforce-packets.c */ int iforce_control_playback(struct iforce*, u16 id, unsigned int); -void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data); +void iforce_process_packet(struct iforce *iforce, + u8 packet_id, u8 *data, size_t len); int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); void iforce_dump_packet(struct iforce *iforce, char *msg, u16 cmd, unsigned char *data); -- cgit v1.2.3-59-g8ed1b From 2880dcf9cfc28a3803aee4c964743adbb66b0f1a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 10 Aug 2018 10:21:13 -0700 Subject: Input: iforce - signal command completion from transport code Signalling command completion from iforce_process_packet() does not make sense, as not all transport use the same data path for both commands and motion data form the device, that is why USB code already has to signal command completion iforce_usb_out(). Let's move signalling completion into individual transport modules. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-packets.c | 2 -- drivers/input/joystick/iforce/iforce-serio.c | 9 ++++++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 35b7a5206977..c0a665961c23 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -172,8 +172,6 @@ void iforce_process_packet(struct iforce *iforce, struct input_dev *dev = iforce->dev; int i, j; - wake_up(&iforce->wait); - if (!iforce->type) return; diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index f8bf7d2aa59f..0dd95d145e85 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -169,10 +169,13 @@ static irqreturn_t iforce_serio_irq(struct serio *serio, iforce->ecmd = (iforce_serio->id << 8) | iforce_serio->idx; memcpy(iforce->edata, iforce->data, IFORCE_MAX_LENGTH); - } - iforce_process_packet(iforce, iforce_serio->id, - iforce->data, iforce_serio->len); + /* Signal that command is done */ + wake_up(&iforce->wait); + } else { + iforce_process_packet(iforce, iforce_serio->id, + iforce->data, iforce_serio->len); + } iforce_serio->pkt = 0; iforce_serio->id = 0; -- cgit v1.2.3-59-g8ed1b From 633354d1910262f2a3262797572ff72da461379e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 10 Aug 2018 10:34:13 -0700 Subject: Input: iforce - only call iforce_process_packet() if initialized It is excessive to check if device is fully initialized in iforce_process_packet(), as for USB-conected devices we do not start collecting reports until the device is fully initialized. Let's change serio transport code to not call iforce_process_packet() until device initialization is done. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-packets.c | 3 --- drivers/input/joystick/iforce/iforce-serio.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index c0a665961c23..976ec1c7cf15 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -172,9 +172,6 @@ void iforce_process_packet(struct iforce *iforce, struct input_dev *dev = iforce->dev; int i, j; - if (!iforce->type) - return; - switch (packet_id) { case 0x01: /* joystick position data */ diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 0dd95d145e85..8d7eba9c9f0e 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -172,7 +172,7 @@ static irqreturn_t iforce_serio_irq(struct serio *serio, /* Signal that command is done */ wake_up(&iforce->wait); - } else { + } else if (likely(iforce->type)) { iforce_process_packet(iforce, iforce_serio->id, iforce->data, iforce_serio->len); } -- cgit v1.2.3-59-g8ed1b From 6ac0aec6b0a651d64eef759fddf17d9145b51033 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 9 Aug 2018 17:28:35 -0700 Subject: Input: iforce - allow callers supply data buffer when fetching device IDs We want to move buffer handling into transport layers as the properties of buffers (DMA-safety, alignment, etc) are different for different transports. To allow this, let's allow caller to specify their own buffers for the results of iforce_get_id_packet() and let transport drivers to figure what buffers they need to use for transfers. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-main.c | 27 +++++++++++++++------------ drivers/input/joystick/iforce/iforce-serio.c | 28 ++++++++++++++++++++-------- drivers/input/joystick/iforce/iforce-usb.c | 11 ++++++----- drivers/input/joystick/iforce/iforce.h | 11 ++++++----- 4 files changed, 47 insertions(+), 30 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 9964aa8b3cdc..5cb3e80f4e0d 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -225,7 +225,9 @@ int iforce_init_device(struct device *parent, u16 bustype, { struct input_dev *input_dev; struct ff_device *ff; - unsigned char c[] = "CEOV"; + u8 c[] = "CEOV"; + u8 buf[IFORCE_MAX_LENGTH]; + size_t len; int i, error; int ff_effects = 0; @@ -269,7 +271,7 @@ int iforce_init_device(struct device *parent, u16 bustype, */ for (i = 0; i < 20; i++) - if (!iforce_get_id_packet(iforce, "O")) + if (!iforce_get_id_packet(iforce, 'O', buf, &len)) break; if (i == 20) { /* 5 seconds */ @@ -283,23 +285,23 @@ int iforce_init_device(struct device *parent, u16 bustype, * Get device info. */ - if (!iforce_get_id_packet(iforce, "M")) - input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'M', buf, &len) || len < 3) + input_dev->id.vendor = (buf[2] << 8) | buf[1]; else dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n"); - if (!iforce_get_id_packet(iforce, "P")) - input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'P', buf, &len) || len < 3) + input_dev->id.product = (buf[2] << 8) | buf[1]; else dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n"); - if (!iforce_get_id_packet(iforce, "B")) - iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'B', buf, &len) || len < 3) + iforce->device_memory.end = (buf[2] << 8) | buf[1]; else dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n"); - if (!iforce_get_id_packet(iforce, "N")) - ff_effects = iforce->edata[1]; + if (!iforce_get_id_packet(iforce, 'N', buf, &len) || len < 2) + ff_effects = buf[1]; else dev_warn(&iforce->dev->dev, "Device does not respond to id packet N\n"); @@ -315,8 +317,9 @@ int iforce_init_device(struct device *parent, u16 bustype, */ for (i = 0; c[i]; i++) - if (!iforce_get_id_packet(iforce, c + i)) - iforce_dump_packet(iforce, "info", iforce->ecmd, iforce->edata); + if (!iforce_get_id_packet(iforce, c[i], buf, &len)) + iforce_dump_packet(iforce, "info", + (FF_CMD_QUERY & 0xff00) | len, buf); /* * Disable spring, enable force feedback. diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 8d7eba9c9f0e..be44aed551f7 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -31,6 +31,8 @@ struct iforce_serio { int idx, pkt, len, id; u8 csum; u8 expect_packet; + u8 cmd_response[IFORCE_MAX_LENGTH]; + u8 cmd_response_len; }; static void iforce_serio_xmit(struct iforce *iforce) @@ -81,24 +83,34 @@ again: spin_unlock_irqrestore(&iforce->xmit_lock, flags); } -static int iforce_serio_get_id(struct iforce *iforce, u8 *packet) +static int iforce_serio_get_id(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len) { struct iforce_serio *iforce_serio = container_of(iforce, struct iforce_serio, iforce); iforce_serio->expect_packet = HI(FF_CMD_QUERY); - iforce_send_packet(iforce, FF_CMD_QUERY, packet); + iforce_serio->cmd_response_len = 0; + + iforce_send_packet(iforce, FF_CMD_QUERY, &id); wait_event_interruptible_timeout(iforce->wait, !iforce_serio->expect_packet, HZ); if (iforce_serio->expect_packet) { iforce_serio->expect_packet = 0; - return -EIO; + return -ETIMEDOUT; } - return -(iforce->edata[0] != packet[0]); + if (iforce_serio->cmd_response[0] != id) + return -EIO; + + memcpy(response_data, iforce_serio->cmd_response, + iforce_serio->cmd_response_len); + *response_len = iforce_serio->cmd_response_len; + + return 0; } static int iforce_serio_start_io(struct iforce *iforce) @@ -127,7 +139,7 @@ static void iforce_serio_write_wakeup(struct serio *serio) } static irqreturn_t iforce_serio_irq(struct serio *serio, - unsigned char data, unsigned int flags) + unsigned char data, unsigned int flags) { struct iforce_serio *iforce_serio = serio_get_drvdata(serio); struct iforce *iforce = &iforce_serio->iforce; @@ -166,9 +178,9 @@ static irqreturn_t iforce_serio_irq(struct serio *serio, /* Handle command completion */ if (iforce_serio->expect_packet == iforce_serio->id) { iforce_serio->expect_packet = 0; - iforce->ecmd = (iforce_serio->id << 8) | - iforce_serio->idx; - memcpy(iforce->edata, iforce->data, IFORCE_MAX_LENGTH); + memcpy(iforce_serio->cmd_response, iforce->data, + IFORCE_MAX_LENGTH); + iforce_serio->cmd_response_len = iforce_serio->len; /* Signal that command is done */ wake_up(&iforce->wait); diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index b3743fde2a3a..68155c4de412 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -87,7 +87,8 @@ static void iforce_usb_xmit(struct iforce *iforce) __iforce_usb_xmit(iforce); } -static int iforce_usb_get_id(struct iforce *iforce, u8 *packet) +static int iforce_usb_get_id(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len) { struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, iforce); @@ -100,18 +101,18 @@ static int iforce_usb_get_id(struct iforce *iforce, u8 *packet) status = usb_control_msg(iforce_usb->usbdev, usb_rcvctrlpipe(iforce_usb->usbdev, 0), - packet[0], + id, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE, 0, 0, buf, IFORCE_MAX_LENGTH, HZ); if (status < 0) { dev_err(&iforce_usb->intf->dev, "usb_submit_urb failed: %d\n", status); - } else if (buf[0] != packet[0]) { + } else if (buf[0] != id) { status = -EIO; } else { - iforce->ecmd = 0xff00 | status; - memcpy(iforce->edata, buf, status); + memcpy(response_data, buf, status); + *response_len = status; status = 0; } diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index ce3c6aead8b6..68558c594e54 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -95,7 +95,8 @@ struct iforce; struct iforce_xport_ops { void (*xmit)(struct iforce *iforce); - int (*get_id)(struct iforce *iforce, u8* id); + int (*get_id)(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len); int (*start_io)(struct iforce *iforce); void (*stop_io)(struct iforce *iforce); }; @@ -107,8 +108,6 @@ struct iforce { int bus; unsigned char data[IFORCE_MAX_LENGTH]; - unsigned char edata[IFORCE_MAX_LENGTH]; - u16 ecmd; spinlock_t xmit_lock; /* Buffer used for asynchronous sending of bytes to the device */ @@ -135,9 +134,11 @@ struct iforce { /* Encode a time value */ #define TIME_SCALE(a) (a) -static inline int iforce_get_id_packet(struct iforce *iforce, u8* id) +static inline int iforce_get_id_packet(struct iforce *iforce, u8 id, + u8 *response_data, size_t *response_len) { - return iforce->xport_ops->get_id(iforce, id); + return iforce->xport_ops->get_id(iforce, id, + response_data, response_len); } /* Public functions */ -- cgit v1.2.3-59-g8ed1b From dfad2b17935d70d7dc3830c4986344b3f2669c62 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 10 Aug 2018 13:44:52 -0700 Subject: Input: iforce - use DMA-safe buffores for USB transfers USB transport has to use cache line-aligned buffers for transfers to avoid DMA issues; serio doe snot have such restrictions. Let's move "data_in" buffer from main driver structure into transport modules and make sure USB requirements are respected. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-serio.c | 10 ++++++---- drivers/input/joystick/iforce/iforce-usb.c | 28 +++++++++++++++++++--------- drivers/input/joystick/iforce/iforce.h | 2 -- 3 files changed, 25 insertions(+), 15 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index be44aed551f7..c73d988cbc92 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -33,6 +33,7 @@ struct iforce_serio { u8 expect_packet; u8 cmd_response[IFORCE_MAX_LENGTH]; u8 cmd_response_len; + u8 data_in[IFORCE_MAX_LENGTH]; }; static void iforce_serio_xmit(struct iforce *iforce) @@ -169,7 +170,7 @@ static irqreturn_t iforce_serio_irq(struct serio *serio, } if (iforce_serio->idx < iforce_serio->len) { - iforce->data[iforce_serio->idx++] = data; + iforce_serio->data_in[iforce_serio->idx++] = data; iforce_serio->csum += data; goto out; } @@ -178,15 +179,16 @@ static irqreturn_t iforce_serio_irq(struct serio *serio, /* Handle command completion */ if (iforce_serio->expect_packet == iforce_serio->id) { iforce_serio->expect_packet = 0; - memcpy(iforce_serio->cmd_response, iforce->data, - IFORCE_MAX_LENGTH); + memcpy(iforce_serio->cmd_response, + iforce_serio->data_in, IFORCE_MAX_LENGTH); iforce_serio->cmd_response_len = iforce_serio->len; /* Signal that command is done */ wake_up(&iforce->wait); } else if (likely(iforce->type)) { iforce_process_packet(iforce, iforce_serio->id, - iforce->data, iforce_serio->len); + iforce_serio->data_in, + iforce_serio->len); } iforce_serio->pkt = 0; diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 68155c4de412..d85258b50be2 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -30,6 +30,9 @@ struct iforce_usb { struct usb_device *usbdev; struct usb_interface *intf; struct urb *irq, *out; + + u8 data_in[IFORCE_MAX_LENGTH] ____cacheline_aligned; + u8 data_out[IFORCE_MAX_LENGTH] ____cacheline_aligned; }; static void __iforce_usb_xmit(struct iforce *iforce) @@ -171,8 +174,8 @@ static void iforce_usb_irq(struct urb *urb) goto exit; } - iforce_process_packet(iforce, iforce->data[0], - iforce->data + 1, urb->actual_length - 1); + iforce_process_packet(iforce, iforce_usb->data_in[0], + iforce_usb->data_in + 1, urb->actual_length - 1); exit: status = usb_submit_urb(urb, GFP_ATOMIC); @@ -216,13 +219,16 @@ static int iforce_usb_probe(struct usb_interface *intf, epirq = &interface->endpoint[0].desc; epout = &interface->endpoint[1].desc; - if (!(iforce_usb = kzalloc(sizeof(*iforce_usb) + 32, GFP_KERNEL))) + iforce_usb = kzalloc(sizeof(*iforce_usb), GFP_KERNEL); + if (!iforce_usb) goto fail; - if (!(iforce_usb->irq = usb_alloc_urb(0, GFP_KERNEL))) + iforce_usb->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!iforce_usb->irq) goto fail; - if (!(iforce_usb->out = usb_alloc_urb(0, GFP_KERNEL))) + iforce_usb->out = usb_alloc_urb(0, GFP_KERNEL); + if (!iforce_usb->out) goto fail; iforce = &iforce_usb->iforce; @@ -233,11 +239,15 @@ static int iforce_usb_probe(struct usb_interface *intf, iforce_usb->usbdev = dev; iforce_usb->intf = intf; - usb_fill_int_urb(iforce_usb->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), - iforce->data, 16, iforce_usb_irq, iforce_usb, epirq->bInterval); + usb_fill_int_urb(iforce_usb->irq, dev, + usb_rcvintpipe(dev, epirq->bEndpointAddress), + iforce_usb->data_in, sizeof(iforce_usb->data_in), + iforce_usb_irq, iforce_usb, epirq->bInterval); - usb_fill_int_urb(iforce_usb->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress), - iforce_usb + 1, 32, iforce_usb_out, iforce_usb, epout->bInterval); + usb_fill_int_urb(iforce_usb->out, dev, + usb_sndintpipe(dev, epout->bEndpointAddress), + iforce_usb->data_out, sizeof(iforce_usb->data_out), + iforce_usb_out, iforce_usb, epout->bInterval); err = iforce_init_device(&intf->dev, BUS_USB, iforce); if (err) diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index 68558c594e54..180de7a3f3a1 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -107,8 +107,6 @@ struct iforce { const struct iforce_xport_ops *xport_ops; int bus; - unsigned char data[IFORCE_MAX_LENGTH]; - spinlock_t xmit_lock; /* Buffer used for asynchronous sending of bytes to the device */ struct circ_buf xmit; -- cgit v1.2.3-59-g8ed1b From 2178db65cd9c81c790cbf7504e90650750c3b467 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 10 Aug 2018 13:48:16 -0700 Subject: Input: iforce - drop bus type from iforce structure It is not needed anymore as behavior is controlled by the transport operations set up for given device. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-serio.c | 1 - drivers/input/joystick/iforce/iforce-usb.c | 1 - drivers/input/joystick/iforce/iforce.h | 5 ----- 3 files changed, 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index c73d988cbc92..277522d0f324 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -214,7 +214,6 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) iforce = &iforce_serio->iforce; iforce->xport_ops = &iforce_serio_xport_ops; - iforce->bus = IFORCE_232; iforce_serio->serio = serio; serio_set_drvdata(serio, iforce_serio); diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index d85258b50be2..ae2dd5b5a416 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -234,7 +234,6 @@ static int iforce_usb_probe(struct usb_interface *intf, iforce = &iforce_usb->iforce; iforce->xport_ops = &iforce_usb_xport_ops; - iforce->bus = IFORCE_USB; iforce_usb->usbdev = dev; iforce_usb->intf = intf; diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index 180de7a3f3a1..3e91cc381488 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -38,10 +38,6 @@ #define IFORCE_MAX_LENGTH 16 -/* iforce::bus */ -#define IFORCE_232 1 -#define IFORCE_USB 2 - #define IFORCE_EFFECTS_MAX 32 /* Each force feedback effect is made of one core effect, which can be @@ -105,7 +101,6 @@ struct iforce { struct input_dev *dev; /* Input device interface */ struct iforce_device *type; const struct iforce_xport_ops *xport_ops; - int bus; spinlock_t xmit_lock; /* Buffer used for asynchronous sending of bytes to the device */ -- cgit v1.2.3-59-g8ed1b From 8624dfd10a3bb3ea3d8a959e17f8951f1b03d68d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 10 Aug 2018 13:52:31 -0700 Subject: Input: iforce - drop couple of temps from transport code Transport initialization code now deals mostly with transport-specific data, so we can drop couple of temporary variables. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-serio.c | 7 ++----- drivers/input/joystick/iforce/iforce-usb.c | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 277522d0f324..e7692a38591e 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -204,16 +204,13 @@ out: static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) { struct iforce_serio *iforce_serio; - struct iforce *iforce; int err; iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL); if (!iforce_serio) return -ENOMEM; - iforce = &iforce_serio->iforce; - - iforce->xport_ops = &iforce_serio_xport_ops; + iforce_serio->iforce.xport_ops = &iforce_serio_xport_ops; iforce_serio->serio = serio; serio_set_drvdata(serio, iforce_serio); @@ -222,7 +219,7 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) if (err) goto fail1; - err = iforce_init_device(&serio->dev, BUS_RS232, iforce); + err = iforce_init_device(&serio->dev, BUS_RS232, &iforce_serio->iforce); if (err) goto fail2; diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index ae2dd5b5a416..a1e670781441 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -208,7 +208,6 @@ static int iforce_usb_probe(struct usb_interface *intf, struct usb_host_interface *interface; struct usb_endpoint_descriptor *epirq, *epout; struct iforce_usb *iforce_usb; - struct iforce *iforce; int err = -ENOMEM; interface = intf->cur_altsetting; @@ -231,9 +230,7 @@ static int iforce_usb_probe(struct usb_interface *intf, if (!iforce_usb->out) goto fail; - iforce = &iforce_usb->iforce; - - iforce->xport_ops = &iforce_usb_xport_ops; + iforce_usb->iforce.xport_ops = &iforce_usb_xport_ops; iforce_usb->usbdev = dev; iforce_usb->intf = intf; @@ -248,7 +245,7 @@ static int iforce_usb_probe(struct usb_interface *intf, iforce_usb->data_out, sizeof(iforce_usb->data_out), iforce_usb_out, iforce_usb, epout->bInterval); - err = iforce_init_device(&intf->dev, BUS_USB, iforce); + err = iforce_init_device(&intf->dev, BUS_USB, &iforce_usb->iforce); if (err) goto fail; -- cgit v1.2.3-59-g8ed1b From 21ae38f8558511450a33fb3873bfcd6b8f1e0922 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 10 Aug 2018 13:54:02 -0700 Subject: Input: iforce - use unaligned accessors, where appropriate Instead of open-coding conversion from/to little-endian, let's use proper accessors. Tested-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-main.c | 7 ++++--- drivers/input/joystick/iforce/iforce-packets.c | 12 ++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 5cb3e80f4e0d..d696b0b653b6 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -21,6 +21,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include "iforce.h" MODULE_AUTHOR("Vojtech Pavlik , Johann Deneux "); @@ -286,17 +287,17 @@ int iforce_init_device(struct device *parent, u16 bustype, */ if (!iforce_get_id_packet(iforce, 'M', buf, &len) || len < 3) - input_dev->id.vendor = (buf[2] << 8) | buf[1]; + input_dev->id.vendor = get_unaligned_le16(buf + 1); else dev_warn(&iforce->dev->dev, "Device does not respond to id packet M\n"); if (!iforce_get_id_packet(iforce, 'P', buf, &len) || len < 3) - input_dev->id.product = (buf[2] << 8) | buf[1]; + input_dev->id.product = get_unaligned_le16(buf + 1); else dev_warn(&iforce->dev->dev, "Device does not respond to id packet P\n"); if (!iforce_get_id_packet(iforce, 'B', buf, &len) || len < 3) - iforce->device_memory.end = (buf[2] << 8) | buf[1]; + iforce->device_memory.end = get_unaligned_le16(buf + 1); else dev_warn(&iforce->dev->dev, "Device does not respond to id packet B\n"); diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 976ec1c7cf15..76c4475740ab 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -21,6 +21,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include "iforce.h" static struct { @@ -175,8 +176,10 @@ void iforce_process_packet(struct iforce *iforce, switch (packet_id) { case 0x01: /* joystick position data */ - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); + input_report_abs(dev, ABS_X, + (__s16) get_unaligned_le16(data)); + input_report_abs(dev, ABS_Y, + (__s16) get_unaligned_le16(data + 2)); input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); if (len >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) @@ -188,7 +191,8 @@ void iforce_process_packet(struct iforce *iforce, break; case 0x03: /* wheel position data */ - input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_WHEEL, + (__s16) get_unaligned_le16(data)); input_report_abs(dev, ABS_GAS, 255 - data[2]); input_report_abs(dev, ABS_BRAKE, 255 - data[3]); @@ -214,7 +218,7 @@ void iforce_process_packet(struct iforce *iforce, } for (j = 3; j < len; j += 2) - mark_core_as_ready(iforce, data[j] | (data[j + 1] << 8)); + mark_core_as_ready(iforce, get_unaligned_le16(data + j)); break; } -- cgit v1.2.3-59-g8ed1b From 11518370b332c0eeaaccef1f5de7877747893f1f Mon Sep 17 00:00:00 2001 From: Tim Schumacher Date: Tue, 18 Jun 2019 17:22:14 -0700 Subject: Input: iforce - add the Saitek R440 Force Wheel This is added based on the fact that this is an iforce-based device and that the Windows driver for the R440 works for the Logitech WingMan Formula Force after replacing the device/vendor IDs. Signed-off-by: Tim Schumacher Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-main.c | 1 + drivers/input/joystick/iforce/iforce-usb.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index d696b0b653b6..40eb65bfd57e 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -68,6 +68,7 @@ static struct iforce_device iforce_device[] = { { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? { 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //? { 0x061c, 0xc084, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, + { 0x06a3, 0xff04, "Saitek R440 Force Wheel", btn_wheel, abs_wheel, ff_iforce }, //? { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //? { 0x06f8, 0x0001, "Guillemot Jet Leader Force Feedback", btn_joystick, abs_joystick_rudder, ff_iforce }, { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index a1e670781441..75a2b0ea37b4 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -285,6 +285,7 @@ static const struct usb_device_id iforce_usb_ids[] = { { USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */ { USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */ { USB_DEVICE(0x061c, 0xc084) }, /* ACT LABS Force RS */ + { USB_DEVICE(0x06a3, 0xff04) }, /* Saitek R440 Force Wheel */ { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ { USB_DEVICE(0x06f8, 0x0003) }, /* Guillemot Jet Leader Force Feedback */ { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */ -- cgit v1.2.3-59-g8ed1b From 1b9c698c41c947f8adf2febcbc1df122cb3d09da Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 22 Jun 2019 23:11:51 -0700 Subject: Input: edt-ft5x06 - use get_unaligned_be16() Instead of doing conversion by hand, let's use the proper accessors. Reviewed-by: Andy Shevchenko Tested-by: Benoit Parrot Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index c639ebce914c..ec770226e119 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -27,6 +27,7 @@ #include #include #include +#include #define WORK_REGISTER_THRESHOLD 0x00 #define WORK_REGISTER_REPORT_RATE 0x08 @@ -239,8 +240,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN) continue; - x = ((buf[0] << 8) | buf[1]) & 0x0fff; - y = ((buf[2] << 8) | buf[3]) & 0x0fff; + x = get_unaligned_be16(buf) & 0x0fff; + y = get_unaligned_be16(buf + 2) & 0x0fff; /* The FT5x26 send the y coordinate first */ if (tsdata->version == EV_FT) swap(x, y); -- cgit v1.2.3-59-g8ed1b From 0828c1001399d5c5fcab547ef7b0a29c78d4bdf6 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Sun, 30 Jun 2019 00:14:52 -0700 Subject: Input: elan_i2c - export the device id whitelist Elan_i2c and hid-quirks work in conjunction to decide which devices each driver will handle. Elan_i2c has a whitelist of devices that should be consumed by hid-quirks so that there is one master list of devices to handoff between the drivers. Put the ids in a header file so that hid-quirks can consume it instead of duplicating the list. Signed-off-by: Jeffrey Hugo Acked-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 50 +----------------------- include/linux/input/elan-i2c-ids.h | 76 +++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 49 deletions(-) create mode 100644 include/linux/input/elan-i2c-ids.h (limited to 'drivers/input') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 65cd325eabc3..e2c824abd19c 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -1375,55 +1376,6 @@ static const struct i2c_device_id elan_id[] = { MODULE_DEVICE_TABLE(i2c, elan_id); #ifdef CONFIG_ACPI -static const struct acpi_device_id elan_acpi_id[] = { - { "ELAN0000", 0 }, - { "ELAN0100", 0 }, - { "ELAN0600", 0 }, - { "ELAN0601", 0 }, - { "ELAN0602", 0 }, - { "ELAN0603", 0 }, - { "ELAN0604", 0 }, - { "ELAN0605", 0 }, - { "ELAN0606", 0 }, - { "ELAN0607", 0 }, - { "ELAN0608", 0 }, - { "ELAN0609", 0 }, - { "ELAN060B", 0 }, - { "ELAN060C", 0 }, - { "ELAN060F", 0 }, - { "ELAN0610", 0 }, - { "ELAN0611", 0 }, - { "ELAN0612", 0 }, - { "ELAN0615", 0 }, - { "ELAN0616", 0 }, - { "ELAN0617", 0 }, - { "ELAN0618", 0 }, - { "ELAN0619", 0 }, - { "ELAN061A", 0 }, - { "ELAN061B", 0 }, - { "ELAN061C", 0 }, - { "ELAN061D", 0 }, - { "ELAN061E", 0 }, - { "ELAN061F", 0 }, - { "ELAN0620", 0 }, - { "ELAN0621", 0 }, - { "ELAN0622", 0 }, - { "ELAN0623", 0 }, - { "ELAN0624", 0 }, - { "ELAN0625", 0 }, - { "ELAN0626", 0 }, - { "ELAN0627", 0 }, - { "ELAN0628", 0 }, - { "ELAN0629", 0 }, - { "ELAN062A", 0 }, - { "ELAN062B", 0 }, - { "ELAN062C", 0 }, - { "ELAN062D", 0 }, - { "ELAN0631", 0 }, - { "ELAN0632", 0 }, - { "ELAN1000", 0 }, - { } -}; MODULE_DEVICE_TABLE(acpi, elan_acpi_id); #endif diff --git a/include/linux/input/elan-i2c-ids.h b/include/linux/input/elan-i2c-ids.h new file mode 100644 index 000000000000..ceabb01a6a7d --- /dev/null +++ b/include/linux/input/elan-i2c-ids.h @@ -0,0 +1,76 @@ +/* + * Elan I2C/SMBus Touchpad device whitelist + * + * Copyright (c) 2013 ELAN Microelectronics Corp. + * + * Author: æ維 (Duson Lin) + * Author: KT Liao + * Version: 1.6.3 + * + * Based on cyapa driver: + * copyright (c) 2011-2012 Cypress Semiconductor, Inc. + * copyright (c) 2011-2012 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Trademarks are the property of their respective owners. + */ + +#ifndef __ELAN_I2C_IDS_H +#define __ELAN_I2C_IDS_H + +#include + +static const struct acpi_device_id elan_acpi_id[] = { + { "ELAN0000", 0 }, + { "ELAN0100", 0 }, + { "ELAN0600", 0 }, + { "ELAN0601", 0 }, + { "ELAN0602", 0 }, + { "ELAN0603", 0 }, + { "ELAN0604", 0 }, + { "ELAN0605", 0 }, + { "ELAN0606", 0 }, + { "ELAN0607", 0 }, + { "ELAN0608", 0 }, + { "ELAN0609", 0 }, + { "ELAN060B", 0 }, + { "ELAN060C", 0 }, + { "ELAN060F", 0 }, + { "ELAN0610", 0 }, + { "ELAN0611", 0 }, + { "ELAN0612", 0 }, + { "ELAN0615", 0 }, + { "ELAN0616", 0 }, + { "ELAN0617", 0 }, + { "ELAN0618", 0 }, + { "ELAN0619", 0 }, + { "ELAN061A", 0 }, + { "ELAN061B", 0 }, + { "ELAN061C", 0 }, + { "ELAN061D", 0 }, + { "ELAN061E", 0 }, + { "ELAN061F", 0 }, + { "ELAN0620", 0 }, + { "ELAN0621", 0 }, + { "ELAN0622", 0 }, + { "ELAN0623", 0 }, + { "ELAN0624", 0 }, + { "ELAN0625", 0 }, + { "ELAN0626", 0 }, + { "ELAN0627", 0 }, + { "ELAN0628", 0 }, + { "ELAN0629", 0 }, + { "ELAN062A", 0 }, + { "ELAN062B", 0 }, + { "ELAN062C", 0 }, + { "ELAN062D", 0 }, + { "ELAN0631", 0 }, + { "ELAN0632", 0 }, + { "ELAN1000", 0 }, + { } +}; + +#endif /* __ELAN_I2C_IDS_H */ -- cgit v1.2.3-59-g8ed1b From 8d3c60c7688ec17c084417b7f6ac57a1d5f154e1 Mon Sep 17 00:00:00 2001 From: Alexander Tsoy Date: Sun, 30 Jun 2019 00:32:00 -0700 Subject: Input: joydev - extend absolute mouse detection Extend event signature matching to catch more input devices emulated by BMC firmwares, QEMU and VMware. Signed-off-by: Alexander Tsoy Signed-off-by: Dmitry Torokhov --- drivers/input/joydev.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 4c1e427dfabb..319c641edb93 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -812,6 +812,7 @@ static bool joydev_dev_is_blacklisted(struct input_dev *dev) static bool joydev_dev_is_absolute_mouse(struct input_dev *dev) { DECLARE_BITMAP(jd_scratch, KEY_CNT); + bool ev_match = false; BUILD_BUG_ON(ABS_CNT > KEY_CNT || EV_CNT > KEY_CNT); @@ -830,17 +831,36 @@ static bool joydev_dev_is_absolute_mouse(struct input_dev *dev) * considered to be an absolute mouse if the following is * true: * - * 1) Event types are exactly EV_ABS, EV_KEY and EV_SYN. + * 1) Event types are exactly + * EV_ABS, EV_KEY and EV_SYN + * or + * EV_ABS, EV_KEY, EV_SYN and EV_MSC + * or + * EV_ABS, EV_KEY, EV_SYN, EV_MSC and EV_REL. * 2) Absolute events are exactly ABS_X and ABS_Y. * 3) Keys are exactly BTN_LEFT, BTN_RIGHT and BTN_MIDDLE. * 4) Device is not on "Amiga" bus. */ bitmap_zero(jd_scratch, EV_CNT); + /* VMware VMMouse, HP ILO2 */ __set_bit(EV_ABS, jd_scratch); __set_bit(EV_KEY, jd_scratch); __set_bit(EV_SYN, jd_scratch); - if (!bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + ev_match = true; + + /* HP ILO2, AMI BMC firmware */ + __set_bit(EV_MSC, jd_scratch); + if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + ev_match = true; + + /* VMware Virtual USB Mouse, QEMU USB Tablet, ATEN BMC firmware */ + __set_bit(EV_REL, jd_scratch); + if (bitmap_equal(jd_scratch, dev->evbit, EV_CNT)) + ev_match = true; + + if (!ev_match) return false; bitmap_zero(jd_scratch, ABS_CNT); -- cgit v1.2.3-59-g8ed1b From 5cecc2bccc03f5f7b496b43a80fd5b768d44f13c Mon Sep 17 00:00:00 2001 From: Nathan Huckleberry Date: Mon, 1 Jul 2019 01:03:25 -0700 Subject: Input: atmel_mxt_ts - fix -Wunused-const-variable Clang produces the following warning drivers/input/touchscreen/atmel_mxt_ts.c:259:42: warning: unused variable 'mxt_video_fops' [-Wunused-const-variable] static const struct v4l2_file_operations mxt_video_fops = { Since mxt_video_fops is only used inside an ifdef. It should be moved inside the ifdef. Link: https://github.com/ClangBuiltLinux/linux/issues/527 Signed-off-by: Nathan Huckleberry Reviewed-by: Nick Desaulniers Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 5c63d25ce84e..d530aade0103 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -261,16 +261,6 @@ enum v4l_dbg_inputs { MXT_V4L_INPUT_MAX, }; -static const struct v4l2_file_operations mxt_video_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .unlocked_ioctl = video_ioctl2, - .read = vb2_fop_read, - .mmap = vb2_fop_mmap, - .poll = vb2_fop_poll, -}; - enum mxt_suspend_mode { MXT_SUSPEND_DEEP_SLEEP = 0, MXT_SUSPEND_T9_CTRL = 1, @@ -2223,6 +2213,16 @@ recheck: } #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 +static const struct v4l2_file_operations mxt_video_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x, unsigned int y) { -- cgit v1.2.3-59-g8ed1b From abbe3acd7d72ab4633ade6bd24e8306b67e0add3 Mon Sep 17 00:00:00 2001 From: Cole Rogers Date: Mon, 1 Jul 2019 00:47:48 -0700 Subject: Input: synaptics - enable SMBUS on T480 thinkpad trackpad Thinkpad t480 laptops had some touchpad features disabled, resulting in the loss of pinch to activities in GNOME, on wayland, and other touch gestures being slower. This patch adds the touchpad of the t480 to the smbus_pnp_ids whitelist to enable the extra features. In my testing this does not break suspend (on fedora, with wayland, and GNOME, using the rc-6 kernel), while also fixing the feature on a T480. Signed-off-by: Cole Rogers Acked-by: Benjamin Tissoires Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 8e6077d8e434..68fd8232d44c 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -176,6 +176,7 @@ static const char * const smbus_pnp_ids[] = { "LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */ "LEN0073", /* X1 Carbon G5 (Elantech) */ "LEN0092", /* X1 Carbon 6 */ + "LEN0093", /* T480 */ "LEN0096", /* X280 */ "LEN0097", /* X280 -> ALPS trackpoint */ "LEN200f", /* T450s */ -- cgit v1.2.3-59-g8ed1b From f0dd687815f9546860fc3ac4379d55da045942c9 Mon Sep 17 00:00:00 2001 From: Ian Ray Date: Thu, 4 Jul 2019 16:13:25 -0700 Subject: Input: atmel_mxt_ts - fix leak in mxt_update_cfg() Fix leak (whose magnitude is the configuration file size) when the CRCs match in mxt_update_cfg(). Signed-off-by: Ian Ray Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 5c63d25ce84e..8b536778f1d8 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1526,7 +1526,8 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) } else if (config_crc == data->config_crc) { dev_dbg(dev, "Config CRC 0x%06X: OK\n", data->config_crc); - return 0; + ret = 0; + goto release_raw; } else { dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n", data->config_crc, config_crc); -- cgit v1.2.3-59-g8ed1b From 904e782b07df1c685fdc8c4fc8d62e1d61f9ee32 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 4 Jul 2019 16:12:54 -0700 Subject: Input: max77650-onkey - add MODULE_ALIAS() Define a MODULE_ALIAS() in the input sub-driver for max77650 so that the appropriate module gets loaded together with the core mfd driver. Signed-off-by: Bartosz Golaszewski Signed-off-by: Dmitry Torokhov --- drivers/input/misc/max77650-onkey.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/misc/max77650-onkey.c b/drivers/input/misc/max77650-onkey.c index fbf6caab7217..4d875f2ac13d 100644 --- a/drivers/input/misc/max77650-onkey.c +++ b/drivers/input/misc/max77650-onkey.c @@ -119,3 +119,4 @@ module_platform_driver(max77650_onkey_driver); MODULE_DESCRIPTION("MAXIM 77650/77651 ONKEY driver"); MODULE_AUTHOR("Bartosz Golaszewski "); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:max77650-onkey"); -- cgit v1.2.3-59-g8ed1b From 17b92927f8531d1ceb7e4f10b75fc4b066ac77fc Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 22 Jun 2019 23:21:24 -0700 Subject: Input: edt-ft5x06 - simplify event reporting code Now that input_mt_report_slot_state() returns true if slot is active we no longer need a temporary for the slot state. Tested-by: Benoit Parrot Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index ec770226e119..3cc4341bbdff 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -229,7 +229,6 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) for (i = 0; i < tsdata->max_support_points; i++) { u8 *buf = &rdbuf[i * tplen + offset]; - bool down; type = buf[0] >> 6; /* ignore Reserved events */ @@ -247,16 +246,12 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) swap(x, y); id = (buf[2] >> 4) & 0x0f; - down = type != TOUCH_EVENT_UP; input_mt_slot(tsdata->input, id); - input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down); - - if (!down) - continue; - - touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y, - true); + if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, + type != TOUCH_EVENT_UP)) + touchscreen_report_pos(tsdata->input, &tsdata->prop, + x, y, true); } input_mt_report_pointer_emulation(tsdata->input, true); -- cgit v1.2.3-59-g8ed1b From 593fdd4fb44ef2cbf4ec53ec2c6eb60eb079bb4c Mon Sep 17 00:00:00 2001 From: "Enrico Weigelt, metux IT consult" Date: Sat, 6 Jul 2019 22:55:46 -0700 Subject: Input: gpio_keys_polled - allow specifying name of input device Instead of hardcoding the input name to the driver name ('gpio-keys-polled'), allow specifying the name of the device via "label" property. If the property is not present (nor name is set in board-supplied platform data), we'll default to the old name. Signed-off-by: Enrico Weigelt, metux IT consult Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys_polled.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index c4087be0c2e0..033655ab5ed0 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -168,6 +168,8 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev) pdata->rep = device_property_present(dev, "autorepeat"); device_property_read_u32(dev, "poll-interval", &pdata->poll_interval); + device_property_read_string(dev, "label", &pdata->name); + device_for_each_child_node(dev, child) { if (fwnode_property_read_u32(child, "linux,code", &button->code)) { @@ -270,7 +272,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) input = poll_dev->input; - input->name = pdev->name; + input->name = pdata->name ?: pdev->name; input->phys = DRV_NAME"/input0"; input->id.bustype = BUS_HOST; -- cgit v1.2.3-59-g8ed1b