diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-11-17 12:00:40 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-11-17 12:00:40 -0800 |
commit | 0fa8ee0d9ab95c9350b8b84574824d9a384a9f7d (patch) | |
tree | e93b1f28886347874c3ec40d763735bb9af07fef /drivers | |
parent | 111e91a6df505e532a3809ead372787a01e23e0c (diff) | |
parent | ae3d6083acf60116d4f409677452399547ed2009 (diff) | |
download | lwn-0fa8ee0d9ab95c9350b8b84574824d9a384a9f7d.tar.gz lwn-0fa8ee0d9ab95c9350b8b84574824d9a384a9f7d.zip |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input fixes from Dmitry Torokhov:
"A fix for use-after-free in the Sun keyboard driver, a fix to firmware
updates on newer ICs in the Elan touchpad diver, and a couple misc
driver fixes"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
Input: elan_i2c - fix firmware update on newer ICs
Input: resistive-adc-touch - fix kconfig dependency on IIO_BUFFER
Input: sunkbd - avoid use-after-free in teardown paths
Input: i8042 - allow insmod to succeed on devices without an i8042 controller
Input: adxl34x - clean up a data type in adxl34x_probe()
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/keyboard/sunkbd.c | 41 | ||||
-rw-r--r-- | drivers/input/misc/adxl34x.c | 2 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c.h | 2 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c_core.c | 3 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c_i2c.c | 10 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c_smbus.c | 2 | ||||
-rw-r--r-- | drivers/input/serio/i8042.c | 12 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 1 |
8 files changed, 55 insertions, 18 deletions
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 27126e621eb6..d450f11b98a7 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -99,7 +99,8 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio, switch (data) { case SUNKBD_RET_RESET: - schedule_work(&sunkbd->tq); + if (sunkbd->enabled) + schedule_work(&sunkbd->tq); sunkbd->reset = -1; break; @@ -200,16 +201,12 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) } /* - * sunkbd_reinit() sets leds and beeps to a state the computer remembers they - * were in. + * sunkbd_set_leds_beeps() sets leds and beeps to a state the computer remembers + * they were in. */ -static void sunkbd_reinit(struct work_struct *work) +static void sunkbd_set_leds_beeps(struct sunkbd *sunkbd) { - struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq); - - wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); - serio_write(sunkbd->serio, SUNKBD_CMD_SETLED); serio_write(sunkbd->serio, (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | @@ -222,11 +219,39 @@ static void sunkbd_reinit(struct work_struct *work) SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); } + +/* + * sunkbd_reinit() wait for the keyboard reset to complete and restores state + * of leds and beeps. + */ + +static void sunkbd_reinit(struct work_struct *work) +{ + struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq); + + /* + * It is OK that we check sunkbd->enabled without pausing serio, + * as we only want to catch true->false transition that will + * happen once and we will be woken up for it. + */ + wait_event_interruptible_timeout(sunkbd->wait, + sunkbd->reset >= 0 || !sunkbd->enabled, + HZ); + + if (sunkbd->reset >= 0 && sunkbd->enabled) + sunkbd_set_leds_beeps(sunkbd); +} + static void sunkbd_enable(struct sunkbd *sunkbd, bool enable) { serio_pause_rx(sunkbd->serio); sunkbd->enabled = enable; serio_continue_rx(sunkbd->serio); + + if (!enable) { + wake_up_interruptible(&sunkbd->wait); + cancel_work_sync(&sunkbd->tq); + } } /* diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c index 5fe92d4ba3f0..4cc4e8ff42b3 100644 --- a/drivers/input/misc/adxl34x.c +++ b/drivers/input/misc/adxl34x.c @@ -696,7 +696,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq, struct input_dev *input_dev; const struct adxl34x_platform_data *pdata; int err, range, i; - unsigned char revid; + int revid; if (!irq) { dev_err(dev, "no IRQ?\n"); diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index c75b00c45d75..36e3cd908671 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -78,7 +78,7 @@ struct elan_transport_ops { int (*iap_reset)(struct i2c_client *client); int (*prepare_fw_update)(struct i2c_client *client, u16 ic_type, - u8 iap_version); + u8 iap_version, u16 fw_page_size); int (*write_fw_block)(struct i2c_client *client, u16 fw_page_size, const u8 *page, u16 checksum, int idx); int (*finish_fw_update)(struct i2c_client *client, diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index c599e21a8478..61ed3f5ca219 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -497,7 +497,8 @@ static int __elan_update_firmware(struct elan_tp_data *data, u16 sw_checksum = 0, fw_checksum = 0; error = data->ops->prepare_fw_update(client, data->ic_type, - data->iap_version); + data->iap_version, + data->fw_page_size); if (error) return error; diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index 5a496d4ffa49..13dc097eb6c6 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -517,7 +517,7 @@ static int elan_i2c_set_flash_key(struct i2c_client *client) return 0; } -static int elan_read_write_iap_type(struct i2c_client *client) +static int elan_read_write_iap_type(struct i2c_client *client, u16 fw_page_size) { int error; u16 constant; @@ -526,7 +526,7 @@ static int elan_read_write_iap_type(struct i2c_client *client) do { error = elan_i2c_write_cmd(client, ETP_I2C_IAP_TYPE_CMD, - ETP_I2C_IAP_TYPE_REG); + fw_page_size / 2); if (error) { dev_err(&client->dev, "cannot write iap type: %d\n", error); @@ -543,7 +543,7 @@ static int elan_read_write_iap_type(struct i2c_client *client) constant = le16_to_cpup((__le16 *)val); dev_dbg(&client->dev, "iap type reg: 0x%04x\n", constant); - if (constant == ETP_I2C_IAP_TYPE_REG) + if (constant == fw_page_size / 2) return 0; } while (--retry > 0); @@ -553,7 +553,7 @@ static int elan_read_write_iap_type(struct i2c_client *client) } static int elan_i2c_prepare_fw_update(struct i2c_client *client, u16 ic_type, - u8 iap_version) + u8 iap_version, u16 fw_page_size) { struct device *dev = &client->dev; int error; @@ -594,7 +594,7 @@ static int elan_i2c_prepare_fw_update(struct i2c_client *client, u16 ic_type, } if (ic_type >= 0x0D && iap_version >= 1) { - error = elan_read_write_iap_type(client); + error = elan_read_write_iap_type(client, fw_page_size); if (error) return error; } diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 8ff823751f3b..1820f1cfc1dc 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -340,7 +340,7 @@ static int elan_smbus_set_flash_key(struct i2c_client *client) } static int elan_smbus_prepare_fw_update(struct i2c_client *client, u16 ic_type, - u8 iap_version) + u8 iap_version, u16 fw_page_size) { struct device *dev = &client->dev; int len; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index d3eda48032e3..944cbb519c6d 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -122,6 +122,7 @@ module_param_named(unmask_kbd_data, i8042_unmask_kbd_data, bool, 0600); MODULE_PARM_DESC(unmask_kbd_data, "Unconditional enable (may reveal sensitive data) of normally sanitize-filtered kbd data traffic debug log [pre-condition: i8042.debug=1 enabled]"); #endif +static bool i8042_present; static bool i8042_bypass_aux_irq_test; static char i8042_kbd_firmware_id[128]; static char i8042_aux_firmware_id[128]; @@ -343,6 +344,9 @@ int i8042_command(unsigned char *param, int command) unsigned long flags; int retval; + if (!i8042_present) + return -1; + spin_lock_irqsave(&i8042_lock, flags); retval = __i8042_command(param, command); spin_unlock_irqrestore(&i8042_lock, flags); @@ -1612,12 +1616,15 @@ static int __init i8042_init(void) err = i8042_platform_init(); if (err) - return err; + return (err == -ENODEV) ? 0 : err; err = i8042_controller_check(); if (err) goto err_platform_exit; + /* Set this before creating the dev to allow i8042_command to work right away */ + i8042_present = true; + pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0); if (IS_ERR(pdev)) { err = PTR_ERR(pdev); @@ -1636,6 +1643,9 @@ static int __init i8042_init(void) static void __exit i8042_exit(void) { + if (!i8042_present) + return; + platform_device_unregister(i8042_platform_device); platform_driver_unregister(&i8042_driver); i8042_platform_exit(); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index f012fe746df0..cc18f54ea887 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -96,6 +96,7 @@ config TOUCHSCREEN_AD7879_SPI config TOUCHSCREEN_ADC tristate "Generic ADC based resistive touchscreen" depends on IIO + select IIO_BUFFER select IIO_BUFFER_CB help Say Y here if you want to use the generic ADC |