[patch 05/12] input: adapt uinput for the new force feedback interface

From: Anssi Hannula
Date: Tue May 30 2006 - 07:01:44 EST


Modify the uinput driver for the new force feedback interface. The userspace
interface of the force feedback part is changed and documentation in uinput.h
is updated accordingly. MODULE_VERSION is also added to reflect the revision.

Signed-off-by: Anssi Hannula <anssi.hannula@xxxxxxxxx>

---
drivers/input/misc/uinput.c | 79 ++++++++++++++++++++++++++++++++++++--------
include/linux/uinput.h | 21 ++++++++---
2 files changed, 80 insertions(+), 20 deletions(-)

Index: linux-2.6.17-rc4-git12/drivers/input/misc/uinput.c
===================================================================
--- linux-2.6.17-rc4-git12.orig/drivers/input/misc/uinput.c 2006-05-30 13:38:57.000000000 +0300
+++ linux-2.6.17-rc4-git12/drivers/input/misc/uinput.c 2006-05-30 13:42:16.000000000 +0300
@@ -20,6 +20,9 @@
* Author: Aristeu Sergio Rozanski Filho <aris@xxxxxxxxxxxxxxxxx>
*
* Changes/Revisions:
+ * 0.3 09/04/2006 (Anssi Hannula <anssi.hannula@xxxxxxxxx>)
+ * - updated ff support for the changes in kernel interface
+ * - added MODULE_VERSION
* 0.2 16/10/2004 (Micah Dowty <micah@xxxxxxx>)
* - added force feedback support
* - added UI_SET_PHYS
@@ -40,6 +43,9 @@ static int uinput_dev_event(struct input
{
struct uinput_device *udev;

+ if (type == EV_FF)
+ return input_ff_event(dev, type, code, value);
+
udev = dev->private;

udev->buff[udev->head].type = type;
@@ -107,18 +113,31 @@ static int uinput_request_submit(struct
return request->retval;
}

-static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
+static void uinput_dev_set_gain(struct input_dev *dev, u16 gain)
+{
+ uinput_dev_event(dev, EV_FF, FF_GAIN, gain);
+}
+
+static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+ uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude);
+}
+
+static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value)
+{
+ return uinput_dev_event(dev, EV_FF, effect_id, value);
+}
+
+static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
{
struct uinput_request request;
int retval;

- if (!test_bit(EV_FF, dev->evbit))
- return -ENOSYS;
-
request.id = -1;
init_completion(&request.done);
request.code = UI_FF_UPLOAD;
- request.u.effect = effect;
+ request.u.upload.effect = effect;
+ request.u.upload.old = old;

retval = uinput_request_reserve_slot(dev->private, &request);
if (!retval)
@@ -166,6 +185,14 @@ static void uinput_destroy_device(struct
udev->state = UIST_NEW_DEVICE;
}

+static struct ff_driver uinput_ff_driver = {
+ .upload = uinput_dev_upload_effect,
+ .erase = uinput_dev_erase_effect,
+ .playback = uinput_dev_playback,
+ .set_gain = uinput_dev_set_gain,
+ .set_autocenter = uinput_dev_set_autocenter
+};
+
static int uinput_create_device(struct uinput_device *udev)
{
int error;
@@ -181,6 +208,14 @@ static int uinput_create_device(struct u
return error;
}

+ if (udev->dev->ff) {
+ error = input_ff_register(udev->dev, &uinput_ff_driver);
+ if (error) {
+ uinput_destroy_device(udev);
+ return error;
+ }
+ }
+
udev->state = UIST_CREATED;

return 0;
@@ -243,8 +278,6 @@ static int uinput_allocate_device(struct
return -ENOMEM;

udev->dev->event = uinput_dev_event;
- udev->dev->upload_effect = uinput_dev_upload_effect;
- udev->dev->erase_effect = uinput_dev_erase_effect;
udev->dev->private = udev;

return 0;
@@ -296,7 +329,12 @@ static int uinput_setup_device(struct ui
dev->id.vendor = user_dev->id.vendor;
dev->id.product = user_dev->id.product;
dev->id.version = user_dev->id.version;
- dev->ff_effects_max = user_dev->ff_effects_max;
+ if (user_dev->ff_effects_max) {
+ retval = input_ff_allocate(dev);
+ if (retval)
+ goto exit;
+ dev->ff_effects_max = user_dev->ff_effects_max;
+ }

size = sizeof(int) * (ABS_MAX + 1);
memcpy(dev->absmax, user_dev->absmax, size);
@@ -459,7 +497,12 @@ static long uinput_ioctl(struct file *fi
break;

case UI_SET_EVBIT:
- retval = uinput_set_bit(arg, evbit, EV_MAX);
+ if (arg == EV_FF)
+ /* EV_FF shall not be touched by the driver
+ it is set by force feedback subsystem */
+ retval = -EINVAL;
+ else
+ retval = uinput_set_bit(arg, evbit, EV_MAX);
break;

case UI_SET_KEYBIT:
@@ -487,7 +530,10 @@ static long uinput_ioctl(struct file *fi
break;

case UI_SET_FFBIT:
- retval = uinput_set_bit(arg, ffbit, FF_MAX);
+ if (!udev->dev->ff)
+ retval = -EINVAL;
+ else
+ retval = uinput_set_bit(arg, ff->flags, FF_MAX);
break;

case UI_SET_SWBIT:
@@ -525,12 +571,17 @@ static long uinput_ioctl(struct file *fi
break;
}
req = uinput_request_find(udev, ff_up.request_id);
- if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) {
+ if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) {
retval = -EINVAL;
break;
}
ff_up.retval = 0;
- memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect));
+ memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect));
+ if (req->u.upload.old)
+ memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect));
+ else
+ memset(&ff_up.old, 0, sizeof(struct ff_effect));
+
if (copy_to_user(p, &ff_up, sizeof(ff_up))) {
retval = -EFAULT;
break;
@@ -561,12 +612,11 @@ static long uinput_ioctl(struct file *fi
break;
}
req = uinput_request_find(udev, ff_up.request_id);
- if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) {
+ if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) {
retval = -EINVAL;
break;
}
req->retval = ff_up.retval;
- memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect));
uinput_request_done(udev, req);
break;

@@ -622,6 +672,7 @@ static void __exit uinput_exit(void)
MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
MODULE_DESCRIPTION("User level driver support for input subsystem");
MODULE_LICENSE("GPL");
+MODULE_VERSION("0.3");

module_init(uinput_init);
module_exit(uinput_exit);
Index: linux-2.6.17-rc4-git12/include/linux/uinput.h
===================================================================
--- linux-2.6.17-rc4-git12.orig/include/linux/uinput.h 2006-05-30 13:38:57.000000000 +0300
+++ linux-2.6.17-rc4-git12/include/linux/uinput.h 2006-05-30 13:40:55.000000000 +0300
@@ -22,12 +22,18 @@
* Author: Aristeu Sergio Rozanski Filho <aris@xxxxxxxxxxxxxxxxx>
*
* Changes/Revisions:
+ * 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
+ * - update ff support for the changes in kernel interface
+ * - add UINPUT_VERSION
* 0.2 16/10/2004 (Micah Dowty <micah@xxxxxxx>)
* - added force feedback support
* - added UI_SET_PHYS
* 0.1 20/06/2002
* - first public version
*/
+
+#define UINPUT_VERSION 3
+
#ifdef __KERNEL__
#define UINPUT_MINOR 223
#define UINPUT_NAME "uinput"
@@ -45,7 +51,10 @@ struct uinput_request {

union {
int effect_id;
- struct ff_effect* effect;
+ struct {
+ struct ff_effect* effect;
+ struct ff_effect* old;
+ } upload;
} u;
};

@@ -69,6 +78,7 @@ struct uinput_ff_upload {
int request_id;
int retval;
struct ff_effect effect;
+ struct ff_effect old;
};

struct uinput_ff_erase {
@@ -105,7 +115,7 @@ struct uinput_ff_erase {
* ioctls to retrieve additional parameters and send the return code.
* The callback blocks until this return code is sent.
*
- * The described callback mechanism is only used if EV_FF is set.
+ * The described callback mechanism is only used if ff_effects_max is set.
* Otherwise, default implementations of upload_effect and erase_effect
* are used.
*
@@ -116,9 +126,9 @@ struct uinput_ff_erase {
* the 'value' from the EV_UINPUT event.
* 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the
* uinput_ff_upload struct. It will be filled in with the
- * ff_effect passed to upload_effect().
- * 4. Perform the effect upload, and place the modified ff_effect
- * and a return code back into the uinput_ff_upload struct.
+ * ff_effects passed to upload_effect().
+ * 4. Perform the effect upload, and place a return code back into
+ the uinput_ff_upload struct.
* 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the
* uinput_ff_upload_effect struct. This will complete execution
* of our upload_effect() handler.
@@ -133,7 +143,6 @@ struct uinput_ff_erase {
* effect ID passed to erase_effect().
* 4. Perform the effect erasure, and place a return code back
* into the uinput_ff_erase struct.
- * and a return code back into the uinput_ff_erase struct.
* 5. Issue a UI_END_FF_ERASE ioctl, also giving it the
* uinput_ff_erase_effect struct. This will complete execution
* of our erase_effect() handler.

--
Anssi Hannula
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/