@@ -225,16 +225,43 @@ static int uinput_dev_erase_effect(struc
return -ENOSYS;
request.code = UI_FF_ERASE;
request.u.effect_id = effect_id;
return uinput_request_submit(udev, &request);
}
+/* Callback for ff-memless. Uploads effect and immediately plays it */
+static int uinput_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+ uinput_dev_upload_effect(dev, effect, NULL);
+ uinput_dev_playback(dev, effect->id, 1);
+ return 0;
+}
+
+static int uinput_is_memless_device(struct uinput_device *udev)
+{
+ /*
+ * A device is expected to be memless if it only supports one effect
+ * simultaneously and FF_RUMBLE is the only supported effect
+ */
+
+ if (udev->ff_effects_max != 1)
+ return 0;
+
+ DECLARE_BITMAP(ui_scratch, FF_CNT);
+ bitmap_zero(ui_scratch, FF_CNT);
+ set_bit(FF_RUMBLE, ui_scratch);
+ if (!bitmap_equal(ui_scratch, udev->dev->ffbit, FF_CNT))
+ return 0;
+
+ return 1;
+}
+
static void uinput_destroy_device(struct uinput_device *udev)
{
const char *name, *phys;
struct input_dev *dev = udev->dev;
enum uinput_state old_state = udev->state;
udev->state = UIST_NEW_DEVICE;
@@ -275,25 +302,33 @@ static int uinput_create_device(struct u
if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) {
printk(KERN_DEBUG "%s: ff_effects_max should be non-zero when FF_BIT is set\n",
UINPUT_NAME);
error = -EINVAL;
goto fail1;
}
if (udev->ff_effects_max) {
- error = input_ff_create(dev, udev->ff_effects_max);
- if (error)
- goto fail1;
-
- dev->ff->upload = uinput_dev_upload_effect;
- dev->ff->erase = uinput_dev_erase_effect;
- dev->ff->playback = uinput_dev_playback;
- dev->ff->set_gain = uinput_dev_set_gain;
- dev->ff->set_autocenter = uinput_dev_set_autocenter;
+ if (uinput_is_memless_device(udev)) {
+ input_set_capability(dev, EV_FF, FF_RUMBLE);
+ error = input_ff_create_memless(dev, NULL, uinput_play_effect);
+ if (error)
+ goto fail1;
+ }
+ else {
+ error = input_ff_create(dev, udev->ff_effects_max);
+ if (error)
+ goto fail1;
+
+ dev->ff->upload = uinput_dev_upload_effect;
+ dev->ff->erase = uinput_dev_erase_effect;
+ dev->ff->playback = uinput_dev_playback;
+ dev->ff->set_gain = uinput_dev_set_gain;
+ dev->ff->set_autocenter = uinput_dev_set_autocenter;
+ }
}
error = input_register_device(udev->dev);
if (error)
goto fail2;
udev->state = UIST_CREATED;