Re: [PATCH] Apple USB Touchpad driver (new)

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

 



Vojtech Pavlik <[email protected]> writes:

> On Sun, Jul 10, 2005 at 12:48:30AM +0200, Peter Osterlund wrote:
> > Vojtech Pavlik <[email protected]> writes:
> > 
> > > Btw, what I don't completely understand is why you need linear
> > > regression, when you're not trying to detect motion or something like
> > > that. Basic floating average, or even simpler filtering like the input
> > > core uses for fuzz could work well enough I believe.
> > 
> > Indeed, this function doesn't make much sense:
> > 
> > +static inline int smooth_history(int x0, int x1, int x2, int x3)
> > +{
> > +	return x0 - ( x0 * 3 + x1 - x2 - x3 * 3 ) / 10;
> > +}
>  
> Using a function like
> 
> 	return (x_old * 3 + x) / 4;
> 
> eliminates the need for a FIFO, and has similar (if not better)
> properties to floating average, because its coefficients are
> [ .25 .18 .14 .10 ... ].

Agreed.

> Setting
> 
> 	absfuzz[ABS_X] = some number;

The patch already does that.

> activates the abovementioned filtering (with additional cutoff and fast
> motion compensation) directly in input.c, which should eliminate a lot
> of the code in the appletouch driver.

I took the liberty to modify the patch myself, making these changes:

* Removed the extra filtering.
* Converted the "open" counter to an "open" flag. (It is still needed
  by the atp_resume() function.)
* CodingStyle fixes.

I have only compile tested this as I don't have access to the
hardware, so I don't know how well this works in practice. It's
possible that the "dev->h_count > 3" test in the old patch filtered
out spikes in the input signal.

Also, it might be a good idea to compute an ABS_PRESSURE value instead
of hardcoding it to 100. I think the psum variable in
atp_calculate_abs() can be used, possibly after rescaling.

Signed-off-by: Peter Osterlund <[email protected]>
---

 Documentation/input/appletouch.txt |  120 +++++++++
 drivers/usb/input/Kconfig          |   19 +
 drivers/usb/input/Makefile         |    1 
 drivers/usb/input/appletouch.c     |  461 ++++++++++++++++++++++++++++++++++++
 4 files changed, 601 insertions(+), 0 deletions(-)

diff --git a/Documentation/input/appletouch.txt b/Documentation/input/appletouch.txt
new file mode 100644
--- /dev/null
+++ b/Documentation/input/appletouch.txt
@@ -0,0 +1,120 @@
+Apple Touchpad Driver (appletouch)
+----------------------------------
+	Copyright (C) 2005 Stelian Pop <[email protected]>
+
+appletouch is a Linux kernel driver for the USB touchpad found on post
+February 2005 Apple Alu Powerbooks.
+
+This driver is derived from Johannes Berg's appletrackpad driver[1], but it has
+been improved in some areas:
+	* appletouch is a full kernel driver, no userspace program is necessary
+	* appletouch can be interfaced with the synaptics X11 driver, in order
+	  to have touchpad acceleration, scrolling, etc.
+
+Credits go to Johannes Berg for reverse-engineering the touchpad protocol,
+Frank Arnold for further improvements, and Alex Harper for some additional
+information about the inner workings of the touchpad sensors.
+
+Usage:
+------
+
+In order to use the touchpad in the basic mode, compile the driver and load
+the module. A new input device will be detected and you will be able to read
+the mouse data from /dev/input/mice (using gpm, or X11).
+
+In X11, you can configure the touchpad to use the synaptics X11 driver, which
+will give additional functionalities, like acceleration, scrolling etc. In
+order to do this, make sure you're using a recent version of the synaptics
+driver (tested with 0.14.2, available from [2]), and configure a new input
+device in your X11 configuration file (take a look below for an example). For
+additional configuration, see the synaptics driver documentation.
+
+	Section "InputDevice"
+        	Identifier      "Synaptics Touchpad"
+	        Driver          "synaptics"
+		Option          "SendCoreEvents"        "true"
+		Option          "Device"                "/dev/input/mice"
+		Option          "Protocol"              "auto-dev"
+		Option		"LeftEdge"		"0"
+		Option		"RightEdge"		"850"
+		Option		"TopEdge"		"0"
+		Option		"BottomEdge"		"645"
+		Option		"MinSpeed"		"0.4"
+		Option		"MaxSpeed"		"1"
+		Option		"AccelFactor"		"0.02"
+		Option		"FingerLow"		"55"
+		Option		"FingerHigh"		"60"
+		Option		"MaxTapMove"		"20"
+		Option		"MaxTapTime"		"100"
+		Option		"HorizScrollDelta"	"0"
+		Option		"VertScrollDelta"	"30"
+		Option		"SHMConfig"		"on"
+	EndSection
+
+	Section "ServerLayout"
+		...
+		InputDevice	"Mouse"
+		InputDevice	"Synaptics Touchpad"
+	...
+	EndSection
+
+Fuzz problems:
+--------------
+
+The touchpad sensors are very sensitive to heat, and will generate a lot of
+noise when the temperature changes. This is especially true when you power-on
+the laptop for the first time.
+
+The appletouch driver tries to handle this noise and auto adapt itself, but it
+is not perfect. If finger movements are not recognized anymore, try reloading
+the driver.
+
+You can activate debugging using the 'debug' module parameter. A value of 0
+deactivates any debugging, 1 activates tracing of invalid samples, 2 activates
+full tracing (each sample is being traced):
+	modprobe appletouch debug=1
+		or
+	echo "1" > /sys/module/appletouch/parameters/debug
+
+Synaptics re-detection problems:
+--------------------------------
+
+The synaptics X11 driver tries to re-open the touchpad input device file
+(/dev/input/eventX) each time you change from text mode back to X11. If the
+input device file does not exist at this precise moment, the synaptics driver
+will give up searching for a touchpad, permanently. You will need to restart
+X11 if you want to reissue a scan.
+
+In normal circumstances, this is not a problem since the touchpad driver is
+loaded before X11 starts, so all will go well.
+
+But if you rmmod/insmod the appletouch driver (because you're hacking it), or
+if you need to unload the usb modules before doing a suspend to disk (like I
+need to), you will get into problems.
+
+The solution I found is to modify udev configuration files in order to create a
+stable device file for the touchpad (/dev/input/appletouch), and point the
+synaptics driver to this fixed device file.
+
+You need to add this rule to /etc/udev/udev.rules:
+
+	# Add a symlink for the touchpad
+	KERNEL="event[0-9]*",	BUS="usb", SYSFS{interface}="Touchpad", SYMLINK="input/appletouch"
+
+And of course instruct X11 to look at /dev/input/appletouch instead of
+/dev/input/mice:
+
+	Section "InputDevice"
+	        Identifier      "Synaptics Touchpad"
+		Driver          "synaptics"
+		Option          "SendCoreEvents"        "true"
+		Option          "Device"                "/dev/input/appletouch"
+		Option          "Protocol"              "event"
+		...
+	EndSection
+
+Links:
+------
+
+[1]: http://johannes.sipsolutions.net/PowerBook/touchpad/
+[2]: http://web.telia.com/~u89404340/touchpad/index.html
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -259,3 +259,22 @@ config USB_ATI_REMOTE
 	  To compile this driver as a module, choose M here: the module will be
 	  called ati_remote.
 
+config USB_APPLETOUCH
+	tristate "Apple USB Touchpad support"
+	depends on USB && INPUT
+	---help---
+	  Say Y here if you want to use an Apple USB Touchpad.
+
+	  These are the touchpads that can be found on post-February 2005
+	  Apple Powerbooks (prior models have a Synaptics touchpad connected
+	  to the ADB bus).
+
+	  This driver provides a basic mouse driver but can be interfaced
+	  with the synaptics X11 driver to provide acceleration and
+	  scrolling in X11.
+
+	  For further information, see
+	  <file:Documentation/input/appletouch.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called appletouch.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
--- a/drivers/usb/input/Makefile
+++ b/drivers/usb/input/Makefile
@@ -39,3 +39,4 @@ obj-$(CONFIG_USB_POWERMATE)	+= powermate
 obj-$(CONFIG_USB_WACOM)		+= wacom.o
 obj-$(CONFIG_USB_ACECAD)	+= acecad.o
 obj-$(CONFIG_USB_XPAD)		+= xpad.o
+obj-$(CONFIG_USB_APPLETOUCH)	+= appletouch.o
diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c
new file mode 100644
--- /dev/null
+++ b/drivers/usb/input/appletouch.c
@@ -0,0 +1,461 @@
+/*
+ * Apple USB Touchpad (for post-February 2005 PowerBooks) driver
+ *
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman ([email protected])
+ * Copyright (C) 2005      Johannes Berg ([email protected])
+ * Copyright (C) 2005      Stelian Pop ([email protected])
+ * Copyright (C) 2005      Frank Arnold ([email protected])
+ *
+ * Thanks to Alex Harper <[email protected]> for his inputs.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/input.h>
+
+/* Apple has powerbooks which have the keyboard with different Product IDs */
+#define APPLE_VENDOR_ID		0x05AC
+#define ATP_12INCH_ID1		0x030A
+#define ATP_15INCH_ID1		0x020E
+#define ATP_15INCH_ID2		0x020F
+#define ATP_17INCH_ID1		0xFFFF /* XXX need a tester !!! */
+
+#define ATP_DRIVER_VERSION	0x0006 /* 00.06 */
+
+#define ATP_DEVICE(prod)					\
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |   		\
+		       USB_DEVICE_ID_MATCH_INT_CLASS |		\
+		       USB_DEVICE_ID_MATCH_INT_PROTOCOL,	\
+	.idVendor = APPLE_VENDOR_ID,				\
+	.idProduct = (prod),					\
+	.bInterfaceClass = 0x03,				\
+	.bInterfaceProtocol = 0x02
+
+/* table of devices that work with this driver */
+static struct usb_device_id atp_table [] = {
+	{ ATP_DEVICE(ATP_12INCH_ID1) },
+	{ ATP_DEVICE(ATP_15INCH_ID1) },
+	{ ATP_DEVICE(ATP_15INCH_ID2) },
+#if 0
+	Disabled until someone gives us the real USB id and tests the driver
+	{ ATP_DEVICE(ATP_17INCH_ID1) },
+#endif
+	{ }					/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, atp_table);
+
+/* size of a USB urb transfer */
+#define ATP_DATASIZE	81
+
+/*
+ * number of sensors. Note that only 16 instead of 26 X (horizontal)
+ * sensors exist on 12" and 15" PowerBooks. All models have 16 Y
+ * (vertical) sensors.
+ */
+#define ATP_XSENSORS	26
+#define ATP_YSENSORS	16
+
+/* amount of fuzz this touchpad generates */
+#define ATP_FUZZ	16
+
+/*
+ * multiplication factor for the X and Y coordinates.
+ * We try to keep the touchpad aspect ratio while still doing only simple
+ * arithmetics.
+ * The factors below give coordinates like:
+ * 	0 <= x <  960 on 12" and 15" Powerbooks
+ * 	0 <= x < 1600 on 17" Powerbooks
+ * 	0 <= y <  646
+ */
+#define ATP_XFACT	64
+#define ATP_YFACT	43
+
+/*
+ * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
+ * ignored.
+ */
+#define ATP_THRESHOLD	 4
+
+/* Structure to hold all of our device specific stuff */
+struct atp {
+	struct usb_device *	udev;		/* usb device */
+	struct urb *		urb;		/* usb request block */
+	signed char *		data;		/* transferred data */
+	int			open;		/* non-zero if opened */
+	struct input_dev	input;		/* input dev */
+};
+
+#define dbg_dump(msg, tab) \
+	if (debug > 1) {						\
+		int i;							\
+		printk("appletouch: %s ", msg);				\
+		for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++)	\
+			printk("%02x ", tab[i]); 			\
+		printk("\n"); 						\
+	}
+
+#define dprintk(format, a...) 						\
+	do {								\
+		if (debug) printk(format, ##a);				\
+	} while (0)
+
+MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold");
+MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver");
+MODULE_LICENSE("GPL");
+
+static int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activate debugging output");
+
+/* are the sensors in a valid state ? */
+static int valid = 0;
+
+static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact)
+{
+	int i;
+	/* values to calculate mean */
+	int pcum = 0, psum = 0;
+	/* indexes of the first and last triggered sensors */
+	int istart = -1, iend = -1;
+
+	for (i = 0; i < nb_sensors; i++) {
+		if (xy_sensors[i] > ATP_THRESHOLD && istart == -1)
+			istart = i;
+		if (xy_sensors[i] < ATP_THRESHOLD && istart != -1 && iend == -1)
+			iend = i;
+		if (xy_sensors[i] > ATP_THRESHOLD && iend != -1) {
+			/*
+			 * in the future, we could add here code to search for
+			 * a second finger...
+			 * for now, scrolling using the synaptics X driver is
+			 * much more simpler to achieve.
+			 */
+			dprintk("appletouch: invalid sensor at %d"
+				" (2 fingers ?)\n", i);
+			return -1;
+		}
+	}
+
+	if (istart == -1)
+		return 0;
+
+	if (iend == -1)
+		iend = nb_sensors;
+
+	for (i = istart; i < iend; i++) {
+		pcum += xy_sensors[i] * i;
+		psum += xy_sensors[i];
+	}
+
+	return pcum * fact / psum;
+}
+
+static void atp_complete(struct urb* urb, struct pt_regs* regs)
+{
+	static int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
+	static signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS];
+	static signed char xy_old[ATP_XSENSORS + ATP_YSENSORS];
+	int retval, i;
+	int x_hw, y_hw;
+	struct atp *dev = urb->context;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* This urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d",
+		    __FUNCTION__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d",
+		    __FUNCTION__, urb->status);
+		goto exit;
+	}
+
+	/* drop incomplete datasets */
+	if (dev->urb->actual_length != ATP_DATASIZE) {
+		dprintk("appletouch: incomplete data package.\n");
+		goto exit;
+	}
+
+	/* reorder the sensors values */
+	for (i = 0; i < 8; i++) {
+		/* X values */
+		xy_cur[i     ] = dev->data[5 * i +  2];
+		xy_cur[i +  8] = dev->data[5 * i +  4];
+		xy_cur[i + 16] = dev->data[5 * i + 42];
+		if (i < 2)
+			xy_cur[i + 24] = dev->data[5 * i + 44];
+
+		/* Y values */
+		xy_cur[i + 26] = dev->data[5 * i +  1];
+		xy_cur[i + 34] = dev->data[5 * i +  3];
+	}
+
+	dbg_dump("sample", xy_cur);
+
+	if (!valid) {
+		/* first sample */
+		valid = 1;
+		memcpy(xy_old, xy_cur, sizeof(xy_old));
+		goto exit;
+	}
+
+	for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
+		/* accumulate the change */
+		signed char change = xy_old[i] - xy_cur[i];
+		xy_acc[i] -= change;
+
+		/* prevent down drifting */
+		if (xy_acc[i] < 0)
+			xy_acc[i] = 0;
+	}
+
+	memcpy(xy_old, xy_cur, sizeof(xy_old));
+
+	dbg_dump("accumulator", xy_acc);
+
+	x_hw = atp_calculate_abs(xy_acc,
+				 ATP_XSENSORS, ATP_XFACT);
+	y_hw = atp_calculate_abs(xy_acc + ATP_XSENSORS,
+				 ATP_YSENSORS, ATP_YFACT);
+
+	if (x_hw < 0 || y_hw < 0) {
+		memset(xy_acc, 0, sizeof(xy_acc));
+		goto exit;
+	}
+
+	if (x_hw && y_hw) {
+		if (debug > 1)
+			printk("appletouch: Xhw: %3d Yhw: %3d "
+			       "Xsm: %3d Ysm: %3d\n",
+			       x_hw, y_hw, x_hw, y_hw);
+
+		input_report_key(&dev->input, BTN_TOUCH, 1);
+		input_report_abs(&dev->input, ABS_X, x_hw);
+		input_report_abs(&dev->input, ABS_Y, y_hw);
+		input_report_abs(&dev->input, ABS_PRESSURE, 100);
+		input_report_key(&dev->input, BTN_TOOL_FINGER, 1);
+	} else if (!x_hw && !y_hw) {
+		input_report_key(&dev->input, BTN_TOUCH, 0);
+		input_report_abs(&dev->input, ABS_PRESSURE, 0);
+		input_report_key(&dev->input, BTN_TOOL_FINGER, 0);
+
+		/* reset the accumulator on release */
+		memset(xy_acc, 0, sizeof(xy_acc));
+	}
+
+	input_report_key(&dev->input, BTN_LEFT, !!dev->data[80]);
+
+	input_sync(&dev->input);
+
+exit:
+	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
+	if (retval) {
+		err("%s - usb_submit_urb failed with result %d",
+		    __FUNCTION__, retval);
+	}
+}
+
+static int atp_open(struct input_dev *input)
+{
+	struct atp *dev = input->private;
+
+	if (usb_submit_urb(dev->urb, GFP_ATOMIC))
+		return -EIO;
+
+	dev->open = 1;
+	return 0;
+}
+
+static void atp_close(struct input_dev *input)
+{
+	struct atp *dev = input->private;
+
+	usb_kill_urb(dev->urb);
+	dev->open = 0;
+}
+
+static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+	struct atp *dev = NULL;
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	int int_in_endpointAddr = 0;
+	int i, retval = -ENOMEM;
+
+	/* allocate memory for our device state and initialize it */
+	dev = kmalloc(sizeof(struct atp), GFP_KERNEL);
+	if (dev == NULL) {
+		err("Out of memory");
+		goto err_kmalloc;
+	}
+	memset(dev, 0, sizeof(struct atp));
+
+	dev->udev = interface_to_usbdev(iface);
+
+	/* set up the endpoint information */
+	/* use only the first interrupt-in endpoint */
+	iface_desc = iface->cur_altsetting;
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+		endpoint = &iface_desc->endpoint[i].desc;
+		if (!int_in_endpointAddr &&
+		    (endpoint->bEndpointAddress & USB_DIR_IN) &&
+		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+					== USB_ENDPOINT_XFER_INT)) {
+			/* we found an interrupt in endpoint */
+			int_in_endpointAddr = endpoint->bEndpointAddress;
+			break;
+		}
+	}
+	if (!int_in_endpointAddr) {
+		retval = -EIO;
+		err("Could not find int-in endpoint");
+		goto err_endpoint;
+	}
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(iface, dev);
+
+	dev->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->urb) {
+		retval = -ENOMEM;
+		goto err_usballoc;
+	}
+	dev->data = usb_buffer_alloc(dev->udev, ATP_DATASIZE, GFP_KERNEL,
+				     &dev->urb->transfer_dma);
+	if (!dev->data) {
+		retval = -ENOMEM;
+		goto err_usbbufalloc;
+	}
+	usb_fill_int_urb(dev->urb, dev->udev,
+			 usb_rcvintpipe(dev->udev, int_in_endpointAddr),
+			 dev->data, ATP_DATASIZE, atp_complete, dev, 1);
+
+	init_input_dev(&dev->input);
+	dev->input.name = "appletouch";
+	dev->input.dev = &iface->dev;
+	dev->input.private = dev;
+	dev->input.open = atp_open;
+	dev->input.close = atp_close;
+
+	dev->input.id.bustype = BUS_USB;
+	dev->input.id.vendor = id->idVendor;
+	dev->input.id.product = id->idProduct;
+	dev->input.id.version = ATP_DRIVER_VERSION;
+
+	set_bit(EV_ABS, dev->input.evbit);
+	if (id->idProduct == ATP_17INCH_ID1)
+		input_set_abs_params(&dev->input, ABS_X, 0,
+				     (ATP_XSENSORS - 1) * ATP_XFACT - 1,
+				     ATP_FUZZ, 0);
+	else
+		/* 12" and 15" Powerbooks only have 16 x sensors */
+		input_set_abs_params(&dev->input, ABS_X, 0,
+				     (16 - 1) * ATP_XFACT - 1,
+				     ATP_FUZZ, 0);
+	input_set_abs_params(&dev->input, ABS_Y, 0,
+			     (ATP_YSENSORS - 1) * ATP_YFACT - 1,
+			     ATP_FUZZ, 0);
+	input_set_abs_params(&dev->input, ABS_PRESSURE, 0, 100, 0, 0);
+
+	set_bit(EV_KEY, dev->input.evbit);
+	set_bit(BTN_TOUCH, dev->input.keybit);
+	set_bit(BTN_TOOL_FINGER, dev->input.keybit);
+	set_bit(BTN_LEFT, dev->input.keybit);
+
+	input_register_device(&dev->input);
+
+	printk(KERN_INFO "input: appletouch connected\n");
+
+	return 0;
+
+err_usbbufalloc:
+	usb_free_urb(dev->urb);
+err_usballoc:
+	usb_set_intfdata(iface, NULL);
+err_endpoint:
+	kfree(dev);
+err_kmalloc:
+	return retval;
+}
+
+static void atp_disconnect(struct usb_interface *iface)
+{
+	struct atp *dev = usb_get_intfdata(iface);
+
+	usb_set_intfdata(iface, NULL);
+	if (dev) {
+		usb_kill_urb(dev->urb);
+		input_unregister_device(&dev->input);
+		usb_free_urb(dev->urb);
+		usb_buffer_free(dev->udev, ATP_DATASIZE,
+				dev->data, dev->urb->transfer_dma);
+		kfree(dev);
+	}
+	printk(KERN_INFO "input: appletouch disconnected\n");
+}
+
+static int atp_suspend(struct usb_interface *iface, pm_message_t message)
+{
+	struct atp *dev = usb_get_intfdata(iface);
+	usb_kill_urb(dev->urb);
+	valid = 0;
+	return 0;
+}
+
+static int atp_resume(struct usb_interface *iface)
+{
+	struct atp *dev = usb_get_intfdata(iface);
+	if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
+		return -EIO;
+
+	return 0;
+}
+
+static struct usb_driver atp_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "appletouch",
+	.probe		= atp_probe,
+	.disconnect	= atp_disconnect,
+	.suspend	= atp_suspend,
+	.resume		= atp_resume,
+	.id_table	= atp_table,
+};
+
+static int __init atp_init(void)
+{
+	return usb_register(&atp_driver);
+}
+
+static void __exit atp_exit(void)
+{
+	usb_deregister(&atp_driver);
+}
+
+module_init(atp_init);
+module_exit(atp_exit);

-- 
Peter Osterlund - [email protected]
http://web.telia.com/~u89404340
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux