mirror of https://gitee.com/openkylin/linux.git
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()
This commit is contained in:
commit
0fa8ee0d9a
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue