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_event_interruptible_timeout(wait, 0, 
> msecs_to_jiffies(8000));
> + }
>   dev->ff->set_autocenter(dev, 0);
>   }




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_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-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 = [idx];
+
+   if (product->idProduct == 0) {
+   dev_err(>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 = 
_skelswitch_vendors[idx];
+
+   if (vendor->idVendor == 0) {
+   dev_err(>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 = _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(>dev, "Logitech G920 - No interrupt out endpoint 
found");
+   return -ENODEV;
+   }
+
+   if (buffer_size < cmd_len) {
+   dev_err(>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, , USB_CTRL_SET_TIMEOUT);
+
+   if (ret) {
+   dev_err(>dev, "LG G920: Failed to submit URB, errno: %d", 
ret);
+   return ret;
+   }
+   if (xferred != cmd_len) {
+   dev_err(>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 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 <elias@gmail.com>
Signed-off-by: Michal Malý <madcatxs...@devoid-pointer.net>
---
 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 = _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(>dev, "Logitech G920 - No interrupt out endpoint 
found");
+   return -ENODEV;
+   }
+
+   if (buffer_size < cmd_len) {
+   dev_err(>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, , USB_CTRL_SET_TIMEOUT);
+
+   if (ret) {
+   dev_err(>dev, "LG G920: Failed to submit URB, errno: %d", 
ret);
+   return ret;
+   }
+   if (xferred != cmd_len) {
+   dev_err(>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ý <madcatxs...@devoid-pointer.net>

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 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ý <madcatxs...@devoid-pointer.net>
---
 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 = [idx];
+
+   if (product->idProduct == 0) {
+   dev_err(>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 = 
_skelswitch_vendors[idx];
+
+   if (vendor->idVendor == 0) {
+   dev_err(>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



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ý <madcatxs...@devoid-pointer.net> 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 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 = 
>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 = 
>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 = 
>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 = 
>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 wheel */
-static void hid_lg4ff_set_

[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 = 
>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 = 
>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 = 
>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 = 
>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 = 
>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)
/* Formula Force EX ex

[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 = 
>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(>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(>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 = 
>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(>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(>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(>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 = 
>report_enum[HID_OUTPUT_REPORT].report_list;
-   struct hid_report *report = list_entry(report_list->next, struct 
hid_report, list);
struct lg4ff_device_entr

[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(>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(>dev, _attr_real_id);
-   if (error) {
-   device_remove_file(>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(>dev, 
_attr_alternate_modes);
-   if (error) {
-   device_remove_file(>dev, _attr_real_id);
-   device_remove_file(>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, _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 = _multimode_wheels[mmode_idx];
}
+   lg4ff_init_wheel_data(>wdata, _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 = 
>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(>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(>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(>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 = 
>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 = report->field[0]->value;
+   u32 expand_a

[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 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ý madcatxs...@devoid-pointer.net
---
 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 wheel */
-static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
+static void hid_lg4ff_set_range_dfp(struct

[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ý madcatxs...@devoid-pointer.net
---
 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)
/* Formula Force EX expects different

[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ý madcatxs...@devoid-pointer.net
---
 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 si...@mungewell.org or Michal 
Maly madcatxs...@gmail.com\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 si...@mungewell.org or Michal Maly 
madcatxs...@devoid-pointer.net\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ý madcatxs...@devoid-pointer.net
---
 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 = list_entry(report_list-next, struct 
hid_report, list);
struct lg4ff_device_entry *entry;
struct lg_drv_data *drv_data;
unsigned

[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 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ý madcatxs...@devoid-pointer.net
---
 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 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ý madcatxs...@devoid-pointer.net
---
 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ý madcatxs...@devoid-pointer.net
---
 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ý madcatxs...@devoid-pointer.net
---
 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 = report-field[0]-value;
+   u32 expand_a, expand_b;
+   unsigned long flags;
 
drv_data = hid_get_drvdata(hid

[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ý madcatxs...@devoid-pointer.net
---
 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ý madcatxs...@devoid-pointer.net
---
 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/dev/range.
+What:  /sys/bus/hid/drivers/logitech/dev/range
 Date:  July 2011
 KernelVersion: 3.2
-Contact:   Michal Malý madcatxs...@gmail.com
+Contact:   Michal Malý madcatxs...@devoid-pointer.net
 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/dev/alternate_modes
 Date:  Feb 2015
 KernelVersion: 4.1
-Contact:   Michal Malý madcatxs...@gmail.com
+Contact:   Michal Malý madcatxs...@devoid-pointer.net
 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/dev/real_id
 Date:  Feb 2015
 KernelVersion: 4.1
-Contact:   Michal Malý madcatxs...@gmail.com
+Contact:   Michal Malý madcatxs...@devoid-pointer.net
 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 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ý madcatxs...@devoid-pointer.net
---
 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 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ý madcatxs...@devoid-pointer.net
---
 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 = 
>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, 
, 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,
+   {_dfgt_ident_info,
+_g27_ident_info,
+_g25_ident_info,
+_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, _dfgt}, /* Driving Force GT */
-   {DFGT_REV_MAJ, DFGT2_REV_MIN

[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 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ý madcatxs...@devoid-pointer.net
---
 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ý madcatxs...@gmail.com
 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/dev/alternate_modes
+Date:  Feb 2015
+KernelVersion: 4.1
+Contact:   Michal Malý madcatxs...@gmail.com
+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/dev/real_id
+Date:  Feb 2015
+KernelVersion: 4.1
+Contact:   Michal Malý madcatxs...@gmail.com
+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_MODE_G25 | LG4FF_MODE_DFP | 
LG4FF_MODE_DFEX

[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ý madcatxs...@devoid-pointer.net
---
 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}, /* Driving Force GT */
-   {DFGT_REV_MAJ, DFGT2_REV_MIN, native_dfgt

[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ý madcatxs...@devoid-pointer.net
---
 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/dev/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 - Understood by G25 and G27 */
+static const struct lg4ff_compat_mode_switch

[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ý madcatxs...@devoid-pointer.net

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ý madcatxs...@devoid-pointer.net
---
 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] 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ý madcatxs...@devoid-pointer.net
---
 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 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,
+   {_dfgt_ident_info,
+_g27_ident_info,
+_g25_ident_info,
+_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, _dfgt}, /* Driving Force GT */
-   {DFGT_REV_MAJ, DFGT2_REV_MIN, _dfgt},/* Driving Force GT v2 
*/
-   {DFP_REV_MAJ,  DFP_REV_MIN,  _dfp},  /* Driving Force Pro */
-   {G25_REV_MAJ,  G25_REV_MIN,  _g25},  /* G25 */
-   {G27_REV_MAJ,  G27_REV_MIN,  _g

[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 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ý madcatxs...@devoid-pointer.net
---
 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_MIN,  native_g25},  /* G25 */
-   {G27_REV_MAJ

[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ý madcatxs...@devoid-pointer.net
---
 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/dev/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 - Understood by G25 and G27 */
+static const struct lg4ff_compat_mode_switch

[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ý madcatxs...@devoid-pointer.net
---
 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ý madcatxs...@gmail.com
 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/dev/alternate_modes
+Date:  Feb 2015
+KernelVersion: 4.1
+Contact:   Michal Malý madcatxs...@gmail.com
+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/dev/real_id
+Date:  Feb 2015
+KernelVersion: 4.1
+Contact:   Michal Malý madcatxs...@gmail.com
+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_MODE_G25 | LG4FF_MODE_DFP | 
LG4FF_MODE_DFEX

[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ý madcatxs...@devoid-pointer.net

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ý madcatxs...@devoid-pointer.net
---
 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 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,
+   {_dfgt_ident_info,
+_g27_ident_info,
+_g25_ident_info,
+_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, _dfgt}, /* Driving Force GT */
-   {DFGT_REV_MAJ, DFGT2_REV_MIN, _dfgt},/* Driv

[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

[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ý madcatxs...@devoid-pointer.net 
---
 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_REV_MAJ, DFGT2_REV_MIN, native_dfgt

[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ý madcatxs...@devoid-pointer.net 

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 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ý madcatxs...@devoid-pointer.net 
---
 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 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ý madcatxs...@devoid-pointer.net 
---
 .../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ý madcatxs...@gmail.com
 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/dev/alternate_modes
+Date:  Feb 2015
+KernelVersion: 3.21
+Contact:   Michal Malý madcatxs...@gmail.com
+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/dev/real_id
+Date:  Feb 2015
+KernelVersion: 3.21
+Contact:   Michal Malý madcatxs...@gmail.com
+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

[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ý madcatxs...@devoid-pointer.net 
---
 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_TAG, 
LG4FF_DFEX_NAME},
+   [LG4FF_MODE_DFP_IDX] = {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, 
LG4FF_DFP_TAG, LG4FF_DFP_NAME

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/


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

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ý madcatxs...@devoid-pointer.net

---
 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, char *buf);
@@ -73,6 +62,26 @@ static const signed short

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: [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. For ins

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

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_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.
 
 Thank you for the explanation. This further solidifies for me the idea
 that handling of such effects that are in fact uploaded to and managed
 by the device should not be handled by the memoryless core but rather by
 the driver itself. I.e. such drivers should implement their own play(),
 upload(), erase(), etc, and decide whether to use a hardware slot for
 the effect or handle effect in memoryless fashion

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. 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.
  
  Thank you for the explanation. This further solidifies for me the idea
  that handling of such effects that are in fact uploaded to and managed
  by the device should not be handled by the memoryless core but rather by
  the driver itself. I.e. such drivers should implement their own play(),
  upload(), erase(), etc, and decide whether to use a hardware slot for
  the effect or handle effect in memoryless fashion (if possible

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 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 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-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

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 been successf

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 been successful.
  ff-memless-next will never send + * a START/STOP_UNCOMB command for an
  effect that has not been uploaded + * successfully, nor will it send an
  ERASE command for an effect that is + * playing (= has been started with
  START_UNCOMB command).
  
  + */
  +
  +enum mlnx_commands {
  +   /* Start or update a combined effect. This command is sent whenever
  +* a FF_CONSTANT, FF_PERIODIC or FF_RAMP is started

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_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.
 
 Thank you for the explanation. This further solidifies for me the idea
 that handling of such effects that are in fact uploaded to and managed
 by the device should not be handled by the memoryless core but rather by
 the driver itself. I.e. such drivers should implement their own play(),
 upload(), erase(), etc, and decide whether to use a hardware slot for
 the effect or handle effect in memoryless fashion

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 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/


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 *mlnxeff)
+{
+  

[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, 
>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 = 
>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, 
>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->ffbi

[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 = >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(>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 >u.periodic.envelope;
-
-   case FF_CONSTANT:
-   return >u.constant.envelope;
-
-   default:
-  

[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 = >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, >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/


  1   2   3   4   >