diff -ruN linux-2.6.21.orig/drivers/input/joystick/xpad.c linux-2.6.21/drivers/input/joystick/xpad.c
--- linux-2.6.21.orig/drivers/input/joystick/xpad.c	2007-05-03 23:07:28.000000000 +0200
+++ linux-2.6.21/drivers/input/joystick/xpad.c	2007-05-03 23:07:35.000000000 +0200
@@ -1,5 +1,5 @@
 /*
- * X-Box gamepad - v0.0.6
+ * X-Box gamepad - v0.0.8
  *
  * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
  *               2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>,
@@ -8,6 +8,7 @@
  *                    Ivan Hawkes <blackhawk@ivanhawkes.com>
  *               2005 Dominic Cerquetti <binary1230@yahoo.com>
  *               2006 Adam Buchbinder <adam.buchbinder@gmail.com>
+ *               2007 Miguel Boton <mboton@gmail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -40,6 +41,7 @@
  *  - fix "analog" buttons (reported as digital now)
  *  - get rumble working
  *  - need USB IDs for other dance pads
+ *  - need USB IDs for other 360 controllers
  *
  * History:
  *
@@ -66,6 +68,15 @@
  *  - 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
+ *
+ * 2007-05-03 - 0.0.7 : Xbox 360 controller support
+ *  - added "is360" variable in xpad_device struct to know if connected controller is 360 compatible
+ *
+ * 2007-06-23 - 0.0.8 : Xbox 360 wireless controller support (code from Xbox-Linux project)
+ *  - "is360" variable from xpad_device struct now changed to "type" variable to specify controller type
+ *  - added constants to specify controller type
+ *  - Xbox 360 will map D-PAD to axes
+ *  - more USB id's added for Xbox 360 controllers
  */
 
 #include <linux/kernel.h>
@@ -76,7 +87,7 @@
 #include <linux/moduleparam.h>
 #include <linux/usb/input.h>
 
-#define DRIVER_VERSION "v0.0.6"
+#define DRIVER_VERSION "v0.0.8"
 #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
 #define DRIVER_DESC "X-Box pad driver"
 
@@ -88,6 +99,11 @@
 #define MAP_DPAD_TO_AXES       1
 #define MAP_DPAD_UNKNOWN       -1
 
+/* xbox pads */
+#define GAMEPAD_XBOX               0
+#define GAMEPAD_XBOX360            1
+#define GAMEPAD_XBOX360_WIRELESS   2
+
 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");
@@ -97,45 +113,61 @@
 	u16 idProduct;
 	char *name;
 	u8 dpad_mapping;
+	u8 type;
 } xpad_device[] = {
-	{ 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES },
-	{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES },
-	{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES },
-	{ 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES },
-	{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS },
-	{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES },
-	{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES },
-	{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES },
-	{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES },
-	{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES },
-	{ 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES },
-	{ 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES },
-	{ 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES },
-	{ 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES },
-	{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS },
-	{ 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES },
-	{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS },
-	{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES },
-	{ 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES },
-	{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES },
-	{ 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES },
-	{ 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES},
-	{ 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES },
-	{ 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES },
-	{ 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES },
-	{ 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES },
-	{ 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES },
-	{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES },
-	{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES },
-	{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS },
-	{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS },
-	{ 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES },
-	{ 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN }
+	{ 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x045e, 0x028e, "Microsoft Xbox 360 Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX360 },
+	{ 0x045e, 0x0291, "Microsoft Xbox 360 Wireless Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX360_WIRELESS },
+	{ 0x045e, 0x0719, "Microsoft Xbox 360 Wireless Controller (PC)", MAP_DPAD_TO_AXES, GAMEPAD_XBOX360_WIRELESS },
+	{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, GAMEPAD_XBOX },
+	{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, GAMEPAD_XBOX },
+	{ 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0738, 0x4716, "Mad Catz Xbox 360 Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX360 },
+	{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, GAMEPAD_XBOX },
+	{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, GAMEPAD_XBOX },
+	{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, GAMEPAD_XBOX360 },
+	{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, GAMEPAD_XBOX },
+	{ 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, GAMEPAD_XBOX },
+	{ 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, GAMEPAD_XBOX }
 };
 
 static const signed short xpad_btn[] = {
 	BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,	/* "analog" buttons */
 	BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
+	BTN_TL, BTN_TR,					/* Button LB/RB (360) */
+	BTN_MODE,					/* The big X (360) */
+	-1						/* terminating entry */
+};
+
+static const signed short xpad_btn_360[] = {
+	BTN_A, BTN_B, BTN_X, BTN_Y,			/* "analog" buttons */
+	BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
+	BTN_TL, BTN_TR,					/* Button LB/RB (360) */
+	BTN_MODE,					/* The big X (360) */
 	-1						/* terminating entry */
 };
 
@@ -161,6 +193,10 @@
 
 static struct usb_device_id xpad_table [] = {
 	{ USB_INTERFACE_INFO('X', 'B', 0) },	/* X-Box USB-IF not approved class */
+	{ USB_DEVICE(0x045e, 0x028e) }, /* Xbox 360 */
+	{ USB_DEVICE(0x045e, 0x0291) }, /* Xbox 360 Wireless Controller */
+	{ USB_DEVICE(0x045e, 0x0719) }, /* Xbox 360 Wireless PC Receiver */
+	{ USB_DEVICE(0x1430, 0x4748) }, /* RedOctane Guitar Hero X-plorer */
 	{ }
 };
 
@@ -177,6 +213,10 @@
 	char phys[65];			/* physical device path */
 
 	int dpad_mapping;		/* map d-pad to buttons or to axes */
+
+	u8 is360;			/* is this a Xbox 360 controller */
+	u8 isWireless;			/* is this a Xbox 360 wireless controller */
+	u8 isConnected;			/* is the controller connected */
 };
 
 /*
@@ -194,16 +234,31 @@
 	struct input_dev *dev = xpad->dev;
 
 	/* left stick */
-	input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
-	input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
+	if (xpad->is360) {
+		input_report_abs(dev, ABS_X, (__s16)(((__s16)data[7] << 8) | (__s16)data[6]));
+		input_report_abs(dev, ABS_Y, ~(__s16)(((__s16)data[9] << 8) | data[8]));
+	} else { /* xpad->is360 == FALSE */
+		input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
+		input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
+	}
 
 	/* right stick */
-	input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
-	input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
+	if (xpad->is360) {
+		input_report_abs(dev, ABS_RX, (__s16)(((__s16)data[13] << 8) | (__s16)data[12]));
+		input_report_abs(dev, ABS_RY, (__s16)(((__s16)data[11] << 8) | (__s16)data[10]));
+	} else { /* xpad->is360 == FALSE */
+		input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
+		input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
+	}
 
 	/* triggers left/right */
-	input_report_abs(dev, ABS_Z, data[10]);
-	input_report_abs(dev, ABS_RZ, data[11]);
+	if (xpad->is360) {
+		input_report_abs(dev, ABS_Z, data[4]);
+		input_report_abs(dev, ABS_RZ, data[5]);
+	} else { /* xpad->is360 == FALSE */
+		input_report_abs(dev, ABS_Z, data[10]);
+		input_report_abs(dev, ABS_RZ, data[11]);
+	}
 
 	/* digital pad */
 	if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
@@ -223,14 +278,26 @@
 	input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
 
 	/* "analog" buttons A, B, X, Y */
-	input_report_key(dev, BTN_A, data[4]);
-	input_report_key(dev, BTN_B, data[5]);
-	input_report_key(dev, BTN_X, data[6]);
-	input_report_key(dev, BTN_Y, data[7]);
+	if (xpad->is360) {
+		input_report_key(dev, BTN_A, (data[3] & 0x10) >> 4);
+		input_report_key(dev, BTN_B, (data[3] & 0x20) >> 5);
+		input_report_key(dev, BTN_X, (data[3] & 0x80) >> 7);
+		input_report_key(dev, BTN_Y, (data[3] & 0x40) >> 6);
+		input_report_key(dev, BTN_TL, data[3] & 0x01 );
+		input_report_key(dev, BTN_TR, (data[3] & 0x02) >> 1);
+		input_report_key(dev, BTN_MODE, (data[3] & 0x04) >> 2);
+	} else { /* xpad->is360 == FALSE */
+		input_report_key(dev, BTN_A, data[4]);
+		input_report_key(dev, BTN_B, data[5]);
+		input_report_key(dev, BTN_X, data[6]);
+		input_report_key(dev, BTN_Y, data[7]);
+	}
 
 	/* "analog" buttons black, white */
-	input_report_key(dev, BTN_C, data[8]);
-	input_report_key(dev, BTN_Z, data[9]);
+	if (!xpad->is360) {
+		input_report_key(dev, BTN_C, data[8]);
+		input_report_key(dev, BTN_Z, data[9]);
+	}
 
 	input_sync(dev);
 }
@@ -255,7 +322,20 @@
 		goto exit;
 	}
 
-	xpad_process_packet(xpad, 0, xpad->idata);
+	if (xpad->isWireless) {
+		// connection status message
+		if (urb->actual_length == 2) {
+			if (!xpad->isConnected && xpad->idata[1] == 0x80)
+				xpad->isConnected = true;
+			else if (xpad->isConnected && xpad->idata[1] == 0x00)
+				xpad->isConnected = false;
+			else
+				err("unknown connection status %d", xpad->idata[1]);
+		} else if (urb->actual_length == 29 && xpad->idata[1] == 0x01)
+			xpad_process_packet(xpad, 0, (char*) ((unsigned long) xpad->idata + 4));
+	}
+	else
+		xpad_process_packet(xpad, 0, xpad->idata);
 
 exit:
 	retval = usb_submit_urb (urb, GFP_ATOMIC);
@@ -264,7 +344,7 @@
 		     __FUNCTION__, retval);
 }
 
-static int xpad_open (struct input_dev *dev)
+static int xpad_open(struct input_dev *dev)
 {
 	struct usb_xpad *xpad = input_get_drvdata(dev);
 
@@ -275,7 +355,7 @@
 	return 0;
 }
 
-static void xpad_close (struct input_dev *dev)
+static void xpad_close(struct input_dev *dev)
 {
 	struct usb_xpad *xpad = input_get_drvdata(dev);
 
@@ -310,6 +390,7 @@
 	struct usb_xpad *xpad;
 	struct input_dev *input_dev;
 	struct usb_endpoint_descriptor *ep_irq_in;
+	static const signed short *xpad_buttons;
 	int i;
 	int error = -ENOMEM;
 
@@ -319,6 +400,10 @@
 			break;
 	}
 
+	if ( (xpad_device[i].type == GAMEPAD_XBOX360 && intf->cur_altsetting->desc.bInterfaceProtocol != 1) ||
+             (xpad_device[i].type == GAMEPAD_XBOX360_WIRELESS && intf->cur_altsetting->desc.bInterfaceProtocol != 129) )
+		return -ENODEV;
+
 	xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!xpad || !input_dev)
@@ -335,6 +420,21 @@
 
 	xpad->udev = udev;
 	xpad->dpad_mapping = xpad_device[i].dpad_mapping;
+	xpad->is360 = false;
+	xpad->isWireless = false;
+	xpad->isConnected = true;
+
+	switch(xpad_device[i].type) {
+		case GAMEPAD_XBOX360:
+			xpad->is360 = true;
+			break;
+
+		case GAMEPAD_XBOX360_WIRELESS:
+			xpad->is360 = xpad->isWireless = true;
+			xpad->isConnected = false;
+			break;
+	}
+
 	if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
 		xpad->dpad_mapping = dpad_to_buttons;
 	xpad->dev = input_dev;
@@ -354,8 +454,13 @@
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
 	/* set up buttons */
-	for (i = 0; xpad_btn[i] >= 0; i++)
-		set_bit(xpad_btn[i], input_dev->keybit);
+	if (xpad->is360)
+		xpad_buttons = xpad_btn_360;
+	else
+		xpad_buttons = xpad_btn;
+
+	for (i = 0; xpad_buttons[i] >= 0; i++)
+		set_bit(xpad_buttons[i], input_dev->keybit);
 	if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
 		for (i = 0; xpad_btn_pad[i] >= 0; i++)
 			set_bit(xpad_btn_pad[i], input_dev->keybit);
@@ -380,6 +485,13 @@
 		goto fail3;
 
 	usb_set_intfdata(intf, xpad);
+
+	/* Turn off the LEDs on xpad 360 controllers */
+	if (xpad->is360 && !xpad->isWireless) {
+		char ledcmd[] = {1, 3, 0}; /* The LED-off command for Xbox-360 controllers */
+		usb_bulk_msg(udev, usb_sndintpipe(udev,2), ledcmd, sizeof(ledcmd), NULL, 0);
+	}
+
 	return 0;
 
  fail3:	usb_free_urb(xpad->irq_in);
