Re: [PATCH] [Resubmit] Xbox 360 big button controllers suport

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

 



Hi Peter,

On Sat, Feb 20, 2010 at 03:28:53PM +0100, Peter Paul wrote:
> Hi,
> I've cleaned up James' patch as it received no replies

The driver looks really raw, that's probably one of the reasons there
were no replies.

> (basically
> removed the line wrapping and ran scripts/checkpatch.pl)
> The only thing I've tested is that it applies and compiles, but I do not
> have the hardware to really test it.
> 
> ----------------------
> 
> The xbox 360 game "Scene-it" comes with a set of four "big button"
> controllers, see
> http://en.wikipedia.org/wiki/Big_Button_Controller#Big_Button_Pad.
> 
> Below is a patch which works (most of the time). Each receiver
> attached to the system via USB (multiple at once not tested!) will
> show up as four input devices, one for each controller.  They each
> show up as 11 buttons.  Occasionally, I see missed button-up events,
> and even doubled key-down events (which I didn't think was possible),
> but it works most of the time.  Ideas as to why this happens very
> welcome, as are replies to any of the comments in the patch.
> 
>    Thank you,
>    -=- James Mastros
>    theorbtwo
> 
> 
> Signed-off-by: James Mastros <james@xxxxxxxxxxx>
> 
> diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
> index b114195..eea0550 100644
> --- a/drivers/input/joystick/Kconfig
> +++ b/drivers/input/joystick/Kconfig
> @@ -294,6 +294,16 @@  config JOYSTICK_XPAD_LEDS
>  	  This option enables support for the LED which surrounds the Big X on
>  	  XBox 360 controller.
> 
> +config JOYSTICK_XBOX360BB
> +	tristate "X-Box 360 big-button controller support"
> +	depends on USB_ARCH_HAS_HCD
> +	select USB
> +	help
> +	  Say Y here if you want to use the X-Box 360 "big button"
> +	  controllers with your computer.  These are the large game-show
> +	  style controllers that come with games like "Scene It? Lights, Camera,
> +	  Action."
> +

To compile this driver as a module...

>  config JOYSTICK_WALKERA0701
>  	tristate "Walkera WK-0701 RC transmitter"
>  	depends on HIGH_RES_TIMERS && PARPORT
> diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
> index f3a8cbe..7ab2f96 100644
> --- a/drivers/input/joystick/Makefile
> +++ b/drivers/input/joystick/Makefile
> @@ -29,6 +29,7 @@  obj-$(CONFIG_JOYSTICK_TURBOGRAFX)	+= turbografx.o
>  obj-$(CONFIG_JOYSTICK_TWIDJOY)		+= twidjoy.o
>  obj-$(CONFIG_JOYSTICK_WARRIOR)		+= warrior.o
>  obj-$(CONFIG_JOYSTICK_XPAD)		+= xpad.o
> +obj-$(CONFIG_JOYSTICK_XBOX360BB)	+= xbox360bb.o
>  obj-$(CONFIG_JOYSTICK_ZHENHUA)		+= zhenhua.o
>  obj-$(CONFIG_JOYSTICK_WALKERA0701)	+= walkera0701.o
> 
> diff --git a/drivers/input/joystick/xbox360bb.c b/drivers/input/joystick/xbox360bb.c
> new file mode 100644
> index 0000000..7865c8d
> --- /dev/null
> +++ b/drivers/input/joystick/xbox360bb.c
> @@ -0,0 +1,548 @@ 
> +/*
> + * X-Box 360 big-button controller driver
> + *
> + * This is for the controllers that come with game-show style games
> + * for the xbox 360.  They consist of an IR reciver with a USB cable,
> + * marked on the bottom "Microsoft X-Box 360 Big Button IR" (fixme:
> + * verify), and four seperate controller devices, each with a
> + * different colour scheme: green, red, blue, and yellow (in that
> + * order).
> + *
> + * To the best of my knowledge, these haven't been publicly reverse
> + * engineered before.  The protocol is pretty simple, and is explained
> + * in the comments below.  It's not terribly far from the normal xbox
> + * protocol; there's an additional byte or three of metadata at the
> + * beginning, which specifies what controller is talking, and one of
> + * the otherwise unused bit is the centre-of-dpad button that normal
> + * controllers don't have.
> + *
> + * What is different from the normal controller is the fact that there
> + * are four of them, and that they use the repeat scheme that is
> + * popular in the CIR world -- you keep getting reports of the same
> + * buttons being held down until they aren't held anymore, and you
> + * never get a report that tells you no buttons are held.
> + *
> + * Unlike a normal xbox360 controller, there are no LEDs (so far as I
> + * know; I haven't actually disassembled one, but the game I played
> + * with them didn't use it at all, if there is one, and it would have
> + * been an obvious enhancement to the gameplay.)
> + *
> + * Copyright 2009 James Mastros <james@xxxxxxxxxxx>
> + *
> + * 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
> + *
> + * This driver is based on:
> + *  - the xpad driver -- general input & usb, some xbox -- drivers/input/joystick/xpad.c
> + *  - winbond-cir -- repeat handling -- drivers/input/misc/winbond-cir.c
> + *
> + * TODO:
> + *  - smarter support for repeat.
> + *  - Become certian of the correct keycode for the centre button.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/usb/input.h>
> +#define DRIVER_AUTHOR "James Mastros <james@xxxxxxxxxxx>"
> +#define DRIVER_DESC "X-Box 360 big-buttons driver"
> +
> +#define DPRINTK(fmt, ...)
> +
> +/* No idea where this came from, it's copped from xpad.c */
> +#define XBOX360BB_PKT_LEN 32
> +
> +/*
> + * This might be overkill at this point.  I'm honestly not really
> + * sure.
> + */
> +static const struct xbox360bb_dev_options {
> +	u16 idVendor;
> +	u16 idProduct;
> +	char *name;
> +} xbox360bb_dev_options[] = {
> +	{ 0x045e, 0x02a0, "Microsoft X-Box 360 Big Button IR" },
> +	{ },
> +};
> +
> +static const signed short xbox360bb_btn[] = {
> +	/* Byte 2 (zero-based) or report, MSB to LSB */
> +	/* 0x80 and 0x40 are unused */
> +	BTN_BACK,   /* 0x20 */
> +	BTN_START,  /* 0x10 */
> +	BTN_RIGHT,  /* 0x08 */
> +	BTN_LEFT,   /* 0x04 */
> +	/* No good names for "up" and "down" buttons, use the same as
> +	 * xpad. */
> +	BTN_1,      /* 0x02 */
> +	BTN_0,      /* 0x01 */
> +	/* Byte 3 (zero-based) of report, MSB to LSB */
> +	BTN_Y,      /* 0x80 */
> +	BTN_X,      /* 0x40 */
> +	BTN_B,      /* 0x20 */
> +	BTN_A,      /* 0x10 */
> +	/*
> +	 * this bit isn't used for normal xbox controllers -- on a
> +	 * normal controller, you simply can't hit all the directions at
> +	 * the same time, and on a dance controller, you can only if
> +	 * you have four feet.
> +	 * There's no clear button defintion for this use, so we use
> +	 * thumbr.
> +	 * In any case, it's byte 4, 0x08.
> +	 */
> +	BTN_THUMBR, /* 0x08 */
> +	/* The big X, logo button.  xpad uses BTN_MODE. */
> +	BTN_MODE,   /* 0x04 */
> +	/* 0x02 and 0x01 seem to be unused. */
> +	/* end marker */
> +	-1
> +};

This needs to be copied into instance data, be unsigned short, use
sizeof to get size, set up input->keycode and friends to allow users
remap keys.

> +
> +/*
> + * Xbox 360 has a vendor-specific class, so we cannot match it with only
> + * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
> + * match against vendor id as well. Wired Xbox 360 devices have protocol 1,
> + * wireless controllers have protocol 129, and big button controllers
> + * have protocol 4.
> + */
> +#define XBOX360BB_VENDOR_PROTOCOL(vend, pr) \
> +	.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
> +	.idVendor = (vend), \
> +	.bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
> +	.bInterfaceSubClass = 93, \
> +	.bInterfaceProtocol = (pr)
> +#define XBOX360BB_VENDOR(vend) \
> +	{ XBOX360BB_VENDOR_PROTOCOL(vend, 4) }
> +
> +static struct usb_device_id xbox360bb_usb_table[] = {
> +	XBOX360BB_VENDOR(0x045e),	/* Microsoft X-Box 360 controllers */
> +	{}
> +};
> +
> +MODULE_DEVICE_TABLE(usb, xbox360bb_usb_table);
> +
> +/* Circular dependency */
> +struct xbox360bb;
> +
> +struct xbox360bb_controller {
> +	/* Points back to the parent usb_xbox360bb struct */
> +	struct xbox360bb *receiver;
> +	/* 0..3 */
> +	int controller_number;
> +	struct input_dev *idev;
> +	unsigned char last_report[2];
> +	struct timer_list timer_keyup;
> +};
> +
> +struct xbox360bb {
> +	/* USB side */
> +	struct usb_device *udev;	/* usb device */
> +	struct urb *irq_in;		/* urb for interrupt in report */
> +	unsigned char *raw_data;	/* input data */
> +	/* TODO: rename to raw_data_dma */
> +	dma_addr_t idata_dma;
> +
> +	/* input side */
> +
> +	/* the number of input devices which are open.  Should always
> +	   be between 0 and 4, and FIXME should have locking? */
> +	int idev_open_count;
> +
> +	/* These are in a sub-struct per controller, so that we have
> +	 * something nice to point to as user data in the callback
> +	 * functions that lets us know which controller we are
> +	 * handling in a nice, clean manner.  OTOH, directly embedding
> +	 * the struct lets us not worry about that messy allocation
> +	 * stuff
> +	 */
> +	struct xbox360bb_controller controller[4];
> +};
> +
> +/* xbox360bb_keydown
> + *
> + * Note that a key has gone down, or is still down.
> + * While currently this is quite simple, it should shortly become
> + * quite a bit more complex.  FIXME: Take code for this from
> + * drivers/input/misc/winbond-cir.c, bcir_keyup & such.
> + *
> + *
> + */
> +static void xbox360bb_keydown(struct xbox360bb_controller *controller, int button, int val)
> +{
> +	input_report_key(controller->idev, button, val);
> +}

What is the point of the wrapper?

> +
> +/* xbox360bb_keyup
> + *
> + * This is the timer callback function.  If we reach this, that means
> + * we haven't had a report at all for this controller in some time, so
> + * we should consider *all* keys that it had down as up.
> + */
> +static void xbox360bb_keyup(unsigned long user_data)
> +{
> +	int btn_i;
> +	struct xbox360bb_controller *controller = (struct xbox360bb_controller *)user_data;
> +
> +	printk(KERN_INFO "xbox360bb: timer callback for controller %d\n", controller->controller_number);

Not a good idea, how often woudl you see this and why would one care?

> +
> +	/* FIXME: Is there a quick, simple way to keyup all currently
> +	 * down keys at once? */

No, there isn't.

> +	for (btn_i = 0; xbox360bb_btn[btn_i] >= 0; btn_i++)
> +		input_report_key(controller->idev, xbox360bb_btn[btn_i], 0);
> +
> +	input_sync(controller->idev);
> +	controller->last_report[0] = 0;
> +	controller->last_report[1] = 0;
> +}
> +
> +/*
> + * xbox360bb_usb_process_packet
> + *
> + * Given the actual payload of a packet, make it into events.  This is
> + * the actual core of this module; everything else is plumbing.
> + */
> +static void xbox360bb_usb_process_packet(struct xbox360bb *xbox360bb, u16 cmd, unsigned char* data)
> +{
> +	/* Byte 2 of the input is what controller we've got, zero
> +	 * based: green, red, blue, yellow. */
> +	struct xbox360bb_controller *controller;
> +
> +	if (data[2] > 3) {
> +		printk(KERN_WARNING "Argh, xbox360bb controller number out of range: %d", data[2]);
> +		/* Should we stop processing completely, rather then
> +		just this report?  Depends on how severe the error is,
> +		and I currently have no way of telling.  There's
> +		unlikely to be worse results then just the driver
> +		hitting random buttons -- this is the only place where
> +		we use input from the controller as an index in kernel
> +		space. On the other hand, what controller do we
> +		attribute the report to? */

You tell me...

> +		return;
> +	}
> +	controller = &(xbox360bb->controller[data[2]]);
> +
> +	DPRINTK("xbox360bb: %d ms currently remaining on timer\n", jiffies_to_msecs(controller->timer_keyup.expires-jiffies));
> +
> +	/* Arm the timer (or move it forward).  In a quick test, 188
> +	 * ms is longest between two reports.  250 should give us
> +	 * plenty of time for highly loaded systems. */
> +	mod_timer(&controller->timer_keyup, jiffies + msecs_to_jiffies(250));
> +
> +	/* Short-circuit further processing if this report is the same
> +	 * as the previous one.  Just a cheap way of saving CPU time,
> +	 * mostly. */
> +	if (controller->last_report[0] == data[3] &&
> +	    controller->last_report[1] == data[4]) {
> +		DPRINTK("xbox360bb: Ignoring duplicate report\n");
> +		return;
> +	}
> +	controller->last_report[0] = data[3];
> +	controller->last_report[1] = data[4];
> +
> +	/* dpad as four buttons... */
> +	xbox360bb_keydown(controller, BTN_0,      data[3] & 0x01); /* up */
> +	xbox360bb_keydown(controller, BTN_1,      data[3] & 0x02); /* down */
> +	xbox360bb_keydown(controller, BTN_LEFT,   data[3] & 0x04);
> +	xbox360bb_keydown(controller, BTN_RIGHT,  data[3] & 0x08);
> +
> +	/* start/back buttons */
> +	xbox360bb_keydown(controller, BTN_START,  data[3] & 0x10);
> +	xbox360bb_keydown(controller, BTN_BACK,   data[3] & 0x20);
> +	xbox360bb_keydown(controller, BTN_MODE,   data[4] & 0x04);
> +

Hmm, we have a keytable but here we hard-coding events. Either we need
to do a flat table lookup or use sparse keymap library.

> +	/* This is the only button that is rather novel vs the normal
> +	 * controller.  The corsponding bit for the normal controllers
> +	 * isn't used, as far as I can see.  It's like the thumb
> +	 * buttons, so call it the right one, randomly.
> +	 * (Normally the thumb button goes with an analog stick, not a dpad.)
> +	 */
> +	xbox360bb_keydown(controller, BTN_THUMBR, data[4] & 0x08);
> +
> +
> +	/* buttons A,B,X,Y,TL,TR and MODE */
> +	xbox360bb_keydown(controller, BTN_A,	  data[4] & 0x10);
> +	xbox360bb_keydown(controller, BTN_B,	  data[4] & 0x20);
> +	xbox360bb_keydown(controller, BTN_X,	  data[4] & 0x40);
> +	xbox360bb_keydown(controller, BTN_Y,	  data[4] & 0x80);
> +
> +	input_sync(controller->idev);
> +}
> +
> +static void xbox360bb_usb_irq_in(struct urb *urb)
> +{
> +	struct xbox360bb *xbox360bb = urb->context;
> +	int retval, status;
> +
> +	status = urb->status;
> +
> +
> +	switch (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",
> +		    __func__, status);
> +		return;
> +	default:
> +		dbg("%s - nonzero urb status received: %d",
> +		    __func__, status);
> +		goto exit;
> +	}
> +
> +	xbox360bb_usb_process_packet(xbox360bb, 0, xbox360bb->raw_data);
> +
> +exit:
> +	retval = usb_submit_urb(urb, GFP_ATOMIC);
> +	if (retval)
> +		err("%s - usb_submit_urb failed with result %d",
> +		     __func__, retval);
> +}
> +
> +/* Input side device opened.  We'll never see two overlapping opens
> + * for the same controller; the kernel handles the multiplexing for
> + * us.
> + */
> +static int xbox360bb_input_open(struct input_dev *idev)
> +{
> +	struct xbox360bb_controller *controller = input_get_drvdata(idev);
> +	struct xbox360bb *xbox360bb = controller->receiver;
> +	int error;
> +
> +	if (xbox360bb->idev_open_count == 0) {

No need to count, input core will only call us when needed (once unless
device has been closed in the mean time).

> +		DPRINTK("In open, submitting URB\n");
> +		error = usb_submit_urb(xbox360bb->irq_in, GFP_KERNEL);
> +		if (error) {
> +			printk(KERN_WARNING "xbox360bb: ...error = %d\n", error);
> +			return -EIO;
> +		}
> +		DPRINTK("...passed\n");
> +	} else {
> +		DPRINTK("Not trying to submit URB; it should already be running (idev_open_count=%d)\n", xbox360bb->idev_open_count);
> +	}
> +	xbox360bb->idev_open_count++;
> +	if (xbox360bb->idev_open_count > 4)
> +		printk(KERN_WARNING "xbox360bb: WTF, idev_open_count=%d is out of range after open\n", xbox360bb->idev_open_count);
> +
> +	return 0;
> +}
> +
> +static void xbox360bb_input_close(struct input_dev *idev)
> +{
> +	struct xbox360bb_controller *controller = input_get_drvdata(idev);
> +	struct xbox360bb *xbox360bb = controller->receiver;
> +
> +	if (xbox360bb->idev_open_count == 1) {

Same here, just do it.

> +		DPRINTK("In close, killing urb\n");
> +		usb_kill_urb(xbox360bb->irq_in);
> +	} else {
> +		DPRINTK("In close, not killing urb, open count=%d\n", xbox360bb->idev_open_count);
> +	}
> +	xbox360bb->idev_open_count--;
> +	if (xbox360bb->idev_open_count < 0)
> +		printk(KERN_WARNING "xbox360bb: Argh, idev_open_count less then 0: %d\n", xbox360bb->idev_open_count);
> +}
> +
> +static int xbox360bb_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
> +{
> +	struct usb_device *udev = interface_to_usbdev(intf);
> +	struct xbox360bb *xbox360bb;
> +	struct input_dev *input_dev;
> +	struct usb_endpoint_descriptor *ep_irq_in;
> +	const struct xbox360bb_dev_options *dev_options = NULL;
> +	char *controller_colors[] = {" green controller",
> +				     " red controller",
> +				     " blue controller",
> +				     " yellow controller"};
> +
> +	int options_i;
> +	int controller_i;
> +	int btn_i;
> +	int error = -ENOMEM;
> +
> +	printk(KERN_INFO "xbox360bb_usb_probe vendor=0x%x, product=0x%x\n",
> +	       le16_to_cpu(udev->descriptor.idVendor),
> +	       le16_to_cpu(udev->descriptor.idProduct)
> +		);
> +
> +	/* Find the xbox360bb_device entry for this one.  (FIXME:
> +	   Should we get rid of this?  We only have one, presently,
> +	   and no options we need to look up in here anyway.) */
> +	for (options_i = 0; xbox360bb_dev_options[options_i].idVendor; options_i++) {
> +		dev_options = &xbox360bb_dev_options[options_i];
> +		if ((le16_to_cpu(udev->descriptor.idVendor) == dev_options->idVendor) &&
> +		    (le16_to_cpu(udev->descriptor.idProduct) == dev_options->idProduct))
> +			break;
> +	}
> +
> +	xbox360bb = kzalloc(sizeof(struct xbox360bb), GFP_KERNEL);
> +	if (!xbox360bb)
> +		goto fail1;
> +
> +	/* Init the USB stuff */
> +	xbox360bb->udev = udev;
> +
> +	xbox360bb->raw_data = usb_buffer_alloc(udev, XBOX360BB_PKT_LEN, GFP_KERNEL, &xbox360bb->idata_dma);
> +	if (!xbox360bb->raw_data)
> +		goto fail2;
> +
> +	xbox360bb->irq_in = usb_alloc_urb(0, GFP_KERNEL);
> +	if (!xbox360bb->irq_in)
> +		goto fail3;
> +
> +	ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
> +	usb_fill_int_urb(xbox360bb->irq_in, udev,
> +			 usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
> +			 xbox360bb->raw_data, XBOX360BB_PKT_LEN, xbox360bb_usb_irq_in,
> +			 xbox360bb, ep_irq_in->bInterval);
> +	xbox360bb->irq_in->transfer_dma = xbox360bb->idata_dma;
> +	xbox360bb->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> +	xbox360bb->irq_in->dev = xbox360bb->udev;
> +
> +	usb_set_intfdata(intf, xbox360bb);
> +
> +	/* Init the input stuff */
> +	for (controller_i = 0; controller_i < 4; controller_i++) {
> +		int name_size;
> +		/* input_dev name/phys are const char *, so we need
> +		 * to warn all over, or use a temporary.  */
> +		char *name;
> +		char *phys;
> +		struct xbox360bb_controller *controller = &(xbox360bb->controller[controller_i]);
> +
> +		printk(KERN_INFO "xbox360bb: making input dev %d\n", controller_i);

dev_dbg().

> +
> +		controller->controller_number = controller_i;
> +		controller->receiver = xbox360bb;
> +
> +		setup_timer(&(controller->timer_keyup), xbox360bb_keyup, (unsigned long)controller);
> +
> +		input_dev = input_allocate_device();
> +		if (!input_dev)
> +			goto fail4;
> +		controller->idev = input_dev;
> +
> +		name_size = strlen(dev_options->name) + strlen(controller_colors[controller_i]) + 1;
> +		name = kzalloc(name_size, GFP_KERNEL);
> +		if (!name)
> +			goto fail4;
> +
> +		/* Don't bother checking returns, we explicitly sized
> +		 * input_dev->name so it will fit, and the worst that
> +		 * will happen with str*l*(cpy|cat) is truncation.
> +		 */
> +		strlcpy(name, dev_options->name, name_size);
> +		strlcat(name, controller_colors[controller_i], name_size);

Snprintf... also can kill word "contoller" in all the colors.

> +
> +		printk(KERN_INFO "xbox360bb: ... name='%s'\n", name);

Looks like dev_dbg() to me.

> +		input_dev->name = name;
> +
> +		/* Right, now need to do the same with phys, more or less. */
> +		/* 64 is taken from xpad.c.  I hope it's long enough. */
> +		phys = kzalloc(64, GFP_KERNEL);
> +		if (!phys)
> +			goto fail4;
> +		usb_make_path(udev, phys, 64);
> +		snprintf(phys, 64, "%s/input%d", phys, controller_i);
> +		printk(KERN_INFO "xbox360bb: ... phys='%s'\n", phys);
> +		input_dev->phys = phys;
> +
> +		/* Static data */
> +		input_dev->dev.parent = &intf->dev;
> +		printk(KERN_INFO "xbox360bb: ... input_set_drvdata\n");
> +		input_set_drvdata(input_dev, controller);
> +		/* Set the input device vendor/product/version from
> +		   the usb ones. */
> +		usb_to_input_id(udev, &input_dev->id);
> +		input_dev->open  = xbox360bb_input_open;
> +		input_dev->close = xbox360bb_input_close;
> +
> +		/* This is probably horribly inefficent, but it's
> +		   one-time init code.  Keep it easy to read, until
> +		   profiling says it's *actually* a problem. */
> +		input_dev->evbit[0] = BIT_MASK(EV_KEY);
> +		for (btn_i = 0; xbox360bb_btn[btn_i] >= 0; btn_i++)
> +			set_bit(xbox360bb_btn[btn_i], input_dev->keybit);
> +
> +
> +		printk(KERN_INFO "xbox360bb: ... input_register_device\n");
> +		error = input_register_device(input_dev);
> +		printk(KERN_INFO "xbox360bb: returned from input_register_device, error=%d\n", error);
> +		if (error)
> +			goto fail4;
> +	}
> +
> +	return 0;
> +
> +	/* FIXME: We currently leak in failure cases numbered above
> +	 * fail3. */

Yes, please do fixme.

> +fail4:
> +	printk(KERN_WARNING "xbox360bb: Aaargh, hit fail4!\n");
> +	/* need to check which bits of the input stuff have been
> +	 * allocated, because it's all loopy. */
> +fail3:
> +	usb_free_urb(xbox360bb->irq_in);
> +fail2:
> +	usb_buffer_free(udev, XBOX360BB_PKT_LEN, xbox360bb->raw_data, xbox360bb->idata_dma);
> +fail1:
> +	return error;
> +}
> +
> +static void xbox360bb_usb_disconnect(struct usb_interface *intf)
> +{
> +	struct xbox360bb *xbox360bb = usb_get_intfdata(intf);
> +
> +	usb_set_intfdata(intf, NULL);
> +	if (!xbox360bb)
> +		return;
> +
> +	input_unregister_device(xbox360bb->controller[0].idev);
> +	input_unregister_device(xbox360bb->controller[1].idev);
> +	input_unregister_device(xbox360bb->controller[2].idev);
> +	input_unregister_device(xbox360bb->controller[3].idev);

Use for ()? Also, what about freeing name and phys for each of these?

> +	/* FIXME: free the timers? */

Free? They are part of the controller structure. But we need to make sure
they are stopped and this should be done in close().

> +	usb_free_urb(xbox360bb->irq_in);
> +	usb_buffer_free(xbox360bb->udev, XBOX360BB_PKT_LEN,
> +			xbox360bb->raw_data, xbox360bb->idata_dma);
> +	kfree(xbox360bb);
> +}
> +
> +static struct usb_driver xbox360bb_usb_driver = {
> +	.name       = "xbox360bb",
> +	.probe      = xbox360bb_usb_probe,
> +	.disconnect = xbox360bb_usb_disconnect,
> +	.id_table   = xbox360bb_usb_table
> +};
> +
> +static int __init xbox360bb_usb_init(void)
> +{
> +	int result = usb_register(&xbox360bb_usb_driver);
> +	if (result == 0)
> +		printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
> +	return result;

Just do "return usb_register(&xbox360bb_usb_driver);", no need for
printk here.

What about PM (suspend/resume)?

> +}
> +
> +static void __exit xbox360bb_usb_exit(void)
> +{
> +	usb_deregister(&xbox360bb_usb_driver);
> +}
> +
> +module_init(xbox360bb_usb_init);
> +module_exit(xbox360bb_usb_exit);
> +
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE("GPL");
> 

Thanks.

-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux