Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input fixes from Dmitry Torokhov:

 - fixes for two long standing issues (lock up and a crash) in force
   feedback handling in uinput driver

 - tweak to firmware update timing in Elan I2C touchpad driver.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: elan_i2c - extend Flash-Write delay
  Input: uinput - avoid crash when sending FF request to device going away
  Input: uinput - avoid FF flush when destroying device
This commit is contained in:
Linus Torvalds 2017-09-22 17:23:41 -10:00
commit d32e5f44a5
4 changed files with 51 additions and 22 deletions

View File

@ -237,9 +237,15 @@ int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file)
EXPORT_SYMBOL_GPL(input_ff_erase);
/*
* flush_effects - erase all effects owned by a file handle
* input_ff_flush - erase all effects owned by a file handle
* @dev: input device to erase effect from
* @file: purported owner of the effects
*
* This function erases all force-feedback effects associated with
* the given owner from specified device. Note that @file may be %NULL,
* in which case all effects will be erased.
*/
static int flush_effects(struct input_dev *dev, struct file *file)
int input_ff_flush(struct input_dev *dev, struct file *file)
{
struct ff_device *ff = dev->ff;
int i;
@ -255,6 +261,7 @@ static int flush_effects(struct input_dev *dev, struct file *file)
return 0;
}
EXPORT_SYMBOL_GPL(input_ff_flush);
/**
* input_ff_event() - generic handler for force-feedback events
@ -343,7 +350,7 @@ int input_ff_create(struct input_dev *dev, unsigned int max_effects)
mutex_init(&ff->mutex);
dev->ff = ff;
dev->flush = flush_effects;
dev->flush = input_ff_flush;
dev->event = input_ff_event;
__set_bit(EV_FF, dev->evbit);

View File

@ -98,14 +98,15 @@ static int uinput_request_reserve_slot(struct uinput_device *udev,
uinput_request_alloc_id(udev, request));
}
static void uinput_request_done(struct uinput_device *udev,
struct uinput_request *request)
static void uinput_request_release_slot(struct uinput_device *udev,
unsigned int id)
{
/* Mark slot as available */
udev->requests[request->id] = NULL;
wake_up(&udev->requests_waitq);
spin_lock(&udev->requests_lock);
udev->requests[id] = NULL;
spin_unlock(&udev->requests_lock);
complete(&request->done);
wake_up(&udev->requests_waitq);
}
static int uinput_request_send(struct uinput_device *udev,
@ -138,20 +139,22 @@ static int uinput_request_send(struct uinput_device *udev,
static int uinput_request_submit(struct uinput_device *udev,
struct uinput_request *request)
{
int error;
int retval;
error = uinput_request_reserve_slot(udev, request);
if (error)
return error;
retval = uinput_request_reserve_slot(udev, request);
if (retval)
return retval;
error = uinput_request_send(udev, request);
if (error) {
uinput_request_done(udev, request);
return error;
}
retval = uinput_request_send(udev, request);
if (retval)
goto out;
wait_for_completion(&request->done);
return request->retval;
retval = request->retval;
out:
uinput_request_release_slot(udev, request->id);
return retval;
}
/*
@ -169,7 +172,7 @@ static void uinput_flush_requests(struct uinput_device *udev)
request = udev->requests[i];
if (request) {
request->retval = -ENODEV;
uinput_request_done(udev, request);
complete(&request->done);
}
}
@ -230,6 +233,18 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
return uinput_request_submit(udev, &request);
}
static int uinput_dev_flush(struct input_dev *dev, struct file *file)
{
/*
* If we are called with file == NULL that means we are tearing
* down the device, and therefore we can not handle FF erase
* requests: either we are handling UI_DEV_DESTROY (and holding
* the udev->mutex), or the file descriptor is closed and there is
* nobody on the other side anymore.
*/
return file ? input_ff_flush(dev, file) : 0;
}
static void uinput_destroy_device(struct uinput_device *udev)
{
const char *name, *phys;
@ -297,6 +312,12 @@ static int uinput_create_device(struct uinput_device *udev)
dev->ff->playback = uinput_dev_playback;
dev->ff->set_gain = uinput_dev_set_gain;
dev->ff->set_autocenter = uinput_dev_set_autocenter;
/*
* The standard input_ff_flush() implementation does
* not quite work for uinput as we can't reasonably
* handle FF requests during device teardown.
*/
dev->flush = uinput_dev_flush;
}
error = input_register_device(udev->dev);
@ -939,7 +960,7 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
}
req->retval = ff_up.retval;
uinput_request_done(udev, req);
complete(&req->done);
goto out;
case UI_END_FF_ERASE:
@ -955,7 +976,7 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
}
req->retval = ff_erase.retval;
uinput_request_done(udev, req);
complete(&req->done);
goto out;
}

View File

@ -598,7 +598,7 @@ static int elan_i2c_write_fw_block(struct i2c_client *client,
}
/* Wait for F/W to update one page ROM data. */
msleep(20);
msleep(35);
error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val);
if (error) {

View File

@ -529,6 +529,7 @@ int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code,
int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file);
int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file);
int input_ff_flush(struct input_dev *dev, struct file *file);
int input_ff_create_memless(struct input_dev *dev, void *data,
int (*play_effect)(struct input_dev *, void *, struct ff_effect *));