|
View:
New views
4 Messages
—
Rating Filter:
Alert me
|
|
|
[patch] xpad: extended xbox 360 gamepad supportImproved support for the xbox 360 gamepad. Support for setting the LEDs
on the controller upon initialization, fine tuning of the axes and triggers, and removal of unused buttons from the driver are all included. The behavior of the original xbox gamepad should not be affected. Signed-off-by: Matthew Nicholson <matt@...> --- The drivers maps the left and right stick, up and right directions to positive values, this may not be how other drivers handle this. I was not able to confirm if this is the case or not, but at least one game I have encountered expected the Y axis to be inverted although it makes more sense the way it is now. -- Matthew A. Nicholson matt-land.com diff -ruN a/xpad.c b/xpad.c --- a/xpad.c 2006-05-01 22:42:29.000000000 -0500 +++ b/xpad.c 2006-05-02 00:36:58.000000000 -0500 @@ -1,4 +1,4 @@ -/* +/* vim: set noet sw=8: * Xbox input device driver for Linux - v0.1.6 * * Copyright (c) 2002 - 2004 Marko Friedemann <mfr@...> @@ -11,6 +11,7 @@ * Franz Lehner <franz@...>, * Ivan Hawkes <blackhawk@...> * Edgar Hucek <hostmaster@...> + * Matthew Nicholson <matt@...> * * * This program is free software; you can redistribute it and/or @@ -30,6 +31,7 @@ * * This driver is based on: * - information from http://euc.jp/periphs/xbox-controller.en.html + * - information from http://www.free60.org/wiki/Gamepad * - the iForce driver drivers/char/joystick/iforce.c * - the skeleton-driver drivers/usb/usb-skeleton.c * @@ -110,6 +112,13 @@ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, /* analogue buttons */ BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ BTN_0, BTN_1, BTN_2, BTN_3, /* d-pad as buttons */ + -1 /* terminating entry */ +}; + +static const signed short x360_btn[] = { + BTN_A, BTN_B, BTN_X, BTN_Y, /* face buttons */ + BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ + BTN_0, BTN_1, BTN_2, BTN_3, /* d-pad as buttons */ BTN_TL, BTN_TR, /* Button LB/RB */ BTN_MODE, /* The big X */ -1 /* terminating entry */ @@ -133,6 +142,13 @@ -1 /* terminating entry */ }; +static const signed short x360_abs[] = { + ABS_X, ABS_Y, /* left stick */ + ABS_RX, ABS_RY, /* right stick */ + ABS_Z, ABS_RZ, /* triggers left/right */ + -1 /* terminating entry */ +}; + static struct usb_device_id xpad_table [] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not approved class */ { USB_INTERFACE_INFO( 3 , 0 , 0) }, /* for Joytech Advanced Controller */ @@ -166,6 +182,12 @@ printk("\n"); } + if (xpad->is360) { + /* make sure this is an input report message */ + if (data[0] != 0x00) + return; + } + /* digital pad (button mode) bits (3 2 1 0) (right left down up) */ input_report_key(dev, BTN_0, (data[2] & 0x01)); input_report_key(dev, BTN_1, (data[2] & 0x08) >> 3); @@ -184,8 +206,8 @@ 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_X, (data[3] & 0x40) >> 6); + input_report_key(dev, BTN_Y, (data[3] & 0x80) >> 7); 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); @@ -199,11 +221,12 @@ if (xpad->isMat) return; - /* left stick (Y axis needs to be flipped) */ + /* left stick */ 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])); + input_report_abs(dev, ABS_Y, (__s16)(((__s16)data[9] << 8) | data[8])); } else { + /* Y axis needs to be flipped */ input_report_abs(dev, ABS_X, (__s16)(((__s16)data[13] << 8) | (__s16)data[12])); input_report_abs(dev, ABS_Y, ~(__s16)(((__s16)data[15] << 8) | data[14])); } @@ -287,6 +310,39 @@ } /** + * xpad_irq_out + * + * Completion handler for interrupt in transfers (led and rumble output). + */ +static void xpad_irq_out(struct urb *urb, struct pt_regs *regs) +{ + int retval; + + 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", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + +exit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("%s - usb_submit_urb failed with result %d", + __FUNCTION__, retval); +} + +/** * xpad_open * * Called when a an application opens the device. @@ -339,7 +395,9 @@ struct usb_xpad *xpad; struct input_dev *input_dev; struct usb_endpoint_descriptor *ep_irq_in; + struct usb_endpoint_descriptor *ep_irq_out; int i; + int status; int probedDevNum = -1; /* this takes the index into the known devices array for the recognized device */ @@ -366,16 +424,32 @@ SLAB_ATOMIC, &xpad->idata_dma); if (!xpad->idata) goto fail1; + + xpad->isMat = xpad_device[probedDevNum].isMat; + xpad->is360 = xpad_device[probedDevNum].is360; + + /* allocate buffer for led output packets */ + if (xpad->is360) { + xpad->odata_led = usb_buffer_alloc(udev, X360_PKT_LEN_LED, + SLAB_ATOMIC, &xpad->odata_led_dma); + if (!xpad->odata_led) + goto fail2; + } /* setup input interrupt pipe (button and axis state) */ xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); if (!xpad->irq_in) - goto fail2; + goto fail3; + + if (xpad->is360) { + /* setup output interrupt pipe (led and rumble control) */ + xpad->irq_led_out = usb_alloc_urb(0, GFP_KERNEL); + if (!xpad->irq_led_out) + goto fail4; + } xpad->udev = udev; xpad->dev = input_dev; - xpad->isMat = xpad_device[probedDevNum].isMat; - xpad->is360 = xpad_device[probedDevNum].is360; usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); @@ -399,46 +473,71 @@ set_bit(xpad_mat_btn[i], input_dev->keybit); } else { input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + if (xpad->is360) { + for (i = 0; x360_btn[i] >= 0; ++i) + set_bit(x360_btn[i], xpad->dev->keybit); + + for (i = 0; x360_abs[i] >= 0; ++i) { + signed short t = x360_abs[i]; + + set_bit(t, xpad->dev->absbit); + + switch (t) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, t, + -32768, 32767, 16, 5000); + break; + case ABS_Z: /* left trigger */ + case ABS_RZ: /* right trigger */ + input_set_abs_params(input_dev, t, + -255, 255, 0, 0); + break; + } + } - for (i = 0; xpad_btn[i] >= 0; ++i) - set_bit(xpad_btn[i], input_dev->keybit); - - for (i = 0; xpad_abs[i] >= 0; ++i) { - - signed short t = xpad_abs[i]; - - set_bit(t, input_dev->absbit); - - switch (t) { - case ABS_X: - case ABS_Y: - case ABS_RX: - case ABS_RY: /* the two sticks */ - input_set_abs_params(input_dev, t, - -32768, 32767, 16, 12000); - break; - case ABS_Z: /* left trigger */ - case ABS_RZ: /* right trigger */ - case ABS_HAT1X: /* analogue button A */ - case ABS_HAT1Y: /* analogue button B */ - case ABS_HAT2X: /* analogue button C */ - case ABS_HAT2Y: /* analogue button X */ - case ABS_HAT3X: /* analogue button Y */ - case ABS_HAT3Y: /* analogue button Z */ - input_set_abs_params(input_dev, t, - 0, 255, 0, 0); - break; - case ABS_HAT0X: - case ABS_HAT0Y: /* the d-pad */ - input_set_abs_params(input_dev, t, - -1, 1, 0, 0); - break; + } else { + for (i = 0; xpad_btn[i] >= 0; ++i) + set_bit(xpad_btn[i], input_dev->keybit); + + for (i = 0; xpad_abs[i] >= 0; ++i) { + + signed short t = xpad_abs[i]; + + set_bit(t, input_dev->absbit); + + switch (t) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, t, + -32768, 32767, 16, 12000); + break; + case ABS_Z: /* left trigger */ + case ABS_RZ: /* right trigger */ + case ABS_HAT1X: /* analogue button A */ + case ABS_HAT1Y: /* analogue button B */ + case ABS_HAT2X: /* analogue button C */ + case ABS_HAT2Y: /* analogue button X */ + case ABS_HAT3X: /* analogue button Y */ + case ABS_HAT3Y: /* analogue button Z */ + input_set_abs_params(input_dev, t, + 0, 255, 0, 0); + break; + case ABS_HAT0X: + case ABS_HAT0Y: /* the d-pad */ + input_set_abs_params(input_dev, t, + -1, 1, 0, 0); + break; + } } - } - if (!xpad->is360) if (xpad_rumble_probe(udev, xpad, ifnum) != 0) err("could not init rumble"); + } } /* init input URB for USB INT transfer from device */ @@ -449,12 +548,36 @@ xpad, ep_irq_in->bInterval); xpad->irq_in->transfer_dma = xpad->idata_dma; xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + if (xpad->is360) { + /* init output URB for USB INT transfer to device */ + ep_irq_out = &intf->cur_altsetting->endpoint[1].desc; + usb_fill_int_urb(xpad->irq_led_out, udev, + usb_sndintpipe(udev, ep_irq_out->bEndpointAddress), + xpad->odata_led, X360_PKT_LEN_LED, + xpad_irq_out, xpad, ep_irq_out->bInterval); + xpad->irq_led_out->transfer_dma = xpad->odata_led_dma; + xpad->irq_led_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* set xpad 360 leds */ + xpad->odata_led[0] = 0x01; /* message type */ + xpad->odata_led[1] = 0x03; /* message length */ + /* xpad->odata_led[2] = 0x00; /* use 0x00 to turn the leds off */ + xpad->odata_led[2] = 0x06; /* use 0x06 to turn on the '1' */ + + if ((status = usb_submit_urb(xpad->irq_led_out, GFP_KERNEL))) { + err("sending led output urb failed: %d", status); + } + } input_register_device(xpad->dev); usb_set_intfdata(intf, xpad); return 0; +fail4: usb_free_urb(xpad->irq_in); +fail3: if (xpad->is360) + usb_buffer_free(udev, X360_PKT_LEN_LED, xpad->odata_led, xpad->odata_led_dma); fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); fail1: input_free_device(input_dev); kfree(xpad); @@ -474,6 +597,10 @@ usb_set_intfdata(intf, NULL); if (xpad) { usb_kill_urb(xpad->irq_in); + + if (xpad->is360) + usb_kill_urb(xpad->irq_led_out); + if(!xpad->is360) { xpad_rumble_close(xpad); } @@ -483,6 +610,12 @@ usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); + + if (xpad->is360) { + usb_free_urb(xpad->irq_led_out); + usb_buffer_free(interface_to_usbdev(intf), X360_PKT_LEN_LED, + xpad->odata_led, xpad->odata_led_dma); + } if(!xpad->is360) { xpad_rumble_disconnect(xpad); diff -ruN a/xpad.h b/xpad.h --- a/xpad.h 2006-05-01 22:42:14.000000000 -0500 +++ b/xpad.h 2006-05-01 23:17:56.000000000 -0500 @@ -1,4 +1,4 @@ -/* +/* vim: set noet sw=8: * Xbox Controller driver for Linux - v0.1.5 * * header file containing ioctl definitions @@ -55,8 +55,11 @@ #define XPAD_MAX_DEVICES 4 #define XPAD_PKT_LEN 32 /* input packet size */ #define XPAD_PKT_LEN_FF 6 /* output packet size - rumble */ +#define X360_PKT_LEN_FF 8 /* output packet size - rumble */ +#define X360_PKT_LEN_LED 3 /* output packet size - led */ #define XPAD_TX_BUFSIZE XPAD_PKT_LEN_FF * 8 /* max. 8 requests */ +#define X360_TX_BUFSIZE X360_PKT_LEN_FF * 8 /* max. 8 requests */ /************************* the device struct **************************/ struct usb_xpad { @@ -67,6 +70,14 @@ unsigned char *idata; /* input data */ dma_addr_t idata_dma; + struct urb *irq_led_out; /* urb for int. transfer of led data */ + unsigned char *odata_led; /* output data buffer (led) */ + dma_addr_t odata_led_dma; + + struct urb *irq_ff_out; /* urb for int. transfer of force feedback data */ + unsigned char *odata_ff; /* output data buffer (force feedback) */ + dma_addr_t odata_ff_dma; + char phys[65]; /* physical input dev path */ unsigned char offsetset_compensation; |
|
|
[patch v2] xpad: extended xbox 360 gamepad supportImproved support for the xbox 360 gamepad. Support for setting the LEDs
on the controller upon initialization, fine tuning of the axes and triggers, and removal of unused buttons from the driver are all included. The behavior of the original xbox gamepad should not be affected. Signed-off-by: Matthew Nicholson <matt@...> --- > The drivers maps the left and right stick, up and right directions to > positive values, this may not be how other drivers handle this. I was > not able to confirm if this is the case or not, but at least one game I > have encountered expected the Y axis to be inverted although it makes > more sense the way it is now. Here is another stab at the patch this time with the kernel directory hierarchy correct. -- Matthew A. Nicholson matt-land.com diff -ruN a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c --- a/drivers/usb/input/xpad.c 2006-05-01 22:42:29.000000000 -0500 +++ b/drivers/usb/input/xpad.c 2006-05-02 00:36:58.000000000 -0500 @@ -1,4 +1,4 @@ -/* +/* vim: set noet sw=8: * Xbox input device driver for Linux - v0.1.6 * * Copyright (c) 2002 - 2004 Marko Friedemann <mfr@...> @@ -11,6 +11,7 @@ * Franz Lehner <franz@...>, * Ivan Hawkes <blackhawk@...> * Edgar Hucek <hostmaster@...> + * Matthew Nicholson <matt@...> * * * This program is free software; you can redistribute it and/or @@ -30,6 +31,7 @@ * * This driver is based on: * - information from http://euc.jp/periphs/xbox-controller.en.html + * - information from http://www.free60.org/wiki/Gamepad * - the iForce driver drivers/char/joystick/iforce.c * - the skeleton-driver drivers/usb/usb-skeleton.c * @@ -110,6 +112,13 @@ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, /* analogue buttons */ BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ BTN_0, BTN_1, BTN_2, BTN_3, /* d-pad as buttons */ + -1 /* terminating entry */ +}; + +static const signed short x360_btn[] = { + BTN_A, BTN_B, BTN_X, BTN_Y, /* face buttons */ + BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ + BTN_0, BTN_1, BTN_2, BTN_3, /* d-pad as buttons */ BTN_TL, BTN_TR, /* Button LB/RB */ BTN_MODE, /* The big X */ -1 /* terminating entry */ @@ -133,6 +142,13 @@ -1 /* terminating entry */ }; +static const signed short x360_abs[] = { + ABS_X, ABS_Y, /* left stick */ + ABS_RX, ABS_RY, /* right stick */ + ABS_Z, ABS_RZ, /* triggers left/right */ + -1 /* terminating entry */ +}; + static struct usb_device_id xpad_table [] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not approved class */ { USB_INTERFACE_INFO( 3 , 0 , 0) }, /* for Joytech Advanced Controller */ @@ -166,6 +182,12 @@ printk("\n"); } + if (xpad->is360) { + /* make sure this is an input report message */ + if (data[0] != 0x00) + return; + } + /* digital pad (button mode) bits (3 2 1 0) (right left down up) */ input_report_key(dev, BTN_0, (data[2] & 0x01)); input_report_key(dev, BTN_1, (data[2] & 0x08) >> 3); @@ -184,8 +206,8 @@ 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_X, (data[3] & 0x40) >> 6); + input_report_key(dev, BTN_Y, (data[3] & 0x80) >> 7); 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); @@ -199,11 +221,12 @@ if (xpad->isMat) return; - /* left stick (Y axis needs to be flipped) */ + /* left stick */ 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])); + input_report_abs(dev, ABS_Y, (__s16)(((__s16)data[9] << 8) | data[8])); } else { + /* Y axis needs to be flipped */ input_report_abs(dev, ABS_X, (__s16)(((__s16)data[13] << 8) | (__s16)data[12])); input_report_abs(dev, ABS_Y, ~(__s16)(((__s16)data[15] << 8) | data[14])); } @@ -287,6 +310,39 @@ } /** + * xpad_irq_out + * + * Completion handler for interrupt in transfers (led and rumble output). + */ +static void xpad_irq_out(struct urb *urb, struct pt_regs *regs) +{ + int retval; + + 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", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + +exit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("%s - usb_submit_urb failed with result %d", + __FUNCTION__, retval); +} + +/** * xpad_open * * Called when a an application opens the device. @@ -339,7 +395,9 @@ struct usb_xpad *xpad; struct input_dev *input_dev; struct usb_endpoint_descriptor *ep_irq_in; + struct usb_endpoint_descriptor *ep_irq_out; int i; + int status; int probedDevNum = -1; /* this takes the index into the known devices array for the recognized device */ @@ -366,16 +424,32 @@ SLAB_ATOMIC, &xpad->idata_dma); if (!xpad->idata) goto fail1; + + xpad->isMat = xpad_device[probedDevNum].isMat; + xpad->is360 = xpad_device[probedDevNum].is360; + + /* allocate buffer for led output packets */ + if (xpad->is360) { + xpad->odata_led = usb_buffer_alloc(udev, X360_PKT_LEN_LED, + SLAB_ATOMIC, &xpad->odata_led_dma); + if (!xpad->odata_led) + goto fail2; + } /* setup input interrupt pipe (button and axis state) */ xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); if (!xpad->irq_in) - goto fail2; + goto fail3; + + if (xpad->is360) { + /* setup output interrupt pipe (led and rumble control) */ + xpad->irq_led_out = usb_alloc_urb(0, GFP_KERNEL); + if (!xpad->irq_led_out) + goto fail4; + } xpad->udev = udev; xpad->dev = input_dev; - xpad->isMat = xpad_device[probedDevNum].isMat; - xpad->is360 = xpad_device[probedDevNum].is360; usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); @@ -399,46 +473,71 @@ set_bit(xpad_mat_btn[i], input_dev->keybit); } else { input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + if (xpad->is360) { + for (i = 0; x360_btn[i] >= 0; ++i) + set_bit(x360_btn[i], xpad->dev->keybit); + + for (i = 0; x360_abs[i] >= 0; ++i) { + signed short t = x360_abs[i]; + + set_bit(t, xpad->dev->absbit); + + switch (t) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, t, + -32768, 32767, 16, 5000); + break; + case ABS_Z: /* left trigger */ + case ABS_RZ: /* right trigger */ + input_set_abs_params(input_dev, t, + -255, 255, 0, 0); + break; + } + } - for (i = 0; xpad_btn[i] >= 0; ++i) - set_bit(xpad_btn[i], input_dev->keybit); - - for (i = 0; xpad_abs[i] >= 0; ++i) { - - signed short t = xpad_abs[i]; - - set_bit(t, input_dev->absbit); - - switch (t) { - case ABS_X: - case ABS_Y: - case ABS_RX: - case ABS_RY: /* the two sticks */ - input_set_abs_params(input_dev, t, - -32768, 32767, 16, 12000); - break; - case ABS_Z: /* left trigger */ - case ABS_RZ: /* right trigger */ - case ABS_HAT1X: /* analogue button A */ - case ABS_HAT1Y: /* analogue button B */ - case ABS_HAT2X: /* analogue button C */ - case ABS_HAT2Y: /* analogue button X */ - case ABS_HAT3X: /* analogue button Y */ - case ABS_HAT3Y: /* analogue button Z */ - input_set_abs_params(input_dev, t, - 0, 255, 0, 0); - break; - case ABS_HAT0X: - case ABS_HAT0Y: /* the d-pad */ - input_set_abs_params(input_dev, t, - -1, 1, 0, 0); - break; + } else { + for (i = 0; xpad_btn[i] >= 0; ++i) + set_bit(xpad_btn[i], input_dev->keybit); + + for (i = 0; xpad_abs[i] >= 0; ++i) { + + signed short t = xpad_abs[i]; + + set_bit(t, input_dev->absbit); + + switch (t) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, t, + -32768, 32767, 16, 12000); + break; + case ABS_Z: /* left trigger */ + case ABS_RZ: /* right trigger */ + case ABS_HAT1X: /* analogue button A */ + case ABS_HAT1Y: /* analogue button B */ + case ABS_HAT2X: /* analogue button C */ + case ABS_HAT2Y: /* analogue button X */ + case ABS_HAT3X: /* analogue button Y */ + case ABS_HAT3Y: /* analogue button Z */ + input_set_abs_params(input_dev, t, + 0, 255, 0, 0); + break; + case ABS_HAT0X: + case ABS_HAT0Y: /* the d-pad */ + input_set_abs_params(input_dev, t, + -1, 1, 0, 0); + break; + } } - } - if (!xpad->is360) if (xpad_rumble_probe(udev, xpad, ifnum) != 0) err("could not init rumble"); + } } /* init input URB for USB INT transfer from device */ @@ -449,12 +548,36 @@ xpad, ep_irq_in->bInterval); xpad->irq_in->transfer_dma = xpad->idata_dma; xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + if (xpad->is360) { + /* init output URB for USB INT transfer to device */ + ep_irq_out = &intf->cur_altsetting->endpoint[1].desc; + usb_fill_int_urb(xpad->irq_led_out, udev, + usb_sndintpipe(udev, ep_irq_out->bEndpointAddress), + xpad->odata_led, X360_PKT_LEN_LED, + xpad_irq_out, xpad, ep_irq_out->bInterval); + xpad->irq_led_out->transfer_dma = xpad->odata_led_dma; + xpad->irq_led_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* set xpad 360 leds */ + xpad->odata_led[0] = 0x01; /* message type */ + xpad->odata_led[1] = 0x03; /* message length */ + /* xpad->odata_led[2] = 0x00; /* use 0x00 to turn the leds off */ + xpad->odata_led[2] = 0x06; /* use 0x06 to turn on the '1' */ + + if ((status = usb_submit_urb(xpad->irq_led_out, GFP_KERNEL))) { + err("sending led output urb failed: %d", status); + } + } input_register_device(xpad->dev); usb_set_intfdata(intf, xpad); return 0; +fail4: usb_free_urb(xpad->irq_in); +fail3: if (xpad->is360) + usb_buffer_free(udev, X360_PKT_LEN_LED, xpad->odata_led, xpad->odata_led_dma); fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); fail1: input_free_device(input_dev); kfree(xpad); @@ -474,6 +597,10 @@ usb_set_intfdata(intf, NULL); if (xpad) { usb_kill_urb(xpad->irq_in); + + if (xpad->is360) + usb_kill_urb(xpad->irq_led_out); + if(!xpad->is360) { xpad_rumble_close(xpad); } @@ -483,6 +610,12 @@ usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); + + if (xpad->is360) { + usb_free_urb(xpad->irq_led_out); + usb_buffer_free(interface_to_usbdev(intf), X360_PKT_LEN_LED, + xpad->odata_led, xpad->odata_led_dma); + } if(!xpad->is360) { xpad_rumble_disconnect(xpad); diff -ruN a/drivers/usb/input/xpad.h b/drivers/usb/input/xpad.h --- a/drivers/usb/input/xpad.h 2006-05-01 22:42:14.000000000 -0500 +++ b/drivers/usb/input/xpad.h 2006-05-01 23:17:56.000000000 -0500 @@ -1,4 +1,4 @@ -/* +/* vim: set noet sw=8: * Xbox Controller driver for Linux - v0.1.5 * * header file containing ioctl definitions @@ -55,8 +55,11 @@ #define XPAD_MAX_DEVICES 4 #define XPAD_PKT_LEN 32 /* input packet size */ #define XPAD_PKT_LEN_FF 6 /* output packet size - rumble */ +#define X360_PKT_LEN_FF 8 /* output packet size - rumble */ +#define X360_PKT_LEN_LED 3 /* output packet size - led */ #define XPAD_TX_BUFSIZE XPAD_PKT_LEN_FF * 8 /* max. 8 requests */ +#define X360_TX_BUFSIZE X360_PKT_LEN_FF * 8 /* max. 8 requests */ /************************* the device struct **************************/ struct usb_xpad { @@ -67,6 +70,14 @@ unsigned char *idata; /* input data */ dma_addr_t idata_dma; + struct urb *irq_led_out; /* urb for int. transfer of led data */ + unsigned char *odata_led; /* output data buffer (led) */ + dma_addr_t odata_led_dma; + + struct urb *irq_ff_out; /* urb for int. transfer of force feedback data */ + unsigned char *odata_ff; /* output data buffer (force feedback) */ + dma_addr_t odata_ff_dma; + char phys[65]; /* physical input dev path */ unsigned char offsetset_compensation; |
|
|
[patch v3] xpad: extended xbox 360 gamepad supportImproved support for the xbox 360 gamepad. Support for setting the LEDs
on the controller upon initialization, fine tuning of the axes and triggers, and removal of unused buttons from the driver are all included. The behavior of the original xbox gamepad should not be affected. Signed-off-by: Matthew Nicholson <matt@...> --- >> The drivers maps the left and right stick, up and right directions to >> positive values, this may not be how other drivers handle this. I was >> not able to confirm if this is the case or not, but at least one game >> I have encountered expected the Y axis to be inverted although it >> makes more sense the way it is now. > > Here is another stab at the patch this time with the kernel directory > hierarchy correct. This version of the patch swaps the right stick's X and Y axes so that map to the X and Y axes on the controller properly. -- Matthew A. Nicholson matt-land.com diff -ruN a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c --- a/drivers/usb/input/xpad.c 2006-05-01 22:42:29.000000000 -0500 +++ b/drivers/usb/input/xpad.c 2006-05-03 09:42:32.000000000 -0500 @@ -1,4 +1,4 @@ -/* +/* vim: set noet sw=8: * Xbox input device driver for Linux - v0.1.6 * * Copyright (c) 2002 - 2004 Marko Friedemann <mfr@...> @@ -11,6 +11,7 @@ * Franz Lehner <franz@...>, * Ivan Hawkes <blackhawk@...> * Edgar Hucek <hostmaster@...> + * Matthew Nicholson <matt@...> * * * This program is free software; you can redistribute it and/or @@ -30,6 +31,7 @@ * * This driver is based on: * - information from http://euc.jp/periphs/xbox-controller.en.html + * - information from http://www.free60.org/wiki/Gamepad * - the iForce driver drivers/char/joystick/iforce.c * - the skeleton-driver drivers/usb/usb-skeleton.c * @@ -110,6 +112,13 @@ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, /* analogue buttons */ BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ BTN_0, BTN_1, BTN_2, BTN_3, /* d-pad as buttons */ + -1 /* terminating entry */ +}; + +static const signed short x360_btn[] = { + BTN_A, BTN_B, BTN_X, BTN_Y, /* face buttons */ + BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ + BTN_0, BTN_1, BTN_2, BTN_3, /* d-pad as buttons */ BTN_TL, BTN_TR, /* Button LB/RB */ BTN_MODE, /* The big X */ -1 /* terminating entry */ @@ -133,6 +142,13 @@ -1 /* terminating entry */ }; +static const signed short x360_abs[] = { + ABS_X, ABS_Y, /* left stick */ + ABS_RX, ABS_RY, /* right stick */ + ABS_Z, ABS_RZ, /* triggers left/right */ + -1 /* terminating entry */ +}; + static struct usb_device_id xpad_table [] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not approved class */ { USB_INTERFACE_INFO( 3 , 0 , 0) }, /* for Joytech Advanced Controller */ @@ -166,6 +182,12 @@ printk("\n"); } + if (xpad->is360) { + /* make sure this is an input report message */ + if (data[0] != 0x00) + return; + } + /* digital pad (button mode) bits (3 2 1 0) (right left down up) */ input_report_key(dev, BTN_0, (data[2] & 0x01)); input_report_key(dev, BTN_1, (data[2] & 0x08) >> 3); @@ -184,8 +206,8 @@ 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_X, (data[3] & 0x40) >> 6); + input_report_key(dev, BTN_Y, (data[3] & 0x80) >> 7); 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); @@ -199,19 +221,20 @@ if (xpad->isMat) return; - /* left stick (Y axis needs to be flipped) */ + /* left stick */ 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])); + input_report_abs(dev, ABS_Y, (__s16)(((__s16)data[9] << 8) | data[8])); } else { + /* Y axis needs to be flipped */ input_report_abs(dev, ABS_X, (__s16)(((__s16)data[13] << 8) | (__s16)data[12])); input_report_abs(dev, ABS_Y, ~(__s16)(((__s16)data[15] << 8) | data[14])); } /* right stick */ 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])); + input_report_abs(dev, ABS_RX, (__s16)(((__s16)data[11] << 8) | (__s16)data[10])); + input_report_abs(dev, ABS_RY, (__s16)(((__s16)data[13] << 8) | (__s16)data[12])); } else { input_report_abs(dev, ABS_RX, (__s16)(((__s16)data[17] << 8) | (__s16)data[16])); input_report_abs(dev, ABS_RY, (__s16)(((__s16)data[19] << 8) | (__s16)data[18])); @@ -287,6 +310,39 @@ } /** + * xpad_irq_out + * + * Completion handler for interrupt in transfers (led and rumble output). + */ +static void xpad_irq_out(struct urb *urb, struct pt_regs *regs) +{ + int retval; + + 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", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + +exit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("%s - usb_submit_urb failed with result %d", + __FUNCTION__, retval); +} + +/** * xpad_open * * Called when a an application opens the device. @@ -339,7 +395,9 @@ struct usb_xpad *xpad; struct input_dev *input_dev; struct usb_endpoint_descriptor *ep_irq_in; + struct usb_endpoint_descriptor *ep_irq_out; int i; + int status; int probedDevNum = -1; /* this takes the index into the known devices array for the recognized device */ @@ -366,16 +424,32 @@ SLAB_ATOMIC, &xpad->idata_dma); if (!xpad->idata) goto fail1; + + xpad->isMat = xpad_device[probedDevNum].isMat; + xpad->is360 = xpad_device[probedDevNum].is360; + + /* allocate buffer for led output packets */ + if (xpad->is360) { + xpad->odata_led = usb_buffer_alloc(udev, X360_PKT_LEN_LED, + SLAB_ATOMIC, &xpad->odata_led_dma); + if (!xpad->odata_led) + goto fail2; + } /* setup input interrupt pipe (button and axis state) */ xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); if (!xpad->irq_in) - goto fail2; + goto fail3; + + if (xpad->is360) { + /* setup output interrupt pipe (led and rumble control) */ + xpad->irq_led_out = usb_alloc_urb(0, GFP_KERNEL); + if (!xpad->irq_led_out) + goto fail4; + } xpad->udev = udev; xpad->dev = input_dev; - xpad->isMat = xpad_device[probedDevNum].isMat; - xpad->is360 = xpad_device[probedDevNum].is360; usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); @@ -399,46 +473,71 @@ set_bit(xpad_mat_btn[i], input_dev->keybit); } else { input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + if (xpad->is360) { + for (i = 0; x360_btn[i] >= 0; ++i) + set_bit(x360_btn[i], xpad->dev->keybit); + + for (i = 0; x360_abs[i] >= 0; ++i) { + signed short t = x360_abs[i]; + + set_bit(t, xpad->dev->absbit); + + switch (t) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, t, + -32768, 32767, 16, 5000); + break; + case ABS_Z: /* left trigger */ + case ABS_RZ: /* right trigger */ + input_set_abs_params(input_dev, t, + -255, 255, 0, 0); + break; + } + } - for (i = 0; xpad_btn[i] >= 0; ++i) - set_bit(xpad_btn[i], input_dev->keybit); - - for (i = 0; xpad_abs[i] >= 0; ++i) { - - signed short t = xpad_abs[i]; - - set_bit(t, input_dev->absbit); - - switch (t) { - case ABS_X: - case ABS_Y: - case ABS_RX: - case ABS_RY: /* the two sticks */ - input_set_abs_params(input_dev, t, - -32768, 32767, 16, 12000); - break; - case ABS_Z: /* left trigger */ - case ABS_RZ: /* right trigger */ - case ABS_HAT1X: /* analogue button A */ - case ABS_HAT1Y: /* analogue button B */ - case ABS_HAT2X: /* analogue button C */ - case ABS_HAT2Y: /* analogue button X */ - case ABS_HAT3X: /* analogue button Y */ - case ABS_HAT3Y: /* analogue button Z */ - input_set_abs_params(input_dev, t, - 0, 255, 0, 0); - break; - case ABS_HAT0X: - case ABS_HAT0Y: /* the d-pad */ - input_set_abs_params(input_dev, t, - -1, 1, 0, 0); - break; + } else { + for (i = 0; xpad_btn[i] >= 0; ++i) + set_bit(xpad_btn[i], input_dev->keybit); + + for (i = 0; xpad_abs[i] >= 0; ++i) { + + signed short t = xpad_abs[i]; + + set_bit(t, input_dev->absbit); + + switch (t) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, t, + -32768, 32767, 16, 12000); + break; + case ABS_Z: /* left trigger */ + case ABS_RZ: /* right trigger */ + case ABS_HAT1X: /* analogue button A */ + case ABS_HAT1Y: /* analogue button B */ + case ABS_HAT2X: /* analogue button C */ + case ABS_HAT2Y: /* analogue button X */ + case ABS_HAT3X: /* analogue button Y */ + case ABS_HAT3Y: /* analogue button Z */ + input_set_abs_params(input_dev, t, + 0, 255, 0, 0); + break; + case ABS_HAT0X: + case ABS_HAT0Y: /* the d-pad */ + input_set_abs_params(input_dev, t, + -1, 1, 0, 0); + break; + } } - } - if (!xpad->is360) if (xpad_rumble_probe(udev, xpad, ifnum) != 0) err("could not init rumble"); + } } /* init input URB for USB INT transfer from device */ @@ -449,12 +548,36 @@ xpad, ep_irq_in->bInterval); xpad->irq_in->transfer_dma = xpad->idata_dma; xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + if (xpad->is360) { + /* init output URB for USB INT transfer to device */ + ep_irq_out = &intf->cur_altsetting->endpoint[1].desc; + usb_fill_int_urb(xpad->irq_led_out, udev, + usb_sndintpipe(udev, ep_irq_out->bEndpointAddress), + xpad->odata_led, X360_PKT_LEN_LED, + xpad_irq_out, xpad, ep_irq_out->bInterval); + xpad->irq_led_out->transfer_dma = xpad->odata_led_dma; + xpad->irq_led_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* set xpad 360 leds */ + xpad->odata_led[0] = 0x01; /* message type */ + xpad->odata_led[1] = 0x03; /* message length */ + /* xpad->odata_led[2] = 0x00; /* use 0x00 to turn the leds off */ + xpad->odata_led[2] = 0x06; /* use 0x06 to turn on the '1' */ + + if ((status = usb_submit_urb(xpad->irq_led_out, GFP_KERNEL))) { + err("sending led output urb failed: %d", status); + } + } input_register_device(xpad->dev); usb_set_intfdata(intf, xpad); return 0; +fail4: usb_free_urb(xpad->irq_in); +fail3: if (xpad->is360) + usb_buffer_free(udev, X360_PKT_LEN_LED, xpad->odata_led, xpad->odata_led_dma); fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); fail1: input_free_device(input_dev); kfree(xpad); @@ -474,6 +597,10 @@ usb_set_intfdata(intf, NULL); if (xpad) { usb_kill_urb(xpad->irq_in); + + if (xpad->is360) + usb_kill_urb(xpad->irq_led_out); + if(!xpad->is360) { xpad_rumble_close(xpad); } @@ -483,6 +610,12 @@ usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); + + if (xpad->is360) { + usb_free_urb(xpad->irq_led_out); + usb_buffer_free(interface_to_usbdev(intf), X360_PKT_LEN_LED, + xpad->odata_led, xpad->odata_led_dma); + } if(!xpad->is360) { xpad_rumble_disconnect(xpad); diff -ruN a/drivers/usb/input/xpad.h b/drivers/usb/input/xpad.h --- a/drivers/usb/input/xpad.h 2006-05-01 22:42:14.000000000 -0500 +++ b/drivers/usb/input/xpad.h 2006-05-01 23:17:56.000000000 -0500 @@ -1,4 +1,4 @@ -/* +/* vim: set noet sw=8: * Xbox Controller driver for Linux - v0.1.5 * * header file containing ioctl definitions @@ -55,8 +55,11 @@ #define XPAD_MAX_DEVICES 4 #define XPAD_PKT_LEN 32 /* input packet size */ #define XPAD_PKT_LEN_FF 6 /* output packet size - rumble */ +#define X360_PKT_LEN_FF 8 /* output packet size - rumble */ +#define X360_PKT_LEN_LED 3 /* output packet size - led */ #define XPAD_TX_BUFSIZE XPAD_PKT_LEN_FF * 8 /* max. 8 requests */ +#define X360_TX_BUFSIZE X360_PKT_LEN_FF * 8 /* max. 8 requests */ /************************* the device struct **************************/ struct usb_xpad { @@ -67,6 +70,14 @@ unsigned char *idata; /* input data */ dma_addr_t idata_dma; + struct urb *irq_led_out; /* urb for int. transfer of led data */ + unsigned char *odata_led; /* output data buffer (led) */ + dma_addr_t odata_led_dma; + + struct urb *irq_ff_out; /* urb for int. transfer of force feedback data */ + unsigned char *odata_ff; /* output data buffer (force feedback) */ + dma_addr_t odata_ff_dma; + char phys[65]; /* physical input dev path */ unsigned char offsetset_compensation; |
|
|
Re: [patch v3] xpad: extended xbox 360 gamepad supportImproved support for the xbox 360 gamepad. Fine tuning of the axes and
triggers and removal of unused buttons from the 360 parts driver are included. The behavior of the original xbox gamepad should not be affected. Signed-off-by: Matthew Nicholson <matt@...> --- >>> The drivers maps the left and right stick, up and right directions to >>> positive values, this may not be how other drivers handle this. I >>> was not able to confirm if this is the case or not, but at least one >>> game I have encountered expected the Y axis to be inverted although >>> it makes more sense the way it is now. >> >> Here is another stab at the patch this time with the kernel directory >> hierarchy correct. > > This version of the patch swaps the right stick's X and Y axes so that > map to the X and Y axes on the controller properly. code from CVS. Led initialization has been removed as that has been added upstream already. I have not gotten a chance to test this one, but all that has changed is removing the led stuff from my code. -- Matthew A. Nicholson matt-land.com diff -ruN a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c --- a/drivers/usb/input/xpad.c 2006-10-05 14:38:07.000000000 -0500 +++ b/drivers/usb/input/xpad.c 2006-10-05 14:49:00.000000000 -0500 @@ -1,4 +1,4 @@ -/* +/* vim: set noet sw=8: * Xbox input device driver for Linux - v0.1.6 * * Copyright (c) 2002 - 2004 Marko Friedemann <mfr@...> @@ -12,6 +12,7 @@ * Ivan Hawkes <blackhawk@...> * Edgar Hucek <hostmaster@...> * Niklas Lundberg <niklas@...> + * Matthew Nicholson <matt@...> * * * This program is free software; you can redistribute it and/or @@ -31,6 +32,7 @@ * * This driver is based on: * - information from http://euc.jp/periphs/xbox-controller.en.html + * - information from http://wiki.free60.org/Gamepad * - the iForce driver drivers/char/joystick/iforce.c * - the skeleton-driver drivers/usb/usb-skeleton.c * @@ -112,6 +114,13 @@ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, /* analogue buttons */ BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ BTN_0, BTN_1, BTN_2, BTN_3, /* d-pad as buttons */ + -1 /* terminating entry */ +}; + +static const signed short x360_btn[] = { + BTN_A, BTN_B, BTN_X, BTN_Y, /* face buttons */ + BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ + BTN_0, BTN_1, BTN_2, BTN_3, /* d-pad as buttons */ BTN_TL, BTN_TR, /* Button LB/RB */ BTN_MODE, /* The big X */ -1 /* terminating entry */ @@ -135,6 +144,13 @@ -1 /* terminating entry */ }; +static const signed short x360_abs[] = { + ABS_X, ABS_Y, /* left stick */ + ABS_RX, ABS_RY, /* right stick */ + ABS_Z, ABS_RZ, /* triggers left/right */ + -1 /* terminating entry */ +}; + static struct usb_device_id xpad_table [] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not approved class */ { USB_INTERFACE_INFO( 3 , 0 , 0) }, /* for Joytech Advanced Controller */ @@ -168,6 +184,12 @@ printk("\n"); } + if (xpad->is360) { + /* make sure this is an input report message */ + if (data[0] != 0x00) + return; + } + /* digital pad (button mode) bits (3 2 1 0) (right left down up) */ input_report_key(dev, BTN_0, (data[2] & 0x01)); input_report_key(dev, BTN_1, (data[2] & 0x08) >> 3); @@ -186,8 +208,8 @@ 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_X, (data[3] & 0x40) >> 6); + input_report_key(dev, BTN_Y, (data[3] & 0x80) >> 7); 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); @@ -201,19 +223,20 @@ if (xpad->isMat) return; - /* left stick (Y axis needs to be flipped) */ + /* left stick */ 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])); + input_report_abs(dev, ABS_Y, (__s16)(((__s16)data[9] << 8) | data[8])); } else { + /* Y axis needs to be flipped */ input_report_abs(dev, ABS_X, (__s16)(((__s16)data[13] << 8) | (__s16)data[12])); input_report_abs(dev, ABS_Y, ~(__s16)(((__s16)data[15] << 8) | data[14])); } /* right stick */ 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])); + input_report_abs(dev, ABS_RX, (__s16)(((__s16)data[11] << 8) | (__s16)data[10])); + input_report_abs(dev, ABS_RY, (__s16)(((__s16)data[13] << 8) | (__s16)data[12])); } else { input_report_abs(dev, ABS_RX, (__s16)(((__s16)data[17] << 8) | (__s16)data[16])); input_report_abs(dev, ABS_RY, (__s16)(((__s16)data[19] << 8) | (__s16)data[18])); @@ -401,46 +424,71 @@ set_bit(xpad_mat_btn[i], input_dev->keybit); } else { input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + if (xpad->is360) { + for (i = 0; x360_btn[i] >= 0; ++i) + set_bit(x360_btn[i], xpad->dev->keybit); + + for (i = 0; x360_abs[i] >= 0; ++i) { + signed short t = x360_abs[i]; + + set_bit(t, xpad->dev->absbit); + + switch (t) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, t, + -32768, 32767, 16, 5000); + break; + case ABS_Z: /* left trigger */ + case ABS_RZ: /* right trigger */ + input_set_abs_params(input_dev, t, + -255, 255, 0, 0); + break; + } + } - for (i = 0; xpad_btn[i] >= 0; ++i) - set_bit(xpad_btn[i], input_dev->keybit); - - for (i = 0; xpad_abs[i] >= 0; ++i) { - - signed short t = xpad_abs[i]; - - set_bit(t, input_dev->absbit); - - switch (t) { - case ABS_X: - case ABS_Y: - case ABS_RX: - case ABS_RY: /* the two sticks */ - input_set_abs_params(input_dev, t, - -32768, 32767, 16, 12000); - break; - case ABS_Z: /* left trigger */ - case ABS_RZ: /* right trigger */ - case ABS_HAT1X: /* analogue button A */ - case ABS_HAT1Y: /* analogue button B */ - case ABS_HAT2X: /* analogue button C */ - case ABS_HAT2Y: /* analogue button X */ - case ABS_HAT3X: /* analogue button Y */ - case ABS_HAT3Y: /* analogue button Z */ - input_set_abs_params(input_dev, t, - 0, 255, 0, 0); - break; - case ABS_HAT0X: - case ABS_HAT0Y: /* the d-pad */ - input_set_abs_params(input_dev, t, - -1, 1, 0, 0); - break; + } else { + for (i = 0; xpad_btn[i] >= 0; ++i) + set_bit(xpad_btn[i], input_dev->keybit); + + for (i = 0; xpad_abs[i] >= 0; ++i) { + + signed short t = xpad_abs[i]; + + set_bit(t, input_dev->absbit); + + switch (t) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, t, + -32768, 32767, 16, 12000); + break; + case ABS_Z: /* left trigger */ + case ABS_RZ: /* right trigger */ + case ABS_HAT1X: /* analogue button A */ + case ABS_HAT1Y: /* analogue button B */ + case ABS_HAT2X: /* analogue button C */ + case ABS_HAT2Y: /* analogue button X */ + case ABS_HAT3X: /* analogue button Y */ + case ABS_HAT3Y: /* analogue button Z */ + input_set_abs_params(input_dev, t, + 0, 255, 0, 0); + break; + case ABS_HAT0X: + case ABS_HAT0Y: /* the d-pad */ + input_set_abs_params(input_dev, t, + -1, 1, 0, 0); + break; + } } - } - if (!xpad->is360) if (xpad_rumble_probe(udev, xpad, ifnum) != 0) err("could not init rumble"); + } } /* init input URB for USB INT transfer from device */ @@ -458,6 +506,7 @@ /* Turn off the LEDs on xpad 360 controllers */ if (xpad->is360) { + /* char ledcmd[] = {1, 3, 6}; /* The LED-1 on command for Xbox-360 controllers */ char ledcmd[] = {1, 3, 0}; /* The LED-off command for Xbox-360 controllers */ int j; usb_bulk_msg(udev, usb_sndintpipe(udev,2), ledcmd, 3, &j, 0); ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys -- and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ Xbox-linux-devel mailing list Xbox-linux-devel@... https://lists.sourceforge.net/lists/listinfo/xbox-linux-devel |
| Free embeddable forum powered by Nabble | Forum Help |