Re: [PATCH] (revision 1) input: xpad.c - Xbox 360 wireless andsysfs support
From: Frederic Weisbecker
Date: Sun Feb 22 2009 - 01:48:34 EST
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-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/