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:
commit
d32e5f44a5
4 changed files with 51 additions and 22 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 *));
|
||||
|
|
Loading…
Reference in a new issue