Commit 0fa8ee0d authored by Linus Torvalds's avatar Linus Torvalds

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()
parents 111e91a6 ae3d6083
...@@ -99,6 +99,7 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio, ...@@ -99,6 +99,7 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio,
switch (data) { switch (data) {
case SUNKBD_RET_RESET: case SUNKBD_RET_RESET:
if (sunkbd->enabled)
schedule_work(&sunkbd->tq); schedule_work(&sunkbd->tq);
sunkbd->reset = -1; sunkbd->reset = -1;
break; break;
...@@ -200,16 +201,12 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) ...@@ -200,16 +201,12 @@ static int sunkbd_initialize(struct sunkbd *sunkbd)
} }
/* /*
* sunkbd_reinit() sets leds and beeps to a state the computer remembers they * sunkbd_set_leds_beeps() sets leds and beeps to a state the computer remembers
* were in. * 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, SUNKBD_CMD_SETLED);
serio_write(sunkbd->serio, serio_write(sunkbd->serio,
(!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) |
...@@ -222,11 +219,39 @@ static void sunkbd_reinit(struct work_struct *work) ...@@ -222,11 +219,39 @@ static void sunkbd_reinit(struct work_struct *work)
SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); 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) static void sunkbd_enable(struct sunkbd *sunkbd, bool enable)
{ {
serio_pause_rx(sunkbd->serio); serio_pause_rx(sunkbd->serio);
sunkbd->enabled = enable; sunkbd->enabled = enable;
serio_continue_rx(sunkbd->serio); serio_continue_rx(sunkbd->serio);
if (!enable) {
wake_up_interruptible(&sunkbd->wait);
cancel_work_sync(&sunkbd->tq);
}
} }
/* /*
......
...@@ -696,7 +696,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq, ...@@ -696,7 +696,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
struct input_dev *input_dev; struct input_dev *input_dev;
const struct adxl34x_platform_data *pdata; const struct adxl34x_platform_data *pdata;
int err, range, i; int err, range, i;
unsigned char revid; int revid;
if (!irq) { if (!irq) {
dev_err(dev, "no IRQ?\n"); dev_err(dev, "no IRQ?\n");
......
...@@ -78,7 +78,7 @@ struct elan_transport_ops { ...@@ -78,7 +78,7 @@ struct elan_transport_ops {
int (*iap_reset)(struct i2c_client *client); int (*iap_reset)(struct i2c_client *client);
int (*prepare_fw_update)(struct i2c_client *client, u16 ic_type, 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, int (*write_fw_block)(struct i2c_client *client, u16 fw_page_size,
const u8 *page, u16 checksum, int idx); const u8 *page, u16 checksum, int idx);
int (*finish_fw_update)(struct i2c_client *client, int (*finish_fw_update)(struct i2c_client *client,
......
...@@ -497,7 +497,8 @@ static int __elan_update_firmware(struct elan_tp_data *data, ...@@ -497,7 +497,8 @@ static int __elan_update_firmware(struct elan_tp_data *data,
u16 sw_checksum = 0, fw_checksum = 0; u16 sw_checksum = 0, fw_checksum = 0;
error = data->ops->prepare_fw_update(client, data->ic_type, error = data->ops->prepare_fw_update(client, data->ic_type,
data->iap_version); data->iap_version,
data->fw_page_size);
if (error) if (error)
return error; return error;
......
...@@ -517,7 +517,7 @@ static int elan_i2c_set_flash_key(struct i2c_client *client) ...@@ -517,7 +517,7 @@ static int elan_i2c_set_flash_key(struct i2c_client *client)
return 0; 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; int error;
u16 constant; u16 constant;
...@@ -526,7 +526,7 @@ static int elan_read_write_iap_type(struct i2c_client *client) ...@@ -526,7 +526,7 @@ static int elan_read_write_iap_type(struct i2c_client *client)
do { do {
error = elan_i2c_write_cmd(client, ETP_I2C_IAP_TYPE_CMD, error = elan_i2c_write_cmd(client, ETP_I2C_IAP_TYPE_CMD,
ETP_I2C_IAP_TYPE_REG); fw_page_size / 2);
if (error) { if (error) {
dev_err(&client->dev, dev_err(&client->dev,
"cannot write iap type: %d\n", error); "cannot write iap type: %d\n", error);
...@@ -543,7 +543,7 @@ static int elan_read_write_iap_type(struct i2c_client *client) ...@@ -543,7 +543,7 @@ static int elan_read_write_iap_type(struct i2c_client *client)
constant = le16_to_cpup((__le16 *)val); constant = le16_to_cpup((__le16 *)val);
dev_dbg(&client->dev, "iap type reg: 0x%04x\n", constant); 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; return 0;
} while (--retry > 0); } while (--retry > 0);
...@@ -553,7 +553,7 @@ static int elan_read_write_iap_type(struct i2c_client *client) ...@@ -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, 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; struct device *dev = &client->dev;
int error; int error;
...@@ -594,7 +594,7 @@ static int elan_i2c_prepare_fw_update(struct i2c_client *client, u16 ic_type, ...@@ -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) { 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) if (error)
return error; return error;
} }
......
...@@ -340,7 +340,7 @@ static int elan_smbus_set_flash_key(struct i2c_client *client) ...@@ -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, 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; struct device *dev = &client->dev;
int len; int len;
......
...@@ -122,6 +122,7 @@ module_param_named(unmask_kbd_data, i8042_unmask_kbd_data, bool, 0600); ...@@ -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]"); 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 #endif
static bool i8042_present;
static bool i8042_bypass_aux_irq_test; static bool i8042_bypass_aux_irq_test;
static char i8042_kbd_firmware_id[128]; static char i8042_kbd_firmware_id[128];
static char i8042_aux_firmware_id[128]; static char i8042_aux_firmware_id[128];
...@@ -343,6 +344,9 @@ int i8042_command(unsigned char *param, int command) ...@@ -343,6 +344,9 @@ int i8042_command(unsigned char *param, int command)
unsigned long flags; unsigned long flags;
int retval; int retval;
if (!i8042_present)
return -1;
spin_lock_irqsave(&i8042_lock, flags); spin_lock_irqsave(&i8042_lock, flags);
retval = __i8042_command(param, command); retval = __i8042_command(param, command);
spin_unlock_irqrestore(&i8042_lock, flags); spin_unlock_irqrestore(&i8042_lock, flags);
...@@ -1612,12 +1616,15 @@ static int __init i8042_init(void) ...@@ -1612,12 +1616,15 @@ static int __init i8042_init(void)
err = i8042_platform_init(); err = i8042_platform_init();
if (err) if (err)
return err; return (err == -ENODEV) ? 0 : err;
err = i8042_controller_check(); err = i8042_controller_check();
if (err) if (err)
goto err_platform_exit; 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); pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0);
if (IS_ERR(pdev)) { if (IS_ERR(pdev)) {
err = PTR_ERR(pdev); err = PTR_ERR(pdev);
...@@ -1636,6 +1643,9 @@ static int __init i8042_init(void) ...@@ -1636,6 +1643,9 @@ static int __init i8042_init(void)
static void __exit i8042_exit(void) static void __exit i8042_exit(void)
{ {
if (!i8042_present)
return;
platform_device_unregister(i8042_platform_device); platform_device_unregister(i8042_platform_device);
platform_driver_unregister(&i8042_driver); platform_driver_unregister(&i8042_driver);
i8042_platform_exit(); i8042_platform_exit();
......
...@@ -96,6 +96,7 @@ config TOUCHSCREEN_AD7879_SPI ...@@ -96,6 +96,7 @@ config TOUCHSCREEN_AD7879_SPI
config TOUCHSCREEN_ADC config TOUCHSCREEN_ADC
tristate "Generic ADC based resistive touchscreen" tristate "Generic ADC based resistive touchscreen"
depends on IIO depends on IIO
select IIO_BUFFER
select IIO_BUFFER_CB select IIO_BUFFER_CB
help help
Say Y here if you want to use the generic ADC Say Y here if you want to use the generic ADC
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment