Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 17 Nov 2020 20:00:40 +0000 (12:00 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 17 Nov 2020 20:00:40 +0000 (12:00 -0800)
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()

drivers/input/keyboard/sunkbd.c
drivers/input/misc/adxl34x.c
drivers/input/mouse/elan_i2c.h
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/elan_i2c_i2c.c
drivers/input/mouse/elan_i2c_smbus.c
drivers/input/serio/i8042.c
drivers/input/touchscreen/Kconfig

index 27126e6..d450f11 100644 (file)
@@ -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);
+       }
 }
 
 /*
index 5fe92d4..4cc4e8f 100644 (file)
@@ -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");
index c75b00c..36e3cd9 100644 (file)
@@ -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,
index c599e21..61ed3f5 100644 (file)
@@ -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;
 
index 5a496d4..13dc097 100644 (file)
@@ -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;
        }
index 8ff8237..1820f1c 100644 (file)
@@ -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;
index d3eda48..944cbb5 100644 (file)
@@ -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();
index f012fe7..cc18f54 100644 (file)
@@ -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