Re: [RFC] HID:hid-lg4ff: Delay to allow wheels to center after plug-in

2016-10-26 Thread Michal Malý
Hi all,

maybe instead of stalling the entire init() function it'd be better to put a 
request to disable autocentering on a workqueue and start a delayed work once 
the init() function is done setting the wheel up? There'd be a bit more code 
to write though...

Michal

On Tuesday, October 25, 2016 7:26:12 PM CEST Simon Wood wrote:
> A number of wheels (G27/etc) do a little full right/full left 'dance'
> when first plugged in. This patch inserts a delay so that this 'dance'
> is completed before we disable (set to zero) the autocenter spring.
> 
> A side benefit is that the DFGT was confused without the delay, and is
> now correctly being set to 900' rotation mode.
> 
> Side Effect - and the reason I am sending as RFC. This 8s delay seems
> to have an effect on other wheels connected at the same time.
> 
> With 3 wheels on a hub, and then the hub connected to PC. The wheel
> on the right in video below waits for G27 to complete this 8s, before
> it will do it's 'dance' and register with the system.
> 
> https://www.youtube.com/watch?v=xCVpCw_yGgA
> 
> I don't know if this is a problem, or if someone here has suggestions
> on a better way to implement the delay...
> ---
>  drivers/hid/hid-lg4ff.c | 10 ++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
> index af3a8ec..3eee920 100644
> --- a/drivers/hid/hid-lg4ff.c
> +++ b/drivers/hid/hid-lg4ff.c
> @@ -1248,6 +1248,8 @@ int lg4ff_init(struct hid_device *hid)
>   /* Check if autocentering is available and
>* set the centering force to zero by default */
>   if (test_bit(FF_AUTOCENTER, dev->ffbit)) {
> + wait_queue_head_t wait;
> +
>   /* Formula Force EX expects different autocentering command */
>   if ((bcdDevice >> 8) == LG4FF_FFEX_REV_MAJ &&
>   (bcdDevice & 0xff) == LG4FF_FFEX_REV_MIN)
> @@ -1255,6 +1257,14 @@ int lg4ff_init(struct hid_device *hid)
>   else
>   dev->ff->set_autocenter = lg4ff_set_autocenter_default;
> 
> + /* insert a 8s delay to allow DFGT/G25/G27/G29 wheels to return 
> to 
center
> position*/ +  if (lg4ff_devices[i].product_id ==
> USB_DEVICE_ID_LOGITECH_DFGT_WHEEL || +
lg4ff_devices[i].product_id ==
> USB_DEVICE_ID_LOGITECH_G25_WHEEL || + 
> lg4ff_devices[i].product_id 
==
> USB_DEVICE_ID_LOGITECH_G27_WHEEL || + 
> lg4ff_devices[i].product_id 
==
> USB_DEVICE_ID_LOGITECH_G29_WHEEL) { + init_waitqueue_head 
> (&wait);
> + wait_event_interruptible_timeout(wait, 0, 
> msecs_to_jiffies(8000));
> + }
>   dev->ff->set_autocenter(dev, 0);
>   }




Re: [PATCH 0/2] Add a skeleton module to perform a basic initialization on certain USB devices

2016-01-25 Thread Michal Malý
On Mon, 2016-01-25 at 15:17 +0100, Jiri Kosina wrote:
> On Sat, 23 Jan 2016, Michal Malý wrote:
> 
> > I briefly considered leaving the switch up to the userspace and
> handling the 
> > device in the kernel only once it's been switched. I am however
> uncertain how 
> > to advertise this to the users. Writing a tiny app that would
> currently handle 
> > just one device seems like an overkill, abusing usb_modeswitch
> seems counter-
> > intuitive as it's purpose is to handle various USB modems. 
> 
> Well, originally usb_modeswitch (beware, it's called "modeswitch",
> not 
> "modemswitch" :) ) was purely for handling ZeroCD on USB 3G modems,
> and 
> it's currently still by far the most common case, but there are
> other 
> devices being handled by that package now; I for example recall some 
> HP printers needing a magic USB command to be sent to it before they
> would 
> start printing, and usb_modeswitch is handling those now AFAIK.
> 
> So if we do this in userspace, I think usb_modeswitch is not a bad
> choice.

Ok, that's interesting... I tinkered with usb_modeswitch a bit and I
made it switch the G920 just fine after a while. Consider the patches
dropped then, letting usb_modeswitch take care of this sounds
reasonable.

Michal


Re: [PATCH 0/2] Add a skeleton module to perform a basic initialization on certain USB devices

2016-01-23 Thread Michal Malý
On sobota 23. ledna 2016 13:46:32 CET Bjørn Mork wrote:
> Michal Malý  writes:
> > This mini series adds a simple skeleton module whose only purpose is to
> > bring devices that at first appear as a generic USB device into another
> > mode that can be handled by a more specific subsystem.
> > 
> > This patch was originally requested by Dmitry, reasoning that loading the
> > entire xpad module just to switch a Logitech G920 wheel into HID mode is
> > excessive and does not make much sense.
> > 
> > The module can be extended to handle any other USB device that might
> > require such a switch.
> 
> Can this switching be done in userspace? That's what we normally do, ref
> usb_modeswitch.

I briefly considered leaving the switch up to the userspace and handling the 
device in the kernel only once it's been switched. I am however uncertain how 
to advertise this to the users. Writing a tiny app that would currently handle 
just one device seems like an overkill, abusing usb_modeswitch seems counter-
intuitive as it's purpose is to handle various USB modems. Having a tiny 
module in the kernel looks like the most straightforward thing to do as far as 
user experience is concerned.

I would not object to deferring the switch to userspace as long as there is an 
easy way how to communicate the need for a small switching tool to the users.

Michal


[PATCH 1/2] Add usb_skelswitch skeleton module to do basic initialization of devices that at first appear as a generic USB device.

2016-01-23 Thread Michal Malý
This gets rid of the need to handle such devices in more specific
drivers that will be loaded for no purpose other than to do some basic
initialization on the device.

Signed-off-by: Michal Malý 
---
 drivers/usb/Kconfig |  2 +
 drivers/usb/common/Kconfig  | 15 +++
 drivers/usb/common/Makefile |  2 +
 drivers/usb/common/usb-skelswitch.c | 81 +
 4 files changed, 100 insertions(+)
 create mode 100644 drivers/usb/common/Kconfig
 create mode 100644 drivers/usb/common/usb-skelswitch.c

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 8ed451d..3de5d35 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -78,6 +78,8 @@ if USB
 
 source "drivers/usb/core/Kconfig"
 
+source "drivers/usb/common/Kconfig"
+
 source "drivers/usb/mon/Kconfig"
 
 source "drivers/usb/wusbcore/Kconfig"
diff --git a/drivers/usb/common/Kconfig b/drivers/usb/common/Kconfig
new file mode 100644
index 000..6d9ec79
--- /dev/null
+++ b/drivers/usb/common/Kconfig
@@ -0,0 +1,15 @@
+#
+# USB common modules
+#
+
+if USB_COMMON
+
+config USB_SKELSWITCH
+   tristate "Simple USB module for basic device initialization"
+   help
+ Simple module that performs basic initialization on devices that at 
first
+ appear as a generic USB device.
+
+ Say Y if you intend to use a device that requires this initial switch.
+
+endif # USB_COMMON
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index 6bbb3ec..5e7c15a 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -8,3 +8,5 @@ usb-common-$(CONFIG_USB_LED_TRIG) += led.o
 
 obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o
 obj-$(CONFIG_USB_ULPI_BUS) += ulpi.o
+
+obj-$(CONFIG_USB_SKELSWITCH)  += usb-skelswitch.o
diff --git a/drivers/usb/common/usb-skelswitch.c 
b/drivers/usb/common/usb-skelswitch.c
new file mode 100644
index 000..ae72068
--- /dev/null
+++ b/drivers/usb/common/usb-skelswitch.c
@@ -0,0 +1,81 @@
+#include 
+#include 
+
+MODULE_LICENSE("GPL");
+
+struct usb_skelswitch_product {
+   const u16 idProduct;
+   int (*action)(struct usb_interface *);
+};
+
+struct usb_skelswitch_vendor {
+   const u16 idVendor;
+   const struct usb_skelswitch_product *products;
+};
+
+static const struct usb_device_id usb_skelswitch_table[] = {
+   { }
+};
+
+static const struct usb_skelswitch_vendor usb_skelswitch_vendors[] = {
+   { 0, NULL }
+};
+
+static int usb_skelswitch_process_products(struct usb_interface *intf, const 
struct usb_skelswitch_product *products, const u16 idProduct)
+{
+   size_t idx = 0;
+   const struct usb_device *udev = interface_to_usbdev(intf);
+
+   while (1) {
+   const struct usb_skelswitch_product *product = &products[idx];
+
+   if (product->idProduct == 0) {
+   dev_err(&udev->dev, "usb_skelswitch: Unhandled 
idProduct 0x%04x\n", idProduct);
+   return -EINVAL;
+   }
+
+   if (product->idProduct == idProduct) {
+   if (product->action)
+   return product->action(intf);
+   else
+   return 0;
+   }
+
+   idx++;
+   }
+}
+
+static int usb_skelswitch_probe(struct usb_interface *intf, const struct 
usb_device_id *id)
+{
+   size_t idx = 0;
+   const struct usb_device *udev = interface_to_usbdev(intf);
+
+   while (1) {
+   const struct usb_skelswitch_vendor *vendor = 
&usb_skelswitch_vendors[idx];
+
+   if (vendor->idVendor == 0) {
+   dev_err(&udev->dev, "Unhandled idVendor 0x%04x", 
id->idVendor);
+   return -EINVAL;
+   }
+
+   if (id->idVendor == vendor->idVendor)
+   return usb_skelswitch_process_products(intf, 
vendor->products, id->idProduct);
+
+   idx++;
+   }
+}
+
+static void usb_skelswitch_disconnect(struct usb_interface *intf)
+{
+   (void)intf;
+}
+
+static struct usb_driver usb_skelswitch_driver = {
+   .disconnect = usb_skelswitch_disconnect,
+   .name = "usb_skelswitch",
+   .probe = usb_skelswitch_probe,
+   .id_table = usb_skelswitch_table
+};
+
+module_usb_driver(usb_skelswitch_driver);
+
-- 
2.7.0



[PATCH 2/2] Use usb_skelswitch module to switch Logitech G920 Racing Wheel to HID mode.

2016-01-23 Thread Michal Malý
Tested-by: Elias Vanderstuyft 
Signed-off-by: Michal Malý 
---
 drivers/usb/common/Kconfig  |  2 ++
 drivers/usb/common/usb-skelswitch.c | 60 +
 2 files changed, 62 insertions(+)

diff --git a/drivers/usb/common/Kconfig b/drivers/usb/common/Kconfig
index 6d9ec79..8ae9a1e 100644
--- a/drivers/usb/common/Kconfig
+++ b/drivers/usb/common/Kconfig
@@ -11,5 +11,7 @@ config USB_SKELSWITCH
  appear as a generic USB device.
 
  Say Y if you intend to use a device that requires this initial switch.
+ Devices that currently require this module:
+  - Logitech G920 Racing Wheel
 
 endif # USB_COMMON
diff --git a/drivers/usb/common/usb-skelswitch.c 
b/drivers/usb/common/usb-skelswitch.c
index ae72068..fc85c70 100644
--- a/drivers/usb/common/usb-skelswitch.c
+++ b/drivers/usb/common/usb-skelswitch.c
@@ -14,10 +14,70 @@ struct usb_skelswitch_vendor {
 };
 
 static const struct usb_device_id usb_skelswitch_table[] = {
+   { USB_DEVICE(0x046d, 0xc261) },
{ }
 };
 
+MODULE_DEVICE_TABLE(usb, usb_skelswitch_table);
+
+static int usb_skelswitch_lg_g920(struct usb_interface *intf)
+{
+   struct usb_host_interface *iface_desc;
+   struct usb_endpoint_descriptor *endpoint;
+   struct usb_device *udev;
+   int idx;
+   int ret;
+   int xferred;
+   size_t buffer_size;
+   unsigned char cmd[] = { 0x0f, 0x00, 0x01, 0x01, 0x42 };
+   const size_t cmd_len = ARRAY_SIZE(cmd);
+   u8 intr_out_addr = 0;
+
+   udev = usb_get_dev(interface_to_usbdev(intf));
+   iface_desc = intf->cur_altsetting;
+   for (idx = 0; idx < iface_desc->desc.bNumEndpoints; idx++) {
+   endpoint = &iface_desc->endpoint[idx].desc;
+
+   if (usb_endpoint_is_int_out(endpoint)) {
+   intr_out_addr = endpoint->bEndpointAddress;
+   buffer_size = usb_endpoint_maxp(endpoint);
+   break;
+   }
+   }
+
+   if (!intr_out_addr) {
+   dev_err(&udev->dev, "Logitech G920 - No interrupt out endpoint 
found");
+   return -ENODEV;
+   }
+
+   if (buffer_size < cmd_len) {
+   dev_err(&udev->dev, "usb_skelswitch: Logitech G920 - Output 
buffer is too small");
+   return -ENODEV;
+   }
+
+
+   ret = usb_interrupt_msg(udev, usb_sndintpipe(udev, intr_out_addr),
+   cmd, cmd_len, &xferred, USB_CTRL_SET_TIMEOUT);
+
+   if (ret) {
+   dev_err(&udev->dev, "LG G920: Failed to submit URB, errno: %d", 
ret);
+   return ret;
+   }
+   if (xferred != cmd_len) {
+   dev_err(&udev->dev, "LG G920: Incorrect number of bytes 
transferred: %d", xferred);
+   return -EIO;
+   }
+
+   return 0;
+}
+
+static const struct usb_skelswitch_product usb_skelswitch_logitech_devs[] = {
+   { 0xc261, usb_skelswitch_lg_g920 },
+   { 0, NULL }
+};
+
 static const struct usb_skelswitch_vendor usb_skelswitch_vendors[] = {
+   { 0x046d, usb_skelswitch_logitech_devs },
{ 0, NULL }
 };
 
-- 
2.7.0



[PATCH 0/2] Add a skeleton module to perform a basic initialization on certain USB devices

2016-01-23 Thread Michal Malý
This mini series adds a simple skeleton module whose only purpose is to bring
devices that at first appear as a generic USB device into another mode that
can be handled by a more specific subsystem.

This patch was originally requested by Dmitry, reasoning that loading the
entire xpad module just to switch a Logitech G920 wheel into HID mode is
excessive and does not make much sense.

The module can be extended to handle any other USB device that might require
such a switch.

Signed-off-by: Michal Malý 

Michal Malý (2):
  Add usb_skelswitch skeleton module to do basic initialization of
devices that at first appear as a generic USB device.
  Use usb_skelswitch module to switch Logitech G920 Racing Wheel to HID 
   mode.

 drivers/usb/Kconfig |   2 +
 drivers/usb/common/Kconfig  |  17 +
 drivers/usb/common/Makefile |   2 +
 drivers/usb/common/usb-skelswitch.c | 141 
 4 files changed, 162 insertions(+)
 create mode 100644 drivers/usb/common/Kconfig
 create mode 100644 drivers/usb/common/usb-skelswitch.c

-- 
2.7.0



[PATCH 01/12] HID: hid-lg4ff: (Cleanup) Remove double underscore prefix from numeric types.

2015-03-21 Thread Michal Malý
This code will never be used outside the kernel so the prefixes are
unnecessary.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg4ff.c | 52 -
 drivers/hid/hid-lg4ff.h |  4 ++--
 2 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 1232210..70e5ae6 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -72,12 +72,12 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, 
u16 range);
 static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
 
 struct lg4ff_device_entry {
-   __u32 product_id;
-   __u16 range;
-   __u16 min_range;
-   __u16 max_range;
+   u32 product_id;
+   u16 range;
+   u16 min_range;
+   u16 max_range;
 #ifdef CONFIG_LEDS_CLASS
-   __u8  led_state;
+   u8  led_state;
struct led_classdev *led[5];
 #endif
u32 alternate_modes;
@@ -95,16 +95,16 @@ static const signed short lg4ff_wheel_effects[] = {
 };
 
 struct lg4ff_wheel {
-   const __u32 product_id;
+   const u32 product_id;
const signed short *ff_effects;
-   const __u16 min_range;
-   const __u16 max_range;
+   const u16 min_range;
+   const u16 max_range;
void (*set_range)(struct hid_device *hid, u16 range);
 };
 
 struct lg4ff_compat_mode_switch {
-   const __u8 cmd_count;   /* Number of commands to send */
-   const __u8 cmd[];
+   const u8 cmd_count; /* Number of commands to send */
+   const u8 cmd[];
 };
 
 struct lg4ff_wheel_ident_info {
@@ -245,10 +245,10 @@ static const struct lg4ff_compat_mode_switch 
lg4ff_mode_switch_ext16_g25 = {
 };
 
 /* Recalculates X axis value accordingly to currently selected range */
-static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range)
+static s32 lg4ff_adjust_dfp_x_axis(s32 value, u16 range)
 {
-   __u16 max_range;
-   __s32 new_value;
+   u16 max_range;
+   s32 new_value;
 
if (range == 900)
return value;
@@ -269,10 +269,10 @@ static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 
range)
 }
 
 int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
-struct hid_usage *usage, __s32 value, struct 
lg_drv_data *drv_data)
+struct hid_usage *usage, s32 value, struct 
lg_drv_data *drv_data)
 {
struct lg4ff_device_entry *entry = drv_data->device_props;
-   __s32 new_value = 0;
+   s32 new_value = 0;
 
if (!entry) {
hid_err(hid, "Device properties not found");
@@ -299,7 +299,7 @@ static int hid_lg4ff_play(struct input_dev *dev, void 
*data, struct ff_effect *e
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
-   __s32 *value = report->field[0]->value;
+   s32 *value = report->field[0]->value;
int x;
 
 #define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while 
(0)
@@ -344,8 +344,8 @@ static void hid_lg4ff_set_autocenter_default(struct 
input_dev *dev, u16 magnitud
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
-   __s32 *value = report->field[0]->value;
-   __u32 expand_a, expand_b;
+   s32 *value = report->field[0]->value;
+   u32 expand_a, expand_b;
struct lg4ff_device_entry *entry;
struct lg_drv_data *drv_data;
 
@@ -421,7 +421,7 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev 
*dev, u16 magnitude)
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
-   __s32 *value = report->field[0]->value;
+   s32 *value = report->field[0]->value;
magnitude = magnitude * 90 / 65535;
 
value[0] = 0xfe;
@@ -440,7 +440,7 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, 
u16 range)
 {
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
-   __s32 *value = report->field[0]->value;
+   s32 *value = report->field[0]->value;
 
dbg_hid("G25/G27/DFGT: setting range to %u\n", range);
 
@@ -456,12 +456,12 @@ static void hid_lg4ff_set_range_g25(struct hid_device 
*hid, u16 range)
 }
 
 /* Sends commands to set range compatible with Driving Force Pro wh

[PATCH 02/12] HID: hid-lg4ff: (Cleanup) Remove "hid_" prefix from some functions names.

2015-03-21 Thread Michal Malý
All internal functions of hid-lg4ff should be prefixed with just
"lg4ff_"

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg4ff.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 70e5ae6..9a0c0e5 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -68,8 +68,8 @@
 #define LG4FF_FFEX_REV_MAJ 0x21
 #define LG4FF_FFEX_REV_MIN 0x00
 
-static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
-static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
+static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
+static void lg4ff_set_range_g25(struct hid_device *hid, u16 range);
 
 struct lg4ff_device_entry {
u32 product_id;
@@ -134,10 +134,10 @@ struct lg4ff_alternate_mode {
 static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WHEEL,   lg4ff_wheel_effects, 40, 270, 
NULL},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL,  lg4ff_wheel_effects, 40, 270, 
NULL},
-   {USB_DEVICE_ID_LOGITECH_DFP_WHEEL,   lg4ff_wheel_effects, 40, 900, 
hid_lg4ff_set_range_dfp},
-   {USB_DEVICE_ID_LOGITECH_G25_WHEEL,   lg4ff_wheel_effects, 40, 900, 
hid_lg4ff_set_range_g25},
-   {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL,  lg4ff_wheel_effects, 40, 900, 
hid_lg4ff_set_range_g25},
-   {USB_DEVICE_ID_LOGITECH_G27_WHEEL,   lg4ff_wheel_effects, 40, 900, 
hid_lg4ff_set_range_g25},
+   {USB_DEVICE_ID_LOGITECH_DFP_WHEEL,   lg4ff_wheel_effects, 40, 900, 
lg4ff_set_range_dfp},
+   {USB_DEVICE_ID_LOGITECH_G25_WHEEL,   lg4ff_wheel_effects, 40, 900, 
lg4ff_set_range_g25},
+   {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL,  lg4ff_wheel_effects, 40, 900, 
lg4ff_set_range_g25},
+   {USB_DEVICE_ID_LOGITECH_G27_WHEEL,   lg4ff_wheel_effects, 40, 900, 
lg4ff_set_range_g25},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, 
NULL},
{USB_DEVICE_ID_LOGITECH_WII_WHEEL,   lg4ff_wheel_effects, 40, 270, NULL}
 };
@@ -294,7 +294,7 @@ int lg4ff_adjust_input_event(struct hid_device *hid, struct 
hid_field *field,
}
 }
 
-static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect 
*effect)
+static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect 
*effect)
 {
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
@@ -339,7 +339,7 @@ static int hid_lg4ff_play(struct input_dev *dev, void 
*data, struct ff_effect *e
 
 /* Sends default autocentering command compatible with
  * all wheels except Formula Force EX */
-static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 
magnitude)
+static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude)
 {
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
@@ -416,7 +416,7 @@ static void hid_lg4ff_set_autocenter_default(struct 
input_dev *dev, u16 magnitud
 }
 
 /* Sends autocentering command compatible with Formula Force EX */
-static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
+static void lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
 {
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
@@ -436,7 +436,7 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev 
*dev, u16 magnitude)
 }
 
 /* Sends command to set range compatible with G25/G27/Driving Force GT */
-static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range)
+static void lg4ff_set_range_g25(struct hid_device *hid, u16 range)
 {
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
@@ -456,7 +456,7 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, 
u16 range)
 }
 
 /* Sends commands to set range compatible with Driving Force Pro wheel */
-static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range)
+static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range)
 {
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
@@ -1043,7 +1043,7 @@ int lg4ff_init(struct hid_device *hid)
for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++)
set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit);
 
-   error = input_ff_create_memless(dev, NULL, hid_lg4ff_play);
+   error = input_ff_create_memless(dev, NULL, lg4ff_play);
 
if (error)
return error;
@@ -1081,9 +1081,9 @@ int lg4ff_init(struct hid_device *hid)
/*

[PATCH 05/12] HID: hid-lg4ff: Update a warning message for a case where device is incorrectly flagged to be handled by hid-lg4ff in hid-lg.

2015-03-21 Thread Michal Malý
The original warning message was highly misleading. This warning can be
triggered only if a device is flagged to be handled by hid-lg4ff in
hid-lg but hid-lg4ff lacks support for such device.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg4ff.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index d1d5d45..a2f47ee 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -1021,8 +1021,7 @@ int lg4ff_init(struct hid_device *hid)
}
 
if (i == ARRAY_SIZE(lg4ff_devices)) {
-   hid_err(hid, "Device is not supported by lg4ff driver. If you 
think it should be, consider reporting a bug to"
-"LKML, Simon Wood  or Michal 
Maly \n");
+   hid_err(hid, "This device is flagged to be handled by the lg4ff 
module but this module does not know how to handle it. Please report this as a 
bug to LKML, Simon Wood  or Michal Maly 
\n");
return -1;
}
 
-- 
2.3.3

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


[PATCH 08/12] HID: hid-lg4ff: Store pointer to the output HID report struct in the device entry struct.

2015-03-21 Thread Michal Malý
This eliminates the need to look the HID report struct up every time it is 
needed.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg4ff.c | 67 +++--
 1 file changed, 32 insertions(+), 35 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 0bbdeea..fd6f140 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -90,6 +90,7 @@ struct lg4ff_wheel_data {
 
 struct lg4ff_device_entry {
spinlock_t report_lock;
+   struct hid_report *report;
struct lg4ff_wheel_data wdata;
 };
 
@@ -302,11 +303,9 @@ int lg4ff_adjust_input_event(struct hid_device *hid, 
struct hid_field *field,
 static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect 
*effect)
 {
struct hid_device *hid = input_get_drvdata(dev);
-   struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-   struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
struct lg4ff_device_entry *entry;
struct lg_drv_data *drv_data;
-   s32 *value = report->field[0]->value;
+   s32 *value;
int x;
unsigned long flags;
 
@@ -321,6 +320,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, 
struct ff_effect *effec
hid_err(hid, "Device properties not found!\n");
return -EINVAL;
}
+   value = entry->report->field[0]->value;
 
 #define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while 
(0)
 
@@ -340,7 +340,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, 
struct ff_effect *effec
value[5] = 0x00;
value[6] = 0x00;
 
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&entry->report_lock, flags);
return 0;
}
@@ -353,7 +353,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, 
struct ff_effect *effec
value[5] = 0x00;
value[6] = 0x00;
 
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&entry->report_lock, flags);
break;
}
@@ -365,11 +365,9 @@ static int lg4ff_play(struct input_dev *dev, void *data, 
struct ff_effect *effec
 static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude)
 {
struct hid_device *hid = input_get_drvdata(dev);
-   struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-   struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
struct lg4ff_device_entry *entry;
struct lg_drv_data *drv_data;
-   s32 *value = report->field[0]->value;
+   s32 *value;
u32 expand_a, expand_b;
unsigned long flags;
 
@@ -384,6 +382,7 @@ static void lg4ff_set_autocenter_default(struct input_dev 
*dev, u16 magnitude)
hid_err(hid, "Device properties not found!\n");
return;
}
+   value = entry->report->field[0]->value;
 
/* De-activate Auto-Center */
spin_lock_irqsave(&entry->report_lock, flags);
@@ -396,7 +395,7 @@ static void lg4ff_set_autocenter_default(struct input_dev 
*dev, u16 magnitude)
value[5] = 0x00;
value[6] = 0x00;
 
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&entry->report_lock, flags);
return;
}
@@ -427,7 +426,7 @@ static void lg4ff_set_autocenter_default(struct input_dev 
*dev, u16 magnitude)
value[5] = 0x00;
value[6] = 0x00;
 
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
 
/* Activate Auto-Center */
value[0] = 0x14;
@@ -438,7 +437,7 @@ static void lg4ff_set_autocenter_default(struct input_dev 
*dev, u16 magnitude)
value[5] = 0x00;
value[6] = 0x00;
 
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&entry->report_lock, flags);
 }
 
@@ -446,12 +445,10 @@ static void lg4ff_set_autocenter_default(struct input_dev 
*dev, u16 magnitude)
 static void lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
 {
struct hid_device *hid = input_get_drvdata(dev);
-   struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-   struct hid_report *report = li

[PATCH 06/12] HID: hid-lg: Check return values from lg[N]ff_init()

2015-03-21 Thread Michal Malý
hid-lg did not check return values from the lg[N]_init() functions,
possibly trying to work with a device whose initialization has failed.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index b86c18e..c797781 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -712,13 +712,16 @@ static int lg_probe(struct hid_device *hdev, const struct 
hid_device_id *id)
}
 
if (drv_data->quirks & LG_FF)
-   lgff_init(hdev);
+   ret = lgff_init(hdev);
if (drv_data->quirks & LG_FF2)
-   lg2ff_init(hdev);
+   ret = lg2ff_init(hdev);
if (drv_data->quirks & LG_FF3)
-   lg3ff_init(hdev);
+   ret = lg3ff_init(hdev);
if (drv_data->quirks & LG_FF4)
-   lg4ff_init(hdev);
+   ret = lg4ff_init(hdev);
+
+   if (ret)
+   goto err_free;
 
return 0;
 err_free:
-- 
2.3.3

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


[PATCH 00/12] HID: hid-lg, hid-lg4ff: Mostly cleanup patches

2015-03-21 Thread Michal Malý
Hello everyone,

this is a mostly boring series that deals with a few inconsistencies in the
code that have accumulated over the years. Besides that it patches up a handful
of problems such a return values not being checked etc.

The only significant change comes in patch 0007 which introduces a spinlock to
handle concurrent access to the HID report that is used by the driver to send
data to the wheel. I would appreciate some comments on this one, particularly
on the way it handles deinitialization.

Michal Malý (12):
  HID: hid-lg4ff: (Cleanup) Remove double underscore prefix from numeric
types.
  HID: hid-lg4ff: (Cleanup) Remove "hid_" prefix from some functions
names.
  HID: hid-lg4ff: (Cleanup) Replace DEVICE_ATTR_RW with DEVICE_ATTR to
have all internal functions prefixed with "lg4ff_"
  HID: hid-lg4ff: (Cleanup) Remove unused variable from the
"lg4ff_device_entry" struct.
  HID: hid-lg4ff: Update a warning message for a case where device is
incorrectly flagged to be handled by hid-lg4ff in hid-lg.
  HID: hid-lg: Check return values from lg[N]ff_init()
  HID: hid-lg4ff: Protect concurrent access to the output HID report
values with a spinlock.
  HID: hid-lg4ff: Store pointer to the output HID report struct in the
device entry struct.
  HID: hid-lg4ff: Constify those members of lg4ff_device_entry struct
whose value is not supposed to change.
  HID: hid-lg4ff: Allow the driver to continue without sysfs interface.
  HID: hid-lg4ff: Update respective sysfs interface documentation
  HID: hid-lg: Only one of LG_FF flags can be set for a given device.

 .../ABI/testing/sysfs-driver-hid-logitech-lg4ff|   8 +-
 drivers/hid/hid-lg.c   |  21 +-
 drivers/hid/hid-lg4ff.c| 459 ++---
 drivers/hid/hid-lg4ff.h|   4 +-
 4 files changed, 319 insertions(+), 173 deletions(-)

-- 
2.3.3

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


[PATCH 10/12] HID: hid-lg4ff: Allow the driver to continue without sysfs interface.

2015-03-21 Thread Michal Malý
Instead of aborting the initialization allow the driver to continue in
a degraded mode.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg4ff.c | 15 +--
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index ad959e2..5543728 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -1226,19 +1226,14 @@ int lg4ff_init(struct hid_device *hid)
/* Create sysfs interface */
error = device_create_file(&hid->dev, &dev_attr_range);
if (error)
-   goto err_init;
+   hid_warn(hid, "Unable to create sysfs interface for \"range\", 
errno %d\n", error);
if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) {
error = device_create_file(&hid->dev, &dev_attr_real_id);
-   if (error) {
-   device_remove_file(&hid->dev, &dev_attr_range);
-   goto err_init;
-   }
+   if (error)
+   hid_warn(hid, "Unable to create sysfs interface for 
\"real_id\", errno %d\n", error);
error = device_create_file(&hid->dev, 
&dev_attr_alternate_modes);
-   if (error) {
-   device_remove_file(&hid->dev, &dev_attr_real_id);
-   device_remove_file(&hid->dev, &dev_attr_range);
-   goto err_init;
-   }
+   if (error)
+   hid_warn(hid, "Unable to create sysfs interface for 
\"alternate_modes\", errno %d\n", error);
}
dbg_hid("sysfs interface created\n");
 
-- 
2.3.3

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


[PATCH 09/12] HID: hid-lg4ff: Constify those members of lg4ff_device_entry struct whose value is not supposed to change.

2015-03-21 Thread Michal Malý
Prevent accidental modifications of read-only members of the lg4ff_device_entry
struct.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg4ff.c | 54 +++--
 1 file changed, 39 insertions(+), 15 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index fd6f140..ad959e2 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -72,18 +72,18 @@ static void lg4ff_set_range_dfp(struct hid_device *hid, u16 
range);
 static void lg4ff_set_range_g25(struct hid_device *hid, u16 range);
 
 struct lg4ff_wheel_data {
-   u32 product_id;
+   const u32 product_id;
u16 range;
-   u16 min_range;
-   u16 max_range;
+   const u16 min_range;
+   const u16 max_range;
 #ifdef CONFIG_LEDS_CLASS
u8  led_state;
struct led_classdev *led[5];
 #endif
-   u32 alternate_modes;
-   const char *real_tag;
-   const char *real_name;
-   u16 real_product_id;
+   const u32 alternate_modes;
+   const char * const real_tag;
+   const char * const real_name;
+   const u16 real_product_id;
 
void (*set_range)(struct hid_device *hid, u16 range);
 };
@@ -300,6 +300,34 @@ int lg4ff_adjust_input_event(struct hid_device *hid, 
struct hid_field *field,
}
 }
 
+static void lg4ff_init_wheel_data(struct lg4ff_wheel_data * const wdata, const 
struct lg4ff_wheel *wheel,
+ const struct lg4ff_multimode_wheel 
*mmode_wheel,
+ const u16 real_product_id)
+{
+   u32 alternate_modes = 0;
+   const char *real_tag = NULL;
+   const char *real_name = NULL;
+
+   if (mmode_wheel) {
+   alternate_modes = mmode_wheel->alternate_modes;
+   real_tag = mmode_wheel->real_tag;
+   real_name = mmode_wheel->real_name;
+   }
+
+   {
+   struct lg4ff_wheel_data t_wdata =  { .product_id = 
wheel->product_id,
+.real_product_id = 
real_product_id,
+.min_range = 
wheel->min_range,
+.max_range = 
wheel->max_range,
+.set_range = 
wheel->set_range,
+.alternate_modes = 
alternate_modes,
+.real_tag = real_tag,
+.real_name = real_name };
+
+   memcpy(wdata, &t_wdata, sizeof(t_wdata));
+   }
+}
+
 static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect 
*effect)
 {
struct hid_device *hid = input_get_drvdata(dev);
@@ -1101,6 +1129,7 @@ int lg4ff_init(struct hid_device *hid)
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
const struct usb_device_descriptor *udesc = 
&(hid_to_usb_dev(hid)->descriptor);
const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice);
+   const struct lg4ff_multimode_wheel *mmode_wheel = NULL;
struct lg4ff_device_entry *entry;
struct lg_drv_data *drv_data;
int error, i, j;
@@ -1174,17 +1203,12 @@ int lg4ff_init(struct hid_device *hid)
if (error)
goto err_init;
 
-   entry->wdata.product_id = lg4ff_devices[i].product_id;
-   entry->wdata.real_product_id = real_product_id;
-   entry->wdata.min_range = lg4ff_devices[i].min_range;
-   entry->wdata.max_range = lg4ff_devices[i].max_range;
-   entry->wdata.set_range = lg4ff_devices[i].set_range;
+   /* Initialize device properties */
if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) {
BUG_ON(mmode_idx == -1);
-   entry->wdata.alternate_modes = 
lg4ff_multimode_wheels[mmode_idx].alternate_modes;
-   entry->wdata.real_tag = 
lg4ff_multimode_wheels[mmode_idx].real_tag;
-   entry->wdata.real_name = 
lg4ff_multimode_wheels[mmode_idx].real_name;
+   mmode_wheel = &lg4ff_multimode_wheels[mmode_idx];
}
+   lg4ff_init_wheel_data(&entry->wdata, &lg4ff_devices[i], mmode_wheel, 
real_product_id);
 
/* Check if autocentering is available and
 * set the centering force to zero by default */
-- 
2.3.3

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


[PATCH 07/12] HID: hid-lg4ff: Protect concurrent access to the output HID report values with a spinlock.

2015-03-21 Thread Michal Malý
Since all functions that need to send some data to the device they
manage share the same HID report some synchronization is needed to
prevent sending bogus data to the device.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg.c|   4 +-
 drivers/hid/hid-lg4ff.c | 293 ++--
 2 files changed, 213 insertions(+), 84 deletions(-)

diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index c797781..c3981da 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -734,8 +734,8 @@ static void lg_remove(struct hid_device *hdev)
struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
if (drv_data->quirks & LG_FF4)
lg4ff_deinit(hdev);
-
-   hid_hw_stop(hdev);
+   else
+   hid_hw_stop(hdev);
kfree(drv_data);
 }
 
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index a2f47ee..0bbdeea 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -71,7 +71,7 @@
 static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
 static void lg4ff_set_range_g25(struct hid_device *hid, u16 range);
 
-struct lg4ff_device_entry {
+struct lg4ff_wheel_data {
u32 product_id;
u16 range;
u16 min_range;
@@ -84,9 +84,15 @@ struct lg4ff_device_entry {
const char *real_tag;
const char *real_name;
u16 real_product_id;
+
void (*set_range)(struct hid_device *hid, u16 range);
 };
 
+struct lg4ff_device_entry {
+   spinlock_t report_lock;
+   struct lg4ff_wheel_data wdata;
+};
+
 static const signed short lg4ff_wheel_effects[] = {
FF_CONSTANT,
FF_AUTOCENTER,
@@ -278,11 +284,11 @@ int lg4ff_adjust_input_event(struct hid_device *hid, 
struct hid_field *field,
return 0;
}
 
-   switch (entry->product_id) {
+   switch (entry->wdata.product_id) {
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
switch (usage->code) {
case ABS_X:
-   new_value = lg4ff_adjust_dfp_x_axis(value, 
entry->range);
+   new_value = lg4ff_adjust_dfp_x_axis(value, 
entry->wdata.range);
input_event(field->hidinput->input, usage->type, 
usage->code, new_value);
return 1;
default:
@@ -298,8 +304,23 @@ static int lg4ff_play(struct input_dev *dev, void *data, 
struct ff_effect *effec
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
+   struct lg4ff_device_entry *entry;
+   struct lg_drv_data *drv_data;
s32 *value = report->field[0]->value;
int x;
+   unsigned long flags;
+
+   drv_data = hid_get_drvdata(hid);
+   if (!drv_data) {
+   hid_err(hid, "Private driver data not found!\n");
+   return -EINVAL;
+   }
+
+   entry = drv_data->device_props;
+   if (!entry) {
+   hid_err(hid, "Device properties not found!\n");
+   return -EINVAL;
+   }
 
 #define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while 
(0)
 
@@ -308,6 +329,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, 
struct ff_effect *effec
x = effect->u.ramp.start_level + 0x80;  /* 0x80 is no force */
CLAMP(x);
 
+   spin_lock_irqsave(&entry->report_lock, flags);
if (x == 0x80) {
/* De-activate force in slot-1*/
value[0] = 0x13;
@@ -319,6 +341,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, 
struct ff_effect *effec
value[6] = 0x00;
 
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   spin_unlock_irqrestore(&entry->report_lock, flags);
return 0;
}
 
@@ -331,6 +354,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, 
struct ff_effect *effec
value[6] = 0x00;
 
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   spin_unlock_irqrestore(&entry->report_lock, flags);
break;
}
return 0;
@@ -343,10 +367,11 @@ static void lg4ff_set_autocenter_default(struct input_dev 
*dev, u16 magnitude)
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
-   s32 *value = report->field[0]->value;
-   u32 expand_a, expand_b;
struct lg4ff_device_entry *entry;
struct lg_drv_data *drv_data;
+   s32 *value = rep

[PATCH 03/12] HID: hid-lg4ff: (Cleanup) Replace DEVICE_ATTR_RW with DEVICE_ATTR to have all internal functions prefixed with "lg4ff_"

2015-03-21 Thread Michal Malý
All internal functions should be prefixed with just "lg4ff_". Usage of
DEVICE_ATTR_RW breaks this scheme because it expects the functions'
names to match the name of the respective sysfs entry.
This partially reverts "2f1cec3250e38609bf9252db52dbbe61603c04a7"

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg4ff.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 9a0c0e5..cec84a5 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -721,9 +721,9 @@ static ssize_t lg4ff_alternate_modes_store(struct device 
*dev, struct device_att
 }
 static DEVICE_ATTR(alternate_modes, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | 
S_IROTH, lg4ff_alternate_modes_show, lg4ff_alternate_modes_store);
 
-/* Read current range and display it in terminal */
-static ssize_t range_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+/* Export the currently set range of the wheel */
+static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute 
*attr,
+   char *buf)
 {
struct hid_device *hid = to_hid_device(dev);
struct lg4ff_device_entry *entry;
@@ -748,8 +748,8 @@ static ssize_t range_show(struct device *dev, struct 
device_attribute *attr,
 
 /* Set range to user specified value, call appropriate function
  * according to the type of the wheel */
-static ssize_t range_store(struct device *dev, struct device_attribute *attr,
-  const char *buf, size_t count)
+static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute 
*attr,
+const char *buf, size_t count)
 {
struct hid_device *hid = to_hid_device(dev);
struct lg4ff_device_entry *entry;
@@ -780,7 +780,7 @@ static ssize_t range_store(struct device *dev, struct 
device_attribute *attr,
 
return count;
 }
-static DEVICE_ATTR_RW(range);
+static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, 
lg4ff_range_show, lg4ff_range_store);
 
 static ssize_t lg4ff_real_id_show(struct device *dev, struct device_attribute 
*attr, char *buf)
 {
-- 
2.3.3

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


[PATCH 12/12] HID: hid-lg: Only one of LG_FF flags can be set for a given device.

2015-03-21 Thread Michal Malý
Reflect the mutual exclusivity of the LG_FF flags in the code.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index c3981da..f1e92bf 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -713,11 +713,11 @@ static int lg_probe(struct hid_device *hdev, const struct 
hid_device_id *id)
 
if (drv_data->quirks & LG_FF)
ret = lgff_init(hdev);
-   if (drv_data->quirks & LG_FF2)
+   else if (drv_data->quirks & LG_FF2)
ret = lg2ff_init(hdev);
-   if (drv_data->quirks & LG_FF3)
+   else if (drv_data->quirks & LG_FF3)
ret = lg3ff_init(hdev);
-   if (drv_data->quirks & LG_FF4)
+   else if (drv_data->quirks & LG_FF4)
ret = lg4ff_init(hdev);
 
if (ret)
-- 
2.3.3

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


[PATCH 11/12] HID: hid-lg4ff: Update respective sysfs interface documentation

2015-03-21 Thread Michal Malý
- Refer to the sysfs interface for "range" using "/sys/bus/..."
- Update contact email address

Signed-off-by: Michal Malý 
---
 Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff 
b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
index b3f6a2a..db197a8 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
+++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
@@ -1,7 +1,7 @@
-What:  /sys/module/hid_logitech/drivers/hid:logitech//range.
+What:  /sys/bus/hid/drivers/logitech//range
 Date:  July 2011
 KernelVersion: 3.2
-Contact:   Michal Malý 
+Contact:   Michal Malý 
 Description:   Display minimum, maximum and current range of the steering
wheel. Writing a value within min and max boundaries sets the
range of the wheel.
@@ -9,7 +9,7 @@ Description:Display minimum, maximum and current range of 
the steering
 What:  /sys/bus/hid/drivers/logitech//alternate_modes
 Date:  Feb 2015
 KernelVersion: 4.1
-Contact:   Michal Malý 
+Contact:   Michal Malý 
 Description:   Displays a set of alternate modes supported by a wheel. Each
mode is listed as follows:
  Tag: Mode Name
@@ -45,7 +45,7 @@ Description:  Displays a set of alternate modes supported by 
a wheel. Each
 What:  /sys/bus/hid/drivers/logitech//real_id
 Date:  Feb 2015
 KernelVersion: 4.1
-Contact:   Michal Malý 
+Contact:   Michal Malý 
 Description:   Displays the real model of the wheel regardless of any
alternate mode the wheel might be switched to.
It is a read-only value.
-- 
2.3.3

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


[PATCH 04/12] HID: hid-lg4ff: (Cleanup) Remove unused variable from the "lg4ff_device_entry" struct.

2015-03-21 Thread Michal Malý
This is a leftover from times where hid_get|set_drvdata() was not
available to hid-lg4ff so it had to keep track of the devices it managed
by itself.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg4ff.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index cec84a5..d1d5d45 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -84,7 +84,6 @@ struct lg4ff_device_entry {
const char *real_tag;
const char *real_name;
u16 real_product_id;
-   struct list_head list;
void (*set_range)(struct hid_device *hid, u16 range);
 };
 
-- 
2.3.3

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


[PATCH] HID: hid-lg4ff: Fix "undefined reference" build issue with CONFIG_USB disabled.

2015-02-18 Thread Michal Malý
Fix "undefined reference" build issue with CONFIG_USB disabled.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg4ff.c | 17 +
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 854982b..1232210 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -569,19 +569,20 @@ static const struct lg4ff_compat_mode_switch 
*lg4ff_get_mode_switch_command(cons
 
 static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const 
struct lg4ff_compat_mode_switch *s)
 {
-   struct usb_device *usbdev = hid_to_usb_dev(hid);
-   struct usbhid_device *usbhid = hid->driver_data;
+   struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
+   struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
+   __s32 *value = report->field[0]->value;
u8 i;
 
for (i = 0; i < s->cmd_count; i++) {
-   int xferd, ret;
-   u8 data[7];
+   u8 j;
 
-   memcpy(data, s->cmd + (7*i), 7);
-   ret = usb_interrupt_msg(usbdev, usbhid->urbout->pipe, data, 7, 
&xferd, USB_CTRL_SET_TIMEOUT);
-   if (ret)
-   return ret;
+   for (j = 0; j < 7; j++)
+   value[j] = s->cmd[j + (7*i)];
+
+   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
+   hid_hw_wait(hid);
return 0;
 }
 
-- 
2.3.0

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


[PATCH v3 2/4] HID: hid-lg4ff: Display the real wheel model and supported alternate modes through sysfs. This applies only to multimode wheels.

2015-02-18 Thread Michal Malý
Display the real wheel model and supported alternate modes through sysfs. This
applies only to multimode wheels.

Signed-off-by: Michal Malý 
---
 v2: Document the sysfs interface

 .../ABI/testing/sysfs-driver-hid-logitech-lg4ff|  20 ++
 drivers/hid/hid-lg4ff.c| 205 -
 2 files changed, 218 insertions(+), 7 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff 
b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
index 167d903..60f24a1 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
+++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
@@ -5,3 +5,23 @@ Contact:   Michal Malý 
 Description:   Display minimum, maximum and current range of the steering
wheel. Writing a value within min and max boundaries sets the
range of the wheel.
+
+What:  /sys/bus/hid/drivers/logitech//alternate_modes
+Date:  Feb 2015
+KernelVersion: 4.1
+Contact:   Michal Malý 
+Description:   Displays a set of alternate modes supported by a wheel. Each
+   mode is listed as follows:
+ Tag: Mode Name
+   Currently active mode is marked with an asterisk. List also
+   contains an abstract item "native" which always denotes the
+   native mode of the wheel.
+
+What:  /sys/bus/hid/drivers/logitech//real_id
+Date:  Feb 2015
+KernelVersion: 4.1
+Contact:       Michal Malý 
+Description:   Displays the real model of the wheel regardless of any
+   alternate mode the wheel might be switched to.
+   It is a read-only value.
+   This entry is not created for devices that have only one mode.
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 190c5e3..a64a35e 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -34,10 +34,36 @@
 
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
-#define LG4FF_MMODE_DONE 0
+#define LG4FF_MMODE_IS_MULTIMODE 0
 #define LG4FF_MMODE_SWITCHED 1
 #define LG4FF_MMODE_NOT_MULTIMODE 2
 
+#define LG4FF_MODE_NATIVE_IDX 0
+#define LG4FF_MODE_DFEX_IDX 1
+#define LG4FF_MODE_DFP_IDX 2
+#define LG4FF_MODE_G25_IDX 3
+#define LG4FF_MODE_DFGT_IDX 4
+#define LG4FF_MODE_G27_IDX 5
+#define LG4FF_MODE_MAX_IDX 6
+
+#define LG4FF_MODE_NATIVE BIT(LG4FF_MODE_NATIVE_IDX)
+#define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_IDX)
+#define LG4FF_MODE_DFP BIT(LG4FF_MODE_DFP_IDX)
+#define LG4FF_MODE_G25 BIT(LG4FF_MODE_G25_IDX)
+#define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX)
+#define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_IDX)
+
+#define LG4FF_DFEX_TAG "DF-EX"
+#define LG4FF_DFEX_NAME "Driving Force / Formula EX"
+#define LG4FF_DFP_TAG "DFP"
+#define LG4FF_DFP_NAME "Driving Force Pro"
+#define LG4FF_G25_TAG "G25"
+#define LG4FF_G25_NAME "G25 Racing Wheel"
+#define LG4FF_G27_TAG "G27"
+#define LG4FF_G27_NAME "G27 Racing Wheel"
+#define LG4FF_DFGT_TAG "DFGT"
+#define LG4FF_DFGT_NAME "Driving Force GT"
+
 #define LG4FF_FFEX_REV_MAJ 0x21
 #define LG4FF_FFEX_REV_MIN 0x00
 
@@ -53,6 +79,10 @@ struct lg4ff_device_entry {
__u8  led_state;
struct led_classdev *led[5];
 #endif
+   u32 alternate_modes;
+   const char *real_tag;
+   const char *real_name;
+   u16 real_product_id;
struct list_head list;
void (*set_range)(struct hid_device *hid, u16 range);
 };
@@ -87,6 +117,19 @@ struct lg4ff_wheel_ident_checklist {
const struct lg4ff_wheel_ident_info *models[];
 };
 
+struct lg4ff_multimode_wheel {
+   const u16 product_id;
+   const u32 alternate_modes;
+   const char *real_tag;
+   const char *real_name;
+};
+
+struct lg4ff_alternate_mode {
+   const u16 product_id;
+   const char *tag;
+   const char *name;
+};
+
 static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WHEEL,   lg4ff_wheel_effects, 40, 270, 
NULL},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL,  lg4ff_wheel_effects, 40, 270, 
NULL},
@@ -98,6 +141,30 @@ static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WII_WHEEL,   lg4ff_wheel_effects, 40, 270, NULL}
 };
 
+static const struct lg4ff_multimode_wheel lg4ff_multimode_wheels[] = {
+   {USB_DEVICE_ID_LOGITECH_DFP_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+LG4FF_DFP_TAG, LG4FF_DFP_NAME},
+   {USB_DEVICE_ID_LOGITECH_G25_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+LG4FF_G25_TAG, LG4FF_G25_NAME},
+   {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+LG4FF_DFGT_TAG, LG4FF_DFGT_NAME},
+   {USB_DEVICE_ID_LOGITECH_G27_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MOD

[PATCH v3 4/4] HID: hid-lg4ff: Allow switching of Logitech gaming wheels between available compatibility modes through sysfs. This only applies to multimode wheels.

2015-02-18 Thread Michal Malý
Allow switching of Logitech gaming wheels between available compatibility modes
through sysfs. This only applies to multimode wheels.

Signed-off-by: Michal Malý 
---
 v2: Fix a misleading error message regarding unsupported wheel mode

 .../ABI/testing/sysfs-driver-hid-logitech-lg4ff|  27 ++-
 drivers/hid/hid-lg4ff.c| 204 ++---
 2 files changed, 201 insertions(+), 30 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff 
b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
index 60f24a1..b3f6a2a 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
+++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
@@ -15,7 +15,32 @@ Description: Displays a set of alternate modes supported by 
a wheel. Each
  Tag: Mode Name
Currently active mode is marked with an asterisk. List also
contains an abstract item "native" which always denotes the
-   native mode of the wheel.
+   native mode of the wheel. Echoing the mode tag switches the
+   wheel into the corresponding mode. Depending on the exact model
+   of the wheel not all listed modes might always be selectable.
+   If a wheel cannot be switched into the desired mode, -EINVAL
+   is returned accompanied with an explanatory message in the
+   kernel log.
+   This entry is not created for devices that have only one mode.
+
+   Currently supported mode switches:
+   Driving Force Pro:
+ DF-EX --> DFP
+
+   G25:
+ DF-EX --> DFP --> G25
+
+   G27:
+ DF-EX <*> DFP <-> G25 <-> G27
+ DF-EX <*> G25 <-> G27
+ DF-EX <*> G27
+
+   DFGT:
+ DF-EX <*> DFP <-> DFGT
+ DF-EX <*> DFGT
+
+   * hid_logitech module must be loaded with lg4ff_no_autoswitch=1
+ parameter set in order for the switch to DF-EX mode to work.
 
 What:  /sys/bus/hid/drivers/logitech//real_id
 Date:  Feb 2015
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index dd30772..854982b 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -201,26 +201,47 @@ static const struct lg4ff_wheel_ident_checklist 
lg4ff_main_checklist = {
 };
 
 /* Compatibility mode switching commands */
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfp = {
-   1,
-   {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+/* EXT_CMD9 - Understood by G27 and DFGT */
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfex = {
+   2,
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to DF-EX 
with detach */
 };
 
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfgt = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfp = {
2,
-   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
-0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x01, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to DFP 
with detach */
 };
 
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g25 = {
-   1,
-   {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g25 = {
+   2,
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x02, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to G25 
with detach */
 };
 
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g27 = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfgt = {
2,
-   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
-0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to DFGT 
with detach */
+};
+
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g27 = {
+   2,
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to G27 
with detach */
+};
+
+/* EXT_CMD1 - Understood by DFP, G25, G27 and DFGT */
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = {
+   1,
+   {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+/* EXT_CMD16 - U

[PATCH v3 1/4] HID: hid-lg4ff: Identify Logitech gaming wheels in compatibility modes accordingly to Logitech specifications

2015-02-18 Thread Michal Malý
Identify Logitech gaming wheels in compatibility modes accordingly to Logitech
specifications.

Logitech specification contains a general method of identifying various
models of their gaming wheels while they are in "compatibility" mode.
This patch implements the method instead of checking against known
values of bcdDevice. Handling of the mode switch upon initialization is
also adjusted so that the driver does not have to go through the entire
initialization routine because the wheels are set to perform a USB
detach before they reappear in "native" mode.

Signed-off-by: Michal Malý 
---
 v3: Mark "lg4ff_identify_multimode_wheel" and "lg4ff_handle_multimode_wheel"
 functions static.

 drivers/hid/hid-lg4ff.c | 266 ++--
 1 file changed, 190 insertions(+), 76 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index db0dd9b..190c5e3 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -32,21 +32,15 @@
 #include "hid-lg.h"
 #include "hid-ids.h"
 
-#define DFGT_REV_MAJ 0x13
-#define DFGT_REV_MIN 0x22
-#define DFGT2_REV_MIN 0x26
-#define DFP_REV_MAJ 0x11
-#define DFP_REV_MIN 0x06
-#define FFEX_REV_MAJ 0x21
-#define FFEX_REV_MIN 0x00
-#define G25_REV_MAJ 0x12
-#define G25_REV_MIN 0x22
-#define G27_REV_MAJ 0x12
-#define G27_REV_MIN 0x38
-#define G27_2_REV_MIN 0x39
-
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
+#define LG4FF_MMODE_DONE 0
+#define LG4FF_MMODE_SWITCHED 1
+#define LG4FF_MMODE_NOT_MULTIMODE 2
+
+#define LG4FF_FFEX_REV_MAJ 0x21
+#define LG4FF_FFEX_REV_MIN 0x00
+
 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
 static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
 
@@ -77,6 +71,22 @@ struct lg4ff_wheel {
void (*set_range)(struct hid_device *hid, u16 range);
 };
 
+struct lg4ff_compat_mode_switch {
+   const __u8 cmd_count;   /* Number of commands to send */
+   const __u8 cmd[];
+};
+
+struct lg4ff_wheel_ident_info {
+   const u16 mask;
+   const u16 result;
+   const u16 real_product_id;
+};
+
+struct lg4ff_wheel_ident_checklist {
+   const u32 count;
+   const struct lg4ff_wheel_ident_info *models[];
+};
+
 static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WHEEL,   lg4ff_wheel_effects, 40, 270, 
NULL},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL,  lg4ff_wheel_effects, 40, 270, 
NULL},
@@ -88,48 +98,63 @@ static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WII_WHEEL,   lg4ff_wheel_effects, 40, 270, NULL}
 };
 
-struct lg4ff_native_cmd {
-   const __u8 cmd_num; /* Number of commands to send */
-   const __u8 cmd[];
+/* Multimode wheel identificators */
+static const struct lg4ff_wheel_ident_info lg4ff_dfp_ident_info = {
+   0xf000,
+   0x1000,
+   USB_DEVICE_ID_LOGITECH_DFP_WHEEL
+};
+
+static const struct lg4ff_wheel_ident_info lg4ff_g25_ident_info = {
+   0xff00,
+   0x1200,
+   USB_DEVICE_ID_LOGITECH_G25_WHEEL
+};
+
+static const struct lg4ff_wheel_ident_info lg4ff_g27_ident_info = {
+   0xfff0,
+   0x1230,
+   USB_DEVICE_ID_LOGITECH_G27_WHEEL
 };
 
-struct lg4ff_usb_revision {
-   const __u16 rev_maj;
-   const __u16 rev_min;
-   const struct lg4ff_native_cmd *command;
+static const struct lg4ff_wheel_ident_info lg4ff_dfgt_ident_info = {
+   0xff00,
+   0x1300,
+   USB_DEVICE_ID_LOGITECH_DFGT_WHEEL
 };
 
-static const struct lg4ff_native_cmd native_dfp = {
+/* Multimode wheel identification checklists */
+static const struct lg4ff_wheel_ident_checklist lg4ff_main_checklist = {
+   4,
+   {&lg4ff_dfgt_ident_info,
+&lg4ff_g27_ident_info,
+&lg4ff_g25_ident_info,
+&lg4ff_dfp_ident_info}
+};
+
+/* Compatibility mode switching commands */
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfp = {
1,
{0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-static const struct lg4ff_native_cmd native_dfgt = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfgt = {
2,
{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
 0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
 };
 
-static const struct lg4ff_native_cmd native_g25 = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g25 = {
1,
{0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-static const struct lg4ff_native_cmd native_g27 = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g27 = {
2,
{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
 };
 
-static const struct lg4ff_usb_revision lg4ff_revs[] = {
-   {DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt}, /* Drivin

[PATCH v3 0/4] HID: hid-lg4ff: Improve handling of Logitech multimode wheels

2015-02-18 Thread Michal Malý
This patch series improves handling of various Logitech gaming wheels and
allows switching between various compatibility modes which might be useful
to improve compatibility with very old games and testing purposes.

Signed-off-by: Michal Malý 

v3: - Marked all internal functions static
- Moved function and external variable declarations to hid-lg4ff.h

v2: - Rebased against latest linux-next
- Document the newly introduced sysfs interfaces in appropriate commits
- Assume that we are targeting kernel version 4.1
- Fix a misleading error message regarding unsupported wheel mode

Michal Malý (4):
  Identify Logitech gaming wheels in compatibility modes accordingly to
Logitech specifications
  Display the real wheel model and supported alternate modes through
sysfs. This applies only to multimode wheels.
  Introduce a module parameter to disable automatic switch of Logitech
gaming wheels from compatibility to native mode. This only applies
to multimode wheels.
  Allow switching of Logitech gaming wheels between available
compatibility modes through sysfs. This only applies to multimode
wheels.

 .../ABI/testing/sysfs-driver-hid-logitech-lg4ff|  45 ++
 drivers/hid/hid-lg.c   |   7 +
 drivers/hid/hid-lg.h   |  12 -
 drivers/hid/hid-lg4ff.c| 605 ++---
 drivers/hid/hid-lg4ff.h|  18 +
 5 files changed, 599 insertions(+), 88 deletions(-)
 create mode 100644 drivers/hid/hid-lg4ff.h

-- 
2.3.0

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


[PATCH v3 3/4] HID: hid-lg4ff: Introduce a module parameter to disable automatic switch of Logitech gaming wheels from compatibility to native mode. This only applies to multimode wheels.

2015-02-18 Thread Michal Malý
Introduce a module parameter to disable automatic switch of Logitech gaming
wheels from compatibility to native mode. This only applies to multimode wheels.

Signed-off-by: Michal Malý 
---
 v3: - Share the module parameter through header file.
 - Create a new "hid-lg4ff.h" header file containing stuff specific to
   hid-lg4ff submodule.
 
 drivers/hid/hid-lg.c|  7 +++
 drivers/hid/hid-lg.h| 12 
 drivers/hid/hid-lg4ff.c |  4 +++-
 drivers/hid/hid-lg4ff.h | 18 ++
 4 files changed, 28 insertions(+), 13 deletions(-)
 create mode 100644 drivers/hid/hid-lg4ff.h

diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index f91ff14..b86c18e 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -27,6 +27,7 @@
 #include "usbhid/usbhid.h"
 #include "hid-ids.h"
 #include "hid-lg.h"
+#include "hid-lg4ff.h"
 
 #define LG_RDESC   0x001
 #define LG_BAD_RELATIVE_KEYS   0x002
@@ -818,4 +819,10 @@ static struct hid_driver lg_driver = {
 };
 module_hid_driver(lg_driver);
 
+#ifdef CONFIG_LOGIWHEELS_FF
+int lg4ff_no_autoswitch = 0;
+module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
+MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their 
native mode automatically");
+#endif
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index 142ce3f..10dd8f0 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -24,16 +24,4 @@ int lg3ff_init(struct hid_device *hdev);
 static inline int lg3ff_init(struct hid_device *hdev) { return -1; }
 #endif
 
-#ifdef CONFIG_LOGIWHEELS_FF
-int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
-struct hid_usage *usage, __s32 value, struct 
lg_drv_data *drv_data);
-int lg4ff_init(struct hid_device *hdev);
-int lg4ff_deinit(struct hid_device *hdev);
-#else
-static inline int lg4ff_adjust_input_event(struct hid_device *hid, struct 
hid_field *field,
-  struct hid_usage *usage, __s32 
value, struct lg_drv_data *drv_data) { return 0; }
-static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
-static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; }
-#endif
-
 #endif
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index a64a35e..dd30772 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -30,6 +30,7 @@
 
 #include "usbhid/usbhid.h"
 #include "hid-lg.h"
+#include "hid-lg4ff.h"
 #include "hid-ids.h"
 
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
@@ -803,7 +804,8 @@ static int lg4ff_handle_multimode_wheel(struct hid_device 
*hid, u16 *real_produc
/* Switch from "Driving Force" mode to native mode automatically.
 * Otherwise keep the wheel in its current mode */
if (reported_product_id == USB_DEVICE_ID_LOGITECH_WHEEL &&
-   reported_product_id != *real_product_id) {
+   reported_product_id != *real_product_id &&
+   !lg4ff_no_autoswitch) {
const struct lg4ff_compat_mode_switch *s;
 
switch (*real_product_id) {
diff --git a/drivers/hid/hid-lg4ff.h b/drivers/hid/hid-lg4ff.h
new file mode 100644
index 000..5b6a508
--- /dev/null
+++ b/drivers/hid/hid-lg4ff.h
@@ -0,0 +1,18 @@
+#ifndef __HID_LG4FF_H
+#define __HID_LG4FF_H
+
+#ifdef CONFIG_LOGIWHEELS_FF
+extern int lg4ff_no_autoswitch; /* From hid-lg.c */
+
+int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
+struct hid_usage *usage, __s32 value, struct 
lg_drv_data *drv_data);
+int lg4ff_init(struct hid_device *hdev);
+int lg4ff_deinit(struct hid_device *hdev);
+#else
+static inline int lg4ff_adjust_input_event(struct hid_device *hid, struct 
hid_field *field,
+  struct hid_usage *usage, __s32 
value, struct lg_drv_data *drv_data) { return 0; }
+static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
+static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; }
+#endif
+
+#endif
-- 
2.3.0

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


[PATCH v2 2/4] HID: hid-lg4ff: Display the real wheel model and supported alternate modes through sysfs. This applies only to multimode wheels.

2015-02-14 Thread Michal Malý
Display the real wheel model and supported alternate modes through sysfs. This
applies only to multimode wheels.

Signed-off-by: Michal Malý 
---
 v2: Document the sysfs interface

 .../ABI/testing/sysfs-driver-hid-logitech-lg4ff|  20 ++
 drivers/hid/hid-lg4ff.c| 205 -
 2 files changed, 218 insertions(+), 7 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff 
b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
index 167d903..3204440 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
+++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
@@ -5,3 +5,23 @@ Contact:   Michal Malý 
 Description:   Display minimum, maximum and current range of the steering
wheel. Writing a value within min and max boundaries sets the
range of the wheel.
+
+What:  /sys/bus/hid/drivers/logitech//alternate_modes
+Date:  Feb 2015
+KernelVersion: 4.1
+Contact:   Michal Malý 
+Description:   Displays a set of alternate modes supported by a wheel. Each
+   mode is listed as follows:
+ Tag: Mode Name
+   Currently active mode is marked with an asterisk. List also
+   contains an abstract item "native" which always denotes the
+   native mode of the wheel. 
+
+What:  /sys/bus/hid/drivers/logitech//real_id
+Date:  Feb 2015
+KernelVersion: 4.1
+Contact:       Michal Malý 
+Description:   Displays the real model of the wheel regardless of any
+   alternate mode the wheel might be switched to.
+   It is a read-only value.
+   This entry is not created for devices that have only one mode.
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 72a4381..3401f17 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -34,10 +34,36 @@
 
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
-#define LG4FF_MMODE_DONE 0
+#define LG4FF_MMODE_IS_MULTIMODE 0
 #define LG4FF_MMODE_SWITCHED 1
 #define LG4FF_MMODE_NOT_MULTIMODE 2
 
+#define LG4FF_MODE_NATIVE_IDX 0
+#define LG4FF_MODE_DFEX_IDX 1
+#define LG4FF_MODE_DFP_IDX 2
+#define LG4FF_MODE_G25_IDX 3
+#define LG4FF_MODE_DFGT_IDX 4
+#define LG4FF_MODE_G27_IDX 5
+#define LG4FF_MODE_MAX_IDX 6
+
+#define LG4FF_MODE_NATIVE BIT(LG4FF_MODE_NATIVE_IDX)
+#define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_IDX)
+#define LG4FF_MODE_DFP BIT(LG4FF_MODE_DFP_IDX)
+#define LG4FF_MODE_G25 BIT(LG4FF_MODE_G25_IDX)
+#define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX)
+#define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_IDX)
+
+#define LG4FF_DFEX_TAG "DF-EX"
+#define LG4FF_DFEX_NAME "Driving Force / Formula EX"
+#define LG4FF_DFP_TAG "DFP"
+#define LG4FF_DFP_NAME "Driving Force Pro"
+#define LG4FF_G25_TAG "G25"
+#define LG4FF_G25_NAME "G25 Racing Wheel"
+#define LG4FF_G27_TAG "G27"
+#define LG4FF_G27_NAME "G27 Racing Wheel"
+#define LG4FF_DFGT_TAG "DFGT"
+#define LG4FF_DFGT_NAME "Driving Force GT"
+
 #define LG4FF_FFEX_REV_MAJ 0x21
 #define LG4FF_FFEX_REV_MIN 0x00
 
@@ -53,6 +79,10 @@ struct lg4ff_device_entry {
__u8  led_state;
struct led_classdev *led[5];
 #endif
+   u32 alternate_modes;
+   const char *real_tag;
+   const char *real_name;
+   u16 real_product_id;
struct list_head list;
void (*set_range)(struct hid_device *hid, u16 range);
 };
@@ -87,6 +117,19 @@ struct lg4ff_wheel_ident_checklist {
const struct lg4ff_wheel_ident_info *models[];
 };
 
+struct lg4ff_multimode_wheel {
+   const u16 product_id;
+   const u32 alternate_modes;
+   const char *real_tag;
+   const char *real_name;
+};
+
+struct lg4ff_alternate_mode {
+   const u16 product_id;
+   const char *tag;
+   const char *name;
+};
+
 static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WHEEL,   lg4ff_wheel_effects, 40, 270, 
NULL},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL,  lg4ff_wheel_effects, 40, 270, 
NULL},
@@ -98,6 +141,30 @@ static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WII_WHEEL,   lg4ff_wheel_effects, 40, 270, NULL}
 };
 
+static const struct lg4ff_multimode_wheel lg4ff_multimode_wheels[] = {
+   {USB_DEVICE_ID_LOGITECH_DFP_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+LG4FF_DFP_TAG, LG4FF_DFP_NAME},
+   {USB_DEVICE_ID_LOGITECH_G25_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+LG4FF_G25_TAG, LG4FF_G25_NAME},
+   {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+LG4FF_DFGT_TAG, LG4FF_DFGT_NAME},
+   {USB_DEVICE_ID_LOGITECH_G27_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MOD

[PATCH v2 1/4] HID: hid-lg4ff: Identify Logitech gaming wheels in compatibility modes accordingly to Logitech specifications

2015-02-14 Thread Michal Malý
Logitech specification contains a general method of identifying various
models of their gaming wheels while they are in "compatibility" mode.
This patch implements the method instead of checking against known
values of bcdDevice. Handling of the mode switch upon initialization is
also adjusted so that the driver does not have to go through the entire
initialization routine because the wheels are set to perform a USB
detach before they reappear in "native" mode.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg4ff.c | 266 ++--
 1 file changed, 190 insertions(+), 76 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index db0dd9b..72a4381 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -32,21 +32,15 @@
 #include "hid-lg.h"
 #include "hid-ids.h"
 
-#define DFGT_REV_MAJ 0x13
-#define DFGT_REV_MIN 0x22
-#define DFGT2_REV_MIN 0x26
-#define DFP_REV_MAJ 0x11
-#define DFP_REV_MIN 0x06
-#define FFEX_REV_MAJ 0x21
-#define FFEX_REV_MIN 0x00
-#define G25_REV_MAJ 0x12
-#define G25_REV_MIN 0x22
-#define G27_REV_MAJ 0x12
-#define G27_REV_MIN 0x38
-#define G27_2_REV_MIN 0x39
-
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
+#define LG4FF_MMODE_DONE 0
+#define LG4FF_MMODE_SWITCHED 1
+#define LG4FF_MMODE_NOT_MULTIMODE 2
+
+#define LG4FF_FFEX_REV_MAJ 0x21
+#define LG4FF_FFEX_REV_MIN 0x00
+
 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
 static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
 
@@ -77,6 +71,22 @@ struct lg4ff_wheel {
void (*set_range)(struct hid_device *hid, u16 range);
 };
 
+struct lg4ff_compat_mode_switch {
+   const __u8 cmd_count;   /* Number of commands to send */
+   const __u8 cmd[];
+};
+
+struct lg4ff_wheel_ident_info {
+   const u16 mask;
+   const u16 result;
+   const u16 real_product_id;
+};
+
+struct lg4ff_wheel_ident_checklist {
+   const u32 count;
+   const struct lg4ff_wheel_ident_info *models[];
+};
+
 static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WHEEL,   lg4ff_wheel_effects, 40, 270, 
NULL},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL,  lg4ff_wheel_effects, 40, 270, 
NULL},
@@ -88,48 +98,63 @@ static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WII_WHEEL,   lg4ff_wheel_effects, 40, 270, NULL}
 };
 
-struct lg4ff_native_cmd {
-   const __u8 cmd_num; /* Number of commands to send */
-   const __u8 cmd[];
+/* Multimode wheel identificators */
+static const struct lg4ff_wheel_ident_info lg4ff_dfp_ident_info = {
+   0xf000,
+   0x1000,
+   USB_DEVICE_ID_LOGITECH_DFP_WHEEL
+};
+
+static const struct lg4ff_wheel_ident_info lg4ff_g25_ident_info = {
+   0xff00,
+   0x1200,
+   USB_DEVICE_ID_LOGITECH_G25_WHEEL
+};
+
+static const struct lg4ff_wheel_ident_info lg4ff_g27_ident_info = {
+   0xfff0,
+   0x1230,
+   USB_DEVICE_ID_LOGITECH_G27_WHEEL
 };
 
-struct lg4ff_usb_revision {
-   const __u16 rev_maj;
-   const __u16 rev_min;
-   const struct lg4ff_native_cmd *command;
+static const struct lg4ff_wheel_ident_info lg4ff_dfgt_ident_info = {
+   0xff00,
+   0x1300,
+   USB_DEVICE_ID_LOGITECH_DFGT_WHEEL
 };
 
-static const struct lg4ff_native_cmd native_dfp = {
+/* Multimode wheel identification checklists */
+static const struct lg4ff_wheel_ident_checklist lg4ff_main_checklist = {
+   4,
+   {&lg4ff_dfgt_ident_info,
+&lg4ff_g27_ident_info,
+&lg4ff_g25_ident_info,
+&lg4ff_dfp_ident_info}
+};
+
+/* Compatibility mode switching commands */
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfp = {
1,
{0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-static const struct lg4ff_native_cmd native_dfgt = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfgt = {
2,
{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
 0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
 };
 
-static const struct lg4ff_native_cmd native_g25 = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g25 = {
1,
{0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-static const struct lg4ff_native_cmd native_g27 = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g27 = {
2,
{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
 };
 
-static const struct lg4ff_usb_revision lg4ff_revs[] = {
-   {DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt}, /* Driving Force GT */
-   {DFGT_REV_MAJ, DFGT2_REV_MIN, &native_dfgt},/* Driving Force GT v2 
*/
-   {DFP_REV_MAJ,  DFP_REV_MIN,  &native_dfp},  /* Driving Force Pro */
-   {G25_REV_MAJ,  G25_REV_M

[PATCH v2 0/4] HID: hid-lg4ff: Improve handling of Logitech multimode gaming wheels

2015-02-14 Thread Michal Malý
This patch series improves handling of various Logitech gaming wheels and
allows switching between various compatibility modes which might be useful
to improve compatibility with very old games and testing purposes.

Signed-off-by: Michal Malý 

v2: - Rebased against latest linux-next
- Document the newly introduced sysfs interfaces in appropriate commits
- Assume that we are targeting kernel version 4.1
- Fix a misleading error message regarding unsupported wheel mode

Michal Malý (4):
  Identify Logitech gaming wheels in compatibility modes accordingly to
Logitech specifications
  Display the real wheel model and supported alternate modes through
sysfs. This applies only to multimode wheels.
  Introduce a module parameter to disable automatic switch of Logitech
gaming wheels from compatibility to native mode. This only applies
to multimode wheels.
  Allow switching of Logitech gaming wheels between available
compatibility modes through sysfs. This only applies to multimode
wheels.

 .../ABI/testing/sysfs-driver-hid-logitech-lg4ff|  45 ++
 drivers/hid/hid-lg.c   |   6 +
 drivers/hid/hid-lg4ff.c| 605 ++---
 3 files changed, 580 insertions(+), 76 deletions(-)

-- 
2.3.0

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


[PATCH v2 3/4] HID: hid-lg4ff: Introduce a module parameter to disable automatic switch of Logitech gaming wheels from compatibility to native mode. This only applies to multimode wheels.

2015-02-14 Thread Michal Malý
Introduce a module parameter to disable automatic switch of Logitech gaming
wheels from compatibility to native mode. This only applies to multimode wheels.

Signed-off-by: Michal Malý 
---
 drivers/hid/hid-lg.c| 6 ++
 drivers/hid/hid-lg4ff.c | 4 +++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index f91ff14..8dae03f 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -818,4 +818,10 @@ static struct hid_driver lg_driver = {
 };
 module_hid_driver(lg_driver);
 
+#ifdef CONFIG_LOGIWHEELS_FF
+extern int lg4ff_no_autoswitch; /* From hid-lg4ff.c */
+module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
+MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their 
native mode automatically");
+#endif
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 3401f17..e4b8cae 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -67,6 +67,7 @@
 #define LG4FF_FFEX_REV_MAJ 0x21
 #define LG4FF_FFEX_REV_MIN 0x00
 
+int lg4ff_no_autoswitch = 0;
 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
 static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
 
@@ -803,7 +804,8 @@ int lg4ff_handle_multimode_wheel(struct hid_device *hid, 
u16 *real_product_id, c
/* Switch from "Driving Force" mode to native mode automatically.
 * Otherwise keep the wheel in its current mode */
if (reported_product_id == USB_DEVICE_ID_LOGITECH_WHEEL &&
-   reported_product_id != *real_product_id) {
+   reported_product_id != *real_product_id &&
+   !lg4ff_no_autoswitch) {
const struct lg4ff_compat_mode_switch *s;
 
switch (*real_product_id) {
-- 
2.3.0

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


[PATCH v2 4/4] HID: hid-lg4ff: Allow switching of Logitech gaming wheels between available compatibility modes through sysfs. This only applies to multimode wheels.

2015-02-14 Thread Michal Malý
Allow switching of Logitech gaming wheels between available compatibility modes
through sysfs. This only applies to multimode wheels.

Signed-off-by: Michal Malý 
---
 v2: Fix a misleading error message regarding unsupported wheel mode

 .../ABI/testing/sysfs-driver-hid-logitech-lg4ff|  27 ++-
 drivers/hid/hid-lg4ff.c| 204 ++---
 2 files changed, 201 insertions(+), 30 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff 
b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
index 3204440..b3f6a2a 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
+++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
@@ -15,7 +15,32 @@ Description: Displays a set of alternate modes supported by 
a wheel. Each
  Tag: Mode Name
Currently active mode is marked with an asterisk. List also
contains an abstract item "native" which always denotes the
-   native mode of the wheel. 
+   native mode of the wheel. Echoing the mode tag switches the
+   wheel into the corresponding mode. Depending on the exact model
+   of the wheel not all listed modes might always be selectable.
+   If a wheel cannot be switched into the desired mode, -EINVAL
+   is returned accompanied with an explanatory message in the
+   kernel log.
+   This entry is not created for devices that have only one mode.
+
+   Currently supported mode switches:
+   Driving Force Pro:
+ DF-EX --> DFP
+
+   G25:
+ DF-EX --> DFP --> G25
+
+   G27:
+ DF-EX <*> DFP <-> G25 <-> G27
+ DF-EX <*> G25 <-> G27
+ DF-EX <*> G27
+
+   DFGT:
+ DF-EX <*> DFP <-> DFGT
+ DF-EX <*> DFGT
+
+   * hid_logitech module must be loaded with lg4ff_no_autoswitch=1
+ parameter set in order for the switch to DF-EX mode to work.
 
 What:  /sys/bus/hid/drivers/logitech//real_id
 Date:  Feb 2015
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index e4b8cae..1bc4020 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -201,26 +201,47 @@ static const struct lg4ff_wheel_ident_checklist 
lg4ff_main_checklist = {
 };
 
 /* Compatibility mode switching commands */
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfp = {
-   1,
-   {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+/* EXT_CMD9 - Understood by G27 and DFGT */
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfex = {
+   2,
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to DF-EX 
with detach */
 };
 
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfgt = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfp = {
2,
-   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
-0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x01, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to DFP 
with detach */
 };
 
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g25 = {
-   1,
-   {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g25 = {
+   2,
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x02, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to G25 
with detach */
 };
 
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g27 = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfgt = {
2,
-   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
-0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to DFGT 
with detach */
+};
+
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g27 = {
+   2,
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to G27 
with detach */
+};
+
+/* EXT_CMD1 - Understood by DFP, G25, G27 and DFGT */
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = {
+   1,
+   {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+/* EXT_CMD16 - U

[PATCH 2/4] HID: Display the real wheel model and supported alternate modes through sysfs. This applies only to multimode wheels.

2015-02-06 Thread Michal Malý
Display the real wheel model and supported alternate modes through sysfs. This
applies only to multimode wheels.

Signed-off-by: Michal Malý  
---
 drivers/hid/hid-lg4ff.c | 209 ++--
 1 file changed, 202 insertions(+), 7 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 3a9de73..b9c9fe6 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -34,19 +34,51 @@
 
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
-#define LG4FF_MMODE_DONE 0
+#define LG4FF_MMODE_IS_MULTIMODE 0
 #define LG4FF_MMODE_SWITCHED 1
 #define LG4FF_MMODE_NOT_MULTIMODE 2
 
+#define LG4FF_MODE_NATIVE_IDX 0
+#define LG4FF_MODE_DFEX_IDX 1
+#define LG4FF_MODE_DFP_IDX 2
+#define LG4FF_MODE_G25_IDX 3
+#define LG4FF_MODE_DFGT_IDX 4
+#define LG4FF_MODE_G27_IDX 5
+#define LG4FF_MODE_MAX_IDX 6
+
+#define LG4FF_MODE_NATIVE BIT(LG4FF_MODE_NATIVE_IDX)
+#define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_IDX)
+#define LG4FF_MODE_DFP BIT(LG4FF_MODE_DFP_IDX)
+#define LG4FF_MODE_G25 BIT(LG4FF_MODE_G25_IDX)
+#define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX)
+#define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_IDX)
+
+#define LG4FF_DFEX_TAG "DF-EX"
+#define LG4FF_DFEX_NAME "Driving Force / Formula EX"
+#define LG4FF_DFP_TAG "DFP"
+#define LG4FF_DFP_NAME "Driving Force Pro"
+#define LG4FF_G25_TAG "G25"
+#define LG4FF_G25_NAME "G25 Racing Wheel"
+#define LG4FF_G27_TAG "G27"
+#define LG4FF_G27_NAME "G27 Racing Wheel"
+#define LG4FF_DFGT_TAG "DFGT"
+#define LG4FF_DFGT_NAME "Driving Force GT"
+
 #define LG4FF_FFEX_REV_MAJ 0x21
 #define LG4FF_FFEX_REV_MIN 0x00
 
 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
 static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
+static ssize_t lg4ff_alternate_modes_show(struct device *dev, struct 
device_attribute *attr, char *buf);
+static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct 
device_attribute *attr, const char *buf, size_t count);
 static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute 
*attr, char *buf);
 static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute 
*attr, const char *buf, size_t count);
+static ssize_t lg4ff_real_id_show(struct device *dev, struct device_attribute 
*attr, char *buf);
+static ssize_t lg4ff_real_id_store(struct device *dev, struct device_attribute 
*attr, const char *buf, size_t count);
 
+static DEVICE_ATTR(alternate_modes, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | 
S_IROTH, lg4ff_alternate_modes_show, lg4ff_alternate_modes_store);
 static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IROTH, lg4ff_range_show, 
lg4ff_range_store);
+static DEVICE_ATTR(real_id, S_IRUGO, lg4ff_real_id_show, lg4ff_real_id_store);
 
 struct lg4ff_device_entry {
__u32 product_id;
@@ -57,6 +89,10 @@ struct lg4ff_device_entry {
__u8  led_state;
struct led_classdev *led[5];
 #endif
+   u32 alternate_modes;
+   const char *real_tag;
+   const char *real_name;
+   u16 real_product_id;
struct list_head list;
void (*set_range)(struct hid_device *hid, u16 range);
 };
@@ -91,6 +127,19 @@ struct lg4ff_wheel_ident_checklist {
const struct lg4ff_wheel_ident_info *models[];
 };
 
+struct lg4ff_multimode_wheel {
+   const u16 product_id;
+   const u32 alternate_modes;
+   const char *real_tag;
+   const char *real_name;
+};
+
+struct lg4ff_alternate_mode {
+   const u16 product_id;
+   const char *tag;
+   const char *name;
+};
+
 static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WHEEL,   lg4ff_wheel_effects, 40, 270, 
NULL},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL,  lg4ff_wheel_effects, 40, 270, 
NULL},
@@ -102,6 +151,30 @@ static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WII_WHEEL,   lg4ff_wheel_effects, 40, 270, NULL}
 };
 
+static const struct lg4ff_multimode_wheel lg4ff_multimode_wheels[] = {
+   {USB_DEVICE_ID_LOGITECH_DFP_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+LG4FF_DFP_TAG, LG4FF_DFP_NAME},
+   {USB_DEVICE_ID_LOGITECH_G25_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+LG4FF_G25_TAG, LG4FF_G25_NAME},
+   {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
+LG4FF_DFGT_TAG, LG4FF_DFGT_NAME},
+   {USB_DEVICE_ID_LOGITECH_G27_WHEEL,
+LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | 
LG4FF_MODE_DFEX,
+LG4FF_G27_TAG, LG4FF_G27_NAME},
+};
+
+static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = {
+   [LG4FF_MODE_NATIVE_IDX] = {0, "native", ""},
+   [LG4FF_MODE_DFEX_IDX] = {USB_DEVICE_ID_LOGITECH_WHEEL, LG4FF_DFEX_

[PATCH 1/4] HID: Identify Logitech gaming wheels in compatibility modes accordingly to Logitech specifications

2015-02-06 Thread Michal Malý
Identify Logitech gaming wheels in compatibility modes accordingly to Logitech
specifications.

Logitech specification contains a general method of identifying various
models of their gaming wheels while they are in "compatibility" mode.
This patch implements the method instead of checking against known
values of bcdDevice. Handling of the mode switch upon initialization is
also adjusted so that the driver does not have to go through the entire
initialization routine because the wheels are set to perform a USB
detach before they reappear in "native" mode.

Signed-off-by: Michal Malý  
---
 drivers/hid/hid-lg4ff.c | 266 ++--
 1 file changed, 190 insertions(+), 76 deletions(-)

diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 7835717..3a9de73 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -32,21 +32,15 @@
 #include "hid-lg.h"
 #include "hid-ids.h"
 
-#define DFGT_REV_MAJ 0x13
-#define DFGT_REV_MIN 0x22
-#define DFGT2_REV_MIN 0x26
-#define DFP_REV_MAJ 0x11
-#define DFP_REV_MIN 0x06
-#define FFEX_REV_MAJ 0x21
-#define FFEX_REV_MIN 0x00
-#define G25_REV_MAJ 0x12
-#define G25_REV_MIN 0x22
-#define G27_REV_MAJ 0x12
-#define G27_REV_MIN 0x38
-#define G27_2_REV_MIN 0x39
-
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
+#define LG4FF_MMODE_DONE 0
+#define LG4FF_MMODE_SWITCHED 1
+#define LG4FF_MMODE_NOT_MULTIMODE 2
+
+#define LG4FF_FFEX_REV_MAJ 0x21
+#define LG4FF_FFEX_REV_MIN 0x00
+
 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
 static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
 static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute 
*attr, char *buf);
@@ -81,6 +75,22 @@ struct lg4ff_wheel {
void (*set_range)(struct hid_device *hid, u16 range);
 };
 
+struct lg4ff_compat_mode_switch {
+   const __u8 cmd_count;   /* Number of commands to send */
+   const __u8 cmd[];
+};
+
+struct lg4ff_wheel_ident_info {
+   const u16 mask;
+   const u16 result;
+   const u16 real_product_id;
+};
+
+struct lg4ff_wheel_ident_checklist {
+   const u32 count;
+   const struct lg4ff_wheel_ident_info *models[];
+};
+
 static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WHEEL,   lg4ff_wheel_effects, 40, 270, 
NULL},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL,  lg4ff_wheel_effects, 40, 270, 
NULL},
@@ -92,48 +102,63 @@ static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WII_WHEEL,   lg4ff_wheel_effects, 40, 270, NULL}
 };
 
-struct lg4ff_native_cmd {
-   const __u8 cmd_num; /* Number of commands to send */
-   const __u8 cmd[];
+/* Multimode wheel identificators */
+static const struct lg4ff_wheel_ident_info lg4ff_dfp_ident_info = {
+   0xf000,
+   0x1000,
+   USB_DEVICE_ID_LOGITECH_DFP_WHEEL
+};
+
+static const struct lg4ff_wheel_ident_info lg4ff_g25_ident_info = {
+   0xff00,
+   0x1200,
+   USB_DEVICE_ID_LOGITECH_G25_WHEEL
+};
+
+static const struct lg4ff_wheel_ident_info lg4ff_g27_ident_info = {
+   0xfff0,
+   0x1230,
+   USB_DEVICE_ID_LOGITECH_G27_WHEEL
 };
 
-struct lg4ff_usb_revision {
-   const __u16 rev_maj;
-   const __u16 rev_min;
-   const struct lg4ff_native_cmd *command;
+static const struct lg4ff_wheel_ident_info lg4ff_dfgt_ident_info = {
+   0xff00,
+   0x1300,
+   USB_DEVICE_ID_LOGITECH_DFGT_WHEEL
 };
 
-static const struct lg4ff_native_cmd native_dfp = {
+/* Multimode wheel identification checklists */
+static const struct lg4ff_wheel_ident_checklist lg4ff_main_checklist = {
+   4,
+   {&lg4ff_dfgt_ident_info,
+&lg4ff_g27_ident_info,
+&lg4ff_g25_ident_info,
+&lg4ff_dfp_ident_info}
+};
+
+/* Compatibility mode switching commands */
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfp = {
1,
{0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-static const struct lg4ff_native_cmd native_dfgt = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfgt = {
2,
{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
 0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
 };
 
-static const struct lg4ff_native_cmd native_g25 = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g25 = {
1,
{0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-static const struct lg4ff_native_cmd native_g27 = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g27 = {
2,
{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
 };
 
-static const struct lg4ff_usb_revision lg4ff_revs[] = {
-   {DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt}, /* Driving Force GT */
-   {DFGT_R

[PATCH 3/4] HID: Introduce a module parameter to disable automatic switch of Logitech gaming wheels from compatibility to native mode. This only applies to multimode wheels.

2015-02-06 Thread Michal Malý
Introduce a module parameter to disable automatic switch of Logitech gaming
wheels from compatibility to native mode. This only applies to multimode wheels.

Signed-off-by: Michal Malý  
---
 drivers/hid/hid-lg.c| 6 ++
 drivers/hid/hid-lg4ff.c | 4 +++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index f91ff14..8dae03f 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -818,4 +818,10 @@ static struct hid_driver lg_driver = {
 };
 module_hid_driver(lg_driver);
 
+#ifdef CONFIG_LOGIWHEELS_FF
+extern int lg4ff_no_autoswitch; /* From hid-lg4ff.c */
+module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
+MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their 
native mode automatically");
+#endif
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index b9c9fe6..cbb000a 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -67,6 +67,7 @@
 #define LG4FF_FFEX_REV_MAJ 0x21
 #define LG4FF_FFEX_REV_MIN 0x00
 
+int lg4ff_no_autoswitch = 0;
 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
 static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
 static ssize_t lg4ff_alternate_modes_show(struct device *dev, struct 
device_attribute *attr, char *buf);
@@ -808,7 +809,8 @@ int lg4ff_handle_multimode_wheel(struct hid_device *hid, 
u16 *real_product_id, c
/* Switch from "Driving Force" mode to native mode automatically.
 * Otherwise keep the wheel in its current mode */
if (reported_product_id == USB_DEVICE_ID_LOGITECH_WHEEL &&
-   reported_product_id != *real_product_id) {
+   reported_product_id != *real_product_id &&
+   !lg4ff_no_autoswitch) {
const struct lg4ff_compat_mode_switch *s;
 
switch (*real_product_id) {
-- 
2.2.2

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


[PATCH 0/4] HID: Improve handling of multimode Logitech handling wheels

2015-02-06 Thread Michal Malý
This patch series improves handling of various Logitech gaming wheels and
allows switching between various compatibility modes which might be useful
to improve compatibility with very old games and testing purposes.

Signed-off-by: Michal Malý  

Michal Malý (4):
  Identify Logitech gaming wheels in compatibility modes accordingly to 
   Logitech specifications
  Display the real wheel model and supported alternate modes through
sysfs. This applies only to multimode wheels.
  Introduce a module parameter to disable automatic switch of Logitech  
  gaming wheels from compatibility to native mode. This only applies
to multimode wheels.
  Allow switching of Logitech gaming wheels between available
compatibility modes through sysfs. This only applies to multimode
wheels.

 .../ABI/testing/sysfs-driver-hid-logitech-lg4ff|  45 ++
 drivers/hid/hid-lg.c   |   6 +
 drivers/hid/hid-lg4ff.c| 608 ++---
 3 files changed, 583 insertions(+), 76 deletions(-)

-- 
2.2.2

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


[PATCH 4/4] HID: Allow switching of Logitech gaming wheels between available compatibility modes through sysfs. This only applies to multimode wheels.

2015-02-06 Thread Michal Malý
Allow switching of Logitech gaming wheels between available compatibility modes
through sysfs. This only applies to multimode wheels.

Signed-off-by: Michal Malý  
---
 .../ABI/testing/sysfs-driver-hid-logitech-lg4ff|  45 +
 drivers/hid/hid-lg4ff.c| 203 ++---
 2 files changed, 219 insertions(+), 29 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff 
b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
index 167d903..0dfeb6c 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
+++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff
@@ -5,3 +5,48 @@ Contact:   Michal Malý 
 Description:   Display minimum, maximum and current range of the steering
wheel. Writing a value within min and max boundaries sets the
range of the wheel.
+
+What:  /sys/bus/hid/drivers/logitech//alternate_modes
+Date:  Feb 2015
+KernelVersion: 3.21
+Contact:   Michal Malý 
+Description:   Displays a set of alternate modes supported by a wheel. Each
+   mode is listed as follows:
+ Tag: Mode Name
+   Currently active mode is marked with an asterisk. List also
+   contains an abstract item "native" which always denotes the
+   native mode of the wheel. Echoing the mode tag switches the
+   wheel into the corresponding mode. Depending on the exact model
+   of the wheel not all listed modes might always be selectable.
+   If a wheel cannot be switched into the desired mode, -EINVAL
+   is returned accompanied with an explanatory message in the
+   kernel log.
+   This entry is not created for devices that have only one mode.
+
+   Currently supported mode switches:
+   Driving Force Pro:
+ DF-EX --> DFP
+
+   G25:
+ DF-EX --> DFP --> G25
+
+   G27:
+ DF-EX <*> DFP <-> G25 <-> G27
+ DF-EX <*> G25 <-> G27
+ DF-EX <*> G27
+
+   DFGT:
+ DF-EX <*> DFP <-> DFGT
+ DF-EX <*> DFGT
+
+   * hid_logitech module must be loaded with lg4ff_no_autoswitch=1
+ parameter set in order for the switch to DF-EX mode to work.
+
+What:  /sys/bus/hid/drivers/logitech//real_id
+Date:  Feb 2015
+KernelVersion: 3.21
+Contact:   Michal Malý 
+Description:   Displays the real model of the wheel regardless of any
+   alternate mode the wheel might be switched to.
+   It is a read-only value.
+   This entry is not created for devices that have only one mode.
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index cbb000a..f1ae03a 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -211,26 +211,47 @@ static const struct lg4ff_wheel_ident_checklist 
lg4ff_main_checklist = {
 };
 
 /* Compatibility mode switching commands */
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfp = {
-   1,
-   {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+/* EXT_CMD9 - Understood by G27 and DFGT */
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfex = {
+   2,
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to DF-EX 
with detach */
 };
 
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_dfgt = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfp = {
2,
-   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
-0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x01, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to DFP 
with detach */
 };
 
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g25 = {
-   1,
-   {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g25 = {
+   2,
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x09, 0x02, 0x01, 0x00, 0x00, 0x00}  /* Switch mode to G25 
with detach */
 };
 
-static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_g27 = {
+static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_dfgt = {
2,
-   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 1st command */
-0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00}  /* 2nd command */
+   {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Revert mode upon USB 
reset */
+0xf8, 0x0

Re: PATCH hid: Implement mode switching on Logitech gaming wheels accordingly to the documentation

2014-08-12 Thread Michal Malý
On Tuesday 12 of August 2014 15:10:12 Jiri Kosina wrote:
> On Thu, 31 Jul 2014, si...@mungewell.org wrote:
> > > +#define LG4FF_MSW_MIN 0
> > > +#define LG4FF_MSW_NATIVE 0   /* Switch device to its native mode (if
> > > applicable) */
> > > +#define LG4FF_MSW_DONTSWITCH 1   /* Leave device in its current mode */
> > > +#define LG4FF_MSW_DFP 2  /* Switch device so that it emulates 
Driving
> > > Force Pro (only G25, G27, DFGT) */
> > > +#define LG4FF_MSW_G25 3  /* Switch device so that it emulates 
> > > G25 
(only
> > > G27) */
> > > +#define LG4FF_MSW_MAX 3
> > 
> > Just to let everyone know I am looking at this patch, and have emailed
> > Michal some questions on whether it covers all options for control.
> 
> Hi guys,
> 
> did you reach any kind of conclusion here?

Hi,

Simon mailed me his revised patchset which has the changes broken out into 
four separate patches and allows to switch "extended compatibility" modes on 
the fly through sysfs. I looked them over and I they seem fine to me. I 
suppose he'll submit them for review very soon.

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


PATCH hid: Implement mode switching on Logitech gaming wheels accordingly to the documentation

2014-07-30 Thread Michal Malý
Implement mode switching on Logitech gaming wheels accordingly to the 
documentation

Signed-off-by: Michal Malý 

---
 Logitech has recently released technical documentation which describes the
 protocol used by their force feedback gaming devices. The documentation
 describes the method by which the driver is supposed to recognize what
 model of the wheel is connected and switch it to so-called "native" mode.
 (https://opensource.logitech.com/opensource/index.php/Technical_Information)

 The patch implements this logic and provides an additional module parameter
 which can force the driver either not perform the switch at all or switch the
 wheel into an "extended compatibility" mode (not applicable for all wheels).
 If a wheel does not support the mode enforced by the parameter, it is left in
 its original mode. Default behavior is to switch all wheels into native mode.

 drivers/hid/hid-lg.c|  17 +++-
 drivers/hid/hid-lg.h|  11 ++-
 drivers/hid/hid-lg4ff.c | 224 +++-
 3 files changed, 188 insertions(+), 64 deletions(-)

diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index a976f48..dc0f2f1 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -334,6 +334,16 @@ static __u8 momo2_rdesc_fixed[] = {
 };
 
 /*
+ * Certain Logitech wheels provide various compatibililty modes
+ * for games that cannot handle their advanced features properly.
+ * This switch forces the wheel into a specific compatibililty
+ * instead of its native mode
+ */
+#ifdef CONFIG_LOGIWHEELS_FF
+static int lg4ff_switch_force_mode;
+#endif
+
+/*
  * Certain Logitech keyboards send in report #3 keys which are far
  * above the logical maximum described in descriptor. This extends
  * the original value of 0x28c of logical maximum to 0x104d
@@ -717,7 +727,7 @@ static int lg_probe(struct hid_device *hdev, const struct 
hid_device_id *id)
if (drv_data->quirks & LG_FF3)
lg3ff_init(hdev);
if (drv_data->quirks & LG_FF4)
-   lg4ff_init(hdev);
+   lg4ff_init(hdev, lg4ff_switch_force_mode);
 
return 0;
 err_free:
@@ -818,4 +828,9 @@ static struct hid_driver lg_driver = {
 };
 module_hid_driver(lg_driver);
 
+#ifdef CONFIG_LOGIWHEELS_FF
+module_param_named(lg4ff_switch_force_mode, lg4ff_switch_force_mode, int, 
S_IRUGO);
+MODULE_PARM_DESC(lg4ff_switch_force_mode, "Force gaming wheel into specific 
compatibililty mode (only certain devices)");
+#endif
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index 142ce3f..d070e479 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -25,14 +25,21 @@ static inline int lg3ff_init(struct hid_device *hdev) { 
return -1; }
 #endif
 
 #ifdef CONFIG_LOGIWHEELS_FF
+#define LG4FF_MSW_MIN 0
+#define LG4FF_MSW_NATIVE 0 /* Switch device to its native mode (if 
applicable) */
+#define LG4FF_MSW_DONTSWITCH 1 /* Leave device in its current mode */
+#define LG4FF_MSW_DFP 2/* Switch device so that it emulates 
Driving Force Pro (only G25, G27, DFGT) */
+#define LG4FF_MSW_G25 3/* Switch device so that it emulates 
G25 (only G27) */
+#define LG4FF_MSW_MAX 3
+
 int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
 struct hid_usage *usage, __s32 value, struct 
lg_drv_data *drv_data);
-int lg4ff_init(struct hid_device *hdev);
+int lg4ff_init(struct hid_device *hdev, const int switch_force_mode);
 int lg4ff_deinit(struct hid_device *hdev);
 #else
 static inline int lg4ff_adjust_input_event(struct hid_device *hid, struct 
hid_field *field,
   struct hid_usage *usage, __s32 
value, struct lg_drv_data *drv_data) { return 0; }
-static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
+static inline int lg4ff_init(struct hid_device *hdev, const int 
switch_force_mode) { return -1; }
 static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; }
 #endif
 
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index cc2bd20..14692d9 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -32,21 +32,10 @@
 #include "hid-lg.h"
 #include "hid-ids.h"
 
-#define DFGT_REV_MAJ 0x13
-#define DFGT_REV_MIN 0x22
-#define DFGT2_REV_MIN 0x26
-#define DFP_REV_MAJ 0x11
-#define DFP_REV_MIN 0x06
-#define FFEX_REV_MAJ 0x21
-#define FFEX_REV_MIN 0x00
-#define G25_REV_MAJ 0x12
-#define G25_REV_MIN 0x22
-#define G27_REV_MAJ 0x12
-#define G27_REV_MIN 0x38
-#define G27_2_REV_MIN 0x39
-
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
+#define LG4FF_FFEX_BCDDEVICE 0x2100
+
 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
 static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
 static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute 
*attr, ch

Re: [v2] input: drv260x: Add TI drv260x haptics driver

2014-07-29 Thread Michal Malý
On Monday 28 of July 2014 21:21:26 Murphy, Dan wrote:
> Dmitry
> 
> On 07/28/2014 12:59 PM, si...@mungewell.org wrote:
> >>> The initial driver supports the devices
> >>> real time playback mode.  But the device
> >>> has additional wave patterns in ROM.
> >> 
> >> As it presented the device appears to be a memoryless device, however
> >> you present it to the rest of the system as if it can support playback
> >> of multiple effects simultaneously, which is incorrect.
> >> 
> >> My guess that you need to engage the memoryless input library to schedule
> >> handling multiple effects for your device, including ramping up, ramping
> >> down, stopping playback when effects runs out, etc.
> > 
> > Hi Dan,
> > Elias and Michal (cc'ed) are working on a kernel/userland library to
> > handle sending multiple force feedback signals to 'simple' devices,
> > perhaps you should engage with them.
> > 
> > Simon

Hi Dan,

since I spent some time trying to improve the memoryless library I can 
hopefully provide you with some hints.

If I'm reading this right, your device cannot play more than one effect at once 
but it can operate eihter in RTP mode where the user controls the operation of 
the motors directly on in an automated mode where the device follows some pre-
programmed waveform. These two modes are mutually exclusive.

If my understanding of the problem is correct, you will struggle both with 
memoryless library and your own imlementation. The memoryless library is quite 
simplistic and it doesn't have any sort of "passthrough" mode so you would not 
be able to do anything besides RTP that way.

On the other hand if you decide to write your own implementation of effect 
handling you will end up duplicating a lot of code that already exists in the 
memoryless library and has been proven to work.

A possible solution for the problem would be to separate the functions that 
control effect timing from the memoryless library and make them globally 
accessible. I believe that this would simplify any customized haptic 
implementation considerably and it might be a decent interim solution before 
the project Simon mentioned is ready.

If there is anybody interested in such a solution I can probably whip up a 
patch for it quite quickly.

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


Re: [PATCH v4 01/24] input: Add ff-memless-next module

2014-05-20 Thread Michal Malý
On Tuesday 20 of May 2014 18:17:51 Roland Bosa wrote:
> 
> The file format of an IFR is probably easily deducible. There's a lot of
> textual clues to parameters and the values are also written out in
> string form.
> 
> I don't have a FEdit file at hand, but I suppose it will be similar.

I believe that Elias successfully reverse engineered the effect file format 
produced by FEdit. There is no support for this kind of prefabricated effects 
in the Linux FF API.

> > I assume that most AAA games, would implement these through some middle
> > layer. I think that is probably via Steam using SDL2 haptic API, we have
> > been testing against SDL2's 'testhaptic'.
> 
> I wasn't aware of this layer. I must read up on it. It sounds like a
> simple way to access force feedback - I guess a game developer should
> shed some light on this...
>
>
> > Do you see another path (which we should be supporting/testing)?
> 
> Nope, not at this time.
> 
> > There was some discussion about rate limiting the USB packets to the
> > wheel, and how to deal if app updates too quickly. Is there an upper limit
> > for the wheel itself, or is it just the USB 'pipe' which is the limiting
> > factor?
> 
> On the Windows side we send 125 reports/sec. The entire simulation loop
> runs with a 8ms resolution. I assume this value was chosen for some
> hardware constraints back in the days, but it has proven to be a good
> compromise for simulated periodics and physics constraints.

Our current code uses 8 msecs delay as well.

> In any case, the USB traffic should be decoupled from the app. Any force
> updates should only change state in the ff-memless[-next] driver. Any
> change there should trickle down to a 'slot' representation of the
> device. If there's any change in the slots, the device is marked as
> 'dirty' and USB transfers are scheduled to send the latest state to the
> physical device.
> 
> The scheduling should keep track of how many requests are in-flight and
> delay writing the next output, until the previous one has completed.

The approach I had in mind would keep track of the last effect that made it to 
the device and the last effect that arrived from userspace. This would be 
stored for each effect slot. An update would be scheduled at the desired update 
rate. The updating routine would figure out the state change between last 
update and "now", send the required data to the device and reschedule itself. 
The routine could check if there are any USB transfers still running and 
reschedule itself immediately.

> Question back to the community: are there APIs in the USB layer to check
> for presence of in-progress requests? Can one add a 'completion'
> callback to a request, that gets invoked on completion/cancellation?

For instance "usb_submit_urb()" can have a completion handler that is called 
once the transfer is done. The current code uses "hid_hw_request()" which is 
asynchronous and doesn't report anything back.

Proper decoupling of the userspace and driver is the only important thing that 
is missing from the current code.

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


Re: [PATCH v4 01/24] input: Add ff-memless-next module

2014-05-20 Thread Michal Malý
On Tuesday 20 of May 2014 19:45:44 si...@mungewell.org wrote:
> >> Regarding the question of emulated vs. real effects, can we extend the
> >> API
> >> so that applications can know which effects are really supported, and
> >> enable/disable emulation somehow?
> > 
> > I suppose that a few extra flags (FF_PERIODIC_EMULATED etc.) defined in
> > "uapi/linux/input.h" should suffice.
> 
> The only problem is that we probably want to maintain backward
> compatibility so that older apps still see 'PERIODIC' (even though it is
> emulated).
> --
> #define FF_RUMBLE 0x50
> #define FF_PERIODIC   0x51
> #define FF_CONSTANT   0x52
> #define FF_SPRING 0x53
> #define FF_FRICTION   0x54
> #define FF_DAMPER 0x55
> #define FF_INERTIA0x56
> #define FF_RAMP   0x57
> --
> 
> Do we therefore have to list extra items in our capabilities?
> --
> static const signed short lg4ff_wheel_effects[] = {
>   FF_CONSTANT,
>   FF_PERIODIC,
>   FF_PERIODIC_NOT_EMULATED,
>   FF_AUTOCENTER,
>   -1
> };
> --
> 
> Simon

Actually I was thinking something like this:

"input.h"
#define FF_DAMPER   0x55
#define FF_INERTIA  0x56
#define FF_RAMP 0x57
+# define FF_PERIODIC_EMULATED  0x58
+# define FF_RUMBLE_EMULATED0x59

and

in the future "library-like" reimplementation of MLNX:
#define EMULATE_PERIODIC BIT(0)
#define EMULATE_RUMBLE BIT(1)

kfflib_init(..., EMULATE_PERIODIC | EMULATE_RUMBLE);
for full emulation.

Michal


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


Re: [PATCH v4 01/24] input: Add ff-memless-next module

2014-05-20 Thread Michal Malý
On Tuesday 20 of May 2014 16:16:12 si...@mungewell.org wrote:
> > To bring this to a conclusion we could go from, would this be an
> > acceptable
> > solution?
> > 
> > - Have the HW-specific driver talk directly to ff-core and reimplement
> > upload(),
> > play(), etc.
> > - Rewrite "ff-memless-next" so that it is not a self-contained module but
> > a
> > library of functions.
> > 
> > - Have the driver either:
> >   - Upload an effect to a device directly if the device can fully manage
> > 
> > the
> > effect by itself.
> > 
> >   - Use provided timing functions to know when an effect should start,
> > 
> > stop,
> > restart etc...
> > 
> >   - Use provided timing AND processing functions to combine effects that
> > 
> > can be
> > combined into one, calculate periodic waveforms etc?
> > 
> > I have no problem with throwing my current approach away but before I
> > start working on a new one I'd like to know which way to go...
> 
> Hi all,
> If the driver itself (hid-logitech, via hid-lg4ff for example) is more
> involved in the creation/timing/management of the effects, does this mean
> that we end up with code duplicated in lots of places?

Hopefully not. I tried to work out some scheme how this would work in my head 
today and the code duplication among other drivers should be minimal. 
Basically an equivalent of "play_effects()" - implemented in the HW-specific 
driver - would by called as needed. Such a function would then use provided 
helper functions to process combinable effects and check if any uncombinable 
effects changed state. A proper rate limiting will fit into this scheme nicely 
as well.
The biggest advantage of this design is that the HW-specific driver will be 
able to either handle an effect all by itself or use the provided "helper" 
infrastructure.

In retrospect I've got agree with Dmitry that the current handling of 
(semi)memless devices is not very flexible and therefore potentially 
problematic. It'll require some extra work but we don't have to invent 
anything entirely new here, we can just rearrange what we've already done in 
MLNX and package it into a library.

> Also, does this mean that the 'old' ff-memless system would remain in
> kernel? If not, who will reworking each driver?

I suppose that the maintainers would want us to move all FF drivers to this 
architecture. If we get it right, it shouldn't require a terrible amount of 
work to port the other drivers.

> Regarding the question of emulated vs. real effects, can we extend the API
> so that applications can know which effects are really supported, and
> enable/disable emulation somehow?

I suppose that a few extra flags (FF_PERIODIC_EMULATED etc.) defined in 
"uapi/linux/input.h" should suffice.

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


Re: [PATCH v4 01/24] input: Add ff-memless-next module

2014-05-20 Thread Michal Malý
On Tuesday 20 of May 2014 11:32:14 Roland Bosa wrote:
> On 05/20/2014 02:27 AM, Michal Malý wrote:
> > On Wednesday 14 of May 2014 11:05:58 Dmitry Torokhov wrote:
> >> On Wed, May 14, 2014 at 10:35:25AM +0200, Michal Malý wrote:
> >>> Hi Dmitry,
> >>> 
> >>> thank you for reviewing this.
> >>> 
> >>> On Tuesday 13 of May 2014 23:38:06 Dmitry Torokhov wrote:
> >>>> On Sat, Apr 26, 2014 at 05:02:00PM +0200, Michal Malý wrote:
> >>>>> +
> >>>>> +/** DEFINITION OF TERMS
> >>>>> + *
> >>>>> + * Combined effect - An effect whose force is a superposition of
> >>>>> forces
> >>>>> + *   generated by all effects that can be added
> >>>>> together.
> >>>>> + *   Only one combined effect can be playing at a
> >>>>> time.
> >>>>> + *   Effects that can be added together to create a
> >>>>> combined + *   effect are FF_CONSTANT, FF_PERIODIC and
> >>>>> FF_RAMP. + * Uncombinable effect - An effect that cannot be combined
> >>>>> with
> >>>>> another effect. + *   All conditional effects -
> >>>>> FF_DAMPER, FF_FRICTION, + *   FF_INERTIA and
> >>>>> FF_SPRING are uncombinable. + *   Number of
> >>>>> uncombinable effects playing simultaneously + *
> >>>>> depends on the capabilities of the hardware. + * Rumble effect - An
> >>>>> effect generated by device's rumble motors instead of + *
> >>>>> force feedback actuators.
> >>>>> + *
> >>>>> + *
> >>>>> + * HANDLING OF UNCOMBINABLE EFFECTS
> >>>>> + *
> >>>>> + * Uncombinable effects cannot be combined together into just one
> >>>>> effect,
> >>>>> at + * least not in a clear and obvious manner. Therefore these
> >>>>> effects
> >>>>> have to + * be handled individually by ff-memless-next. Handling of
> >>>>> these
> >>>>> effects is + * left entirely to the hardware-specific driver,
> >>>>> ff-memless-next merely + * passes these effects to the
> >>>>> hardware-specific
> >>>>> driver at appropriate time. + * ff-memless-next provides the UPLOAD
> >>>>> command to notify the hardware-specific + * driver that the userspace
> >>>>> is
> >>>>> about to request playback of an uncombinable + * effect. The
> >>>>> hardware-specific driver shall take all steps needed to make + * the
> >>>>> device ready to play the effect when it receives the UPLOAD command. +
> >>>>> *
> >>>>> The actual playback shall commence when START_UNCOMB command is
> >>>>> received.
> >>>>> + * Opposite to the UPLOAD command is the ERASE command which tells +
> >>>>> *
> >>>>> the hardware-specific driver that the playback has finished and that +
> >>>>> *
> >>>>> the effect will not be restarted. STOP_UNCOMB command tells
> >>>>> + * the hardware-specific driver that the playback shall stop but the
> >>>>> device + * shall still be ready to resume the playback immediately.
> >>>>> + *
> >>>>> + * In case it is not possible to make the device ready to play an
> >>>>> uncombinable + * effect (all hardware effect slots are occupied), the
> >>>>> hardware-specific + * driver may return an error when it receives an
> >>>>> UPLOAD command. If the
> >>>> 
> >>>> This part concerns me. It seems to me that devices supporting
> >>>> "uncombinable" effects are in fact not memoryless devices and we should
> >>>> not be introducing this term here. If the goal is to work around
> >>>> limited
> >>>> number of effect slots in the devices by combining certain effects then
> >>>> it needs to be done at ff-core level as it will be potentially useful
> >>>> for all devices.
> >>> 
> >>> Force generated by a conditional effect (referred to as "uncombinable"
> >>> within ff-memless-next to make the distinction clear) depends on a
> >>> position of the device. Fo

Re: [PATCH v4 01/24] input: Add ff-memless-next module

2014-05-20 Thread Michal Malý
On Wednesday 14 of May 2014 11:05:58 Dmitry Torokhov wrote:
> On Wed, May 14, 2014 at 10:35:25AM +0200, Michal Malý wrote:
> > Hi Dmitry,
> > 
> > thank you for reviewing this.
> > 
> > On Tuesday 13 of May 2014 23:38:06 Dmitry Torokhov wrote:
> > > On Sat, Apr 26, 2014 at 05:02:00PM +0200, Michal Malý wrote:
> > > > +
> > > > +/** DEFINITION OF TERMS
> > > > + *
> > > > + * Combined effect - An effect whose force is a superposition of
> > > > forces
> > > > + *   generated by all effects that can be added
> > > > together.
> > > > + *   Only one combined effect can be playing at a
> > > > time.
> > > > + *   Effects that can be added together to create a
> > > > combined + *   effect are FF_CONSTANT, FF_PERIODIC and
> > > > FF_RAMP. + * Uncombinable effect - An effect that cannot be combined
> > > > with
> > > > another effect. + *   All conditional effects -
> > > > FF_DAMPER, FF_FRICTION, + *   FF_INERTIA and
> > > > FF_SPRING are uncombinable. + *   Number of
> > > > uncombinable effects playing simultaneously + *
> > > > depends on the capabilities of the hardware. + * Rumble effect - An
> > > > effect generated by device's rumble motors instead of + *
> > > > force feedback actuators.
> > > > + *
> > > > + *
> > > > + * HANDLING OF UNCOMBINABLE EFFECTS
> > > > + *
> > > > + * Uncombinable effects cannot be combined together into just one
> > > > effect,
> > > > at + * least not in a clear and obvious manner. Therefore these
> > > > effects
> > > > have to + * be handled individually by ff-memless-next. Handling of
> > > > these
> > > > effects is + * left entirely to the hardware-specific driver,
> > > > ff-memless-next merely + * passes these effects to the
> > > > hardware-specific
> > > > driver at appropriate time. + * ff-memless-next provides the UPLOAD
> > > > command to notify the hardware-specific + * driver that the userspace
> > > > is
> > > > about to request playback of an uncombinable + * effect. The
> > > > hardware-specific driver shall take all steps needed to make + * the
> > > > device ready to play the effect when it receives the UPLOAD command. +
> > > > *
> > > > The actual playback shall commence when START_UNCOMB command is
> > > > received.
> > > > + * Opposite to the UPLOAD command is the ERASE command which tells +
> > > > *
> > > > the hardware-specific driver that the playback has finished and that +
> > > > *
> > > > the effect will not be restarted. STOP_UNCOMB command tells
> > > > + * the hardware-specific driver that the playback shall stop but the
> > > > device + * shall still be ready to resume the playback immediately.
> > > > + *
> > > > + * In case it is not possible to make the device ready to play an
> > > > uncombinable + * effect (all hardware effect slots are occupied), the
> > > > hardware-specific + * driver may return an error when it receives an
> > > > UPLOAD command. If the
> > > 
> > > This part concerns me. It seems to me that devices supporting
> > > "uncombinable" effects are in fact not memoryless devices and we should
> > > not be introducing this term here. If the goal is to work around limited
> > > number of effect slots in the devices by combining certain effects then
> > > it needs to be done at ff-core level as it will be potentially useful
> > > for all devices.
> > 
> > Force generated by a conditional effect (referred to as "uncombinable"
> > within ff-memless-next to make the distinction clear) depends on a
> > position of the device. For instance the more a device is deflected from
> > a neutral position the greater force FF_SPRING generates. A truly
> > memoryless device would have to report its position to the driver, have
> > it calculate the appropriate force and send it back to the device. IMHO
> > such a loop would require a very high USB polling rate to play
> > conditional effects with acceptable quality.
> > 
> > We know for a fact that at least many (all?) Logitech devices that support
> > conditional effects use this "semi-memoryless" approach where FF_CON

Re: [PATCH v4 01/24] input: Add ff-memless-next module

2014-05-14 Thread Michal Malý
On Wednesday 14 of May 2014 11:14:02 Dmitry Torokhov wrote:
> On Sat, Apr 26, 2014 at 05:02:00PM +0200, Michal Malý wrote:
> > +
> > +/** input_ff_create_mlnx() - Register a device within ff-memless-next and
> > + *   the kernel force feedback system
> > + * @dev: Pointer to the struct input_dev associated with the device.
> > + * @data: Any device-specific data that shall be passed to the callback.
> > + *function called by ff-memless-next when a force feedback action
> > + *shall be performed.
> > + * @control_effect: Pointer to the callback function.
> > + * @update_date: Delay in milliseconds between two recalculations of
> > periodic + *   effects, ramp effects and envelopes. Note that
> > this value will + *   never be lower than (CONFIG_HZ / 1000)
> > + 1 regardless of the + *   value specified here. This is not
> > a "hard" rate limiter. + *   Userspace still can submit
> > effects at a rate faster than + *   this value.
> 
> The update rate change seems useful whether we use new ff implementation
> or enhance the old one but I would prefer having a separate call to
> control it.

OK, that should not be a problem. Please note that the plan is to use this 
value to do proper "hard" rate limiting in the future.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v4 01/24] input: Add ff-memless-next module

2014-05-14 Thread Michal Malý
On Wednesday 14 of May 2014 11:05:58 Dmitry Torokhov wrote:
> On Wed, May 14, 2014 at 10:35:25AM +0200, Michal Malý wrote:
> > Hi Dmitry,
> > 
> > thank you for reviewing this.
> > 
> > On Tuesday 13 of May 2014 23:38:06 Dmitry Torokhov wrote:
> > > On Sat, Apr 26, 2014 at 05:02:00PM +0200, Michal Malý wrote:
> > > > +
> > > > +/** DEFINITION OF TERMS
> > > > + *
> > > > + * Combined effect - An effect whose force is a superposition of
> > > > forces
> > > > + *   generated by all effects that can be added
> > > > together.
> > > > + *   Only one combined effect can be playing at a
> > > > time.
> > > > + *   Effects that can be added together to create a
> > > > combined + *   effect are FF_CONSTANT, FF_PERIODIC and
> > > > FF_RAMP. + * Uncombinable effect - An effect that cannot be combined
> > > > with
> > > > another effect. + *   All conditional effects -
> > > > FF_DAMPER, FF_FRICTION, + *   FF_INERTIA and
> > > > FF_SPRING are uncombinable. + *   Number of
> > > > uncombinable effects playing simultaneously + *
> > > > depends on the capabilities of the hardware. + * Rumble effect - An
> > > > effect generated by device's rumble motors instead of + *
> > > > force feedback actuators.
> > > > + *
> > > > + *
> > > > + * HANDLING OF UNCOMBINABLE EFFECTS
> > > > + *
> > > > + * Uncombinable effects cannot be combined together into just one
> > > > effect,
> > > > at + * least not in a clear and obvious manner. Therefore these
> > > > effects
> > > > have to + * be handled individually by ff-memless-next. Handling of
> > > > these
> > > > effects is + * left entirely to the hardware-specific driver,
> > > > ff-memless-next merely + * passes these effects to the
> > > > hardware-specific
> > > > driver at appropriate time. + * ff-memless-next provides the UPLOAD
> > > > command to notify the hardware-specific + * driver that the userspace
> > > > is
> > > > about to request playback of an uncombinable + * effect. The
> > > > hardware-specific driver shall take all steps needed to make + * the
> > > > device ready to play the effect when it receives the UPLOAD command. +
> > > > *
> > > > The actual playback shall commence when START_UNCOMB command is
> > > > received.
> > > > + * Opposite to the UPLOAD command is the ERASE command which tells +
> > > > *
> > > > the hardware-specific driver that the playback has finished and that +
> > > > *
> > > > the effect will not be restarted. STOP_UNCOMB command tells
> > > > + * the hardware-specific driver that the playback shall stop but the
> > > > device + * shall still be ready to resume the playback immediately.
> > > > + *
> > > > + * In case it is not possible to make the device ready to play an
> > > > uncombinable + * effect (all hardware effect slots are occupied), the
> > > > hardware-specific + * driver may return an error when it receives an
> > > > UPLOAD command. If the
> > > 
> > > This part concerns me. It seems to me that devices supporting
> > > "uncombinable" effects are in fact not memoryless devices and we should
> > > not be introducing this term here. If the goal is to work around limited
> > > number of effect slots in the devices by combining certain effects then
> > > it needs to be done at ff-core level as it will be potentially useful
> > > for all devices.
> > 
> > Force generated by a conditional effect (referred to as "uncombinable"
> > within ff-memless-next to make the distinction clear) depends on a
> > position of the device. For instance the more a device is deflected from
> > a neutral position the greater force FF_SPRING generates. A truly
> > memoryless device would have to report its position to the driver, have
> > it calculate the appropriate force and send it back to the device. IMHO
> > such a loop would require a very high USB polling rate to play
> > conditional effects with acceptable quality.
> > 
> > We know for a fact that at least many (all?) Logitech devices that support
> > conditional effects use this "semi-memoryless" approach where FF_CON

Re: [PATCH v4 01/24] input: Add ff-memless-next module

2014-05-14 Thread Michal Malý
Hi Dmitry,

thank you for reviewing this.

On Tuesday 13 of May 2014 23:38:06 Dmitry Torokhov wrote:
> On Sat, Apr 26, 2014 at 05:02:00PM +0200, Michal Malý wrote:
> > +
> > +/** DEFINITION OF TERMS
> > + *
> > + * Combined effect - An effect whose force is a superposition of forces
> > + *   generated by all effects that can be added together.
> > + *   Only one combined effect can be playing at a time.
> > + *   Effects that can be added together to create a
> > combined + *   effect are FF_CONSTANT, FF_PERIODIC and
> > FF_RAMP. + * Uncombinable effect - An effect that cannot be combined with
> > another effect. + *   All conditional effects -
> > FF_DAMPER, FF_FRICTION, + *   FF_INERTIA and
> > FF_SPRING are uncombinable. + *   Number of
> > uncombinable effects playing simultaneously + *  
> > depends on the capabilities of the hardware. + * Rumble effect - An
> > effect generated by device's rumble motors instead of + *
> > force feedback actuators.
> > + *
> > + *
> > + * HANDLING OF UNCOMBINABLE EFFECTS
> > + *
> > + * Uncombinable effects cannot be combined together into just one effect,
> > at + * least not in a clear and obvious manner. Therefore these effects
> > have to + * be handled individually by ff-memless-next. Handling of these
> > effects is + * left entirely to the hardware-specific driver,
> > ff-memless-next merely + * passes these effects to the hardware-specific
> > driver at appropriate time. + * ff-memless-next provides the UPLOAD
> > command to notify the hardware-specific + * driver that the userspace is
> > about to request playback of an uncombinable + * effect. The
> > hardware-specific driver shall take all steps needed to make + * the
> > device ready to play the effect when it receives the UPLOAD command. + *
> > The actual playback shall commence when START_UNCOMB command is received.
> > + * Opposite to the UPLOAD command is the ERASE command which tells + *
> > the hardware-specific driver that the playback has finished and that + *
> > the effect will not be restarted. STOP_UNCOMB command tells
> > + * the hardware-specific driver that the playback shall stop but the
> > device + * shall still be ready to resume the playback immediately.
> > + *
> > + * In case it is not possible to make the device ready to play an
> > uncombinable + * effect (all hardware effect slots are occupied), the
> > hardware-specific + * driver may return an error when it receives an
> > UPLOAD command. If the
> This part concerns me. It seems to me that devices supporting
> "uncombinable" effects are in fact not memoryless devices and we should
> not be introducing this term here. If the goal is to work around limited
> number of effect slots in the devices by combining certain effects then
> it needs to be done at ff-core level as it will be potentially useful
> for all devices.

Force generated by a conditional effect (referred to as "uncombinable" within
ff-memless-next to make the distinction clear) depends on a position of the 
device. For instance the more a device is deflected from a neutral position the 
greater force FF_SPRING generates. A truly memoryless device would have to 
report its position to the driver, have it calculate the appropriate force and 
send it back to the device. IMHO such a loop would require a very high USB 
polling rate to play conditional effects with acceptable quality.

We know for a fact that at least many (all?) Logitech devices that support 
conditional effects use this "semi-memoryless" approach where FF_CONSTANT and 
FF_PERIODIC are handled in the memoryless fashion and conditional effects are 
uploaded to the device (in a somewhat simplified form). The amount of effects 
that can be uploaded to a device is limited which is why ff-memless-next uses 
two steps (UPLOAD/ERASE and START/STOP) to handle these effects.

Conditional effects - even if they are of the same type - cannot be effectively 
combined into one because superposition doesn't seem to work here so they have 
to be processed one by one.

If we ever come across a really memoryless device it should not be 
particularly difficult to add another callback to ff-memless-next which would 
emulate conditional effects with constant force.

> > + * hardware-specific driver returns 0, the upload is considered
> > successful. + * START_UNCOMB and STOP_UNCOMB commands cannot fail and the
> > device must always + * start the playback of the requested effect if the
> > UPLOAD command of the + * respective effect has bee

Re: [PATCH v4 00/24] input: Introduce ff-memless-next as an improved replacement for ff-memless

2014-05-12 Thread Michal Malý
On Monday 12 of May 2014 11:14:42 Jiri Kosina wrote:
> On Sat, 26 Apr 2014, Michal Malý wrote:
> > ff-memless-next (MLNX) is a largely improved version of the current
> > ff-memless (FFML) driver. MLNX supports all force feedback effects
> > currently available in the Linux force feedback userspace API. All
> > effects are handled in accordance with Microsoft's DirectInput/XInput.
> > Most notable changes include support for conditional effects, proper
> > handling of all periodic waveforms and improved emulation of rumble
> > effects through periodic effects. MLNX also uses its own kernel API to
> > pass processed effects to hardware-specific drivers instead of abusing
> > "ff_effect" struct. The API is documented in the respective header file.
> > 
> > MLNX has been expanded to be a direct replacement for FFML.
> > 
> > Support for FF_PERIODIC and FF_RAMP has been added to all devices that
> > support FF_CONSTANT as a part of the port to the new API.
> > 
> > This patch series:
> > 1) Adds "ff-memless-next" module [1]
> > 2) Ports all hardware-specific drivers to MLNX's API [2-23]
> > 3) Removes FFML and replaces it with MLNX [24]
> 
> Dmitry,
> 
> what are your plans with this, please?
> 
> I personally don't really completely like having two implementations of FF
> in the kernel; can't it be really done as an extension to ff-memless?

There will be no duplication. This patchset fully replaces "ff-memless" with 
"ff-memless-next". Even though "ff-memless-next" is basically an extended 
version of "ff-memless", the extent of the changes makes it look very much like 
a rewrite.

If you are concerned about any confusion due to the "ff-memless" -> "ff-memless-
next" name change I can modify the code to make it look like "ff-memless" if 
you think that'd be more appropriate. However, given the scope of the changes 
I considered it a better idea to implement this as a new driver to make it 
clear that ff-memless-next behaves differently from the HW-specific drivers' 
perspective.

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


[PATCH v4 01/24] input: Add ff-memless-next module

2014-04-26 Thread Michal Malý
Add ff-memless-next module

Signed-off-by: Michal Malý 
Tested-by: Elias Vanderstuyft 
---
 drivers/input/Kconfig |   11 +
 drivers/input/Makefile|1 +
 drivers/input/ff-memless-next.c   | 1037 +
 include/linux/input/ff-memless-next.h |  162 +
 4 files changed, 1211 insertions(+)
 create mode 100644 drivers/input/ff-memless-next.c
 create mode 100644 include/linux/input/ff-memless-next.h

diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index a11ff74..3780962 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -38,6 +38,17 @@ config INPUT_FF_MEMLESS
  To compile this driver as a module, choose M here: the
  module will be called ff-memless.
 
+config INPUT_FF_MEMLESS_NEXT
+   tristate "New version of support for memoryless force-feedback devices"
+   help
+ Say Y here to enable a new version of support for memoryless force
+ feedback devices.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ff-memless-next.
+
 config INPUT_POLLDEV
tristate "Polled input device skeleton"
help
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 5ca3f63..b4f11f5 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_INPUT) += input-core.o
 input-core-y := input.o input-compat.o input-mt.o ff-core.o
 
 obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
+obj-$(CONFIG_INPUT_FF_MEMLESS_NEXT)+= ff-memless-next.o
 obj-$(CONFIG_INPUT_POLLDEV)+= input-polldev.o
 obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
 obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o
diff --git a/drivers/input/ff-memless-next.c b/drivers/input/ff-memless-next.c
new file mode 100644
index 000..24619e9
--- /dev/null
+++ b/drivers/input/ff-memless-next.c
@@ -0,0 +1,1037 @@
+/*
+ * Force feedback support for memoryless devices
+ *
+ * This module is based on "ff-memless" orignally written by Anssi Hannula.
+ * It is extended to support all force feedback effects currently supported
+ * by the Linux input stack.
+ * Logic of emulation of FF_RUMBLE through FF_PERIODIC provided by
+ * Elias Vanderstuyft 
+ *
+ * Copyright(c) 2014 Michal "MadCatX" Maly 
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal \"MadCatX\" Maly");
+MODULE_DESCRIPTION("Force feedback support for memoryless force feedback 
devices");
+
+#define FF_MAX_EFFECTS 16
+#define FF_MIN_EFFECT_LENGTH ((MSEC_PER_SEC / CONFIG_HZ) + 1)
+#define FF_EFFECT_STARTED 1
+#define FF_EFFECT_PLAYING 2
+#define FF_EFFECT_EMULATED 3
+
+enum mlnx_emulate {
+   EMUL_NOTHING,   /* Do not emulate anything */
+   EMUL_RUMBLE,/* Emulate FF_RUMBLE with FF_PERIODIC */
+   EMUL_PERIODIC   /* Emulate FF_PERIODIC with FF_RUMBLE */
+};
+
+struct mlnx_effect {
+   struct ff_effect effect;
+   unsigned long flags;
+   unsigned long begin_at;
+   unsigned long stop_at;
+   unsigned long updated_at;
+   unsigned long attack_stop;
+   unsigned long fade_begin;
+   int repeat;
+};
+
+struct mlnx_device {
+   u8 combinable_playing;
+   u8 rumble_playing;
+   unsigned long update_rate_jiffies;
+   void *private;
+   struct mlnx_effect effects[FF_MAX_EFFECTS];
+   u16 gain;
+   struct timer_list timer;
+   struct input_dev *dev;
+   enum mlnx_emulate emul;
+
+   int (*control_effect)(struct input_dev *, void *,
+ const struct mlnx_effect_command *);
+};
+
+static s32 mlnx_calculate_x_force(const s32 level,
+ const u16 direction)
+{
+   s32 new = (level * -fixp_sin(direction)) >> FRAC_N;
+   pr_debug("x force: %d\n", new);
+   return new;
+}
+
+static s32 mlnx_calculate_y_force(const s32 level,
+ const u16 direction)
+{
+   s32 new = (level * fixp_cos(direction)) >> FRAC_N;
+   pr_debug("y force: %d\n", new);
+   return new;
+}
+
+static bool mlnx_is_combinable(const struct ff_effect *effect)
+{
+   switch (effect->type) {
+   case FF_CONSTANT:
+   case FF_PERIODIC:
+   case FF_RAMP:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static bool mlnx_is_conditional(const struct ff_effect *effect)
+{
+   switch (effect->type) {
+   case FF_DAMPER:
+   case FF_FRICTION:
+   case FF_INERTIA:
+   case FF_SPRING:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static void mlnx_clr_emulated(struct mlnx_effect *mlnx

[PATCH v4 22/24] hid: Port hid-lg2ff to ff-memless-next

2014-04-26 Thread Michal Malý
- Port hid-lg2ff to ff-memless-next
- Clamp vibration magnitude to range <0x02; 0xfd> to prevent irregular
  shaking of the vibration motors.

Signed-off-by: Elias Vanderstuyft 
---
 drivers/hid/Kconfig |  2 +-
 drivers/hid/hid-lg2ff.c | 65 ++---
 2 files changed, 47 insertions(+), 20 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 97d2d8f..5e70519 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -381,7 +381,7 @@ config LOGITECH_FF
 config LOGIRUMBLEPAD2_FF
bool "Logitech force feedback support (variant 2)"
depends on HID_LOGITECH
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  Say Y here if you want to enable force feedback support for:
  - Logitech RumblePad
diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c
index 0e3fb1a..6ab5327 100644
--- a/drivers/hid/hid-lg2ff.c
+++ b/drivers/hid/hid-lg2ff.c
@@ -22,42 +22,69 @@
 
 
 #include 
+#include 
 #include 
 #include 
 
 #include "hid-lg.h"
 
+#define FF_UPDATE_RATE 8
+
 struct lg2ff_device {
struct hid_report *report;
 };
 
-static int play_effect(struct input_dev *dev, void *data,
-struct ff_effect *effect)
+static int hid_lg2ff_start_rumble(struct hid_device *hid, struct hid_report 
*report,
+   const struct mlnx_rumble_force *rumble)
 {
-   struct hid_device *hid = input_get_drvdata(dev);
-   struct lg2ff_device *lg2ff = data;
int weak, strong;
 
-   strong = effect->u.rumble.strong_magnitude;
-   weak = effect->u.rumble.weak_magnitude;
+#define CLAMP_QUIRK(x) do { if (x < 2) x = 2; else if (x > 0xfd) x = 0xfd; } \
+   while (0)
 
-   if (weak || strong) {
-   weak = weak * 0xff / 0x;
-   strong = strong * 0xff / 0x;
+   /* Scale down from MLNX range */
+   strong = rumble->strong * 0xff / 0x;
+   weak = rumble->weak * 0xff / 0x;
+   CLAMP_QUIRK(weak);
+   CLAMP_QUIRK(strong);
 
-   lg2ff->report->field[0]->value[0] = 0x51;
-   lg2ff->report->field[0]->value[2] = weak;
-   lg2ff->report->field[0]->value[4] = strong;
-   } else {
-   lg2ff->report->field[0]->value[0] = 0xf3;
-   lg2ff->report->field[0]->value[2] = 0x00;
-   lg2ff->report->field[0]->value[4] = 0x00;
-   }
+   report->field[0]->value[0] = 0x51;
+   report->field[0]->value[2] = weak;
+   report->field[0]->value[4] = strong;
 
-   hid_hw_request(hid, lg2ff->report, HID_REQ_SET_REPORT);
+   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
return 0;
 }
 
+static int hid_lg2ff_stop_rumble(struct hid_device *hid, struct hid_report 
*report)
+{
+   report->field[0]->value[0] = 0xf3;
+   report->field[0]->value[2] = 0x00;
+   report->field[0]->value[4] = 0x00;
+
+   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   return 0;
+}
+
+static int hid_lg2ff_control(struct input_dev *dev, void *data,
+   const struct mlnx_effect_command *command)
+{
+   struct hid_device *hid = input_get_drvdata(dev);
+   struct lg2ff_device *lg2ff = data;
+
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   return hid_lg2ff_start_rumble(hid, lg2ff->report, 
&command->u.rumble_force);
+   break;
+   case MLNX_STOP_RUMBLE:
+   return hid_lg2ff_stop_rumble(hid, lg2ff->report);
+   break;
+   default:
+   dbg_hid("Unsupported effect command");
+   return -EINVAL;
+   }
+}
+
 int lg2ff_init(struct hid_device *hid)
 {
struct lg2ff_device *lg2ff;
@@ -78,7 +105,7 @@ int lg2ff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, lg2ff, play_effect);
+   error = input_ff_create_mlnx(dev, lg2ff, hid_lg2ff_control, 
FF_UPDATE_RATE);
if (error) {
kfree(lg2ff);
return error;
-- 
1.9.2

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


[PATCH v4 23/24] hid: Port hid-lg4ff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-lg4ff to ff-memless-next

Signed-off-by: Michal Malý 
Tested-by: Tested-by: Elias Vanderstuyft 
---
 drivers/hid/Kconfig |  2 +-
 drivers/hid/hid-lg4ff.c | 93 ++---
 2 files changed, 59 insertions(+), 36 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 5e70519..546ac4a 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -399,7 +399,7 @@ config LOGIG940_FF
 config LOGIWHEELS_FF
bool "Logitech wheels configuration and force feedback support"
depends on HID_LOGITECH
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
default LOGITECH_FF
help
  Say Y here if you want to enable force feedback and range setting
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 24883b4..d629093 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -25,6 +25,7 @@
 
 
 #include 
+#include 
 #include 
 #include 
 
@@ -45,6 +46,8 @@
 #define G27_REV_MIN 0x38
 #define G27_2_REV_MIN 0x39
 
+#define FF_UPDATE_RATE 8
+
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
@@ -69,6 +72,13 @@ struct lg4ff_device_entry {
 
 static const signed short lg4ff_wheel_effects[] = {
FF_CONSTANT,
+   FF_RAMP,
+   FF_PERIODIC,
+   FF_SQUARE,
+   FF_TRIANGLE,
+   FF_SINE,
+   FF_SAW_UP,
+   FF_SAW_DOWN,
FF_AUTOCENTER,
-1
 };
@@ -184,47 +194,60 @@ int lg4ff_adjust_input_event(struct hid_device *hid, 
struct hid_field *field,
}
 }
 
-static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect 
*effect)
+static int hid_lg4ff_start_combined(struct hid_device *hid, struct hid_report 
*report,
+   const struct mlnx_simple_force *force)
+{
+   __s32 *value = report->field[0]->value;
+   int scaled_x;
+
+   /* Scale down from MLNX range */
+   scaled_x = 0x80 - (force->x * 0xff / 0x);
+
+   value[0] = 0x11;/* Slot 1 */
+   value[1] = 0x08;
+   value[2] = scaled_x;
+   value[3] = 0x80;
+   value[4] = 0x00;
+   value[5] = 0x00;
+   value[6] = 0x00;
+
+   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   return 0;
+}
+
+static int hid_lg4ff_stop_combined(struct hid_device *hid, struct hid_report 
*report)
+{
+   __s32 *value = report->field[0]->value;
+
+   value[0] = 0x13;/* Slot 1 */
+   value[1] = 0x00;
+   value[2] = 0x00;
+   value[3] = 0x00;
+   value[4] = 0x00;
+   value[5] = 0x00;
+   value[6] = 0x00;
+
+   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   return 0;
+}
+
+static int hid_lg4ff_control(struct input_dev *dev, void *data, const struct 
mlnx_effect_command *command)
 {
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
-   __s32 *value = report->field[0]->value;
-   int x;
-
-#define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while 
(0)
-
-   switch (effect->type) {
-   case FF_CONSTANT:
-   x = effect->u.ramp.start_level + 0x80;  /* 0x80 is no force */
-   CLAMP(x);
-
-   if (x == 0x80) {
-   /* De-activate force in slot-1*/
-   value[0] = 0x13;
-   value[1] = 0x00;
-   value[2] = 0x00;
-   value[3] = 0x00;
-   value[4] = 0x00;
-   value[5] = 0x00;
-   value[6] = 0x00;
-
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
-   return 0;
-   }
-
-   value[0] = 0x11;/* Slot 1 */
-   value[1] = 0x08;
-   value[2] = x;
-   value[3] = 0x80;
-   value[4] = 0x00;
-   value[5] = 0x00;
-   value[6] = 0x00;
 
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   switch (command->cmd) {
+   case MLNX_START_COMBINED:
+   return hid_lg4ff_start_combined(hid, report, 
&command->u.simple_force);
+   break;
+   case MLNX_STOP_COMBINED:
+   return hid_lg4ff_stop_combined(hid, report);
break;
+   default:
+   dbg_hid("Unsupported effect command");
+   return -EINVAL;
}
-   return 0;
 }
 
 /* Sends default autocentering command compatible with
@@ -610,7 +633,7 @@ int lg4ff_init(struct hid_device *hid)
for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++)
set_bit(lg4ff_devices[i].ff_

[PATCH v4 02/24] input: Port arizona-haptics to ff-memless-next

2014-04-26 Thread Michal Malý
Port arizona-haptics to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/misc/Kconfig   |  2 +-
 drivers/input/misc/arizona-haptics.c | 39 +++-
 2 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 5928ea7..f669cc7 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -75,7 +75,7 @@ config INPUT_AD714X_SPI
 config INPUT_ARIZONA_HAPTICS
tristate "Arizona haptics support"
depends on MFD_ARIZONA && SND_SOC
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  Say Y to enable support for the haptics module in Arizona CODECs.
 
diff --git a/drivers/input/misc/arizona-haptics.c 
b/drivers/input/misc/arizona-haptics.c
index ef2e281..b4707cc 100644
--- a/drivers/input/misc/arizona-haptics.c
+++ b/drivers/input/misc/arizona-haptics.c
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -22,6 +23,8 @@
 #include 
 #include 
 
+#define FF_UPDATE_RATE 50
+
 struct arizona_haptics {
struct arizona *arizona;
struct input_dev *input_dev;
@@ -108,29 +111,37 @@ static void arizona_haptics_work(struct work_struct *work)
 }
 
 static int arizona_haptics_play(struct input_dev *input, void *data,
-   struct ff_effect *effect)
+   const struct mlnx_effect_command *command)
 {
struct arizona_haptics *haptics = input_get_drvdata(input);
struct arizona *arizona = haptics->arizona;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
 
if (!arizona->dapm) {
dev_err(arizona->dev, "No DAPM context\n");
return -EBUSY;
}
 
-   if (effect->u.rumble.strong_magnitude) {
-   /* Scale the magnitude into the range the device supports */
-   if (arizona->pdata.hap_act) {
-   haptics->intensity =
-   effect->u.rumble.strong_magnitude >> 9;
-   if (effect->direction < 0x8000)
-   haptics->intensity += 0x7f;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   if (rumble_force->strong) {
+   /* Scale the magnitude into the range the device 
supports */
+   if (arizona->pdata.hap_act) {
+   haptics->intensity = rumble_force->strong >> 9;
+   if (rumble_force->strong_dir < 0x8000)
+   haptics->intensity += 0x7f;
+   } else {
+   haptics->intensity = rumble_force->strong >> 8;
+   }
} else {
-   haptics->intensity =
-   effect->u.rumble.strong_magnitude >> 8;
+   haptics->intensity = 0;
}
-   } else {
+   break;
+   case MLNX_STOP_RUMBLE:
haptics->intensity = 0;
+   break;
+   default:
+   return -EINVAL;
}
 
schedule_work(&haptics->work);
@@ -183,10 +194,10 @@ static int arizona_haptics_probe(struct platform_device 
*pdev)
haptics->input_dev->close = arizona_haptics_close;
__set_bit(FF_RUMBLE, haptics->input_dev->ffbit);
 
-   ret = input_ff_create_memless(haptics->input_dev, NULL,
- arizona_haptics_play);
+   ret = input_ff_create_mlnx(haptics->input_dev, NULL,
+  arizona_haptics_play, FF_UPDATE_RATE);
if (ret < 0) {
-   dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n",
+   dev_err(arizona->dev, "input_ff_create_mlnx() failed: %d\n",
ret);
goto err_ialloc;
}
-- 
1.9.2

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


[PATCH v4 24/24] input: Replace ff-memless with ff-memless-next

2014-04-26 Thread Michal Malý
Replace ff-memless with ff-memless-next

ff-memless-next is a module for handling force feedback devices that
have no FFB effect memory of their own. It is based on the ff-memless
module but it has been largerly extended. Notable changes include:
- Support for all force feedback effects currently defined by Microsoft
  DirectInput.
- Improved emulation of periodic and rumble effects in case either of
  those is not supported by a device.
- New kernel API to interface with HW-specific drivers.

Signed-off-by: Michal Malý 
---
 drivers/input/Kconfig  |  13 +-
 drivers/input/Makefile |   1 -
 drivers/input/ff-memless.c | 547 -
 include/linux/input.h  |   3 -
 4 files changed, 1 insertion(+), 563 deletions(-)
 delete mode 100644 drivers/input/ff-memless.c

diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 3780962..061ae3c 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -25,7 +25,7 @@ config INPUT
 
 if INPUT
 
-config INPUT_FF_MEMLESS
+config INPUT_FF_MEMLESS_NEXT
tristate "Support for memoryless force-feedback devices"
help
  Say Y here if you have memoryless force-feedback input device
@@ -36,17 +36,6 @@ config INPUT_FF_MEMLESS
  If unsure, say N.
 
  To compile this driver as a module, choose M here: the
- module will be called ff-memless.
-
-config INPUT_FF_MEMLESS_NEXT
-   tristate "New version of support for memoryless force-feedback devices"
-   help
- Say Y here to enable a new version of support for memoryless force
- feedback devices.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
  module will be called ff-memless-next.
 
 config INPUT_POLLDEV
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index b4f11f5..f7ae055 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -7,7 +7,6 @@
 obj-$(CONFIG_INPUT)+= input-core.o
 input-core-y := input.o input-compat.o input-mt.o ff-core.o
 
-obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
 obj-$(CONFIG_INPUT_FF_MEMLESS_NEXT)+= ff-memless-next.o
 obj-$(CONFIG_INPUT_POLLDEV)+= input-polldev.o
 obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
deleted file mode 100644
index 74c0d8c..000
--- a/drivers/input/ff-memless.c
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- *  Force feedback support for memoryless devices
- *
- *  Copyright (c) 2006 Anssi Hannula 
- *  Copyright (c) 2006 Dmitry Torokhov 
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* #define DEBUG */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Anssi Hannula ");
-MODULE_DESCRIPTION("Force feedback support for memoryless devices");
-
-/* Number of effects handled with memoryless devices */
-#define FF_MEMLESS_EFFECTS 16
-
-/* Envelope update interval in ms */
-#define FF_ENVELOPE_INTERVAL   50
-
-#define FF_EFFECT_STARTED  0
-#define FF_EFFECT_PLAYING  1
-#define FF_EFFECT_ABORTING 2
-
-struct ml_effect_state {
-   struct ff_effect *effect;
-   unsigned long flags;/* effect state (STARTED, PLAYING, etc) */
-   int count;  /* loop count of the effect */
-   unsigned long play_at;  /* start time */
-   unsigned long stop_at;  /* stop time */
-   unsigned long adj_at;   /* last time the effect was sent */
-};
-
-struct ml_device {
-   void *private;
-   struct ml_effect_state states[FF_MEMLESS_EFFECTS];
-   int gain;
-   struct timer_list timer;
-   struct input_dev *dev;
-
-   int (*play_effect)(struct input_dev *dev, void *data,
-  struct ff_effect *effect);
-};
-
-static const struct ff_envelope *get_envelope(const struct ff_effect *effect)
-{
-   static const struct ff_envelope empty_envelope;
-
-   switch (effect->type) {
-   case FF_PERIODIC:
-   return &effect->u.periodic.envelope;
-
-   case FF_CONSTANT:
-   return &effect->u.constant.envelope;
-
-   defa

[PATCH v4 04/24] input: Port twl6040-vibra to ff-memless-next

2014-04-26 Thread Michal Malý
Port twl6040-vibra to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/misc/Kconfig |  2 +-
 drivers/input/misc/twl6040-vibra.c | 27 ++-
 2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 817156f..b9cbb91 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -417,7 +417,7 @@ config INPUT_TWL4030_VIBRA
 config INPUT_TWL6040_VIBRA
tristate "Support for TWL6040 Vibrator"
depends on TWL6040_CORE
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  This option enables support for TWL6040 Vibrator Driver.
 
diff --git a/drivers/input/misc/twl6040-vibra.c 
b/drivers/input/misc/twl6040-vibra.c
index 77dc23b..7440a74 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -30,12 +30,14 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 
 #define EFFECT_DIR_180_DEG 0x8000
+#define FF_UPDATE_RATE 50
 
 /* Recommended modulation index 85% */
 #define TWL6040_VIBRA_MOD  85
@@ -197,9 +199,10 @@ static void vibra_play_work(struct work_struct *work)
 }
 
 static int vibra_play(struct input_dev *input, void *data,
- struct ff_effect *effect)
+ const struct mlnx_effect_command *command)
 {
struct vibra_info *info = input_get_drvdata(input);
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int ret;
 
/* Do not allow effect, while the routing is set to use audio */
@@ -209,9 +212,23 @@ static int vibra_play(struct input_dev *input, void *data,
return -EBUSY;
}
 
-   info->weak_speed = effect->u.rumble.weak_magnitude;
-   info->strong_speed = effect->u.rumble.strong_magnitude;
-   info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   info->weak_speed = rumble_force->weak;
+   info->strong_speed = rumble_force->strong;
+   if (info->strong_speed >= info->weak_speed)
+   info->direction = rumble_force->strong_dir < 
EFFECT_DIR_180_DEG ? 1 : -1;
+   else
+   info->direction = rumble_force->weak_dir < 
EFFECT_DIR_180_DEG ? 1 : -1;
+   break;
+   case MLNX_STOP_RUMBLE:
+   info->weak_speed = 0;
+   info->strong_speed = 0;
+   info->direction = 1;
+   break;
+   default:
+   return -EINVAL;
+   }
 
ret = queue_work(info->workqueue, &info->play_work);
if (!ret) {
@@ -367,7 +384,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
info->input_dev->close = twl6040_vibra_close;
__set_bit(FF_RUMBLE, info->input_dev->ffbit);
 
-   ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
+   ret = input_ff_create_mlnx(info->input_dev, NULL, vibra_play, 
FF_UPDATE_RATE);
if (ret < 0) {
dev_err(info->dev, "couldn't register vibrator to FF\n");
goto err_ialloc;
-- 
1.9.2

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


[PATCH v4 03/24] input: Port twl4030-vibra to ff-memless-next

2014-04-26 Thread Michal Malý
Port twl4030-vibra to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/misc/Kconfig |  2 +-
 drivers/input/misc/twl4030-vibra.c | 31 +--
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index f669cc7..817156f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -407,7 +407,7 @@ config INPUT_TWL4030_VIBRA
tristate "Support for TWL4030 Vibrator"
depends on TWL4030_CORE
select MFD_TWL4030_AUDIO
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  This option enables support for TWL4030 Vibrator Driver.
 
diff --git a/drivers/input/misc/twl4030-vibra.c 
b/drivers/input/misc/twl4030-vibra.c
index 960ef2a..5274ad2 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -32,9 +32,11 @@
 #include 
 #include 
 #include 
+#include 
 
 /* MODULE ID2 */
 #define LEDEN  0x00
+#define FF_UPDATE_RATE 50
 
 /* ForceFeedback */
 #define EFFECT_DIR_180_DEG 0x8000 /* range is 0 - 0x */
@@ -134,14 +136,31 @@ static void vibra_play_work(struct work_struct *work)
 /*** Input/ForceFeedback ***/
 
 static int vibra_play(struct input_dev *input, void *data,
- struct ff_effect *effect)
+ const struct mlnx_effect_command *command)
 {
struct vibra_info *info = input_get_drvdata(input);
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
+
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   if (command->u.rumble_force.strong) {
+   info->speed = rumble_force->strong >> 8;
+   info->direction = rumble_force->strong_dir < 
EFFECT_DIR_180_DEG ?
+ 0 : 1;
+   } else {
+   info->speed = rumble_force->weak >> 9;
+   info->direction = rumble_force->weak_dir < 
EFFECT_DIR_180_DEG ?
+ 0 : 1;
+   }
+   break;
+   case MLNX_STOP_RUMBLE:
+   info->speed = 0;
+   info->direction = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
-   info->speed = effect->u.rumble.strong_magnitude >> 8;
-   if (!info->speed)
-   info->speed = effect->u.rumble.weak_magnitude >> 9;
-   info->direction = effect->direction < EFFECT_DIR_180_DEG ? 0 : 1;
schedule_work(&info->play_work);
return 0;
 }
@@ -227,7 +246,7 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
info->input_dev->close = twl4030_vibra_close;
__set_bit(FF_RUMBLE, info->input_dev->ffbit);
 
-   ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
+   ret = input_ff_create_mlnx(info->input_dev, NULL, vibra_play, 
FF_UPDATE_RATE);
if (ret < 0) {
dev_dbg(&pdev->dev, "couldn't register vibrator to FF\n");
return ret;
-- 
1.9.2

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


[PATCH v4 05/24] input: Port max8997_haptic to ff-memless-next

2014-04-26 Thread Michal Malý
Port max8997_haptic to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/misc/Kconfig  |  2 +-
 drivers/input/misc/max8997_haptic.c | 25 +++--
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index b9cbb91..a89dc22 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -157,7 +157,7 @@ config INPUT_MAX8925_ONKEY
 config INPUT_MAX8997_HAPTIC
tristate "MAXIM MAX8997 haptic controller support"
depends on PWM && MFD_MAX8997
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  This option enables device driver support for the haptic controller
  on MAXIM MAX8997 chip. This driver supports ff-memless interface
diff --git a/drivers/input/misc/max8997_haptic.c 
b/drivers/input/misc/max8997_haptic.c
index 1fea548..029ac8b 100644
--- a/drivers/input/misc/max8997_haptic.c
+++ b/drivers/input/misc/max8997_haptic.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Haptic configuration 2 register */
 #define MAX8997_MOTOR_TYPE_SHIFT   7
@@ -43,6 +44,8 @@
 #define MAX8997_SIG_DUTY_SHIFT 2
 #define MAX8997_PWM_DUTY_SHIFT 0
 
+#define FF_UPDATE_RATE 50
+
 struct max8997_haptic {
struct device *dev;
struct i2c_client *client;
@@ -219,13 +222,23 @@ static void max8997_haptic_play_effect_work(struct 
work_struct *work)
 }
 
 static int max8997_haptic_play_effect(struct input_dev *dev, void *data,
- struct ff_effect *effect)
+ const struct mlnx_effect_command *command)
 {
struct max8997_haptic *chip = input_get_drvdata(dev);
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
 
-   chip->level = effect->u.rumble.strong_magnitude;
-   if (!chip->level)
-   chip->level = effect->u.rumble.weak_magnitude;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   chip->level = rumble_force->strong;
+   if (!chip->level)
+   chip->level = rumble_force->weak;
+   break;
+   case MLNX_STOP_RUMBLE:
+   chip->level = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
schedule_work(&chip->work);
 
@@ -319,8 +332,8 @@ static int max8997_haptic_probe(struct platform_device 
*pdev)
input_set_drvdata(input_dev, chip);
input_set_capability(input_dev, EV_FF, FF_RUMBLE);
 
-   error = input_ff_create_memless(input_dev, NULL,
-   max8997_haptic_play_effect);
+   error = input_ff_create_mlnx(input_dev, NULL,
+   max8997_haptic_play_effect, FF_UPDATE_RATE);
if (error) {
dev_err(&pdev->dev,
"unable to create FF device, error: %d\n",
-- 
1.9.2

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


[PATCH v4 07/24] hid: Port hid-axff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-axff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-axff.c | 32 +++-
 2 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 7af9d0b..e076627 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -106,7 +106,7 @@ config HID_ACRUX
 config HID_ACRUX_FF
bool "ACRUX force feedback support"
depends on HID_ACRUX
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you want to enable force feedback support for ACRUX
game controllers.
diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c
index a594e47..7fbfcbc 100644
--- a/drivers/hid/hid-axff.c
+++ b/drivers/hid/hid-axff.c
@@ -31,31 +31,45 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
 #ifdef CONFIG_HID_ACRUX_FF
 
 struct axff_device {
struct hid_report *report;
 };
 
-static int axff_play(struct input_dev *dev, void *data, struct ff_effect 
*effect)
+static int axff_play(struct input_dev *dev, void *data,
+const struct mlnx_effect_command *command)
 {
struct hid_device *hid = input_get_drvdata(dev);
struct axff_device *axff = data;
struct hid_report *report = axff->report;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int field_count = 0;
int left, right;
int i, j;
 
-   left = effect->u.rumble.strong_magnitude;
-   right = effect->u.rumble.weak_magnitude;
-
-   dbg_hid("called with 0x%04x 0x%04x", left, right);
-
-   left = left * 0xff / 0x;
-   right = right * 0xff / 0x;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   left = rumble_force->strong;
+   right = rumble_force->weak;
+
+   dbg_hid("called with 0x%04x 0x%04x", left, right);
+
+   left = left * 0xff / 0x;
+   right = right * 0xff / 0x;
+   break;
+   case MLNX_STOP_RUMBLE:
+   left = 0;
+   right = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
for (i = 0; i < report->maxfield; i++) {
for (j = 0; j < report->field[i]->report_count; j++) {
@@ -107,7 +121,7 @@ static int axff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, axff, axff_play);
+   error = input_ff_create_mlnx(dev, axff, axff_play, FF_UPDATE_RATE);
if (error)
goto err_free_mem;
 
-- 
1.9.2

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


[PATCH v4 08/24] hid: Port hid-emsff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-emsff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig |  2 +-
 drivers/hid/hid-emsff.c | 38 ++
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e076627..a78b5d8 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -213,7 +213,7 @@ config DRAGONRISE_FF
 config HID_EMS_FF
tristate "EMS Production Inc. force feedback support"
depends on HID
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you want to enable force feedback support for devices by
EMS Production Ltd.
diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c
index d82d75b..c0cbe50 100644
--- a/drivers/hid/hid-emsff.c
+++ b/drivers/hid/hid-emsff.c
@@ -24,30 +24,44 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 struct emsff_device {
struct hid_report *report;
 };
 
 static int emsff_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 emsff_device *emsff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int weak, strong;
 
-   weak = effect->u.rumble.weak_magnitude;
-   strong = effect->u.rumble.strong_magnitude;
-
-   dbg_hid("called with 0x%04x 0x%04x\n", strong, weak);
-
-   weak = weak * 0xff / 0x;
-   strong = strong * 0xff / 0x;
-
-   emsff->report->field[0]->value[1] = weak;
-   emsff->report->field[0]->value[2] = strong;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   weak = rumble_force->weak;
+   strong = rumble_force->strong;
+
+   dbg_hid("called with 0x%04x 0x%04x\n", strong, weak);
+
+   weak = weak * 0xff / 0x;
+   strong = strong * 0xff / 0x;
+
+   emsff->report->field[0]->value[1] = weak;
+   emsff->report->field[0]->value[2] = strong;
+   break;
+   case MLNX_STOP_RUMBLE:
+   weak = 0;
+   strong = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
dbg_hid("running with 0x%02x 0x%02x\n", strong, weak);
hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
@@ -88,7 +102,7 @@ static int emsff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, emsff, emsff_play);
+   error = input_ff_create_mlnx(dev, emsff, emsff_play, FF_UPDATE_RATE);
if (error) {
kfree(emsff);
return error;
-- 
1.9.2

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


[PATCH v4 06/24] input: Port pm8xxx-vibrator to ff-memless-next

2014-04-26 Thread Michal Malý
Port pm8xxx-vibrator to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/misc/Kconfig   |  2 +-
 drivers/input/misc/pm8xxx-vibrator.c | 28 +++-
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index a89dc22..7b962e4 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -108,7 +108,7 @@ config INPUT_PCSPKR
 config INPUT_PM8XXX_VIBRATOR
tristate "Qualcomm PM8XXX vibrator support"
depends on MFD_PM8XXX
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  This option enables device driver support for the vibrator
  on Qualcomm PM8xxx chip. This driver supports ff-memless interface
diff --git a/drivers/input/misc/pm8xxx-vibrator.c 
b/drivers/input/misc/pm8xxx-vibrator.c
index 6a915ba..1796f4f 100644
--- a/drivers/input/misc/pm8xxx-vibrator.c
+++ b/drivers/input/misc/pm8xxx-vibrator.c
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define VIB_DRV0x4A
 
@@ -29,7 +30,7 @@
 #define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV)
 
 #define MAX_FF_SPEED   0xff
-
+#define FF_UPDATE_RATE 50
 /**
  * struct pm8xxx_vib - structure to hold vibrator data
  * @vib_input_dev: input device supporting force feedback
@@ -128,14 +129,23 @@ static void pm8xxx_vib_close(struct input_dev *dev)
  * Currently this driver supports only rumble effects.
  */
 static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,
- struct ff_effect *effect)
+ const struct mlnx_command *command)
 {
struct pm8xxx_vib *vib = input_get_drvdata(dev);
-
-   vib->speed = effect->u.rumble.strong_magnitude >> 8;
-   if (!vib->speed)
-   vib->speed = effect->u.rumble.weak_magnitude >> 9;
-
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
+
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   vib->speed = rumble_force->strong >> 8;
+   if (!vib->speed)
+   vib->speed = rumble_force->weak >> 9;
+   break;
+   case MLNX_STOP_RUMBLE:
+   vib->speed = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
schedule_work(&vib->work);
 
return 0;
@@ -181,8 +191,8 @@ static int pm8xxx_vib_probe(struct platform_device *pdev)
input_set_drvdata(input_dev, vib);
input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE);
 
-   error = input_ff_create_memless(input_dev, NULL,
-   pm8xxx_vib_play_effect);
+   error = input_ff_create_mlnx(input_dev, NULL,
+pm8xxx_vib_play_effect, FF_UPDATE_RATE);
if (error) {
dev_err(&pdev->dev,
"couldn't register vibrator as FF device\n");
-- 
1.9.2

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


[PATCH v4 09/24] hid: Port hid-dr to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-dr to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig  |  2 +-
 drivers/hid/hid-dr.c | 59 
 2 files changed, 37 insertions(+), 24 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index a78b5d8..1d4180c 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -205,7 +205,7 @@ config HID_DRAGONRISE
 config DRAGONRISE_FF
bool "DragonRise Inc. force feedback"
depends on HID_DRAGONRISE
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you want to enable force feedback support for DragonRise 
Inc.
game controllers.
diff --git a/drivers/hid/hid-dr.c b/drivers/hid/hid-dr.c
index ce06444..b95c676 100644
--- a/drivers/hid/hid-dr.c
+++ b/drivers/hid/hid-dr.c
@@ -31,8 +31,10 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
+#define FF_UPDATE_RATE 50
 
 #ifdef CONFIG_DRAGONRISE_FF
 
@@ -41,38 +43,49 @@ struct drff_device {
 };
 
 static int drff_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 drff_device *drff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int strong, weak;
 
-   strong = effect->u.rumble.strong_magnitude;
-   weak = effect->u.rumble.weak_magnitude;
+   strong = rumble_force->strong;
+   weak = rumble_force->weak;
 
dbg_hid("called with 0x%04x 0x%04x", strong, weak);
 
-   if (strong || weak) {
-   strong = strong * 0xff / 0x;
-   weak = weak * 0xff / 0x;
-
-   /* While reverse engineering this device, I found that when
-  this value is set, it causes the strong rumble to function
-  at a near maximum speed, so we'll bypass it. */
-   if (weak == 0x0a)
-   weak = 0x0b;
-
-   drff->report->field[0]->value[0] = 0x51;
-   drff->report->field[0]->value[1] = 0x00;
-   drff->report->field[0]->value[2] = weak;
-   drff->report->field[0]->value[4] = strong;
-   hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
-
-   drff->report->field[0]->value[0] = 0xfa;
-   drff->report->field[0]->value[1] = 0xfe;
-   } else {
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   if (strong || weak) {
+   strong = strong * 0xff / 0x;
+   weak = weak * 0xff / 0x;
+
+   /* While reverse engineering this device, I found that 
when
+   this value is set, it causes the strong rumble to 
function
+   at a near maximum speed, so we'll bypass it. */
+   if (weak == 0x0a)
+   weak = 0x0b;
+
+   drff->report->field[0]->value[0] = 0x51;
+   drff->report->field[0]->value[1] = 0x00;
+   drff->report->field[0]->value[2] = weak;
+   drff->report->field[0]->value[4] = strong;
+   hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
+
+   drff->report->field[0]->value[0] = 0xfa;
+   drff->report->field[0]->value[1] = 0xfe;
+   } else {
+   drff->report->field[0]->value[0] = 0xf3;
+   drff->report->field[0]->value[1] = 0x00;
+   }
+   break;
+   case MLNX_STOP_RUMBLE:
drff->report->field[0]->value[0] = 0xf3;
drff->report->field[0]->value[1] = 0x00;
+   break;
+   default:
+   return -EINVAL;
}
 
drff->report->field[0]->value[2] = 0x00;
@@ -116,7 +129,7 @@ static int drff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, drff, drff_play);
+   error = input_ff_create_mlnx(dev, drff, drff_play, FF_UPDATE_RATE);
if (error) {
kfree(drff);
return error;
-- 
1.9.2

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


[PATCH v4 10/24] hid: Port hid-gaff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-gaff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-gaff.c | 32 +++-
 2 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 1d4180c..4c59a88 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -667,7 +667,7 @@ config HID_GREENASIA
 config GREENASIA_FF
bool "GreenAsia (Product ID 0x12) force feedback support"
depends on HID_GREENASIA
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you have a GreenAsia (Product ID 0x12) based game 
controller
(like MANTA Warrior MM816 and SpeedLink Strike2 SL-6635) or adapter
diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c
index 2d8cead..f2f70c1 100644
--- a/drivers/hid/hid-gaff.c
+++ b/drivers/hid/hid-gaff.c
@@ -31,8 +31,11 @@
 #include 
 #include 
 #include 
+#include 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 #ifdef CONFIG_GREENASIA_FF
 
 struct gaff_device {
@@ -40,19 +43,30 @@ struct gaff_device {
 };
 
 static int hid_gaff_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 gaff_device *gaff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int left, right;
 
-   left = effect->u.rumble.strong_magnitude;
-   right = effect->u.rumble.weak_magnitude;
-
-   dbg_hid("called with 0x%04x 0x%04x", left, right);
-
-   left = left * 0xfe / 0x;
-   right = right * 0xfe / 0x;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   left = rumble_force->strong;
+   right = rumble_force->weak;
+
+   dbg_hid("called with 0x%04x 0x%04x", left, right);
+
+   left = left * 0xfe / 0x;
+   right = right * 0xfe / 0x;
+   break;
+   case MLNX_STOP_RUMBLE:
+   left = 0;
+   right = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
gaff->report->field[0]->value[0] = 0x51;
gaff->report->field[0]->value[1] = 0x0;
@@ -109,7 +123,7 @@ static int gaff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, gaff, hid_gaff_play);
+   error = input_ff_create_mlnx(dev, gaff, hid_gaff_play, FF_UPDATE_RATE);
if (error) {
kfree(gaff);
return error;
-- 
1.9.2

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


[PATCH v4 11/24] hid: Port hid-holtekff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-holtekff to ff-memless-next

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

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 4c59a88..1749a4a 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -256,7 +256,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 
 #include 
 #include 
+#include 
 
 #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;
-- 
1.9.2

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


[PATCH v4 12/24] hid: Port hid-lgff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-lgff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-lgff.c | 70 +++---
 2 files changed, 51 insertions(+), 21 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 1749a4a..c4b0cbb 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -365,7 +365,7 @@ config HID_LOGITECH_DJ
 config LOGITECH_FF
bool "Logitech force feedback support"
depends on HID_LOGITECH
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  Say Y here if you have one of these devices:
  - Logitech WingMan Cordless RumblePad
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index e1394af..40ad68a 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -31,9 +31,12 @@
 
 #include 
 #include 
+#include 
 
 #include "hid-lg.h"
 
+#define FF_UPDATE_RATE 50
+
 struct dev_type {
u16 idVendor;
u16 idProduct;
@@ -47,11 +50,25 @@ static const signed short ff_rumble[] = {
 
 static const signed short ff_joystick[] = {
FF_CONSTANT,
+   FF_RAMP,
+   FF_PERIODIC,
+   FF_SQUARE,
+   FF_TRIANGLE,
+   FF_SINE,
+   FF_SAW_UP,
+   FF_SAW_DOWN,
-1
 };
 
 static const signed short ff_joystick_ac[] = {
FF_CONSTANT,
+   FF_RAMP,
+   FF_PERIODIC,
+   FF_SQUARE,
+   FF_TRIANGLE,
+   FF_SINE,
+   FF_SAW_UP,
+   FF_SAW_DOWN,
FF_AUTOCENTER,
-1
 };
@@ -66,45 +83,58 @@ static const struct dev_type devices[] = {
{ 0x046d, 0xc295, ff_joystick },
 };
 
-static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect 
*effect)
+static int hid_lgff_play(struct input_dev *dev, void *data,
+const struct mlnx_effect_command *command)
 {
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
-   int x, y;
-   unsigned int left, right;
 
-#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
+   switch (command->cmd) {
+   case MLNX_START_COMBINED: {
+   const struct mlnx_simple_force *simple_force = 
&command->u.simple_force;
+   /* Scale down from MLNX range */
+   const int x = 0x80 - (simple_force->x * 0xff / 0x);
+   const int y = 0x80 - (simple_force->y * 0xff / 0x);
 
-   switch (effect->type) {
-   case FF_CONSTANT:
-   x = effect->u.ramp.start_level + 0x7f;  /* 0x7f is center */
-   y = effect->u.ramp.end_level + 0x7f;
-   CLAMP(x);
-   CLAMP(y);
report->field[0]->value[0] = 0x51;
report->field[0]->value[1] = 0x08;
report->field[0]->value[2] = x;
report->field[0]->value[3] = y;
dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
+   }
+   case MLNX_STOP_COMBINED:
+   report->field[0]->value[0] = 0x51;
+   report->field[0]->value[1] = 0x08;
+   report->field[0]->value[2] = 0x80;
+   report->field[0]->value[3] = 0x80;
+   break;
+   case MLNX_START_RUMBLE: {
+   const struct mlnx_rumble_force *rumble_force = 
&command->u.rumble_force;
+   /* Scale down from MLNX range */
+   const unsigned int right = rumble_force->weak * 0xff / 0x;
+   const unsigned int left = rumble_force->strong * 0xff / 0x;
 
-   case FF_RUMBLE:
-   right = effect->u.rumble.strong_magnitude;
-   left = effect->u.rumble.weak_magnitude;
-   right = right * 0xff / 0x;
-   left = left * 0xff / 0x;
-   CLAMP(left);
-   CLAMP(right);
report->field[0]->value[0] = 0x42;
report->field[0]->value[1] = 0x00;
report->field[0]->value[2] = left;
report->field[0]->value[3] = right;
dbg_hid("(left, right)=(%04x, %04x)\n", left, right);
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
}
+   case MLNX_STOP_RUMBLE:
+   report->field[0]->value[0] = 0x42;
+   report->field[0]->value[1] = 0x00;
+   report->field[0]->value[2] = 0;
+   report->field[0]->value[3] = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   hid_hw_request(hid, report, HID_REQ_SET_RE

[PATCH v4 13/24] hid: Port hid-lg3ff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-lg3ff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig |  2 +-
 drivers/hid/hid-lg3ff.c | 60 +++--
 2 files changed, 39 insertions(+), 23 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index c4b0cbb..eb0c7f1 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -391,7 +391,7 @@ config LOGIRUMBLEPAD2_FF
 config LOGIG940_FF
bool "Logitech Flight System G940 force feedback support"
depends on HID_LOGITECH
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  Say Y here if you want to enable force feedback support for Logitech
  Flight System G940 devices.
diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c
index 8c2da18..c49b374 100644
--- a/drivers/hid/hid-lg3ff.c
+++ b/drivers/hid/hid-lg3ff.c
@@ -23,9 +23,12 @@
 
 #include 
 #include 
+#include 
 
 #include "hid-lg.h"
 
+#define FF_UPDATE_RATE 50
+
 /*
  * G940 Theory of Operation (from experimentation)
  *
@@ -58,12 +61,11 @@ struct lg3ff_device {
 };
 
 static int hid_lg3ff_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 list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
-   int x, y;
 
 /*
  * Available values in the field should always be 63, but we only use up to
@@ -72,30 +74,37 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data,
memset(report->field[0]->value, 0,
   sizeof(__s32) * report->field[0]->report_count);
 
-   switch (effect->type) {
-   case FF_CONSTANT:
-/*
- * Already clamped in ff_memless
- * 0 is center (different then other logitech)
- */
-   x = effect->u.ramp.start_level;
-   y = effect->u.ramp.end_level;
-
-   /* send command byte */
-   report->field[0]->value[0] = 0x51;
-
-/*
- * Sign backwards from other Force3d pro
- * which get recast here in two's complement 8 bits
- */
-   report->field[0]->value[1] = (unsigned char)(-x);
-   report->field[0]->value[31] = (unsigned char)(-y);
+   /* send command byte */
+   report->field[0]->value[0] = 0x51;
 
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   switch (command->cmd) {
+   case MLNX_START_COMBINED: {
+   const struct mlnx_simple_force *simple_force = 
&command->u.simple_force;
+   /* Scale down from MLNX range */
+   const int x = simple_force->x * 0xff / 0x;
+   const int y = simple_force->y * 0xff / 0x;
+
+   /*
+* Sign backwards from other Force3d pro
+* which get recast here in two's complement 8 bits
+   */
+   report->field[0]->value[1] = (unsigned char)x;
+   report->field[0]->value[31] = (unsigned char)y;
+   break;
+   }
+   case MLNX_STOP_COMBINED:
+   report->field[0]->value[1] = 0;
+   report->field[0]->value[31] = 0;
break;
+   default:
+   return -EINVAL;
}
+
+   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+
return 0;
 }
+
 static void hid_lg3ff_set_autocenter(struct input_dev *dev, u16 magnitude)
 {
struct hid_device *hid = input_get_drvdata(dev);
@@ -123,6 +132,13 @@ static void hid_lg3ff_set_autocenter(struct input_dev 
*dev, u16 magnitude)
 
 static const signed short ff3_joystick_ac[] = {
FF_CONSTANT,
+   FF_RAMP,
+   FF_PERIODIC,
+   FF_SQUARE,
+   FF_TRIANGLE,
+   FF_SINE,
+   FF_SAW_UP,
+   FF_SAW_DOWN,
FF_AUTOCENTER,
-1
 };
@@ -143,7 +159,7 @@ int lg3ff_init(struct hid_device *hid)
for (i = 0; ff_bits[i] >= 0; i++)
set_bit(ff_bits[i], dev->ffbit);
 
-   error = input_ff_create_memless(dev, NULL, hid_lg3ff_play);
+   error = input_ff_create_mlnx(dev, NULL, hid_lg3ff_play, FF_UPDATE_RATE);
if (error)
return error;
 
-- 
1.9.2

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


[PATCH v4 14/24] hid: Port hid-pl to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-pl to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig  |  2 +-
 drivers/hid/hid-pl.c | 38 ++
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index eb0c7f1..42904e4 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -509,7 +509,7 @@ config HID_PANTHERLORD
 config PANTHERLORD_FF
bool "Pantherlord force feedback support"
depends on HID_PANTHERLORD
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
  Say Y here if you have a PantherLord/GreenAsia based game controller
  or adapter and want to enable force feedback support for it.
diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c
index 2dcd7d9..9b539d5 100644
--- a/drivers/hid/hid-pl.c
+++ b/drivers/hid/hid-pl.c
@@ -44,9 +44,12 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 #ifdef CONFIG_PANTHERLORD_FF
 
 struct plff_device {
@@ -57,24 +60,35 @@ struct plff_device {
 };
 
 static int hid_plff_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 plff_device *plff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int left, right;
 
-   left = effect->u.rumble.strong_magnitude;
-   right = effect->u.rumble.weak_magnitude;
-   debug("called with 0x%04x 0x%04x", left, right);
-
-   left = left * plff->maxval / 0x;
-   right = right * plff->maxval / 0x;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   left = rumble_force->strong;
+   right = rumble_force->weak;
+   debug("called with 0x%04x 0x%04x", left, right);
+
+   left = left * plff->maxval / 0x;
+   right = right * plff->maxval / 0x;
+
+   *plff->strong = left;
+   *plff->weak = right;
+   debug("running with 0x%02x 0x%02x", left, right);
+   break;
+   case MLNX_STOP_RUMBLE:
+   *plff->strong = 0;
+   *plff->weak = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
-   *plff->strong = left;
-   *plff->weak = right;
-   debug("running with 0x%02x 0x%02x", left, right);
hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT);
-
return 0;
 }
 
@@ -160,7 +174,7 @@ static int plff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, plff, hid_plff_play);
+   error = input_ff_create_mlnx(dev, plff, hid_plff_play, 
FF_UPDATE_RATE);
if (error) {
kfree(plff);
return error;
-- 
1.9.2

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


[PATCH v4 16/24] hid: Port hid-sony to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-sony to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-sony.c | 23 +--
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 9260d14..e97c382 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -634,7 +634,7 @@ config HID_SONY
 config SONY_FF
bool "Sony PS2/3/4 accessories force feedback support" 
depends on HID_SONY
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you have a Sony PS2/3/4 accessory and want to enable
force feedback support for it.
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 908de27..5a28833 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -34,6 +34,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
@@ -53,6 +54,7 @@
 #define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)
 #define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)
 
+#define FF_UPDATE_RATE 50
 #define MAX_LEDS 4
 
 static const u8 sixaxis_rdesc_fixup[] = {
@@ -1308,16 +1310,25 @@ static void dualshock4_state_worker(struct work_struct 
*work)
 
 #ifdef CONFIG_SONY_FF
 static int sony_play_effect(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 sony_sc *sc = hid_get_drvdata(hid);
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
 
-   if (effect->type != FF_RUMBLE)
-   return 0;
 
-   sc->left = effect->u.rumble.strong_magnitude / 256;
-   sc->right = effect->u.rumble.weak_magnitude / 256;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   sc->left = rumble_force->strong / 256;
+   sc->right = rumble_force->weak / 256;
+   break;
+   case MLNX_STOP_RUMBLE:
+   sc->left = 0;
+   sc->right = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
schedule_work(&sc->state_worker);
return 0;
@@ -1330,7 +1341,7 @@ static int sony_init_ff(struct hid_device *hdev)
struct input_dev *input_dev = hidinput->input;
 
input_set_capability(input_dev, EV_FF, FF_RUMBLE);
-   return input_ff_create_memless(input_dev, NULL, sony_play_effect);
+   return input_ff_create_mlnx(input_dev, NULL, sony_play_effect, 
FF_UPDATE_RATE);
 }
 
 #else
-- 
1.9.2

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


[PATCH v4 15/24] hid: Port hid-sjoy to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-sjoy to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-sjoy.c | 35 +--
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 42904e4..9260d14 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -692,7 +692,7 @@ config HID_SMARTJOYPLUS
 config SMARTJOYPLUS_FF
bool "SmartJoy PLUS PS2/USB adapter force feedback support"
depends on HID_SMARTJOYPLUS
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you have a SmartJoy PLUS PS2/USB adapter and want to
enable force feedback support for it.
diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c
index 37845ec..a6f8cfe 100644
--- a/drivers/hid/hid-sjoy.c
+++ b/drivers/hid/hid-sjoy.c
@@ -30,8 +30,11 @@
 #include 
 #include 
 #include 
+#include 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 #ifdef CONFIG_SMARTJOYPLUS_FF
 
 struct sjoyff_device {
@@ -39,21 +42,33 @@ struct sjoyff_device {
 };
 
 static int hid_sjoyff_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 sjoyff_device *sjoyff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
u32 left, right;
 
-   left = effect->u.rumble.strong_magnitude;
-   right = effect->u.rumble.weak_magnitude;
-   dev_dbg(&dev->dev, "called with 0x%08x 0x%08x\n", left, right);
-
-   left = left * 0xff / 0x;
-   right = (right != 0); /* on/off only */
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   left = rumble_force->strong;
+   right = rumble_force->weak;
+   dev_dbg(&dev->dev, "called with 0x%08x 0x%08x\n", left, right);
+
+   left = left * 0xff / 0x;
+   right = (right != 0); /* on/off only */
+
+   sjoyff->report->field[0]->value[1] = right;
+   sjoyff->report->field[0]->value[2] = left;
+   break;
+   case MLNX_STOP_RUMBLE:
+   left = 0;
+   right = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
-   sjoyff->report->field[0]->value[1] = right;
-   sjoyff->report->field[0]->value[2] = left;
dev_dbg(&dev->dev, "running with 0x%02x 0x%02x\n", left, right);
hid_hw_request(hid, sjoyff->report, HID_REQ_SET_REPORT);
 
@@ -103,7 +118,7 @@ static int sjoyff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
+   error = input_ff_create_mlnx(dev, sjoyff, hid_sjoyff_play, 
FF_UPDATE_RATE);
if (error) {
kfree(sjoyff);
return error;
-- 
1.9.2

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


[PATCH v4 17/24] hid: Port hid-tmff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-tmff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-tmff.c | 83 ++
 2 files changed, 51 insertions(+), 34 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e97c382..17ed5cf 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -730,7 +730,7 @@ config HID_THRUSTMASTER
 config THRUSTMASTER_FF
bool "ThrustMaster devices force feedback support"
depends on HID_THRUSTMASTER
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
  Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or 3,
  a THRUSTMASTER Dual Trigger 3-in-1 or a THRUSTMASTER Ferrari GT
diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c
index b833760..3df000c 100644
--- a/drivers/hid/hid-tmff.c
+++ b/drivers/hid/hid-tmff.c
@@ -31,9 +31,12 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 static const signed short ff_rumble[] = {
FF_RUMBLE,
-1
@@ -41,6 +44,13 @@ static const signed short ff_rumble[] = {
 
 static const signed short ff_joystick[] = {
FF_CONSTANT,
+   FF_RAMP,
+   FF_PERIODIC,
+   FF_SINE,
+   FF_SQUARE,
+   FF_TRIANGLE,
+   FF_SAW_DOWN,
+   FF_SAW_UP,
-1
 };
 
@@ -67,12 +77,12 @@ static inline int tmff_scale_u16(unsigned int in, int 
minimum, int maximum)
return ret;
 }
 
-/* Changes values from -0x80 to 0x7f into values from minimum to maximum */
-static inline int tmff_scale_s8(int in, int minimum, int maximum)
+/* Changes values from -0x7fff to 0x7fff into values from minimum to maximum */
+static inline int tmff_scale_s32(int in, int minimum, int maximum)
 {
int ret;
 
-   ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum;
+   ret = (((in + 0x7fff) * (maximum - minimum)) / 0x) + minimum;
if (ret < minimum)
return minimum;
if (ret > maximum)
@@ -81,43 +91,50 @@ static inline int tmff_scale_s8(int in, int minimum, int 
maximum)
 }
 
 static int tmff_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 tmff_device *tmff = data;
struct hid_field *ff_field = tmff->ff_field;
int x, y;
-   int left, right;/* Rumbling */
-
-   switch (effect->type) {
-   case FF_CONSTANT:
-   x = tmff_scale_s8(effect->u.ramp.start_level,
-   ff_field->logical_minimum,
-   ff_field->logical_maximum);
-   y = tmff_scale_s8(effect->u.ramp.end_level,
-   ff_field->logical_minimum,
-   ff_field->logical_maximum);
-
-   dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
-   ff_field->value[0] = x;
-   ff_field->value[1] = y;
-   hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
-   break;
 
-   case FF_RUMBLE:
-   left = tmff_scale_u16(effect->u.rumble.weak_magnitude,
-   ff_field->logical_minimum,
-   ff_field->logical_maximum);
-   right = tmff_scale_u16(effect->u.rumble.strong_magnitude,
-   ff_field->logical_minimum,
-   ff_field->logical_maximum);
-
-   dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
-   ff_field->value[0] = left;
-   ff_field->value[1] = right;
-   hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
+   switch (command->cmd) {
+   case MLNX_START_COMBINED: {
+   const struct mlnx_simple_force *sf = &command->u.simple_force;
+   x = tmff_scale_s32(sf->x,
+  ff_field->logical_minimum,
+  ff_field->logical_maximum);
+   y = tmff_scale_s32(sf->y,
+  ff_field->logical_minimum,
+  ff_field->logical_maximum);
+   break;
+   }
+   case MLNX_STOP_COMBINED:
+   x = 0;
+   y = 0;
+   break;
+   case MLNX_START_RUMBLE: {
+   const struct mlnx_rumble_force *rumble_force = 
&command->u.rumble_force;
+   x = tmff_scale_u16(rumble_force->weak,
+  ff_field->logical_minimum,
+  ff_field->logical_maximum);
+   y = tmff_scal

[PATCH v4 19/24] hid: Port hid-zpff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-zpff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-zpff.c | 30 ++
 2 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 23d9776..97d2d8f 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -786,7 +786,7 @@ config HID_ZEROPLUS
 config ZEROPLUS_FF
bool "Zeroplus based game controller force feedback support"
depends on HID_ZEROPLUS
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
  Say Y here if you have a Zeroplus based game controller and want
  to have force feedback support for it.
diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c
index a29756c..6912500 100644
--- a/drivers/hid/hid-zpff.c
+++ b/drivers/hid/hid-zpff.c
@@ -25,9 +25,12 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 #ifdef CONFIG_ZEROPLUS_FF
 
 struct zpff_device {
@@ -35,10 +38,11 @@ struct zpff_device {
 };
 
 static int zpff_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 zpff_device *zpff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int left, right;
 
/*
@@ -47,12 +51,22 @@ static int zpff_play(struct input_dev *dev, void *data,
 * however it is possible that the XFX Executioner is an exception
 */
 
-   left = effect->u.rumble.strong_magnitude;
-   right = effect->u.rumble.weak_magnitude;
-   dbg_hid("called with 0x%04x 0x%04x\n", left, right);
-
-   left = left * 0x7f / 0x;
-   right = right * 0x7f / 0x;
+   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);
+
+   left = left * 0x7f / 0x;
+   right = right * 0x7f / 0x;
+   break;
+   case MLNX_STOP_RUMBLE:
+   left = 0;
+   right = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
zpff->report->field[2]->value[0] = left;
zpff->report->field[3]->value[0] = right;
@@ -83,7 +97,7 @@ static int zpff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, zpff, zpff_play);
+   error = input_ff_create_mlnx(dev, zpff, zpff_play, FF_UPDATE_RATE);
if (error) {
kfree(zpff);
return error;
-- 
1.9.2

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


[PATCH v4 18/24] hid: Port hid-wiimote-modules to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-wiimote-modules to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig   |  2 +-
 drivers/hid/hid-wiimote-modules.c | 74 ---
 2 files changed, 46 insertions(+), 30 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 17ed5cf..23d9776 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -749,7 +749,7 @@ config HID_WIIMOTE
depends on HID
depends on LEDS_CLASS
select POWER_SUPPLY
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Support for Nintendo Wii and Wii U Bluetooth peripherals. Supported
devices are the Wii Remote and its extension devices, but also devices
diff --git a/drivers/hid/hid-wiimote-modules.c 
b/drivers/hid/hid-wiimote-modules.c
index 6b61f01..95b20ea 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -37,8 +37,11 @@
 #include 
 #include 
 #include 
+#include 
 #include "hid-wiimote.h"
 
+#define FF_UPDATE_RATE 50
+
 /*
  * Keys
  * The initial Wii Remote provided a bunch of buttons that are reported as
@@ -131,21 +134,27 @@ static void wiimod_rumble_worker(struct work_struct *work)
 }
 
 static int wiimod_rumble_play(struct input_dev *dev, void *data,
- struct ff_effect *eff)
+ const struct mlnx_effect_command *command)
 {
struct wiimote_data *wdata = input_get_drvdata(dev);
-   __u8 value;
-
-   /*
-* The wiimote supports only a single rumble motor so if any magnitude
-* is set to non-zero then we start the rumble motor. If both are set to
-* zero, we stop the rumble motor.
-*/
-
-   if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
-   value = 1;
-   else
-   value = 0;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
+   __u8 value = 0;
+
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   /*
+* The wiimote supports only a single rumble motor so if any 
magnitude
+* is set to non-zero then we start the rumble motor. If both 
are set to
+* zero, we stop the rumble motor.
+*/
+   if (rumble_force->strong || rumble_force->weak)
+   value = 1;
+   break;
+   case MLNX_STOP_RUMBLE:
+   break;
+   default:
+   return -EINVAL;
+   }
 
/* Locking state.lock here might deadlock with input_event() calls.
 * schedule_work acts as barrier. Merging multiple changes is fine. */
@@ -161,7 +170,7 @@ static int wiimod_rumble_probe(const struct wiimod_ops *ops,
INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker);
 
set_bit(FF_RUMBLE, wdata->input->ffbit);
-   if (input_ff_create_memless(wdata->input, NULL, wiimod_rumble_play))
+   if (input_ff_create_mlnx(wdata->input, NULL, wiimod_rumble_play, 
FF_UPDATE_RATE))
return -ENOMEM;
 
return 0;
@@ -1771,21 +1780,28 @@ static void wiimod_pro_close(struct input_dev *dev)
 }
 
 static int wiimod_pro_play(struct input_dev *dev, void *data,
-  struct ff_effect *eff)
+  const struct mlnx_effect_command *command)
 {
struct wiimote_data *wdata = input_get_drvdata(dev);
-   __u8 value;
-
-   /*
-* The wiimote supports only a single rumble motor so if any magnitude
-* is set to non-zero then we start the rumble motor. If both are set to
-* zero, we stop the rumble motor.
-*/
-
-   if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
-   value = 1;
-   else
-   value = 0;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
+   __u8 value = 0;
+
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   /*
+* The wiimote supports only a single rumble motor so if any 
magnitude
+* is set to non-zero then we start the rumble motor. If both 
are set to
+* zero, we stop the rumble motor.
+*/
+
+   if (rumble_force->strong || rumble_force->weak)
+   value = 1;
+   break;
+   case MLNX_STOP_RUMBLE:
+   break;
+   default:
+   return -EINVAL;
+   }
 
/* Locking state.lock here might deadlock with input_event() calls.
 * schedule_work acts as barrier. Merging multiple changes is fine. */
@@ -1867,8 +1883,8 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops,
set_bit(FF_RUMBLE, wdata->extension.input->ffbit);
input_set_drvdata(wdata->extension

Re: [PATCH v3 16/24] hid: Port hid-sony to ff-memless-next

2014-04-26 Thread Michal Malý
On Saturday 26 of April 2014 15:09:44 Antonio Ospite wrote:
> On Sat, 26 Apr 2014 13:57:53 +0200
> 
> Michal Malý  wrote:
> > Port hid-sony to ff-memless-next
> > 
> > Signed-off-by: Michal Malý 
> 
> Not a big deal, but note that the patch adds an unneeded
> blank line. Pointed out below.

Oh, thanks. Corrected in "v4".

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


Re: [PATCH v3 01/24] input: Add ff-memless-next module

2014-04-26 Thread Michal Malý
On Saturday 26 of April 2014 15:07:01 Antonio Ospite wrote:
> On Sat, 26 Apr 2014 13:57:38 +0200
> 
> Michal Malý  wrote:
> > Add ff-memless-next module
> 
> Hi Michal, what about adding the notes from 0/24 to this commit
> message? This is the one which will actually get into the project
> history. And perhaps hint briefly about the improvements also in the
> commit message of 24/24?

Okay. I added a summary of the changes to the commit message in "v4".
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v4 20/24] input: Port gamecon to ff-memless-next

2014-04-26 Thread Michal Malý
Port gamecon to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/joystick/Kconfig   |  2 +-
 drivers/input/joystick/gamecon.c | 57 ++--
 2 files changed, 33 insertions(+), 26 deletions(-)

diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 56eb471..2dd3ba1 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -221,7 +221,7 @@ config JOYSTICK_DB9
 config JOYSTICK_GAMECON
tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads"
depends on PARPORT
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
  Say Y here if you have a Nintendo Entertainment System gamepad,
  Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index e68e497..209d0fb 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 
 MODULE_AUTHOR("Vojtech Pavlik ");
 MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver");
@@ -47,6 +48,7 @@ MODULE_LICENSE("GPL");
 
 #define GC_MAX_PORTS   3
 #define GC_MAX_DEVICES 5
+#define FF_UPDATE_RATE 50
 
 struct gc_config {
int args[GC_MAX_DEVICES + 1];
@@ -263,43 +265,48 @@ static void gc_n64_process_packet(struct gc *gc)
 }
 
 static int gc_n64_play_effect(struct input_dev *dev, void *data,
- struct ff_effect *effect)
+ const struct mlnx_effect_command *command)
 {
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int i;
unsigned long flags;
struct gc *gc = input_get_drvdata(dev);
struct gc_subdev *sdev = data;
unsigned char target = 1 << sdev->idx; /* select desired pin */
+   unsigned int cmd;
 
-   if (effect->type == FF_RUMBLE) {
-   struct ff_rumble_effect *rumble = &effect->u.rumble;
-   unsigned int cmd =
-   rumble->strong_magnitude || rumble->weak_magnitude ?
-   GC_N64_CMD_01 : GC_N64_CMD_00;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   cmd = (rumble_force->strong || rumble_force->weak) ? 
GC_N64_CMD_01 : GC_N64_CMD_00;
+   break;
+   case MLNX_STOP_RUMBLE:
+   cmd = GC_N64_CMD_00;
+   break;
+   default:
+   return -EINVAL;
+   }
 
-   local_irq_save(flags);
+   local_irq_save(flags);
 
-   /* Init Rumble - 0x03, 0x80, 0x01, (34)0x80 */
-   gc_n64_send_command(gc, GC_N64_CMD_03, target);
+   /* Init Rumble - 0x03, 0x80, 0x01, (34)0x80 */
+   gc_n64_send_command(gc, GC_N64_CMD_03, target);
+   gc_n64_send_command(gc, GC_N64_CMD_80, target);
+   gc_n64_send_command(gc, GC_N64_CMD_01, target);
+   for (i = 0; i < 32; i++)
gc_n64_send_command(gc, GC_N64_CMD_80, target);
-   gc_n64_send_command(gc, GC_N64_CMD_01, target);
-   for (i = 0; i < 32; i++)
-   gc_n64_send_command(gc, GC_N64_CMD_80, target);
-   gc_n64_send_stop_bit(gc, target);
+   gc_n64_send_stop_bit(gc, target);
 
-   udelay(GC_N64_DELAY);
-
-   /* Now start or stop it - 0x03, 0xc0, 0zx1b, (32)0x01/0x00 */
-   gc_n64_send_command(gc, GC_N64_CMD_03, target);
-   gc_n64_send_command(gc, GC_N64_CMD_c0, target);
-   gc_n64_send_command(gc, GC_N64_CMD_1b, target);
-   for (i = 0; i < 32; i++)
-   gc_n64_send_command(gc, cmd, target);
-   gc_n64_send_stop_bit(gc, target);
+   udelay(GC_N64_DELAY);
 
-   local_irq_restore(flags);
+   /* Now start or stop it - 0x03, 0xc0, 0zx1b, (32)0x01/0x00 */
+   gc_n64_send_command(gc, GC_N64_CMD_03, target);
+   gc_n64_send_command(gc, GC_N64_CMD_c0, target);
+   gc_n64_send_command(gc, GC_N64_CMD_1b, target);
+   for (i = 0; i < 32; i++)
+   gc_n64_send_command(gc, cmd, target);
+   gc_n64_send_stop_bit(gc, target);
 
-   }
+   local_irq_restore(flags);
 
return 0;
 }
@@ -317,7 +324,7 @@ static int __init gc_n64_init_ff(struct input_dev *dev, int 
i)
 
input_set_capability(dev, EV_FF, FF_RUMBLE);
 
-   err = input_ff_create_memless(dev, sdev, gc_n64_play_effect);
+   err = input_ff_create_mlnx(dev, sdev, gc_n64_play_effect, 
FF_UPDATE_RATE);
if (err) {
kfree(sdev);
return err;
-- 
1.9.2

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


[PATCH v4 21/24] input: Port xpad to ff-memless-next

2014-04-26 Thread Michal Malý
Port xpad to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/joystick/Kconfig |   2 +-
 drivers/input/joystick/xpad.c  | 125 +++--
 2 files changed, 71 insertions(+), 56 deletions(-)

diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 2dd3ba1..9f26e48 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -294,7 +294,7 @@ config JOYSTICK_XPAD
 config JOYSTICK_XPAD_FF
bool "X-Box gamepad rumble support"
depends on JOYSTICK_XPAD && INPUT
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
  Say Y here if you want to take advantage of xbox 360 rumble features.
 
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 603fe0d..5d9c8a2 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -78,6 +78,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define DRIVER_AUTHOR "Marko Friedemann "
 #define DRIVER_DESC "X-Box pad driver"
@@ -97,6 +98,8 @@
 #define XTYPE_XBOX360W2
 #define XTYPE_UNKNOWN 3
 
+#define FF_UPDATE_RATE 50
+
 static bool dpad_to_buttons;
 module_param(dpad_to_buttons, bool, S_IRUGO);
 MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for 
unknown pads");
@@ -628,63 +631,75 @@ static void xpad_stop_output(struct usb_xpad *xpad) {}
 #endif
 
 #ifdef CONFIG_JOYSTICK_XPAD_FF
-static int xpad_play_effect(struct input_dev *dev, void *data, struct 
ff_effect *effect)
+static int xpad_play_effect(struct input_dev *dev, void *data,
+   const struct mlnx_effect_command *command)
 {
struct usb_xpad *xpad = input_get_drvdata(dev);
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
+   __u16 strong, weak;
 
-   if (effect->type == FF_RUMBLE) {
-   __u16 strong = effect->u.rumble.strong_magnitude;
-   __u16 weak = effect->u.rumble.weak_magnitude;
-
-   switch (xpad->xtype) {
-
-   case XTYPE_XBOX:
-   xpad->odata[0] = 0x00;
-   xpad->odata[1] = 0x06;
-   xpad->odata[2] = 0x00;
-   xpad->odata[3] = strong / 256;  /* left actuator */
-   xpad->odata[4] = 0x00;
-   xpad->odata[5] = weak / 256;/* right actuator */
-   xpad->irq_out->transfer_buffer_length = 6;
-
-   return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
-   case XTYPE_XBOX360:
-   xpad->odata[0] = 0x00;
-   xpad->odata[1] = 0x08;
-   xpad->odata[2] = 0x00;
-   xpad->odata[3] = strong / 256;  /* left actuator? */
-   xpad->odata[4] = weak / 256;/* right actuator? */
-   xpad->odata[5] = 0x00;
-   xpad->odata[6] = 0x00;
-   xpad->odata[7] = 0x00;
-   xpad->irq_out->transfer_buffer_length = 8;
-
-   return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
-   case XTYPE_XBOX360W:
-   xpad->odata[0] = 0x00;
-   xpad->odata[1] = 0x01;
-   xpad->odata[2] = 0x0F;
-   xpad->odata[3] = 0xC0;
-   xpad->odata[4] = 0x00;
-   xpad->odata[5] = strong / 256;
-   xpad->odata[6] = weak / 256;
-   xpad->odata[7] = 0x00;
-   xpad->odata[8] = 0x00;
-   xpad->odata[9] = 0x00;
-   xpad->odata[10] = 0x00;
-   xpad->odata[11] = 0x00;
-   xpad->irq_out->transfer_buffer_length = 12;
-
-   return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
-   default:
-   dev_dbg(&xpad->dev->dev,
-   "%s - rumble command sent to unsupported xpad 
type: %d\n",
-   __func__, xpad->xtype);
-   return -1;
-   }
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   strong = rumble_force->strong;
+   weak = rumble_force->weak;
+   break;
+   case MLNX_STOP_RUMBLE:
+   strong = 0;
+   weak = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
+
+
+   switch (xpad->xtype) {
+
+   case XTYPE_XBOX:
+   xpad->odata[0] = 0x00;
+   xpad->odata[1] = 0x06;
+   xpad->odata[2] = 0x00;
+

[PATCH v4 00/24] input: Introduce ff-memless-next as an improved replacement for ff-memless

2014-04-26 Thread Michal Malý
ff-memless-next (MLNX) is a largely improved version of the current ff-memless
(FFML) driver. MLNX supports all force feedback effects currently available in
the Linux force feedback userspace API. All effects are handled in accordance
with Microsoft's DirectInput/XInput. Most notable changes include support for
conditional effects, proper handling of all periodic waveforms and improved
emulation of rumble effects through periodic effects. MLNX also uses its own
kernel API to pass processed effects to hardware-specific drivers instead of
abusing "ff_effect" struct. The API is documented in the respective header
file.

MLNX has been expanded to be a direct replacement for FFML.

Support for FF_PERIODIC and FF_RAMP has been added to all devices that
support FF_CONSTANT as a part of the port to the new API.

This patch series:
1) Adds "ff-memless-next" module [1]
2) Ports all hardware-specific drivers to MLNX's API [2-23]
3) Removes FFML and replaces it with MLNX [24]

Signed-off-by: Michal Malý 

v4:
 - Add a summary of changes between MLNX and FFML to the last patch
 - Remove a stale empty line in hid-sony.c
 - Add "Tested-by: Elias Vanderstuyft " to hid-lg4ff patch.

v3:
 - Rebase against latest linux-next. Fixes conflict in hid-sony.c and
   max8997_haptic.c
 - Updated documentation in ff-memless-next.h. The documentation now describes
   parameters of the callback function and specifically mentions that
   HW-specific drivers must not keep a reference to mlnx_effect_command struct
   to which a pointer is passed in the callback function.
 - Fix a minor brace inconsistency in hid-lgff
 I believe that all concerns regarding v2 have been resolved as false alarms.

v2:
 - Add missing msecs to jiffies conversion in ff-memless-next
 - lgff: Properly convert force on Y axis from MLNX to device range
 Support periodic effects for "joystick_ac" device class
 - lg3ff: Properly convert forces from MLNX to device range
 - Very minor coding style issues fixed

Michal Malý (24):
  Add ff-memless-next module
  Port arizona-haptics to ff-memless-next
  Port twl4030-vibra to ff-memless-next
  Port twl6040-vibra to ff-memless-next
  Port max8997_haptic to ff-memless-next
  Port pm8xxx-vibrator to ff-memless-next
  Port hid-axff to ff-memless-next
  Port hid-emsff to ff-memless-next
  Port hid-dr to ff-memless-next
  Port hid-gaff to ff-memless-next
  Port hid-holtekff to ff-memless-next
  Port hid-lgff to ff-memless-next
  Port hid-lg3ff to ff-memless-next
  Port hid-pl to ff-memless-next
  Port hid-sjoy to ff-memless-next
  Port hid-sony to ff-memless-next
  Port hid-tmff to ff-memless-next
  Port hid-wiimote-modules to ff-memless-next
  Port hid-zpff to ff-memless-next
  Port gamecon to ff-memless-next
  Port xpad to ff-memless-next
  Port hid-lg2ff to ff-memless-next
  Port hid-lg4ff to ff-memless-next
  Replace ff-memless with ff-memless-next

 drivers/hid/Kconfig   |   30 +-
 drivers/hid/hid-axff.c|   32 +-
 drivers/hid/hid-dr.c  |   59 +-
 drivers/hid/hid-emsff.c   |   38 +-
 drivers/hid/hid-gaff.c|   32 +-
 drivers/hid/hid-holtekff.c|   47 +-
 drivers/hid/hid-lg2ff.c   |   65 ++-
 drivers/hid/hid-lg3ff.c   |   60 +-
 drivers/hid/hid-lg4ff.c   |   93 +--
 drivers/hid/hid-lgff.c|   70 ++-
 drivers/hid/hid-pl.c  |   38 +-
 drivers/hid/hid-sjoy.c|   35 +-
 drivers/hid/hid-sony.c|   23 +-
 drivers/hid/hid-tmff.c|   83 +--
 drivers/hid/hid-wiimote-modules.c |   74 ++-
 drivers/hid/hid-zpff.c|   30 +-
 drivers/input/Kconfig |4 +-
 drivers/input/Makefile|2 +-
 drivers/input/ff-memless-next.c   | 1037 +
 drivers/input/ff-memless.c|  547 -
 drivers/input/joystick/Kconfig|4 +-
 drivers/input/joystick/gamecon.c  |   57 +-
 drivers/input/joystick/xpad.c |  125 ++--
 drivers/input/misc/Kconfig|   10 +-
 drivers/input/misc/arizona-haptics.c  |   39 +-
 drivers/input/misc/max8997_haptic.c   |   25 +-
 drivers/input/misc/pm8xxx-vibrator.c  |   28 +-
 drivers/input/misc/twl4030-vibra.c|   31 +-
 drivers/input/misc/twl6040-vibra.c|   27 +-
 include/linux/input.h |3 -
 include/linux/input/ff-memless-next.h |  162 +
 31 files changed, 1951 insertions(+), 959 deletions(-)
 create mode 100644 drivers/input/ff-memless-next.c
 delete mode 100644 drivers/input/ff-memless.c
 create mode 100644 include/linux/input/ff-memless-next.h

-- 
1.9.2

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


[PATCH v3 02/24] input: Port arizona-haptics to ff-memless-next

2014-04-26 Thread Michal Malý
Port arizona-haptics to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/misc/Kconfig   |  2 +-
 drivers/input/misc/arizona-haptics.c | 39 +++-
 2 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 5928ea7..f669cc7 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -75,7 +75,7 @@ config INPUT_AD714X_SPI
 config INPUT_ARIZONA_HAPTICS
tristate "Arizona haptics support"
depends on MFD_ARIZONA && SND_SOC
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  Say Y to enable support for the haptics module in Arizona CODECs.
 
diff --git a/drivers/input/misc/arizona-haptics.c 
b/drivers/input/misc/arizona-haptics.c
index ef2e281..b4707cc 100644
--- a/drivers/input/misc/arizona-haptics.c
+++ b/drivers/input/misc/arizona-haptics.c
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -22,6 +23,8 @@
 #include 
 #include 
 
+#define FF_UPDATE_RATE 50
+
 struct arizona_haptics {
struct arizona *arizona;
struct input_dev *input_dev;
@@ -108,29 +111,37 @@ static void arizona_haptics_work(struct work_struct *work)
 }
 
 static int arizona_haptics_play(struct input_dev *input, void *data,
-   struct ff_effect *effect)
+   const struct mlnx_effect_command *command)
 {
struct arizona_haptics *haptics = input_get_drvdata(input);
struct arizona *arizona = haptics->arizona;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
 
if (!arizona->dapm) {
dev_err(arizona->dev, "No DAPM context\n");
return -EBUSY;
}
 
-   if (effect->u.rumble.strong_magnitude) {
-   /* Scale the magnitude into the range the device supports */
-   if (arizona->pdata.hap_act) {
-   haptics->intensity =
-   effect->u.rumble.strong_magnitude >> 9;
-   if (effect->direction < 0x8000)
-   haptics->intensity += 0x7f;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   if (rumble_force->strong) {
+   /* Scale the magnitude into the range the device 
supports */
+   if (arizona->pdata.hap_act) {
+   haptics->intensity = rumble_force->strong >> 9;
+   if (rumble_force->strong_dir < 0x8000)
+   haptics->intensity += 0x7f;
+   } else {
+   haptics->intensity = rumble_force->strong >> 8;
+   }
} else {
-   haptics->intensity =
-   effect->u.rumble.strong_magnitude >> 8;
+   haptics->intensity = 0;
}
-   } else {
+   break;
+   case MLNX_STOP_RUMBLE:
haptics->intensity = 0;
+   break;
+   default:
+   return -EINVAL;
}
 
schedule_work(&haptics->work);
@@ -183,10 +194,10 @@ static int arizona_haptics_probe(struct platform_device 
*pdev)
haptics->input_dev->close = arizona_haptics_close;
__set_bit(FF_RUMBLE, haptics->input_dev->ffbit);
 
-   ret = input_ff_create_memless(haptics->input_dev, NULL,
- arizona_haptics_play);
+   ret = input_ff_create_mlnx(haptics->input_dev, NULL,
+  arizona_haptics_play, FF_UPDATE_RATE);
if (ret < 0) {
-   dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n",
+   dev_err(arizona->dev, "input_ff_create_mlnx() failed: %d\n",
ret);
goto err_ialloc;
}
-- 
1.9.2

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


[PATCH v3 03/24] input: Port twl4030-vibra to ff-memless-next

2014-04-26 Thread Michal Malý
Port twl4030-vibra to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/misc/Kconfig |  2 +-
 drivers/input/misc/twl4030-vibra.c | 31 +--
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index f669cc7..817156f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -407,7 +407,7 @@ config INPUT_TWL4030_VIBRA
tristate "Support for TWL4030 Vibrator"
depends on TWL4030_CORE
select MFD_TWL4030_AUDIO
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  This option enables support for TWL4030 Vibrator Driver.
 
diff --git a/drivers/input/misc/twl4030-vibra.c 
b/drivers/input/misc/twl4030-vibra.c
index 960ef2a..5274ad2 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -32,9 +32,11 @@
 #include 
 #include 
 #include 
+#include 
 
 /* MODULE ID2 */
 #define LEDEN  0x00
+#define FF_UPDATE_RATE 50
 
 /* ForceFeedback */
 #define EFFECT_DIR_180_DEG 0x8000 /* range is 0 - 0x */
@@ -134,14 +136,31 @@ static void vibra_play_work(struct work_struct *work)
 /*** Input/ForceFeedback ***/
 
 static int vibra_play(struct input_dev *input, void *data,
- struct ff_effect *effect)
+ const struct mlnx_effect_command *command)
 {
struct vibra_info *info = input_get_drvdata(input);
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
+
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   if (command->u.rumble_force.strong) {
+   info->speed = rumble_force->strong >> 8;
+   info->direction = rumble_force->strong_dir < 
EFFECT_DIR_180_DEG ?
+ 0 : 1;
+   } else {
+   info->speed = rumble_force->weak >> 9;
+   info->direction = rumble_force->weak_dir < 
EFFECT_DIR_180_DEG ?
+ 0 : 1;
+   }
+   break;
+   case MLNX_STOP_RUMBLE:
+   info->speed = 0;
+   info->direction = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
-   info->speed = effect->u.rumble.strong_magnitude >> 8;
-   if (!info->speed)
-   info->speed = effect->u.rumble.weak_magnitude >> 9;
-   info->direction = effect->direction < EFFECT_DIR_180_DEG ? 0 : 1;
schedule_work(&info->play_work);
return 0;
 }
@@ -227,7 +246,7 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
info->input_dev->close = twl4030_vibra_close;
__set_bit(FF_RUMBLE, info->input_dev->ffbit);
 
-   ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
+   ret = input_ff_create_mlnx(info->input_dev, NULL, vibra_play, 
FF_UPDATE_RATE);
if (ret < 0) {
dev_dbg(&pdev->dev, "couldn't register vibrator to FF\n");
return ret;
-- 
1.9.2

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


[PATCH v3 01/24] input: Add ff-memless-next module

2014-04-26 Thread Michal Malý
Add ff-memless-next module

Signed-off-by: Michal Malý 
Tested-by: Elias Vanderstuyft 
---
 drivers/input/Kconfig |   11 +
 drivers/input/Makefile|1 +
 drivers/input/ff-memless-next.c   | 1037 +
 include/linux/input/ff-memless-next.h |  162 +
 4 files changed, 1211 insertions(+)
 create mode 100644 drivers/input/ff-memless-next.c
 create mode 100644 include/linux/input/ff-memless-next.h

diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index a11ff74..3780962 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -38,6 +38,17 @@ config INPUT_FF_MEMLESS
  To compile this driver as a module, choose M here: the
  module will be called ff-memless.
 
+config INPUT_FF_MEMLESS_NEXT
+   tristate "New version of support for memoryless force-feedback devices"
+   help
+ Say Y here to enable a new version of support for memoryless force
+ feedback devices.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ff-memless-next.
+
 config INPUT_POLLDEV
tristate "Polled input device skeleton"
help
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 5ca3f63..b4f11f5 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_INPUT) += input-core.o
 input-core-y := input.o input-compat.o input-mt.o ff-core.o
 
 obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
+obj-$(CONFIG_INPUT_FF_MEMLESS_NEXT)+= ff-memless-next.o
 obj-$(CONFIG_INPUT_POLLDEV)+= input-polldev.o
 obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
 obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o
diff --git a/drivers/input/ff-memless-next.c b/drivers/input/ff-memless-next.c
new file mode 100644
index 000..24619e9
--- /dev/null
+++ b/drivers/input/ff-memless-next.c
@@ -0,0 +1,1037 @@
+/*
+ * Force feedback support for memoryless devices
+ *
+ * This module is based on "ff-memless" orignally written by Anssi Hannula.
+ * It is extended to support all force feedback effects currently supported
+ * by the Linux input stack.
+ * Logic of emulation of FF_RUMBLE through FF_PERIODIC provided by
+ * Elias Vanderstuyft 
+ *
+ * Copyright(c) 2014 Michal "MadCatX" Maly 
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal \"MadCatX\" Maly");
+MODULE_DESCRIPTION("Force feedback support for memoryless force feedback 
devices");
+
+#define FF_MAX_EFFECTS 16
+#define FF_MIN_EFFECT_LENGTH ((MSEC_PER_SEC / CONFIG_HZ) + 1)
+#define FF_EFFECT_STARTED 1
+#define FF_EFFECT_PLAYING 2
+#define FF_EFFECT_EMULATED 3
+
+enum mlnx_emulate {
+   EMUL_NOTHING,   /* Do not emulate anything */
+   EMUL_RUMBLE,/* Emulate FF_RUMBLE with FF_PERIODIC */
+   EMUL_PERIODIC   /* Emulate FF_PERIODIC with FF_RUMBLE */
+};
+
+struct mlnx_effect {
+   struct ff_effect effect;
+   unsigned long flags;
+   unsigned long begin_at;
+   unsigned long stop_at;
+   unsigned long updated_at;
+   unsigned long attack_stop;
+   unsigned long fade_begin;
+   int repeat;
+};
+
+struct mlnx_device {
+   u8 combinable_playing;
+   u8 rumble_playing;
+   unsigned long update_rate_jiffies;
+   void *private;
+   struct mlnx_effect effects[FF_MAX_EFFECTS];
+   u16 gain;
+   struct timer_list timer;
+   struct input_dev *dev;
+   enum mlnx_emulate emul;
+
+   int (*control_effect)(struct input_dev *, void *,
+ const struct mlnx_effect_command *);
+};
+
+static s32 mlnx_calculate_x_force(const s32 level,
+ const u16 direction)
+{
+   s32 new = (level * -fixp_sin(direction)) >> FRAC_N;
+   pr_debug("x force: %d\n", new);
+   return new;
+}
+
+static s32 mlnx_calculate_y_force(const s32 level,
+ const u16 direction)
+{
+   s32 new = (level * fixp_cos(direction)) >> FRAC_N;
+   pr_debug("y force: %d\n", new);
+   return new;
+}
+
+static bool mlnx_is_combinable(const struct ff_effect *effect)
+{
+   switch (effect->type) {
+   case FF_CONSTANT:
+   case FF_PERIODIC:
+   case FF_RAMP:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static bool mlnx_is_conditional(const struct ff_effect *effect)
+{
+   switch (effect->type) {
+   case FF_DAMPER:
+   case FF_FRICTION:
+   case FF_INERTIA:
+   case FF_SPRING:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static void mlnx_clr_emulated(struct mlnx_effect *mlnx

[PATCH v4 04/24] input: Port twl6040-vibra to ff-memless-next

2014-04-26 Thread Michal Malý
Port twl6040-vibra to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/misc/Kconfig |  2 +-
 drivers/input/misc/twl6040-vibra.c | 27 ++-
 2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 817156f..b9cbb91 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -417,7 +417,7 @@ config INPUT_TWL4030_VIBRA
 config INPUT_TWL6040_VIBRA
tristate "Support for TWL6040 Vibrator"
depends on TWL6040_CORE
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  This option enables support for TWL6040 Vibrator Driver.
 
diff --git a/drivers/input/misc/twl6040-vibra.c 
b/drivers/input/misc/twl6040-vibra.c
index 77dc23b..7440a74 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -30,12 +30,14 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 
 #define EFFECT_DIR_180_DEG 0x8000
+#define FF_UPDATE_RATE 50
 
 /* Recommended modulation index 85% */
 #define TWL6040_VIBRA_MOD  85
@@ -197,9 +199,10 @@ static void vibra_play_work(struct work_struct *work)
 }
 
 static int vibra_play(struct input_dev *input, void *data,
- struct ff_effect *effect)
+ const struct mlnx_effect_command *command)
 {
struct vibra_info *info = input_get_drvdata(input);
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int ret;
 
/* Do not allow effect, while the routing is set to use audio */
@@ -209,9 +212,23 @@ static int vibra_play(struct input_dev *input, void *data,
return -EBUSY;
}
 
-   info->weak_speed = effect->u.rumble.weak_magnitude;
-   info->strong_speed = effect->u.rumble.strong_magnitude;
-   info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   info->weak_speed = rumble_force->weak;
+   info->strong_speed = rumble_force->strong;
+   if (info->strong_speed >= info->weak_speed)
+   info->direction = rumble_force->strong_dir < 
EFFECT_DIR_180_DEG ? 1 : -1;
+   else
+   info->direction = rumble_force->weak_dir < 
EFFECT_DIR_180_DEG ? 1 : -1;
+   break;
+   case MLNX_STOP_RUMBLE:
+   info->weak_speed = 0;
+   info->strong_speed = 0;
+   info->direction = 1;
+   break;
+   default:
+   return -EINVAL;
+   }
 
ret = queue_work(info->workqueue, &info->play_work);
if (!ret) {
@@ -367,7 +384,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
info->input_dev->close = twl6040_vibra_close;
__set_bit(FF_RUMBLE, info->input_dev->ffbit);
 
-   ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
+   ret = input_ff_create_mlnx(info->input_dev, NULL, vibra_play, 
FF_UPDATE_RATE);
if (ret < 0) {
dev_err(info->dev, "couldn't register vibrator to FF\n");
goto err_ialloc;
-- 
1.9.2

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


[PATCH v3 07/24] hid: Port hid-axff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-axff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-axff.c | 32 +++-
 2 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 7af9d0b..e076627 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -106,7 +106,7 @@ config HID_ACRUX
 config HID_ACRUX_FF
bool "ACRUX force feedback support"
depends on HID_ACRUX
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you want to enable force feedback support for ACRUX
game controllers.
diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c
index a594e47..7fbfcbc 100644
--- a/drivers/hid/hid-axff.c
+++ b/drivers/hid/hid-axff.c
@@ -31,31 +31,45 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
 #ifdef CONFIG_HID_ACRUX_FF
 
 struct axff_device {
struct hid_report *report;
 };
 
-static int axff_play(struct input_dev *dev, void *data, struct ff_effect 
*effect)
+static int axff_play(struct input_dev *dev, void *data,
+const struct mlnx_effect_command *command)
 {
struct hid_device *hid = input_get_drvdata(dev);
struct axff_device *axff = data;
struct hid_report *report = axff->report;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int field_count = 0;
int left, right;
int i, j;
 
-   left = effect->u.rumble.strong_magnitude;
-   right = effect->u.rumble.weak_magnitude;
-
-   dbg_hid("called with 0x%04x 0x%04x", left, right);
-
-   left = left * 0xff / 0x;
-   right = right * 0xff / 0x;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   left = rumble_force->strong;
+   right = rumble_force->weak;
+
+   dbg_hid("called with 0x%04x 0x%04x", left, right);
+
+   left = left * 0xff / 0x;
+   right = right * 0xff / 0x;
+   break;
+   case MLNX_STOP_RUMBLE:
+   left = 0;
+   right = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
for (i = 0; i < report->maxfield; i++) {
for (j = 0; j < report->field[i]->report_count; j++) {
@@ -107,7 +121,7 @@ static int axff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, axff, axff_play);
+   error = input_ff_create_mlnx(dev, axff, axff_play, FF_UPDATE_RATE);
if (error)
goto err_free_mem;
 
-- 
1.9.2

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


[PATCH v3 05/24] input: Port max8997_haptic to ff-memless-next

2014-04-26 Thread Michal Malý
Port max8997_haptic to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/misc/Kconfig  |  2 +-
 drivers/input/misc/max8997_haptic.c | 25 +++--
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index b9cbb91..a89dc22 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -157,7 +157,7 @@ config INPUT_MAX8925_ONKEY
 config INPUT_MAX8997_HAPTIC
tristate "MAXIM MAX8997 haptic controller support"
depends on PWM && MFD_MAX8997
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  This option enables device driver support for the haptic controller
  on MAXIM MAX8997 chip. This driver supports ff-memless interface
diff --git a/drivers/input/misc/max8997_haptic.c 
b/drivers/input/misc/max8997_haptic.c
index 1fea548..029ac8b 100644
--- a/drivers/input/misc/max8997_haptic.c
+++ b/drivers/input/misc/max8997_haptic.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Haptic configuration 2 register */
 #define MAX8997_MOTOR_TYPE_SHIFT   7
@@ -43,6 +44,8 @@
 #define MAX8997_SIG_DUTY_SHIFT 2
 #define MAX8997_PWM_DUTY_SHIFT 0
 
+#define FF_UPDATE_RATE 50
+
 struct max8997_haptic {
struct device *dev;
struct i2c_client *client;
@@ -219,13 +222,23 @@ static void max8997_haptic_play_effect_work(struct 
work_struct *work)
 }
 
 static int max8997_haptic_play_effect(struct input_dev *dev, void *data,
- struct ff_effect *effect)
+ const struct mlnx_effect_command *command)
 {
struct max8997_haptic *chip = input_get_drvdata(dev);
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
 
-   chip->level = effect->u.rumble.strong_magnitude;
-   if (!chip->level)
-   chip->level = effect->u.rumble.weak_magnitude;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   chip->level = rumble_force->strong;
+   if (!chip->level)
+   chip->level = rumble_force->weak;
+   break;
+   case MLNX_STOP_RUMBLE:
+   chip->level = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
schedule_work(&chip->work);
 
@@ -319,8 +332,8 @@ static int max8997_haptic_probe(struct platform_device 
*pdev)
input_set_drvdata(input_dev, chip);
input_set_capability(input_dev, EV_FF, FF_RUMBLE);
 
-   error = input_ff_create_memless(input_dev, NULL,
-   max8997_haptic_play_effect);
+   error = input_ff_create_mlnx(input_dev, NULL,
+   max8997_haptic_play_effect, FF_UPDATE_RATE);
if (error) {
dev_err(&pdev->dev,
"unable to create FF device, error: %d\n",
-- 
1.9.2

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


[PATCH v3 06/24] input: Port pm8xxx-vibrator to ff-memless-next

2014-04-26 Thread Michal Malý
Port pm8xxx-vibrator to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/misc/Kconfig   |  2 +-
 drivers/input/misc/pm8xxx-vibrator.c | 28 +++-
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index a89dc22..7b962e4 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -108,7 +108,7 @@ config INPUT_PCSPKR
 config INPUT_PM8XXX_VIBRATOR
tristate "Qualcomm PM8XXX vibrator support"
depends on MFD_PM8XXX
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  This option enables device driver support for the vibrator
  on Qualcomm PM8xxx chip. This driver supports ff-memless interface
diff --git a/drivers/input/misc/pm8xxx-vibrator.c 
b/drivers/input/misc/pm8xxx-vibrator.c
index 6a915ba..1796f4f 100644
--- a/drivers/input/misc/pm8xxx-vibrator.c
+++ b/drivers/input/misc/pm8xxx-vibrator.c
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define VIB_DRV0x4A
 
@@ -29,7 +30,7 @@
 #define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV)
 
 #define MAX_FF_SPEED   0xff
-
+#define FF_UPDATE_RATE 50
 /**
  * struct pm8xxx_vib - structure to hold vibrator data
  * @vib_input_dev: input device supporting force feedback
@@ -128,14 +129,23 @@ static void pm8xxx_vib_close(struct input_dev *dev)
  * Currently this driver supports only rumble effects.
  */
 static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,
- struct ff_effect *effect)
+ const struct mlnx_command *command)
 {
struct pm8xxx_vib *vib = input_get_drvdata(dev);
-
-   vib->speed = effect->u.rumble.strong_magnitude >> 8;
-   if (!vib->speed)
-   vib->speed = effect->u.rumble.weak_magnitude >> 9;
-
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
+
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   vib->speed = rumble_force->strong >> 8;
+   if (!vib->speed)
+   vib->speed = rumble_force->weak >> 9;
+   break;
+   case MLNX_STOP_RUMBLE:
+   vib->speed = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
schedule_work(&vib->work);
 
return 0;
@@ -181,8 +191,8 @@ static int pm8xxx_vib_probe(struct platform_device *pdev)
input_set_drvdata(input_dev, vib);
input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE);
 
-   error = input_ff_create_memless(input_dev, NULL,
-   pm8xxx_vib_play_effect);
+   error = input_ff_create_mlnx(input_dev, NULL,
+pm8xxx_vib_play_effect, FF_UPDATE_RATE);
if (error) {
dev_err(&pdev->dev,
"couldn't register vibrator as FF device\n");
-- 
1.9.2

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


[PATCH v3 10/24] hid: Port hid-gaff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-gaff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-gaff.c | 32 +++-
 2 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 1d4180c..4c59a88 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -667,7 +667,7 @@ config HID_GREENASIA
 config GREENASIA_FF
bool "GreenAsia (Product ID 0x12) force feedback support"
depends on HID_GREENASIA
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you have a GreenAsia (Product ID 0x12) based game 
controller
(like MANTA Warrior MM816 and SpeedLink Strike2 SL-6635) or adapter
diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c
index 2d8cead..f2f70c1 100644
--- a/drivers/hid/hid-gaff.c
+++ b/drivers/hid/hid-gaff.c
@@ -31,8 +31,11 @@
 #include 
 #include 
 #include 
+#include 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 #ifdef CONFIG_GREENASIA_FF
 
 struct gaff_device {
@@ -40,19 +43,30 @@ struct gaff_device {
 };
 
 static int hid_gaff_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 gaff_device *gaff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int left, right;
 
-   left = effect->u.rumble.strong_magnitude;
-   right = effect->u.rumble.weak_magnitude;
-
-   dbg_hid("called with 0x%04x 0x%04x", left, right);
-
-   left = left * 0xfe / 0x;
-   right = right * 0xfe / 0x;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   left = rumble_force->strong;
+   right = rumble_force->weak;
+
+   dbg_hid("called with 0x%04x 0x%04x", left, right);
+
+   left = left * 0xfe / 0x;
+   right = right * 0xfe / 0x;
+   break;
+   case MLNX_STOP_RUMBLE:
+   left = 0;
+   right = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
gaff->report->field[0]->value[0] = 0x51;
gaff->report->field[0]->value[1] = 0x0;
@@ -109,7 +123,7 @@ static int gaff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, gaff, hid_gaff_play);
+   error = input_ff_create_mlnx(dev, gaff, hid_gaff_play, FF_UPDATE_RATE);
if (error) {
kfree(gaff);
return error;
-- 
1.9.2

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


[PATCH v3 09/24] hid: Port hid-dr to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-dr to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig  |  2 +-
 drivers/hid/hid-dr.c | 59 
 2 files changed, 37 insertions(+), 24 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index a78b5d8..1d4180c 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -205,7 +205,7 @@ config HID_DRAGONRISE
 config DRAGONRISE_FF
bool "DragonRise Inc. force feedback"
depends on HID_DRAGONRISE
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you want to enable force feedback support for DragonRise 
Inc.
game controllers.
diff --git a/drivers/hid/hid-dr.c b/drivers/hid/hid-dr.c
index ce06444..b95c676 100644
--- a/drivers/hid/hid-dr.c
+++ b/drivers/hid/hid-dr.c
@@ -31,8 +31,10 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
+#define FF_UPDATE_RATE 50
 
 #ifdef CONFIG_DRAGONRISE_FF
 
@@ -41,38 +43,49 @@ struct drff_device {
 };
 
 static int drff_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 drff_device *drff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int strong, weak;
 
-   strong = effect->u.rumble.strong_magnitude;
-   weak = effect->u.rumble.weak_magnitude;
+   strong = rumble_force->strong;
+   weak = rumble_force->weak;
 
dbg_hid("called with 0x%04x 0x%04x", strong, weak);
 
-   if (strong || weak) {
-   strong = strong * 0xff / 0x;
-   weak = weak * 0xff / 0x;
-
-   /* While reverse engineering this device, I found that when
-  this value is set, it causes the strong rumble to function
-  at a near maximum speed, so we'll bypass it. */
-   if (weak == 0x0a)
-   weak = 0x0b;
-
-   drff->report->field[0]->value[0] = 0x51;
-   drff->report->field[0]->value[1] = 0x00;
-   drff->report->field[0]->value[2] = weak;
-   drff->report->field[0]->value[4] = strong;
-   hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
-
-   drff->report->field[0]->value[0] = 0xfa;
-   drff->report->field[0]->value[1] = 0xfe;
-   } else {
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   if (strong || weak) {
+   strong = strong * 0xff / 0x;
+   weak = weak * 0xff / 0x;
+
+   /* While reverse engineering this device, I found that 
when
+   this value is set, it causes the strong rumble to 
function
+   at a near maximum speed, so we'll bypass it. */
+   if (weak == 0x0a)
+   weak = 0x0b;
+
+   drff->report->field[0]->value[0] = 0x51;
+   drff->report->field[0]->value[1] = 0x00;
+   drff->report->field[0]->value[2] = weak;
+   drff->report->field[0]->value[4] = strong;
+   hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
+
+   drff->report->field[0]->value[0] = 0xfa;
+   drff->report->field[0]->value[1] = 0xfe;
+   } else {
+   drff->report->field[0]->value[0] = 0xf3;
+   drff->report->field[0]->value[1] = 0x00;
+   }
+   break;
+   case MLNX_STOP_RUMBLE:
drff->report->field[0]->value[0] = 0xf3;
drff->report->field[0]->value[1] = 0x00;
+   break;
+   default:
+   return -EINVAL;
}
 
drff->report->field[0]->value[2] = 0x00;
@@ -116,7 +129,7 @@ static int drff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, drff, drff_play);
+   error = input_ff_create_mlnx(dev, drff, drff_play, FF_UPDATE_RATE);
if (error) {
kfree(drff);
return error;
-- 
1.9.2

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


[PATCH v3 12/24] hid: Port hid-lgff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-lgff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-lgff.c | 70 +++---
 2 files changed, 51 insertions(+), 21 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 1749a4a..c4b0cbb 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -365,7 +365,7 @@ config HID_LOGITECH_DJ
 config LOGITECH_FF
bool "Logitech force feedback support"
depends on HID_LOGITECH
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  Say Y here if you have one of these devices:
  - Logitech WingMan Cordless RumblePad
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index e1394af..40ad68a 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -31,9 +31,12 @@
 
 #include 
 #include 
+#include 
 
 #include "hid-lg.h"
 
+#define FF_UPDATE_RATE 50
+
 struct dev_type {
u16 idVendor;
u16 idProduct;
@@ -47,11 +50,25 @@ static const signed short ff_rumble[] = {
 
 static const signed short ff_joystick[] = {
FF_CONSTANT,
+   FF_RAMP,
+   FF_PERIODIC,
+   FF_SQUARE,
+   FF_TRIANGLE,
+   FF_SINE,
+   FF_SAW_UP,
+   FF_SAW_DOWN,
-1
 };
 
 static const signed short ff_joystick_ac[] = {
FF_CONSTANT,
+   FF_RAMP,
+   FF_PERIODIC,
+   FF_SQUARE,
+   FF_TRIANGLE,
+   FF_SINE,
+   FF_SAW_UP,
+   FF_SAW_DOWN,
FF_AUTOCENTER,
-1
 };
@@ -66,45 +83,58 @@ static const struct dev_type devices[] = {
{ 0x046d, 0xc295, ff_joystick },
 };
 
-static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect 
*effect)
+static int hid_lgff_play(struct input_dev *dev, void *data,
+const struct mlnx_effect_command *command)
 {
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
-   int x, y;
-   unsigned int left, right;
 
-#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
+   switch (command->cmd) {
+   case MLNX_START_COMBINED: {
+   const struct mlnx_simple_force *simple_force = 
&command->u.simple_force;
+   /* Scale down from MLNX range */
+   const int x = 0x80 - (simple_force->x * 0xff / 0x);
+   const int y = 0x80 - (simple_force->y * 0xff / 0x);
 
-   switch (effect->type) {
-   case FF_CONSTANT:
-   x = effect->u.ramp.start_level + 0x7f;  /* 0x7f is center */
-   y = effect->u.ramp.end_level + 0x7f;
-   CLAMP(x);
-   CLAMP(y);
report->field[0]->value[0] = 0x51;
report->field[0]->value[1] = 0x08;
report->field[0]->value[2] = x;
report->field[0]->value[3] = y;
dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
+   }
+   case MLNX_STOP_COMBINED:
+   report->field[0]->value[0] = 0x51;
+   report->field[0]->value[1] = 0x08;
+   report->field[0]->value[2] = 0x80;
+   report->field[0]->value[3] = 0x80;
+   break;
+   case MLNX_START_RUMBLE: {
+   const struct mlnx_rumble_force *rumble_force = 
&command->u.rumble_force;
+   /* Scale down from MLNX range */
+   const unsigned int right = rumble_force->weak * 0xff / 0x;
+   const unsigned int left = rumble_force->strong * 0xff / 0x;
 
-   case FF_RUMBLE:
-   right = effect->u.rumble.strong_magnitude;
-   left = effect->u.rumble.weak_magnitude;
-   right = right * 0xff / 0x;
-   left = left * 0xff / 0x;
-   CLAMP(left);
-   CLAMP(right);
report->field[0]->value[0] = 0x42;
report->field[0]->value[1] = 0x00;
report->field[0]->value[2] = left;
report->field[0]->value[3] = right;
dbg_hid("(left, right)=(%04x, %04x)\n", left, right);
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
}
+   case MLNX_STOP_RUMBLE:
+   report->field[0]->value[0] = 0x42;
+   report->field[0]->value[1] = 0x00;
+   report->field[0]->value[2] = 0;
+   report->field[0]->value[3] = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   hid_hw_request(hid, report, HID_REQ_SET_RE

[PATCH v3 11/24] hid: Port hid-holtekff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-holtekff to ff-memless-next

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

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 4c59a88..1749a4a 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -256,7 +256,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 
 #include 
 #include 
+#include 
 
 #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;
-- 
1.9.2

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


[PATCH v3 16/24] hid: Port hid-sony to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-sony to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-sony.c | 24 ++--
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 9260d14..e97c382 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -634,7 +634,7 @@ config HID_SONY
 config SONY_FF
bool "Sony PS2/3/4 accessories force feedback support" 
depends on HID_SONY
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you have a Sony PS2/3/4 accessory and want to enable
force feedback support for it.
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 908de27..95bb2e1 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -34,6 +34,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
@@ -53,6 +54,7 @@
 #define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)
 #define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)
 
+#define FF_UPDATE_RATE 50
 #define MAX_LEDS 4
 
 static const u8 sixaxis_rdesc_fixup[] = {
@@ -1308,16 +1310,25 @@ static void dualshock4_state_worker(struct work_struct 
*work)
 
 #ifdef CONFIG_SONY_FF
 static int sony_play_effect(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 sony_sc *sc = hid_get_drvdata(hid);
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
 
-   if (effect->type != FF_RUMBLE)
-   return 0;
 
-   sc->left = effect->u.rumble.strong_magnitude / 256;
-   sc->right = effect->u.rumble.weak_magnitude / 256;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   sc->left = rumble_force->strong / 256;
+   sc->right = rumble_force->weak / 256;
+   break;
+   case MLNX_STOP_RUMBLE:
+   sc->left = 0;
+   sc->right = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
schedule_work(&sc->state_worker);
return 0;
@@ -1330,7 +1341,7 @@ static int sony_init_ff(struct hid_device *hdev)
struct input_dev *input_dev = hidinput->input;
 
input_set_capability(input_dev, EV_FF, FF_RUMBLE);
-   return input_ff_create_memless(input_dev, NULL, sony_play_effect);
+   return input_ff_create_mlnx(input_dev, NULL, sony_play_effect, 
FF_UPDATE_RATE);
 }
 
 #else
@@ -1762,6 +1773,7 @@ static const struct hid_device_id sony_devices[] = {
.driver_data = DUALSHOCK4_CONTROLLER_USB },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, 
USB_DEVICE_ID_SONY_PS4_CONTROLLER),
.driver_data = DUALSHOCK4_CONTROLLER_BT },
+
{ }
 };
 MODULE_DEVICE_TABLE(hid, sony_devices);
-- 
1.9.2

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


[PATCH v3 14/24] hid: Port hid-pl to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-pl to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig  |  2 +-
 drivers/hid/hid-pl.c | 38 ++
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index eb0c7f1..42904e4 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -509,7 +509,7 @@ config HID_PANTHERLORD
 config PANTHERLORD_FF
bool "Pantherlord force feedback support"
depends on HID_PANTHERLORD
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
  Say Y here if you have a PantherLord/GreenAsia based game controller
  or adapter and want to enable force feedback support for it.
diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c
index 2dcd7d9..9b539d5 100644
--- a/drivers/hid/hid-pl.c
+++ b/drivers/hid/hid-pl.c
@@ -44,9 +44,12 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 #ifdef CONFIG_PANTHERLORD_FF
 
 struct plff_device {
@@ -57,24 +60,35 @@ struct plff_device {
 };
 
 static int hid_plff_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 plff_device *plff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int left, right;
 
-   left = effect->u.rumble.strong_magnitude;
-   right = effect->u.rumble.weak_magnitude;
-   debug("called with 0x%04x 0x%04x", left, right);
-
-   left = left * plff->maxval / 0x;
-   right = right * plff->maxval / 0x;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   left = rumble_force->strong;
+   right = rumble_force->weak;
+   debug("called with 0x%04x 0x%04x", left, right);
+
+   left = left * plff->maxval / 0x;
+   right = right * plff->maxval / 0x;
+
+   *plff->strong = left;
+   *plff->weak = right;
+   debug("running with 0x%02x 0x%02x", left, right);
+   break;
+   case MLNX_STOP_RUMBLE:
+   *plff->strong = 0;
+   *plff->weak = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
-   *plff->strong = left;
-   *plff->weak = right;
-   debug("running with 0x%02x 0x%02x", left, right);
hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT);
-
return 0;
 }
 
@@ -160,7 +174,7 @@ static int plff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, plff, hid_plff_play);
+   error = input_ff_create_mlnx(dev, plff, hid_plff_play, 
FF_UPDATE_RATE);
if (error) {
kfree(plff);
return error;
-- 
1.9.2

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


[PATCH v3 13/24] hid: Port hid-lg3ff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-lg3ff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig |  2 +-
 drivers/hid/hid-lg3ff.c | 60 +++--
 2 files changed, 39 insertions(+), 23 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index c4b0cbb..eb0c7f1 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -391,7 +391,7 @@ config LOGIRUMBLEPAD2_FF
 config LOGIG940_FF
bool "Logitech Flight System G940 force feedback support"
depends on HID_LOGITECH
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  Say Y here if you want to enable force feedback support for Logitech
  Flight System G940 devices.
diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c
index 8c2da18..c49b374 100644
--- a/drivers/hid/hid-lg3ff.c
+++ b/drivers/hid/hid-lg3ff.c
@@ -23,9 +23,12 @@
 
 #include 
 #include 
+#include 
 
 #include "hid-lg.h"
 
+#define FF_UPDATE_RATE 50
+
 /*
  * G940 Theory of Operation (from experimentation)
  *
@@ -58,12 +61,11 @@ struct lg3ff_device {
 };
 
 static int hid_lg3ff_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 list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
-   int x, y;
 
 /*
  * Available values in the field should always be 63, but we only use up to
@@ -72,30 +74,37 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data,
memset(report->field[0]->value, 0,
   sizeof(__s32) * report->field[0]->report_count);
 
-   switch (effect->type) {
-   case FF_CONSTANT:
-/*
- * Already clamped in ff_memless
- * 0 is center (different then other logitech)
- */
-   x = effect->u.ramp.start_level;
-   y = effect->u.ramp.end_level;
-
-   /* send command byte */
-   report->field[0]->value[0] = 0x51;
-
-/*
- * Sign backwards from other Force3d pro
- * which get recast here in two's complement 8 bits
- */
-   report->field[0]->value[1] = (unsigned char)(-x);
-   report->field[0]->value[31] = (unsigned char)(-y);
+   /* send command byte */
+   report->field[0]->value[0] = 0x51;
 
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   switch (command->cmd) {
+   case MLNX_START_COMBINED: {
+   const struct mlnx_simple_force *simple_force = 
&command->u.simple_force;
+   /* Scale down from MLNX range */
+   const int x = simple_force->x * 0xff / 0x;
+   const int y = simple_force->y * 0xff / 0x;
+
+   /*
+* Sign backwards from other Force3d pro
+* which get recast here in two's complement 8 bits
+   */
+   report->field[0]->value[1] = (unsigned char)x;
+   report->field[0]->value[31] = (unsigned char)y;
+   break;
+   }
+   case MLNX_STOP_COMBINED:
+   report->field[0]->value[1] = 0;
+   report->field[0]->value[31] = 0;
break;
+   default:
+   return -EINVAL;
}
+
+   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+
return 0;
 }
+
 static void hid_lg3ff_set_autocenter(struct input_dev *dev, u16 magnitude)
 {
struct hid_device *hid = input_get_drvdata(dev);
@@ -123,6 +132,13 @@ static void hid_lg3ff_set_autocenter(struct input_dev 
*dev, u16 magnitude)
 
 static const signed short ff3_joystick_ac[] = {
FF_CONSTANT,
+   FF_RAMP,
+   FF_PERIODIC,
+   FF_SQUARE,
+   FF_TRIANGLE,
+   FF_SINE,
+   FF_SAW_UP,
+   FF_SAW_DOWN,
FF_AUTOCENTER,
-1
 };
@@ -143,7 +159,7 @@ int lg3ff_init(struct hid_device *hid)
for (i = 0; ff_bits[i] >= 0; i++)
set_bit(ff_bits[i], dev->ffbit);
 
-   error = input_ff_create_memless(dev, NULL, hid_lg3ff_play);
+   error = input_ff_create_mlnx(dev, NULL, hid_lg3ff_play, FF_UPDATE_RATE);
if (error)
return error;
 
-- 
1.9.2

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


[PATCH v3 15/24] hid: Port hid-sjoy to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-sjoy to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-sjoy.c | 35 +--
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 42904e4..9260d14 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -692,7 +692,7 @@ config HID_SMARTJOYPLUS
 config SMARTJOYPLUS_FF
bool "SmartJoy PLUS PS2/USB adapter force feedback support"
depends on HID_SMARTJOYPLUS
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you have a SmartJoy PLUS PS2/USB adapter and want to
enable force feedback support for it.
diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c
index 37845ec..a6f8cfe 100644
--- a/drivers/hid/hid-sjoy.c
+++ b/drivers/hid/hid-sjoy.c
@@ -30,8 +30,11 @@
 #include 
 #include 
 #include 
+#include 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 #ifdef CONFIG_SMARTJOYPLUS_FF
 
 struct sjoyff_device {
@@ -39,21 +42,33 @@ struct sjoyff_device {
 };
 
 static int hid_sjoyff_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 sjoyff_device *sjoyff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
u32 left, right;
 
-   left = effect->u.rumble.strong_magnitude;
-   right = effect->u.rumble.weak_magnitude;
-   dev_dbg(&dev->dev, "called with 0x%08x 0x%08x\n", left, right);
-
-   left = left * 0xff / 0x;
-   right = (right != 0); /* on/off only */
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   left = rumble_force->strong;
+   right = rumble_force->weak;
+   dev_dbg(&dev->dev, "called with 0x%08x 0x%08x\n", left, right);
+
+   left = left * 0xff / 0x;
+   right = (right != 0); /* on/off only */
+
+   sjoyff->report->field[0]->value[1] = right;
+   sjoyff->report->field[0]->value[2] = left;
+   break;
+   case MLNX_STOP_RUMBLE:
+   left = 0;
+   right = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
-   sjoyff->report->field[0]->value[1] = right;
-   sjoyff->report->field[0]->value[2] = left;
dev_dbg(&dev->dev, "running with 0x%02x 0x%02x\n", left, right);
hid_hw_request(hid, sjoyff->report, HID_REQ_SET_REPORT);
 
@@ -103,7 +118,7 @@ static int sjoyff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
+   error = input_ff_create_mlnx(dev, sjoyff, hid_sjoyff_play, 
FF_UPDATE_RATE);
if (error) {
kfree(sjoyff);
return error;
-- 
1.9.2

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


[PATCH v3 18/24] hid: Port hid-wiimote-modules to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-wiimote-modules to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig   |  2 +-
 drivers/hid/hid-wiimote-modules.c | 74 ---
 2 files changed, 46 insertions(+), 30 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 17ed5cf..23d9776 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -749,7 +749,7 @@ config HID_WIIMOTE
depends on HID
depends on LEDS_CLASS
select POWER_SUPPLY
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Support for Nintendo Wii and Wii U Bluetooth peripherals. Supported
devices are the Wii Remote and its extension devices, but also devices
diff --git a/drivers/hid/hid-wiimote-modules.c 
b/drivers/hid/hid-wiimote-modules.c
index 6b61f01..95b20ea 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -37,8 +37,11 @@
 #include 
 #include 
 #include 
+#include 
 #include "hid-wiimote.h"
 
+#define FF_UPDATE_RATE 50
+
 /*
  * Keys
  * The initial Wii Remote provided a bunch of buttons that are reported as
@@ -131,21 +134,27 @@ static void wiimod_rumble_worker(struct work_struct *work)
 }
 
 static int wiimod_rumble_play(struct input_dev *dev, void *data,
- struct ff_effect *eff)
+ const struct mlnx_effect_command *command)
 {
struct wiimote_data *wdata = input_get_drvdata(dev);
-   __u8 value;
-
-   /*
-* The wiimote supports only a single rumble motor so if any magnitude
-* is set to non-zero then we start the rumble motor. If both are set to
-* zero, we stop the rumble motor.
-*/
-
-   if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
-   value = 1;
-   else
-   value = 0;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
+   __u8 value = 0;
+
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   /*
+* The wiimote supports only a single rumble motor so if any 
magnitude
+* is set to non-zero then we start the rumble motor. If both 
are set to
+* zero, we stop the rumble motor.
+*/
+   if (rumble_force->strong || rumble_force->weak)
+   value = 1;
+   break;
+   case MLNX_STOP_RUMBLE:
+   break;
+   default:
+   return -EINVAL;
+   }
 
/* Locking state.lock here might deadlock with input_event() calls.
 * schedule_work acts as barrier. Merging multiple changes is fine. */
@@ -161,7 +170,7 @@ static int wiimod_rumble_probe(const struct wiimod_ops *ops,
INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker);
 
set_bit(FF_RUMBLE, wdata->input->ffbit);
-   if (input_ff_create_memless(wdata->input, NULL, wiimod_rumble_play))
+   if (input_ff_create_mlnx(wdata->input, NULL, wiimod_rumble_play, 
FF_UPDATE_RATE))
return -ENOMEM;
 
return 0;
@@ -1771,21 +1780,28 @@ static void wiimod_pro_close(struct input_dev *dev)
 }
 
 static int wiimod_pro_play(struct input_dev *dev, void *data,
-  struct ff_effect *eff)
+  const struct mlnx_effect_command *command)
 {
struct wiimote_data *wdata = input_get_drvdata(dev);
-   __u8 value;
-
-   /*
-* The wiimote supports only a single rumble motor so if any magnitude
-* is set to non-zero then we start the rumble motor. If both are set to
-* zero, we stop the rumble motor.
-*/
-
-   if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
-   value = 1;
-   else
-   value = 0;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
+   __u8 value = 0;
+
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   /*
+* The wiimote supports only a single rumble motor so if any 
magnitude
+* is set to non-zero then we start the rumble motor. If both 
are set to
+* zero, we stop the rumble motor.
+*/
+
+   if (rumble_force->strong || rumble_force->weak)
+   value = 1;
+   break;
+   case MLNX_STOP_RUMBLE:
+   break;
+   default:
+   return -EINVAL;
+   }
 
/* Locking state.lock here might deadlock with input_event() calls.
 * schedule_work acts as barrier. Merging multiple changes is fine. */
@@ -1867,8 +1883,8 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops,
set_bit(FF_RUMBLE, wdata->extension.input->ffbit);
input_set_drvdata(wdata->extension

[PATCH v3 17/24] hid: Port hid-tmff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-tmff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-tmff.c | 83 ++
 2 files changed, 51 insertions(+), 34 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e97c382..17ed5cf 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -730,7 +730,7 @@ config HID_THRUSTMASTER
 config THRUSTMASTER_FF
bool "ThrustMaster devices force feedback support"
depends on HID_THRUSTMASTER
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
  Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or 3,
  a THRUSTMASTER Dual Trigger 3-in-1 or a THRUSTMASTER Ferrari GT
diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c
index b833760..3df000c 100644
--- a/drivers/hid/hid-tmff.c
+++ b/drivers/hid/hid-tmff.c
@@ -31,9 +31,12 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 static const signed short ff_rumble[] = {
FF_RUMBLE,
-1
@@ -41,6 +44,13 @@ static const signed short ff_rumble[] = {
 
 static const signed short ff_joystick[] = {
FF_CONSTANT,
+   FF_RAMP,
+   FF_PERIODIC,
+   FF_SINE,
+   FF_SQUARE,
+   FF_TRIANGLE,
+   FF_SAW_DOWN,
+   FF_SAW_UP,
-1
 };
 
@@ -67,12 +77,12 @@ static inline int tmff_scale_u16(unsigned int in, int 
minimum, int maximum)
return ret;
 }
 
-/* Changes values from -0x80 to 0x7f into values from minimum to maximum */
-static inline int tmff_scale_s8(int in, int minimum, int maximum)
+/* Changes values from -0x7fff to 0x7fff into values from minimum to maximum */
+static inline int tmff_scale_s32(int in, int minimum, int maximum)
 {
int ret;
 
-   ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum;
+   ret = (((in + 0x7fff) * (maximum - minimum)) / 0x) + minimum;
if (ret < minimum)
return minimum;
if (ret > maximum)
@@ -81,43 +91,50 @@ static inline int tmff_scale_s8(int in, int minimum, int 
maximum)
 }
 
 static int tmff_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 tmff_device *tmff = data;
struct hid_field *ff_field = tmff->ff_field;
int x, y;
-   int left, right;/* Rumbling */
-
-   switch (effect->type) {
-   case FF_CONSTANT:
-   x = tmff_scale_s8(effect->u.ramp.start_level,
-   ff_field->logical_minimum,
-   ff_field->logical_maximum);
-   y = tmff_scale_s8(effect->u.ramp.end_level,
-   ff_field->logical_minimum,
-   ff_field->logical_maximum);
-
-   dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
-   ff_field->value[0] = x;
-   ff_field->value[1] = y;
-   hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
-   break;
 
-   case FF_RUMBLE:
-   left = tmff_scale_u16(effect->u.rumble.weak_magnitude,
-   ff_field->logical_minimum,
-   ff_field->logical_maximum);
-   right = tmff_scale_u16(effect->u.rumble.strong_magnitude,
-   ff_field->logical_minimum,
-   ff_field->logical_maximum);
-
-   dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
-   ff_field->value[0] = left;
-   ff_field->value[1] = right;
-   hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
+   switch (command->cmd) {
+   case MLNX_START_COMBINED: {
+   const struct mlnx_simple_force *sf = &command->u.simple_force;
+   x = tmff_scale_s32(sf->x,
+  ff_field->logical_minimum,
+  ff_field->logical_maximum);
+   y = tmff_scale_s32(sf->y,
+  ff_field->logical_minimum,
+  ff_field->logical_maximum);
+   break;
+   }
+   case MLNX_STOP_COMBINED:
+   x = 0;
+   y = 0;
+   break;
+   case MLNX_START_RUMBLE: {
+   const struct mlnx_rumble_force *rumble_force = 
&command->u.rumble_force;
+   x = tmff_scale_u16(rumble_force->weak,
+  ff_field->logical_minimum,
+  ff_field->logical_maximum);
+   y = tmff_scal

[PATCH v3 20/24] input: Port gamecon to ff-memless-next

2014-04-26 Thread Michal Malý
Port gamecon to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/joystick/Kconfig   |  2 +-
 drivers/input/joystick/gamecon.c | 57 ++--
 2 files changed, 33 insertions(+), 26 deletions(-)

diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 56eb471..2dd3ba1 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -221,7 +221,7 @@ config JOYSTICK_DB9
 config JOYSTICK_GAMECON
tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads"
depends on PARPORT
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
  Say Y here if you have a Nintendo Entertainment System gamepad,
  Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index e68e497..209d0fb 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -40,6 +40,7 @@
 #include 
 #include 
 #include 
+#include 
 
 MODULE_AUTHOR("Vojtech Pavlik ");
 MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver");
@@ -47,6 +48,7 @@ MODULE_LICENSE("GPL");
 
 #define GC_MAX_PORTS   3
 #define GC_MAX_DEVICES 5
+#define FF_UPDATE_RATE 50
 
 struct gc_config {
int args[GC_MAX_DEVICES + 1];
@@ -263,43 +265,48 @@ static void gc_n64_process_packet(struct gc *gc)
 }
 
 static int gc_n64_play_effect(struct input_dev *dev, void *data,
- struct ff_effect *effect)
+ const struct mlnx_effect_command *command)
 {
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int i;
unsigned long flags;
struct gc *gc = input_get_drvdata(dev);
struct gc_subdev *sdev = data;
unsigned char target = 1 << sdev->idx; /* select desired pin */
+   unsigned int cmd;
 
-   if (effect->type == FF_RUMBLE) {
-   struct ff_rumble_effect *rumble = &effect->u.rumble;
-   unsigned int cmd =
-   rumble->strong_magnitude || rumble->weak_magnitude ?
-   GC_N64_CMD_01 : GC_N64_CMD_00;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   cmd = (rumble_force->strong || rumble_force->weak) ? 
GC_N64_CMD_01 : GC_N64_CMD_00;
+   break;
+   case MLNX_STOP_RUMBLE:
+   cmd = GC_N64_CMD_00;
+   break;
+   default:
+   return -EINVAL;
+   }
 
-   local_irq_save(flags);
+   local_irq_save(flags);
 
-   /* Init Rumble - 0x03, 0x80, 0x01, (34)0x80 */
-   gc_n64_send_command(gc, GC_N64_CMD_03, target);
+   /* Init Rumble - 0x03, 0x80, 0x01, (34)0x80 */
+   gc_n64_send_command(gc, GC_N64_CMD_03, target);
+   gc_n64_send_command(gc, GC_N64_CMD_80, target);
+   gc_n64_send_command(gc, GC_N64_CMD_01, target);
+   for (i = 0; i < 32; i++)
gc_n64_send_command(gc, GC_N64_CMD_80, target);
-   gc_n64_send_command(gc, GC_N64_CMD_01, target);
-   for (i = 0; i < 32; i++)
-   gc_n64_send_command(gc, GC_N64_CMD_80, target);
-   gc_n64_send_stop_bit(gc, target);
+   gc_n64_send_stop_bit(gc, target);
 
-   udelay(GC_N64_DELAY);
-
-   /* Now start or stop it - 0x03, 0xc0, 0zx1b, (32)0x01/0x00 */
-   gc_n64_send_command(gc, GC_N64_CMD_03, target);
-   gc_n64_send_command(gc, GC_N64_CMD_c0, target);
-   gc_n64_send_command(gc, GC_N64_CMD_1b, target);
-   for (i = 0; i < 32; i++)
-   gc_n64_send_command(gc, cmd, target);
-   gc_n64_send_stop_bit(gc, target);
+   udelay(GC_N64_DELAY);
 
-   local_irq_restore(flags);
+   /* Now start or stop it - 0x03, 0xc0, 0zx1b, (32)0x01/0x00 */
+   gc_n64_send_command(gc, GC_N64_CMD_03, target);
+   gc_n64_send_command(gc, GC_N64_CMD_c0, target);
+   gc_n64_send_command(gc, GC_N64_CMD_1b, target);
+   for (i = 0; i < 32; i++)
+   gc_n64_send_command(gc, cmd, target);
+   gc_n64_send_stop_bit(gc, target);
 
-   }
+   local_irq_restore(flags);
 
return 0;
 }
@@ -317,7 +324,7 @@ static int __init gc_n64_init_ff(struct input_dev *dev, int 
i)
 
input_set_capability(dev, EV_FF, FF_RUMBLE);
 
-   err = input_ff_create_memless(dev, sdev, gc_n64_play_effect);
+   err = input_ff_create_mlnx(dev, sdev, gc_n64_play_effect, 
FF_UPDATE_RATE);
if (err) {
kfree(sdev);
return err;
-- 
1.9.2

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


[PATCH v3 23/24] hid: Port hid-lg4ff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-lg4ff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig |  2 +-
 drivers/hid/hid-lg4ff.c | 93 ++---
 2 files changed, 59 insertions(+), 36 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 5e70519..546ac4a 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -399,7 +399,7 @@ config LOGIG940_FF
 config LOGIWHEELS_FF
bool "Logitech wheels configuration and force feedback support"
depends on HID_LOGITECH
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
default LOGITECH_FF
help
  Say Y here if you want to enable force feedback and range setting
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 24883b4..d629093 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -25,6 +25,7 @@
 
 
 #include 
+#include 
 #include 
 #include 
 
@@ -45,6 +46,8 @@
 #define G27_REV_MIN 0x38
 #define G27_2_REV_MIN 0x39
 
+#define FF_UPDATE_RATE 8
+
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
 static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
@@ -69,6 +72,13 @@ struct lg4ff_device_entry {
 
 static const signed short lg4ff_wheel_effects[] = {
FF_CONSTANT,
+   FF_RAMP,
+   FF_PERIODIC,
+   FF_SQUARE,
+   FF_TRIANGLE,
+   FF_SINE,
+   FF_SAW_UP,
+   FF_SAW_DOWN,
FF_AUTOCENTER,
-1
 };
@@ -184,47 +194,60 @@ int lg4ff_adjust_input_event(struct hid_device *hid, 
struct hid_field *field,
}
 }
 
-static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect 
*effect)
+static int hid_lg4ff_start_combined(struct hid_device *hid, struct hid_report 
*report,
+   const struct mlnx_simple_force *force)
+{
+   __s32 *value = report->field[0]->value;
+   int scaled_x;
+
+   /* Scale down from MLNX range */
+   scaled_x = 0x80 - (force->x * 0xff / 0x);
+
+   value[0] = 0x11;/* Slot 1 */
+   value[1] = 0x08;
+   value[2] = scaled_x;
+   value[3] = 0x80;
+   value[4] = 0x00;
+   value[5] = 0x00;
+   value[6] = 0x00;
+
+   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   return 0;
+}
+
+static int hid_lg4ff_stop_combined(struct hid_device *hid, struct hid_report 
*report)
+{
+   __s32 *value = report->field[0]->value;
+
+   value[0] = 0x13;/* Slot 1 */
+   value[1] = 0x00;
+   value[2] = 0x00;
+   value[3] = 0x00;
+   value[4] = 0x00;
+   value[5] = 0x00;
+   value[6] = 0x00;
+
+   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   return 0;
+}
+
+static int hid_lg4ff_control(struct input_dev *dev, void *data, const struct 
mlnx_effect_command *command)
 {
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = 
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
-   __s32 *value = report->field[0]->value;
-   int x;
-
-#define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while 
(0)
-
-   switch (effect->type) {
-   case FF_CONSTANT:
-   x = effect->u.ramp.start_level + 0x80;  /* 0x80 is no force */
-   CLAMP(x);
-
-   if (x == 0x80) {
-   /* De-activate force in slot-1*/
-   value[0] = 0x13;
-   value[1] = 0x00;
-   value[2] = 0x00;
-   value[3] = 0x00;
-   value[4] = 0x00;
-   value[5] = 0x00;
-   value[6] = 0x00;
-
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
-   return 0;
-   }
-
-   value[0] = 0x11;/* Slot 1 */
-   value[1] = 0x08;
-   value[2] = x;
-   value[3] = 0x80;
-   value[4] = 0x00;
-   value[5] = 0x00;
-   value[6] = 0x00;
 
-   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   switch (command->cmd) {
+   case MLNX_START_COMBINED:
+   return hid_lg4ff_start_combined(hid, report, 
&command->u.simple_force);
+   break;
+   case MLNX_STOP_COMBINED:
+   return hid_lg4ff_stop_combined(hid, report);
break;
+   default:
+   dbg_hid("Unsupported effect command");
+   return -EINVAL;
}
-   return 0;
 }
 
 /* Sends default autocentering command compatible with
@@ -610,7 +633,7 @@ int lg4ff_init(struct hid_device *hid)
for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++)
set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit);
 
- 

[PATCH v3 22/24] hid: Port hid-lg2ff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-lg2ff to ff-memless-next.
Clamp vibration magnitude to range <0x02; 0xfd> to prevent irregular
shaking of the vibration motors.

Signed-off-by: Elias Vanderstuyft 
---
 drivers/hid/Kconfig |  2 +-
 drivers/hid/hid-lg2ff.c | 65 ++---
 2 files changed, 47 insertions(+), 20 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 97d2d8f..5e70519 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -381,7 +381,7 @@ config LOGITECH_FF
 config LOGIRUMBLEPAD2_FF
bool "Logitech force feedback support (variant 2)"
depends on HID_LOGITECH
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
help
  Say Y here if you want to enable force feedback support for:
  - Logitech RumblePad
diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c
index 0e3fb1a..6ab5327 100644
--- a/drivers/hid/hid-lg2ff.c
+++ b/drivers/hid/hid-lg2ff.c
@@ -22,42 +22,69 @@
 
 
 #include 
+#include 
 #include 
 #include 
 
 #include "hid-lg.h"
 
+#define FF_UPDATE_RATE 8
+
 struct lg2ff_device {
struct hid_report *report;
 };
 
-static int play_effect(struct input_dev *dev, void *data,
-struct ff_effect *effect)
+static int hid_lg2ff_start_rumble(struct hid_device *hid, struct hid_report 
*report,
+   const struct mlnx_rumble_force *rumble)
 {
-   struct hid_device *hid = input_get_drvdata(dev);
-   struct lg2ff_device *lg2ff = data;
int weak, strong;
 
-   strong = effect->u.rumble.strong_magnitude;
-   weak = effect->u.rumble.weak_magnitude;
+#define CLAMP_QUIRK(x) do { if (x < 2) x = 2; else if (x > 0xfd) x = 0xfd; } \
+   while (0)
 
-   if (weak || strong) {
-   weak = weak * 0xff / 0x;
-   strong = strong * 0xff / 0x;
+   /* Scale down from MLNX range */
+   strong = rumble->strong * 0xff / 0x;
+   weak = rumble->weak * 0xff / 0x;
+   CLAMP_QUIRK(weak);
+   CLAMP_QUIRK(strong);
 
-   lg2ff->report->field[0]->value[0] = 0x51;
-   lg2ff->report->field[0]->value[2] = weak;
-   lg2ff->report->field[0]->value[4] = strong;
-   } else {
-   lg2ff->report->field[0]->value[0] = 0xf3;
-   lg2ff->report->field[0]->value[2] = 0x00;
-   lg2ff->report->field[0]->value[4] = 0x00;
-   }
+   report->field[0]->value[0] = 0x51;
+   report->field[0]->value[2] = weak;
+   report->field[0]->value[4] = strong;
 
-   hid_hw_request(hid, lg2ff->report, HID_REQ_SET_REPORT);
+   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
return 0;
 }
 
+static int hid_lg2ff_stop_rumble(struct hid_device *hid, struct hid_report 
*report)
+{
+   report->field[0]->value[0] = 0xf3;
+   report->field[0]->value[2] = 0x00;
+   report->field[0]->value[4] = 0x00;
+
+   hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+   return 0;
+}
+
+static int hid_lg2ff_control(struct input_dev *dev, void *data,
+   const struct mlnx_effect_command *command)
+{
+   struct hid_device *hid = input_get_drvdata(dev);
+   struct lg2ff_device *lg2ff = data;
+
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   return hid_lg2ff_start_rumble(hid, lg2ff->report, 
&command->u.rumble_force);
+   break;
+   case MLNX_STOP_RUMBLE:
+   return hid_lg2ff_stop_rumble(hid, lg2ff->report);
+   break;
+   default:
+   dbg_hid("Unsupported effect command");
+   return -EINVAL;
+   }
+}
+
 int lg2ff_init(struct hid_device *hid)
 {
struct lg2ff_device *lg2ff;
@@ -78,7 +105,7 @@ int lg2ff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, lg2ff, play_effect);
+   error = input_ff_create_mlnx(dev, lg2ff, hid_lg2ff_control, 
FF_UPDATE_RATE);
if (error) {
kfree(lg2ff);
return error;
-- 
1.9.2

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


[PATCH v3 24/24] input: Replace ff-memless with ff-memless-next

2014-04-26 Thread Michal Malý
Replace ff-memless with ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/Kconfig  |  13 +-
 drivers/input/Makefile |   1 -
 drivers/input/ff-memless.c | 547 -
 include/linux/input.h  |   3 -
 4 files changed, 1 insertion(+), 563 deletions(-)
 delete mode 100644 drivers/input/ff-memless.c

diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 3780962..061ae3c 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -25,7 +25,7 @@ config INPUT
 
 if INPUT
 
-config INPUT_FF_MEMLESS
+config INPUT_FF_MEMLESS_NEXT
tristate "Support for memoryless force-feedback devices"
help
  Say Y here if you have memoryless force-feedback input device
@@ -36,17 +36,6 @@ config INPUT_FF_MEMLESS
  If unsure, say N.
 
  To compile this driver as a module, choose M here: the
- module will be called ff-memless.
-
-config INPUT_FF_MEMLESS_NEXT
-   tristate "New version of support for memoryless force-feedback devices"
-   help
- Say Y here to enable a new version of support for memoryless force
- feedback devices.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
  module will be called ff-memless-next.
 
 config INPUT_POLLDEV
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index b4f11f5..f7ae055 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -7,7 +7,6 @@
 obj-$(CONFIG_INPUT)+= input-core.o
 input-core-y := input.o input-compat.o input-mt.o ff-core.o
 
-obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
 obj-$(CONFIG_INPUT_FF_MEMLESS_NEXT)+= ff-memless-next.o
 obj-$(CONFIG_INPUT_POLLDEV)+= input-polldev.o
 obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
deleted file mode 100644
index 74c0d8c..000
--- a/drivers/input/ff-memless.c
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- *  Force feedback support for memoryless devices
- *
- *  Copyright (c) 2006 Anssi Hannula 
- *  Copyright (c) 2006 Dmitry Torokhov 
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* #define DEBUG */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Anssi Hannula ");
-MODULE_DESCRIPTION("Force feedback support for memoryless devices");
-
-/* Number of effects handled with memoryless devices */
-#define FF_MEMLESS_EFFECTS 16
-
-/* Envelope update interval in ms */
-#define FF_ENVELOPE_INTERVAL   50
-
-#define FF_EFFECT_STARTED  0
-#define FF_EFFECT_PLAYING  1
-#define FF_EFFECT_ABORTING 2
-
-struct ml_effect_state {
-   struct ff_effect *effect;
-   unsigned long flags;/* effect state (STARTED, PLAYING, etc) */
-   int count;  /* loop count of the effect */
-   unsigned long play_at;  /* start time */
-   unsigned long stop_at;  /* stop time */
-   unsigned long adj_at;   /* last time the effect was sent */
-};
-
-struct ml_device {
-   void *private;
-   struct ml_effect_state states[FF_MEMLESS_EFFECTS];
-   int gain;
-   struct timer_list timer;
-   struct input_dev *dev;
-
-   int (*play_effect)(struct input_dev *dev, void *data,
-  struct ff_effect *effect);
-};
-
-static const struct ff_envelope *get_envelope(const struct ff_effect *effect)
-{
-   static const struct ff_envelope empty_envelope;
-
-   switch (effect->type) {
-   case FF_PERIODIC:
-   return &effect->u.periodic.envelope;
-
-   case FF_CONSTANT:
-   return &effect->u.constant.envelope;
-
-   default:
-   return &empty_envelope;
-   }
-}
-
-/*
- * Check for the next time envelope requires an update on memoryless devices
- */
-static unsigned long calculate_next_time(struct ml_effect_state *state)
-{
-   const struct ff_envelope *envelope = get_envelope(state->effect);
-   unsigned long attack_stop, fade_start, next_fade;
-
-   if (envelope->attack_length) {
-   attack_stop = state->play_

[PATCH v3 21/24] input: Port xpad to ff-memless-next

2014-04-26 Thread Michal Malý
Port xpad to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/input/joystick/Kconfig |   2 +-
 drivers/input/joystick/xpad.c  | 125 +++--
 2 files changed, 71 insertions(+), 56 deletions(-)

diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 2dd3ba1..9f26e48 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -294,7 +294,7 @@ config JOYSTICK_XPAD
 config JOYSTICK_XPAD_FF
bool "X-Box gamepad rumble support"
depends on JOYSTICK_XPAD && INPUT
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
  Say Y here if you want to take advantage of xbox 360 rumble features.
 
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 603fe0d..5d9c8a2 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -78,6 +78,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define DRIVER_AUTHOR "Marko Friedemann "
 #define DRIVER_DESC "X-Box pad driver"
@@ -97,6 +98,8 @@
 #define XTYPE_XBOX360W2
 #define XTYPE_UNKNOWN 3
 
+#define FF_UPDATE_RATE 50
+
 static bool dpad_to_buttons;
 module_param(dpad_to_buttons, bool, S_IRUGO);
 MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for 
unknown pads");
@@ -628,63 +631,75 @@ static void xpad_stop_output(struct usb_xpad *xpad) {}
 #endif
 
 #ifdef CONFIG_JOYSTICK_XPAD_FF
-static int xpad_play_effect(struct input_dev *dev, void *data, struct 
ff_effect *effect)
+static int xpad_play_effect(struct input_dev *dev, void *data,
+   const struct mlnx_effect_command *command)
 {
struct usb_xpad *xpad = input_get_drvdata(dev);
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
+   __u16 strong, weak;
 
-   if (effect->type == FF_RUMBLE) {
-   __u16 strong = effect->u.rumble.strong_magnitude;
-   __u16 weak = effect->u.rumble.weak_magnitude;
-
-   switch (xpad->xtype) {
-
-   case XTYPE_XBOX:
-   xpad->odata[0] = 0x00;
-   xpad->odata[1] = 0x06;
-   xpad->odata[2] = 0x00;
-   xpad->odata[3] = strong / 256;  /* left actuator */
-   xpad->odata[4] = 0x00;
-   xpad->odata[5] = weak / 256;/* right actuator */
-   xpad->irq_out->transfer_buffer_length = 6;
-
-   return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
-   case XTYPE_XBOX360:
-   xpad->odata[0] = 0x00;
-   xpad->odata[1] = 0x08;
-   xpad->odata[2] = 0x00;
-   xpad->odata[3] = strong / 256;  /* left actuator? */
-   xpad->odata[4] = weak / 256;/* right actuator? */
-   xpad->odata[5] = 0x00;
-   xpad->odata[6] = 0x00;
-   xpad->odata[7] = 0x00;
-   xpad->irq_out->transfer_buffer_length = 8;
-
-   return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
-   case XTYPE_XBOX360W:
-   xpad->odata[0] = 0x00;
-   xpad->odata[1] = 0x01;
-   xpad->odata[2] = 0x0F;
-   xpad->odata[3] = 0xC0;
-   xpad->odata[4] = 0x00;
-   xpad->odata[5] = strong / 256;
-   xpad->odata[6] = weak / 256;
-   xpad->odata[7] = 0x00;
-   xpad->odata[8] = 0x00;
-   xpad->odata[9] = 0x00;
-   xpad->odata[10] = 0x00;
-   xpad->odata[11] = 0x00;
-   xpad->irq_out->transfer_buffer_length = 12;
-
-   return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
-
-   default:
-   dev_dbg(&xpad->dev->dev,
-   "%s - rumble command sent to unsupported xpad 
type: %d\n",
-   __func__, xpad->xtype);
-   return -1;
-   }
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   strong = rumble_force->strong;
+   weak = rumble_force->weak;
+   break;
+   case MLNX_STOP_RUMBLE:
+   strong = 0;
+   weak = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
+
+
+   switch (xpad->xtype) {
+
+   case XTYPE_XBOX:
+   xpad->odata[0] = 0x00;
+   xpad->odata[1] = 0x06;
+   xpad->odata[2] = 0x00;
+

[PATCH v3 19/24] hid: Port hid-zpff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-zpff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig|  2 +-
 drivers/hid/hid-zpff.c | 30 ++
 2 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 23d9776..97d2d8f 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -786,7 +786,7 @@ config HID_ZEROPLUS
 config ZEROPLUS_FF
bool "Zeroplus based game controller force feedback support"
depends on HID_ZEROPLUS
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
  Say Y here if you have a Zeroplus based game controller and want
  to have force feedback support for it.
diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c
index a29756c..6912500 100644
--- a/drivers/hid/hid-zpff.c
+++ b/drivers/hid/hid-zpff.c
@@ -25,9 +25,12 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 #ifdef CONFIG_ZEROPLUS_FF
 
 struct zpff_device {
@@ -35,10 +38,11 @@ struct zpff_device {
 };
 
 static int zpff_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 zpff_device *zpff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int left, right;
 
/*
@@ -47,12 +51,22 @@ static int zpff_play(struct input_dev *dev, void *data,
 * however it is possible that the XFX Executioner is an exception
 */
 
-   left = effect->u.rumble.strong_magnitude;
-   right = effect->u.rumble.weak_magnitude;
-   dbg_hid("called with 0x%04x 0x%04x\n", left, right);
-
-   left = left * 0x7f / 0x;
-   right = right * 0x7f / 0x;
+   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);
+
+   left = left * 0x7f / 0x;
+   right = right * 0x7f / 0x;
+   break;
+   case MLNX_STOP_RUMBLE:
+   left = 0;
+   right = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
zpff->report->field[2]->value[0] = left;
zpff->report->field[3]->value[0] = right;
@@ -83,7 +97,7 @@ static int zpff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, zpff, zpff_play);
+   error = input_ff_create_mlnx(dev, zpff, zpff_play, FF_UPDATE_RATE);
if (error) {
kfree(zpff);
return error;
-- 
1.9.2

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


[PATCH v3 08/24] hid: Port hid-emsff to ff-memless-next

2014-04-26 Thread Michal Malý
Port hid-emsff to ff-memless-next

Signed-off-by: Michal Malý 
---
 drivers/hid/Kconfig |  2 +-
 drivers/hid/hid-emsff.c | 38 ++
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e076627..a78b5d8 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -213,7 +213,7 @@ config DRAGONRISE_FF
 config HID_EMS_FF
tristate "EMS Production Inc. force feedback support"
depends on HID
-   select INPUT_FF_MEMLESS
+   select INPUT_FF_MEMLESS_NEXT
---help---
Say Y here if you want to enable force feedback support for devices by
EMS Production Ltd.
diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c
index d82d75b..c0cbe50 100644
--- a/drivers/hid/hid-emsff.c
+++ b/drivers/hid/hid-emsff.c
@@ -24,30 +24,44 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "hid-ids.h"
 
+#define FF_UPDATE_RATE 50
+
 struct emsff_device {
struct hid_report *report;
 };
 
 static int emsff_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 emsff_device *emsff = data;
+   const struct mlnx_rumble_force *rumble_force = &command->u.rumble_force;
int weak, strong;
 
-   weak = effect->u.rumble.weak_magnitude;
-   strong = effect->u.rumble.strong_magnitude;
-
-   dbg_hid("called with 0x%04x 0x%04x\n", strong, weak);
-
-   weak = weak * 0xff / 0x;
-   strong = strong * 0xff / 0x;
-
-   emsff->report->field[0]->value[1] = weak;
-   emsff->report->field[0]->value[2] = strong;
+   switch (command->cmd) {
+   case MLNX_START_RUMBLE:
+   weak = rumble_force->weak;
+   strong = rumble_force->strong;
+
+   dbg_hid("called with 0x%04x 0x%04x\n", strong, weak);
+
+   weak = weak * 0xff / 0x;
+   strong = strong * 0xff / 0x;
+
+   emsff->report->field[0]->value[1] = weak;
+   emsff->report->field[0]->value[2] = strong;
+   break;
+   case MLNX_STOP_RUMBLE:
+   weak = 0;
+   strong = 0;
+   break;
+   default:
+   return -EINVAL;
+   }
 
dbg_hid("running with 0x%02x 0x%02x\n", strong, weak);
hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
@@ -88,7 +102,7 @@ static int emsff_init(struct hid_device *hid)
 
set_bit(FF_RUMBLE, dev->ffbit);
 
-   error = input_ff_create_memless(dev, emsff, emsff_play);
+   error = input_ff_create_mlnx(dev, emsff, emsff_play, FF_UPDATE_RATE);
if (error) {
kfree(emsff);
return error;
-- 
1.9.2

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


[PATCH v3 00/24] input: Introduce ff-memless-next as an improved replacement for ff-memless

2014-04-26 Thread Michal Malý
ff-memless-next (MLNX) is a largely improved version of the current ff-memless
(FFML) driver. MLNX supports all force feedback effects currently available in
the Linux force feedback userspace API. All effects are handled in accordance
with Microsoft's DirectInput/XInput. Most notable changes include support for
conditional effects, proper handling of all periodic waveforms and improved
emulation of rumble effects through periodic effects. MLNX also uses its own
kernel API to pass processed effects to hardware-specific drivers instead of
abusing "ff_effect" struct. The API is documented in the respective header
file.

MLNX has been expanded to be a direct replacement for FFML.

Support for FF_PERIODIC and FF_RAMP has been added to all devices that
support FF_CONSTANT as a part of the port to the new API.

This patch series:
1) Adds "ff-memless-next" module [1]
2) Ports all hardware-specific drivers to MLNX's API [2-23]
3) Removes FFML and replaces it with MLNX [24]

Signed-off-by: Michal Malý 

v3:
 - Rebase against latest linux-next. Fixes conflict in hid-sony.c and
   max8997_haptic.c
 - Updated documentation in ff-memless-next.h. The documentation now describes
   parameters of the callback function and specifically mentions that
   HW-specific drivers must not keep a reference to mlnx_effect_command struct
   to which a pointer is passed in the callback function.
 - Fix a minor brace inconsistency in hid-lgff
 I believe that all concerns regarding v2 have been resolved as false alarms.

v2:
 - Add missing msecs to jiffies conversion in ff-memless-next
 - lgff: Properly convert force on Y axis from MLNX to device range
 Support periodic effects for "joystick_ac" device class
 - lg3ff: Properly convert forces from MLNX to device range
 - Very minor coding style issues fixed

Michal Malý (24):
  Add ff-memless-next module
  Port arizona-haptics to ff-memless-next
  Port twl4030-vibra to ff-memless-next
  Port twl6040-vibra to ff-memless-next
  Port max8997_haptic to ff-memless-next
  Port pm8xxx-vibrator to ff-memless-next
  Port hid-axff to ff-memless-next
  Port hid-emsff to ff-memless-next
  Port hid-dr to ff-memless-next
  Port hid-gaff to ff-memless-next
  Port hid-holtekff to ff-memless-next
  Port hid-lgff to ff-memless-next
  Port hid-lg3ff to ff-memless-next
  Port hid-pl to ff-memless-next
  Port hid-sjoy to ff-memless-next
  Port hid-sony to ff-memless-next
  Port hid-tmff to ff-memless-next
  Port hid-wiimote-modules to ff-memless-next
  Port hid-zpff to ff-memless-next
  Port gamecon to ff-memless-next
  Port xpad to ff-memless-next
  - Port hid-lg2ff to ff-memless-next - Clamp vibration magnitude to
range <0x02; 0xfd> to prevent irregular   shaking of the
vibration motors.
  Port hid-lg4ff to ff-memless-next
  Replace ff-memless with ff-memless-next

 drivers/hid/Kconfig   |   30 +-
 drivers/hid/hid-axff.c|   32 +-
 drivers/hid/hid-dr.c  |   59 +-
 drivers/hid/hid-emsff.c   |   38 +-
 drivers/hid/hid-gaff.c|   32 +-
 drivers/hid/hid-holtekff.c|   47 +-
 drivers/hid/hid-lg2ff.c   |   65 ++-
 drivers/hid/hid-lg3ff.c   |   60 +-
 drivers/hid/hid-lg4ff.c   |   93 +--
 drivers/hid/hid-lgff.c|   70 ++-
 drivers/hid/hid-pl.c  |   38 +-
 drivers/hid/hid-sjoy.c|   35 +-
 drivers/hid/hid-sony.c|   24 +-
 drivers/hid/hid-tmff.c|   83 +--
 drivers/hid/hid-wiimote-modules.c |   74 ++-
 drivers/hid/hid-zpff.c|   30 +-
 drivers/input/Kconfig |4 +-
 drivers/input/Makefile|2 +-
 drivers/input/ff-memless-next.c   | 1037 +
 drivers/input/ff-memless.c|  547 -
 drivers/input/joystick/Kconfig|4 +-
 drivers/input/joystick/gamecon.c  |   57 +-
 drivers/input/joystick/xpad.c |  125 ++--
 drivers/input/misc/Kconfig|   10 +-
 drivers/input/misc/arizona-haptics.c  |   39 +-
 drivers/input/misc/max8997_haptic.c   |   25 +-
 drivers/input/misc/pm8xxx-vibrator.c  |   28 +-
 drivers/input/misc/twl4030-vibra.c|   31 +-
 drivers/input/misc/twl6040-vibra.c|   27 +-
 include/linux/input.h |3 -
 include/linux/input/ff-memless-next.h |  162 +
 31 files changed, 1952 insertions(+), 959 deletions(-)
 create mode 100644 drivers/input/ff-memless-next.c
 delete mode 100644 drivers/input/ff-memless.c
 create mode 100644 include/linux/input/ff-memless-next.h

-- 
1.9.2

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


Re: [PATCH v2 09/24] input: Port hid-dr to ff-memless-next

2014-04-24 Thread Michal Malý
On Wednesday 23 of April 2014 15:41:03 Oliver Neukum wrote:
> On Tue, 2014-04-22 at 15:59 +0200, Michal Malý wrote:
> >  static int drff_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 drff_device *drff = data;
> > 
> > +   const struct mlnx_rumble_force *rumble_force =
> > &command->u.rumble_force;
> > 
> > int strong, weak;
> > 
> > -   strong = effect->u.rumble.strong_magnitude;
> > -   weak = effect->u.rumble.weak_magnitude;
> > +   strong = rumble_force->strong;
> > +   weak = rumble_force->weak;
> > 
> > dbg_hid("called with 0x%04x 0x%04x", strong, weak);
> > 
> > -   if (strong || weak) {
> > -   strong = strong * 0xff / 0x;
> > -   weak = weak * 0xff / 0x;
> > -
> > -   /* While reverse engineering this device, I found that
> > when
> > -  this value is set, it causes the strong rumble to
> > function
> > -  at a near maximum speed, so we'll bypass it. */
> > -   if (weak == 0x0a)
> > -   weak = 0x0b;
> > -
> > -   drff->report->field[0]->value[0] = 0x51;
> > -   drff->report->field[0]->value[1] = 0x00;
> > -   drff->report->field[0]->value[2] = weak;
> > -   drff->report->field[0]->value[4] = strong;
> > -   hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
> > -
> > -   drff->report->field[0]->value[0] = 0xfa;
> > -   drff->report->field[0]->value[1] = 0xfe;
> > -   } else {
> > +   switch (command->cmd) {
> > +   case MLNX_START_RUMBLE:
> > +   if (strong || weak) {
> > +   strong = strong * 0xff / 0x;
> > +   weak = weak * 0xff / 0x;
> > +
> > +   /* While reverse engineering this device, I
> > found that when
> > +   this value is set, it causes the strong rumble
> > to function
> > +   at a near maximum speed, so we'll bypass it.
> > */
> > +   if (weak == 0x0a)
> > +   weak = 0x0b;
> > +
> > +   drff->report->field[0]->value[0] = 0x51;
> > +   drff->report->field[0]->value[1] = 0x00;
> > +   drff->report->field[0]->value[2] = weak;
> > +   drff->report->field[0]->value[4] = strong;
> 
> This looks like an endianness bug.

I don't have a big endian machine to check but why would this be an endianness 
issue? We're dealing with values all the time here, not addresses so I'd 
expect the 'weak' and 'strong' values to be truncated if they won't fit into 
byte. Division done beforehand makes sure that the values are within <0; 255> 
range. As far as I can see this is quite common in the HID and Input code. Am 
I missing something here?

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


  1   2   >