First attempt to get uinput connected with ff-memless

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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;
 

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux