diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-24 11:16:06 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-24 11:16:06 -0700 |
| commit | e1611017870fa1582b5ff9ec0edc09542318daa6 (patch) | |
| tree | faff3dcc5bd72395f407a01922ac5366f9a76cea | |
| parent | f0e6f20cb52b14c2c441f04e21cef0c95d498cac (diff) | |
| parent | 7a0e692a0381254b2f77c54dec100cd3325a6fdf (diff) | |
| download | lwn-e1611017870fa1582b5ff9ec0edc09542318daa6.tar.gz lwn-e1611017870fa1582b5ff9ec0edc09542318daa6.zip | |
Merge tag 'input-for-v7.2-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov:
- A new driver for Wacom W9000-series penabled touchscreens
- Updates to STM FTS driver adding support for reset line and preparing
the driver for STMFTS5 support
- Updates to RMI4 and IMS PCU drivers hardening the code
- Support for half-duplex mode restored in ADS7846 driver
- Updates to driver's device_id tables to use named initializers
- Removal of no longer used PCAP keys and touchscreen drivers (support
for the ezx series of phones was removed in 2022)
- Removal of xilinx_ps2 driver which is no longer used either
- Updates to userio to allow setting up additional serio port
characteristics (such as id, extra and proto)
- Assorted hardening and cleanup fixes for other drivers
* tag 'input-for-v7.2-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (72 commits)
Input: mms114 - fix touch indexing for MMS134S and MMS136
Input: elan_i2c - prevent division by zero and arithmetic underflow
Input: stop force-feedback timer when unregistering input devices
Input: iforce - bound the device-reported force-feedback effect index
Input: goodix - clamp the device-reported contact count
Input: mms114 - reject an oversized device packet size
Input: touchwin - reset the packet index on every complete packet
Input: rmi4 - update formatting in F12
Input: rmi4 - propagate proper error code in F12 sensor tuning
Input: rmi4 - simplify size calculations in F12
Input: rmi4 - use sizeof(*ptr) and idiomatic checks in f12 allocators
Input: rmi4 - use devm_kmalloc for F12 data packet buffer
Input: rmi4 - use flexible array member for IRQ masks in F12
Input: rmi4 - use unaligned access helpers in F12
Input: rmi4 - change reg_size type to u32
Input: rmi4 - refactor F12 probe function
Input: rmi4 - use kzalloc_flex() for struct rmi_function
Input: rmi4 - refactor function allocation and registration
Input: rmi4 - use local presence map in rmi_read_register_desc()
Input: rmi4 - fix limit in rmi_register_desc_has_subpacket()
...
110 files changed, 1673 insertions, 1501 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml index 12256ae7df90..64c4f24ea3dd 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.yaml @@ -40,6 +40,10 @@ properties: vdd-supply: description: Power supply + reset-gpios: + description: Reset GPIO (active-low) + maxItems: 1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/input/touchscreen/wacom,w9007a-lt03.yaml b/Documentation/devicetree/bindings/input/touchscreen/wacom,w9007a-lt03.yaml new file mode 100644 index 000000000000..6d1da6a435d3 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/wacom,w9007a-lt03.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/wacom,w9007a-lt03.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Wacom W9000-series penabled I2C touchscreen + +maintainers: + - Hendrik Noack <hendrik-noack@gmx.de> + +description: | + The W9000-series are penabled touchscreen controllers by Wacom. + + The firmware of controllers in different devices may differ. This can also + affect the controller's behavior. + +allOf: + - $ref: touchscreen.yaml# + +properties: + compatible: + enum: + - wacom,w9002 + - wacom,w9007a-lt03 + - wacom,w9007a-v1 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + vdd-supply: true + + flash-mode-gpios: + maxItems: 1 + + reset-gpios: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + digitizer@56 { + compatible = "wacom,w9007a-lt03"; + reg = <0x56>; + interrupt-parent = <&gpd1>; + interrupts = <1 IRQ_TYPE_EDGE_RISING>; + + vdd-supply = <&stylus_reg>; + + flash-mode-gpios = <&gpd1 3 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpx0 1 GPIO_ACTIVE_LOW>; + + touchscreen-x-mm = <216>; + touchscreen-y-mm = <135>; + touchscreen-inverted-x; + }; + }; diff --git a/Documentation/input/userio.rst b/Documentation/input/userio.rst index f780c77931fe..7aaaa629bde0 100644 --- a/Documentation/input/userio.rst +++ b/Documentation/input/userio.rst @@ -5,7 +5,7 @@ The userio Protocol =================== -:Copyright: |copy| 2015 Stephen Chandler Paul <thatslyude@gmail.com> +:Copyright: |copy| 2015 Lyude Paul <thatslyude@gmail.com> Sponsored by Red Hat @@ -66,8 +66,27 @@ USERIO_CMD_SET_PORT_TYPE ~~~~~~~~~~~~~~~~~~~~~~~~ Sets the type of port we're emulating, where ``data`` is the port type being -set. Can be any of the macros from <linux/serio.h>. For example: SERIO_8042 -would set the port type to be a normal PS/2 port. +set. Can be any of the serio type macros from <linux/serio.h>. For example: +SERIO_8042 would set the port type to be a normal PS/2 port. + +USERIO_CMD_SET_PORT_PROTO +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sets the protocol of port we're emulating, where ``data`` is the protocol being +set. Can be any of the serio proto macros from <linux/serio.h>. For example: +SERIO_IFORCE would set the port type to be an I-Force serial joystick. + +USERIO_CMD_SET_PORT_ID +~~~~~~~~~~~~~~~~~~~~~~ + +Sets the ``id`` value on the identification of port we're emulating, where +``data`` is the value being set. + +USERIO_CMD_SET_PORT_EXTRA +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sets the ``extra`` value on the identification of port we're emulating, where +``data`` is the value being set. USERIO_CMD_SEND_INTERRUPT ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/MAINTAINERS b/MAINTAINERS index 9b787bc2855f..75c6bf6699c9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -28731,7 +28731,7 @@ F: sound/drivers/pcmtest.c F: tools/testing/selftests/alsa/test-pcmtest-driver.c VIRTUAL SERIO DEVICE DRIVER -M: Stephen Chandler Paul <thatslyude@gmail.com> +M: Lyude Paul <thatslyude@gmail.com> S: Maintained F: drivers/input/serio/userio.c F: include/uapi/linux/userio.h diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c index 937370d04928..d1fefd1dfc0d 100644 --- a/drivers/input/ff-memless.c +++ b/drivers/input/ff-memless.c @@ -484,17 +484,31 @@ static void ml_ff_destroy(struct ff_device *ff) struct ml_device *ml = ff->private; /* - * Even though we stop all playing effects when tearing down - * an input device (via input_device_flush() that calls into - * input_ff_flush() that stops and erases all effects), we - * do not actually stop the timer, and therefore we should - * do it here. + * The timer is normally shut down in ml_ff_stop() when the device + * is unregistered. However, we still shut it down here as a safety + * net and for cases where the device was never registered (e.g. + * error paths during probe). */ - timer_delete_sync(&ml->timer); + timer_shutdown_sync(&ml->timer); kfree(ml->private); } +static void ml_ff_stop(struct ff_device *ff) +{ + struct ml_device *ml = ff->private; + + /* + * Even though we stop all playing effects when tearing down an + * input device (by the way of evdev calling input_flush_device() + * that calls into input_ff_flush() that stops and erases all + * effects), we do not actually shutdown the timer, and therefore + * we should do it here to prevent it firing after the input + * device is unregistered and its associated resources are freed. + */ + timer_shutdown_sync(&ml->timer); +} + /** * input_ff_create_memless() - create memoryless force-feedback device * @dev: input device supporting force-feedback @@ -529,6 +543,7 @@ int input_ff_create_memless(struct input_dev *dev, void *data, ff->playback = ml_ff_playback; ff->set_gain = ml_ff_set_gain; ff->destroy = ml_ff_destroy; + ff->stop = ml_ff_stop; /* we can emulate periodic effects with RUMBLE */ if (test_bit(FF_RUMBLE, ff->ffbit)) { diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c index fdece6ec1df3..f70a96c4f1fd 100644 --- a/drivers/input/gameport/ns558.c +++ b/drivers/input/gameport/ns558.c @@ -148,29 +148,29 @@ static int ns558_isa_probe(int io) #ifdef CONFIG_PNP static const struct pnp_device_id pnp_devids[] = { - { .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */ - { .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */ - { .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */ - { .id = "@P@2001", .driver_data = 0 }, /* ALS 120 */ - { .id = "ASB16fd", .driver_data = 0 }, /* AdLib NSC16 */ - { .id = "AZT3001", .driver_data = 0 }, /* AZT1008 */ - { .id = "CDC0001", .driver_data = 0 }, /* Opl3-SAx */ - { .id = "CSC0001", .driver_data = 0 }, /* CS4232 */ - { .id = "CSC000f", .driver_data = 0 }, /* CS4236 */ - { .id = "CSC0101", .driver_data = 0 }, /* CS4327 */ - { .id = "CTL7001", .driver_data = 0 }, /* SB16 */ - { .id = "CTL7002", .driver_data = 0 }, /* AWE64 */ - { .id = "CTL7005", .driver_data = 0 }, /* Vibra16 */ - { .id = "ENS2020", .driver_data = 0 }, /* SoundscapeVIVO */ - { .id = "ESS0001", .driver_data = 0 }, /* ES1869 */ - { .id = "ESS0005", .driver_data = 0 }, /* ES1878 */ - { .id = "ESS6880", .driver_data = 0 }, /* ES688 */ - { .id = "IBM0012", .driver_data = 0 }, /* CS4232 */ - { .id = "OPT0001", .driver_data = 0 }, /* OPTi Audio16 */ - { .id = "YMH0006", .driver_data = 0 }, /* Opl3-SA */ - { .id = "YMH0022", .driver_data = 0 }, /* Opl3-SAx */ - { .id = "PNPb02f", .driver_data = 0 }, /* Generic */ - { .id = "", }, + { .id = "@P@0001" }, /* ALS 100 */ + { .id = "@P@0020" }, /* ALS 200 */ + { .id = "@P@1001" }, /* ALS 100+ */ + { .id = "@P@2001" }, /* ALS 120 */ + { .id = "ASB16fd" }, /* AdLib NSC16 */ + { .id = "AZT3001" }, /* AZT1008 */ + { .id = "CDC0001" }, /* Opl3-SAx */ + { .id = "CSC0001" }, /* CS4232 */ + { .id = "CSC000f" }, /* CS4236 */ + { .id = "CSC0101" }, /* CS4327 */ + { .id = "CTL7001" }, /* SB16 */ + { .id = "CTL7002" }, /* AWE64 */ + { .id = "CTL7005" }, /* Vibra16 */ + { .id = "ENS2020" }, /* SoundscapeVIVO */ + { .id = "ESS0001" }, /* ES1869 */ + { .id = "ESS0005" }, /* ES1878 */ + { .id = "ESS6880" }, /* ES688 */ + { .id = "IBM0012" }, /* CS4232 */ + { .id = "OPT0001" }, /* OPTi Audio16 */ + { .id = "YMH0006" }, /* Opl3-SA */ + { .id = "YMH0022" }, /* Opl3-SAx */ + { .id = "PNPb02f" }, /* Generic */ + { } }; MODULE_DEVICE_TABLE(pnp, pnp_devids); diff --git a/drivers/input/input.c b/drivers/input/input.c index 39d9d2b1e3ca..cf6fecea79b8 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -2212,6 +2212,9 @@ static void __input_unregister_device(struct input_dev *dev) input_wakeup_procfs_readers(); } + if (dev->ff && dev->ff->stop) + dev->ff->stop(dev->ff); + device_del(&dev->dev); } diff --git a/drivers/input/joystick/adafruit-seesaw.c b/drivers/input/joystick/adafruit-seesaw.c index c248c15b849d..5835ed1e29e1 100644 --- a/drivers/input/joystick/adafruit-seesaw.c +++ b/drivers/input/joystick/adafruit-seesaw.c @@ -304,7 +304,7 @@ static int seesaw_probe(struct i2c_client *client) } static const struct i2c_device_id seesaw_id_table[] = { - { SEESAW_DEVICE_NAME }, + { .name = SEESAW_DEVICE_NAME }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(i2c, seesaw_id_table); diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c index 7b4d61626898..5fca92bf9df0 100644 --- a/drivers/input/joystick/as5011.c +++ b/drivers/input/joystick/as5011.c @@ -337,7 +337,7 @@ static void as5011_remove(struct i2c_client *client) } static const struct i2c_device_id as5011_id[] = { - { MODULE_DEVICE_ALIAS }, + { .name = MODULE_DEVICE_ALIAS }, { } }; MODULE_DEVICE_TABLE(i2c, as5011_id); diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index fd1cd731d781..effa76bfd8f9 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -186,14 +186,18 @@ void iforce_process_packet(struct iforce *iforce, /* 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 (i < IFORCE_EFFECTS_MAX) { + 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); } - } 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); } for (j = 3; j < len; j += 2) diff --git a/drivers/input/joystick/qwiic-joystick.c b/drivers/input/joystick/qwiic-joystick.c index 6f989d00d3ec..c471afc7862b 100644 --- a/drivers/input/joystick/qwiic-joystick.c +++ b/drivers/input/joystick/qwiic-joystick.c @@ -126,7 +126,7 @@ MODULE_DEVICE_TABLE(of, of_qwiic_match); #endif /* CONFIG_OF */ static const struct i2c_device_id qwiic_id_table[] = { - { KBUILD_MODNAME }, + { .name = KBUILD_MODNAME }, { } }; MODULE_DEVICE_TABLE(i2c, qwiic_id_table); diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 414fbef4abf9..8d14d0f69d4e 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -842,8 +842,8 @@ static int adp5588_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(adp5588_dev_pm_ops, adp5588_suspend, adp5588_resume); static const struct i2c_device_id adp5588_id[] = { - { "adp5588-keys" }, - { "adp5587-keys" }, + { .name = "adp5588-keys" }, + { .name = "adp5587-keys" }, { } }; MODULE_DEVICE_TABLE(i2c, adp5588_id); diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index 0c17cbaa3d27..2447c1ae2166 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c @@ -651,13 +651,13 @@ static const struct of_device_id cap11xx_dt_ids[] = { MODULE_DEVICE_TABLE(of, cap11xx_dt_ids); static const struct i2c_device_id cap11xx_i2c_ids[] = { - { "cap1106", (kernel_ulong_t)&cap1106_model }, - { "cap1126", (kernel_ulong_t)&cap1126_model }, - { "cap1188", (kernel_ulong_t)&cap1188_model }, - { "cap1203", (kernel_ulong_t)&cap1203_model }, - { "cap1206", (kernel_ulong_t)&cap1206_model }, - { "cap1293", (kernel_ulong_t)&cap1293_model }, - { "cap1298", (kernel_ulong_t)&cap1298_model }, + { .name = "cap1106", .driver_data = (kernel_ulong_t)&cap1106_model }, + { .name = "cap1126", .driver_data = (kernel_ulong_t)&cap1126_model }, + { .name = "cap1188", .driver_data = (kernel_ulong_t)&cap1188_model }, + { .name = "cap1203", .driver_data = (kernel_ulong_t)&cap1203_model }, + { .name = "cap1206", .driver_data = (kernel_ulong_t)&cap1206_model }, + { .name = "cap1293", .driver_data = (kernel_ulong_t)&cap1293_model }, + { .name = "cap1298", .driver_data = (kernel_ulong_t)&cap1298_model }, { } }; MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids); diff --git a/drivers/input/keyboard/cypress-sf.c b/drivers/input/keyboard/cypress-sf.c index 335b72efc5aa..4b2ae07f315c 100644 --- a/drivers/input/keyboard/cypress-sf.c +++ b/drivers/input/keyboard/cypress-sf.c @@ -209,7 +209,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops, cypress_sf_suspend, cypress_sf_resume); static const struct i2c_device_id cypress_sf_id_table[] = { - { CYPRESS_SF_DEV_NAME }, + { .name = CYPRESS_SF_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, cypress_sf_id_table); diff --git a/drivers/input/keyboard/dlink-dir685-touchkeys.c b/drivers/input/keyboard/dlink-dir685-touchkeys.c index 4184dd2eaeeb..bf94367f6b64 100644 --- a/drivers/input/keyboard/dlink-dir685-touchkeys.c +++ b/drivers/input/keyboard/dlink-dir685-touchkeys.c @@ -128,7 +128,7 @@ static int dir685_tk_probe(struct i2c_client *client) } static const struct i2c_device_id dir685_tk_id[] = { - { "dir685tk" }, + { .name = "dir685tk" }, { } }; MODULE_DEVICE_TABLE(i2c, dir685_tk_id); diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c index ca7ec054b1ce..ebd991de70f8 100644 --- a/drivers/input/keyboard/ipaq-micro-keys.c +++ b/drivers/input/keyboard/ipaq-micro-keys.c @@ -20,12 +20,6 @@ #include <linux/platform_device.h> #include <linux/mfd/ipaq-micro.h> -struct ipaq_micro_keys { - struct ipaq_micro *micro; - struct input_dev *input; - u16 *codes; -}; - static const u16 micro_keycodes[] = { KEY_RECORD, /* 1: Record button */ KEY_CALENDAR, /* 2: Calendar */ @@ -38,11 +32,20 @@ static const u16 micro_keycodes[] = { KEY_DOWN, /* 9: Down */ }; +struct ipaq_micro_keys { + struct ipaq_micro *micro; + struct input_dev *input; + u16 codes[ARRAY_SIZE(micro_keycodes)]; +}; + static void micro_key_receive(void *data, int len, unsigned char *msg) { struct ipaq_micro_keys *keys = data; int key, down; + if (len < 1) + return; + down = 0x80 & msg[0]; key = 0x7f & msg[0]; @@ -54,7 +57,7 @@ static void micro_key_receive(void *data, int len, unsigned char *msg) static void micro_key_start(struct ipaq_micro_keys *keys) { - guard(spinlock)(&keys->micro->lock); + guard(spinlock_irq)(&keys->micro->lock); keys->micro->key = micro_key_receive; keys->micro->key_data = keys; @@ -62,7 +65,7 @@ static void micro_key_start(struct ipaq_micro_keys *keys) static void micro_key_stop(struct ipaq_micro_keys *keys) { - guard(spinlock)(&keys->micro->lock); + guard(spinlock_irq)(&keys->micro->lock); keys->micro->key = NULL; keys->micro->key_data = NULL; @@ -102,10 +105,7 @@ static int micro_key_probe(struct platform_device *pdev) keys->input->keycodesize = sizeof(micro_keycodes[0]); keys->input->keycodemax = ARRAY_SIZE(micro_keycodes); - keys->codes = devm_kmemdup_array(&pdev->dev, micro_keycodes, keys->input->keycodemax, - keys->input->keycodesize, GFP_KERNEL); - if (!keys->codes) - return -ENOMEM; + memcpy(keys->codes, micro_keycodes, sizeof(keys->codes)); keys->input->keycode = keys->codes; diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index e19442c6f80f..8eac63b2d304 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -259,7 +259,7 @@ static void process_keys(struct lm8323_chip *lm) ret = lm8323_read(lm, LM8323_CMD_READ_FIFO, key_fifo, LM8323_FIFO_LEN); if (ret < 0) { - dev_err(&lm->client->dev, "Failed reading fifo \n"); + dev_err(&lm->client->dev, "Failed reading fifo\n"); return; } key_fifo[ret] = 0; @@ -788,7 +788,7 @@ static int lm8323_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(lm8323_pm_ops, lm8323_suspend, lm8323_resume); static const struct i2c_device_id lm8323_id[] = { - { "lm8323" }, + { .name = "lm8323" }, { } }; diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c index 384baabf9924..34be5b2e476d 100644 --- a/drivers/input/keyboard/lm8333.c +++ b/drivers/input/keyboard/lm8333.c @@ -194,7 +194,7 @@ static int lm8333_probe(struct i2c_client *client) } static const struct i2c_device_id lm8333_id[] = { - { "lm8333" }, + { .name = "lm8333" }, { } }; MODULE_DEVICE_TABLE(i2c, lm8333_id); diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index c10726b5e4d1..f8fb44bc4915 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -270,7 +270,7 @@ static int max7359_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(max7359_pm, max7359_suspend, max7359_resume); static const struct i2c_device_id max7359_ids[] = { - { "max7359" }, + { .name = "max7359" }, { } }; MODULE_DEVICE_TABLE(i2c, max7359_ids); diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 47edc161ec77..a1a102855590 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -322,7 +322,7 @@ static int mpr_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume); static const struct i2c_device_id mpr121_id[] = { - { "mpr121_touchkey" }, + { .name = "mpr121_touchkey" }, { } }; MODULE_DEVICE_TABLE(i2c, mpr121_id); diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index b255b997e279..e31cb115a954 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -233,7 +233,7 @@ static int qt1070_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(qt1070_pm_ops, qt1070_suspend, qt1070_resume); static const struct i2c_device_id qt1070_id[] = { - { "qt1070" }, + { .name = "qt1070" }, { } }; MODULE_DEVICE_TABLE(i2c, qt1070_id); diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 53f5255fd19d..e64adaca10ff 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -393,7 +393,7 @@ static int qt2160_probe(struct i2c_client *client) } static const struct i2c_device_id qt2160_idtable[] = { - { "qt2160" }, + { .name = "qt2160" }, { } }; diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 68c0afafee7b..eb5be644f236 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -354,7 +354,7 @@ static int tca8418_keypad_probe(struct i2c_client *client) } static const struct i2c_device_id tca8418_id[] = { - { "tca8418", 8418, }, + { .name = "tca8418", .driver_data = 8418 }, { } }; MODULE_DEVICE_TABLE(i2c, tca8418_id); diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c index 55d699d9037d..967bbe553c06 100644 --- a/drivers/input/keyboard/tm2-touchkey.c +++ b/drivers/input/keyboard/tm2-touchkey.c @@ -326,7 +326,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops, tm2_touchkey_suspend, tm2_touchkey_resume); static const struct i2c_device_id tm2_touchkey_id_table[] = { - { TM2_TOUCHKEY_DEV_NAME }, + { .name = TM2_TOUCHKEY_DEV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 94a753fcb64f..1f6c57dba030 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -745,16 +745,6 @@ config INPUT_WM831X_ON To compile this driver as a module, choose M here: the module will be called wm831x_on. -config INPUT_PCAP - tristate "Motorola EZX PCAP misc input events" - depends on EZX_PCAP - help - Say Y here if you want to use Power key and Headphone button - on Motorola EZX phones. - - To compile this driver as a module, choose M here: the - module will be called pcap_keys. - config INPUT_ADXL34X tristate "Analog Devices ADXL34x Three-Axis Digital Accelerometer" default n diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 415fc4e2918b..2281d6803fce 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -60,7 +60,6 @@ obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o obj-$(CONFIG_INPUT_MMA8450) += mma8450.o obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o -obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_PF1550_ONKEY) += pf1550-onkey.o diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index 2adb7a058362..c3cb561512ed 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -72,11 +72,11 @@ static int ad714x_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id ad714x_id[] = { - { "ad7142_captouch" }, - { "ad7143_captouch" }, - { "ad7147_captouch" }, - { "ad7147a_captouch" }, - { "ad7148_captouch" }, + { .name = "ad7142_captouch" }, + { .name = "ad7143_captouch" }, + { .name = "ad7147_captouch" }, + { .name = "ad7147a_captouch" }, + { .name = "ad7148_captouch" }, { } }; MODULE_DEVICE_TABLE(i2c, ad714x_id); diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c index 5ea0ce42a507..84665c612f3c 100644 --- a/drivers/input/misc/adxl34x-i2c.c +++ b/drivers/input/misc/adxl34x-i2c.c @@ -96,7 +96,7 @@ static int adxl34x_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl34x_id[] = { - { "adxl34x" }, + { .name = "adxl34x" }, { } }; diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c index d43aebd785b7..3eb02a64acfb 100644 --- a/drivers/input/misc/apanel.c +++ b/drivers/input/misc/apanel.c @@ -192,7 +192,7 @@ static void apanel_shutdown(struct i2c_client *client) } static const struct i2c_device_id apanel_id[] = { - { "fujitsu_apanel" }, + { .name = "fujitsu_apanel" }, { } }; MODULE_DEVICE_TABLE(i2c, apanel_id); diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c index 835ad45a9d65..5805a1a3bb05 100644 --- a/drivers/input/misc/atlas_btns.c +++ b/drivers/input/misc/atlas_btns.c @@ -15,17 +15,18 @@ #include <linux/types.h> #include <linux/acpi.h> #include <linux/platform_device.h> -#include <linux/uaccess.h> #define ACPI_ATLAS_NAME "Atlas ACPI" -#define ACPI_ATLAS_CLASS "Atlas" -static unsigned short atlas_keymap[16]; -static struct input_dev *input_dev; +struct atlas_btns { + struct input_dev *input_dev; + unsigned short keymap[16]; +}; /* button handling code */ static acpi_status acpi_atlas_button_setup(acpi_handle region_handle, - u32 function, void *handler_context, void **return_context) + u32 function, void *handler_context, + void **return_context) { *return_context = (function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL; @@ -34,33 +35,37 @@ static acpi_status acpi_atlas_button_setup(acpi_handle region_handle, } static acpi_status acpi_atlas_button_handler(u32 function, - acpi_physical_address address, - u32 bit_width, u64 *value, - void *handler_context, void *region_context) + acpi_physical_address address, + u32 bit_width, u64 *value, + void *handler_context, + void *region_context) { - acpi_status status; + struct atlas_btns *atlas = region_context; if (function == ACPI_WRITE) { int code = address & 0x0f; int key_down = !(address & 0x10); - input_event(input_dev, EV_MSC, MSC_SCAN, code); - input_report_key(input_dev, atlas_keymap[code], key_down); - input_sync(input_dev); + input_event(atlas->input_dev, EV_MSC, MSC_SCAN, code); + input_report_key(atlas->input_dev, atlas->keymap[code], + key_down); + input_sync(atlas->input_dev); - status = AE_OK; - } else { - pr_warn("shrugged on unexpected function: function=%x,address=%lx,value=%x\n", - function, (unsigned long)address, (u32)*value); - status = AE_BAD_PARAMETER; + return AE_OK; } - return status; + dev_warn(atlas->input_dev->dev.parent, + "unexpected function: function=%x,address=%lx,value=%x\n", + function, (unsigned long)address, (u32)*value); + + return AE_BAD_PARAMETER; } static int atlas_acpi_button_probe(struct platform_device *pdev) { struct acpi_device *device; + struct atlas_btns *atlas; + struct input_dev *input_dev; acpi_status status; int i; int err; @@ -69,65 +74,62 @@ static int atlas_acpi_button_probe(struct platform_device *pdev) if (!device) return -ENODEV; - input_dev = input_allocate_device(); - if (!input_dev) { - pr_err("unable to allocate input device\n"); + atlas = devm_kzalloc(&pdev->dev, sizeof(*atlas), GFP_KERNEL); + if (!atlas) return -ENOMEM; - } + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) + return -ENOMEM; + + atlas->input_dev = input_dev; input_dev->name = "Atlas ACPI button driver"; input_dev->phys = "ASIM0000/atlas/input0"; input_dev->id.bustype = BUS_HOST; - input_dev->keycode = atlas_keymap; - input_dev->keycodesize = sizeof(unsigned short); - input_dev->keycodemax = ARRAY_SIZE(atlas_keymap); + input_dev->keycode = atlas->keymap; + input_dev->keycodesize = sizeof(atlas->keymap[0]); + input_dev->keycodemax = ARRAY_SIZE(atlas->keymap); input_set_capability(input_dev, EV_MSC, MSC_SCAN); - __set_bit(EV_KEY, input_dev->evbit); - for (i = 0; i < ARRAY_SIZE(atlas_keymap); i++) { + for (i = 0; i < ARRAY_SIZE(atlas->keymap); i++) { if (i < 9) { - atlas_keymap[i] = KEY_F1 + i; - __set_bit(KEY_F1 + i, input_dev->keybit); - } else - atlas_keymap[i] = KEY_RESERVED; + atlas->keymap[i] = KEY_F1 + i; + input_set_capability(input_dev, EV_KEY, KEY_F1 + i); + } else { + atlas->keymap[i] = KEY_RESERVED; + } } err = input_register_device(input_dev); - if (err) { - pr_err("couldn't register input device\n"); - input_free_device(input_dev); - return err; - } + if (err) + return dev_err_probe(&pdev->dev, err, + "couldn't register input device\n"); /* hookup button handler */ status = acpi_install_address_space_handler(device->handle, - 0x81, &acpi_atlas_button_handler, - &acpi_atlas_button_setup, device); - if (ACPI_FAILURE(status)) { - pr_err("error installing addr spc handler\n"); - input_unregister_device(input_dev); - err = -EINVAL; - } + 0x81, + &acpi_atlas_button_handler, + &acpi_atlas_button_setup, + atlas); + if (ACPI_FAILURE(status)) + return dev_err_probe(&pdev->dev, -EINVAL, + "error installing addr spc handler\n"); - return err; + return 0; } static void atlas_acpi_button_remove(struct platform_device *pdev) { struct acpi_device *device = ACPI_COMPANION(&pdev->dev); - acpi_status status; - status = acpi_remove_address_space_handler(device->handle, - 0x81, &acpi_atlas_button_handler); - if (ACPI_FAILURE(status)) - pr_err("error removing addr spc handler\n"); - - input_unregister_device(input_dev); + acpi_remove_address_space_handler(device->handle, 0x81, + &acpi_atlas_button_handler); } static const struct acpi_device_id atlas_device_ids[] = { - {"ASIM0000", 0}, - {"", 0}, + { "ASIM0000" }, + { "" } }; MODULE_DEVICE_TABLE(acpi, atlas_device_ids); @@ -144,4 +146,3 @@ module_platform_driver(atlas_acpi_driver); MODULE_AUTHOR("Jaya Kumar"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Atlas button driver"); - diff --git a/drivers/input/misc/atmel_captouch.c b/drivers/input/misc/atmel_captouch.c index f9744cf0ca80..fc4abea68479 100644 --- a/drivers/input/misc/atmel_captouch.c +++ b/drivers/input/misc/atmel_captouch.c @@ -257,7 +257,7 @@ static const struct of_device_id atmel_captouch_of_id[] = { MODULE_DEVICE_TABLE(of, atmel_captouch_of_id); static const struct i2c_device_id atmel_captouch_id[] = { - { "atmel_captouch" }, + { .name = "atmel_captouch" }, { } }; MODULE_DEVICE_TABLE(i2c, atmel_captouch_id); diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index 4cc2a0dcaa75..0ef282932095 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -536,9 +536,9 @@ static int __maybe_unused bma150_resume(struct device *dev) static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL); static const struct i2c_device_id bma150_id[] = { - { "bma150" }, - { "smb380" }, - { "bma023" }, + { .name = "bma150" }, + { .name = "smb380" }, + { .name = "bma023" }, { } }; diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c index f892c5b1e4bd..14be6d4682d0 100644 --- a/drivers/input/misc/cma3000_d0x_i2c.c +++ b/drivers/input/misc/cma3000_d0x_i2c.c @@ -90,7 +90,7 @@ static const struct dev_pm_ops cma3000_i2c_pm_ops = { }; static const struct i2c_device_id cma3000_i2c_id[] = { - { "cma3000_d01" }, + { .name = "cma3000_d01" }, { } }; diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c index e4a605c6af15..77fcf868dca2 100644 --- a/drivers/input/misc/da7280.c +++ b/drivers/input/misc/da7280.c @@ -1305,7 +1305,7 @@ MODULE_DEVICE_TABLE(of, da7280_of_match); #endif static const struct i2c_device_id da7280_i2c_id[] = { - { "da7280", }, + { .name = "da7280" }, { } }; MODULE_DEVICE_TABLE(i2c, da7280_i2c_id); diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index e2089d6ac850..6c5c4c53753b 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -630,10 +630,10 @@ static int drv260x_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume); static const struct i2c_device_id drv260x_id[] = { - { "drv2604" }, - { "drv2604l" }, - { "drv2605" }, - { "drv2605l" }, + { .name = "drv2604" }, + { .name = "drv2604l" }, + { .name = "drv2605" }, + { .name = "drv2605l" }, { } }; MODULE_DEVICE_TABLE(i2c, drv260x_id); diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index 46842cb8ddd7..4f8c1f69aa63 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -281,7 +281,7 @@ static int drv2665_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume); static const struct i2c_device_id drv2665_id[] = { - { "drv2665" }, + { .name = "drv2665" }, { } }; MODULE_DEVICE_TABLE(i2c, drv2665_id); diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index f952a24ec595..97309984fa7c 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -458,7 +458,7 @@ static int drv2667_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume); static const struct i2c_device_id drv2667_id[] = { - { "drv2667" }, + { .name = "drv2667" }, { } }; MODULE_DEVICE_TABLE(i2c, drv2667_id); diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c index 7a1cb9333f53..b1ff8c70877f 100644 --- a/drivers/input/misc/ims-pcu.c +++ b/drivers/input/misc/ims-pcu.c @@ -14,6 +14,7 @@ #include <linux/leds.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/sysfs.h> #include <linux/types.h> #include <linux/usb/input.h> #include <linux/usb/cdc.h> @@ -406,7 +407,16 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu) static void ims_pcu_report_events(struct ims_pcu *pcu) { - u32 data = get_unaligned_be32(&pcu->read_buf[3]); + u32 data; + + /* 6-axis setting (1 byte) + button data + checksum */ + if (pcu->read_pos < IMS_PCU_DATA_OFFSET + 1 + sizeof(data) + 1) { + dev_warn(pcu->dev, "Short buttons report: %d bytes\n", + pcu->read_pos); + return; + } + + data = get_unaligned_be32(&pcu->read_buf[IMS_PCU_DATA_OFFSET + 1]); ims_pcu_buttons_report(pcu, data & ~IMS_PCU_GAMEPAD_MASK); if (pcu->gamepad) @@ -440,7 +450,7 @@ static void ims_pcu_handle_response(struct ims_pcu *pcu) static void ims_pcu_reset_packet(struct ims_pcu *pcu) { - pcu->have_stx = true; + pcu->have_stx = false; pcu->have_dle = false; pcu->read_pos = 0; pcu->check_sum = 0; @@ -686,11 +696,19 @@ static int __ims_pcu_execute_bl_command(struct ims_pcu *pcu, return error; } - if (expected_response && pcu->cmd_buf[2] != expected_response) { - dev_err(pcu->dev, - "Unexpected response from bootloader: 0x%02x, wanted 0x%02x\n", - pcu->cmd_buf[2], expected_response); - return -EINVAL; + if (expected_response) { + if (pcu->cmd_buf_len < 3) { + dev_err(pcu->dev, "Short response from bootloader: %d bytes\n", + pcu->cmd_buf_len); + return -EIO; + } + + if (pcu->cmd_buf[2] != expected_response) { + dev_err(pcu->dev, + "Unexpected response from bootloader: 0x%02x, wanted 0x%02x\n", + pcu->cmd_buf[2], expected_response); + return -EINVAL; + } } return 0; @@ -718,6 +736,12 @@ static int ims_pcu_get_info(struct ims_pcu *pcu) return error; } + if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + IMS_PCU_SET_INFO_SIZE + 1) { + dev_err(pcu->dev, "Short GET_INFO response: %d bytes\n", + pcu->cmd_buf_len); + return -EIO; + } + memcpy(pcu->part_number, &pcu->cmd_buf[IMS_PCU_INFO_PART_OFFSET], sizeof(pcu->part_number)); @@ -815,6 +839,12 @@ static int ims_pcu_verify_block(struct ims_pcu *pcu, return error; } + if (pcu->cmd_buf_len < IMS_PCU_BL_DATA_OFFSET + sizeof(*fragment) + len + 1) { + dev_err(pcu->dev, "Short READ_APP response: %d bytes\n", + pcu->cmd_buf_len); + return -EIO; + } + fragment = (void *)&pcu->cmd_buf[IMS_PCU_BL_DATA_OFFSET]; if (get_unaligned_le32(&fragment->addr) != addr || fragment->len != len) { @@ -934,9 +964,10 @@ out: return retval; } -static void ims_pcu_process_async_firmware(const struct firmware *fw, +static void ims_pcu_process_async_firmware(const struct firmware *_fw, void *context) { + const struct firmware *fw __free(firmware) = _fw; struct ims_pcu *pcu = context; int error; @@ -956,8 +987,6 @@ static void ims_pcu_process_async_firmware(const struct firmware *fw, scoped_guard(mutex, &pcu->cmd_mutex) ims_pcu_handle_firmware_update(pcu, fw); - release_firmware(fw); - out: complete(&pcu->async_firmware_done); } @@ -1009,6 +1038,10 @@ ims_pcu_backlight_get_brightness(struct led_classdev *cdev) error); /* Assume the LED is OFF */ brightness = LED_OFF; + } else if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 2 + 1) { + dev_err(pcu->dev, "Short GET_BRIGHTNESS response: %d bytes\n", + pcu->cmd_buf_len); + brightness = LED_OFF; } else { brightness = get_unaligned_le16(&pcu->cmd_buf[IMS_PCU_DATA_OFFSET]); @@ -1153,6 +1186,8 @@ static ssize_t ims_pcu_reset_device(struct device *dev, dev_info(pcu->dev, "Attempting to reset device\n"); + guard(mutex)(&pcu->cmd_mutex); + error = ims_pcu_execute_command(pcu, PCU_RESET, &reset_byte, 1); if (error) { dev_info(pcu->dev, @@ -1249,6 +1284,9 @@ static umode_t ims_pcu_is_attr_visible(struct kobject *kobj, struct ims_pcu *pcu = usb_get_intfdata(intf); umode_t mode = attr->mode; + if (intf != pcu->ctrl_intf) + return 0; + if (pcu->bootloader_mode) { if (attr != &dev_attr_update_firmware_status.attr && attr != &dev_attr_update_firmware.attr && @@ -1282,6 +1320,12 @@ static int ims_pcu_read_ofn_config(struct ims_pcu *pcu, u8 addr, u8 *data) if (error) return error; + if (pcu->cmd_buf_len < OFN_REG_RESULT_OFFSET + 2 + 1) { + dev_err(pcu->dev, "Short OFN_GET_CONFIG response: %d bytes\n", + pcu->cmd_buf_len); + return -EIO; + } + result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET); if (result < 0) return -EIO; @@ -1302,6 +1346,12 @@ static int ims_pcu_write_ofn_config(struct ims_pcu *pcu, u8 addr, u8 data) if (error) return error; + if (pcu->cmd_buf_len < OFN_REG_RESULT_OFFSET + 2 + 1) { + dev_err(pcu->dev, "Short OFN_SET_CONFIG response: %d bytes\n", + pcu->cmd_buf_len); + return -EIO; + } + result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET); if (result < 0) return -EIO; @@ -1488,6 +1538,9 @@ static umode_t ims_pcu_ofn_is_attr_visible(struct kobject *kobj, struct ims_pcu *pcu = usb_get_intfdata(intf); umode_t mode = attr->mode; + if (intf != pcu->ctrl_intf) + return SYSFS_GROUP_INVISIBLE; + /* * PCU-B devices, both GEN_1 and GEN_2 do not have OFN sensor. */ @@ -1528,7 +1581,7 @@ static void ims_pcu_irq(struct urb *urb) } dev_dbg(pcu->dev, "%s: received %d: %*ph\n", __func__, - urb->actual_length, urb->actual_length, pcu->urb_in_buf); + urb->actual_length, urb->actual_length, urb->transfer_buffer); if (urb == pcu->urb_in) ims_pcu_process_data(pcu, urb); @@ -1656,8 +1709,9 @@ ims_pcu_get_cdc_union_desc(struct usb_interface *intf) while (buflen >= sizeof(*union_desc)) { union_desc = (struct usb_cdc_union_desc *)buf; - if (union_desc->bLength > buflen) { - dev_err(&intf->dev, "Too large descriptor\n"); + if (union_desc->bLength < 2 || union_desc->bLength > buflen) { + dev_err(&intf->dev, "Invalid descriptor length: %d\n", + union_desc->bLength); return NULL; } @@ -1693,7 +1747,7 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc pcu->ctrl_intf = usb_ifnum_to_if(pcu->udev, union_desc->bMasterInterface0); - if (!pcu->ctrl_intf) + if (pcu->ctrl_intf != intf) return -EINVAL; alt = pcu->ctrl_intf->cur_altsetting; @@ -1702,6 +1756,12 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc return -ENODEV; pcu->ep_ctrl = &alt->endpoint[0].desc; + if (!usb_endpoint_is_int_in(pcu->ep_ctrl)) { + dev_err(pcu->dev, + "Control endpoint is not INTERRUPT IN\n"); + return -EINVAL; + } + pcu->max_ctrl_size = usb_endpoint_maxp(pcu->ep_ctrl); pcu->data_intf = usb_ifnum_to_if(pcu->udev, @@ -1783,11 +1843,16 @@ static void ims_pcu_stop_io(struct ims_pcu *pcu) static int ims_pcu_line_setup(struct ims_pcu *pcu) { struct usb_host_interface *interface = pcu->ctrl_intf->cur_altsetting; - struct usb_cdc_line_coding *line = (void *)pcu->cmd_buf; + struct usb_cdc_line_coding *line __free(kfree) = + kmalloc(sizeof(*line), GFP_KERNEL); int error; - memset(line, 0, sizeof(*line)); + if (!line) + return -ENOMEM; + line->dwDTERate = cpu_to_le32(57600); + line->bCharFormat = USB_CDC_1_STOP_BITS; + line->bParityType = USB_CDC_NO_PARITY; line->bDataBits = 8; error = usb_control_msg(pcu->udev, usb_sndctrlpipe(pcu->udev, 0), @@ -1831,6 +1896,12 @@ static int ims_pcu_get_device_info(struct ims_pcu *pcu) return error; } + if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 6 + 1) { + dev_err(pcu->dev, "Short GET_FW_VERSION response: %d bytes\n", + pcu->cmd_buf_len); + return -EIO; + } + snprintf(pcu->fw_version, sizeof(pcu->fw_version), "%02d%02d%02d%02d.%c%c", pcu->cmd_buf[2], pcu->cmd_buf[3], pcu->cmd_buf[4], pcu->cmd_buf[5], @@ -1843,6 +1914,12 @@ static int ims_pcu_get_device_info(struct ims_pcu *pcu) return error; } + if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 6 + 1) { + dev_err(pcu->dev, "Short GET_BL_VERSION response: %d bytes\n", + pcu->cmd_buf_len); + return -EIO; + } + snprintf(pcu->bl_version, sizeof(pcu->bl_version), "%02d%02d%02d%02d.%c%c", pcu->cmd_buf[2], pcu->cmd_buf[3], pcu->cmd_buf[4], pcu->cmd_buf[5], @@ -1855,6 +1932,12 @@ static int ims_pcu_get_device_info(struct ims_pcu *pcu) return error; } + if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 1 + 1) { + dev_err(pcu->dev, "Short RESET_REASON response: %d bytes\n", + pcu->cmd_buf_len); + return -EIO; + } + snprintf(pcu->reset_reason, sizeof(pcu->reset_reason), "%02x", pcu->cmd_buf[IMS_PCU_DATA_OFFSET]); @@ -1881,6 +1964,12 @@ static int ims_pcu_identify_type(struct ims_pcu *pcu, u8 *device_id) return error; } + if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 1 + 1) { + dev_err(pcu->dev, "Short GET_DEVICE_ID response: %d bytes\n", + pcu->cmd_buf_len); + return -EIO; + } + *device_id = pcu->cmd_buf[IMS_PCU_DATA_OFFSET]; dev_dbg(pcu->dev, "Detected device ID: %d\n", *device_id); @@ -1972,6 +2061,12 @@ static int ims_pcu_init_bootloader_mode(struct ims_pcu *pcu) return error; } + if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 15 + 4 + 1) { + dev_err(pcu->dev, "Short QUERY_DEVICE response: %d bytes\n", + pcu->cmd_buf_len); + return -EIO; + } + pcu->fw_start_addr = get_unaligned_le32(&pcu->cmd_buf[IMS_PCU_DATA_OFFSET + 11]); pcu->fw_end_addr = @@ -2071,7 +2166,6 @@ err_free_mem: static void ims_pcu_disconnect(struct usb_interface *intf) { struct ims_pcu *pcu = usb_get_intfdata(intf); - struct usb_host_interface *alt = intf->cur_altsetting; usb_set_intfdata(intf, NULL); @@ -2079,7 +2173,7 @@ static void ims_pcu_disconnect(struct usb_interface *intf) * See if we are dealing with control or data interface. The cleanup * happens when we unbind primary (control) interface. */ - if (alt->desc.bInterfaceClass != USB_CLASS_COMM) + if (intf != pcu->ctrl_intf) return; ims_pcu_stop_io(pcu); @@ -2090,6 +2184,7 @@ static void ims_pcu_disconnect(struct usb_interface *intf) ims_pcu_destroy_application_mode(pcu); ims_pcu_buffers_free(pcu); + usb_driver_release_interface(&ims_pcu_driver, pcu->data_intf); kfree(pcu); } diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index eb9788ea5215..6b3495ba5763 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -525,7 +525,7 @@ static int kxtj9_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume); static const struct i2c_device_id kxtj9_id[] = { - { NAME }, + { .name = NAME }, { } }; diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c index 0c661140fb88..a2888d1ff58f 100644 --- a/drivers/input/misc/mma8450.c +++ b/drivers/input/misc/mma8450.c @@ -200,7 +200,7 @@ static int mma8450_probe(struct i2c_client *c) } static const struct i2c_device_id mma8450_id[] = { - { MMA8450_DRV_NAME }, + { .name = MMA8450_DRV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, mma8450_id); diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c deleted file mode 100644 index b19899b50d0b..000000000000 --- a/drivers/input/misc/pcap_keys.c +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Input driver for PCAP events: - * * Power key - * * Headphone button - * - * Copyright (c) 2008,2009 Ilya Petrov <ilya.muromec@gmail.com> - */ - -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/input.h> -#include <linux/mfd/ezx-pcap.h> -#include <linux/slab.h> - -struct pcap_keys { - struct pcap_chip *pcap; - struct input_dev *input; -}; - -/* PCAP2 interrupts us on keypress */ -static irqreturn_t pcap_keys_handler(int irq, void *_pcap_keys) -{ - struct pcap_keys *pcap_keys = _pcap_keys; - int pirq = irq_to_pcap(pcap_keys->pcap, irq); - u32 pstat; - - ezx_pcap_read(pcap_keys->pcap, PCAP_REG_PSTAT, &pstat); - pstat &= 1 << pirq; - - switch (pirq) { - case PCAP_IRQ_ONOFF: - input_report_key(pcap_keys->input, KEY_POWER, !pstat); - break; - case PCAP_IRQ_MIC: - input_report_key(pcap_keys->input, KEY_HP, !pstat); - break; - } - - input_sync(pcap_keys->input); - - return IRQ_HANDLED; -} - -static int pcap_keys_probe(struct platform_device *pdev) -{ - int err = -ENOMEM; - struct pcap_keys *pcap_keys; - struct input_dev *input_dev; - - pcap_keys = kmalloc_obj(*pcap_keys); - if (!pcap_keys) - return err; - - pcap_keys->pcap = dev_get_drvdata(pdev->dev.parent); - - input_dev = input_allocate_device(); - if (!input_dev) - goto fail; - - pcap_keys->input = input_dev; - - platform_set_drvdata(pdev, pcap_keys); - input_dev->name = pdev->name; - input_dev->phys = "pcap-keys/input0"; - input_dev->id.bustype = BUS_HOST; - input_dev->dev.parent = &pdev->dev; - - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(KEY_POWER, input_dev->keybit); - __set_bit(KEY_HP, input_dev->keybit); - - err = input_register_device(input_dev); - if (err) - goto fail_allocate; - - err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), - pcap_keys_handler, 0, "Power key", pcap_keys); - if (err) - goto fail_register; - - err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), - pcap_keys_handler, 0, "Headphone button", pcap_keys); - if (err) - goto fail_pwrkey; - - return 0; - -fail_pwrkey: - free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); -fail_register: - input_unregister_device(input_dev); - goto fail; -fail_allocate: - input_free_device(input_dev); -fail: - kfree(pcap_keys); - return err; -} - -static void pcap_keys_remove(struct platform_device *pdev) -{ - struct pcap_keys *pcap_keys = platform_get_drvdata(pdev); - - free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys); - free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), pcap_keys); - - input_unregister_device(pcap_keys->input); - kfree(pcap_keys); -} - -static struct platform_driver pcap_keys_device_driver = { - .probe = pcap_keys_probe, - .remove = pcap_keys_remove, - .driver = { - .name = "pcap-keys", - } -}; -module_platform_driver(pcap_keys_device_driver); - -MODULE_DESCRIPTION("Motorola PCAP2 input events driver"); -MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pcap_keys"); diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index 14fc6c6cf699..a831fcc851f7 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -189,7 +189,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(pcf8574_kp_pm_ops, pcf8574_kp_suspend, pcf8574_kp_resume); static const struct i2c_device_id pcf8574_kp_id[] = { - { DRV_NAME }, + { .name = DRV_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id); diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c index 8786ed8b3565..560f895a00cd 100644 --- a/drivers/input/misc/yealink.c +++ b/drivers/input/misc/yealink.c @@ -22,15 +22,6 @@ * - Olivier Vandorpe, for providing the usbb2k-api. * - Martin Diehl, for spotting my memory allocation bug. * - * History: - * 20050527 henk First version, functional keyboard. Keyboard events - * will pop-up on the ../input/eventX bus. - * 20050531 henk Added led, LCD, dialtone and sysfs interface. - * 20050610 henk Cleanups, make it ready for public consumption. - * 20050630 henk Cleanups, fixes in response to comments. - * 20050701 henk sysfs write serialisation, fix potential unload races - * 20050801 henk Added ringtone, restructure USB - * 20050816 henk Merge 2.6.13-rc6 */ #include <linux/kernel.h> diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 6e0d956617a1..47000c30e4d8 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -1456,7 +1456,7 @@ static const struct dev_pm_ops cyapa_pm_ops = { }; static const struct i2c_device_id cyapa_id_table[] = { - { "cyapa" }, + { .name = "cyapa" }, { } }; MODULE_DEVICE_TABLE(i2c, cyapa_id_table); diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 5cba02a156ce..f93dd545d66b 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -428,8 +428,17 @@ static int elan_query_device_parameters(struct elan_tp_data *data) if (error) return error; } - data->width_x = data->max_x / x_traces; - data->width_y = data->max_y / y_traces; + + if (!x_traces || !y_traces) { + dev_warn(&client->dev, + "invalid trace numbers: x=%u, y=%u\n", + x_traces, y_traces); + data->width_x = 1; + data->width_y = 1; + } else { + data->width_x = data->max_x / x_traces; + data->width_y = data->max_y / y_traces; + } if (device_property_read_u32(&client->dev, "touchscreen-x-mm", &x_mm) || @@ -443,8 +452,16 @@ static int elan_query_device_parameters(struct elan_tp_data *data) data->x_res = elan_convert_resolution(hw_x_res, data->pattern); data->y_res = elan_convert_resolution(hw_y_res, data->pattern); } else { - data->x_res = (data->max_x + 1) / x_mm; - data->y_res = (data->max_y + 1) / y_mm; + if (unlikely(x_mm == 0 || y_mm == 0)) { + dev_warn(&client->dev, + "invalid physical dimensions: x_mm=%u, y_mm=%u\n", + x_mm, y_mm); + data->x_res = 1; + data->y_res = 1; + } else { + data->x_res = (data->max_x + 1) / x_mm; + data->y_res = (data->max_y + 1) / y_mm; + } } if (device_property_read_bool(&client->dev, "elan,clickpad")) @@ -956,6 +973,7 @@ static void elan_report_contact(struct elan_tp_data *data, int contact_num, if (data->report_features & ETP_FEATURE_REPORT_MK) { unsigned int mk_x, mk_y, area_x, area_y; + int adj_width_x, adj_width_y; u8 mk_data = high_precision ? packet[ETP_MK_DATA_OFFSET + contact_num] : finger_data[3]; @@ -967,8 +985,14 @@ static void elan_report_contact(struct elan_tp_data *data, int contact_num, * To avoid treating large finger as palm, let's reduce * the width x and y per trace. */ - area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE); - area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE); + + adj_width_x = data->width_x > ETP_FWIDTH_REDUCE ? + data->width_x - ETP_FWIDTH_REDUCE : 0; + adj_width_y = data->width_y > ETP_FWIDTH_REDUCE ? + data->width_y - ETP_FWIDTH_REDUCE : 0; + + area_x = mk_x * adj_width_x; + area_y = mk_y * adj_width_y; input_report_abs(input, ABS_TOOL_WIDTH, mk_x); input_report_abs(input, ABS_MT_TOUCH_MAJOR, @@ -1407,7 +1431,7 @@ err: static DEFINE_SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume); static const struct i2c_device_id elan_id[] = { - { DRIVER_NAME }, + { .name = DRIVER_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, elan_id); diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 6f3d5c33b807..d4cf982f1263 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -607,7 +607,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend, synaptics_i2c_resume); static const struct i2c_device_id synaptics_i2c_id_table[] = { - { "synaptics_i2c" }, + { .name = "synaptics_i2c" }, { } }; MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table); diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h index 61a99c8a7a26..f9d9c1dd5eb0 100644 --- a/drivers/input/rmi4/rmi_2d_sensor.h +++ b/drivers/input/rmi4/rmi_2d_sensor.h @@ -56,8 +56,8 @@ struct rmi_2d_sensor { u16 max_y; u8 nbr_fingers; u8 *data_pkt; - int pkt_size; - int attn_size; + u32 pkt_size; + u32 attn_size; bool topbuttonpad; enum rmi_sensor_type sensor_type; struct input_dev *input; diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index 687cb987bc13..560c85f53327 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -237,36 +237,44 @@ static int rmi_function_remove(struct device *dev) return 0; } -int rmi_register_function(struct rmi_function *fn) +struct rmi_function *rmi_alloc_function(struct rmi_device *rmi_dev, u8 id) { - struct rmi_device *rmi_dev = fn->rmi_dev; - int error; + struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); + struct rmi_function *fn; + + fn = kzalloc_flex(*fn, irq_mask, BITS_TO_LONGS(data->irq_count)); + if (!fn) + return NULL; device_initialize(&fn->dev); - dev_set_name(&fn->dev, "%s.fn%02x", - dev_name(&rmi_dev->dev), fn->fd.function_number); + dev_set_name(&fn->dev, "%s.fn%02x", dev_name(&rmi_dev->dev), id); fn->dev.parent = &rmi_dev->dev; fn->dev.type = &rmi_function_type; fn->dev.bus = &rmi_bus_type; + fn->rmi_dev = rmi_dev; + + return fn; +} + +int rmi_register_function(struct rmi_function *fn) +{ + struct rmi_device *rmi_dev = fn->rmi_dev; + int error; error = device_add(&fn->dev); if (error) { dev_err(&rmi_dev->dev, - "Failed device_register function device %s\n", + "Failed to register function device %s\n", dev_name(&fn->dev)); - goto err_put_device; + return error; } rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Registered F%02X.\n", fn->fd.function_number); return 0; - -err_put_device: - put_device(&fn->dev); - return error; } void rmi_unregister_function(struct rmi_function *fn) @@ -455,11 +463,13 @@ static int __init rmi_bus_init(void) if (error) { pr_err("%s: error registering the RMI physical driver: %d\n", __func__, error); - goto err_unregister_bus; + goto err_unregister_function_handlers; } return 0; +err_unregister_function_handlers: + rmi_unregister_function_handlers(); err_unregister_bus: bus_unregister(&rmi_bus_type); return error; diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h index d4d0d82c69aa..90122df21f74 100644 --- a/drivers/input/rmi4/rmi_bus.h +++ b/drivers/input/rmi4/rmi_bus.h @@ -49,6 +49,7 @@ struct rmi_function { bool rmi_is_function_device(struct device *dev); +struct rmi_function *rmi_alloc_function(struct rmi_device *rmi_dev, u8 id); int __must_check rmi_register_function(struct rmi_function *); void rmi_unregister_function(struct rmi_function *); diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index ccd9338a44db..49a59da6a841 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -22,6 +22,7 @@ #include <uapi/linux/input.h> #include <linux/rmi.h> #include <linux/export.h> +#include <linux/unaligned.h> #include "rmi_bus.h" #include "rmi_driver.h" @@ -182,7 +183,11 @@ void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status, attn_data.size = size; attn_data.data = fifo_data; - kfifo_put(&drvdata->attn_fifo, attn_data); + if (!kfifo_put(&drvdata->attn_fifo, attn_data)) { + dev_warn_ratelimited(&rmi_dev->dev, + "Failed to enqueue attention data, FIFO full\n"); + kfree(fifo_data); + } } EXPORT_SYMBOL_GPL(rmi_set_attn_data); @@ -193,24 +198,24 @@ static irqreturn_t rmi_irq_fn(int irq, void *dev_id) struct rmi4_attn_data attn_data = {0}; int ret, count; - count = kfifo_get(&drvdata->attn_fifo, &attn_data); - if (count) { - *(drvdata->irq_status) = attn_data.irq_status; - drvdata->attn_data = attn_data; - } - - ret = rmi_process_interrupt_requests(rmi_dev); - if (ret) - rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, - "Failed to process interrupt request: %d\n", ret); + do { + count = kfifo_get(&drvdata->attn_fifo, &attn_data); + if (count) { + *drvdata->irq_status = attn_data.irq_status; + drvdata->attn_data = attn_data; + } - if (count) { - kfree(attn_data.data); - drvdata->attn_data.data = NULL; - } + ret = rmi_process_interrupt_requests(rmi_dev); + if (ret) + rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, + "Failed to process interrupt request: %d\n", + ret); - if (!kfifo_is_empty(&drvdata->attn_fifo)) - return rmi_irq_fn(irq, dev_id); + if (count) { + kfree(attn_data.data); + drvdata->attn_data.data = NULL; + } + } while (!kfifo_is_empty(&drvdata->attn_fifo)); return IRQ_HANDLED; } @@ -383,9 +388,8 @@ static int rmi_driver_set_irq_bits(struct rmi_device *rmi_dev, __func__); goto error_unlock; } - bitmap_copy(data->current_irq_mask, data->new_irq_mask, - data->num_of_irq_regs); + bitmap_copy(data->current_irq_mask, data->new_irq_mask, data->irq_count); bitmap_or(data->fn_irq_bits, data->fn_irq_bits, mask, data->irq_count); error_unlock: @@ -414,8 +418,8 @@ static int rmi_driver_clear_irq_bits(struct rmi_device *rmi_dev, __func__); goto error_unlock; } - bitmap_copy(data->current_irq_mask, data->new_irq_mask, - data->num_of_irq_regs); + + bitmap_copy(data->current_irq_mask, data->new_irq_mask, data->irq_count); error_unlock: mutex_unlock(&data->irq_mutex); @@ -558,30 +562,75 @@ int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx, return retval < 0 ? retval : 0; } +static int rmi_parse_register_desc_item(struct rmi_register_desc_item *item, + const u8 *buf, size_t size) +{ + unsigned int offset = 0; + unsigned int map_offset = 0; + int b; + + if (offset >= size) + return -EIO; + + item->reg_size = buf[offset++]; + if (item->reg_size == 0) { + if (size - offset < 2) + return -EIO; + item->reg_size = get_unaligned_le16(&buf[offset]); + offset += 2; + } + + if (item->reg_size == 0) { + if (size - offset < 4) + return -EIO; + item->reg_size = get_unaligned_le32(&buf[offset]); + offset += 4; + } + + do { + if (offset >= size) + return -EIO; + + for (b = 0; b < 7; b++) { + if (buf[offset] & BIT(b)) { + if (map_offset >= RMI_REG_DESC_SUBPACKET_BITS) + return -EIO; + __set_bit(map_offset, item->subpacket_map); + } + ++map_offset; + } + } while (buf[offset++] & BIT(7)); + + item->num_subpackets = bitmap_weight(item->subpacket_map, + RMI_REG_DESC_SUBPACKET_BITS); + + return offset; +} + int rmi_read_register_desc(struct rmi_device *d, u16 addr, - struct rmi_register_descriptor *rdesc) + struct rmi_register_descriptor *rdesc) { - int ret; + DECLARE_BITMAP(presence_map, RMI_REG_DESC_PRESENCE_BITS); + u8 buf[RMI_REG_DESC_PRESENCE_REGS_MAX]; u8 size_presence_reg; - u8 buf[35]; - int presense_offset = 1; - u8 *struct_buf; - int reg; - int offset = 0; - int map_offset = 0; + unsigned int presence_offset; + unsigned int map_offset; + unsigned int offset; + unsigned int reg; int i; int b; + int ret; /* * The first register of the register descriptor is the size of - * the register descriptor's presense register. + * the register descriptor's presence register. */ ret = rmi_read(d, addr, &size_presence_reg); if (ret) return ret; ++addr; - if (size_presence_reg < 0 || size_presence_reg > 35) + if (size_presence_reg < 1 || size_presence_reg > RMI_REG_DESC_PRESENCE_REGS_MAX) return -EIO; memset(buf, 0, sizeof(buf)); @@ -594,25 +643,33 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr, ret = rmi_read_block(d, addr, buf, size_presence_reg); if (ret) return ret; - ++addr; + addr += size_presence_reg; if (buf[0] == 0) { - presense_offset = 3; - rdesc->struct_size = buf[1] | (buf[2] << 8); + if (size_presence_reg < 3) + return -EIO; + presence_offset = 3; + rdesc->struct_size = get_unaligned_le16(&buf[1]); } else { + presence_offset = 1; rdesc->struct_size = buf[0]; } - for (i = presense_offset; i < size_presence_reg; i++) { + memset(presence_map, 0, sizeof(presence_map)); + map_offset = 0; + for (i = presence_offset; i < size_presence_reg; i++) { for (b = 0; b < 8; b++) { - if (buf[i] & (0x1 << b)) - bitmap_set(rdesc->presense_map, map_offset, 1); + if (buf[i] & BIT(b)) { + if (map_offset >= RMI_REG_DESC_PRESENCE_BITS) + return -EIO; + bitmap_set(presence_map, map_offset, 1); + } ++map_offset; } } - rdesc->num_registers = bitmap_weight(rdesc->presense_map, - RMI_REG_DESC_PRESENSE_BITS); + rdesc->num_registers = bitmap_weight(presence_map, + RMI_REG_DESC_PRESENCE_BITS); rdesc->registers = devm_kcalloc(&d->dev, rdesc->num_registers, @@ -626,7 +683,7 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr, * I'm not using devm_kzalloc here since it will not be retained * after exiting this function */ - struct_buf = kzalloc(rdesc->struct_size, GFP_KERNEL); + u8 *struct_buf __free(kfree) = kzalloc(rdesc->struct_size, GFP_KERNEL); if (!struct_buf) return -ENOMEM; @@ -638,56 +695,32 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr, */ ret = rmi_read_block(d, addr, struct_buf, rdesc->struct_size); if (ret) - goto free_struct_buff; + return ret; - reg = find_first_bit(rdesc->presense_map, RMI_REG_DESC_PRESENSE_BITS); + reg = find_first_bit(presence_map, RMI_REG_DESC_PRESENCE_BITS); + offset = 0; for (i = 0; i < rdesc->num_registers; i++) { struct rmi_register_desc_item *item = &rdesc->registers[i]; - int reg_size = struct_buf[offset]; - - ++offset; - if (reg_size == 0) { - reg_size = struct_buf[offset] | - (struct_buf[offset + 1] << 8); - offset += 2; - } + int item_size; - if (reg_size == 0) { - reg_size = struct_buf[offset] | - (struct_buf[offset + 1] << 8) | - (struct_buf[offset + 2] << 16) | - (struct_buf[offset + 3] << 24); - offset += 4; - } + item_size = rmi_parse_register_desc_item(item, + &struct_buf[offset], + rdesc->struct_size - offset); + if (item_size < 0) + return item_size; item->reg = reg; - item->reg_size = reg_size; - - map_offset = 0; - - do { - for (b = 0; b < 7; b++) { - if (struct_buf[offset] & (0x1 << b)) - bitmap_set(item->subpacket_map, - map_offset, 1); - ++map_offset; - } - } while (struct_buf[offset++] & 0x80); - - item->num_subpackets = bitmap_weight(item->subpacket_map, - RMI_REG_DESC_SUBPACKET_BITS); + offset += item_size; rmi_dbg(RMI_DEBUG_CORE, &d->dev, - "%s: reg: %d reg size: %ld subpackets: %d\n", __func__, + "%s: reg: %d reg size: %u subpackets: %d\n", __func__, item->reg, item->reg_size, item->num_subpackets); - reg = find_next_bit(rdesc->presense_map, - RMI_REG_DESC_PRESENSE_BITS, reg + 1); + reg = find_next_bit(presence_map, + RMI_REG_DESC_PRESENCE_BITS, reg + 1); } -free_struct_buff: - kfree(struct_buf); - return ret; + return 0; } const struct rmi_register_desc_item *rmi_get_register_desc_item( @@ -713,7 +746,7 @@ size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc) for (i = 0; i < rdesc->num_registers; i++) { item = &rdesc->registers[i]; - size += item->reg_size; + size = size_add(size, item->reg_size); } return size; } @@ -738,7 +771,7 @@ int rmi_register_desc_calc_reg_offset( bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item, u8 subpacket) { - return find_next_bit(item->subpacket_map, RMI_REG_DESC_PRESENSE_BITS, + return find_next_bit(item->subpacket_map, RMI_REG_DESC_SUBPACKET_BITS, subpacket) == subpacket; } @@ -839,9 +872,7 @@ static int rmi_create_function(struct rmi_device *rmi_dev, rmi_dbg(RMI_DEBUG_CORE, dev, "Initializing F%02X.\n", pdt->function_number); - fn = kzalloc(sizeof(struct rmi_function) + - BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long), - GFP_KERNEL); + fn = rmi_alloc_function(rmi_dev, pdt->function_number); if (!fn) { dev_err(dev, "Failed to allocate memory for F%02X\n", pdt->function_number); @@ -851,8 +882,6 @@ static int rmi_create_function(struct rmi_device *rmi_dev, INIT_LIST_HEAD(&fn->node); rmi_driver_copy_pdt_to_fd(pdt, &fn->fd); - fn->rmi_dev = rmi_dev; - fn->num_of_irqs = pdt->interrupt_source_count; fn->irq_pos = *current_irq_count; *current_irq_count += fn->num_of_irqs; @@ -861,8 +890,10 @@ static int rmi_create_function(struct rmi_device *rmi_dev, set_bit(fn->irq_pos + i, fn->irq_mask); error = rmi_register_function(fn); - if (error) + if (error) { + put_device(&fn->dev); return error; + } if (pdt->function_number == 0x01) data->f01_container = fn; @@ -1133,6 +1164,7 @@ static int rmi_driver_probe(struct device *dev) return -ENOMEM; INIT_LIST_HEAD(&data->function_list); + INIT_KFIFO(data->attn_fifo); data->rmi_dev = rmi_dev; dev_set_drvdata(&rmi_dev->dev, data); diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h index e84495caab15..abeafb77a483 100644 --- a/drivers/input/rmi4/rmi_driver.h +++ b/drivers/input/rmi4/rmi_driver.h @@ -46,16 +46,16 @@ struct pdt_entry { u8 function_number; }; -#define RMI_REG_DESC_PRESENSE_BITS (32 * BITS_PER_BYTE) +#define RMI_REG_DESC_PRESENCE_BITS (32 * BITS_PER_BYTE) +#define RMI_REG_DESC_PRESENCE_REGS_MAX (3 + RMI_REG_DESC_PRESENCE_BITS / 8) #define RMI_REG_DESC_SUBPACKET_BITS (37 * BITS_PER_BYTE) /* describes a single packet register */ struct rmi_register_desc_item { + u32 reg_size; u16 reg; - unsigned long reg_size; - u8 num_subpackets; - unsigned long subpacket_map[BITS_TO_LONGS( - RMI_REG_DESC_SUBPACKET_BITS)]; + u16 num_subpackets; + DECLARE_BITMAP(subpacket_map, RMI_REG_DESC_SUBPACKET_BITS); }; /* @@ -64,8 +64,7 @@ struct rmi_register_desc_item { */ struct rmi_register_descriptor { unsigned long struct_size; - unsigned long presense_map[BITS_TO_LONGS(RMI_REG_DESC_PRESENSE_BITS)]; - u8 num_registers; + u16 num_registers; struct rmi_register_desc_item *registers; }; diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index 49ca9168685a..9ade74b36edb 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c @@ -1304,7 +1304,7 @@ static irqreturn_t rmi_f11_attention(int irq, void *ctx) struct f11_data *f11 = dev_get_drvdata(&fn->dev); u16 data_base_addr = fn->fd.data_base_addr; int error; - int valid_bytes = f11->sensor.pkt_size; + u32 valid_bytes = f11->sensor.pkt_size; if (drvdata->attn_data.data) { /* diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 8246fe77114b..88c28089de99 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -5,6 +5,8 @@ #include <linux/input.h> #include <linux/input/mt.h> #include <linux/rmi.h> +#include <linux/sizes.h> +#include <linux/unaligned.h> #include "rmi_driver.h" #include "rmi_2d_sensor.h" @@ -49,7 +51,6 @@ struct f12_data { const struct rmi_register_desc_item *data6; u16 data6_offset; - /* F12 Data9 reports relative data */ const struct rmi_register_desc_item *data9; u16 data9_offset; @@ -57,10 +58,39 @@ struct f12_data { const struct rmi_register_desc_item *data15; u16 data15_offset; - unsigned long *abs_mask; - unsigned long *rel_mask; + unsigned long irq_mask[]; }; +static int rmi_f12_read_register_descs(struct rmi_function *fn, + struct f12_data *f12, u16 query_addr) +{ + struct { + struct rmi_register_descriptor *desc; + const char *name; + } descriptors[] = { + { &f12->query_reg_desc, "Query" }, + { &f12->control_reg_desc, "Control" }, + { &f12->data_reg_desc, "Data" }, + }; + struct rmi_device *rmi_dev = fn->rmi_dev; + int error; + int i; + + for (i = 0; i < ARRAY_SIZE(descriptors); i++) { + error = rmi_read_register_desc(rmi_dev, query_addr, + descriptors[i].desc); + if (error) { + dev_err(&fn->dev, + "Failed to read the %s Register Descriptor: %d\n", + descriptors[i].name, error); + return error; + } + query_addr += 3; + } + + return 0; +} + static int rmi_f12_read_sensor_tuning(struct f12_data *f12) { const struct rmi_register_desc_item *item; @@ -88,20 +118,20 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) if (item->reg_size > sizeof(buf)) { dev_err(&fn->dev, - "F12 control8 should be no bigger than %zd bytes, not: %ld\n", + "F12 control8 should be no bigger than %zd bytes, not: %u\n", sizeof(buf), item->reg_size); return -ENODEV; } - ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr + offset, buf, - item->reg_size); + ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr + offset, + buf, item->reg_size); if (ret) return ret; offset = 0; if (rmi_register_desc_has_subpacket(item, 0)) { - sensor->max_x = (buf[offset + 1] << 8) | buf[offset]; - sensor->max_y = (buf[offset + 3] << 8) | buf[offset + 2]; + sensor->max_x = get_unaligned_le16(&buf[offset]); + sensor->max_y = get_unaligned_le16(&buf[offset + 2]); offset += 4; } @@ -109,8 +139,8 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) sensor->max_x, sensor->max_y); if (rmi_register_desc_has_subpacket(item, 1)) { - pitch_x = (buf[offset + 1] << 8) | buf[offset]; - pitch_y = (buf[offset + 3] << 8) | buf[offset + 2]; + pitch_x = get_unaligned_le16(&buf[offset]); + pitch_y = get_unaligned_le16(&buf[offset + 2]); offset += 4; } @@ -132,12 +162,12 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) if (rmi_get_register_desc_item(&f12->query_reg_desc, RMI_F12_QUERY_RESOLUTION)) { offset = rmi_register_desc_calc_reg_offset(&f12->query_reg_desc, - RMI_F12_QUERY_RESOLUTION); + RMI_F12_QUERY_RESOLUTION); query_dpm_addr = fn->fd.query_base_addr + offset; ret = rmi_read(fn->rmi_dev, query_dpm_addr, buf); - if (ret < 0) { + if (ret) { dev_err(&fn->dev, "Failed to read DPM value: %d\n", ret); - return -ENODEV; + return ret; } dpm_resolution = buf[0]; @@ -164,14 +194,11 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) return 0; } -static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size) +static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, u32 size) { - int i; struct rmi_2d_sensor *sensor = &f12->sensor; - int objects = f12->data1->num_subpackets; - - if ((f12->data1->num_subpackets * F12_DATA1_BYTES_PER_OBJ) > size) - objects = size / F12_DATA1_BYTES_PER_OBJ; + u32 objects = min(f12->data1->num_subpackets, size / F12_DATA1_BYTES_PER_OBJ); + int i; for (i = 0; i < objects; i++) { struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i]; @@ -196,8 +223,8 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size) break; } - obj->x = (data1[2] << 8) | data1[1]; - obj->y = (data1[4] << 8) | data1[3]; + obj->x = get_unaligned_le16(&data1[1]); + obj->y = get_unaligned_le16(&data1[3]); obj->z = data1[5]; obj->wx = data1[6]; obj->wy = data1[7]; @@ -220,21 +247,17 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size) static irqreturn_t rmi_f12_attention(int irq, void *ctx) { - int retval; struct rmi_function *fn = ctx; struct rmi_device *rmi_dev = fn->rmi_dev; struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev); struct f12_data *f12 = dev_get_drvdata(&fn->dev); struct rmi_2d_sensor *sensor = &f12->sensor; - int valid_bytes = sensor->pkt_size; + u32 valid_bytes = sensor->pkt_size; + int retval; if (drvdata->attn_data.data) { - if (sensor->attn_size > drvdata->attn_data.size) - valid_bytes = drvdata->attn_data.size; - else - valid_bytes = sensor->attn_size; - memcpy(sensor->data_pkt, drvdata->attn_data.data, - valid_bytes); + valid_bytes = min_t(u32, sensor->attn_size, drvdata->attn_data.size); + memcpy(sensor->data_pkt, drvdata->attn_data.data, valid_bytes); drvdata->attn_data.data += valid_bytes; drvdata->attn_data.size -= valid_bytes; } else { @@ -248,92 +271,100 @@ static irqreturn_t rmi_f12_attention(int irq, void *ctx) } if (f12->data1) - rmi_f12_process_objects(f12, - &sensor->data_pkt[f12->data1_offset], valid_bytes); + rmi_f12_process_objects(f12, &sensor->data_pkt[f12->data1_offset], + valid_bytes); input_mt_sync_frame(sensor->input); return IRQ_HANDLED; } -static int rmi_f12_write_control_regs(struct rmi_function *fn) +static int rmi_f12_update_dribble(struct rmi_function *fn, struct f12_data *f12) { - int ret; const struct rmi_register_desc_item *item; struct rmi_device *rmi_dev = fn->rmi_dev; - struct f12_data *f12 = dev_get_drvdata(&fn->dev); - int control_size; - char buf[3]; - u16 control_offset = 0; u8 subpacket_offset = 0; + u16 control_offset; + u32 control_size; + int error; + u8 buf[3]; - if (f12->has_dribble - && (f12->sensor.dribble != RMI_REG_STATE_DEFAULT)) { - item = rmi_get_register_desc_item(&f12->control_reg_desc, 20); - if (item) { - control_offset = rmi_register_desc_calc_reg_offset( - &f12->control_reg_desc, 20); - - /* - * The byte containing the EnableDribble bit will be - * in either byte 0 or byte 2 of control 20. Depending - * on the existence of subpacket 0. If control 20 is - * larger then 3 bytes, just read the first 3. - */ - control_size = min(item->reg_size, 3UL); - - ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr - + control_offset, buf, control_size); - if (ret) - return ret; - - if (rmi_register_desc_has_subpacket(item, 0)) - subpacket_offset += 1; - - switch (f12->sensor.dribble) { - case RMI_REG_STATE_OFF: - buf[subpacket_offset] &= ~BIT(2); - break; - case RMI_REG_STATE_ON: - buf[subpacket_offset] |= BIT(2); - break; - case RMI_REG_STATE_DEFAULT: - default: - break; - } + item = rmi_get_register_desc_item(&f12->control_reg_desc, 20); + if (!item) + return 0; - ret = rmi_write_block(rmi_dev, - fn->fd.control_base_addr + control_offset, - buf, control_size); - if (ret) - return ret; - } + control_offset = rmi_register_desc_calc_reg_offset(&f12->control_reg_desc, 20); + + /* + * The byte containing the EnableDribble bit will be + * in either byte 0 or byte 2 of control 20. Depending + * on the existence of subpacket 0. If control 20 is + * larger then 3 bytes, just read the first 3. + */ + control_size = min(item->reg_size, 3U); + + error = rmi_read_block(rmi_dev, fn->fd.control_base_addr + control_offset, + buf, control_size); + if (error) + return error; + + if (rmi_register_desc_has_subpacket(item, 0)) + subpacket_offset += 1; + + switch (f12->sensor.dribble) { + case RMI_REG_STATE_OFF: + buf[subpacket_offset] &= ~BIT(2); + break; + case RMI_REG_STATE_ON: + buf[subpacket_offset] |= BIT(2); + break; + case RMI_REG_STATE_DEFAULT: + default: + break; } + error = rmi_write_block(rmi_dev, fn->fd.control_base_addr + control_offset, + buf, control_size); + if (error) + return error; + return 0; +} + +static int rmi_f12_write_control_regs(struct rmi_function *fn) +{ + struct f12_data *f12 = dev_get_drvdata(&fn->dev); + if (f12->has_dribble && f12->sensor.dribble != RMI_REG_STATE_DEFAULT) + return rmi_f12_update_dribble(fn, f12); + + return 0; } static int rmi_f12_config(struct rmi_function *fn) { struct rmi_driver *drv = fn->rmi_dev->driver; struct f12_data *f12 = dev_get_drvdata(&fn->dev); + struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev); + int irq_mask_size = BITS_TO_LONGS(drvdata->irq_count); + unsigned long *abs_mask = f12->irq_mask; + unsigned long *rel_mask = f12->irq_mask + irq_mask_size; struct rmi_2d_sensor *sensor; int ret; sensor = &f12->sensor; if (!sensor->report_abs) - drv->clear_irq_bits(fn->rmi_dev, f12->abs_mask); + drv->clear_irq_bits(fn->rmi_dev, abs_mask); else - drv->set_irq_bits(fn->rmi_dev, f12->abs_mask); + drv->set_irq_bits(fn->rmi_dev, abs_mask); - drv->clear_irq_bits(fn->rmi_dev, f12->rel_mask); + drv->clear_irq_bits(fn->rmi_dev, rel_mask); ret = rmi_f12_write_control_regs(fn); if (ret) dev_warn(&fn->dev, - "Failed to write F12 control registers: %d\n", ret); + "Failed to write F12 control registers: %d\n", ret); return 0; } @@ -349,12 +380,14 @@ static int rmi_f12_probe(struct rmi_function *fn) struct rmi_2d_sensor *sensor; struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev); - u16 data_offset = 0; - int mask_size; + size_t data_offset = 0; + size_t pkt_size; + int irq_mask_size; + int i; rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__); - mask_size = BITS_TO_LONGS(drvdata->irq_count) * sizeof(unsigned long); + irq_mask_size = BITS_TO_LONGS(drvdata->irq_count); ret = rmi_read(fn->rmi_dev, query_addr, &buf); if (ret < 0) { @@ -370,18 +403,13 @@ static int rmi_f12_probe(struct rmi_function *fn) return -ENODEV; } - f12 = devm_kzalloc(&fn->dev, sizeof(struct f12_data) + mask_size * 2, - GFP_KERNEL); + f12 = devm_kzalloc(&fn->dev, struct_size(f12, irq_mask, irq_mask_size * 2), + GFP_KERNEL); if (!f12) return -ENOMEM; - f12->abs_mask = (unsigned long *)((char *)f12 - + sizeof(struct f12_data)); - f12->rel_mask = (unsigned long *)((char *)f12 - + sizeof(struct f12_data) + mask_size); - - set_bit(fn->irq_pos, f12->abs_mask); - set_bit(fn->irq_pos + 1, f12->rel_mask); + set_bit(fn->irq_pos, f12->irq_mask); + set_bit(fn->irq_pos + 1, f12->irq_mask + irq_mask_size); f12->has_dribble = !!(buf & BIT(3)); @@ -393,55 +421,32 @@ static int rmi_f12_probe(struct rmi_function *fn) f12->sensor_pdata = pdata->sensor_pdata; } - ret = rmi_read_register_desc(rmi_dev, query_addr, - &f12->query_reg_desc); - if (ret) { - dev_err(&fn->dev, - "Failed to read the Query Register Descriptor: %d\n", - ret); - return ret; - } - query_addr += 3; - - ret = rmi_read_register_desc(rmi_dev, query_addr, - &f12->control_reg_desc); - if (ret) { - dev_err(&fn->dev, - "Failed to read the Control Register Descriptor: %d\n", - ret); - return ret; - } - query_addr += 3; - - ret = rmi_read_register_desc(rmi_dev, query_addr, - &f12->data_reg_desc); - if (ret) { - dev_err(&fn->dev, - "Failed to read the Data Register Descriptor: %d\n", - ret); + ret = rmi_f12_read_register_descs(fn, f12, query_addr); + if (ret) return ret; - } - query_addr += 3; sensor = &f12->sensor; sensor->fn = fn; f12->data_addr = fn->fd.data_base_addr; - sensor->pkt_size = rmi_register_desc_calc_size(&f12->data_reg_desc); + pkt_size = rmi_register_desc_calc_size(&f12->data_reg_desc); + if (pkt_size > SZ_1M) { + dev_err(&fn->dev, "Invalid data packet size: %zu\n", pkt_size); + return -EINVAL; + } + sensor->pkt_size = pkt_size; - sensor->axis_align = - f12->sensor_pdata.axis_align; + sensor->axis_align = f12->sensor_pdata.axis_align; sensor->x_mm = f12->sensor_pdata.x_mm; sensor->y_mm = f12->sensor_pdata.y_mm; sensor->dribble = f12->sensor_pdata.dribble; if (sensor->sensor_type == rmi_sensor_default) - sensor->sensor_type = - f12->sensor_pdata.sensor_type; + sensor->sensor_type = f12->sensor_pdata.sensor_type; - rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: data packet size: %d\n", __func__, + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: data packet size: %u\n", __func__, sensor->pkt_size); - sensor->data_pkt = devm_kzalloc(&fn->dev, sensor->pkt_size, GFP_KERNEL); + sensor->data_pkt = devm_kmalloc(&fn->dev, sensor->pkt_size, GFP_KERNEL); if (!sensor->data_pkt) return -ENOMEM; @@ -452,108 +457,86 @@ static int rmi_f12_probe(struct rmi_function *fn) return ret; /* - * Figure out what data is contained in the data registers. HID devices - * may have registers defined, but their data is not reported in the - * HID attention report. Registers which are not reported in the HID - * attention report check to see if the device is receiving data from - * HID attention reports. + * Identify available data registers and calculate their offsets within + * the attention report. For HID devices, only Data1 and Data5 are + * included in the report; other registers may be described but are + * not transmitted in the attention packet and thus skipped here. */ - item = rmi_get_register_desc_item(&f12->data_reg_desc, 0); - if (item && !drvdata->attn_data.data) - data_offset += item->reg_size; - - item = rmi_get_register_desc_item(&f12->data_reg_desc, 1); - if (item) { - f12->data1 = item; - f12->data1_offset = data_offset; - data_offset += item->reg_size; - sensor->nbr_fingers = item->num_subpackets; - sensor->report_abs = 1; - sensor->attn_size += item->reg_size; - } + for (i = 0; i < 16; i++) { + item = rmi_get_register_desc_item(&f12->data_reg_desc, i); + if (!item) + continue; + + /* HID attention reports only contain Data1 and Data5 */ + if (drvdata->attn_data.data && i != 1 && i != 5) + continue; + + if (data_offset > U16_MAX) { + dev_err(&fn->dev, "Invalid offset for data%d: %zu\n", + i, data_offset); + return -EINVAL; + } - item = rmi_get_register_desc_item(&f12->data_reg_desc, 2); - if (item && !drvdata->attn_data.data) - data_offset += item->reg_size; + switch (i) { + case 1: + f12->data1 = item; + f12->data1_offset = data_offset; - item = rmi_get_register_desc_item(&f12->data_reg_desc, 3); - if (item && !drvdata->attn_data.data) - data_offset += item->reg_size; + if (item->num_subpackets > 255) { + dev_err(&fn->dev, + "Too many fingers declared: %d\n", + item->num_subpackets); + return -EINVAL; + } - item = rmi_get_register_desc_item(&f12->data_reg_desc, 4); - if (item && !drvdata->attn_data.data) - data_offset += item->reg_size; + sensor->nbr_fingers = item->num_subpackets; + sensor->report_abs = 1; + sensor->attn_size += item->reg_size; + break; - item = rmi_get_register_desc_item(&f12->data_reg_desc, 5); - if (item) { - f12->data5 = item; - f12->data5_offset = data_offset; - data_offset += item->reg_size; - sensor->attn_size += item->reg_size; - } + case 5: + f12->data5 = item; + f12->data5_offset = data_offset; + sensor->attn_size += item->reg_size; + break; - item = rmi_get_register_desc_item(&f12->data_reg_desc, 6); - if (item && !drvdata->attn_data.data) { - f12->data6 = item; - f12->data6_offset = data_offset; - data_offset += item->reg_size; - } + case 6: + f12->data6 = item; + f12->data6_offset = data_offset; + break; - item = rmi_get_register_desc_item(&f12->data_reg_desc, 7); - if (item && !drvdata->attn_data.data) - data_offset += item->reg_size; + case 9: + f12->data9 = item; + f12->data9_offset = data_offset; + if (!sensor->report_abs) + sensor->report_rel = 1; + break; - item = rmi_get_register_desc_item(&f12->data_reg_desc, 8); - if (item && !drvdata->attn_data.data) - data_offset += item->reg_size; + case 15: + f12->data15 = item; + f12->data15_offset = data_offset; + break; + } - item = rmi_get_register_desc_item(&f12->data_reg_desc, 9); - if (item && !drvdata->attn_data.data) { - f12->data9 = item; - f12->data9_offset = data_offset; data_offset += item->reg_size; - if (!sensor->report_abs) - sensor->report_rel = 1; } - item = rmi_get_register_desc_item(&f12->data_reg_desc, 10); - if (item && !drvdata->attn_data.data) - data_offset += item->reg_size; - - item = rmi_get_register_desc_item(&f12->data_reg_desc, 11); - if (item && !drvdata->attn_data.data) - data_offset += item->reg_size; - - item = rmi_get_register_desc_item(&f12->data_reg_desc, 12); - if (item && !drvdata->attn_data.data) - data_offset += item->reg_size; - - item = rmi_get_register_desc_item(&f12->data_reg_desc, 13); - if (item && !drvdata->attn_data.data) - data_offset += item->reg_size; - - item = rmi_get_register_desc_item(&f12->data_reg_desc, 14); - if (item && !drvdata->attn_data.data) - data_offset += item->reg_size; + /* allocate the in-kernel tracking buffers */ + sensor->tracking_pos = devm_kcalloc(&fn->dev, sensor->nbr_fingers, + sizeof(*sensor->tracking_pos), + GFP_KERNEL); + if (!sensor->tracking_pos) + return -ENOMEM; - item = rmi_get_register_desc_item(&f12->data_reg_desc, 15); - if (item && !drvdata->attn_data.data) { - f12->data15 = item; - f12->data15_offset = data_offset; - data_offset += item->reg_size; - } + sensor->tracking_slots = devm_kcalloc(&fn->dev, sensor->nbr_fingers, + sizeof(*sensor->tracking_slots), + GFP_KERNEL); + if (!sensor->tracking_slots) + return -ENOMEM; - /* allocate the in-kernel tracking buffers */ - sensor->tracking_pos = devm_kcalloc(&fn->dev, - sensor->nbr_fingers, sizeof(struct input_mt_pos), - GFP_KERNEL); - sensor->tracking_slots = devm_kcalloc(&fn->dev, - sensor->nbr_fingers, sizeof(int), GFP_KERNEL); - sensor->objs = devm_kcalloc(&fn->dev, - sensor->nbr_fingers, - sizeof(struct rmi_2d_sensor_abs_object), - GFP_KERNEL); - if (!sensor->tracking_pos || !sensor->tracking_slots || !sensor->objs) + sensor->objs = devm_kcalloc(&fn->dev, sensor->nbr_fingers, + sizeof(*sensor->objs), GFP_KERNEL); + if (!sensor->objs) return -ENOMEM; ret = rmi_2d_sensor_configure_input(fn, sensor); diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c index 3c0c5fd44702..e11d0acb9b96 100644 --- a/drivers/input/rmi4/rmi_i2c.c +++ b/drivers/input/rmi4/rmi_i2c.c @@ -365,7 +365,7 @@ static const struct dev_pm_ops rmi_i2c_pm = { }; static const struct i2c_device_id rmi_id[] = { - { "rmi4_i2c" }, + { .name = "rmi4_i2c" }, { } }; MODULE_DEVICE_TABLE(i2c, rmi_id); diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c index f3d0b40721df..6de68c602558 100644 --- a/drivers/input/rmi4/rmi_smbus.c +++ b/drivers/input/rmi4/rmi_smbus.c @@ -413,7 +413,7 @@ static const struct dev_pm_ops rmi_smb_pm = { }; static const struct i2c_device_id rmi_id[] = { - { "rmi4_smbus" }, + { .name = "rmi4_smbus" }, { } }; MODULE_DEVICE_TABLE(i2c, rmi_id); diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 5f15a6462056..bacab1f58400 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -188,16 +188,6 @@ config SERIO_RAW To compile this driver as a module, choose M here: the module will be called serio_raw. -config SERIO_XILINX_XPS_PS2 - tristate "Xilinx XPS PS/2 Controller Support" - depends on PPC || MICROBLAZE - help - This driver supports XPS PS/2 IP from the Xilinx EDK on - PowerPC platform. - - To compile this driver as a module, choose M here: the - module will be called xilinx_ps2. - config SERIO_ALTERA_PS2 tristate "Altera UP PS/2 controller" depends on HAS_IOMEM diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 8ab98f4aa28d..7f5137dc02e2 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_SERIO_SGI_IOC3) += ioc3kbd.o obj-$(CONFIG_SERIO_LIBPS2) += libps2.o obj-$(CONFIG_SERIO_RAW) += serio_raw.o obj-$(CONFIG_SERIO_AMS_DELTA) += ams_delta_serio.o -obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o obj-$(CONFIG_SERIO_APBPS2) += apbps2.o diff --git a/drivers/input/serio/apbps2.c b/drivers/input/serio/apbps2.c index 0aa4ab00af35..5f21acdd4113 100644 --- a/drivers/input/serio/apbps2.c +++ b/drivers/input/serio/apbps2.c @@ -140,7 +140,7 @@ static int apbps2_of_probe(struct platform_device *ofdev) } /* Find device address */ - priv->regs = devm_platform_get_and_ioremap_resource(ofdev, 0, NULL); + priv->regs = devm_platform_ioremap_resource(ofdev, 0); if (IS_ERR(priv->regs)) return PTR_ERR(priv->regs); @@ -148,7 +148,10 @@ static int apbps2_of_probe(struct platform_device *ofdev) iowrite32be(0, &priv->regs->ctrl); /* IRQ */ - irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); + irq = platform_get_irq(ofdev, 0); + if (irq < 0) + return irq; + err = devm_request_irq(&ofdev->dev, irq, apbps2_isr, IRQF_SHARED, "apbps2", priv); if (err) { diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h index 8ebdf4fb9030..412f82d7a303 100644 --- a/drivers/input/serio/i8042-acpipnpio.h +++ b/drivers/input/serio/i8042-acpipnpio.h @@ -1539,22 +1539,22 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id * } static const struct pnp_device_id pnp_kbd_devids[] = { - { .id = "PNP0300", .driver_data = 0 }, - { .id = "PNP0301", .driver_data = 0 }, - { .id = "PNP0302", .driver_data = 0 }, - { .id = "PNP0303", .driver_data = 0 }, - { .id = "PNP0304", .driver_data = 0 }, - { .id = "PNP0305", .driver_data = 0 }, - { .id = "PNP0306", .driver_data = 0 }, - { .id = "PNP0309", .driver_data = 0 }, - { .id = "PNP030a", .driver_data = 0 }, - { .id = "PNP030b", .driver_data = 0 }, - { .id = "PNP0320", .driver_data = 0 }, - { .id = "PNP0343", .driver_data = 0 }, - { .id = "PNP0344", .driver_data = 0 }, - { .id = "PNP0345", .driver_data = 0 }, - { .id = "CPQA0D7", .driver_data = 0 }, - { .id = "", }, + { .id = "PNP0300" }, + { .id = "PNP0301" }, + { .id = "PNP0302" }, + { .id = "PNP0303" }, + { .id = "PNP0304" }, + { .id = "PNP0305" }, + { .id = "PNP0306" }, + { .id = "PNP0309" }, + { .id = "PNP030a" }, + { .id = "PNP030b" }, + { .id = "PNP0320" }, + { .id = "PNP0343" }, + { .id = "PNP0344" }, + { .id = "PNP0345" }, + { .id = "CPQA0D7" }, + { } }; MODULE_DEVICE_TABLE(pnp, pnp_kbd_devids); @@ -1569,18 +1569,18 @@ static struct pnp_driver i8042_pnp_kbd_driver = { }; static const struct pnp_device_id pnp_aux_devids[] = { - { .id = "AUI0200", .driver_data = 0 }, - { .id = "FJC6000", .driver_data = 0 }, - { .id = "FJC6001", .driver_data = 0 }, - { .id = "PNP0f03", .driver_data = 0 }, - { .id = "PNP0f0b", .driver_data = 0 }, - { .id = "PNP0f0e", .driver_data = 0 }, - { .id = "PNP0f12", .driver_data = 0 }, - { .id = "PNP0f13", .driver_data = 0 }, - { .id = "PNP0f19", .driver_data = 0 }, - { .id = "PNP0f1c", .driver_data = 0 }, - { .id = "SYN0801", .driver_data = 0 }, - { .id = "", }, + { .id = "AUI0200" }, + { .id = "FJC6000" }, + { .id = "FJC6001" }, + { .id = "PNP0f03" }, + { .id = "PNP0f0b" }, + { .id = "PNP0f0e" }, + { .id = "PNP0f12" }, + { .id = "PNP0f13" }, + { .id = "PNP0f19" }, + { .id = "PNP0f1c" }, + { .id = "SYN0801" }, + { }, }; MODULE_DEVICE_TABLE(pnp, pnp_aux_devids); diff --git a/drivers/input/serio/userio.c b/drivers/input/serio/userio.c index 91cb7a177b2d..8c19975c84bf 100644 --- a/drivers/input/serio/userio.c +++ b/drivers/input/serio/userio.c @@ -1,7 +1,7 @@ /* * userio kernel serio device emulation module * Copyright (C) 2015 Red Hat - * Copyright (C) 2015 Stephen Chandler Paul <thatslyude@gmail.com> + * Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by @@ -206,6 +206,36 @@ static int userio_execute_cmd(struct userio_device *userio, userio->serio->id.type = cmd->data; break; + case USERIO_CMD_SET_PORT_EXTRA: + if (userio->running) { + dev_warn(userio_misc.this_device, + "Can't change port extra on an already running userio instance\n"); + return -EBUSY; + } + + userio->serio->id.extra = cmd->data; + break; + + case USERIO_CMD_SET_PORT_ID: + if (userio->running) { + dev_warn(userio_misc.this_device, + "Can't change port id on an already running userio instance\n"); + return -EBUSY; + } + + userio->serio->id.id = cmd->data; + break; + + case USERIO_CMD_SET_PORT_PROTO: + if (userio->running) { + dev_warn(userio_misc.this_device, + "Can't change port proto on an already running userio instance\n"); + return -EBUSY; + } + + userio->serio->id.proto = cmd->data; + break; + case USERIO_CMD_SEND_INTERRUPT: if (!userio->running) { dev_warn(userio_misc.this_device, @@ -278,6 +308,6 @@ module_driver(userio_misc, misc_register, misc_deregister); MODULE_ALIAS_MISCDEV(USERIO_MINOR); MODULE_ALIAS("devname:" USERIO_NAME); -MODULE_AUTHOR("Stephen Chandler Paul <thatslyude@gmail.com>"); +MODULE_AUTHOR("Lyude Paul <thatslyude@gmail.com>"); MODULE_DESCRIPTION("Virtual Serio Device Support"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c deleted file mode 100644 index 411d55ca1a66..000000000000 --- a/drivers/input/serio/xilinx_ps2.c +++ /dev/null @@ -1,363 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Xilinx XPS PS/2 device driver - * - * (c) 2005 MontaVista Software, Inc. - * (c) 2008 Xilinx, Inc. - */ - - -#include <linux/module.h> -#include <linux/serio.h> -#include <linux/interrupt.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/list.h> -#include <linux/io.h> -#include <linux/mod_devicetable.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/platform_device.h> - -#define DRIVER_NAME "xilinx_ps2" - -/* Register offsets for the xps2 device */ -#define XPS2_SRST_OFFSET 0x00000000 /* Software Reset register */ -#define XPS2_STATUS_OFFSET 0x00000004 /* Status register */ -#define XPS2_RX_DATA_OFFSET 0x00000008 /* Receive Data register */ -#define XPS2_TX_DATA_OFFSET 0x0000000C /* Transmit Data register */ -#define XPS2_GIER_OFFSET 0x0000002C /* Global Interrupt Enable reg */ -#define XPS2_IPISR_OFFSET 0x00000030 /* Interrupt Status register */ -#define XPS2_IPIER_OFFSET 0x00000038 /* Interrupt Enable register */ - -/* Reset Register Bit Definitions */ -#define XPS2_SRST_RESET 0x0000000A /* Software Reset */ - -/* Status Register Bit Positions */ -#define XPS2_STATUS_RX_FULL 0x00000001 /* Receive Full */ -#define XPS2_STATUS_TX_FULL 0x00000002 /* Transmit Full */ - -/* - * Bit definitions for ISR/IER registers. Both the registers have the same bit - * definitions and are only defined once. - */ -#define XPS2_IPIXR_WDT_TOUT 0x00000001 /* Watchdog Timeout Interrupt */ -#define XPS2_IPIXR_TX_NOACK 0x00000002 /* Transmit No ACK Interrupt */ -#define XPS2_IPIXR_TX_ACK 0x00000004 /* Transmit ACK (Data) Interrupt */ -#define XPS2_IPIXR_RX_OVF 0x00000008 /* Receive Overflow Interrupt */ -#define XPS2_IPIXR_RX_ERR 0x00000010 /* Receive Error Interrupt */ -#define XPS2_IPIXR_RX_FULL 0x00000020 /* Receive Data Interrupt */ - -/* Mask for all the Transmit Interrupts */ -#define XPS2_IPIXR_TX_ALL (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_TX_ACK) - -/* Mask for all the Receive Interrupts */ -#define XPS2_IPIXR_RX_ALL (XPS2_IPIXR_RX_OVF | XPS2_IPIXR_RX_ERR | \ - XPS2_IPIXR_RX_FULL) - -/* Mask for all the Interrupts */ -#define XPS2_IPIXR_ALL (XPS2_IPIXR_TX_ALL | XPS2_IPIXR_RX_ALL | \ - XPS2_IPIXR_WDT_TOUT) - -/* Global Interrupt Enable mask */ -#define XPS2_GIER_GIE_MASK 0x80000000 - -struct xps2data { - int irq; - spinlock_t lock; - void __iomem *base_address; /* virt. address of control registers */ - unsigned int flags; - struct serio *serio; /* serio */ - struct device *dev; -}; - -/************************************/ -/* XPS PS/2 data transmission calls */ -/************************************/ - -/** - * xps2_recv() - attempts to receive a byte from the PS/2 port. - * @drvdata: pointer to ps2 device private data structure - * @byte: address where the read data will be copied - * - * If there is any data available in the PS/2 receiver, this functions reads - * the data, otherwise it returns error. - */ -static int xps2_recv(struct xps2data *drvdata, u8 *byte) -{ - u32 sr; - int status = -1; - - /* If there is data available in the PS/2 receiver, read it */ - sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET); - if (sr & XPS2_STATUS_RX_FULL) { - *byte = in_be32(drvdata->base_address + XPS2_RX_DATA_OFFSET); - status = 0; - } - - return status; -} - -/*********************/ -/* Interrupt handler */ -/*********************/ -static irqreturn_t xps2_interrupt(int irq, void *dev_id) -{ - struct xps2data *drvdata = dev_id; - u32 intr_sr; - u8 c; - int status; - - /* Get the PS/2 interrupts and clear them */ - intr_sr = in_be32(drvdata->base_address + XPS2_IPISR_OFFSET); - out_be32(drvdata->base_address + XPS2_IPISR_OFFSET, intr_sr); - - /* Check which interrupt is active */ - if (intr_sr & XPS2_IPIXR_RX_OVF) - dev_warn(drvdata->dev, "receive overrun error\n"); - - if (intr_sr & XPS2_IPIXR_RX_ERR) - drvdata->flags |= SERIO_PARITY; - - if (intr_sr & (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_WDT_TOUT)) - drvdata->flags |= SERIO_TIMEOUT; - - if (intr_sr & XPS2_IPIXR_RX_FULL) { - status = xps2_recv(drvdata, &c); - - /* Error, if a byte is not received */ - if (status) { - dev_err(drvdata->dev, - "wrong rcvd byte count (%d)\n", status); - } else { - serio_interrupt(drvdata->serio, c, drvdata->flags); - drvdata->flags = 0; - } - } - - return IRQ_HANDLED; -} - -/*******************/ -/* serio callbacks */ -/*******************/ - -/** - * sxps2_write() - sends a byte out through the PS/2 port. - * @pserio: pointer to the serio structure of the PS/2 port - * @c: data that needs to be written to the PS/2 port - * - * This function checks if the PS/2 transmitter is empty and sends a byte. - * Otherwise it returns error. Transmission fails only when nothing is connected - * to the PS/2 port. Thats why, we do not try to resend the data in case of a - * failure. - */ -static int sxps2_write(struct serio *pserio, unsigned char c) -{ - struct xps2data *drvdata = pserio->port_data; - u32 sr; - - guard(spinlock_irqsave)(&drvdata->lock); - - /* If the PS/2 transmitter is empty send a byte of data */ - sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET); - if (sr & XPS2_STATUS_TX_FULL) - return -EAGAIN; - - out_be32(drvdata->base_address + XPS2_TX_DATA_OFFSET, c); - return 0; -} - -/** - * sxps2_open() - called when a port is opened by the higher layer. - * @pserio: pointer to the serio structure of the PS/2 device - * - * This function requests irq and enables interrupts for the PS/2 device. - */ -static int sxps2_open(struct serio *pserio) -{ - struct xps2data *drvdata = pserio->port_data; - int error; - u8 c; - - error = request_irq(drvdata->irq, &xps2_interrupt, 0, - DRIVER_NAME, drvdata); - if (error) { - dev_err(drvdata->dev, - "Couldn't allocate interrupt %d\n", drvdata->irq); - return error; - } - - /* start reception by enabling the interrupts */ - out_be32(drvdata->base_address + XPS2_GIER_OFFSET, XPS2_GIER_GIE_MASK); - out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, XPS2_IPIXR_RX_ALL); - (void)xps2_recv(drvdata, &c); - - return 0; /* success */ -} - -/** - * sxps2_close() - frees the interrupt. - * @pserio: pointer to the serio structure of the PS/2 device - * - * This function frees the irq and disables interrupts for the PS/2 device. - */ -static void sxps2_close(struct serio *pserio) -{ - struct xps2data *drvdata = pserio->port_data; - - /* Disable the PS2 interrupts */ - out_be32(drvdata->base_address + XPS2_GIER_OFFSET, 0x00); - out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, 0x00); - free_irq(drvdata->irq, drvdata); -} - -/** - * xps2_of_probe - probe method for the PS/2 device. - * @ofdev: pointer to OF device structure - * - * This function probes the PS/2 device in the device tree. - * It initializes the driver data structure and the hardware. - * It returns 0, if the driver is bound to the PS/2 device, or a negative - * value if there is an error. - */ -static int xps2_of_probe(struct platform_device *ofdev) -{ - struct resource r_mem; /* IO mem resources */ - struct xps2data *drvdata; - struct serio *serio; - struct device *dev = &ofdev->dev; - resource_size_t remap_size, phys_addr; - unsigned int irq; - int error; - - dev_info(dev, "Device Tree Probing \'%pOFn\'\n", dev->of_node); - - /* Get iospace for the device */ - error = of_address_to_resource(dev->of_node, 0, &r_mem); - if (error) { - dev_err(dev, "invalid address\n"); - return error; - } - - /* Get IRQ for the device */ - irq = irq_of_parse_and_map(dev->of_node, 0); - if (!irq) { - dev_err(dev, "no IRQ found\n"); - return -ENODEV; - } - - drvdata = kzalloc_obj(*drvdata); - serio = kzalloc_obj(*serio); - if (!drvdata || !serio) { - error = -ENOMEM; - goto failed1; - } - - spin_lock_init(&drvdata->lock); - drvdata->irq = irq; - drvdata->serio = serio; - drvdata->dev = dev; - - phys_addr = r_mem.start; - remap_size = resource_size(&r_mem); - if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) { - dev_err(dev, "Couldn't lock memory region at 0x%08llX\n", - (unsigned long long)phys_addr); - error = -EBUSY; - goto failed1; - } - - /* Fill in configuration data and add them to the list */ - drvdata->base_address = ioremap(phys_addr, remap_size); - if (drvdata->base_address == NULL) { - dev_err(dev, "Couldn't ioremap memory at 0x%08llX\n", - (unsigned long long)phys_addr); - error = -EFAULT; - goto failed2; - } - - /* Disable all the interrupts, just in case */ - out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, 0); - - /* - * Reset the PS2 device and abort any current transaction, - * to make sure we have the PS2 in a good state. - */ - out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET); - - dev_info(dev, "Xilinx PS2 at 0x%08llX mapped to 0x%p, irq=%d\n", - (unsigned long long)phys_addr, drvdata->base_address, - drvdata->irq); - - serio->id.type = SERIO_8042; - serio->write = sxps2_write; - serio->open = sxps2_open; - serio->close = sxps2_close; - serio->port_data = drvdata; - serio->dev.parent = dev; - snprintf(serio->name, sizeof(serio->name), - "Xilinx XPS PS/2 at %08llX", (unsigned long long)phys_addr); - snprintf(serio->phys, sizeof(serio->phys), - "xilinxps2/serio at %08llX", (unsigned long long)phys_addr); - - serio_register_port(serio); - - platform_set_drvdata(ofdev, drvdata); - return 0; /* success */ - -failed2: - release_mem_region(phys_addr, remap_size); -failed1: - kfree(serio); - kfree(drvdata); - - return error; -} - -/** - * xps2_of_remove - unbinds the driver from the PS/2 device. - * @of_dev: pointer to OF device structure - * - * This function is called if a device is physically removed from the system or - * if the driver module is being unloaded. It frees any resources allocated to - * the device. - */ -static void xps2_of_remove(struct platform_device *of_dev) -{ - struct xps2data *drvdata = platform_get_drvdata(of_dev); - struct resource r_mem; /* IO mem resources */ - - serio_unregister_port(drvdata->serio); - iounmap(drvdata->base_address); - - /* Get iospace of the device */ - if (of_address_to_resource(of_dev->dev.of_node, 0, &r_mem)) - dev_err(drvdata->dev, "invalid address\n"); - else - release_mem_region(r_mem.start, resource_size(&r_mem)); - - kfree(drvdata); -} - -/* Match table for of_platform binding */ -static const struct of_device_id xps2_of_match[] = { - { .compatible = "xlnx,xps-ps2-1.00.a", }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(of, xps2_of_match); - -static struct platform_driver xps2_of_driver = { - .driver = { - .name = DRIVER_NAME, - .of_match_table = xps2_of_match, - }, - .probe = xps2_of_probe, - .remove = xps2_of_remove, -}; -module_platform_driver(xps2_of_driver); - -MODULE_AUTHOR("Xilinx, Inc."); -MODULE_DESCRIPTION("Xilinx XPS PS/2 driver"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index c850b5890070..0c1acb9e6b43 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -16,37 +16,6 @@ * * Many thanks to Oliver Kuechemann for his support. * - * ChangeLog: - * v0.1 - Initial release - * v0.2 - Hack to get around fake event 28's. (Bryan W. Headley) - * v0.3 - Make URB dynamic (Bryan W. Headley, Jun-8-2002) - * Released to Linux 2.4.19 and 2.5.x - * v0.4 - Rewrote substantial portions of the code to deal with - * corrected control sequences, timing, dynamic configuration, - * support of 6000U - 12000U, procfs, and macro key support - * (Jan-1-2003 - Feb-5-2003, Bryan W. Headley) - * v1.0 - Added support for diagnostic messages, count of messages - * received from URB - Mar-8-2003, Bryan W. Headley - * v1.1 - added support for tablet resolution, changed DV and proximity - * some corrections - Jun-22-2003, martin schneebacher - * - Added support for the sysfs interface, deprecating the - * procfs interface for 2.5.x kernel. Also added support for - * Wheel command. Bryan W. Headley July-15-2003. - * v1.2 - Reworked jitter timer as a kernel thread. - * Bryan W. Headley November-28-2003/Jan-10-2004. - * v1.3 - Repaired issue of kernel thread going nuts on single-processor - * machines, introduced programmableDelay as a command line - * parameter. Feb 7 2004, Bryan W. Headley. - * v1.4 - Re-wire jitter so it does not require a thread. Courtesy of - * Rene van Paassen. Added reporting of physical pointer device - * (e.g., stylus, mouse in reports 2, 3, 4, 5. We don't know - * for reports 1, 6.) - * what physical device reports for reports 1, 6.) Also enabled - * MOUSE and LENS tool button modes. Renamed "rubber" to "eraser". - * Feb 20, 2004, Bryan W. Headley. - * v1.5 - Added previousJitterable, so we don't do jitter delay when the - * user is holding a button down for periods of time. - * * NOTE: * This kernel driver is augmented by the "Aiptek" XFree86 input * driver for your X server, as well as the Gaiptek GUI Front-end diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index aeaf9a9cbb41..9b9ae8ac3f7f 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -610,6 +610,18 @@ config TOUCHSCREEN_WACOM_I2C To compile this driver as a module, choose M here: the module will be called wacom_i2c. +config TOUCHSCREEN_WACOM_W9000 + tristate "Wacom W9000-series penabled touchscreen (I2C)" + depends on I2C + help + Say Y here if you have a Wacom W9000-series penabled I2C touchscreen. + This driver supports models W9002 and W9007A. + + If unsure, say N. + + To compile this driver as a module, choose M here: the module + will be called wacom_w9000. + config TOUCHSCREEN_LPC32XX tristate "LPC32XX touchscreen controller" depends on ARCH_LPC32XX @@ -1178,16 +1190,6 @@ config TOUCHSCREEN_TSC2007_IIO or ambient light monitoring), temperature and raw input values. -config TOUCHSCREEN_PCAP - tristate "Motorola PCAP touchscreen" - depends on EZX_PCAP - help - Say Y here if you have a Motorola EZX telephone and - want to enable support for the built-in touchscreen. - - To compile this driver as a module, choose M here: the - module will be called pcap_ts. - config TOUCHSCREEN_RM_TS tristate "Raydium I2C Touchscreen" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index f2b002abebe8..bfd9de83389d 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -74,7 +74,6 @@ obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o obj-$(CONFIG_TOUCHSCREEN_IPAQ_MICRO) += ipaq-micro-ts.o obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o -obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o @@ -101,6 +100,7 @@ tsc2007-$(CONFIG_TOUCHSCREEN_TSC2007_IIO) += tsc2007_iio.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C) += wacom_i2c.o +obj-$(CONFIG_TOUCHSCREEN_WACOM_W9000) += wacom_w9000.o obj-$(CONFIG_TOUCHSCREEN_WDT87XX_I2C) += wdt87xx_i2c.o obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index e5b99312c3d9..c1ccdf86b74c 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -42,8 +42,8 @@ static int ad7879_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id ad7879_id[] = { - { "ad7879" }, - { "ad7889" }, + { .name = "ad7879" }, + { .name = "ad7889" }, { } }; MODULE_DEVICE_TABLE(i2c, ad7879_id); diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 4b39f7212d35..8d6416ac283e 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -134,6 +134,9 @@ struct ads7846 { bool disabled; /* P: lock */ bool suspended; /* P: lock */ + int (*setup_spi_msg)(struct ads7846 *ts, + const struct ads7846_platform_data *pdata); + void (*read_state)(struct ads7846 *ts); int (*filter)(void *data, int data_idx, int *val); void *filter_data; int (*get_pendown_state)(void); @@ -325,7 +328,6 @@ struct ser_req { u8 ref_on; u8 command; u8 ref_off; - u16 scratch; struct spi_message msg; struct spi_transfer xfer[8]; /* @@ -333,6 +335,7 @@ struct ser_req { * transfer buffers to live in their own cache lines. */ __be16 sample ____cacheline_aligned; + u16 scratch; }; struct ads7845_ser_req { @@ -403,8 +406,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) spi_message_add_tail(&req->xfer[5], &req->msg); /* clear the command register */ - req->scratch = 0; - req->xfer[6].tx_buf = &req->scratch; + req->xfer[6].rx_buf = &req->scratch; req->xfer[6].len = 1; spi_message_add_tail(&req->xfer[6], &req->msg); @@ -789,6 +791,22 @@ static int ads7846_filter(struct ads7846 *ts) return 0; } +static int ads7846_filter_one(struct ads7846 *ts, unsigned int cmd_idx) +{ + struct ads7846_packet *packet = ts->packet; + struct ads7846_buf_layout *l = &packet->l[cmd_idx]; + int action, val; + + val = ads7846_get_value(&packet->rx[l->offset + l->count - 1]); + action = ts->filter(ts->filter_data, cmd_idx, &val); + if (action == ADS7846_FILTER_REPEAT) + return -EAGAIN; + else if (action != ADS7846_FILTER_OK) + return -EIO; + ads7846_set_cmd_val(ts, cmd_idx, val); + return 0; +} + static void ads7846_wait_for_hsync(struct ads7846 *ts) { if (ts->wait_for_sync) { @@ -811,6 +829,45 @@ static void ads7846_wait_for_hsync(struct ads7846 *ts) cpu_relax(); } +static void ads7846_halfd_read_state(struct ads7846 *ts) +{ + struct ads7846_packet *packet = ts->packet; + int msg_idx = 0; + + packet->ignore = false; + + while (msg_idx < ts->msg_count) { + int error; + + ads7846_wait_for_hsync(ts); + + error = spi_sync(ts->spi, &ts->msg[msg_idx]); + if (error) { + dev_err_ratelimited(&ts->spi->dev, "spi_sync --> %d\n", + error); + packet->ignore = true; + return; + } + + /* + * Last message is power down request, no need to convert + * or filter the value. + */ + if (msg_idx == ts->msg_count - 1) + break; + + error = ads7846_filter_one(ts, msg_idx); + if (error == -EAGAIN) { + continue; + } else if (error) { + packet->ignore = true; + msg_idx = ts->msg_count - 1; + } else { + msg_idx++; + } + } +} + static void ads7846_read_state(struct ads7846 *ts) { struct ads7846_packet *packet = ts->packet; @@ -939,7 +996,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) while (!ts->stopped && get_pendown_state(ts)) { /* pen is down, continue with the measurement */ - ads7846_read_state(ts); + ts->read_state(ts); if (!ts->stopped) ads7846_report_state(ts); @@ -1026,6 +1083,102 @@ static int ads7846_setup_pendown(struct spi_device *spi, * Set up the transfers to read touchscreen state; this assumes we * use formula #2 for pressure, not #3. */ +static int ads7846_halfd_spi_msg(struct ads7846 *ts, + const struct ads7846_platform_data *pdata) +{ + struct spi_message *m = ts->msg; + struct spi_transfer *x = ts->xfer; + struct ads7846_packet *packet = ts->packet; + int vref = pdata->keep_vref_on; + unsigned int offset = 0; + unsigned int cmd_idx, b; + size_t size = 0; + + if (pdata->settle_delay_usecs) + packet->count = 2; + else + packet->count = 1; + + if (ts->model == 7846) + packet->cmds = 5; /* x, y, z1, z2, pwdown */ + else + packet->cmds = 3; /* x, y, pwdown */ + + for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) { + struct ads7846_buf_layout *l = &packet->l[cmd_idx]; + unsigned int max_count; + + if (cmd_idx == packet->cmds - 1) { + cmd_idx = ADS7846_PWDOWN; + max_count = 1; + } else { + max_count = packet->count; + } + + l->offset = offset; + offset += max_count; + l->count = max_count; + l->skip = 0; + size += sizeof(*packet->rx) * max_count; + } + + /* We use two transfers per command. */ + if (ARRAY_SIZE(ts->xfer) < offset * 2) + return -ENOMEM; + + packet->rx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL); + if (!packet->rx) + return -ENOMEM; + + if (ts->model == 7873) { + /* + * The AD7873 is almost identical to the ADS7846 + * keep VREF off during differential/ratiometric + * conversion modes. + */ + ts->model = 7846; + vref = 0; + } + + ts->msg_count = 0; + + for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) { + struct ads7846_buf_layout *l = &packet->l[cmd_idx]; + u8 cmd; + + ts->msg_count++; + spi_message_init(m); + m->context = ts; + + if (cmd_idx == packet->cmds - 1) + cmd_idx = ADS7846_PWDOWN; + + cmd = ads7846_get_cmd(cmd_idx, vref); + + for (b = 0; b < l->count; b++) { + packet->rx[l->offset + b].cmd = cmd; + x->tx_buf = &packet->rx[l->offset + b].cmd; + x->len = 1; + spi_message_add_tail(x, m); + x++; + x->rx_buf = &packet->rx[l->offset + b].data; + x->len = 2; + if (b < l->count - 1 && l->count > 1) { + x->delay.value = pdata->settle_delay_usecs; + x->delay.unit = SPI_DELAY_UNIT_USECS; + } + spi_message_add_tail(x, m); + x++; + } + m++; + } + return 0; +} + +/* + * Set up the transfers to read touchscreen state; this assumes we + * use formula #2 for pressure, not #3. + */ static int ads7846_setup_spi_msg(struct ads7846 *ts, const struct ads7846_platform_data *pdata) { @@ -1236,6 +1389,14 @@ static int ads7846_probe(struct spi_device *spi) if (!ts) return -ENOMEM; + if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) { + ts->setup_spi_msg = ads7846_halfd_spi_msg; + ts->read_state = ads7846_halfd_read_state; + } else { + ts->setup_spi_msg = ads7846_setup_spi_msg; + ts->read_state = ads7846_read_state; + } + packet = devm_kzalloc(dev, sizeof(struct ads7846_packet), GFP_KERNEL); if (!packet) return -ENOMEM; @@ -1330,7 +1491,9 @@ static int ads7846_probe(struct spi_device *spi) ts->core_prop.swap_x_y = true; } - ads7846_setup_spi_msg(ts, pdata); + err = ts->setup_spi_msg(ts, pdata); + if (err) + return err; ts->reg = devm_regulator_get(dev, "vcc"); if (IS_ERR(ts->reg)) { diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 8a588202447d..aa43fc1549df 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -164,7 +164,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume); static const struct i2c_device_id ar1021_i2c_id[] = { - { "ar1021" }, + { .name = "ar1021" }, { } }; MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id); diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index f21bf2844112..2c0e5a67135b 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1397,7 +1397,8 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg) { struct device *dev = &data->client->dev; struct mxt_object *object; - unsigned int type, instance, size, byte_offset; + unsigned int type, instance, size; + int byte_offset; int offset; int ret; int i; @@ -2840,14 +2841,12 @@ static ssize_t mxt_object_show(struct device *dev, int count = 0; int i, j; int error; - u8 *obuf; /* Pre-allocate buffer large enough to hold max sized object. */ - obuf = kmalloc(256, GFP_KERNEL); + u8 *obuf __free(kfree) = kmalloc(256, GFP_KERNEL); if (!obuf) return -ENOMEM; - error = 0; for (i = 0; i < data->info->object_num; i++) { object = data->object_table + i; @@ -2862,15 +2861,13 @@ static ssize_t mxt_object_show(struct device *dev, error = __mxt_read_reg(data->client, addr, size, obuf); if (error) - goto done; + return error; count = mxt_show_instance(buf, count, object, j, obuf); } } -done: - kfree(obuf); - return error ?: count; + return count; } static int mxt_check_firmware_format(struct device *dev, @@ -3420,11 +3417,11 @@ MODULE_DEVICE_TABLE(acpi, mxt_acpi_id); #endif static const struct i2c_device_id mxt_id[] = { - { "qt602240_ts" }, - { "atmel_mxt_ts" }, - { "atmel_mxt_tp" }, - { "maxtouch" }, - { "mXT224" }, + { .name = "qt602240_ts" }, + { .name = "atmel_mxt_ts" }, + { .name = "atmel_mxt_tp" }, + { .name = "maxtouch" }, + { .name = "mXT224" }, { } }; MODULE_DEVICE_TABLE(i2c, mxt_id); diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 401b2264f585..6c6ebebacba9 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -618,7 +618,7 @@ static int auo_pixcir_probe(struct i2c_client *client) } static const struct i2c_device_id auo_pixcir_idtable[] = { - { "auo_pixcir_ts" }, + { .name = "auo_pixcir_ts" }, { } }; MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable); diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index 6baebb7ec089..d1bdccc56fc8 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -597,7 +597,7 @@ static int bu21013_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume); static const struct i2c_device_id bu21013_id[] = { - { DRIVER_TP }, + { .name = DRIVER_TP }, { } }; MODULE_DEVICE_TABLE(i2c, bu21013_id); diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c index 68d9cd55ceeb..339fee1622fb 100644 --- a/drivers/input/touchscreen/bu21029_ts.c +++ b/drivers/input/touchscreen/bu21029_ts.c @@ -442,7 +442,7 @@ static int bu21029_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(bu21029_pm_ops, bu21029_suspend, bu21029_resume); static const struct i2c_device_id bu21029_ids[] = { - { DRIVER_NAME }, + { .name = DRIVER_NAME }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, bu21029_ids); diff --git a/drivers/input/touchscreen/cy8ctma140.c b/drivers/input/touchscreen/cy8ctma140.c index 2d4b6e343203..0ac48eff3376 100644 --- a/drivers/input/touchscreen/cy8ctma140.c +++ b/drivers/input/touchscreen/cy8ctma140.c @@ -322,7 +322,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctma140_pm, cy8ctma140_suspend, cy8ctma140_resume); static const struct i2c_device_id cy8ctma140_idtable[] = { - { CY8CTMA140_NAME }, + { .name = CY8CTMA140_NAME }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, cy8ctma140_idtable); diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index 54d6c4869eb0..33ad4f0512a0 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -267,7 +267,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume); static const struct i2c_device_id cy8ctmg110_idtable[] = { - { CY8CTMG110_DRIVER_NAME, 1 }, + { .name = CY8CTMG110_DRIVER_NAME, .driver_data = 1 }, { } }; diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c index 47f4271395a6..73c397e44da4 100644 --- a/drivers/input/touchscreen/cyttsp5.c +++ b/drivers/input/touchscreen/cyttsp5.c @@ -938,7 +938,7 @@ static const struct of_device_id cyttsp5_of_match[] = { MODULE_DEVICE_TABLE(of, cyttsp5_of_match); static const struct i2c_device_id cyttsp5_i2c_id[] = { - { CYTTSP5_NAME }, + { .name = CYTTSP5_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id); diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index cb15600549cd..17524f7e944d 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -103,7 +103,7 @@ static int cyttsp_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id cyttsp_i2c_id[] = { - { CY_I2C_NAME }, + { .name = CY_I2C_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 492e19a28a74..b12602bc368e 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -266,7 +266,7 @@ static int eeti_ts_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume); static const struct i2c_device_id eeti_ts_id[] = { - { "eeti_ts" }, + { .name = "eeti_ts" }, { } }; MODULE_DEVICE_TABLE(i2c, eeti_ts_id); diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index eb3cc2befcdf..76cf8085553f 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -219,7 +219,7 @@ static int egalax_ts_probe(struct i2c_client *client) } static const struct i2c_device_id egalax_ts_id[] = { - { "egalax_ts" }, + { .name = "egalax_ts" }, { } }; MODULE_DEVICE_TABLE(i2c, egalax_ts_id); diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 835d91dff0a4..17175adcaebb 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1615,9 +1615,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops, elants_i2c_suspend, elants_i2c_resume); static const struct i2c_device_id elants_i2c_id[] = { - { DEVICE_NAME, EKTH3500 }, - { "ekth3500", EKTH3500 }, - { "ektf3624", EKTF3624 }, + { .name = DEVICE_NAME, .driver_data = EKTH3500 }, + { .name = "ekth3500", .driver_data = EKTH3500 }, + { .name = "ektf3624", .driver_data = EKTF3624 }, { } }; MODULE_DEVICE_TABLE(i2c, elants_i2c_id); diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c index 78c0911ba6e2..037bb35238a3 100644 --- a/drivers/input/touchscreen/exc3000.c +++ b/drivers/input/touchscreen/exc3000.c @@ -432,10 +432,10 @@ static int exc3000_probe(struct i2c_client *client) } static const struct i2c_device_id exc3000_id[] = { - { "exc3000", EETI_EXC3000 }, - { "exc80h60", EETI_EXC80H60 }, - { "exc80h84", EETI_EXC80H84 }, - { "exc81w32", EETI_EXC81W32 }, + { .name = "exc3000", .driver_data = EETI_EXC3000 }, + { .name = "exc80h60", .driver_data = EETI_EXC80H60 }, + { .name = "exc80h84", .driver_data = EETI_EXC80H84 }, + { .name = "exc81w32", .driver_data = EETI_EXC81W32 }, { } }; MODULE_DEVICE_TABLE(i2c, exc3000_id); diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index f8798d11ec03..03efc0c792c2 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -1057,7 +1057,8 @@ static void goodix_read_config(struct goodix_ts_data *ts) } ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03; - ts->max_touch_num = ts->config[MAX_CONTACTS_LOC] & 0x0f; + ts->max_touch_num = min(ts->config[MAX_CONTACTS_LOC] & 0x0f, + GOODIX_MAX_CONTACTS); x_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC]); y_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC + 2]); @@ -1523,7 +1524,7 @@ static int goodix_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume); static const struct i2c_device_id goodix_ts_id[] = { - { "GDIX1001:00" }, + { .name = "GDIX1001:00" }, { } }; MODULE_DEVICE_TABLE(i2c, goodix_ts_id); diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index 62041bcca83d..58e00c314ace 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -1081,7 +1081,7 @@ static int hideep_probe(struct i2c_client *client) } static const struct i2c_device_id hideep_i2c_id[] = { - { HIDEEP_I2C_NAME }, + { .name = HIDEEP_I2C_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, hideep_i2c_id); diff --git a/drivers/input/touchscreen/himax_hx83112b.c b/drivers/input/touchscreen/himax_hx83112b.c index 896a145ddb2b..0aa67dfacbad 100644 --- a/drivers/input/touchscreen/himax_hx83112b.c +++ b/drivers/input/touchscreen/himax_hx83112b.c @@ -406,8 +406,8 @@ static const struct himax_chip hx83112b_chip = { }; static const struct i2c_device_id himax_ts_id[] = { - { "hx83100a", (kernel_ulong_t)&hx83100a_chip }, - { "hx83112b", (kernel_ulong_t)&hx83112b_chip }, + { .name = "hx83100a", .driver_data = (kernel_ulong_t)&hx83100a_chip }, + { .name = "hx83112b", .driver_data = (kernel_ulong_t)&hx83112b_chip }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, himax_ts_id); diff --git a/drivers/input/touchscreen/hynitron-cst816x.c b/drivers/input/touchscreen/hynitron-cst816x.c index b64d7928e18f..47d9cd7412d1 100644 --- a/drivers/input/touchscreen/hynitron-cst816x.c +++ b/drivers/input/touchscreen/hynitron-cst816x.c @@ -226,7 +226,7 @@ static int cst816x_probe(struct i2c_client *client) } static const struct i2c_device_id cst816x_id[] = { - { .name = "cst816s", 0 }, + { .name = "cst816s" }, { } }; MODULE_DEVICE_TABLE(i2c, cst816x_id); diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 3bf524a6ee20..66ada7ffbc80 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -1049,10 +1049,10 @@ static int ili210x_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id ili210x_i2c_id[] = { - { "ili210x", (long)&ili210x_chip }, - { "ili2117", (long)&ili211x_chip }, - { "ili2120", (long)&ili212x_chip }, - { "ili251x", (long)&ili251x_chip }, + { .name = "ili210x", .driver_data = (long)&ili210x_chip }, + { .name = "ili2117", .driver_data = (long)&ili211x_chip }, + { .name = "ili2120", .driver_data = (long)&ili212x_chip }, + { .name = "ili251x", .driver_data = (long)&ili251x_chip }, { } }; MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c index 0706443792ba..3de0fbf8da38 100644 --- a/drivers/input/touchscreen/ilitek_ts_i2c.c +++ b/drivers/input/touchscreen/ilitek_ts_i2c.c @@ -639,7 +639,7 @@ static int ilitek_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(ilitek_pm_ops, ilitek_suspend, ilitek_resume); static const struct i2c_device_id ilitek_ts_i2c_id[] = { - { ILITEK_TS_NAME }, + { .name = ILITEK_TS_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, ilitek_ts_i2c_id); diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 587665e4e6fd..b9bbe8b3eab8 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -1049,9 +1049,9 @@ static int iqs5xx_probe(struct i2c_client *client) } static const struct i2c_device_id iqs5xx_id[] = { - { "iqs550", 0 }, - { "iqs572", 1 }, - { "iqs525", 2 }, + { .name = "iqs550" }, + { .name = "iqs572" }, + { .name = "iqs525" }, { } }; MODULE_DEVICE_TABLE(i2c, iqs5xx_id); diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index f39633fc8dc2..3996e4a61ff7 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -213,7 +213,7 @@ static int max11801_ts_probe(struct i2c_client *client) } static const struct i2c_device_id max11801_ts_id[] = { - { "max11801" }, + { .name = "max11801" }, { } }; MODULE_DEVICE_TABLE(i2c, max11801_ts_id); diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 10fccf4e5bb1..fd6c0ac301a2 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -1536,7 +1536,7 @@ MODULE_DEVICE_TABLE(acpi, mip4_acpi_match); #endif static const struct i2c_device_id mip4_i2c_ids[] = { - { MIP4_DEVICE_NAME }, + { .name = MIP4_DEVICE_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, mip4_i2c_ids); diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c index 993d945dcd23..9d221e340404 100644 --- a/drivers/input/touchscreen/migor_ts.c +++ b/drivers/input/touchscreen/migor_ts.c @@ -211,7 +211,7 @@ static int migor_ts_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume); static const struct i2c_device_id migor_ts_id[] = { - { "migor_ts" }, + { .name = "migor_ts" }, { } }; MODULE_DEVICE_TABLE(i2c, migor_ts_id); diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index af462086a65c..53ad35d61d47 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -217,7 +217,9 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) struct mms114_data *data = dev_id; struct i2c_client *client = data->client; struct mms114_touch touch[MMS114_MAX_TOUCH]; + struct mms114_touch *t; int packet_size; + int event_size; int touch_size; int index; int error; @@ -226,11 +228,19 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) if (packet_size <= 0) goto out; + if (packet_size > sizeof(touch)) { + dev_err(&client->dev, "Invalid packet size %d (max %zu)\n", + packet_size, sizeof(touch)); + goto out; + } + /* MMS136 has slightly different event size */ if (data->type == TYPE_MMS134S || data->type == TYPE_MMS136) - touch_size = packet_size / MMS136_EVENT_SIZE; + event_size = MMS136_EVENT_SIZE; else - touch_size = packet_size / MMS114_EVENT_SIZE; + event_size = MMS114_EVENT_SIZE; + + touch_size = packet_size / event_size; error = __mms114_read_reg(data, MMS114_INFORMATION, packet_size, (u8 *)touch); @@ -238,18 +248,20 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) goto out; for (index = 0; index < touch_size; index++) { - switch (touch[index].type) { + t = (struct mms114_touch *)((u8 *)touch + index * event_size); + + switch (t->type) { case MMS114_TYPE_TOUCHSCREEN: - mms114_process_mt(data, touch + index); + mms114_process_mt(data, t); break; case MMS114_TYPE_TOUCHKEY: - mms114_process_touchkey(data, touch + index); + mms114_process_touchkey(data, t); break; default: dev_err(&client->dev, "Wrong touch type (%d)\n", - touch[index].type); + t->type); break; } } @@ -667,7 +679,7 @@ static int mms114_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume); static const struct i2c_device_id mms114_id[] = { - { "mms114" }, + { .name = "mms114" }, { } }; MODULE_DEVICE_TABLE(i2c, mms114_id); diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c index 708bfb933ddd..0f771f681952 100644 --- a/drivers/input/touchscreen/novatek-nvt-ts.c +++ b/drivers/input/touchscreen/novatek-nvt-ts.c @@ -326,8 +326,8 @@ static const struct of_device_id nvt_ts_of_match[] = { MODULE_DEVICE_TABLE(of, nvt_ts_of_match); static const struct i2c_device_id nvt_ts_i2c_id[] = { - { "nt11205-ts", (unsigned long) &nvt_nt11205_ts_data }, - { "nt36672a-ts", (unsigned long) &nvt_nt36672a_ts_data }, + { .name = "nt11205-ts", .driver_data = (unsigned long)&nvt_nt11205_ts_data }, + { .name = "nt36672a-ts", .driver_data = (unsigned long)&nvt_nt36672a_ts_data }, { } }; MODULE_DEVICE_TABLE(i2c, nvt_ts_i2c_id); diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c deleted file mode 100644 index 7b89eb74b9de..000000000000 --- a/drivers/input/touchscreen/pcap_ts.c +++ /dev/null @@ -1,252 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for Motorola PCAP2 touchscreen as found in the EZX phone platform. - * - * Copyright (C) 2006 Harald Welte <laforge@openezx.org> - * Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com> - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/pm.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/input.h> -#include <linux/mfd/ezx-pcap.h> - -struct pcap_ts { - struct pcap_chip *pcap; - struct input_dev *input; - struct delayed_work work; - u16 x, y; - u16 pressure; - u8 read_state; -}; - -#define SAMPLE_DELAY 20 /* msecs */ - -#define X_AXIS_MIN 0 -#define X_AXIS_MAX 1023 -#define Y_AXIS_MAX X_AXIS_MAX -#define Y_AXIS_MIN X_AXIS_MIN -#define PRESSURE_MAX X_AXIS_MAX -#define PRESSURE_MIN X_AXIS_MIN - -static void pcap_ts_read_xy(void *data, u16 res[2]) -{ - struct pcap_ts *pcap_ts = data; - - switch (pcap_ts->read_state) { - case PCAP_ADC_TS_M_PRESSURE: - /* pressure reading is unreliable */ - if (res[0] > PRESSURE_MIN && res[0] < PRESSURE_MAX) - pcap_ts->pressure = res[0]; - pcap_ts->read_state = PCAP_ADC_TS_M_XY; - schedule_delayed_work(&pcap_ts->work, 0); - break; - case PCAP_ADC_TS_M_XY: - pcap_ts->y = res[0]; - pcap_ts->x = res[1]; - if (pcap_ts->x <= X_AXIS_MIN || pcap_ts->x >= X_AXIS_MAX || - pcap_ts->y <= Y_AXIS_MIN || pcap_ts->y >= Y_AXIS_MAX) { - /* pen has been released */ - input_report_abs(pcap_ts->input, ABS_PRESSURE, 0); - input_report_key(pcap_ts->input, BTN_TOUCH, 0); - - pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY; - schedule_delayed_work(&pcap_ts->work, 0); - } else { - /* pen is touching the screen */ - input_report_abs(pcap_ts->input, ABS_X, pcap_ts->x); - input_report_abs(pcap_ts->input, ABS_Y, pcap_ts->y); - input_report_key(pcap_ts->input, BTN_TOUCH, 1); - input_report_abs(pcap_ts->input, ABS_PRESSURE, - pcap_ts->pressure); - - /* switch back to pressure read mode */ - pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE; - schedule_delayed_work(&pcap_ts->work, - msecs_to_jiffies(SAMPLE_DELAY)); - } - input_sync(pcap_ts->input); - break; - default: - dev_warn(&pcap_ts->input->dev, - "pcap_ts: Warning, unhandled read_state %d\n", - pcap_ts->read_state); - break; - } -} - -static void pcap_ts_work(struct work_struct *work) -{ - struct delayed_work *dw = to_delayed_work(work); - struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work); - u8 ch[2]; - - pcap_set_ts_bits(pcap_ts->pcap, - pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); - - if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) - return; - - /* start adc conversion */ - ch[0] = PCAP_ADC_CH_TS_X1; - ch[1] = PCAP_ADC_CH_TS_Y1; - pcap_adc_async(pcap_ts->pcap, PCAP_ADC_BANK_1, 0, ch, - pcap_ts_read_xy, pcap_ts); -} - -static irqreturn_t pcap_ts_event_touch(int pirq, void *data) -{ - struct pcap_ts *pcap_ts = data; - - if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) { - pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE; - schedule_delayed_work(&pcap_ts->work, 0); - } - return IRQ_HANDLED; -} - -static int pcap_ts_open(struct input_dev *dev) -{ - struct pcap_ts *pcap_ts = input_get_drvdata(dev); - - pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY; - schedule_delayed_work(&pcap_ts->work, 0); - - return 0; -} - -static void pcap_ts_close(struct input_dev *dev) -{ - struct pcap_ts *pcap_ts = input_get_drvdata(dev); - - cancel_delayed_work_sync(&pcap_ts->work); - - pcap_ts->read_state = PCAP_ADC_TS_M_NONTS; - pcap_set_ts_bits(pcap_ts->pcap, - pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); -} - -static int pcap_ts_probe(struct platform_device *pdev) -{ - struct input_dev *input_dev; - struct pcap_ts *pcap_ts; - int err = -ENOMEM; - - pcap_ts = kzalloc_obj(*pcap_ts); - if (!pcap_ts) - return err; - - pcap_ts->pcap = dev_get_drvdata(pdev->dev.parent); - platform_set_drvdata(pdev, pcap_ts); - - input_dev = input_allocate_device(); - if (!input_dev) - goto fail; - - INIT_DELAYED_WORK(&pcap_ts->work, pcap_ts_work); - - pcap_ts->read_state = PCAP_ADC_TS_M_NONTS; - pcap_set_ts_bits(pcap_ts->pcap, - pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); - - pcap_ts->input = input_dev; - input_set_drvdata(input_dev, pcap_ts); - - input_dev->name = "pcap-touchscreen"; - input_dev->phys = "pcap_ts/input0"; - input_dev->id.bustype = BUS_HOST; - input_dev->id.vendor = 0x0001; - input_dev->id.product = 0x0002; - input_dev->id.version = 0x0100; - input_dev->dev.parent = &pdev->dev; - input_dev->open = pcap_ts_open; - input_dev->close = pcap_ts_close; - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); - input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); - input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN, - PRESSURE_MAX, 0, 0); - - err = input_register_device(pcap_ts->input); - if (err) - goto fail_allocate; - - err = request_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), - pcap_ts_event_touch, 0, "Touch Screen", pcap_ts); - if (err) - goto fail_register; - - return 0; - -fail_register: - input_unregister_device(input_dev); - goto fail; -fail_allocate: - input_free_device(input_dev); -fail: - kfree(pcap_ts); - - return err; -} - -static void pcap_ts_remove(struct platform_device *pdev) -{ - struct pcap_ts *pcap_ts = platform_get_drvdata(pdev); - - free_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), pcap_ts); - cancel_delayed_work_sync(&pcap_ts->work); - - input_unregister_device(pcap_ts->input); - - kfree(pcap_ts); -} - -#ifdef CONFIG_PM -static int pcap_ts_suspend(struct device *dev) -{ - struct pcap_ts *pcap_ts = dev_get_drvdata(dev); - - pcap_set_ts_bits(pcap_ts->pcap, PCAP_ADC_TS_REF_LOWPWR); - return 0; -} - -static int pcap_ts_resume(struct device *dev) -{ - struct pcap_ts *pcap_ts = dev_get_drvdata(dev); - - pcap_set_ts_bits(pcap_ts->pcap, - pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT); - return 0; -} - -static const struct dev_pm_ops pcap_ts_pm_ops = { - .suspend = pcap_ts_suspend, - .resume = pcap_ts_resume, -}; -#define PCAP_TS_PM_OPS (&pcap_ts_pm_ops) -#else -#define PCAP_TS_PM_OPS NULL -#endif - -static struct platform_driver pcap_ts_driver = { - .probe = pcap_ts_probe, - .remove = pcap_ts_remove, - .driver = { - .name = "pcap-ts", - .pm = PCAP_TS_PM_OPS, - }, -}; -module_platform_driver(pcap_ts_driver); - -MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver"); -MODULE_AUTHOR("Daniel Ribeiro / Harald Welte"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pcap_ts"); diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index c6b3615c8775..1ca5920846df 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -580,8 +580,8 @@ static const struct pixcir_i2c_chip_data pixcir_tangoc_data = { }; static const struct i2c_device_id pixcir_i2c_ts_id[] = { - { "pixcir_ts", (unsigned long) &pixcir_ts_data }, - { "pixcir_tangoc", (unsigned long) &pixcir_tangoc_data }, + { .name = "pixcir_ts", .driver_data = (unsigned long)&pixcir_ts_data }, + { .name = "pixcir_tangoc", .driver_data = (unsigned long)&pixcir_tangoc_data }, { } }; MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id); diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index f2d33ad86fd2..0256055abcef 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -1219,8 +1219,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops, raydium_i2c_suspend, raydium_i2c_resume); static const struct i2c_device_id raydium_i2c_id[] = { - { "raydium_i2c" }, - { "rm32380" }, + { .name = "raydium_i2c" }, + { .name = "rm32380" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, raydium_i2c_id); diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c index 295d8d75ba32..a5c06b7423c0 100644 --- a/drivers/input/touchscreen/rohm_bu21023.c +++ b/drivers/input/touchscreen/rohm_bu21023.c @@ -1144,7 +1144,7 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id rohm_bu21023_i2c_id[] = { - { BU21023_NAME }, + { .name = BU21023_NAME }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id); diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761.c index e1518a75a51b..0f24a9b73063 100644 --- a/drivers/input/touchscreen/s6sy761.c +++ b/drivers/input/touchscreen/s6sy761.c @@ -520,7 +520,7 @@ MODULE_DEVICE_TABLE(of, s6sy761_of_match); #endif static const struct i2c_device_id s6sy761_id[] = { - { "s6sy761" }, + { .name = "s6sy761" }, { } }; MODULE_DEVICE_TABLE(i2c, s6sy761_id); diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index 5ccc96764742..44d7141103f4 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -776,12 +776,12 @@ static int silead_ts_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume); static const struct i2c_device_id silead_ts_id[] = { - { "gsl1680" }, - { "gsl1688" }, - { "gsl3670" }, - { "gsl3675" }, - { "gsl3692" }, - { "mssl1680" }, + { .name = "gsl1680" }, + { .name = "gsl1688" }, + { .name = "gsl3670" }, + { .name = "gsl3675" }, + { .name = "gsl3692" }, + { .name = "mssl1680" }, { } }; MODULE_DEVICE_TABLE(i2c, silead_ts_id); diff --git a/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c index a625f2ad809d..4fa93cd31ee4 100644 --- a/drivers/input/touchscreen/sis_i2c.c +++ b/drivers/input/touchscreen/sis_i2c.c @@ -374,8 +374,8 @@ MODULE_DEVICE_TABLE(of, sis_ts_dt_ids); #endif static const struct i2c_device_id sis_ts_id[] = { - { SIS_I2C_NAME }, - { "9200-ts" }, + { .name = SIS_I2C_NAME }, + { .name = "9200-ts" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, sis_ts_id); diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 9b266927b7fe..c2dcfce5003d 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -453,8 +453,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops, st1232_ts_suspend, st1232_ts_resume); static const struct i2c_device_id st1232_ts_id[] = { - { ST1232_TS_NAME, (unsigned long)&st1232_chip_info }, - { ST1633_TS_NAME, (unsigned long)&st1633_chip_info }, + { .name = ST1232_TS_NAME, .driver_data = (unsigned long)&st1232_chip_info }, + { .name = ST1633_TS_NAME, .driver_data = (unsigned long)&st1633_chip_info }, { } }; MODULE_DEVICE_TABLE(i2c, st1232_ts_id); diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index 8af87d0b6eb6..972687797f82 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -5,6 +5,7 @@ // Copyright (c) 2017 Andi Shyti <andi@etezian.org> #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> @@ -69,20 +70,21 @@ #define STMFTS_MAX_FINGERS 10 #define STMFTS_DEV_NAME "stmfts" -enum stmfts_regulators { - STMFTS_REGULATOR_VDD, - STMFTS_REGULATOR_AVDD, +static const struct regulator_bulk_data stmfts_supplies[] = { + { .supply = "vdd" }, + { .supply = "avdd" }, }; struct stmfts_data { struct i2c_client *client; struct input_dev *input; + struct gpio_desc *reset_gpio; struct led_classdev led_cdev; struct mutex mutex; struct touchscreen_properties prop; - struct regulator_bulk_data regulators[2]; + struct regulator_bulk_data *supplies; /* * Presence of ledvdd will be used also to check @@ -107,7 +109,7 @@ struct stmfts_data { }; static int stmfts_brightness_set(struct led_classdev *led_cdev, - enum led_brightness value) + enum led_brightness value) { struct stmfts_data *sdata = container_of(led_cdev, struct stmfts_data, led_cdev); @@ -250,7 +252,6 @@ static void stmfts_parse_events(struct stmfts_data *sdata) u8 *event = &sdata->data[i * STMFTS_EVENT_SIZE]; switch (event[0]) { - case STMFTS_EV_CONTROLLER_READY: case STMFTS_EV_SLEEP_OUT_CONTROLLER_READY: case STMFTS_EV_STATUS: @@ -263,7 +264,6 @@ static void stmfts_parse_events(struct stmfts_data *sdata) } switch (event[0] & STMFTS_MASK_EVENT_ID) { - case STMFTS_EV_MULTI_TOUCH_ENTER: case STMFTS_EV_MULTI_TOUCH_MOTION: stmfts_report_contact_event(sdata, event); @@ -285,9 +285,9 @@ static void stmfts_parse_events(struct stmfts_data *sdata) case STMFTS_EV_ERROR: dev_warn(&sdata->client->dev, - "error code: 0x%x%x%x%x%x%x", - event[6], event[5], event[4], - event[3], event[2], event[1]); + "error code: 0x%x%x%x%x%x%x", + event[6], event[5], event[4], + event[3], event[2], event[1]); break; default: @@ -404,7 +404,7 @@ static void stmfts_input_close(struct input_dev *dev) } static ssize_t stmfts_sysfs_chip_id(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -412,7 +412,8 @@ static ssize_t stmfts_sysfs_chip_id(struct device *dev, } static ssize_t stmfts_sysfs_chip_version(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -420,7 +421,7 @@ static ssize_t stmfts_sysfs_chip_version(struct device *dev, } static ssize_t stmfts_sysfs_fw_ver(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -428,7 +429,7 @@ static ssize_t stmfts_sysfs_fw_ver(struct device *dev, } static ssize_t stmfts_sysfs_config_id(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -436,7 +437,8 @@ static ssize_t stmfts_sysfs_config_id(struct device *dev, } static ssize_t stmfts_sysfs_config_version(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -444,7 +446,8 @@ static ssize_t stmfts_sysfs_config_version(struct device *dev, } static ssize_t stmfts_sysfs_read_status(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); u8 status[4]; @@ -459,7 +462,8 @@ static ssize_t stmfts_sysfs_read_status(struct device *dev, } static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { struct stmfts_data *sdata = dev_get_drvdata(dev); @@ -467,8 +471,8 @@ static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev, } static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) + struct device_attribute *attr, + const char *buf, size_t len) { struct stmfts_data *sdata = dev_get_drvdata(dev); unsigned long value; @@ -485,8 +489,8 @@ static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev, if (hover != sdata->hover_enabled) { if (sdata->running) { err = i2c_smbus_write_byte(sdata->client, - value ? STMFTS_SS_HOVER_SENSE_ON : - STMFTS_SS_HOVER_SENSE_OFF); + value ? STMFTS_SS_HOVER_SENSE_ON : + STMFTS_SS_HOVER_SENSE_OFF); if (err) return err; } @@ -518,22 +522,11 @@ static struct attribute *stmfts_sysfs_attrs[] = { }; ATTRIBUTE_GROUPS(stmfts_sysfs); -static int stmfts_power_on(struct stmfts_data *sdata) +static int stmfts_read_system_info(struct stmfts_data *sdata) { int err; u8 reg[8]; - err = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators), - sdata->regulators); - if (err) - return err; - - /* - * The datasheet does not specify the power on time, but considering - * that the reset time is < 10ms, I sleep 20ms to be sure - */ - msleep(20); - err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_INFO, sizeof(reg), reg); if (err < 0) @@ -547,9 +540,21 @@ static int stmfts_power_on(struct stmfts_data *sdata) sdata->config_id = reg[4]; sdata->config_ver = reg[5]; - enable_irq(sdata->client->irq); + return 0; +} +static void stmfts_reset(struct stmfts_data *sdata) +{ + gpiod_set_value_cansleep(sdata->reset_gpio, 1); + msleep(20); + + gpiod_set_value_cansleep(sdata->reset_gpio, 0); msleep(50); +} + +static int stmfts_configure(struct stmfts_data *sdata) +{ + int err; err = stmfts_command(sdata, STMFTS_SYSTEM_RESET); if (err) @@ -575,13 +580,52 @@ static int stmfts_power_on(struct stmfts_data *sdata) if (err) return err; + return 0; +} + +static int stmfts_power_on(struct stmfts_data *sdata) +{ + int err; + + err = regulator_bulk_enable(ARRAY_SIZE(stmfts_supplies), + sdata->supplies); + if (err) + return err; + + /* + * The datasheet does not specify the power on time, but considering + * that the reset time is < 10ms, I sleep 20ms to be sure + */ + msleep(20); + + if (sdata->reset_gpio) + stmfts_reset(sdata); + + err = stmfts_read_system_info(sdata); + if (err) + goto err_disable_regulators; + + enable_irq(sdata->client->irq); + + msleep(50); + + err = stmfts_configure(sdata); + if (err) + goto err_disable_irq; + /* * At this point no one is using the touchscreen * and I don't really care about the return value */ - (void) i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN); + (void)i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN); return 0; + +err_disable_irq: + disable_irq(sdata->client->irq); +err_disable_regulators: + regulator_bulk_disable(ARRAY_SIZE(stmfts_supplies), sdata->supplies); + return err; } static void stmfts_power_off(void *data) @@ -589,8 +633,11 @@ static void stmfts_power_off(void *data) struct stmfts_data *sdata = data; disable_irq(sdata->client->irq); - regulator_bulk_disable(ARRAY_SIZE(sdata->regulators), - sdata->regulators); + + if (sdata->reset_gpio) + gpiod_set_value_cansleep(sdata->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(stmfts_supplies), sdata->supplies); } static int stmfts_enable_led(struct stmfts_data *sdata) @@ -619,6 +666,7 @@ static int stmfts_enable_led(struct stmfts_data *sdata) static int stmfts_probe(struct i2c_client *client) { + struct device *dev = &client->dev; int err; struct stmfts_data *sdata; @@ -627,7 +675,7 @@ static int stmfts_probe(struct i2c_client *client) I2C_FUNC_SMBUS_I2C_BLOCK)) return -ENODEV; - sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL); + sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL); if (!sdata) return -ENOMEM; @@ -637,15 +685,19 @@ static int stmfts_probe(struct i2c_client *client) mutex_init(&sdata->mutex); init_completion(&sdata->cmd_done); - sdata->regulators[STMFTS_REGULATOR_VDD].supply = "vdd"; - sdata->regulators[STMFTS_REGULATOR_AVDD].supply = "avdd"; - err = devm_regulator_bulk_get(&client->dev, - ARRAY_SIZE(sdata->regulators), - sdata->regulators); + err = devm_regulator_bulk_get_const(dev, + ARRAY_SIZE(stmfts_supplies), + stmfts_supplies, + &sdata->supplies); if (err) return err; - sdata->input = devm_input_allocate_device(&client->dev); + sdata->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(sdata->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(sdata->reset_gpio), + "Failed to get GPIO 'reset'\n"); + + sdata->input = devm_input_allocate_device(dev); if (!sdata->input) return -ENOMEM; @@ -664,8 +716,7 @@ static int stmfts_probe(struct i2c_client *client) input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0); input_set_abs_params(sdata->input, ABS_DISTANCE, 0, 255, 0, 0); - sdata->use_key = device_property_read_bool(&client->dev, - "touch-key-connected"); + sdata->use_key = device_property_read_bool(dev, "touch-key-connected"); if (sdata->use_key) { input_set_capability(sdata->input, EV_KEY, KEY_MENU); input_set_capability(sdata->input, EV_KEY, KEY_BACK); @@ -685,20 +736,20 @@ static int stmfts_probe(struct i2c_client *client) * interrupts. To be on the safe side it's better to not enable * the interrupts during their request. */ - err = devm_request_threaded_irq(&client->dev, client->irq, + err = devm_request_threaded_irq(dev, client->irq, NULL, stmfts_irq_handler, IRQF_ONESHOT | IRQF_NO_AUTOEN, "stmfts_irq", sdata); if (err) return err; - dev_dbg(&client->dev, "initializing ST-Microelectronics FTS...\n"); + dev_dbg(dev, "initializing ST-Microelectronics FTS...\n"); err = stmfts_power_on(sdata); if (err) return err; - err = devm_add_action_or_reset(&client->dev, stmfts_power_off, sdata); + err = devm_add_action_or_reset(dev, stmfts_power_off, sdata); if (err) return err; @@ -715,13 +766,13 @@ static int stmfts_probe(struct i2c_client *client) * without LEDs. The ledvdd regulator pointer will be * used as a flag. */ - dev_warn(&client->dev, "unable to use touchkey leds\n"); + dev_warn(dev, "unable to use touchkey leds\n"); sdata->ledvdd = NULL; } } - pm_runtime_enable(&client->dev); - device_enable_async_suspend(&client->dev); + pm_runtime_enable(dev); + device_enable_async_suspend(dev); return 0; } @@ -746,9 +797,10 @@ static int stmfts_runtime_suspend(struct device *dev) static int stmfts_runtime_resume(struct device *dev) { struct stmfts_data *sdata = dev_get_drvdata(dev); + struct i2c_client *client = sdata->client; int ret; - ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_OUT); + ret = i2c_smbus_write_byte(client, STMFTS_SLEEP_OUT); if (ret) dev_err(dev, "failed to resume device: %d\n", ret); @@ -785,7 +837,7 @@ MODULE_DEVICE_TABLE(of, stmfts_of_match); #endif static const struct i2c_device_id stmfts_id[] = { - { "stmfts" }, + { .name = "stmfts" }, { } }; MODULE_DEVICE_TABLE(i2c, stmfts_id); @@ -807,4 +859,4 @@ module_i2c_driver(stmfts_driver); MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>"); MODULE_DESCRIPTION("STMicroelectronics FTS Touch Screen"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c index 099fd88e65d8..3ed33378dfcd 100644 --- a/drivers/input/touchscreen/touchwin.c +++ b/drivers/input/touchscreen/touchwin.c @@ -63,12 +63,15 @@ static irqreturn_t tw_interrupt(struct serio *serio, if (data) { /* touch */ tw->touched = 1; tw->data[tw->idx++] = data; - /* verify length and that the two Y's are the same */ - if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) { - input_report_abs(dev, ABS_X, tw->data[0]); - input_report_abs(dev, ABS_Y, tw->data[1]); - input_report_key(dev, BTN_TOUCH, 1); - input_sync(dev); + /* a full packet ends the accumulation, valid or not */ + if (tw->idx == TW_LENGTH) { + /* report only if the two Y's are the same */ + if (tw->data[1] == tw->data[2]) { + input_report_abs(dev, ABS_X, tw->data[0]); + input_report_abs(dev, ABS_Y, tw->data[1]); + input_report_key(dev, BTN_TOUCH, 1); + input_sync(dev); + } tw->idx = 0; } } else if (tw->touched) { /* untouch */ diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c index 787f2caf4f73..130aeb735b65 100644 --- a/drivers/input/touchscreen/tsc2004.c +++ b/drivers/input/touchscreen/tsc2004.c @@ -43,7 +43,7 @@ static int tsc2004_probe(struct i2c_client *i2c) } static const struct i2c_device_id tsc2004_idtable[] = { - { "tsc2004" }, + { .name = "tsc2004" }, { } }; MODULE_DEVICE_TABLE(i2c, tsc2004_idtable); diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 524f14eb3da2..4a775c5df0ea 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -61,10 +61,8 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc) /* turn y+ off, x- on; we'll use formula #1 */ tc->z1 = tsc2007_xfer(tsc, READ_Z1); - tc->z2 = tsc2007_xfer(tsc, READ_Z2); - - /* Prepare for next touch reading - power down ADC, enable PENIRQ */ - tsc2007_xfer(tsc, PWRDOWN); + /* Read Z2 and power down ADC after A/D conversion, enable PENIRQ */ + tc->z2 = tsc2007_xfer(tsc, (TSC2007_POWER_OFF_IRQ_EN | TSC2007_MEASURE_Z2)); } u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc) @@ -407,7 +405,7 @@ static int tsc2007_probe(struct i2c_client *client) } static const struct i2c_device_id tsc2007_idtable[] = { - { "tsc2007" }, + { .name = "tsc2007" }, { } }; diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index fd97a83f5664..dd7c2a8a831b 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -253,7 +253,7 @@ static int wacom_i2c_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume); static const struct i2c_device_id wacom_i2c_id[] = { - { "WAC_I2C_EMR" }, + { .name = "WAC_I2C_EMR" }, { } }; MODULE_DEVICE_TABLE(i2c, wacom_i2c_id); diff --git a/drivers/input/touchscreen/wacom_w9000.c b/drivers/input/touchscreen/wacom_w9000.c new file mode 100644 index 000000000000..4a2629a54167 --- /dev/null +++ b/drivers/input/touchscreen/wacom_w9000.c @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Wacom W9000-series penabled I2C touchscreen driver + * + * Copyright (c) 2026 Hendrik Noack <hendrik-noack@gmx.de> + * + * Partially based on vendor driver: + * Copyright (C) 2012, Samsung Electronics Co. Ltd. + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/touchscreen.h> +#include <linux/interrupt.h> +#include <linux/lockdep.h> +#include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + +/* Some chips have flaky firmware that requires many retries before responding. */ +#define CMD_QUERY_RETRIES 8 + +/* Message length */ +#define CMD_QUERY_NUM_MAX 9 +#define MSG_COORD_NUM_MAX 12 + +/* Commands */ +#define CMD_QUERY 0x2a + +struct wacom_w9000_variant { + const u8 cmd_query_num; + const u8 msg_coord_num; + const char *name; +}; + +struct wacom_w9000_data { + struct i2c_client *client; + struct input_dev *input_dev; + const struct wacom_w9000_variant *variant; + u16 fw_version; + + struct touchscreen_properties prop; + u16 max_pressure; + + struct regulator *regulator; + + struct gpio_desc *flash_mode_gpio; + struct gpio_desc *reset_gpio; + + unsigned int irq; + + bool pen_proximity; +}; + +static int wacom_w9000_read(struct i2c_client *client, u8 command, u8 len, u8 *data) +{ + int error, res; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .buf = &command, + .len = sizeof(command), + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .buf = data, + .len = len, + } + }; + + res = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (res != ARRAY_SIZE(msg)) { + error = res < 0 ? res : -EIO; + dev_err(&client->dev, "%s: i2c transfer failed: %d (%d)\n", + __func__, error, res); + return error; + } + + return 0; +} + +static int wacom_w9000_query(struct wacom_w9000_data *wacom_data) +{ + struct i2c_client *client = wacom_data->client; + struct device *dev = &wacom_data->client->dev; + u8 data[CMD_QUERY_NUM_MAX]; + int retry; + int error; + + for (retry = 0; retry < CMD_QUERY_RETRIES; retry++) { + error = wacom_w9000_read(client, CMD_QUERY, + wacom_data->variant->cmd_query_num, + data); + if (!error && data[0] == 0x0f) + break; + } + + if (error) + return error; + + if (data[0] != 0x0f) + return -EIO; + + dev_dbg(dev, "query: %*ph, %d\n", + wacom_data->variant->cmd_query_num, data, retry); + + wacom_data->prop.max_x = get_unaligned_be16(&data[1]); + wacom_data->prop.max_y = get_unaligned_be16(&data[3]); + wacom_data->max_pressure = get_unaligned_be16(&data[5]); + wacom_data->fw_version = get_unaligned_be16(&data[7]); + + dev_dbg(dev, "max_x:%d, max_y:%d, max_pressure:%d, fw:%#x\n", + wacom_data->prop.max_x, wacom_data->prop.max_y, + wacom_data->max_pressure, wacom_data->fw_version); + + return 0; +} + +static int wacom_w9000_power_on(struct wacom_w9000_data *wacom_data) +{ + int error; + + lockdep_assert_held(&wacom_data->input_dev->mutex); + + error = regulator_enable(wacom_data->regulator); + if (error) { + dev_err(&wacom_data->client->dev, "Failed to enable regulators: %d\n", error); + return error; + } + + msleep(200); + + gpiod_set_value_cansleep(wacom_data->reset_gpio, 0); + enable_irq(wacom_data->irq); + + return 0; +} + +static int wacom_w9000_power_off(struct wacom_w9000_data *wacom_data) +{ + lockdep_assert_held(&wacom_data->input_dev->mutex); + + disable_irq(wacom_data->irq); + gpiod_set_value_cansleep(wacom_data->reset_gpio, 1); + regulator_disable(wacom_data->regulator); + + return 0; +} + +static void wacom_w9000_coord(struct wacom_w9000_data *wacom_data) +{ + struct i2c_client *client = wacom_data->client; + struct device *dev = &wacom_data->client->dev; + u8 data[MSG_COORD_NUM_MAX]; + bool touch, rubber, side_button; + u16 x, y, pressure; + u8 distance = 0; + int error; + + error = i2c_master_recv(client, data, wacom_data->variant->msg_coord_num); + if (error != wacom_data->variant->msg_coord_num) { + if (error >= 0) + error = -EIO; + dev_err_ratelimited(dev, "%s: i2c receive failed (%d)\n", __func__, error); + return; + } + + dev_dbg(dev, "data: %*ph\n", wacom_data->variant->msg_coord_num, data); + + if (data[0] & BIT(7)) { + wacom_data->pen_proximity = true; + + touch = !!(data[0] & BIT(4)); + side_button = !!(data[0] & BIT(5)); + rubber = !!(data[0] & BIT(6)); + + x = get_unaligned_be16(&data[1]); + y = get_unaligned_be16(&data[3]); + pressure = get_unaligned_be16(&data[5]); + + if (wacom_data->variant->msg_coord_num > 7) + distance = data[7]; + + if (x > wacom_data->prop.max_x || y > wacom_data->prop.max_y) { + dev_warn_ratelimited(dev, "Coordinates out of range x=%d, y=%d\n", x, y); + return; + } + + if (pressure > wacom_data->max_pressure) { + dev_warn_ratelimited(dev, "Pressure out of range %d\n", pressure); + return; + } + + touchscreen_report_pos(wacom_data->input_dev, &wacom_data->prop, x, y, false); + input_report_abs(wacom_data->input_dev, ABS_PRESSURE, pressure); + + if (wacom_data->variant->msg_coord_num > 7) + input_report_abs(wacom_data->input_dev, ABS_DISTANCE, distance); + + input_report_key(wacom_data->input_dev, BTN_STYLUS, side_button); + input_report_key(wacom_data->input_dev, BTN_TOUCH, touch); + input_report_key(wacom_data->input_dev, BTN_TOOL_PEN, !rubber); + input_report_key(wacom_data->input_dev, BTN_TOOL_RUBBER, rubber); + input_sync(wacom_data->input_dev); + } else if (wacom_data->pen_proximity) { + input_report_abs(wacom_data->input_dev, ABS_PRESSURE, 0); + + if (wacom_data->variant->msg_coord_num > 7) + input_report_abs(wacom_data->input_dev, ABS_DISTANCE, 255); + + input_report_key(wacom_data->input_dev, BTN_STYLUS, 0); + input_report_key(wacom_data->input_dev, BTN_TOUCH, 0); + input_report_key(wacom_data->input_dev, BTN_TOOL_PEN, 0); + input_report_key(wacom_data->input_dev, BTN_TOOL_RUBBER, 0); + input_sync(wacom_data->input_dev); + + wacom_data->pen_proximity = false; + } +} + +static irqreturn_t wacom_w9000_interrupt(int irq, void *dev_id) +{ + struct wacom_w9000_data *wacom_data = dev_id; + + wacom_w9000_coord(wacom_data); + + return IRQ_HANDLED; +} + +static int wacom_w9000_open(struct input_dev *dev) +{ + struct wacom_w9000_data *wacom_data = input_get_drvdata(dev); + + return wacom_w9000_power_on(wacom_data); +} + +static void wacom_w9000_close(struct input_dev *dev) +{ + struct wacom_w9000_data *wacom_data = input_get_drvdata(dev); + + wacom_w9000_power_off(wacom_data); +} + +static int wacom_w9000_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct wacom_w9000_data *wacom_data; + struct input_dev *input_dev; + int error; + u32 val; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(dev, "i2c_check_functionality error\n"); + return -EIO; + } + + wacom_data = devm_kzalloc(dev, sizeof(*wacom_data), GFP_KERNEL); + if (!wacom_data) + return -ENOMEM; + + wacom_data->variant = i2c_get_match_data(client); + if (!wacom_data->variant) { + dev_err(dev, "No i2c match_data available\n"); + return -EINVAL; + } + + if (wacom_data->variant->cmd_query_num > CMD_QUERY_NUM_MAX || + wacom_data->variant->msg_coord_num > MSG_COORD_NUM_MAX) { + dev_err(dev, "Length of message for %s exceeds the maximum\n", + wacom_data->variant->name); + return -EINVAL; + } + + if (wacom_data->variant->msg_coord_num < 7) { + dev_err(dev, "Length of coordinates message for %s too short\n", + wacom_data->variant->name); + return -EINVAL; + } + + wacom_data->client = client; + wacom_data->irq = client->irq; + i2c_set_clientdata(client, wacom_data); + + wacom_data->regulator = devm_regulator_get(dev, "vdd"); + if (IS_ERR(wacom_data->regulator)) + return dev_err_probe(dev, PTR_ERR(wacom_data->regulator), + "Failed to get regulators\n"); + + wacom_data->flash_mode_gpio = devm_gpiod_get_optional(dev, "flash-mode", GPIOD_OUT_LOW); + if (IS_ERR(wacom_data->flash_mode_gpio)) + return dev_err_probe(dev, PTR_ERR(wacom_data->flash_mode_gpio), + "Failed to get flash-mode gpio\n"); + + wacom_data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(wacom_data->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(wacom_data->reset_gpio), + "Failed to get reset gpio\n"); + + error = regulator_enable(wacom_data->regulator); + if (error) + return dev_err_probe(dev, error, "Failed to enable regulators\n"); + + msleep(200); + + gpiod_set_value_cansleep(wacom_data->reset_gpio, 0); + + error = wacom_w9000_query(wacom_data); + + gpiod_set_value_cansleep(wacom_data->reset_gpio, 1); + regulator_disable(wacom_data->regulator); + + if (error) + return dev_err_probe(dev, error, "Failed to query\n"); + + error = devm_request_threaded_irq(dev, wacom_data->irq, NULL, wacom_w9000_interrupt, + IRQF_ONESHOT | IRQF_NO_AUTOEN, client->name, wacom_data); + if (error) + return dev_err_probe(dev, error, "Failed to register interrupt\n"); + + input_dev = devm_input_allocate_device(dev); + if (!input_dev) + return -ENOMEM; + + wacom_data->input_dev = input_dev; + input_set_drvdata(input_dev, wacom_data); + + input_dev->name = wacom_data->variant->name; + input_dev->id.bustype = BUS_I2C; + input_dev->id.vendor = 0x56a; + input_dev->id.version = wacom_data->fw_version; + input_dev->open = wacom_w9000_open; + input_dev->close = wacom_w9000_close; + + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); + input_set_capability(input_dev, EV_KEY, BTN_TOOL_PEN); + input_set_capability(input_dev, EV_KEY, BTN_TOOL_RUBBER); + input_set_capability(input_dev, EV_KEY, BTN_STYLUS); + + input_set_abs_params(input_dev, ABS_X, 0, wacom_data->prop.max_x, 4, 0); + input_set_abs_params(input_dev, ABS_Y, 0, wacom_data->prop.max_y, 4, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_data->max_pressure, 0, 0); + + if (wacom_data->variant->msg_coord_num > 7) + input_set_abs_params(input_dev, ABS_DISTANCE, 0, 255, 0, 0); + + touchscreen_parse_properties(input_dev, false, &wacom_data->prop); + + dev_info(dev, "%s size X%uY%u\n", wacom_data->variant->name, + wacom_data->prop.max_x, wacom_data->prop.max_y); + + error = device_property_read_u32(dev, "touchscreen-x-mm", &val); + if (!error && val) + input_abs_set_res(input_dev, wacom_data->prop.swap_x_y ? ABS_Y : ABS_X, + wacom_data->prop.max_x / val); + error = device_property_read_u32(dev, "touchscreen-y-mm", &val); + if (!error && val) + input_abs_set_res(input_dev, wacom_data->prop.swap_x_y ? ABS_X : ABS_Y, + wacom_data->prop.max_y / val); + + error = input_register_device(wacom_data->input_dev); + if (error) + return dev_err_probe(dev, error, "Failed to register input device\n"); + + return 0; +} + +static int wacom_w9000_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct wacom_w9000_data *wacom_data = i2c_get_clientdata(client); + + guard(mutex)(&wacom_data->input_dev->mutex); + + if (input_device_enabled(wacom_data->input_dev)) + return wacom_w9000_power_off(wacom_data); + + return 0; +} + +static int wacom_w9000_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct wacom_w9000_data *wacom_data = i2c_get_clientdata(client); + + guard(mutex)(&wacom_data->input_dev->mutex); + + if (input_device_enabled(wacom_data->input_dev)) + return wacom_w9000_power_on(wacom_data); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(wacom_w9000_pm, wacom_w9000_suspend, wacom_w9000_resume); + +static const struct wacom_w9000_variant w9002 = { + .cmd_query_num = 9, + .msg_coord_num = 7, + .name = "Wacom W9002 Digitizer", +}; + +static const struct wacom_w9000_variant w9007a_lt03 = { + .cmd_query_num = 9, + .msg_coord_num = 8, + .name = "Wacom W9007A LT03 Digitizer", +}; + +static const struct wacom_w9000_variant w9007a_v1 = { + .cmd_query_num = 9, + .msg_coord_num = 12, + .name = "Wacom W9007A V1 Digitizer", +}; + +static const struct of_device_id wacom_w9000_of_match[] = { + { .compatible = "wacom,w9002", .data = &w9002 }, + { .compatible = "wacom,w9007a-lt03", .data = &w9007a_lt03, }, + { .compatible = "wacom,w9007a-v1", .data = &w9007a_v1, }, + { } +}; +MODULE_DEVICE_TABLE(of, wacom_w9000_of_match); + +static const struct i2c_device_id wacom_w9000_id[] = { + { .name = "w9002", .driver_data = (kernel_ulong_t)&w9002 }, + { .name = "w9007a-lt03", .driver_data = (kernel_ulong_t)&w9007a_lt03 }, + { .name = "w9007a-v1", .driver_data = (kernel_ulong_t)&w9007a_v1 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wacom_w9000_id); + +static struct i2c_driver wacom_w9000_driver = { + .driver = { + .name = "wacom_w9000", + .of_match_table = wacom_w9000_of_match, + .pm = pm_sleep_ptr(&wacom_w9000_pm), + }, + .probe = wacom_w9000_probe, + .id_table = wacom_w9000_id, +}; +module_i2c_driver(wacom_w9000_driver); + +MODULE_AUTHOR("Hendrik Noack <hendrik-noack@gmx.de>"); +MODULE_DESCRIPTION("Wacom W9000-series penabled touchscreen driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index bdaabb14dc8c..1af309252092 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -1140,7 +1140,7 @@ static int wdt87xx_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(wdt87xx_pm_ops, wdt87xx_suspend, wdt87xx_resume); static const struct i2c_device_id wdt87xx_dev_id[] = { - { WDT87XX_NAME }, + { .name = WDT87XX_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, wdt87xx_dev_id); diff --git a/drivers/input/touchscreen/zet6223.c b/drivers/input/touchscreen/zet6223.c index 943634ba9cd9..a341142f3708 100644 --- a/drivers/input/touchscreen/zet6223.c +++ b/drivers/input/touchscreen/zet6223.c @@ -236,7 +236,7 @@ static const struct of_device_id zet6223_of_match[] = { MODULE_DEVICE_TABLE(of, zet6223_of_match); static const struct i2c_device_id zet6223_id[] = { - { "zet6223" }, + { .name = "zet6223" }, { } }; MODULE_DEVICE_TABLE(i2c, zet6223_id); diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index a360749fa076..4bfc9560bd6c 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -831,7 +831,7 @@ static int zforce_probe(struct i2c_client *client) } static const struct i2c_device_id zforce_idtable[] = { - { "zforce-ts" }, + { .name = "zforce-ts" }, { } }; MODULE_DEVICE_TABLE(i2c, zforce_idtable); diff --git a/include/linux/input.h b/include/linux/input.h index 06ca62328db1..3022bb730898 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -543,6 +543,8 @@ extern const struct class input_class; * @set_autocenter: Called to auto-center device * @destroy: called by input core when parent input device is being * destroyed + * @stop: called by input core when parent input device is being + * unregistered * @private: driver-specific data, will be freed automatically * @ffbit: bitmap of force feedback capabilities truly supported by * device (not emulated like ones in input_dev->ffbit) @@ -571,6 +573,7 @@ struct ff_device { void (*set_autocenter)(struct input_dev *dev, u16 magnitude); void (*destroy)(struct ff_device *); + void (*stop)(struct ff_device *); void *private; diff --git a/include/uapi/linux/userio.h b/include/uapi/linux/userio.h index 74c9951d2cd0..550c7465af1f 100644 --- a/include/uapi/linux/userio.h +++ b/include/uapi/linux/userio.h @@ -2,7 +2,7 @@ /* * userio: virtual serio device support * Copyright (C) 2015 Red Hat - * Copyright (C) 2015 Lyude (Stephen Chandler Paul) <cpaul@redhat.com> + * Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the @@ -27,7 +27,10 @@ enum userio_cmd_type { USERIO_CMD_REGISTER = 0, USERIO_CMD_SET_PORT_TYPE = 1, - USERIO_CMD_SEND_INTERRUPT = 2 + USERIO_CMD_SEND_INTERRUPT = 2, + USERIO_CMD_SET_PORT_EXTRA = 3, + USERIO_CMD_SET_PORT_ID = 4, + USERIO_CMD_SET_PORT_PROTO = 5, }; /* |
