linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] drivers: input: mouse: Add Foxconn's CNTouch driver
@ 2015-01-29 16:03 Thomas Sanchez
  2015-01-29 16:22 ` [PATCH v2] " Thomas Sanchez
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Sanchez @ 2015-01-29 16:03 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-input, Thomas Sanchez

This commit introduces a new driver for Foxconn CNTouch trackpad that
can be found on LDLC's laptop IRIS family.  The driver has been inspired
from usbmouse.c.

Signed-off-by: Thomas Sanchez <thomas.sanchz@gmail.com>
---
 drivers/input/mouse/Kconfig       |  11 ++
 drivers/input/mouse/Makefile      |   1 +
 drivers/input/mouse/foxconn_usb.c | 206 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 218 insertions(+)
 create mode 100644 drivers/input/mouse/foxconn_usb.c

diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index d8b46b0..3ccb924 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -403,4 +403,15 @@ config MOUSE_NAVPOINT_PXA27x
 	  To compile this driver as a module, choose M here: the
 	  module will be called navpoint.
 
+config MOUSE_FOXCONN_CNTOUCH
+	tristate "Foxconn CNTouch USB device support"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  This driver adds support for the Foxconn CNTouch trackpad present for
+	  instance on IRIS laptop family from LDLC.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called foxconn_usb.
+
 endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 560003d..4bfcc75 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MOUSE_ATARI)		+= atarimouse.o
 obj-$(CONFIG_MOUSE_BCM5974)		+= bcm5974.o
 obj-$(CONFIG_MOUSE_CYAPA)		+= cyapa.o
 obj-$(CONFIG_MOUSE_ELAN_I2C)		+= elan_i2c.o
+obj-$(CONFIG_MOUSE_FOXCONN_CNTOUCH)	+= foxconn_usb.o
 obj-$(CONFIG_MOUSE_GPIO)		+= gpio_mouse.o
 obj-$(CONFIG_MOUSE_INPORT)		+= inport.o
 obj-$(CONFIG_MOUSE_LOGIBM)		+= logibm.o
diff --git a/drivers/input/mouse/foxconn_usb.c b/drivers/input/mouse/foxconn_usb.c
new file mode 100644
index 0000000..4627c5c
--- /dev/null
+++ b/drivers/input/mouse/foxconn_usb.c
@@ -0,0 +1,206 @@
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+
+#define USB_VENDOR_ID_FOXCONN		0x294e
+#define USB_DEVICE_ID_FOXCONN_CNTOUCH	0x1001
+
+#define DRIVER_DESC	"CNTouch USB Driver"
+
+static const struct usb_device_id cntouch_devices[] = {
+	{USB_DEVICE(USB_VENDOR_ID_FOXCONN, USB_DEVICE_ID_FOXCONN_CNTOUCH)},
+	{},
+};
+
+MODULE_AUTHOR("Thomas Sanchez, thomas.sanchz@gmail.com")
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(usb, cntouch_devices);
+
+struct cntouch_device {
+	struct usb_device *usb_dev;
+	struct input_dev *input_dev;
+	struct urb *irq;
+	signed char *data;
+	dma_addr_t data_dma;
+	char usb_path[64];
+};
+
+static void cntouch_irq(struct urb *urb)
+{
+	struct cntouch_device *cn_dev = urb->context;
+	signed char *data = cn_dev->data;
+	struct input_dev *dev = cn_dev->input_dev;
+	int status;
+
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:
+		goto resubmit;
+	}
+
+	input_report_key(dev, BTN_LEFT, data[0] & 0x01);
+	input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
+
+	/*
+	 * when scrolling horizontally with two fingers, data[4] is used but I
+	 * did not find the right mapping...
+	 */
+	input_report_key(dev, BTN_TOOL_FINGER, data[4] == 0 ? 1 : 2);
+
+	input_report_rel(dev, REL_X, data[1]);
+	input_report_rel(dev, REL_Y, data[2]);
+
+	input_report_rel(dev, REL_WHEEL, data[3]);
+
+	input_sync(dev);
+
+resubmit:
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status) {
+		dev_err(&cn_dev->usb_dev->dev,
+			"can't resubmit intr, %s-%s/input0, status %d\n",
+			cn_dev->usb_dev->bus->bus_name,
+			cn_dev->usb_dev->devpath, status);
+	}
+}
+
+static int cntouch_open(struct input_dev *dev)
+{
+	struct cntouch_device *cn_dev = input_get_drvdata(dev);
+
+	cn_dev->irq->dev = cn_dev->usb_dev;
+	if (usb_submit_urb(cn_dev->irq, GFP_KERNEL))
+		return -EIO;
+	return 0;
+}
+
+static void cntouch_close(struct input_dev *dev)
+{
+	struct cntouch_device *cn_dev = input_get_drvdata(dev);
+
+	usb_kill_urb(cn_dev->irq);
+}
+
+static int cntouch_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(interface);
+	struct cntouch_device *cn_dev = NULL;
+	struct usb_host_interface *host_interface;
+	struct usb_endpoint_descriptor *endpoint;
+	int pipe, maxp;
+	int error = -ENOMEM;
+
+	host_interface = interface->cur_altsetting;
+
+	if (host_interface->desc.bNumEndpoints != 1)
+		return -ENODEV;
+
+	endpoint = &host_interface->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	pipe = usb_rcvintpipe(usb_dev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe));
+
+	cn_dev = kzalloc(sizeof(*cn_dev), GFP_KERNEL);
+	if (cn_dev == NULL)
+		goto err_1;
+
+	cn_dev->input_dev = input_allocate_device();
+	if (!cn_dev->input_dev)
+		goto err_2;
+
+	cn_dev->usb_dev = usb_get_dev(usb_dev);
+
+	cn_dev->data =
+	    usb_alloc_coherent(usb_dev, 8, GFP_ATOMIC, &cn_dev->data_dma);
+	if (!cn_dev->data)
+		goto err_3;
+
+	cn_dev->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!cn_dev->irq)
+		goto err_4;
+
+	usb_set_intfdata(interface, cn_dev);
+
+	usb_make_path(usb_dev, cn_dev->usb_path, sizeof(cn_dev->usb_path));
+	strlcat(cn_dev->usb_path, "/input0", sizeof(cn_dev->usb_path));
+
+	cn_dev->input_dev->name = "CNTouch";
+	cn_dev->input_dev->phys = cn_dev->usb_path;
+	usb_to_input_id(usb_dev, &cn_dev->input_dev->id);
+	cn_dev->input_dev->dev.parent = &interface->dev;
+
+	cn_dev->input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+	cn_dev->input_dev->keybit[BIT_WORD(BTN_MOUSE)] =
+	    BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
+	cn_dev->input_dev->relbit[0] =
+	    BIT_MASK(REL_X) | BIT_MASK(REL_Y) | BIT_MASK(REL_WHEEL);
+
+	input_set_drvdata(cn_dev->input_dev, cn_dev);
+
+	cn_dev->input_dev->open = cntouch_open;
+	cn_dev->input_dev->close = cntouch_close;
+
+	usb_fill_int_urb(cn_dev->irq, usb_dev, pipe, cn_dev->data,
+			 (maxp > 8 ? 8 : maxp), cntouch_irq, cn_dev,
+			 endpoint->bInterval);
+	cn_dev->irq->transfer_dma = cn_dev->data_dma;
+	cn_dev->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	error = input_register_device(cn_dev->input_dev);
+	if (error)
+		goto err_5;
+
+	dev_info(&interface->dev, DRIVER_DESC "device now attached\n");
+	return 0;
+
+err_5:
+	usb_free_urb(cn_dev->irq);
+err_4:
+	usb_free_coherent(usb_dev, 8, cn_dev->data, cn_dev->data_dma);
+err_3:
+	input_free_device(cn_dev->input_dev);
+err_2:
+	usb_set_intfdata(interface, NULL);
+	usb_put_dev(cn_dev->usb_dev);
+	kfree(cn_dev);
+err_1:
+	dev_err(&interface->dev, "out of memory\n");
+	return error;
+}
+
+static void cntouch_disconnect(struct usb_interface *interface)
+{
+	struct cntouch_device *cn_dev = usb_get_intfdata(interface);
+
+	usb_kill_urb(cn_dev->irq);
+	input_unregister_device(cn_dev->input_dev);
+	usb_free_urb(cn_dev->irq);
+	usb_free_coherent(cn_dev->usb_dev, 8, cn_dev->data, cn_dev->data_dma);
+	usb_set_intfdata(interface, NULL);
+	usb_put_dev(cn_dev->usb_dev);
+	input_free_device(cn_dev->input_dev);
+	kfree(cn_dev);
+	dev_info(&interface->dev, DRIVER_DESC " now disconnected\n");
+}
+
+static struct usb_driver cntouch_driver = {
+	.name = "CNTouch",
+	.probe = &cntouch_probe,
+	.disconnect = &cntouch_disconnect,
+	.id_table = cntouch_devices,
+};
+
+module_usb_driver(cntouch_driver);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2] drivers: input: mouse: Add Foxconn's CNTouch driver
  2015-01-29 16:03 [PATCH] drivers: input: mouse: Add Foxconn's CNTouch driver Thomas Sanchez
@ 2015-01-29 16:22 ` Thomas Sanchez
  2015-01-29 16:22   ` [PATCH] " Thomas Sanchez
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Sanchez @ 2015-01-29 16:22 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-input

Of course for my first mail ever on a Linux ML I did a mistake...
Here is a patch that actually compiles.

Sorry for the noise.
Please let me know if anything's wrong.

Cheers,



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] drivers: input: mouse: Add Foxconn's CNTouch driver
  2015-01-29 16:22 ` [PATCH v2] " Thomas Sanchez
@ 2015-01-29 16:22   ` Thomas Sanchez
  2015-02-01  4:50     ` Dmitry Torokhov
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Sanchez @ 2015-01-29 16:22 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-input, Thomas Sanchez

This commit introduces a new driver for Foxconn CNTouch trackpad that
can be found on LDLC's laptop IRIS family.  The driver has been inspired
from usbmouse.c.

Signed-off-by: Thomas Sanchez <thomas.sanchz@gmail.com>
---
 drivers/input/mouse/Kconfig       |  11 ++
 drivers/input/mouse/Makefile      |   1 +
 drivers/input/mouse/foxconn_usb.c | 206 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 218 insertions(+)
 create mode 100644 drivers/input/mouse/foxconn_usb.c

diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index d8b46b0..3ccb924 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -403,4 +403,15 @@ config MOUSE_NAVPOINT_PXA27x
 	  To compile this driver as a module, choose M here: the
 	  module will be called navpoint.
 
+config MOUSE_FOXCONN_CNTOUCH
+	tristate "Foxconn CNTouch USB device support"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  This driver adds support for the Foxconn CNTouch trackpad present for
+	  instance on IRIS laptop family from LDLC.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called foxconn_usb.
+
 endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 560003d..4bfcc75 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MOUSE_ATARI)		+= atarimouse.o
 obj-$(CONFIG_MOUSE_BCM5974)		+= bcm5974.o
 obj-$(CONFIG_MOUSE_CYAPA)		+= cyapa.o
 obj-$(CONFIG_MOUSE_ELAN_I2C)		+= elan_i2c.o
+obj-$(CONFIG_MOUSE_FOXCONN_CNTOUCH)	+= foxconn_usb.o
 obj-$(CONFIG_MOUSE_GPIO)		+= gpio_mouse.o
 obj-$(CONFIG_MOUSE_INPORT)		+= inport.o
 obj-$(CONFIG_MOUSE_LOGIBM)		+= logibm.o
diff --git a/drivers/input/mouse/foxconn_usb.c b/drivers/input/mouse/foxconn_usb.c
new file mode 100644
index 0000000..d05d03e
--- /dev/null
+++ b/drivers/input/mouse/foxconn_usb.c
@@ -0,0 +1,206 @@
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+
+#define USB_VENDOR_ID_FOXCONN		0x294e
+#define USB_DEVICE_ID_FOXCONN_CNTOUCH	0x1001
+
+#define DRIVER_DESC	"CNTouch USB Driver"
+
+static const struct usb_device_id cntouch_devices[] = {
+	{USB_DEVICE(USB_VENDOR_ID_FOXCONN, USB_DEVICE_ID_FOXCONN_CNTOUCH)},
+	{},
+};
+
+MODULE_AUTHOR("Thomas Sanchez, thomas.sanchz@gmail.com");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(usb, cntouch_devices);
+
+struct cntouch_device {
+	struct usb_device *usb_dev;
+	struct input_dev *input_dev;
+	struct urb *irq;
+	signed char *data;
+	dma_addr_t data_dma;
+	char usb_path[64];
+};
+
+static void cntouch_irq(struct urb *urb)
+{
+	struct cntouch_device *cn_dev = urb->context;
+	signed char *data = cn_dev->data;
+	struct input_dev *dev = cn_dev->input_dev;
+	int status;
+
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:
+		goto resubmit;
+	}
+
+	input_report_key(dev, BTN_LEFT, data[0] & 0x01);
+	input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
+
+	/*
+	 * when scrolling horizontally with two fingers, data[4] is used but I
+	 * did not find the right mapping...
+	 */
+	input_report_key(dev, BTN_TOOL_FINGER, data[4] == 0 ? 1 : 2);
+
+	input_report_rel(dev, REL_X, data[1]);
+	input_report_rel(dev, REL_Y, data[2]);
+
+	input_report_rel(dev, REL_WHEEL, data[3]);
+
+	input_sync(dev);
+
+resubmit:
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status) {
+		dev_err(&cn_dev->usb_dev->dev,
+			"can't resubmit intr, %s-%s/input0, status %d\n",
+			cn_dev->usb_dev->bus->bus_name,
+			cn_dev->usb_dev->devpath, status);
+	}
+}
+
+static int cntouch_open(struct input_dev *dev)
+{
+	struct cntouch_device *cn_dev = input_get_drvdata(dev);
+
+	cn_dev->irq->dev = cn_dev->usb_dev;
+	if (usb_submit_urb(cn_dev->irq, GFP_KERNEL))
+		return -EIO;
+	return 0;
+}
+
+static void cntouch_close(struct input_dev *dev)
+{
+	struct cntouch_device *cn_dev = input_get_drvdata(dev);
+
+	usb_kill_urb(cn_dev->irq);
+}
+
+static int cntouch_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(interface);
+	struct cntouch_device *cn_dev = NULL;
+	struct usb_host_interface *host_interface;
+	struct usb_endpoint_descriptor *endpoint;
+	int pipe, maxp;
+	int error = -ENOMEM;
+
+	host_interface = interface->cur_altsetting;
+
+	if (host_interface->desc.bNumEndpoints != 1)
+		return -ENODEV;
+
+	endpoint = &host_interface->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	pipe = usb_rcvintpipe(usb_dev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe));
+
+	cn_dev = kzalloc(sizeof(*cn_dev), GFP_KERNEL);
+	if (cn_dev == NULL)
+		goto err_1;
+
+	cn_dev->input_dev = input_allocate_device();
+	if (!cn_dev->input_dev)
+		goto err_2;
+
+	cn_dev->usb_dev = usb_get_dev(usb_dev);
+
+	cn_dev->data =
+	    usb_alloc_coherent(usb_dev, 8, GFP_ATOMIC, &cn_dev->data_dma);
+	if (!cn_dev->data)
+		goto err_3;
+
+	cn_dev->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!cn_dev->irq)
+		goto err_4;
+
+	usb_set_intfdata(interface, cn_dev);
+
+	usb_make_path(usb_dev, cn_dev->usb_path, sizeof(cn_dev->usb_path));
+	strlcat(cn_dev->usb_path, "/input0", sizeof(cn_dev->usb_path));
+
+	cn_dev->input_dev->name = "CNTouch";
+	cn_dev->input_dev->phys = cn_dev->usb_path;
+	usb_to_input_id(usb_dev, &cn_dev->input_dev->id);
+	cn_dev->input_dev->dev.parent = &interface->dev;
+
+	cn_dev->input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+	cn_dev->input_dev->keybit[BIT_WORD(BTN_MOUSE)] =
+	    BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
+	cn_dev->input_dev->relbit[0] =
+	    BIT_MASK(REL_X) | BIT_MASK(REL_Y) | BIT_MASK(REL_WHEEL);
+
+	input_set_drvdata(cn_dev->input_dev, cn_dev);
+
+	cn_dev->input_dev->open = cntouch_open;
+	cn_dev->input_dev->close = cntouch_close;
+
+	usb_fill_int_urb(cn_dev->irq, usb_dev, pipe, cn_dev->data,
+			 (maxp > 8 ? 8 : maxp), cntouch_irq, cn_dev,
+			 endpoint->bInterval);
+	cn_dev->irq->transfer_dma = cn_dev->data_dma;
+	cn_dev->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	error = input_register_device(cn_dev->input_dev);
+	if (error)
+		goto err_5;
+
+	dev_info(&interface->dev, DRIVER_DESC "device now attached\n");
+	return 0;
+
+err_5:
+	usb_free_urb(cn_dev->irq);
+err_4:
+	usb_free_coherent(usb_dev, 8, cn_dev->data, cn_dev->data_dma);
+err_3:
+	input_free_device(cn_dev->input_dev);
+err_2:
+	usb_set_intfdata(interface, NULL);
+	usb_put_dev(cn_dev->usb_dev);
+	kfree(cn_dev);
+err_1:
+	dev_err(&interface->dev, "out of memory\n");
+	return error;
+}
+
+static void cntouch_disconnect(struct usb_interface *interface)
+{
+	struct cntouch_device *cn_dev = usb_get_intfdata(interface);
+
+	usb_kill_urb(cn_dev->irq);
+	input_unregister_device(cn_dev->input_dev);
+	usb_free_urb(cn_dev->irq);
+	usb_free_coherent(cn_dev->usb_dev, 8, cn_dev->data, cn_dev->data_dma);
+	usb_set_intfdata(interface, NULL);
+	usb_put_dev(cn_dev->usb_dev);
+	input_free_device(cn_dev->input_dev);
+	kfree(cn_dev);
+	dev_info(&interface->dev, DRIVER_DESC " now disconnected\n");
+}
+
+static struct usb_driver cntouch_driver = {
+	.name = "CNTouch",
+	.probe = &cntouch_probe,
+	.disconnect = &cntouch_disconnect,
+	.id_table = cntouch_devices,
+};
+
+module_usb_driver(cntouch_driver);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] drivers: input: mouse: Add Foxconn's CNTouch driver
  2015-01-29 16:22   ` [PATCH] " Thomas Sanchez
@ 2015-02-01  4:50     ` Dmitry Torokhov
  2015-02-15 12:39       ` [PATCH v3] " Thomas Sanchez
  0 siblings, 1 reply; 10+ messages in thread
From: Dmitry Torokhov @ 2015-02-01  4:50 UTC (permalink / raw)
  To: Thomas Sanchez; +Cc: linux-input

Hi Thomas,

On Thu, Jan 29, 2015 at 05:22:50PM +0100, Thomas Sanchez wrote:
> This commit introduces a new driver for Foxconn CNTouch trackpad that
> can be found on LDLC's laptop IRIS family.  The driver has been inspired
> from usbmouse.c.

So I guess it does not work as a standard HID device, does it?

> 
> Signed-off-by: Thomas Sanchez <thomas.sanchz@gmail.com>
> ---
>  drivers/input/mouse/Kconfig       |  11 ++
>  drivers/input/mouse/Makefile      |   1 +
>  drivers/input/mouse/foxconn_usb.c | 206 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 218 insertions(+)
>  create mode 100644 drivers/input/mouse/foxconn_usb.c
> 
> diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
> index d8b46b0..3ccb924 100644
> --- a/drivers/input/mouse/Kconfig
> +++ b/drivers/input/mouse/Kconfig
> @@ -403,4 +403,15 @@ config MOUSE_NAVPOINT_PXA27x
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called navpoint.
>  
> +config MOUSE_FOXCONN_CNTOUCH
> +	tristate "Foxconn CNTouch USB device support"
> +	depends on USB_ARCH_HAS_HCD
> +	select USB
> +	help
> +	  This driver adds support for the Foxconn CNTouch trackpad present for
> +	  instance on IRIS laptop family from LDLC.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called foxconn_usb.
> +
>  endif
> diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
> index 560003d..4bfcc75 100644
> --- a/drivers/input/mouse/Makefile
> +++ b/drivers/input/mouse/Makefile
> @@ -10,6 +10,7 @@ obj-$(CONFIG_MOUSE_ATARI)		+= atarimouse.o
>  obj-$(CONFIG_MOUSE_BCM5974)		+= bcm5974.o
>  obj-$(CONFIG_MOUSE_CYAPA)		+= cyapa.o
>  obj-$(CONFIG_MOUSE_ELAN_I2C)		+= elan_i2c.o
> +obj-$(CONFIG_MOUSE_FOXCONN_CNTOUCH)	+= foxconn_usb.o
>  obj-$(CONFIG_MOUSE_GPIO)		+= gpio_mouse.o
>  obj-$(CONFIG_MOUSE_INPORT)		+= inport.o
>  obj-$(CONFIG_MOUSE_LOGIBM)		+= logibm.o
> diff --git a/drivers/input/mouse/foxconn_usb.c b/drivers/input/mouse/foxconn_usb.c
> new file mode 100644
> index 0000000..d05d03e
> --- /dev/null
> +++ b/drivers/input/mouse/foxconn_usb.c
> @@ -0,0 +1,206 @@

It is customary to put copyright notice and license at the beginning of
the file.

> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/usb.h>
> +#include <linux/usb/input.h>
> +
> +#define USB_VENDOR_ID_FOXCONN		0x294e
> +#define USB_DEVICE_ID_FOXCONN_CNTOUCH	0x1001
> +
> +#define DRIVER_DESC	"CNTouch USB Driver"
> +
> +static const struct usb_device_id cntouch_devices[] = {
> +	{USB_DEVICE(USB_VENDOR_ID_FOXCONN, USB_DEVICE_ID_FOXCONN_CNTOUCH)},
> +	{},
> +};
> +
> +MODULE_AUTHOR("Thomas Sanchez, thomas.sanchz@gmail.com");
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE("GPL");
> +
> +MODULE_DEVICE_TABLE(usb, cntouch_devices);
> +
> +struct cntouch_device {
> +	struct usb_device *usb_dev;
> +	struct input_dev *input_dev;
> +	struct urb *irq;
> +	signed char *data;
> +	dma_addr_t data_dma;
> +	char usb_path[64];
> +};
> +
> +static void cntouch_irq(struct urb *urb)
> +{
> +	struct cntouch_device *cn_dev = urb->context;
> +	signed char *data = cn_dev->data;
> +	struct input_dev *dev = cn_dev->input_dev;
> +	int status;
> +
> +	switch (urb->status) {
> +	case 0:
> +		break;
> +	case -ECONNRESET:
> +	case -ENOENT:
> +	case -ESHUTDOWN:
> +		return;
> +	default:
> +		goto resubmit;
> +	}
> +
> +	input_report_key(dev, BTN_LEFT, data[0] & 0x01);
> +	input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
> +
> +	/*
> +	 * when scrolling horizontally with two fingers, data[4] is used but I
> +	 * did not find the right mapping...
> +	 */
> +	input_report_key(dev, BTN_TOOL_FINGER, data[4] == 0 ? 1 : 2);

Value of 2 does not make sense to use with input_report_key() as it
converts the value into boolean anyway. Also BTN_TOOL_FINGER should be
used by trackapds/touchpads working in absolute mode while this device
seems to be using relative mode.

By the way, we have REL_HWHEEL event for reporting horizontal scrolling.

> +
> +	input_report_rel(dev, REL_X, data[1]);
> +	input_report_rel(dev, REL_Y, data[2]);
> +
> +	input_report_rel(dev, REL_WHEEL, data[3]);
> +
> +	input_sync(dev);
> +
> +resubmit:
> +	status = usb_submit_urb(urb, GFP_ATOMIC);
> +	if (status) {
> +		dev_err(&cn_dev->usb_dev->dev,
> +			"can't resubmit intr, %s-%s/input0, status %d\n",
> +			cn_dev->usb_dev->bus->bus_name,
> +			cn_dev->usb_dev->devpath, status);
> +	}
> +}
> +
> +static int cntouch_open(struct input_dev *dev)
> +{
> +	struct cntouch_device *cn_dev = input_get_drvdata(dev);
> +
> +	cn_dev->irq->dev = cn_dev->usb_dev;

I do not think you need to do this assignment anymore.

> +	if (usb_submit_urb(cn_dev->irq, GFP_KERNEL))
> +		return -EIO;
> +	return 0;
> +}
> +
> +static void cntouch_close(struct input_dev *dev)
> +{
> +	struct cntouch_device *cn_dev = input_get_drvdata(dev);
> +
> +	usb_kill_urb(cn_dev->irq);
> +}
> +
> +static int cntouch_probe(struct usb_interface *interface,
> +			 const struct usb_device_id *id)
> +{
> +	struct usb_device *usb_dev = interface_to_usbdev(interface);
> +	struct cntouch_device *cn_dev = NULL;

Please do not initialize variables unless you actually need the initial
value. This gives the compiler chance to warn you about "using
uninitialized variable" code paths instead of happily using
NULL/0/whatever initial value you set and running into problems at
runtime.

> +	struct usb_host_interface *host_interface;
> +	struct usb_endpoint_descriptor *endpoint;
> +	int pipe, maxp;
> +	int error = -ENOMEM;

Same here.

> +
> +	host_interface = interface->cur_altsetting;
> +
> +	if (host_interface->desc.bNumEndpoints != 1)
> +		return -ENODEV;
> +
> +	endpoint = &host_interface->endpoint[0].desc;
> +	if (!usb_endpoint_is_int_in(endpoint))
> +		return -ENODEV;
> +
> +	pipe = usb_rcvintpipe(usb_dev, endpoint->bEndpointAddress);
> +	maxp = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe));
> +
> +	cn_dev = kzalloc(sizeof(*cn_dev), GFP_KERNEL);
> +	if (cn_dev == NULL)
> +		goto err_1;
> +
> +	cn_dev->input_dev = input_allocate_device();
> +	if (!cn_dev->input_dev)
> +		goto err_2;
> +
> +	cn_dev->usb_dev = usb_get_dev(usb_dev);

This is not needed: while driver is bound to the device it is not going
anywhere.

> +
> +	cn_dev->data =
> +	    usb_alloc_coherent(usb_dev, 8, GFP_ATOMIC, &cn_dev->data_dma);
> +	if (!cn_dev->data)
> +		goto err_3;
> +
> +	cn_dev->irq = usb_alloc_urb(0, GFP_KERNEL);
> +	if (!cn_dev->irq)
> +		goto err_4;
> +
> +	usb_set_intfdata(interface, cn_dev);
> +
> +	usb_make_path(usb_dev, cn_dev->usb_path, sizeof(cn_dev->usb_path));
> +	strlcat(cn_dev->usb_path, "/input0", sizeof(cn_dev->usb_path));
> +
> +	cn_dev->input_dev->name = "CNTouch";
> +	cn_dev->input_dev->phys = cn_dev->usb_path;
> +	usb_to_input_id(usb_dev, &cn_dev->input_dev->id);
> +	cn_dev->input_dev->dev.parent = &interface->dev;
> +
> +	cn_dev->input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
> +	cn_dev->input_dev->keybit[BIT_WORD(BTN_MOUSE)] =
> +	    BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
> +	cn_dev->input_dev->relbit[0] =
> +	    BIT_MASK(REL_X) | BIT_MASK(REL_Y) | BIT_MASK(REL_WHEEL);
> +
> +	input_set_drvdata(cn_dev->input_dev, cn_dev);
> +
> +	cn_dev->input_dev->open = cntouch_open;
> +	cn_dev->input_dev->close = cntouch_close;
> +
> +	usb_fill_int_urb(cn_dev->irq, usb_dev, pipe, cn_dev->data,
> +			 (maxp > 8 ? 8 : maxp), cntouch_irq, cn_dev,
> +			 endpoint->bInterval);
> +	cn_dev->irq->transfer_dma = cn_dev->data_dma;
> +	cn_dev->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> +
> +	error = input_register_device(cn_dev->input_dev);
> +	if (error)
> +		goto err_5;
> +
> +	dev_info(&interface->dev, DRIVER_DESC "device now attached\n");

Please drop this message, we are already noisy enough. Input core will
message when new input device is created anyway.

> +	return 0;
> +
> +err_5:
> +	usb_free_urb(cn_dev->irq);
> +err_4:
> +	usb_free_coherent(usb_dev, 8, cn_dev->data, cn_dev->data_dma);
> +err_3:
> +	input_free_device(cn_dev->input_dev);
> +err_2:
> +	usb_set_intfdata(interface, NULL);
> +	usb_put_dev(cn_dev->usb_dev);
> +	kfree(cn_dev);
> +err_1:
> +	dev_err(&interface->dev, "out of memory\n");

Maybe. Or maybe not. We do not know why input_register_device() failed.
Just drop the message, driver core will complain about error binding the
driver anyway.

> +	return error;
> +}
> +
> +static void cntouch_disconnect(struct usb_interface *interface)
> +{
> +	struct cntouch_device *cn_dev = usb_get_intfdata(interface);
> +
> +	usb_kill_urb(cn_dev->irq);

Not needed as close() will be called as part of input device
unregistration and will cancel the urb for us. 

> +	input_unregister_device(cn_dev->input_dev);
> +	usb_free_urb(cn_dev->irq);
> +	usb_free_coherent(cn_dev->usb_dev, 8, cn_dev->data, cn_dev->data_dma);
> +	usb_set_intfdata(interface, NULL);
> +	usb_put_dev(cn_dev->usb_dev);
> +	input_free_device(cn_dev->input_dev);

This is wrong - once input device has been registered you only need to
call unregister: once last reference to the object is dropped it will be
freed by input core.

> +	kfree(cn_dev);
> +	dev_info(&interface->dev, DRIVER_DESC " now disconnected\n");

Please drop this message as well.

> +}
> +
> +static struct usb_driver cntouch_driver = {
> +	.name = "CNTouch",
> +	.probe = &cntouch_probe,
> +	.disconnect = &cntouch_disconnect,
> +	.id_table = cntouch_devices,
> +};
> +
> +module_usb_driver(cntouch_driver);
> -- 
> 2.1.0
> 

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3] drivers: input: mouse: Add Foxconn's CNTouch driver
  2015-02-01  4:50     ` Dmitry Torokhov
@ 2015-02-15 12:39       ` Thomas Sanchez
  2015-02-15 12:39         ` [PATCH] " Thomas Sanchez
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Sanchez @ 2015-02-15 12:39 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-input

Hi,
Sorry for the delay. I fixed every comments in your code review. I also
changed the code to use __set_bit which is easier to read IMHO.

About wether it is an HID compatible device, I took a quick glance but
it is not really easy to see... I plan to try out today.

In the meantime here is the patch in case of it is not possible to use
the HID interface.

Thanks,
Cheers,


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] drivers: input: mouse: Add Foxconn's CNTouch driver
  2015-02-15 12:39       ` [PATCH v3] " Thomas Sanchez
@ 2015-02-15 12:39         ` Thomas Sanchez
  2015-02-15 12:44           ` [PATCH v4] " Thomas Sanchez
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Sanchez @ 2015-02-15 12:39 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-input, Thomas Sanchez

This commit introduces a new driver for Foxconn CNTouch trackpad that
can be found on LDLC's laptop IRIS family.  The driver has been inspired
from usbmouse.c.

Signed-off-by: Thomas Sanchez <thomas.sanchz@gmail.com>
---
 Documentation/input/event-codes.txt |   2 +-
 drivers/input/mouse/Kconfig         |  11 ++
 drivers/input/mouse/Makefile        |   1 +
 drivers/input/mouse/foxconn_usb.c   | 231 ++++++++++++++++++++++++++++++++++++
 4 files changed, 244 insertions(+), 1 deletion(-)
 create mode 100644 drivers/input/mouse/foxconn_usb.c

diff --git a/Documentation/input/event-codes.txt b/Documentation/input/event-codes.txt
index c587a96..1349a9e 100644
--- a/Documentation/input/event-codes.txt
+++ b/Documentation/input/event-codes.txt
@@ -156,7 +156,7 @@ instead of EV_REL codes.
 
 A few EV_REL codes have special meanings:
 
-* REL_WHEEL, REL_HWHEEL:
+#* REL_WHEEL, REL_HWHEEL:
   - These codes are used for vertical and horizontal scroll wheels,
     respectively.
 
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 4658b5d..e240be3 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -407,4 +407,15 @@ config MOUSE_NAVPOINT_PXA27x
 	  To compile this driver as a module, choose M here: the
 	  module will be called navpoint.
 
+config MOUSE_FOXCONN_CNTOUCH
+	tristate "Foxconn CNTouch USB device support"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  This driver adds support for the Foxconn CNTouch trackpad present for
+	  instance on IRIS laptop family from LDLC.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called foxconn_usb.
+
 endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 8a9c98e..575804f 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MOUSE_ATARI)		+= atarimouse.o
 obj-$(CONFIG_MOUSE_BCM5974)		+= bcm5974.o
 obj-$(CONFIG_MOUSE_CYAPA)		+= cyapatp.o
 obj-$(CONFIG_MOUSE_ELAN_I2C)		+= elan_i2c.o
+obj-$(CONFIG_MOUSE_FOXCONN_CNTOUCH)	+= foxconn_usb.o
 obj-$(CONFIG_MOUSE_GPIO)		+= gpio_mouse.o
 obj-$(CONFIG_MOUSE_INPORT)		+= inport.o
 obj-$(CONFIG_MOUSE_LOGIBM)		+= logibm.o
diff --git a/drivers/input/mouse/foxconn_usb.c b/drivers/input/mouse/foxconn_usb.c
new file mode 100644
index 0000000..3615b20
--- /dev/null
+++ b/drivers/input/mouse/foxconn_usb.c
@@ -0,0 +1,231 @@
+/*
+ *  Copyright (c) 2015-2016 Thomas Sanchez
+ *
+ *  CNTouch driver
+ */
+
+/*
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+
+#define USB_VENDOR_ID_FOXCONN		0x294e
+#define USB_DEVICE_ID_FOXCONN_CNTOUCH	0x1001
+
+#define DRIVER_DESC	"CNTouch USB Driver"
+
+static const struct usb_device_id cntouch_devices[] = {
+	{USB_DEVICE(USB_VENDOR_ID_FOXCONN, USB_DEVICE_ID_FOXCONN_CNTOUCH)},
+	{},
+};
+
+MODULE_AUTHOR("Thomas Sanchez, thomas.sanchz@gmail.com");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(usb, cntouch_devices);
+
+struct cntouch_device {
+	struct usb_device *usb_dev;
+	struct input_dev *input_dev;
+	struct urb *irq;
+	signed char *data;
+	dma_addr_t data_dma;
+	char usb_path[64];
+};
+
+static void cntouch_irq(struct urb *urb)
+{
+	struct cntouch_device *cn_dev = urb->context;
+	signed char *data = cn_dev->data;
+	struct input_dev *dev = cn_dev->input_dev;
+	int status;
+
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:
+		goto resubmit;
+	}
+
+	input_report_rel(dev, REL_X, data[1]);
+	input_report_rel(dev, REL_Y, data[2]);
+
+	input_report_rel(dev, REL_WHEEL, data[3]);
+	input_report_rel(dev, REL_HWHEEL, data[4]);
+
+	input_report_key(dev, BTN_LEFT, data[0] & 0x01);
+	input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
+
+	input_report_key(
+	    dev, data[4] == 0 ? BTN_TOOL_FINGER : BTN_TOOL_DOUBLETAP, 1);
+
+	input_sync(dev);
+
+resubmit:
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status) {
+		dev_err(&cn_dev->usb_dev->dev,
+			"can't resubmit intr, %s-%s/input0, status %d\n",
+			cn_dev->usb_dev->bus->bus_name,
+			cn_dev->usb_dev->devpath, status);
+	}
+}
+
+static int cntouch_open(struct input_dev *dev)
+{
+	struct cntouch_device *cn_dev = input_get_drvdata(dev);
+
+	if (usb_submit_urb(cn_dev->irq, GFP_KERNEL))
+		return -EIO;
+	return 0;
+}
+
+static void cntouch_close(struct input_dev *dev)
+{
+	struct cntouch_device *cn_dev = input_get_drvdata(dev);
+
+	usb_kill_urb(cn_dev->irq);
+}
+
+static int cntouch_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(interface);
+	struct cntouch_device *cn_dev;
+	struct usb_host_interface *host_interface;
+	struct usb_endpoint_descriptor *endpoint;
+	int pipe, maxp;
+	int error;
+
+	host_interface = interface->cur_altsetting;
+
+	if (host_interface->desc.bNumEndpoints != 1)
+		return -ENODEV;
+
+	endpoint = &host_interface->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	pipe = usb_rcvintpipe(usb_dev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe));
+
+	cn_dev = kzalloc(sizeof(*cn_dev), GFP_KERNEL);
+	if (cn_dev == NULL) {
+		error = -ENOMEM;
+		goto err_1;
+	}
+
+	cn_dev->input_dev = input_allocate_device();
+	if (!cn_dev->input_dev) {
+		error = -ENOMEM;
+		goto err_2;
+	}
+
+	cn_dev->data =
+	    usb_alloc_coherent(usb_dev, 8, GFP_ATOMIC, &cn_dev->data_dma);
+	if (!cn_dev->data) {
+		error = -ENOMEM;
+		goto err_3;
+	}
+
+	cn_dev->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!cn_dev->irq) {
+		error = -ENOMEM;
+		goto err_4;
+	}
+
+	usb_set_intfdata(interface, cn_dev);
+
+	usb_make_path(usb_dev, cn_dev->usb_path, sizeof(cn_dev->usb_path));
+	strlcat(cn_dev->usb_path, "/input0", sizeof(cn_dev->usb_path));
+
+	cn_dev->input_dev->name = "CNTouch";
+	cn_dev->input_dev->phys = cn_dev->usb_path;
+	usb_to_input_id(usb_dev, &cn_dev->input_dev->id);
+	cn_dev->input_dev->dev.parent = &interface->dev;
+
+	__set_bit(EV_REL, cn_dev->input_dev->evbit);
+	__set_bit(EV_KEY, cn_dev->input_dev->evbit);
+
+	__set_bit(BTN_MOUSE, cn_dev->input_dev->keybit);
+	__set_bit(BTN_LEFT, cn_dev->input_dev->keybit);
+	__set_bit(BTN_RIGHT, cn_dev->input_dev->keybit);
+	__set_bit(BTN_TOOL_FINGER, cn_dev->input_dev->keybit);
+	__set_bit(BTN_TOOL_DOUBLETAP, cn_dev->input_dev->keybit);
+
+	__set_bit(REL_X, cn_dev->input_dev->relbit);
+	__set_bit(REL_Y, cn_dev->input_dev->relbit);
+	__set_bit(REL_WHEEL, cn_dev->input_dev->relbit);
+	__set_bit(REL_HWHEEL, cn_dev->input_dev->relbit);
+
+	input_set_drvdata(cn_dev->input_dev, cn_dev);
+
+	cn_dev->input_dev->open = cntouch_open;
+	cn_dev->input_dev->close = cntouch_close;
+
+	usb_fill_int_urb(cn_dev->irq, usb_dev, pipe, cn_dev->data,
+			 (maxp > 8 ? 8 : maxp), cntouch_irq, cn_dev,
+			 endpoint->bInterval);
+	cn_dev->irq->transfer_dma = cn_dev->data_dma;
+	cn_dev->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	error = input_register_device(cn_dev->input_dev);
+	if (error)
+		goto err_5;
+
+	return 0;
+
+err_5:
+	usb_free_urb(cn_dev->irq);
+err_4:
+	usb_free_coherent(usb_dev, 8, cn_dev->data, cn_dev->data_dma);
+err_3:
+	input_free_device(cn_dev->input_dev);
+err_2:
+	usb_set_intfdata(interface, NULL);
+	usb_put_dev(cn_dev->usb_dev);
+	kfree(cn_dev);
+err_1:
+	return error;
+}
+
+static void cntouch_disconnect(struct usb_interface *interface)
+{
+	struct cntouch_device *cn_dev = usb_get_intfdata(interface);
+
+	input_unregister_device(cn_dev->input_dev);
+	usb_free_urb(cn_dev->irq);
+	usb_free_coherent(cn_dev->usb_dev, 8, cn_dev->data, cn_dev->data_dma);
+	usb_set_intfdata(interface, NULL);
+	usb_put_dev(cn_dev->usb_dev);
+	kfree(cn_dev);
+}
+
+static struct usb_driver cntouch_driver = {
+	.name = "CNTouch",
+	.probe = &cntouch_probe,
+	.disconnect = &cntouch_disconnect,
+	.id_table = cntouch_devices,
+};
+
+module_usb_driver(cntouch_driver);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4] drivers: input: mouse: Add Foxconn's CNTouch driver
  2015-02-15 12:39         ` [PATCH] " Thomas Sanchez
@ 2015-02-15 12:44           ` Thomas Sanchez
  2015-02-15 12:44             ` [PATCH] " Thomas Sanchez
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Sanchez @ 2015-02-15 12:44 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-input

As expected a new mistake in the previous patch...
Sorry about that.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] drivers: input: mouse: Add Foxconn's CNTouch driver
  2015-02-15 12:44           ` [PATCH v4] " Thomas Sanchez
@ 2015-02-15 12:44             ` Thomas Sanchez
  2015-02-15 16:12               ` Thomas Sanchez
  2015-02-26 11:01               ` Thomas Sanchez
  0 siblings, 2 replies; 10+ messages in thread
From: Thomas Sanchez @ 2015-02-15 12:44 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-input, Thomas Sanchez

This commit introduces a new driver for Foxconn CNTouch trackpad that
can be found on LDLC's laptop IRIS family.  The driver has been inspired
from usbmouse.c.

Signed-off-by: Thomas Sanchez <thomas.sanchz@gmail.com>
---
 drivers/input/mouse/Kconfig       |  11 ++
 drivers/input/mouse/Makefile      |   1 +
 drivers/input/mouse/foxconn_usb.c | 231 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 243 insertions(+)
 create mode 100644 drivers/input/mouse/foxconn_usb.c

diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 4658b5d..e240be3 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -407,4 +407,15 @@ config MOUSE_NAVPOINT_PXA27x
 	  To compile this driver as a module, choose M here: the
 	  module will be called navpoint.
 
+config MOUSE_FOXCONN_CNTOUCH
+	tristate "Foxconn CNTouch USB device support"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  This driver adds support for the Foxconn CNTouch trackpad present for
+	  instance on IRIS laptop family from LDLC.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called foxconn_usb.
+
 endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 8a9c98e..575804f 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MOUSE_ATARI)		+= atarimouse.o
 obj-$(CONFIG_MOUSE_BCM5974)		+= bcm5974.o
 obj-$(CONFIG_MOUSE_CYAPA)		+= cyapatp.o
 obj-$(CONFIG_MOUSE_ELAN_I2C)		+= elan_i2c.o
+obj-$(CONFIG_MOUSE_FOXCONN_CNTOUCH)	+= foxconn_usb.o
 obj-$(CONFIG_MOUSE_GPIO)		+= gpio_mouse.o
 obj-$(CONFIG_MOUSE_INPORT)		+= inport.o
 obj-$(CONFIG_MOUSE_LOGIBM)		+= logibm.o
diff --git a/drivers/input/mouse/foxconn_usb.c b/drivers/input/mouse/foxconn_usb.c
new file mode 100644
index 0000000..3615b20
--- /dev/null
+++ b/drivers/input/mouse/foxconn_usb.c
@@ -0,0 +1,231 @@
+/*
+ *  Copyright (c) 2015-2016 Thomas Sanchez
+ *
+ *  CNTouch driver
+ */
+
+/*
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+
+#define USB_VENDOR_ID_FOXCONN		0x294e
+#define USB_DEVICE_ID_FOXCONN_CNTOUCH	0x1001
+
+#define DRIVER_DESC	"CNTouch USB Driver"
+
+static const struct usb_device_id cntouch_devices[] = {
+	{USB_DEVICE(USB_VENDOR_ID_FOXCONN, USB_DEVICE_ID_FOXCONN_CNTOUCH)},
+	{},
+};
+
+MODULE_AUTHOR("Thomas Sanchez, thomas.sanchz@gmail.com");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(usb, cntouch_devices);
+
+struct cntouch_device {
+	struct usb_device *usb_dev;
+	struct input_dev *input_dev;
+	struct urb *irq;
+	signed char *data;
+	dma_addr_t data_dma;
+	char usb_path[64];
+};
+
+static void cntouch_irq(struct urb *urb)
+{
+	struct cntouch_device *cn_dev = urb->context;
+	signed char *data = cn_dev->data;
+	struct input_dev *dev = cn_dev->input_dev;
+	int status;
+
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:
+		goto resubmit;
+	}
+
+	input_report_rel(dev, REL_X, data[1]);
+	input_report_rel(dev, REL_Y, data[2]);
+
+	input_report_rel(dev, REL_WHEEL, data[3]);
+	input_report_rel(dev, REL_HWHEEL, data[4]);
+
+	input_report_key(dev, BTN_LEFT, data[0] & 0x01);
+	input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
+
+	input_report_key(
+	    dev, data[4] == 0 ? BTN_TOOL_FINGER : BTN_TOOL_DOUBLETAP, 1);
+
+	input_sync(dev);
+
+resubmit:
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status) {
+		dev_err(&cn_dev->usb_dev->dev,
+			"can't resubmit intr, %s-%s/input0, status %d\n",
+			cn_dev->usb_dev->bus->bus_name,
+			cn_dev->usb_dev->devpath, status);
+	}
+}
+
+static int cntouch_open(struct input_dev *dev)
+{
+	struct cntouch_device *cn_dev = input_get_drvdata(dev);
+
+	if (usb_submit_urb(cn_dev->irq, GFP_KERNEL))
+		return -EIO;
+	return 0;
+}
+
+static void cntouch_close(struct input_dev *dev)
+{
+	struct cntouch_device *cn_dev = input_get_drvdata(dev);
+
+	usb_kill_urb(cn_dev->irq);
+}
+
+static int cntouch_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(interface);
+	struct cntouch_device *cn_dev;
+	struct usb_host_interface *host_interface;
+	struct usb_endpoint_descriptor *endpoint;
+	int pipe, maxp;
+	int error;
+
+	host_interface = interface->cur_altsetting;
+
+	if (host_interface->desc.bNumEndpoints != 1)
+		return -ENODEV;
+
+	endpoint = &host_interface->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	pipe = usb_rcvintpipe(usb_dev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe));
+
+	cn_dev = kzalloc(sizeof(*cn_dev), GFP_KERNEL);
+	if (cn_dev == NULL) {
+		error = -ENOMEM;
+		goto err_1;
+	}
+
+	cn_dev->input_dev = input_allocate_device();
+	if (!cn_dev->input_dev) {
+		error = -ENOMEM;
+		goto err_2;
+	}
+
+	cn_dev->data =
+	    usb_alloc_coherent(usb_dev, 8, GFP_ATOMIC, &cn_dev->data_dma);
+	if (!cn_dev->data) {
+		error = -ENOMEM;
+		goto err_3;
+	}
+
+	cn_dev->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!cn_dev->irq) {
+		error = -ENOMEM;
+		goto err_4;
+	}
+
+	usb_set_intfdata(interface, cn_dev);
+
+	usb_make_path(usb_dev, cn_dev->usb_path, sizeof(cn_dev->usb_path));
+	strlcat(cn_dev->usb_path, "/input0", sizeof(cn_dev->usb_path));
+
+	cn_dev->input_dev->name = "CNTouch";
+	cn_dev->input_dev->phys = cn_dev->usb_path;
+	usb_to_input_id(usb_dev, &cn_dev->input_dev->id);
+	cn_dev->input_dev->dev.parent = &interface->dev;
+
+	__set_bit(EV_REL, cn_dev->input_dev->evbit);
+	__set_bit(EV_KEY, cn_dev->input_dev->evbit);
+
+	__set_bit(BTN_MOUSE, cn_dev->input_dev->keybit);
+	__set_bit(BTN_LEFT, cn_dev->input_dev->keybit);
+	__set_bit(BTN_RIGHT, cn_dev->input_dev->keybit);
+	__set_bit(BTN_TOOL_FINGER, cn_dev->input_dev->keybit);
+	__set_bit(BTN_TOOL_DOUBLETAP, cn_dev->input_dev->keybit);
+
+	__set_bit(REL_X, cn_dev->input_dev->relbit);
+	__set_bit(REL_Y, cn_dev->input_dev->relbit);
+	__set_bit(REL_WHEEL, cn_dev->input_dev->relbit);
+	__set_bit(REL_HWHEEL, cn_dev->input_dev->relbit);
+
+	input_set_drvdata(cn_dev->input_dev, cn_dev);
+
+	cn_dev->input_dev->open = cntouch_open;
+	cn_dev->input_dev->close = cntouch_close;
+
+	usb_fill_int_urb(cn_dev->irq, usb_dev, pipe, cn_dev->data,
+			 (maxp > 8 ? 8 : maxp), cntouch_irq, cn_dev,
+			 endpoint->bInterval);
+	cn_dev->irq->transfer_dma = cn_dev->data_dma;
+	cn_dev->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	error = input_register_device(cn_dev->input_dev);
+	if (error)
+		goto err_5;
+
+	return 0;
+
+err_5:
+	usb_free_urb(cn_dev->irq);
+err_4:
+	usb_free_coherent(usb_dev, 8, cn_dev->data, cn_dev->data_dma);
+err_3:
+	input_free_device(cn_dev->input_dev);
+err_2:
+	usb_set_intfdata(interface, NULL);
+	usb_put_dev(cn_dev->usb_dev);
+	kfree(cn_dev);
+err_1:
+	return error;
+}
+
+static void cntouch_disconnect(struct usb_interface *interface)
+{
+	struct cntouch_device *cn_dev = usb_get_intfdata(interface);
+
+	input_unregister_device(cn_dev->input_dev);
+	usb_free_urb(cn_dev->irq);
+	usb_free_coherent(cn_dev->usb_dev, 8, cn_dev->data, cn_dev->data_dma);
+	usb_set_intfdata(interface, NULL);
+	usb_put_dev(cn_dev->usb_dev);
+	kfree(cn_dev);
+}
+
+static struct usb_driver cntouch_driver = {
+	.name = "CNTouch",
+	.probe = &cntouch_probe,
+	.disconnect = &cntouch_disconnect,
+	.id_table = cntouch_devices,
+};
+
+module_usb_driver(cntouch_driver);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] drivers: input: mouse: Add Foxconn's CNTouch driver
  2015-02-15 12:44             ` [PATCH] " Thomas Sanchez
@ 2015-02-15 16:12               ` Thomas Sanchez
  2015-02-26 11:01               ` Thomas Sanchez
  1 sibling, 0 replies; 10+ messages in thread
From: Thomas Sanchez @ 2015-02-15 16:12 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, Thomas Sanchez

After some researches and tests it seems that the device is not HID compliant...

-- 
Thomas Sanchez

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] drivers: input: mouse: Add Foxconn's CNTouch driver
  2015-02-15 12:44             ` [PATCH] " Thomas Sanchez
  2015-02-15 16:12               ` Thomas Sanchez
@ 2015-02-26 11:01               ` Thomas Sanchez
  1 sibling, 0 replies; 10+ messages in thread
From: Thomas Sanchez @ 2015-02-26 11:01 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input, Thomas Sanchez

Hi,
Any news/thought regarding this patch ?

Thanks,
Cheers,

2015-02-15 13:44 GMT+01:00 Thomas Sanchez <thomas.sanchz@gmail.com>:
> This commit introduces a new driver for Foxconn CNTouch trackpad that
> can be found on LDLC's laptop IRIS family.  The driver has been inspired
> from usbmouse.c.
>
> Signed-off-by: Thomas Sanchez <thomas.sanchz@gmail.com>
> ---
>  drivers/input/mouse/Kconfig       |  11 ++
>  drivers/input/mouse/Makefile      |   1 +
>  drivers/input/mouse/foxconn_usb.c | 231 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 243 insertions(+)
>  create mode 100644 drivers/input/mouse/foxconn_usb.c
>
> diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
> index 4658b5d..e240be3 100644
> --- a/drivers/input/mouse/Kconfig
> +++ b/drivers/input/mouse/Kconfig
> @@ -407,4 +407,15 @@ config MOUSE_NAVPOINT_PXA27x
>           To compile this driver as a module, choose M here: the
>           module will be called navpoint.
>
> +config MOUSE_FOXCONN_CNTOUCH
> +       tristate "Foxconn CNTouch USB device support"
> +       depends on USB_ARCH_HAS_HCD
> +       select USB
> +       help
> +         This driver adds support for the Foxconn CNTouch trackpad present for
> +         instance on IRIS laptop family from LDLC.
> +
> +         To compile this driver as a module, choose M here: the
> +         module will be called foxconn_usb.
> +
>  endif
> diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
> index 8a9c98e..575804f 100644
> --- a/drivers/input/mouse/Makefile
> +++ b/drivers/input/mouse/Makefile
> @@ -10,6 +10,7 @@ obj-$(CONFIG_MOUSE_ATARI)             += atarimouse.o
>  obj-$(CONFIG_MOUSE_BCM5974)            += bcm5974.o
>  obj-$(CONFIG_MOUSE_CYAPA)              += cyapatp.o
>  obj-$(CONFIG_MOUSE_ELAN_I2C)           += elan_i2c.o
> +obj-$(CONFIG_MOUSE_FOXCONN_CNTOUCH)    += foxconn_usb.o
>  obj-$(CONFIG_MOUSE_GPIO)               += gpio_mouse.o
>  obj-$(CONFIG_MOUSE_INPORT)             += inport.o
>  obj-$(CONFIG_MOUSE_LOGIBM)             += logibm.o
> diff --git a/drivers/input/mouse/foxconn_usb.c b/drivers/input/mouse/foxconn_usb.c
> new file mode 100644
> index 0000000..3615b20
> --- /dev/null
> +++ b/drivers/input/mouse/foxconn_usb.c
> @@ -0,0 +1,231 @@
> +/*
> + *  Copyright (c) 2015-2016 Thomas Sanchez
> + *
> + *  CNTouch driver
> + */
> +
> +/*
> + * 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.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/usb.h>
> +#include <linux/usb/input.h>
> +
> +#define USB_VENDOR_ID_FOXCONN          0x294e
> +#define USB_DEVICE_ID_FOXCONN_CNTOUCH  0x1001
> +
> +#define DRIVER_DESC    "CNTouch USB Driver"
> +
> +static const struct usb_device_id cntouch_devices[] = {
> +       {USB_DEVICE(USB_VENDOR_ID_FOXCONN, USB_DEVICE_ID_FOXCONN_CNTOUCH)},
> +       {},
> +};
> +
> +MODULE_AUTHOR("Thomas Sanchez, thomas.sanchz@gmail.com");
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE("GPL");
> +
> +MODULE_DEVICE_TABLE(usb, cntouch_devices);
> +
> +struct cntouch_device {
> +       struct usb_device *usb_dev;
> +       struct input_dev *input_dev;
> +       struct urb *irq;
> +       signed char *data;
> +       dma_addr_t data_dma;
> +       char usb_path[64];
> +};
> +
> +static void cntouch_irq(struct urb *urb)
> +{
> +       struct cntouch_device *cn_dev = urb->context;
> +       signed char *data = cn_dev->data;
> +       struct input_dev *dev = cn_dev->input_dev;
> +       int status;
> +
> +       switch (urb->status) {
> +       case 0:
> +               break;
> +       case -ECONNRESET:
> +       case -ENOENT:
> +       case -ESHUTDOWN:
> +               return;
> +       default:
> +               goto resubmit;
> +       }
> +
> +       input_report_rel(dev, REL_X, data[1]);
> +       input_report_rel(dev, REL_Y, data[2]);
> +
> +       input_report_rel(dev, REL_WHEEL, data[3]);
> +       input_report_rel(dev, REL_HWHEEL, data[4]);
> +
> +       input_report_key(dev, BTN_LEFT, data[0] & 0x01);
> +       input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
> +
> +       input_report_key(
> +           dev, data[4] == 0 ? BTN_TOOL_FINGER : BTN_TOOL_DOUBLETAP, 1);
> +
> +       input_sync(dev);
> +
> +resubmit:
> +       status = usb_submit_urb(urb, GFP_ATOMIC);
> +       if (status) {
> +               dev_err(&cn_dev->usb_dev->dev,
> +                       "can't resubmit intr, %s-%s/input0, status %d\n",
> +                       cn_dev->usb_dev->bus->bus_name,
> +                       cn_dev->usb_dev->devpath, status);
> +       }
> +}
> +
> +static int cntouch_open(struct input_dev *dev)
> +{
> +       struct cntouch_device *cn_dev = input_get_drvdata(dev);
> +
> +       if (usb_submit_urb(cn_dev->irq, GFP_KERNEL))
> +               return -EIO;
> +       return 0;
> +}
> +
> +static void cntouch_close(struct input_dev *dev)
> +{
> +       struct cntouch_device *cn_dev = input_get_drvdata(dev);
> +
> +       usb_kill_urb(cn_dev->irq);
> +}
> +
> +static int cntouch_probe(struct usb_interface *interface,
> +                        const struct usb_device_id *id)
> +{
> +       struct usb_device *usb_dev = interface_to_usbdev(interface);
> +       struct cntouch_device *cn_dev;
> +       struct usb_host_interface *host_interface;
> +       struct usb_endpoint_descriptor *endpoint;
> +       int pipe, maxp;
> +       int error;
> +
> +       host_interface = interface->cur_altsetting;
> +
> +       if (host_interface->desc.bNumEndpoints != 1)
> +               return -ENODEV;
> +
> +       endpoint = &host_interface->endpoint[0].desc;
> +       if (!usb_endpoint_is_int_in(endpoint))
> +               return -ENODEV;
> +
> +       pipe = usb_rcvintpipe(usb_dev, endpoint->bEndpointAddress);
> +       maxp = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe));
> +
> +       cn_dev = kzalloc(sizeof(*cn_dev), GFP_KERNEL);
> +       if (cn_dev == NULL) {
> +               error = -ENOMEM;
> +               goto err_1;
> +       }
> +
> +       cn_dev->input_dev = input_allocate_device();
> +       if (!cn_dev->input_dev) {
> +               error = -ENOMEM;
> +               goto err_2;
> +       }
> +
> +       cn_dev->data =
> +           usb_alloc_coherent(usb_dev, 8, GFP_ATOMIC, &cn_dev->data_dma);
> +       if (!cn_dev->data) {
> +               error = -ENOMEM;
> +               goto err_3;
> +       }
> +
> +       cn_dev->irq = usb_alloc_urb(0, GFP_KERNEL);
> +       if (!cn_dev->irq) {
> +               error = -ENOMEM;
> +               goto err_4;
> +       }
> +
> +       usb_set_intfdata(interface, cn_dev);
> +
> +       usb_make_path(usb_dev, cn_dev->usb_path, sizeof(cn_dev->usb_path));
> +       strlcat(cn_dev->usb_path, "/input0", sizeof(cn_dev->usb_path));
> +
> +       cn_dev->input_dev->name = "CNTouch";
> +       cn_dev->input_dev->phys = cn_dev->usb_path;
> +       usb_to_input_id(usb_dev, &cn_dev->input_dev->id);
> +       cn_dev->input_dev->dev.parent = &interface->dev;
> +
> +       __set_bit(EV_REL, cn_dev->input_dev->evbit);
> +       __set_bit(EV_KEY, cn_dev->input_dev->evbit);
> +
> +       __set_bit(BTN_MOUSE, cn_dev->input_dev->keybit);
> +       __set_bit(BTN_LEFT, cn_dev->input_dev->keybit);
> +       __set_bit(BTN_RIGHT, cn_dev->input_dev->keybit);
> +       __set_bit(BTN_TOOL_FINGER, cn_dev->input_dev->keybit);
> +       __set_bit(BTN_TOOL_DOUBLETAP, cn_dev->input_dev->keybit);
> +
> +       __set_bit(REL_X, cn_dev->input_dev->relbit);
> +       __set_bit(REL_Y, cn_dev->input_dev->relbit);
> +       __set_bit(REL_WHEEL, cn_dev->input_dev->relbit);
> +       __set_bit(REL_HWHEEL, cn_dev->input_dev->relbit);
> +
> +       input_set_drvdata(cn_dev->input_dev, cn_dev);
> +
> +       cn_dev->input_dev->open = cntouch_open;
> +       cn_dev->input_dev->close = cntouch_close;
> +
> +       usb_fill_int_urb(cn_dev->irq, usb_dev, pipe, cn_dev->data,
> +                        (maxp > 8 ? 8 : maxp), cntouch_irq, cn_dev,
> +                        endpoint->bInterval);
> +       cn_dev->irq->transfer_dma = cn_dev->data_dma;
> +       cn_dev->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> +
> +       error = input_register_device(cn_dev->input_dev);
> +       if (error)
> +               goto err_5;
> +
> +       return 0;
> +
> +err_5:
> +       usb_free_urb(cn_dev->irq);
> +err_4:
> +       usb_free_coherent(usb_dev, 8, cn_dev->data, cn_dev->data_dma);
> +err_3:
> +       input_free_device(cn_dev->input_dev);
> +err_2:
> +       usb_set_intfdata(interface, NULL);
> +       usb_put_dev(cn_dev->usb_dev);
> +       kfree(cn_dev);
> +err_1:
> +       return error;
> +}
> +
> +static void cntouch_disconnect(struct usb_interface *interface)
> +{
> +       struct cntouch_device *cn_dev = usb_get_intfdata(interface);
> +
> +       input_unregister_device(cn_dev->input_dev);
> +       usb_free_urb(cn_dev->irq);
> +       usb_free_coherent(cn_dev->usb_dev, 8, cn_dev->data, cn_dev->data_dma);
> +       usb_set_intfdata(interface, NULL);
> +       usb_put_dev(cn_dev->usb_dev);
> +       kfree(cn_dev);
> +}
> +
> +static struct usb_driver cntouch_driver = {
> +       .name = "CNTouch",
> +       .probe = &cntouch_probe,
> +       .disconnect = &cntouch_disconnect,
> +       .id_table = cntouch_devices,
> +};
> +
> +module_usb_driver(cntouch_driver);
> --
> 2.1.0
>



-- 
Thomas Sanchez

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2015-02-26 11:02 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-29 16:03 [PATCH] drivers: input: mouse: Add Foxconn's CNTouch driver Thomas Sanchez
2015-01-29 16:22 ` [PATCH v2] " Thomas Sanchez
2015-01-29 16:22   ` [PATCH] " Thomas Sanchez
2015-02-01  4:50     ` Dmitry Torokhov
2015-02-15 12:39       ` [PATCH v3] " Thomas Sanchez
2015-02-15 12:39         ` [PATCH] " Thomas Sanchez
2015-02-15 12:44           ` [PATCH v4] " Thomas Sanchez
2015-02-15 12:44             ` [PATCH] " Thomas Sanchez
2015-02-15 16:12               ` Thomas Sanchez
2015-02-26 11:01               ` Thomas Sanchez

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).