Hello,
attached is a try to get the uinput driver connected with ff-memless.
The idea behind this is, that this would allow uinput drivers to use
this kernel built-in logic.
My attempt is pretty simple and seems to miss something important. I'm
no kernel hacker, so I don't know what's the problem.
If I listen on a serial console, then I'm able to catch many messages
like this:
[ 364.431753] bad: scheduling from the idle thread!
[ 364.490514] bad: scheduling from the idle thread!
[ 364.527516] bad: scheduling from the idle thread!
If I try to Ctrl+C the running and hanging fftest, then the whole system
freezes.
My simple idea was "Just upload the rumble effect and play it
immediately afterwards", but it seems to be not that simple to do this...
Maybe someone can have a look at this.
Manuel
--- uinput.c.org 2016-04-29 19:13:08.135810778 +0200
+++ uinput.c 2016-04-29 18:54:44.732493058 +0200
@@ -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;