Re: [PATCH] (revision 1) input: xpad.c - Xbox 360 wireless and sysfs support

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

 



On Sun, Feb 22, 2009 at 12:31:27AM -0500, Mike Murphy wrote:
> Greetings,
> 
> Attached is a revised version of my previous patch to
> drivers/input/joystick/xpad.c, which should apply without issues to
> the current stable tree (2.6.28.7 at the time of this writing). I have
> made a number of major changes since the original:
> 
> 1. Removed kobject and used input device's existing kobject for sysfs
> via DEVICE_ATTR. All attributes are part of a game_device group, which
> I will document once this patch has been reviewed. Thanks to Greg K-H
> for his help with the sysfs interface and helpful feedback. Return
> values for sscanf are also now checked, and the ugly strcmp code has
> been replaced by a cleaner solution (thanks Oliver Neukum). Wireless
> 360 controllers now produce an online/offline uevent when
> connecting/disconnecting, for later userspace use. Additionally, the
> whole sysfs interface is now dependent upon CONFIG_SYSFS (the driver
> should continue to work without it).
> 
> 2. urb submissions while holding mutexes have been reverted to
> GFP_KERNEL, and fixes have been made to the shared workqueue code to
> account for possible adverse events (such as removal of the device
> before the work gets done). Thanks to Oliver Neukum for his feedback.
> 
> 3. Re-factored the code a bit and split it into two pieces (xpad.h and
> xpad.c). The division of the main data structures into a header file
> makes development on the main body much easier.
> 
> 4. After extensive testing and debugging with a popular fighting game
> in an emulator (with 3-4 concurrent players on wireless 360
> controllers), I changed the original square axis algorithm to an axis
> limiting and scaling algorithm that works on a per-stick basis. This
> new algorithm is substantially less jumpy when using a square axis,
> and it permits the size of the inscribed square to be adjusted on a
> per-controller basis. The nominal value to use to achieve the largest
> possible inscribed square on "perfect" hardware is 23170, but
> manufacturing variations in the controllers might require a smaller
> number.
> 
> Comments and feedback on this revision are greatly appreciated, and I
> plan to test all the supported hardware I can get my hands on (need to
> borrow some wired classic and 360 devices) to be sure the new code
> doesn't break support for older devices. I will also document the
> userspace interface by submitting a Documentation/ABI/testing patch
> with the "final" version of the driver, once it has been nailed down.
> 
> Thanks,
> Mike
> -- 
> Mike Murphy
> Ph.D. Candidate and NSF Graduate Research Fellow
> Clemson University School of Computing
> 120 McAdams Hall
> Clemson, SC 29634-0974 USA
> Tel: +1 864.656.2838   Fax: +1 864.656.0145
> http://cirg.cs.clemson.edu/~mamurph

> diff -uNr origdrv/drivers/input/joystick/xpad.c newdrv/drivers/input/joystick/xpad.c
> --- origdrv/drivers/input/joystick/xpad.c	2009-02-14 22:39:20.000000000 -0500
> +++ newdrv/drivers/input/joystick/xpad.c	2009-02-21 23:58:21.000000000 -0500
> @@ -1,5 +1,8 @@
>  /*
> - * X-Box gamepad driver
> + * Xbox gamepad driver with Xbox 360 wired/wireless support
> + *
> + * Last Modified:	21 February 2009
> + *			Mike Murphy <mamurph@xxxxxxxxxxxxxx>
>   *
>   * Copyright (c) 2002 Marko Friedemann <mfr@xxxxxxxxxxxxxxx>
>   *               2004 Oliver Schwartz <Oliver.Schwartz@xxxxxx>,
> @@ -9,6 +12,8 @@
>   *               2005 Dominic Cerquetti <binary1230@xxxxxxxxx>
>   *               2006 Adam Buchbinder <adam.buchbinder@xxxxxxxxx>
>   *               2007 Jan Kratochvil <honza@xxxxxxxx>
> + *               2009 Clemson University
> + *		      (contact: Mike Murphy <mamurph@xxxxxxxxxxxxxx>)
>   *
>   * This program is free software; you can redistribute it and/or
>   * modify it under the terms of the GNU General Public License as
> @@ -24,224 +29,305 @@
>   * along with this program; if not, write to the Free Software
>   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>   *
> + * Please see xbox.h for the ChangeLog.
> + */
> +
> +
> +
> +#include "xpad.h"
> +
> +
> +/* The dead zone and stick limit both affect the behavior of the corresponding
> + * analog stick, since the output values reported for the stick inputs will
> + * be scaled onto [0,32767]. It is thus necessary to ensure that the dead zone
> + * is never larger than the stick limit. In fact, a minimal amount of stick
> + * travel space (1024) is maintained between the two values. In practice,
> + * however, the stick limit should always be much greater than the dead zone.
> + */
> +
> +static void set_dead_zone(unsigned int new_size, unsigned int *dz, unsigned int stick_limit)
> +{
> +	if ((new_size + 1024) >= stick_limit)
> +		new_size = (stick_limit > 1024) ? stick_limit - 1024 : 0;
> +	*dz = new_size;
> +}
> +
> +static void set_stick_limit(unsigned int new_size, unsigned int *sl, unsigned int dead_zone)
> +{
> +	if (new_size < (dead_zone + 1024))
> +		new_size = dead_zone + 1024;
> +	if (new_size > 32767)
> +		new_size = 32767;
> +	*sl = new_size;
> +}
> +
> +
> +/****************************************************************************/
> +/*
> + * SysFs interface functions
>   *
> - * This driver is based on:
> - *  - information from     http://euc.jp/periphs/xbox-controller.ja.html
> - *  - the iForce driver    drivers/char/joystick/iforce.c
> - *  - the skeleton-driver  drivers/usb/usb-skeleton.c
> - *  - Xbox 360 information http://www.free60.org/wiki/Gamepad
> - *
> - * Thanks to:
> - *  - ITO Takayuki for providing essential xpad information on his website
> - *  - Vojtech Pavlik     - iforce driver / input subsystem
> - *  - Greg Kroah-Hartman - usb-skeleton driver
> - *  - XBOX Linux project - extra USB id's
> - *
> - * TODO:
> - *  - fine tune axes (especially trigger axes)
> - *  - fix "analog" buttons (reported as digital now)
> - *  - get rumble working
> - *  - need USB IDs for other dance pads
> - *
> - * History:
> - *
> - * 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller"
> - *
> - * 2002-07-02 - 0.0.2 : basic working version
> - *  - all axes and 9 of the 10 buttons work (german InterAct device)
> - *  - the black button does not work
> - *
> - * 2002-07-14 - 0.0.3 : rework by Vojtech Pavlik
> - *  - indentation fixes
> - *  - usb + input init sequence fixes
> - *
> - * 2002-07-16 - 0.0.4 : minor changes, merge with Vojtech's v0.0.3
> - *  - verified the lack of HID and report descriptors
> - *  - verified that ALL buttons WORK
> - *  - fixed d-pad to axes mapping
> - *
> - * 2002-07-17 - 0.0.5 : simplified d-pad handling
> - *
> - * 2004-10-02 - 0.0.6 : DDR pad support
> - *  - borrowed from the XBOX linux kernel
> - *  - USB id's for commonly used dance pads are present
> - *  - dance pads will map D-PAD to buttons, not axes
> - *  - pass the module paramater 'dpad_to_buttons' to force
> - *    the D-PAD to map to buttons if your pad is not detected
> - *
> - * Later changes can be tracked in SCM.
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/init.h>
> -#include <linux/slab.h>
> -#include <linux/stat.h>
> -#include <linux/module.h>
> -#include <linux/usb/input.h>
> -
> -#define DRIVER_AUTHOR "Marko Friedemann <mfr@xxxxxxxxxxxxxxx>"
> -#define DRIVER_DESC "X-Box pad driver"
> -
> -#define XPAD_PKT_LEN 32
> -
> -/* xbox d-pads should map to buttons, as is required for DDR pads
> -   but we map them to axes when possible to simplify things */
> -#define MAP_DPAD_TO_BUTTONS    0
> -#define MAP_DPAD_TO_AXES       1
> -#define MAP_DPAD_UNKNOWN       2
> -
> -#define XTYPE_XBOX        0
> -#define XTYPE_XBOX360     1
> -#define XTYPE_XBOX360W    2
> -#define XTYPE_UNKNOWN     3
> -
> -static int dpad_to_buttons;
> -module_param(dpad_to_buttons, bool, S_IRUGO);
> -MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
> -
> -static const struct xpad_device {
> -	u16 idVendor;
> -	u16 idProduct;
> -	char *name;
> -	u8 dpad_mapping;
> -	u8 xtype;
> -} xpad_device[] = {
> -	{ 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
> -	{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
> -	{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
> -	{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
> -	{ 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
> -	{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
> -	{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0c12, 0x880a, "Pelican Eclipse PL-2023", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
> -	{ 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
> -	{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
> -	{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
> -	{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
> -	{ 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
> -	{ 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN }
> -};
> -
> -/* buttons shared with xbox and xbox360 */
> -static const signed short xpad_common_btn[] = {
> -	BTN_A, BTN_B, BTN_X, BTN_Y,			/* "analog" buttons */
> -	BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
> -	-1						/* terminating entry */
> -};
> -
> -/* original xbox controllers only */
> -static const signed short xpad_btn[] = {
> -	BTN_C, BTN_Z,		/* "analog" buttons */
> -	-1			/* terminating entry */
> -};
> -
> -/* only used if MAP_DPAD_TO_BUTTONS */
> -static const signed short xpad_btn_pad[] = {
> -	BTN_LEFT, BTN_RIGHT,		/* d-pad left, right */
> -	BTN_0, BTN_1,			/* d-pad up, down (XXX names??) */
> -	-1				/* terminating entry */
> -};
> -
> -static const signed short xpad360_btn[] = {  /* buttons for x360 controller */
> -	BTN_TL, BTN_TR,		/* Button LB/RB */
> -	BTN_MODE,		/* The big X button */
> -	-1
> -};
> -
> -static const signed short xpad_abs[] = {
> -	ABS_X, ABS_Y,		/* left stick */
> -	ABS_RX, ABS_RY,		/* right stick */
> -	ABS_Z, ABS_RZ,		/* triggers left/right */
> -	-1			/* terminating entry */
> -};
> -
> -/* only used if MAP_DPAD_TO_AXES */
> -static const signed short xpad_abs_pad[] = {
> -	ABS_HAT0X, ABS_HAT0Y,	/* d-pad axes */
> -	-1			/* terminating entry */
> -};
> -
> -/* 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. */
> -#define XPAD_XBOX360_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 XPAD_XBOX360_VENDOR(vend) \
> -	{ XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \
> -	{ XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) }
> -
> -static struct usb_device_id xpad_table [] = {
> -	{ USB_INTERFACE_INFO('X', 'B', 0) },	/* X-Box USB-IF not approved class */
> -	XPAD_XBOX360_VENDOR(0x045e),		/* Microsoft X-Box 360 controllers */
> -	XPAD_XBOX360_VENDOR(0x046d),		/* Logitech X-Box 360 style controllers */
> -	XPAD_XBOX360_VENDOR(0x0738),		/* Mad Catz X-Box 360 controllers */
> -	XPAD_XBOX360_VENDOR(0x0e6f),		/* 0x0e6f X-Box 360 controllers */
> -	XPAD_XBOX360_VENDOR(0x1430),		/* RedOctane X-Box 360 controllers */
> -	{ }
> -};
> -
> -MODULE_DEVICE_TABLE (usb, xpad_table);
> -
> -struct usb_xpad {
> -	struct input_dev *dev;		/* input device interface */
> -	struct usb_device *udev;	/* usb device */
> -
> -	int pad_present;
> -
> -	struct urb *irq_in;		/* urb for interrupt in report */
> -	unsigned char *idata;		/* input data */
> -	dma_addr_t idata_dma;
> + * We use common functions, where possible, to implement the show/store
> + * routines. This design saves on code and reduces the burden of adding to or
> + * changing the interface.
> + */
> + 
> +#if defined(CONFIG_SYSFS)
>  
> -	struct urb *bulk_out;
> -	unsigned char *bdata;
> +static ssize_t xpad_show_uint(struct device *dev, struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct usb_xpad *xpad = to_xpad(dev);
> +	unsigned int value;
> +	if (attr == &dev_attr_left_dead_zone)
> +		value = xpad->left_dead_zone;
> +	else if (attr == &dev_attr_right_dead_zone)
> +		value = xpad->right_dead_zone;
> +	else if (attr == &dev_attr_left_stick_limit)
> +		value = xpad->left_stick_limit;
> +	else if (attr == &dev_attr_right_stick_limit)
> +		value = xpad->right_stick_limit;
> +	else
> +		return -EIO;
> +	return snprintf(buf, PAGE_SIZE, "%u\n", value);
> +}
>  
> -#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
> -	struct urb *irq_out;		/* urb for interrupt out report */
> -	unsigned char *odata;		/* output data */
> -	dma_addr_t odata_dma;
> -	struct mutex odata_mutex;
> -#endif
>  
> -#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
> -	struct xpad_led *led;
> +static ssize_t xpad_store_uint(struct device *dev,
> +		struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct usb_xpad *xpad = to_xpad(dev);
> +	unsigned int new_value;
> +	if (1 != sscanf(buf, "%u", &new_value)) {
> +		return -EIO;
> +	}
> +	if (attr == &dev_attr_left_dead_zone)
> +		set_dead_zone(new_value, &xpad->left_dead_zone, xpad->left_stick_limit);
> +	else if (attr == &dev_attr_right_dead_zone)
> +		set_dead_zone(new_value, &xpad->right_dead_zone, xpad->right_stick_limit);
> +	else if (attr == &dev_attr_left_stick_limit)
> +		set_stick_limit(new_value, &xpad->left_stick_limit, xpad->left_dead_zone);
> +	else if (attr == &dev_attr_right_stick_limit)
> +		set_stick_limit(new_value, &xpad->right_stick_limit, xpad->right_dead_zone);
> +	else
> +		return -EIO;
> +	return strnlen(buf, PAGE_SIZE);
> +}
> +
> +
> +static ssize_t xpad_store_rumble_enable(struct device *dev,
> +		struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct usb_xpad *xpad = to_xpad(dev);
> +	int newrumble = xpad->rumble_enable;
> +	if (1 == sscanf(buf, "%d", &newrumble))


Oh, that's not wrong but it looks weird, usually, a code reader would
expect to see if (sscanf(...) == 1)


> +		xpad->rumble_enable = (newrumble) ? 1 : 0;
> +	return count;
> +}
> +
> +
> +/* read-only attributes share a common store function that returns an error */
> +static ssize_t xpad_store_ro(struct device *dev, struct device_attribute *attr,
> +		const char *buf, size_t count)
> +{
> +	return -EIO;
> +}
> +
> +
> +static ssize_t xpad_show_int(struct device *dev, struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct usb_xpad *xpad = to_xpad(dev);
> +	int value;
> +	if (attr == &dev_attr_rumble_enable)
> +		value = xpad->rumble_enable;
> +	else if (attr == &dev_attr_controller_number)
> +		value = xpad->controller_number;
> +	else if (attr == &dev_attr_controller_present)
> +		value = xpad->controller_present;
> +	else if (attr == &dev_attr_controller_type)
> +		value = xpad->controller_type;
> +	else
> +		return -EIO;
> +	return snprintf(buf, PAGE_SIZE, "%d\n", value);
> +}
> +
> +
> +static ssize_t xpad_show_id(struct device *dev,
> +		struct device_attribute *attr, char *buf)
> +{
> +	struct usb_xpad *xpad = to_xpad(dev);
> +	return snprintf(buf, PAGE_SIZE, "%s\n", xpad->controller_unique_id);
> +}
> +
>  #endif
> +/* end of sysfs interface */
> +/*****************************************************************************/
> +
> +/* Input section */
> +
> +/*	xpad_init_controller
> + *
> + *	Performs controller setup based on controller type.
> + *
> + *	NOTE: xpad->controller_data->controller_type needs to be set BEFORE
> + *	calling this function!
> + */
> + 
> +static void xpad_init_controller(struct usb_xpad *xpad)
> +{
> +	set_stick_limit(XSTICK_LIMIT_DEFAULT, &xpad->left_stick_limit, xpad->left_dead_zone);
> +	set_stick_limit(XSTICK_LIMIT_DEFAULT, &xpad->right_stick_limit, xpad->right_dead_zone);
> +	set_dead_zone(XDEAD_ZONE_DEFAULT, &xpad->left_dead_zone, xpad->left_stick_limit);
> +	set_dead_zone(XDEAD_ZONE_DEFAULT, &xpad->right_dead_zone, xpad->right_stick_limit);
> +	
> +	if (xpad->controller_type == XCONTROLLER_TYPE_GUITAR) {
> +		xpad->rumble_enable = 0;
> +	}
> +	else if (xpad->controller_type == XCONTROLLER_TYPE_DANCE_PAD) {
> +		xpad->rumble_enable = 0;
> +	}
> +	else {
> +		xpad->rumble_enable = 1;
> +	}


The brackets are not needed in these checks, may be you should run
scripts/checkpatch.pl to check obvious coding styles issues.


> +}
> +
>  
> -	char phys[64];			/* physical device path */
> +/*
> + *	xpad_work_controller
> + *
> + *	Submits command to set pad number on LED display of wireless 360
> + *	controllers. The shared workqueue is used for this purpose, so that
> + *	the interrupt handler is kept short.
> + */
> + 
> +static void xpad_work_controller(struct work_struct *w)
> +{
> +   struct usb_xpad * xpad = container_of(w, struct usb_xpad, work);
> +   xpad_send_led_command(xpad, xpad->controller_number + 1);
> +   xpad->work_pending = 0;
> +}
> +
> +
> +/*
> + *	xpad_process_sticks
> + *
> + *	Handles stick input, accounting for dead zones and square axes. Based
> + *	on the original handlers for the Xbox and Xbox 360 in
> + *	xpad_process_packet and xpad360_process_packet, but unified to avoid
> + *	duplication.
> + *
> + *	Whenever a dead zone is used, each axis is scaled so that moving the
> + *	stick slightly out of the dead zone range results in a low axis
> + *	value in jstest(1), while moving the stick to the maximum position
> + *	along any axis still results in 32767.
> + *
> + *	In order to provide the ability to map inputs to a square axis (used
> + *	by older games), the left_stick_limit and right_stick_limit can be
> + *	set. These limits specify at what point in the raw input coordinates
> + *	an axis is reported to be at maximum value (32767 or -32767).
> + *
> + *	Both the dead zone and stick limit algorithms are implemented
> + *	together as a coordinate transformation from "effective coordinates"
> + *	onto the output coordinates (which have absolute values from 0 to
> + *	32767 and are positive or negative based on direction). Effective
> + *	coordinates are defined as those input values that are greater than
> + *	the dead zone but less than the stick limit on the axis in question.
> + *
> + *	DANGER: All denominator values in division operations MUST be checked
> + *	for non-zero condition. Dividing by zero inside the kernel can cause
> + *	a system deadlock.
> + */
> +
> +static void xpad_process_sticks(struct usb_xpad *xpad, unsigned char *data)
> +{
> +	struct input_dev *dev = xpad->dev;
> +	int coords[4];    /* x, y, rx, ry */
> +	int x_offset, y_offset, rx_offset, ry_offset;
> +	int c;
> +	int range;
> +	int abs_magnitude, adjusted_magnitude, difference, scale_fraction;
> +	int dead_zone[2], stick_limit[2];
> +	
> +	dead_zone[0] = xpad->left_dead_zone;
> +	dead_zone[1] = xpad->right_dead_zone;
> +	stick_limit[0] = xpad->left_stick_limit;
> +	stick_limit[1] = xpad->right_stick_limit;
> +	
> +	if (xpad->xtype == XTYPE_XBOX) {
> +		x_offset = 12;
> +		y_offset = 14;
> +		rx_offset = 16;
> +		ry_offset = 18;
> +	}
> +	else {
> +		x_offset = 6;
> +		y_offset = 8;
> +		rx_offset = 10;
> +		ry_offset = 12;
> +	}
> +	
> +	coords[0] = (__s16) le16_to_cpup((__le16 *)(data + x_offset));
> +	coords[1] = ~(__s16) le16_to_cpup((__le16 *)(data + y_offset));
> +	coords[2] = (__s16) le16_to_cpup((__le16 *)(data + rx_offset));
> +	coords[3] = ~(__s16) le16_to_cpup((__le16 *)(data + ry_offset));
> +	
> +	/* Adjustment for dead zone and square axis */
> +	for (c = 0; c < 4; c++) {
> +		abs_magnitude = (int) coords[c];
> +		if (abs_magnitude < 0)
> +			abs_magnitude = -abs_magnitude;
> +		adjusted_magnitude = abs_magnitude;
> +		
> +		range = (stick_limit[c/2] - dead_zone[c/2]);
> +		
> +		if (abs_magnitude >= stick_limit[c/2]) {
> +			adjusted_magnitude = 32767;
> +		}
> +		else if (abs_magnitude <= dead_zone[c/2]) {
> +			adjusted_magnitude = 0;
> +		}
> +		else if (range > 0) {
> +			difference = 32767 - range;
> +			if (difference) {
> +				/* DIVISION: difference non-zero */
> +				scale_fraction = range / difference;
> +				adjusted_magnitude = abs_magnitude - dead_zone[c/2];
> +				
> +				/* Approximate floating-point division with a
> +				 * "catch-up" scaling algorithm that adds back
> +				 * to the adjusted_magnitude based on distance
> +				 * from the origin (0 in adjusted coordinates).
> +				 * If the range / difference is at least 1,
> +				 * then 1 needs to be added to the adjusted
> +				 * magnitude for every scale_fraction units
> +				 * from the origin. If the range / difference
> +				 * is less than 1 (0 in integer division),
> +				 * then divide the difference by the range to
> +				 * obtain the number of units to add per unit
> +				 * from the adjusted origin.
> +				 */
> +				if (scale_fraction) {
> +					/* DIVISION: scale_fraction non-zero */
> +					adjusted_magnitude += adjusted_magnitude / scale_fraction;
> +				}
> +				else {
> +					/* DIVISION: range non-zero */
> +					scale_fraction = difference / range;
> +					adjusted_magnitude += adjusted_magnitude * scale_fraction;
> +				}
> +				if (adjusted_magnitude > 32767)
> +					adjusted_magnitude = 32767;
> +			}
> +		}
> +		coords[c] = (coords[c] < 0) ? -adjusted_magnitude : adjusted_magnitude;
> +	}
> +	
> +	input_report_abs(dev, ABS_X, (__s16) coords[0]);
> +	input_report_abs(dev, ABS_Y, (__s16) coords[1]);
> +	input_report_abs(dev, ABS_RX, (__s16) coords[2]);
> +	input_report_abs(dev, ABS_RY, (__s16) coords[3]);
> +}
>  
> -	int dpad_mapping;		/* map d-pad to buttons or to axes */
> -	int xtype;			/* type of xbox device */
> -};
>  
>  /*
>   *	xpad_process_packet
> @@ -256,18 +342,9 @@
>  static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
>  {
>  	struct input_dev *dev = xpad->dev;
> -
> -	/* left stick */
> -	input_report_abs(dev, ABS_X,
> -			 (__s16) le16_to_cpup((__le16 *)(data + 12)));
> -	input_report_abs(dev, ABS_Y,
> -			 ~(__s16) le16_to_cpup((__le16 *)(data + 14)));
> -
> -	/* right stick */
> -	input_report_abs(dev, ABS_RX,
> -			 (__s16) le16_to_cpup((__le16 *)(data + 16)));
> -	input_report_abs(dev, ABS_RY,
> -			 ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
> +	
> +	/* left and right sticks */
> +	xpad_process_sticks(xpad, data);
>  
>  	/* triggers left/right */
>  	input_report_abs(dev, ABS_Z, data[10]);
> @@ -305,6 +382,7 @@
>  	input_sync(dev);
>  }
>  
> +
>  /*
>   *	xpad360_process_packet
>   *
> @@ -350,18 +428,9 @@
>  	input_report_key(dev, BTN_TL,	data[3] & 0x01);
>  	input_report_key(dev, BTN_TR,	data[3] & 0x02);
>  	input_report_key(dev, BTN_MODE,	data[3] & 0x04);
> -
> -	/* left stick */
> -	input_report_abs(dev, ABS_X,
> -			 (__s16) le16_to_cpup((__le16 *)(data + 6)));
> -	input_report_abs(dev, ABS_Y,
> -			 ~(__s16) le16_to_cpup((__le16 *)(data + 8)));
> -
> -	/* right stick */
> -	input_report_abs(dev, ABS_RX,
> -			 (__s16) le16_to_cpup((__le16 *)(data + 10)));
> -	input_report_abs(dev, ABS_RY,
> -			 ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
> +	
> +	/* left and right sticks */
> +	xpad_process_sticks(xpad, data);
>  
>  	/* triggers left/right */
>  	input_report_abs(dev, ABS_Z, data[4]);
> @@ -370,6 +439,33 @@
>  	input_sync(dev);
>  }
>  
> +
> +static void xpad360w_identify_controller(struct usb_xpad *xpad, unsigned char *data)
> +{
> +	u32 id;
> +	int i;
> +	
> +	snprintf(xpad->controller_unique_id, 17,
> +		"%02x%02x%02x%02x%02x%02x%02x%02x",
> +		data[8], data[9], data[10], data[11], data[12], data[13],
> +		data[14], data[15]);
> +			
> +	/* Identify controller type */
> +	id = (u32) *(data + 22);
> +	xpad->controller_type = XCONTROLLER_TYPE_OTHER;
> +	for (i = 0; w360_id[i].id_bytes; i++) {
> +		if (id == w360_id[i].id_bytes) {
> +			xpad->controller_type =
> +				w360_id[i].controller_type;
> +			break;
> +		}
> +	}
> +	
> +	if (id == XCONTROLLER_TYPE_OTHER)
> +		printk(KERN_INFO "xpad: unknown wireless controller type: %08x\n", id);
> +}
> +
> +
>  /*
>   * xpad360w_process_packet
>   *
> @@ -379,6 +475,7 @@
>   * Byte.Bit
>   * 00.1 - Status change: The controller or headset has connected/disconnected
>   *                       Bits 01.7 and 01.6 are valid
> + * 01.f - Some kind of unique identifier message (see above)
>   * 01.7 - Controller present
>   * 01.6 - Headset present
>   * 01.1 - Pad state (Bytes 4+) valid
> @@ -387,22 +484,53 @@
>  
>  static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
>  {
> -	/* Presence change */
> +	int padnum = 0;
> +
> +	/* Presence change */	
>  	if (data[0] & 0x08) {
> +		padnum = xpad->controller_number;
>  		if (data[1] & 0x80) {
> -			xpad->pad_present = 1;
> -			usb_submit_urb(xpad->bulk_out, GFP_ATOMIC);
> -		} else
> -			xpad->pad_present = 0;
> +			/* ignore duplicates */
> +			if (!xpad->controller_present) {
> +				xpad->controller_present = 1;
> +				
> +				if (xpad->work_pending)
> +					PREPARE_WORK(&xpad->work, &xpad_work_controller);
> +				else
> +					INIT_WORK(&xpad->work, &xpad_work_controller);
> +				xpad->work_pending = 1;
> +				schedule_work(&xpad->work);
> +				kobject_uevent(&xpad->dev->dev.kobj, KOBJ_ONLINE);
> +			}
> +		}
> +		else {
> +			kobject_uevent(&xpad->dev->dev.kobj, KOBJ_OFFLINE);
> +			xpad->controller_present = 0;
> +			xpad->controller_unique_id[0] = '\0';
> +			xpad->controller_type = XCONTROLLER_TYPE_NONE;
> +			/* We do NOT flush the shared workqueue here, because
> +			 * this function is called from an interrupt handler.
> +			 * If the controller has disconnected from the receiver,
> +			 * the worst that will happen from the work task running
> +			 * is that a packet will be transmitted from the
> +			 * receiver to a non-listening controller
> +			 */
> +		}
>  	}
>  
> -	/* Valid pad data */
> -	if (!(data[1] & 0x1))
> -		return;
> -
> -	xpad360_process_packet(xpad, cmd, &data[4]);
> +	/* Process packets according to type */
> +	if (data[1] == 0x0f) {
> +		if (! xpad->controller_unique_id[0]) {
> +			xpad360w_identify_controller(xpad, data);
> +			xpad_init_controller(xpad);
> +		}
> +	}
> +	else if (data[1] & 0x1) {
> +		xpad360_process_packet(xpad, cmd, &data[4]);
> +	}
>  }
>  
> +
>  static void xpad_irq_in(struct urb *urb)
>  {
>  	struct usb_xpad *xpad = urb->context;
> @@ -445,24 +573,16 @@
>  		     __func__, retval);
>  }
>  
> -static void xpad_bulk_out(struct urb *urb)
> -{
> -	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", __func__, urb->status);
> -		break;
> -	default:
> -		dbg("%s - nonzero urb status received: %d", __func__, urb->status);
> -	}
> -}
>  
> +/* end input section */
> +
> +/*****************************************************************************/
> +/* IRQ output section: present in object code only if the force feedback or
> + * LED interface is enabled.
> + */
> + 
>  #if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
> +
>  static void xpad_irq_out(struct urb *urb)
>  {
>  	int retval, status;
> @@ -493,12 +613,13 @@
>  		    __func__, retval);
>  }
>  
> +
>  static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
>  {
>  	struct usb_endpoint_descriptor *ep_irq_out;
>  	int error = -ENOMEM;
>  
> -	if (xpad->xtype != XTYPE_XBOX360)
> +	if ((xpad->xtype != XTYPE_XBOX360) && (xpad->xtype != XTYPE_XBOX360W))
>  		return 0;
>  
>  	xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
> @@ -526,45 +647,82 @@
>   fail1:	return error;
>  }
>  
> +
>  static void xpad_stop_output(struct usb_xpad *xpad)
>  {
> -	if (xpad->xtype == XTYPE_XBOX360)
> +	if ((xpad->xtype == XTYPE_XBOX360) || (xpad->xtype == XTYPE_XBOX360W))
>  		usb_kill_urb(xpad->irq_out);
>  }
>  
> +
>  static void xpad_deinit_output(struct usb_xpad *xpad)
>  {
> -	if (xpad->xtype == XTYPE_XBOX360) {
> +	if ((xpad->xtype == XTYPE_XBOX360) || (xpad->xtype == XTYPE_XBOX360W)) {
>  		usb_free_urb(xpad->irq_out);
>  		usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
>  				xpad->odata, xpad->odata_dma);
>  	}
>  }
> +
>  #else
> +/* Dummy implementations for xpad_probe and xpad_disconnect */
>  static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
>  static void xpad_deinit_output(struct usb_xpad *xpad) {}
>  static void xpad_stop_output(struct usb_xpad *xpad) {}
>  #endif
>  
> -#ifdef CONFIG_JOYSTICK_XPAD_FF
> +/* end output section */
> +
> +/*****************************************************************************/
> +
> +/* Force feedback (rumble effect) section, depends on CONFIG_JOYSTICK_XPAD_FF */
> +
> +#if defined(CONFIG_JOYSTICK_XPAD_FF)
> +
> +/* Rumble support for wireless controllers follows protocol description
> + * from xboxdrv userspace driver:
> + *       http://pingus.seul.org/~grumbel/xboxdrv/
> + */
>  static int xpad_play_effect(struct input_dev *dev, void *data,
>  			    struct ff_effect *effect)
>  {
>  	struct usb_xpad *xpad = input_get_drvdata(dev);
> +	
> +	if (! xpad->rumble_enable)
> +		return 0;
>  
>  	if (effect->type == FF_RUMBLE) {
>  		__u16 strong = effect->u.rumble.strong_magnitude;
>  		__u16 weak = effect->u.rumble.weak_magnitude;
> -		xpad->odata[0] = 0x00;
> -		xpad->odata[1] = 0x08;
> -		xpad->odata[2] = 0x00;
> -		xpad->odata[3] = strong / 256;
> -		xpad->odata[4] = weak / 256;
> -		xpad->odata[5] = 0x00;
> -		xpad->odata[6] = 0x00;
> -		xpad->odata[7] = 0x00;
> -		xpad->irq_out->transfer_buffer_length = 8;
> +		mutex_lock(&xpad->odata_mutex);
> +		if (xpad->xtype == XTYPE_XBOX360W) {
> +			xpad->odata[0] = 0x00;
> +			xpad->odata[1] = 0x01;
> +			xpad->odata[2] = 0x0f;
> +			xpad->odata[3] = 0xc0;
> +			xpad->odata[4] = 0x00;
> +			xpad->odata[5] = strong / 256;
> +			xpad->odata[6] = weak / 256;
> +			xpad->odata[7] = 0x00;
> +			xpad->odata[8] = 0x00;
> +			xpad->odata[9] = 0x00;
> +			xpad->odata[10] = 0x00;
> +			xpad->odata[11] = 0x00;
> +			xpad->irq_out->transfer_buffer_length = 12;
> +		}
> +		else {
> +			xpad->odata[0] = 0x00;
> +			xpad->odata[1] = 0x08;
> +			xpad->odata[2] = 0x00;
> +			xpad->odata[3] = strong / 256;
> +			xpad->odata[4] = weak / 256;
> +			xpad->odata[5] = 0x00;
> +			xpad->odata[6] = 0x00;
> +			xpad->odata[7] = 0x00;
> +			xpad->irq_out->transfer_buffer_length = 8;
> +		}
>  		usb_submit_urb(xpad->irq_out, GFP_KERNEL);
> +		mutex_unlock(&xpad->odata_mutex);
>  	}
>  
>  	return 0;
> @@ -572,7 +730,7 @@
>  
>  static int xpad_init_ff(struct usb_xpad *xpad)
>  {
> -	if (xpad->xtype != XTYPE_XBOX360)
> +	if ((xpad->xtype != XTYPE_XBOX360) && (xpad->xtype != XTYPE_XBOX360W))
>  		return 0;
>  
>  	input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
> @@ -581,26 +739,50 @@
>  }
>  
>  #else
> +/* dummy implementation for xpad_probe */
>  static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
>  #endif
>  
> +
> +/* end force feedback section */
> +
> +/*****************************************************************************/
> +
> +/* LED handling section: provides support for the ring of LEDs on the 360
> + * controllers. */
> +
>  #if defined(CONFIG_JOYSTICK_XPAD_LEDS)
> -#include <linux/leds.h>
>  
> -struct xpad_led {
> -	char name[16];
> -	struct led_classdev led_cdev;
> -	struct usb_xpad *xpad;
> -};
>  
> +/* XBox 360 wireless controller follows protocol from xboxdrv userspace
> + * driver:
> + *    http://pingus.seul.org/~grumbel/xboxdrv/
> + */
>  static void xpad_send_led_command(struct usb_xpad *xpad, int command)
>  {
>  	if (command >= 0 && command < 14) {
>  		mutex_lock(&xpad->odata_mutex);
> -		xpad->odata[0] = 0x01;
> -		xpad->odata[1] = 0x03;
> -		xpad->odata[2] = command;
> -		xpad->irq_out->transfer_buffer_length = 3;
> +		if (xpad->xtype == XTYPE_XBOX360W) {
> +			xpad->odata[0] = 0x00;
> +			xpad->odata[1] = 0x00;
> +			xpad->odata[2] = 0x08;
> +			xpad->odata[3] = 0x40 + (command % 0x0e);
> +			xpad->odata[4] = 0x00;
> +			xpad->odata[5] = 0x00;
> +			xpad->odata[6] = 0x00;
> +			xpad->odata[7] = 0x00;
> +			xpad->odata[8] = 0x00;
> +			xpad->odata[9] = 0x00;
> +			xpad->odata[10] = 0x00;
> +			xpad->odata[11] = 0x00;
> +			xpad->irq_out->transfer_buffer_length = 12;
> +		}
> +		else {
> +			xpad->odata[0] = 0x01;
> +			xpad->odata[1] = 0x03;
> +			xpad->odata[2] = command;
> +			xpad->irq_out->transfer_buffer_length = 3;
> +		}
>  		usb_submit_urb(xpad->irq_out, GFP_KERNEL);
>  		mutex_unlock(&xpad->odata_mutex);
>  	}
> @@ -615,6 +797,7 @@
>  	xpad_send_led_command(xpad_led->xpad, value);
>  }
>  
> +
>  static int xpad_led_probe(struct usb_xpad *xpad)
>  {
>  	static atomic_t led_seq	= ATOMIC_INIT(0);
> @@ -623,7 +806,7 @@
>  	struct led_classdev *led_cdev;
>  	int error;
>  
> -	if (xpad->xtype != XTYPE_XBOX360)
> +	if ((xpad->xtype != XTYPE_XBOX360) && (xpad->xtype != XTYPE_XBOX360W))
>  		return 0;
>  
>  	xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL);
> @@ -664,10 +847,16 @@
>  	}
>  }
>  #else
> +/* dummies for xpad_probe and xpad_disconnect */
>  static int xpad_led_probe(struct usb_xpad *xpad) { return 0; }
>  static void xpad_led_disconnect(struct usb_xpad *xpad) { }
>  #endif
>  
> +/* end LED section */
> +
> +/*****************************************************************************/
> +
> +/* Module and device functions */
>  
>  static int xpad_open(struct input_dev *dev)
>  {
> @@ -721,6 +910,7 @@
>  	struct usb_xpad *xpad;
>  	struct input_dev *input_dev;
>  	struct usb_endpoint_descriptor *ep_irq_in;
> +	int controller_type;
>  	int i;
>  	int error = -ENOMEM;
>  
> @@ -747,6 +937,7 @@
>  	xpad->udev = udev;
>  	xpad->dpad_mapping = xpad_device[i].dpad_mapping;
>  	xpad->xtype = xpad_device[i].xtype;
> +	controller_type = xpad_device[i].controller_type;
>  	if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
>  		xpad->dpad_mapping = !dpad_to_buttons;
>  	if (xpad->xtype == XTYPE_UNKNOWN) {
> @@ -819,6 +1010,10 @@
>  		goto fail4;
>  
>  	usb_set_intfdata(intf, xpad);
> +	
> +	xpad->controller_type = controller_type;
> +	if (controller_type != XCONTROLLER_TYPE_NONE)
> +		xpad_init_controller(xpad);
>  
>  	/*
>  	 * Submit the int URB immediatly rather than waiting for open
> @@ -828,48 +1023,38 @@
>  	 * we're waiting for.
>  	 */
>  	if (xpad->xtype == XTYPE_XBOX360W) {
> +		xpad->controller_present = 0;
> +		xpad->controller_unique_id[0] = '\0';
> +		xpad->controller_number =
> +			(intf->cur_altsetting->desc.bInterfaceNumber / 2) + 1;
>  		xpad->irq_in->dev = xpad->udev;
>  		error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
>  		if (error)
> -			goto fail4;
> -
> -		/*
> -		 * Setup the message to set the LEDs on the
> -		 * controller when it shows up
> -		 */
> -		xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL);
> -		if(!xpad->bulk_out)
>  			goto fail5;
> -
> -		xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL);
> -		if(!xpad->bdata)
> -			goto fail6;
> -
> -		xpad->bdata[2] = 0x08;
> -		switch (intf->cur_altsetting->desc.bInterfaceNumber) {
> -		case 0:
> -			xpad->bdata[3] = 0x42;
> -			break;
> -		case 2:
> -			xpad->bdata[3] = 0x43;
> -			break;
> -		case 4:
> -			xpad->bdata[3] = 0x44;
> -			break;
> -		case 6:
> -			xpad->bdata[3] = 0x45;
> -		}
> -
> -		ep_irq_in = &intf->cur_altsetting->endpoint[1].desc;
> -		usb_fill_bulk_urb(xpad->bulk_out, udev,
> -				usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress),
> -				xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad);
>  	}
> +	else {
> +		xpad->controller_present = 1;
> +		strncpy(xpad->controller_unique_id, "wired", 17);
> +		xpad->controller_number = 0;
> +	}
> +	
> +	/* Set up device attributes */
> +#ifdef CONFIG_SYSFS
> +	xpad->sysfs_ok = 1;
> +	error = sysfs_create_group(&input_dev->dev.kobj, &xpad_default_attr_group);
> +	if (error) {
> +		/* Driver will work without the sysfs interface, but parameters
> +		 * will not be adjustable, so this failure is a warning. */
> +		printk(KERN_WARNING "xpad: sysfs_create_group failed with error %d\n", error);
> +		xpad->sysfs_ok = 0;
> +	}
> +#endif


No need to check for CONFIG_SYSFS, sysfs_create_group will be a no-op which returns 0
if not built.


>  
>  	return 0;
>  
> - fail6:	usb_free_urb(xpad->bulk_out);
> - fail5:	usb_kill_urb(xpad->irq_in);
> + fail5: usb_set_intfdata(intf, NULL);
> + 	input_unregister_device(xpad->dev);
> + 	xpad_led_disconnect(xpad);
>   fail4:	usb_free_urb(xpad->irq_in);
>   fail3:	xpad_deinit_output(xpad);
>   fail2:	usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
> @@ -885,12 +1070,19 @@
>  
>  	usb_set_intfdata(intf, NULL);
>  	if (xpad) {
> +		/* If a work task remains, get rid of it by flushing the
> +		 * shared work queue.
> +		 */
> +		if (xpad->work_pending)
> +			flush_scheduled_work();
> +#ifdef CONFIG_SYSFS
> +		if (xpad->sysfs_ok)
> +			sysfs_remove_group(&xpad->dev->dev.kobj, &xpad_default_attr_group);
> +#endif


Ditto.


>  		xpad_led_disconnect(xpad);
>  		input_unregister_device(xpad->dev);
>  		xpad_deinit_output(xpad);
>  		if (xpad->xtype == XTYPE_XBOX360W) {
> -			usb_kill_urb(xpad->bulk_out);
> -			usb_free_urb(xpad->bulk_out);
>  			usb_kill_urb(xpad->irq_in);
>  		}
>  		usb_free_urb(xpad->irq_in);
> @@ -900,12 +1092,7 @@
>  	}
>  }
>  
> -static struct usb_driver xpad_driver = {
> -	.name		= "xpad",
> -	.probe		= xpad_probe,
> -	.disconnect	= xpad_disconnect,
> -	.id_table	= xpad_table,
> -};
> +
>  
>  static int __init usb_xpad_init(void)
>  {
> @@ -920,9 +1107,4 @@
>  	usb_deregister(&xpad_driver);
>  }
>  
> -module_init(usb_xpad_init);
> -module_exit(usb_xpad_exit);
>  
> -MODULE_AUTHOR(DRIVER_AUTHOR);
> -MODULE_DESCRIPTION(DRIVER_DESC);
> -MODULE_LICENSE("GPL");
> diff -uNr origdrv/drivers/input/joystick/xpad.h newdrv/drivers/input/joystick/xpad.h
> --- origdrv/drivers/input/joystick/xpad.h	1969-12-31 19:00:00.000000000 -0500
> +++ newdrv/drivers/input/joystick/xpad.h	2009-02-21 23:49:36.000000000 -0500
> @@ -0,0 +1,578 @@
> +/*
> + * Xbox gamepad driver with Xbox 360 wired/wireless support
> + *
> + * Last Modified:	21 February 2009
> + *			Mike Murphy <mamurph@xxxxxxxxxxxxxx>
> + *
> + * Copyright (c) 2002 Marko Friedemann <mfr@xxxxxxxxxxxxxxx>
> + *               2004 Oliver Schwartz <Oliver.Schwartz@xxxxxx>,
> + *                    Steven Toth <steve@xxxxxxxxxxxxxxxx>,
> + *                    Franz Lehner <franz@xxxxxxx>,
> + *                    Ivan Hawkes <blackhawk@xxxxxxxxxxxxxx>
> + *               2005 Dominic Cerquetti <binary1230@xxxxxxxxx>
> + *               2006 Adam Buchbinder <adam.buchbinder@xxxxxxxxx>
> + *               2007 Jan Kratochvil <honza@xxxxxxxx>
> + *               2009 Clemson University
> + *		      (contact: Mike Murphy <mamurph@xxxxxxxxxxxxxx>)
> + *
> + * 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:
> + *  - information from     http://euc.jp/periphs/xbox-controller.ja.html
> + *  - the iForce driver    drivers/char/joystick/iforce.c
> + *  - the skeleton-driver  drivers/usb/usb-skeleton.c
> + *  - Xbox 360 information http://www.free60.org/wiki/Gamepad
> + *  - xboxdrv docs         http://pingus.seul.org/~grumbel/xboxdrv/
> + *
> + * Thanks to:
> + *  - ITO Takayuki for providing essential xpad information on his website
> + *  - Vojtech Pavlik     - iforce driver / input subsystem
> + *  - Greg Kroah-Hartman - usb-skeleton driver
> + *  - XBOX Linux project - extra USB id's
> + *
> + * TODO:
> + *  - fix "analog" buttons (reported as digital now)
> + *  - need USB IDs for other dance pads
> + *
> + * Driver history is located at the bottom of this file.
> + */
> +
> +#ifndef _XPAD_H
> +#define _XPAD_H
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/stat.h>
> +#include <linux/module.h>
> +#include <linux/usb/input.h>
> +#include <linux/workqueue.h>
> +
> +#if defined(CONFIG_SYSFS)
> +#include <linux/kobject.h>
> +#include <linux/sysfs.h>
> +#include <linux/string.h>
> +#endif


Same here, conditionally including these files is not necessary.


> +
> +#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
> +#include <linux/leds.h>
> +
> +struct xpad_led {
> +	char name[16];
> +	struct led_classdev led_cdev;
> +	struct usb_xpad *xpad;
> +};
> +#endif
> +


Ditto. Actually it's useful for data which consume memory,
or fields inside structures, but not for types themselves.

But well, these parts are a removing, not new code.

Anyway, looks like a nice work.


Frederic.


> +#define DRIVER_AUTHOR "Marko Friedemann <mfr@xxxxxxxxxxxxxxx>"
> +#define DRIVER_DESC "Xbox/360 pad driver"
> +
> +#define XPAD_PKT_LEN 32
> +
> +
> +/* xbox d-pads should map to buttons, as is required for DDR pads
> +   but we map them to axes when possible to simplify things */
> +#define MAP_DPAD_TO_BUTTONS    0
> +#define MAP_DPAD_TO_AXES       1
> +#define MAP_DPAD_UNKNOWN       2
> +
> +/* Type of controller *interface* (original, wired 360, wireless 360) */
> +#define XTYPE_XBOX        0
> +#define XTYPE_XBOX360     1
> +#define XTYPE_XBOX360W    2
> +#define XTYPE_UNKNOWN     3
> +
> +/* Type of controller (e.g. pad, guitar, other input device) */
> +#define XCONTROLLER_TYPE_NONE		0
> +#define XCONTROLLER_TYPE_PAD		1
> +#define XCONTROLLER_TYPE_GUITAR		2
> +#define XCONTROLLER_TYPE_DANCE_PAD	3
> +#define XCONTROLLER_TYPE_OTHER		255
> +
> +
> +/* The Xbox 360 controllers have sensitive sticks that often do not center
> + * exactly. A dead zone causes stick events below a certain threshhold to be
> + * reported as zero.
> + *
> + * The default dead zone size is 8192, which was obtained by testing a
> + * wireless 360 controller with jstest(1) and consulting gaming forums for
> + * a recommended dead zone for this controller. The consensus opinion was
> + * 0.25 (on a scale from 0 to 1), which corresponds to 8192 (out of 32767).
> + */
> +#define XDEAD_ZONE_DEFAULT   8192
> +
> +/* Default limit for the sticks is the maximum axis value (32767), which will
> + * cause the sticks to have a radial axis as designed in the hardware. To
> + * enable square axis support, set the stick limits to 23170 or lower at run
> + * time via the sysfs interface. */
> +#define XSTICK_LIMIT_DEFAULT 32767
> +
> +/* Rumble normally enabled */
> +#define XRUMBLE_DEFAULT		1
> +
> +
> +/* This module parameter is something of a relic, but it remains for
> + * compatibility. Importantly, the option to map the D-PAD buttons applies
> + * only to controller *interfaces* (i.e. vendor and product codes) not
> + * explicitly present in xpad_device[]. */
> +static int dpad_to_buttons = 0;
> +module_param(dpad_to_buttons, bool, S_IRUGO);
> +MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
> +
> +
> +/* Table of various device interfaces recognized by this driver. Each supported
> + * device has a directional pad mapping, interface type, and controller type.
> + * Note that wireless 360 devices have XCONTROLLER_TYPE_NONE, as the actual
> + * type of the gaming controller is not known until the controller binds
> + * wirelessly with the receiver
> + */
> +static const struct xpad_device {
> +	u16 idVendor;
> +	u16 idProduct;
> +	char *name;
> +	u8 dpad_mapping;
> +	u8 xtype;
> +	u8 controller_type;
> +} xpad_device[] = {
> +	{ 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W,
> +		XCONTROLLER_TYPE_NONE },
> +	{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_DANCE_PAD },
> +	{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES,
> +		XTYPE_XBOX, XCONTROLLER_TYPE_PAD },
> +	{ 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_DANCE_PAD },
> +	{ 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_DANCE_PAD },
> +	{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0c12, 0x880a, "Pelican Eclipse PL-2023", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", MAP_DPAD_TO_AXES,
> +		XTYPE_XBOX360, XCONTROLLER_TYPE_PAD },
> +	{ 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_DANCE_PAD },
> +	{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360,
> +		XCONTROLLER_TYPE_GUITAR },
> +	{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_DANCE_PAD },
> +	{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX,
> +		XCONTROLLER_TYPE_PAD },
> +	{ 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN,
> +		XCONTROLLER_TYPE_PAD }
> +};
> +
> +
> +/* buttons shared with xbox and xbox360 */
> +static const signed short xpad_common_btn[] = {
> +	BTN_A, BTN_B, BTN_X, BTN_Y,			/* "analog" buttons */
> +	BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
> +	-1						/* terminating entry */
> +};
> +
> +/* original xbox controllers only */
> +static const signed short xpad_btn[] = {
> +	BTN_C, BTN_Z,		/* "analog" buttons */
> +	-1			/* terminating entry */
> +};
> +
> +/* only used if MAP_DPAD_TO_BUTTONS */
> +static const signed short xpad_btn_pad[] = {
> +	BTN_LEFT, BTN_RIGHT,		/* d-pad left, right */
> +	BTN_0, BTN_1,			/* d-pad up, down (XXX names??) */
> +	-1				/* terminating entry */
> +};
> +
> +/* buttons for x360 controller */
> +static const signed short xpad360_btn[] = {
> +	BTN_TL, BTN_TR,		/* Button LB/RB */
> +	BTN_MODE,		/* The big X button */
> +	-1
> +};
> +
> +/* sticks and triggers common to all devices */
> +static const signed short xpad_abs[] = {
> +	ABS_X, ABS_Y,		/* left stick */
> +	ABS_RX, ABS_RY,		/* right stick */
> +	ABS_Z, ABS_RZ,		/* triggers left/right */
> +	-1			/* terminating entry */
> +};
> +
> +/* only used if MAP_DPAD_TO_AXES */
> +static const signed short xpad_abs_pad[] = {
> +	ABS_HAT0X, ABS_HAT0Y,	/* d-pad axes */
> +	-1			/* terminating entry */
> +};
> +
> +
> +/* 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. */
> +#define XPAD_XBOX360_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 XPAD_XBOX360_VENDOR(vend) \
> +	{ XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \
> +	{ XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) }
> +
> +static struct usb_device_id xpad_table [] = {
> +	{ USB_INTERFACE_INFO('X', 'B', 0) },	/* X-Box USB-IF not approved class */
> +	XPAD_XBOX360_VENDOR(0x045e),		/* Microsoft X-Box 360 controllers */
> +	XPAD_XBOX360_VENDOR(0x046d),		/* Logitech X-Box 360 style controllers */
> +	XPAD_XBOX360_VENDOR(0x0738),		/* Mad Catz X-Box 360 controllers */
> +	XPAD_XBOX360_VENDOR(0x0e6f),		/* 0x0e6f X-Box 360 controllers */
> +	XPAD_XBOX360_VENDOR(0x1430),		/* RedOctane X-Box 360 controllers */
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE (usb, xpad_table);
> +
> +
> +/* Wireless 360 device identification.
> + *
> + * When a wireless controller connects, the 2nd packet it sends SEEMS to
> + * be some kind of unique controller identification message. Using usbmon
> + * (see Documentation/usb/usbmon.txt), I tried 4 gamepads and a guitar, and
> + * I collected the following 5 ID packets from the 5 devices:
> + *
> + * 000f00f0 00ccfd27 0060e226 63700010 13e3201d 30034001 5001ffff ff
> + * 000f00f0 f0ccfd27 0060d8c4 e9600009 13e7201d 30034001 5001ffff ff
> + * 000f00f0 00ccfd27 0060578b 82f00010 13e3201d 30034001 5001ffff ff
> + * 000f00f0 f0ccfd27 0060da1c b1500009 13e7201d 30034001 5001ffff ff
> + * 000f00f0 f0ccfd27 006002d1 71d10000 13e3201d 30034430 5107ffff ff
> + *
> + * From this trace data, I concocted the following (potentially incorrect)
> + * scheme for detecting type and unique ID:
> + *
> + * ******** xx****xx xxxxxxxx xxxx**xx **xx**** ****tttt tttt**** **
> + *                |  unique id |                    |  type |
> + *
> + * It appears that some of the bytes in the first half of the message, noted
> + * above as "unique id" are some sort of serial number, though I cannot work
> + * out any correspondence between these bytes and the serial number printed
> + * under the battery pack. Many of the bytes in this possibly unique field
> + * are not unique across my controllers, and may not in fact be part of the
> + * controller's unique identification, but I figured it was better to have
> + * extra bytes on either end of the unique byte string instead of the
> + * alternative. In addition, the packet appears to indicate the type of
> + * the controller toward the end: the pads all send 4001 5001, while the
> + * guitar sends 4430 5107.
> + *
> + * Further testing over a wider variety of devices is probably needed to
> + * determine if changes need to be made to this scheme.
> + */
> +static const struct w360_id {
> +	u32 id_bytes;
> +	u8 controller_type;
> +} w360_id[] = {
> +	{ 0x40015001, XCONTROLLER_TYPE_PAD },
> +	{ 0x44305107, XCONTROLLER_TYPE_GUITAR },
> +	{ 0x00000000, XCONTROLLER_TYPE_NONE }
> +};
> +
> +
> +/* Some of the fields in the following structure are for later use with
> + * userspace applications to recognize individual controllers. The dead zones
> + * and axis limits can be changed "on the fly" and are effective immediately.
> + *
> + * The fields labeled "ro" and "rw" are intended to be read-only and
> + * read-write, respectively, when exposed in sysfs. Most of the read-only
> + * fields are to support *wireless* 360 controllers. The controller_number
> + * is used to set the LED, while controller_present tracks whether the
> + * controller is connected to the wireless receiver. Controller type applies
> + * to all models (wired and wireless), and tracks whether the device is a pad,
> + * guitar, etc. for later userspace use. See the comment above regarding
> + * type and unique ID detection on wireless 360 receivers.
> + */
> +struct usb_xpad {
> +	struct input_dev *dev;		/* input device interface */
> +	struct usb_device *udev;	/* usb device */
> +
> +	struct urb *irq_in;		/* urb for interrupt in report */
> +	unsigned char *idata;		/* input data */
> +	dma_addr_t idata_dma;
> +
> +#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
> +	struct urb *irq_out;		/* urb for interrupt out report */
> +	unsigned char *odata;		/* output data */
> +	dma_addr_t odata_dma;
> +	struct mutex odata_mutex;
> +#endif
> +
> +#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
> +	struct xpad_led *led;
> +#endif
> +
> +	char phys[64];			/* physical device path */
> +
> +	int dpad_mapping;		/* map d-pad to buttons or to axes */
> +	int xtype;			/* type of xbox device */
> +	
> +	/* Work structure for moving the call to xpad_send_led_command
> +	 * outside the interrupt handler for packet processing */
> +	struct work_struct work;
> +	int work_pending;
> +	
> +	int controller_number;		/* controller number (1-4) for 360w. ro */
> +	int controller_present;         /* 360w controller presence detection. ro */
> +	int controller_type;            /* controller type. ro */
> +	char controller_unique_id[17];  /* unique ID of controller (360w). ro */
> +	unsigned int left_dead_zone;    /* dead zone for left stick. rw */
> +	unsigned int right_dead_zone;   /* dead zone for right stick. rw */
> +	unsigned int left_stick_limit;  /* stick axis limit for left stick. rw */
> +	unsigned int right_stick_limit; /* stick axis limit for right stick. rw */
> +	int rumble_enable;              /* enable/disable rumble. rw */
> +	
> +#if defined(CONFIG_SYSFS)
> +	int sysfs_ok;                   /* sysfs interface OK */
> +#endif
> +};
> +#define to_xpad(d) input_get_drvdata(to_input_dev(d))
> +
> +
> +/* Function prototypes for non-sysfs interface functions */
> +static void set_dead_zone(unsigned int new_size, unsigned int *dz, unsigned int stick_limit);
> +static void set_stick_limit(unsigned int new_size, unsigned int *sl, unsigned int dead_zone);
> +static void xpad_init_controller(struct usb_xpad *xpad);
> +static void xpad_send_led_command(struct usb_xpad *xpad, int command);
> +static void xpad_work_controller(struct work_struct *w);
> +static void xpad_process_sticks(struct usb_xpad *xpad, unsigned char *data);
> +static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data);
> +static void xpad360_process_packet(struct usb_xpad *xpad,
> +				   u16 cmd, unsigned char *data);
> +static void xpad360w_identify_controller(struct usb_xpad *xpad, unsigned char *data);
> +static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data);
> +static void xpad_irq_in(struct urb *urb);
> +static void xpad_irq_out(struct urb *urb);
> +static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad);
> +static void xpad_stop_output(struct usb_xpad *xpad);
> +static void xpad_stop_output(struct usb_xpad *xpad);
> +static int xpad_play_effect(struct input_dev *dev, void *data,
> +			    struct ff_effect *effect);
> +static int xpad_init_ff(struct usb_xpad *xpad);
> +static void xpad_send_led_command(struct usb_xpad *xpad, int command);
> +static void xpad_led_set(struct led_classdev *led_cdev, enum led_brightness value);
> +static int xpad_led_probe(struct usb_xpad *xpad);
> +static void xpad_led_disconnect(struct usb_xpad *xpad);
> +static int xpad_open(struct input_dev *dev);
> +static void xpad_close(struct input_dev *dev);
> +static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs);
> +static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id);
> +static void xpad_disconnect(struct usb_interface *intf);
> +static int __init usb_xpad_init(void);
> +static void __exit usb_xpad_exit(void);
> +
> +
> +/* sysfs interface */
> +#if defined(CONFIG_SYSFS)
> +static ssize_t xpad_show_uint(struct device *dev, struct device_attribute *attr,
> +		char *buf);
> +static ssize_t xpad_store_uint(struct device *dev,
> +		struct device_attribute *attr, const char *buf, size_t count);
> +static ssize_t xpad_store_rumble_enable(struct device *dev,
> +		struct device_attribute *attr, const char *buf, size_t count);
> +static ssize_t xpad_store_ro(struct device *dev, struct device_attribute *attr,
> +		const char *buf, size_t count);
> +static ssize_t xpad_show_int(struct device *dev, struct device_attribute *attr,
> +		char *buf);
> +static ssize_t xpad_show_id(struct device *dev,
> +		struct device_attribute *attr, char *buf);
> +
> +	
> +
> +/* Device attributes */
> +static DEVICE_ATTR(left_dead_zone, 0666, xpad_show_uint, xpad_store_uint);
> +static DEVICE_ATTR(right_dead_zone, 0666, xpad_show_uint, xpad_store_uint);
> +static DEVICE_ATTR(left_stick_limit, 0666, xpad_show_uint, xpad_store_uint);
> +static DEVICE_ATTR(right_stick_limit, 0666, xpad_show_uint, xpad_store_uint);
> +static DEVICE_ATTR(rumble_enable, 0666, xpad_show_int, xpad_store_rumble_enable);
> +static DEVICE_ATTR(controller_number, 0444, xpad_show_int, xpad_store_ro);
> +static DEVICE_ATTR(controller_present, 0444, xpad_show_int, xpad_store_ro);
> +static DEVICE_ATTR(controller_type, 0444, xpad_show_int, xpad_store_ro);
> +static DEVICE_ATTR(id, 0444, xpad_show_id, xpad_store_ro);
> +
> +static struct attribute *xpad_default_attrs[] = {
> +	&dev_attr_left_dead_zone.attr,
> +	&dev_attr_right_dead_zone.attr,
> +	&dev_attr_left_stick_limit.attr,
> +	&dev_attr_right_stick_limit.attr,
> +	&dev_attr_rumble_enable.attr,
> +	&dev_attr_controller_number.attr,
> +	&dev_attr_controller_present.attr,
> +	&dev_attr_controller_type.attr,
> +	&dev_attr_id.attr,
> +	NULL
> +};
> +
> +static struct attribute_group xpad_default_attr_group = {
> +	.attrs = xpad_default_attrs,
> +	.name = "game_device",
> +};
> +#endif
> +
> +
> +static struct usb_driver xpad_driver = {
> +	.name		= "xpad",
> +	.probe		= xpad_probe,
> +	.disconnect	= xpad_disconnect,
> +	.id_table	= xpad_table,
> +};
> +
> +module_init(usb_xpad_init);
> +module_exit(usb_xpad_exit);
> +
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_LICENSE("GPL");
> +
> +#endif
> +
> +/* Driver History:
> + *
> + * 2009-02-21 : Refactored and changed stick handling
> + *  - split code into two pieces (xpad.h and xpad.c)
> + *  - cleaned up sysfs interface
> + *  - changed square axis algorithm to an axis limit algorithm, which allows
> + *    size of inscribed square to be adjusted; available for both sticks
> + *  - dead zones now per-stick
> + *
> + * 2009-02-18 : Changes per mailing list (and some additions)
> + *  - revised sysfs interface (thanks Greg K-H)
> + *  - check return values of sscanf (thanks Oliver Neukum)
> + *  - urb submission while holding mutex now once again GFP_KERNEL (thanks Oliver Neukum)
> + *  - work structure fixes (thanks Oliver Neukum)
> + *  - uevents generated for wireless controller online/offline
> + *  - sysfs interface only if CONFIG_SYSFS is set
> + *
> + * 2009-02-15 : Minor adjustments
> + *  - added KOBJ_ONLINE/KOBJ_OFFLINE events when controllers are connected to
> + *    or disconnected from the wireless 360 receiver
> + *  - ignore duplicate connect messages on the same connection
> + *  - added option to enable/disable rumble on a per-controller basis
> + *  - rumble events are not sent to guitar or dance pad devices
> + *
> + * 2009-02-14 : Added sysfs interface
> + *  - dead zones and square axis settings can now be made per-controller
> + *  - removed dead_zone and square_axis module parameters (use sysfs)
> + *  - new square axis algorithm
> + *
> + * 2009-02-13 : Disable square axis for right stick
> + *  - square axis applies to left stick only
> + *
> + * 2009-02-12 : Scaling for dead zone and square axis support
> + *  - axes now scale from 0 to 32767 starting at edge of dead zone
> + *  - increased default dead zone to 8192
> + *  - initial square axis support (reliable only with left stick)
> + *
> + * 2009-02-07 : More wireless 360 controller fixes
> + *  - removed bulk urb completely
> + *  - use xpad_send_led_command to set controller number on LED display
> + *    (wireless 360 controller)
> + *  - dead_zone is now an adjustable module parameter
> + *
> + * 2009-02-06 : Axis handling improvements
> + *  - unified handler for left and right sticks
> + *  - initial support for dead zones
> + *
> + * 2009-02-02 : Wireless 360 controller fixes
> + *  - followed PROTOCOL description from xboxdrv userspace driver
> + *  - LED and rumble support added for wireless 360 controller (protocol
> + *    is different from wired!)
> + *
> + * 2004-10-02 - 0.0.6 : DDR pad support
> + *  - borrowed from the XBOX linux kernel
> + *  - USB id's for commonly used dance pads are present
> + *  - dance pads will map D-PAD to buttons, not axes
> + *  - pass the module paramater 'dpad_to_buttons' to force
> + *    the D-PAD to map to buttons if your pad is not detected
> + *
> + * 2002-07-17 - 0.0.5 : simplified d-pad handling
> + *
> + * 2002-07-16 - 0.0.4 : minor changes, merge with Vojtech's v0.0.3
> + *  - verified the lack of HID and report descriptors
> + *  - verified that ALL buttons WORK
> + *  - fixed d-pad to axes mapping
> + *
> + * 2002-07-14 - 0.0.3 : rework by Vojtech Pavlik
> + *  - indentation fixes
> + *  - usb + input init sequence fixes
> + *
> + * 2002-07-02 - 0.0.2 : basic working version
> + *  - all axes and 9 of the 10 buttons work (german InterAct device)
> + *  - the black button does not work
> + *
> + * 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller"
> + *
> + */


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