diff mbox

[v2,11/24] input: Port hid-holtekff to ff-memless-next

Message ID 1398175209-9565-12-git-send-email-madcatxster@devoid-pointer.net (mailing list archive)
State New, archived
Delegated to: Jiri Kosina
Headers show

Commit Message

Michal Malý April 22, 2014, 1:59 p.m. UTC
Port hid-holtekff to ff-memless-next

Signed-off-by: Michal Malý <madcatxster@devoid-pointer.net>
---
 drivers/hid/Kconfig        |  2 +-
 drivers/hid/hid-holtekff.c | 47 +++++++++++++++++++++++++++++-----------------
 2 files changed, 31 insertions(+), 18 deletions(-)

Comments

Oliver Neukum April 23, 2014, 12:17 p.m. UTC | #1
On Tue, 2014-04-22 at 15:59 +0200, Michal Malý wrote:
>  static int holtekff_play(struct input_dev *dev, void *data,
> -                        struct ff_effect *effect)
> +                        const struct mlnx_effect_command *command)
>  {
>         struct hid_device *hid = input_get_drvdata(dev);
>         struct holtekff_device *holtekff = data;
> +       const struct mlnx_rumble_force *rumble_force =
> &command->u.rumble_force;
>         int left, right;
>         /* effect type 1, length 65535 msec */
>         u8 buf[HOLTEKFF_MSG_LENGTH] =
>                 { 0x01, 0x01, 0xff, 0xff, 0x10, 0xe0, 0x00 };

On the kernel stack.

>  
> -       left = effect->u.rumble.strong_magnitude;
> -       right = effect->u.rumble.weak_magnitude;
> -       dbg_hid("called with 0x%04x 0x%04x\n", left, right);
> +       switch (command->cmd) {
> +       case MLNX_START_RUMBLE:
> +               left = rumble_force->strong;
> +               right = rumble_force->weak;
> +               dbg_hid("called with 0x%04x 0x%04x\n", left, right);
>  
> -       if (!left && !right) {
> -               holtekff_send(holtekff, hid, stop_all6);
> -               return 0;
> -       }
> +               if (!left && !right) {
> +                       holtekff_send(holtekff, hid, stop_all6);
> +                       return 0;
> +               }
>  
> -       if (left)
> -               buf[1] |= 0x80;
> -       if (right)
> -               buf[1] |= 0x40;
> +               if (left)
> +                       buf[1] |= 0x80;
> +               if (right)
> +                       buf[1] |= 0x40;
>  
> -       /* The device takes a single magnitude, so we just sum them
> up. */
> -       buf[6] = min(0xf, (left >> 12) + (right >> 12));
> +               /* The device takes a single magnitude, so we just sum
> them up. */
> +               buf[6] = min(0xf, (left >> 12) + (right >> 12));
>  
> -       holtekff_send(holtekff, hid, buf);
> -       holtekff_send(holtekff, hid, start_effect_1);
> +               holtekff_send(holtekff, hid, buf);
> +               holtekff_send(holtekff, hid, start_effect_1);
> +               return 0;
> +       case MLNX_STOP_RUMBLE:
> +               holtekff_send(holtekff, hid, stop_all6);
> +               return 0;
> +       default:
> +               return -EINVAL;
> +       }
>  
>         return 0;
>  }

This looks very much like doing DMA on the kernel stack.
That is very strictly forbidden. The bug is also in the current
code, but would you care to fix it up?

	Regards
		Oliver


--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Michal Malý April 23, 2014, 12:31 p.m. UTC | #2
On Wednesday 23 of April 2014 14:17:50 Oliver Neukum wrote:
> On Tue, 2014-04-22 at 15:59 +0200, Michal Malý wrote:
> >  static int holtekff_play(struct input_dev *dev, void *data,
> > 
> > -                        struct ff_effect *effect)
> > +                        const struct mlnx_effect_command *command)
> > 
> >  {
> >  
> >         struct hid_device *hid = input_get_drvdata(dev);
> >         struct holtekff_device *holtekff = data;
> > 
> > +       const struct mlnx_rumble_force *rumble_force =
> > &command->u.rumble_force;
> > 
> >         int left, right;
> >         /* effect type 1, length 65535 msec */
> >         u8 buf[HOLTEKFF_MSG_LENGTH] =
> >         
> >                 { 0x01, 0x01, 0xff, 0xff, 0x10, 0xe0, 0x00 };
> 
> On the kernel stack.
> 
> > -       left = effect->u.rumble.strong_magnitude;
> > -       right = effect->u.rumble.weak_magnitude;
> > -       dbg_hid("called with 0x%04x 0x%04x\n", left, right);
> > +       switch (command->cmd) {
> > +       case MLNX_START_RUMBLE:
> > +               left = rumble_force->strong;
> > +               right = rumble_force->weak;
> > +               dbg_hid("called with 0x%04x 0x%04x\n", left, right);
> > 
> > -       if (!left && !right) {
> > -               holtekff_send(holtekff, hid, stop_all6);
> > -               return 0;
> > -       }
> > +               if (!left && !right) {
> > +                       holtekff_send(holtekff, hid, stop_all6);
> > +                       return 0;
> > +               }
> > 
> > -       if (left)
> > -               buf[1] |= 0x80;
> > -       if (right)
> > -               buf[1] |= 0x40;
> > +               if (left)
> > +                       buf[1] |= 0x80;
> > +               if (right)
> > +                       buf[1] |= 0x40;
> > 
> > -       /* The device takes a single magnitude, so we just sum them
> > up. */
> > -       buf[6] = min(0xf, (left >> 12) + (right >> 12));
> > +               /* The device takes a single magnitude, so we just sum
> > them up. */
> > +               buf[6] = min(0xf, (left >> 12) + (right >> 12));
> > 
> > -       holtekff_send(holtekff, hid, buf);
> > -       holtekff_send(holtekff, hid, start_effect_1);
> > +               holtekff_send(holtekff, hid, buf);
> > +               holtekff_send(holtekff, hid, start_effect_1);
> > +               return 0;
> > +       case MLNX_STOP_RUMBLE:
> > +               holtekff_send(holtekff, hid, stop_all6);
> > +               return 0;
> > +       default:
> > +               return -EINVAL;
> > +       }
> > 
> >         return 0;
> >  
> >  }
> 
> This looks very much like doing DMA on the kernel stack.
> That is very strictly forbidden. The bug is also in the current
> code, but would you care to fix it up?

Okay, I'll look into it.

Michal

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dmitry Torokhov April 23, 2014, 4:02 p.m. UTC | #3
On Wed, Apr 23, 2014 at 02:17:50PM +0200, Oliver Neukum wrote:
> On Tue, 2014-04-22 at 15:59 +0200, Michal Malý wrote:
> >  static int holtekff_play(struct input_dev *dev, void *data,
> > -                        struct ff_effect *effect)
> > +                        const struct mlnx_effect_command *command)
> >  {
> >         struct hid_device *hid = input_get_drvdata(dev);
> >         struct holtekff_device *holtekff = data;
> > +       const struct mlnx_rumble_force *rumble_force =
> > &command->u.rumble_force;
> >         int left, right;
> >         /* effect type 1, length 65535 msec */
> >         u8 buf[HOLTEKFF_MSG_LENGTH] =
> >                 { 0x01, 0x01, 0xff, 0xff, 0x10, 0xe0, 0x00 };
> 
> On the kernel stack.
> 
> >  
> > -       left = effect->u.rumble.strong_magnitude;
> > -       right = effect->u.rumble.weak_magnitude;
> > -       dbg_hid("called with 0x%04x 0x%04x\n", left, right);
> > +       switch (command->cmd) {
> > +       case MLNX_START_RUMBLE:
> > +               left = rumble_force->strong;
> > +               right = rumble_force->weak;
> > +               dbg_hid("called with 0x%04x 0x%04x\n", left, right);
> >  
> > -       if (!left && !right) {
> > -               holtekff_send(holtekff, hid, stop_all6);
> > -               return 0;
> > -       }
> > +               if (!left && !right) {
> > +                       holtekff_send(holtekff, hid, stop_all6);
> > +                       return 0;
> > +               }
> >  
> > -       if (left)
> > -               buf[1] |= 0x80;
> > -       if (right)
> > -               buf[1] |= 0x40;
> > +               if (left)
> > +                       buf[1] |= 0x80;
> > +               if (right)
> > +                       buf[1] |= 0x40;
> >  
> > -       /* The device takes a single magnitude, so we just sum them
> > up. */
> > -       buf[6] = min(0xf, (left >> 12) + (right >> 12));
> > +               /* The device takes a single magnitude, so we just sum
> > them up. */
> > +               buf[6] = min(0xf, (left >> 12) + (right >> 12));
> >  
> > -       holtekff_send(holtekff, hid, buf);
> > -       holtekff_send(holtekff, hid, start_effect_1);
> > +               holtekff_send(holtekff, hid, buf);
> > +               holtekff_send(holtekff, hid, start_effect_1);
> > +               return 0;
> > +       case MLNX_STOP_RUMBLE:
> > +               holtekff_send(holtekff, hid, stop_all6);
> > +               return 0;
> > +       default:
> > +               return -EINVAL;
> > +       }
> >  
> >         return 0;
> >  }
> 
> This looks very much like doing DMA on the kernel stack.

It isn't:

static void holtekff_send(struct holtekff_device *holtekff,
                          struct hid_device *hid,
                          const u8 data[HOLTEKFF_MSG_LENGTH])
{
        int i;

        for (i = 0; i < HOLTEKFF_MSG_LENGTH; i++) {
                holtekff->field->value[i] = data[i];
        }

        dbg_hid("sending %7ph\n", data);

        hid_hw_request(hid, holtekff->field->report, HID_REQ_SET_REPORT);
}

And also hid layer copies data a bunch of times over into DMA-safe
buffers.

> That is very strictly forbidden. The bug is also in the current
> code, but would you care to fix it up?
> 
> 	Regards
> 		Oliver
> 
>
diff mbox

Patch

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 24b336e..d1d4e77 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -247,7 +247,7 @@  config HID_HOLTEK
 config HOLTEK_FF
 	bool "Holtek On Line Grip force feedback support"
 	depends on HID_HOLTEK
-	select INPUT_FF_MEMLESS
+	select INPUT_FF_MEMLESS_NEXT
 	---help---
 	  Say Y here if you have a Holtek On Line Grip based game controller
 	  and want to have force feedback support for it.
diff --git a/drivers/hid/hid-holtekff.c b/drivers/hid/hid-holtekff.c
index 9325545..9c6064d 100644
--- a/drivers/hid/hid-holtekff.c
+++ b/drivers/hid/hid-holtekff.c
@@ -27,9 +27,12 @@ 
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/input/ff-memless-next.h>
 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 #ifdef CONFIG_HOLTEK_FF
 
 MODULE_LICENSE("GPL");
@@ -104,34 +107,44 @@  static void holtekff_send(struct holtekff_device *holtekff,
 }
 
 static int holtekff_play(struct input_dev *dev, void *data,
-			 struct ff_effect *effect)
+			 const struct mlnx_effect_command *command)
 {
 	struct hid_device *hid = input_get_drvdata(dev);
 	struct holtekff_device *holtekff = data;
+	const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
 	int left, right;
 	/* effect type 1, length 65535 msec */
 	u8 buf[HOLTEKFF_MSG_LENGTH] =
 		{ 0x01, 0x01, 0xff, 0xff, 0x10, 0xe0, 0x00 };
 
-	left = effect->u.rumble.strong_magnitude;
-	right = effect->u.rumble.weak_magnitude;
-	dbg_hid("called with 0x%04x 0x%04x\n", left, right);
+	switch (command->cmd) {
+	case MLNX_START_RUMBLE:
+		left = rumble_force->strong;
+		right = rumble_force->weak;
+		dbg_hid("called with 0x%04x 0x%04x\n", left, right);
 
-	if (!left && !right) {
-		holtekff_send(holtekff, hid, stop_all6);
-		return 0;
-	}
+		if (!left && !right) {
+			holtekff_send(holtekff, hid, stop_all6);
+			return 0;
+		}
 
-	if (left)
-		buf[1] |= 0x80;
-	if (right)
-		buf[1] |= 0x40;
+		if (left)
+			buf[1] |= 0x80;
+		if (right)
+			buf[1] |= 0x40;
 
-	/* The device takes a single magnitude, so we just sum them up. */
-	buf[6] = min(0xf, (left >> 12) + (right >> 12));
+		/* The device takes a single magnitude, so we just sum them up. */
+		buf[6] = min(0xf, (left >> 12) + (right >> 12));
 
-	holtekff_send(holtekff, hid, buf);
-	holtekff_send(holtekff, hid, start_effect_1);
+		holtekff_send(holtekff, hid, buf);
+		holtekff_send(holtekff, hid, start_effect_1);
+		return 0;
+	case MLNX_STOP_RUMBLE:
+		holtekff_send(holtekff, hid, stop_all6);
+		return 0;
+	default:
+		return -EINVAL;
+	}
 
 	return 0;
 }
@@ -171,7 +184,7 @@  static int holtekff_init(struct hid_device *hid)
 	holtekff_send(holtekff, hid, stop_all4);
 	holtekff_send(holtekff, hid, stop_all6);
 
-	error = input_ff_create_memless(dev, holtekff, holtekff_play);
+	error = input_ff_create_mlnx(dev, holtekff, holtekff_play, FF_UPDATE_RATE);
 	if (error) {
 		kfree(holtekff);
 		return error;