diff -uNr linux-2.4.19-XBOX-2002-10-09-CVS/Documentation/Configure.help linux/Documentation/Configure.help --- linux-2.4.19-XBOX-2002-10-09-CVS/Documentation/Configure.help Wed Oct 9 17:31:44 2002 +++ linux/Documentation/Configure.help Wed Oct 9 17:36:56 2002 @@ -13144,6 +13144,35 @@ to say Y to "USB Keyboard support" (CONFIG_INPUT_KBD) and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well. +Xbox Joystick +CONFIG_USB_XPAD + Say Y here if you want to use the X-Box pad with your computer. + Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV) + and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well. + + For information about how to connect the X-Box pad to USB, see + Documentation/input/xpad.txt. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called xpad.o. If you want to compile it as a + module, say M here and read . + +Xbox Joystick Mouse +CONFIG_USB_XPAD + Say Y here if you want to use the X-Box pad as a mouse + with your computer. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) as well. Note that you should only load + either the xpad.o module or the xpad-mouse.o module, but not both. + + For information about how to connect the X-Box pad to USB, see + Documentation/input/xpad.txt. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called xpad-mouse.o. If you want to compile it as a + module, say M here and read . + Aiptek 8000U tablet support CONFIG_USB_AIPTEK Say Y here if you want to use the USB version of the Aiptek 8000U diff -uNr linux-2.4.19-XBOX-2002-10-09-CVS/Documentation/input/xpad.txt linux/Documentation/input/xpad.txt --- linux-2.4.19-XBOX-2002-10-09-CVS/Documentation/input/xpad.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/input/xpad.txt Wed Oct 9 17:37:55 2002 @@ -0,0 +1,116 @@ +xpad - Linux USB driver for X-Box gamepads +------------------------------------------ + +This driver is work in progress. Although it is already fairly functional, +there are still quite a few things that are not implemented. +See the ToDo-List in drivers/usb/input/xpad.c for details. + + +0. Status +--------- + +For now, this driver has AFAIK only been tested on just one Linux-Box. +This one is running a 2.4.18 kernel with usb-uhci on an amd athlon 600. + +The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) reports +14 axes (6 of them are the analog buttons) and 10 buttons (the analog buttons +are mapped as digital ones, too). + +Alls 14 axes work, though they all have the same range (-32768..32767) +and the zero-setting is not correct for the triggers and the buttons +(I don't know if that is some limitation of jstest, since the input device +setup should be fine. I didn't have a look at jstest itself yet). + +All of the 10 buttons work. The six buttons on the right side (A, B, C [black], +X, Y, Z [white]) are pressure-sensitive and report analog values as 8 bit unsigned. +These are mapped to analog (ABS_HAT1X - ABS_HAT3Y) as well as digital inputs. + +I tested the controller with quake3, and configuration and +in game functionality were OK. However, I find it rather difficult to +play first person shooters with a pad. Your mileage may vary. + + +1. USB adapter +-------------- + +Before you can actually use the driver, you need to get yourself an +adapter cable to connect the X-Box controller to your Linux-Box. + +Such a cable is pretty easy to build. The Controller itself is a USB compound +device (a hub with three ports for two expansion slots and the controller +device) with the only difference in a nonstandard connector (5 pins vs. 4 on +standard USB connector). + +You just need to solder a USB connector onto the cable and keep the +yellow wire unconnected. The other pins have the same order on both +connectors so there is no magic to it. Detailed info on these matters +can be found on the net ([1], [2], [3]). + +Thanks to the trip splitter found on the cable you don't even need to cut the +original one. You can buy an extension cable and cut that instead. That way, +you can still use the controller with your X-Box, if you have one ;) + + +2. driver installation +---------------------- + +Once you have the adapter cable and the controller is connected, you need +to load your USB subsystem and should cat /proc/bus/usb/devices. +There should be an entry like the one at the end [4]. + +Currently (as of version 0.0.4), the following three devices are included: + original Microsoft XBOX controller (US), vendor=0x045e, product=0x0202 + original Microsoft XBOX controller (Japan), vendor=0x045e, product=0x0285 + InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a + +If you have another controller that is not listed above and is not recognized +by the driver, please drop me a line with the appropriate info (that is, include +the name, vendor and product ID, as well as the country where you bought it; +sending the whole dump out of /proc/bus/usb/devices along would be even better). + +In theory, the driver should work with other controllers than mine +(InterAct PowerPad pro, bought in Germany) just fine, but I cannot test this +for I only have this one controller. + +If you compiled and installed the driver, test the functionality: +> modprobe xpad +> modprobe joydev +> jstest /dev/js0 + +There should be 24 inputs (14 axes, 10 buttons), and the values should change +if you move the sticks and push the buttons. + +It works? Voila, your done ;) + + +3. Thanks +--------- + +I have to thank ITO Takayuki for the detailed info on his site + http://euc.jp/periphs/xbox-controller.ja.html. + +His useful info and both the usb-skeleton as well as the iforce input driver +(Greg Kroah-Hartmann; Vojtech Pavlik) helped a lot in rapid prototyping +the basic functionality. + + +4. References +------------- + +1. http://euc.jp/periphs/xbox-controller.ja.html (ITO Takayuki) +2. http://xpad.xbox-scene.com/ +3. http://www.xboxhackz.com/Hackz-Reference.htm + +4. /proc/bus/usb/devices - dump from InterAct PowerPad Pro (Germany): + +T: Bus=01 Lev=03 Prnt=04 Port=00 Cnt=01 Dev#= 5 Spd=12 MxCh= 0 +D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=32 #Cfgs= 1 +P: Vendor=05fd ProdID=107a Rev= 1.00 +C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA +I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=(none) +E: Ad=81(I) Atr=03(Int.) MxPS= 32 Ivl= 10ms +E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl= 10ms + +-- +Marko Friedemann +2002-08-05 diff -uNr linux-2.4.19-XBOX-2002-10-09-CVS/drivers/usb/Config.in linux/drivers/usb/Config.in --- linux-2.4.19-XBOX-2002-10-09-CVS/drivers/usb/Config.in Wed Oct 9 17:31:16 2002 +++ linux/drivers/usb/Config.in Wed Oct 9 17:34:41 2002 @@ -61,7 +61,8 @@ fi dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT dep_tristate ' XBOX Infrared DVD dongle support (EXPERIMENTAL)' CONFIG_USB_XBOXIR $CONFIG_USB $CONFIG_INPUT $CONFIG_USB_KBD $CONFIG_EXPERIMENTAL - dep_tristate ' XBOX XPAD controller support (EXPERIMENTAL)' CONFIG_USB_XPAD $CONFIG_USB $CONFIG_EXPERIMENTAL + dep_tristate ' XBOX XPAD controller support (EXPERIMENTAL)' CONFIG_USB_XPAD $CONFIG_USB $CONFIG_INPUT $CONFIG_EXPERIMENTAL + dep_tristate ' XBOX XPAD mouse emulation support (EXPERIMENTAL)' CONFIG_USB_XPAD_MOUSE $CONFIG_USB $CONFIG_INPUT $CONFIG_EXPERIMENTAL comment 'USB Imaging devices' dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB diff -uNr linux-2.4.19-XBOX-2002-10-09-CVS/drivers/usb/Makefile linux/drivers/usb/Makefile --- linux-2.4.19-XBOX-2002-10-09-CVS/drivers/usb/Makefile Wed Oct 9 17:31:16 2002 +++ linux/drivers/usb/Makefile Wed Oct 9 17:37:14 2002 @@ -94,6 +94,7 @@ obj-$(CONFIG_USB_AUERSWALD) += auerswald.o obj-$(CONFIG_USB_BRLVGER) += brlvger.o obj-$(CONFIG_USB_XPAD) += xpad.o +obj-$(CONFIG_USB_XPAD_MOUSE) += xpad-mouse.o # Object files in subdirectories mod-subdirs := serial hcd diff -uNr linux-2.4.19-XBOX-2002-10-09-CVS/drivers/usb/xpad-mouse.c linux/drivers/usb/xpad-mouse.c --- linux-2.4.19-XBOX-2002-10-09-CVS/drivers/usb/xpad-mouse.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/usb/xpad-mouse.c Wed Oct 9 17:38:19 2002 @@ -0,0 +1,336 @@ +/* + * X-Box gamepad mousedriver - v0.0.1 + * + * Copyright (c) 2002 Marko Friedemann , + * Oliver Schwartz + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * This driver is based on: + * - the original xpad driver from Marko Friedmann + * - 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 + * + * Thanks to: + * - ITO Takayuki for providing essential xpad information on his website + * - Vojtech Pavlik - iforce driver / input subsystem + * - Greg Kroah-Hartman - usb-skeleton driver + * + * TODO: + * - post events even if no movement on sticks + * + * History: + * + * 2002-08-31 - 0.0.1 : first version, based on v0.0.6 of xpad driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "v0.0.1" +#define DRIVER_AUTHOR "Marko Friedemann , Oliver Schwartz" +#define DRIVER_DESC "X-Box pad mouse driver" + +#define XPAD_PKT_LEN 32 + +static struct xpad_device { + u16 idVendor; + u16 idProduct; + char *name; +} xpad_device[] = { + { 0x045e, 0x0202, "Microsoft X-Box pad (US)" }, + { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" }, + { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)" }, + { 0x0000, 0x0000, "X-Box pad" } +}; + +static 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 */ + -1 /* terminating entry */ +}; + +static signed short xpad_abs[] = { + ABS_X, ABS_Y, /* left stick */ + ABS_RX, ABS_RY, /* right stick */ + ABS_Z, ABS_RZ, /* triggers left/right */ + ABS_HAT0X, ABS_HAT0Y, /* digital pad */ + ABS_HAT1X, ABS_HAT1Y, /* analog buttons A + B */ + ABS_HAT2X, ABS_HAT2Y, /* analog buttons C + X */ + ABS_HAT3X, ABS_HAT3Y, /* analog buttons Y + Z */ + -1 /* terminating entry */ +}; + +static struct usb_device_id xpad_table [] = { + { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ + { } +}; + +MODULE_DEVICE_TABLE (usb, xpad_table); + +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[XPAD_PKT_LEN]; /* input data */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) + char phys[65]; /* physical device path */ +#endif + int open_count; /* reference count */ +}; + +/* + * xpad_process_packet + * + * Completes a request by converting the data into events for the + * input subsystem. + * + * The used report descriptor was taken from ITO Takayukis website: + * http://euc.jp/periphs/xbox-controller.ja.html + */ +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) (((__s16)data[13] << 8) | data[12])); +// input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14])); + input_report_rel(dev, REL_WHEEL, (__s16) ((__s8)data[15])/32); + + /* 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])); + input_report_rel(dev, REL_X, (__s16) ((__s8)data[17])/32); + input_report_rel(dev, REL_Y, (__s16) (-(__s8)data[19])/32); + + /* triggers left/right */ +// input_report_abs(dev, ABS_Z, data[10]); +// input_report_abs(dev, ABS_RZ, data[11]); + + /* digital pad: bits (3 2 1 0) (right left down up) */ +// input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); +// input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x01) - !!(data[2] & 0x02)); + + /* start/back buttons and stick press left/right */ +// input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4); +// input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5); +// input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6); +// input_report_key(dev, BTN_THUMBR, data[2] >> 7); + input_report_key(dev, BTN_LEFT, data[2] >> 7); + + /* button A digital/analog mode */ +// input_report_key(dev, BTN_A, data[4]); +// input_report_abs(dev, ABS_HAT1X, data[4]); + input_report_key(dev, BTN_RIGHT, data[4]); + + /* button B digital/analog mode */ +// input_report_key(dev, BTN_B, data[5]); +// input_report_abs(dev, ABS_HAT1Y, data[5]); + + /* button C (black) digital/analog mode */ +// input_report_key(dev, BTN_C, data[8]); +// input_report_abs(dev, ABS_HAT2X, data[8]); + + /* button X digital/analog mode */ +// input_report_key(dev, BTN_X, data[6]); +// input_report_abs(dev, ABS_HAT2Y, data[6]); + input_report_key(dev, BTN_MIDDLE, data[6]); + + /* button Y digital/analog mode */ +// input_report_key(dev, BTN_Y, data[7]); +// input_report_abs(dev, ABS_HAT3X, data[7]); + + /* button Z (white) digital/analog mode */ +// input_report_key(dev, BTN_Z, data[9]); +// input_report_abs(dev, ABS_HAT3Y, data[9]); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 29) + input_sync(dev); +#endif +} + +static void xpad_irq_in(struct urb *urb) +{ + struct usb_xpad *xpad = urb->context; + + if (urb->status) + return; + xpad_process_packet(xpad, 0, xpad->idata); +} + +static int xpad_open (struct input_dev *dev) +{ + struct usb_xpad *xpad = dev->private; + + if (xpad->open_count++) + return 0; + + xpad->irq_in->dev = xpad->udev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) + if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) +#else + if (usb_submit_urb(xpad->irq_in)) +#endif + return -EIO; + + return 0; +} + +static void xpad_close (struct input_dev *dev) +{ + struct usb_xpad *xpad = dev->private; + + if (!--xpad->open_count) + usb_unlink_urb(xpad->irq_in); +} + +static void * xpad_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) +{ + struct usb_xpad *xpad = NULL; + struct usb_endpoint_descriptor *ep_irq_in; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) + char path[64]; +#endif + int i; + + for (i = 0; xpad_device[i].idVendor; i++) { + if ((udev->descriptor.idVendor == xpad_device[i].idVendor) && + (udev->descriptor.idProduct == xpad_device[i].idProduct)) + break; + } + + if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) { + err("cannot allocate memory for new pad"); + return NULL; + } + memset(xpad, 0, sizeof(struct usb_xpad)); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) + xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); +#else + xpad->irq_in = usb_alloc_urb(0); +#endif + if (!xpad->irq_in) { + err("cannot allocate memory for new pad irq urb"); + kfree(xpad); + return NULL; + } + + ep_irq_in = udev->actconfig->interface[ifnum].altsetting[0].endpoint + 0; + + FILL_INT_URB(xpad->irq_in, udev, + usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), + xpad->idata, XPAD_PKT_LEN, xpad_irq_in, xpad, + ep_irq_in->bInterval); + + xpad->udev = udev; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 29) + xpad->dev.id.bustype = BUS_USB; + xpad->dev.id.vendor = udev->descriptor.idVendor; + xpad->dev.id.product = udev->descriptor.idProduct; + xpad->dev.id.version = udev->descriptor.bcdDevice; +#else + xpad->dev.idbus = BUS_USB; + xpad->dev.idvendor = udev->descriptor.idVendor; + xpad->dev.idproduct = udev->descriptor.idProduct; + xpad->dev.idversion = udev->descriptor.bcdDevice; +#endif + xpad->dev.private = xpad; + xpad->dev.name = xpad_device[i].name; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) + xpad->dev.phys = xpad->phys; +#endif + xpad->dev.open = xpad_open; + xpad->dev.close = xpad_close; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) + usb_make_path(udev, path, 64); + snprintf(xpad->phys, 64, "%s/input0", path); +#endif + + xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + xpad->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + xpad->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + xpad->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); + xpad->dev.relbit[0] |= BIT(REL_WHEEL); + + + input_register_device(&xpad->dev); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) + printk(KERN_INFO "input: %s on %s", xpad->dev.name, path); +#else + printk(KERN_INFO "input: %s", xpad->dev.name); +#endif + + return xpad; +} + +static void xpad_disconnect(struct usb_device *udev, void *ptr) +{ + struct usb_xpad *xpad = ptr; + + usb_unlink_urb(xpad->irq_in); + input_unregister_device(&xpad->dev); + usb_free_urb(xpad->irq_in); + kfree(xpad); +} + +static struct usb_driver xpad_driver = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 29) + .name = "xpad", + .probe = xpad_probe, + .disconnect = xpad_disconnect, + .id_table = xpad_table, +#else + name: "xpad", + probe: xpad_probe, + disconnect: xpad_disconnect, + id_table: xpad_table, +#endif +}; + +static int __init usb_xpad_init(void) +{ + usb_register(&xpad_driver); + info(DRIVER_DESC ":" DRIVER_VERSION); + return 0; +} + +static void __exit usb_xpad_exit(void) +{ + 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");