GIT a66917f6e387c1397583d5da13f301fd23acc5f4 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/dtor/input.git commit Author: Dmitry Torokhov Date: Mon May 14 23:52:22 2007 -0400 Input: ucb1x00-ts - remove commented out code Signed-off-by: Dmitry Torokhov commit 90c71fa712e3c5dd029d779f22e1667251df5b08 Author: Satoru Takeuchi Date: Mon May 14 23:52:07 2007 -0400 Input: ucb1400_ts - use sched_setscheduler() Fix Philips UCB1400 driver to use sched_setscheduler() instead of setting the fields of task_struct directly. Signed-off-by: Satoru Takeuchi Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov commit 6bf5ddf3a0e310a1b7d82baeef3643ced3f00323 Author: Dmitry Torokhov Date: Mon May 14 23:51:54 2007 -0400 Input: ALPS - force stream mode ALPS appears to need SETSTREAM command after reset, otherwise it does not produce any data. Now that we do not request stream mode by default individual drivers need to take care of it. [Jason Riedy - fix oops] Signed-off-by: Dmitry Torokhov commit 5f70330564b8cc5f1cdfbef74d6ec83a68528096 Author: Johann Deneux Date: Mon May 14 00:09:33 2007 -0400 Input: iforce - minor clean-ups Signed-off-by: Johann Deneux Signed-off-by: Dmitry Torokhov commit 9072b2669c3b3c8f1f146bbbe80b5da1ef36a0e4 Author: Johann Deneux Date: Mon May 14 00:09:28 2007 -0400 Input: iforce - fix force feedback not working Use an interrupt URB to send force-feedback data to the device instead of a bulk URB. This was broken since 2.6.18. Signed-off-by: Johann Deneux Signed-off-by: Dmitry Torokhov commit 7e393e4487171d3aae8af12c10b50487595c681f Author: Dmitry Torokhov Date: Fri May 11 01:16:12 2007 -0400 Input: ucb1x00 - do not access input_dev->private directly Use input_get_drvdata() and input_set_drvdata() helpers to do that. Signed-off-by: Dmitry Torokhov Acked-by: Pavel Machek commit 23416adf1da2641d1319da2076d0189b7b0a5648 Author: Aristeu Rozanski Date: Thu May 10 01:47:18 2007 -0400 Input: psmouse - add support for Cortron PS/2 Trackballs Cortron PS/2 Trackballs (700-0001A) report the 4th button using the 4th bit of the first packet (yes, it breaks the standard PS/2 protocol). This patch adds an extra protocol to generate BTN_SIDE based on the 4th bit. There's no way to detect those trackballs using any kind of special sequence, thus the protocol must be activated explicitely by writing into 'protocol' sysfs attribute: echo -n "cortps" > /sys/devices/platform/i8042/serio1/protocol Signed-off-by: Aristeu Rozanski Signed-off-by: Dmitry Torokhov commit 1bf8b983977fe5be69db68f715bb32f2c9b3b597 Author: Jan Kratochvil Date: Wed May 9 00:27:51 2007 -0400 Input: xpad - add Xbox360 gamepad rumble support Implementation is using force feedback support for memoryless devices. Signed-off-by: Jan Kratochvil Signed-off-by: Dmitry Torokhov commit bad058541d848500b5f2cc049c1082d0b2935b7d Author: Jan Kratochvil Date: Wed May 9 00:27:37 2007 -0400 Input: xpad - add support for Xbox 360 gamepad Xbox 360 gamepad is slightly different then the previous model so it has its own version of process_packet method. Detection of this new device relies on USB_DEVICE_INTERFACE_PROTOCOL macro. This device got vendor specific subclass so it can't be matched with USB_INTERFACE_INFO and we need only one interface protocol from four availaible. It means USB_DEVICE can't be used either. Added xpad360_btn structure with additional buttons for x360 gamepad. Added xtype into xpad_device structure to distinguish between different types of xbox devices. Signed-off-by: Jan Kratochvil Signed-off-by: Dmitry Torokhov commit 135803427592ba35c94f8a5814eae7e80a22d6be Author: Jan Kratochvil Date: Wed May 9 00:26:15 2007 -0400 USB: Add USB_DEVICE_INTERFACE_PROTOCOL macro The USB_DEVICE_INTERFACE_PROTOCOL will allow to match one interface protocol of vendor specific device. This macro is used in patch adding support for xbox360 to xpad.c Signed-off-by: Jan Kratochvil Signed-off-by: Greg Kroah-Hartman Signed-off-by: Dmitry Torokhov commit 7d7b33d6d558ea43018c3b2a94c6d52e78128cbe Author: Dmitry Torokhov Date: Tue May 8 23:34:30 2007 -0400 Input: adbhid - do not access input_dev->private directly Use input_get_drvdata() and input_set_drvdata() helpers to do that. Signed-off-by: Dmitry Torokhov commit 18cc6757532e3b0e7a569b1631869c812b777196 Author: Peter Samuelson Date: Tue May 8 23:34:18 2007 -0400 Input: logips2pp - add type 72 (PS/2 TrackMan Marble) This is purely cosmetic: this is standard 3-button, no wheel or other such features, so it already _worked_ just fine. This patch suppresses a warning about the unknown model, and changes the printk from "Mouse" to "TrackMan". Signed-off-by: Peter Samuelson Signed-off-by: Dmitry Torokhov drivers/input/joystick/Kconfig | 7 + drivers/input/joystick/iforce/iforce-main.c | 4 drivers/input/joystick/iforce/iforce-packets.c | 10 + drivers/input/joystick/iforce/iforce-usb.c | 5 drivers/input/joystick/xpad.c | 276 +++++++++++++++++++++--- drivers/input/mouse/alps.c | 58 +++-- drivers/input/mouse/logips2pp.c | 1 drivers/input/mouse/psmouse-base.c | 29 +++ drivers/input/mouse/psmouse.h | 1 drivers/input/touchscreen/ucb1400_ts.c | 4 drivers/macintosh/adbhid.c | 16 + drivers/mfd/ucb1x00-ts.c | 18 -- include/linux/usb.h | 16 + 13 files changed, 350 insertions(+), 95 deletions(-) diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 82f563e..a15a923 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -267,4 +267,11 @@ config JOYSTICK_XPAD To compile this driver as a module, choose M here: the module will be called xpad. +config JOYSTICK_XPAD_FF + bool "X-Box gamepad rumble support" + depends on JOYSTICK_XPAD && INPUT + select INPUT_FF_MEMLESS + ---help--- + Say Y here if you want to take advantage of xbox 360 rumble features. + endif diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index fb129c4..682244b 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -370,10 +370,8 @@ #endif /* * Disable spring, enable force feedback. - * FIXME: We should use iforce_set_autocenter() et al here. */ - - iforce_send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); + iforce_set_autocenter(input_dev, 0); /* * Find appropriate device entry diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 21c4e13..3154ccd 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -246,6 +246,8 @@ #endif int iforce_get_id_packet(struct iforce *iforce, char *packet) { + int status; + switch (iforce->bus) { case IFORCE_USB: @@ -254,18 +256,22 @@ #ifdef CONFIG_JOYSTICK_IFORCE_USB iforce->cr.bRequest = packet[0]; iforce->ctrl->dev = iforce->usbdev; - if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) + status = usb_submit_urb(iforce->ctrl, GFP_ATOMIC); + if (status) { + err("usb_submit_urb failed %d", status); return -1; + } wait_event_interruptible_timeout(iforce->wait, iforce->ctrl->status != -EINPROGRESS, HZ); if (iforce->ctrl->status) { + dbg("iforce->ctrl->status = %d", iforce->ctrl->status); usb_unlink_urb(iforce->ctrl); return -1; } #else - err("iforce_get_id_packet: iforce->bus = USB!"); + dbg("iforce_get_id_packet: iforce->bus = USB!"); #endif break; diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 750099d..1457b73 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -65,6 +65,7 @@ void iforce_usb_xmit(struct iforce *ifor XMIT_INC(iforce->xmit.tail, n); if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) { + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); warn("usb_submit_urb failed %d\n", n); } @@ -163,8 +164,8 @@ static int iforce_usb_probe(struct usb_i usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); - usb_fill_bulk_urb(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), - iforce + 1, 32, iforce_usb_out, iforce); + usb_fill_int_urb(iforce->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress), + iforce + 1, 32, iforce_usb_out, iforce, epout->bInterval); usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce); diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 8c8cd95..0c04a26 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -8,6 +8,7 @@ * Ivan Hawkes * 2005 Dominic Cerquetti * 2006 Adam Buchbinder + * 2007 Jan Kratochvil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -28,6 +29,7 @@ * - 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 @@ -88,6 +90,9 @@ #define MAP_DPAD_TO_BUTTONS 0 #define MAP_DPAD_TO_AXES 1 #define MAP_DPAD_UNKNOWN -1 +#define XTYPE_XBOX 0 +#define XTYPE_XBOX360 1 + 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,40 +102,42 @@ static const struct xpad_device { u16 idProduct; char *name; u8 dpad_mapping; + u8 xtype; } 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, 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 }, + { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, + { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, + { 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, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, + { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 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 }, + { 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, 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_XBOX } }; static const signed short xpad_btn[] = { @@ -146,6 +153,12 @@ static const signed short xpad_btn_pad[] -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 */ @@ -159,8 +172,12 @@ static const signed short xpad_abs_pad[] -1 /* terminating entry */ }; +/* Xbox 360 has a vendor-specific (sub)class, so we cannot match it with only + * USB_INTERFACE_INFO, more to that this device has 4 InterfaceProtocols, + * but we need only one of them. */ static struct usb_device_id xpad_table [] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ + { USB_DEVICE_INTERFACE_PROTOCOL(0x045e, 0x028e, 1) }, /* X-Box 360 controller */ { } }; @@ -174,9 +191,16 @@ struct usb_xpad { unsigned char *idata; /* input data */ dma_addr_t idata_dma; +#ifdef CONFIG_JOYSTICK_XPAD_FF + struct urb *irq_out; /* urb for interrupt out report */ + unsigned char *odata; /* output data */ + dma_addr_t odata_dma; +#endif + char phys[65]; /* physical device path */ int dpad_mapping; /* map d-pad to buttons or to axes */ + int xtype; /* type of xbox device */ }; /* @@ -235,6 +259,64 @@ static void xpad_process_packet(struct u input_sync(dev); } +/* + * xpad360_process_packet + * + * Completes a request by converting the data into events for the + * input subsystem. It is version for xbox 360 controller + * + * The used report descriptor was taken from: + * http://www.free60.org/wiki/Gamepad + */ + +static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) +{ + struct input_dev *dev = xpad->dev; + + /* digital pad */ + if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { + input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x01) - !!((data[2] & 0x08) >> 3)); + input_report_abs(dev, ABS_HAT0Y, !!((data[2] & 0x02) >> 1) - !!((data[2] & 0x04) >> 2)); + } else if ( xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS ) { + /* dpad as buttons (right, left, down, up) */ + input_report_key(dev, BTN_RIGHT, (data[2] & 0x01)); + input_report_key(dev, BTN_LEFT, (data[2] & 0x08) >> 3); + input_report_key(dev, BTN_0, (data[2] & 0x02) >> 1); + input_report_key(dev, BTN_1, (data[2] & 0x04) >> 2); + } + + /* start/back buttons */ + input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4); + input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5); + + /* stick press left/right */ + input_report_key(dev, BTN_THUMBL, data[2] & 0x40); + input_report_key(dev, BTN_THUMBR, data[2] & 0x80); + + /* buttons A,B,X,Y,TL,TR and MODE */ + 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] & 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); + + /* left stick */ + 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) | (__s16)data[8])); + + /* right stick */ + input_report_abs(dev, ABS_RY, ~(__s16) (((__s16)data[13] << 8) | (__s16)data[12])); + input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[11] << 8) | (__s16)data[10])); + + /* triggers left/right */ + input_report_abs(dev, ABS_Z, data[4]); + input_report_abs(dev, ABS_RZ, data[5]); + + input_sync(dev); +} + static void xpad_irq_in(struct urb *urb) { struct usb_xpad *xpad = urb->context; @@ -255,7 +337,10 @@ static void xpad_irq_in(struct urb *urb) goto exit; } - xpad_process_packet(xpad, 0, xpad->idata); + if (xpad->xtype == XTYPE_XBOX360) + xpad360_process_packet(xpad, 0, xpad->idata); + else + xpad_process_packet(xpad, 0, xpad->idata); exit: retval = usb_submit_urb (urb, GFP_ATOMIC); @@ -264,7 +349,113 @@ exit: __FUNCTION__, retval); } -static int xpad_open (struct input_dev *dev) +#ifdef CONFIG_JOYSTICK_XPAD_FF +static void xpad_irq_out(struct urb *urb) +{ + 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); +} + +int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) +{ + struct usb_xpad *xpad = input_get_drvdata(dev); + + 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; + usb_submit_urb(xpad->irq_out, GFP_KERNEL); + } + + return 0; +} + +static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad) +{ + struct usb_endpoint_descriptor *ep_irq_out; + int error = -ENOMEM; + + if (xpad->xtype != XTYPE_XBOX360) + return 0; + + xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN, + GFP_ATOMIC, &xpad->odata_dma ); + if (!xpad->idata) + goto fail1; + + xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL); + if (!xpad->irq_out) + goto fail2; + + ep_irq_out = &intf->cur_altsetting->endpoint[1].desc; + usb_fill_int_urb(xpad->irq_out, xpad->udev, + usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress), + xpad->odata, XPAD_PKT_LEN, + xpad_irq_out, xpad, ep_irq_out->bInterval); + xpad->irq_out->transfer_dma = xpad->odata_dma; + xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + input_set_capability(xpad->dev, EV_FF, FF_RUMBLE); + + error = input_ff_create_memless(xpad->dev, NULL, xpad_play_effect); + if (error) + goto fail2; + + return 0; + + fail2: usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma); + fail1: return error; +} + +static void xpad_stop_ff(struct usb_xpad *xpad) +{ + if (xpad->xtype == XTYPE_XBOX360) + usb_kill_urb(xpad->irq_out); +} + +static void xpad_deinit_ff(struct usb_xpad *xpad) +{ + if (xpad->xtype == XTYPE_XBOX360) { + usb_free_urb(xpad->irq_out); + usb_buffer_free(xpad->udev, XPAD_PKT_LEN, + xpad->odata, xpad->odata_dma); + } +} + +#else +static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; } +static void xpad_stop_ff(struct usb_xpad *xpad) { } +static void xpad_deinit_ff(struct usb_xpad *xpad) { } +#endif + +static int xpad_open(struct input_dev *dev) { struct usb_xpad *xpad = input_get_drvdata(dev); @@ -275,11 +466,12 @@ static int xpad_open (struct input_dev * 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); usb_kill_urb(xpad->irq_in); + xpad_stop_ff(xpad); } static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) @@ -335,6 +527,7 @@ static int xpad_probe(struct usb_interfa xpad->udev = udev; xpad->dpad_mapping = xpad_device[i].dpad_mapping; + xpad->xtype = xpad_device[i].xtype; if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) xpad->dpad_mapping = dpad_to_buttons; xpad->dev = input_dev; @@ -356,6 +549,9 @@ static int xpad_probe(struct usb_interfa /* set up buttons */ for (i = 0; xpad_btn[i] >= 0; i++) set_bit(xpad_btn[i], input_dev->keybit); + if (xpad->xtype == XTYPE_XBOX360) + for (i = 0; xpad360_btn[i] >= 0; i++) + set_bit(xpad360_btn[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); @@ -367,6 +563,10 @@ static int xpad_probe(struct usb_interfa for (i = 0; xpad_abs_pad[i] >= 0; i++) xpad_set_up_abs(input_dev, xpad_abs_pad[i]); + error = xpad_init_ff(intf, xpad); + if (error) + goto fail2; + ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(xpad->irq_in, udev, usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), @@ -396,10 +596,10 @@ static void xpad_disconnect(struct usb_i usb_set_intfdata(intf, NULL); if (xpad) { - usb_kill_urb(xpad->irq_in); input_unregister_device(xpad->dev); + xpad_deinit_ff(xpad); usb_free_urb(xpad->irq_in); - usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, + usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); kfree(xpad); } diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index cf3e466..2c5f11a 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -251,11 +251,15 @@ static const struct alps_model_info *alp dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); - for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++); - *version = (param[0] << 8) | (param[1] << 4) | i; + if (version) { + for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++) + /* empty */; + *version = (param[0] << 8) | (param[1] << 4) | i; + } for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) - if (!memcmp(param, alps_model_data[i].signature, sizeof(alps_model_data[i].signature))) + if (!memcmp(param, alps_model_data[i].signature, + sizeof(alps_model_data[i].signature))) return alps_model_data + i; return NULL; @@ -380,32 +384,46 @@ static int alps_poll(struct psmouse *psm return 0; } -static int alps_reconnect(struct psmouse *psmouse) +static int alps_hw_init(struct psmouse *psmouse, int *version) { struct alps_data *priv = psmouse->private; - int version; - - psmouse_reset(psmouse); - if (!(priv->i = alps_get_model(psmouse, &version))) + priv->i = alps_get_model(psmouse, version); + if (!priv->i) return -1; if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1)) return -1; if (alps_tap_mode(psmouse, 1)) { - printk(KERN_WARNING "alps.c: Failed to reenable hardware tapping\n"); + printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n"); return -1; } if (alps_absolute_mode(psmouse)) { - printk(KERN_ERR "alps.c: Failed to reenable absolute mode\n"); + printk(KERN_ERR "alps.c: Failed to enable absolute mode\n"); return -1; } if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0)) return -1; + /* ALPS needs stream mode, otherwise it won't report any data */ + if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) { + printk(KERN_ERR "alps.c: Failed to enable stream mode\n"); + return -1; + } + + return 0; +} + +static int alps_reconnect(struct psmouse *psmouse) +{ + psmouse_reset(psmouse); + + if (alps_hw_init(psmouse, NULL)) + return -1; + return 0; } @@ -430,23 +448,9 @@ int alps_init(struct psmouse *psmouse) goto init_fail; priv->dev2 = dev2; + psmouse->private = priv; - priv->i = alps_get_model(psmouse, &version); - if (!priv->i) - goto init_fail; - - if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1)) - goto init_fail; - - if (alps_tap_mode(psmouse, 1)) - printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n"); - - if (alps_absolute_mode(psmouse)) { - printk(KERN_ERR "alps.c: Failed to enable absolute mode\n"); - goto init_fail; - } - - if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0)) + if (alps_hw_init(psmouse, &version)) goto init_fail; dev1->evbit[LONG(EV_KEY)] |= BIT(EV_KEY); @@ -493,13 +497,13 @@ int alps_init(struct psmouse *psmouse) /* We are having trouble resyncing ALPS touchpads so disable it for now */ psmouse->resync_time = 0; - psmouse->private = priv; return 0; init_fail: psmouse_reset(psmouse); input_free_device(dev2); kfree(priv); + psmouse->private = NULL; return -1; } diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 9df74b7..0c5660d 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -221,6 +221,7 @@ static const struct ps2pp_info *get_mode { 66, PS2PP_KIND_MX, /* MX3100 reciver */ PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL }, + { 72, PS2PP_KIND_TRACKMAN, 0 }, /* T-CH11: TrackMan Marble */ { 73, 0, PS2PP_SIDE_BTN }, { 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index f15f695..b9f0fb2 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -178,6 +178,15 @@ static psmouse_ret_t psmouse_process_byt } /* + * Cortron PS2 Trackball reports SIDE button on the 4th bit of the first + * byte. + */ + if (psmouse->type == PSMOUSE_CORTRON) { + input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1); + packet[0] |= 0x08; + } + +/* * Generic PS/2 Mouse */ @@ -539,6 +548,20 @@ static int ps2bare_detect(struct psmouse return 0; } +/* + * Cortron PS/2 protocol detection. There's no special way to detect it, so it + * must be forced by sysfs protocol writing. + */ +static int cortron_detect(struct psmouse *psmouse, int set_properties) +{ + if (set_properties) { + psmouse->vendor = "Cortron"; + psmouse->name = "PS/2 Trackball"; + set_bit(BTN_SIDE, psmouse->dev->keybit); + } + + return 0; +} /* * psmouse_extensions() probes for any extensions to the basic PS/2 protocol @@ -740,6 +763,12 @@ #ifdef CONFIG_MOUSE_PS2_TOUCHKIT }, #endif { + .type = PSMOUSE_CORTRON, + .name = "CortronPS/2", + .alias = "cortps", + .detect = cortron_detect, + }, + { .type = PSMOUSE_AUTO, .name = "auto", .alias = "any", diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 3964e8a..27a6883 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -88,6 +88,7 @@ enum psmouse_type { PSMOUSE_LIFEBOOK, PSMOUSE_TRACKPOINT, PSMOUSE_TOUCHKIT_PS2, + PSMOUSE_CORTRON, PSMOUSE_AUTO /* This one should always be last */ }; diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 6582816..f0cbcdb 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -288,9 +288,9 @@ static int ucb1400_ts_thread(void *_ucb) struct ucb1400 *ucb = _ucb; struct task_struct *tsk = current; int valid = 0; + struct sched_param param = { .sched_priority = 1 }; - tsk->policy = SCHED_FIFO; - tsk->rt_priority = 1; + sched_setscheduler(tsk, SCHED_FIFO, ¶m); while (!kthread_should_stop()) { unsigned int x, y, p; diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index b77ef51..b46817f 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -628,16 +628,16 @@ static void real_leds(unsigned char leds */ static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { - struct adbhid *adbhid = dev->private; + struct adbhid *adbhid = input_get_drvdata(dev); unsigned char leds; switch (type) { case EV_LED: - leds = (test_bit(LED_SCROLLL, dev->led) ? 4 : 0) - | (test_bit(LED_NUML, dev->led) ? 1 : 0) - | (test_bit(LED_CAPSL, dev->led) ? 2 : 0); - real_leds(leds, adbhid->id); - return 0; + leds = (test_bit(LED_SCROLLL, dev->led) ? 4 : 0) | + (test_bit(LED_NUML, dev->led) ? 1 : 0) | + (test_bit(LED_CAPSL, dev->led) ? 2 : 0); + real_leds(leds, adbhid->id); + return 0; } return -1; @@ -649,7 +649,7 @@ adb_message_handler(struct notifier_bloc switch (code) { case ADB_MSG_PRE_RESET: case ADB_MSG_POWERDOWN: - /* Stop the repeat timer. Autopoll is already off at this point */ + /* Stop the repeat timer. Autopoll is already off at this point */ { int i; for (i = 1; i < 16; i++) { @@ -699,7 +699,7 @@ adbhid_input_register(int id, int defaul hid->current_handler_id = current_handler_id; hid->mouse_kind = mouse_kind; hid->flags = 0; - input_dev->private = hid; + input_set_drvdata(input_dev, hid); input_dev->name = hid->name; input_dev->phys = hid->phys; input_dev->id.bustype = BUS_ADB; diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index cb8c264..38e815a 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -207,16 +207,7 @@ static int ucb1x00_thread(void *_ts) struct ucb1x00_ts *ts = _ts; struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); - int valid; - - /* - * We could run as a real-time thread. However, thus far - * this doesn't seem to be necessary. - */ -// tsk->policy = SCHED_FIFO; -// tsk->rt_priority = 1; - - valid = 0; + int valid = 0; add_wait_queue(&ts->irq_wait, &wait); while (!kthread_should_stop()) { @@ -300,7 +291,7 @@ static void ucb1x00_ts_irq(int idx, void static int ucb1x00_ts_open(struct input_dev *idev) { - struct ucb1x00_ts *ts = idev->private; + struct ucb1x00_ts *ts = input_get_drvdata(idev); int ret = 0; BUG_ON(ts->rtask); @@ -337,7 +328,7 @@ static int ucb1x00_ts_open(struct input_ */ static void ucb1x00_ts_close(struct input_dev *idev) { - struct ucb1x00_ts *ts = idev->private; + struct ucb1x00_ts *ts = input_get_drvdata(idev); if (ts->rtask) kthread_stop(ts->rtask); @@ -389,7 +380,6 @@ static int ucb1x00_ts_add(struct ucb1x00 ts->idev = idev; ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; - idev->private = ts; idev->name = "Touchscreen panel"; idev->id.product = ts->ucb->id; idev->open = ucb1x00_ts_open; @@ -400,6 +390,8 @@ static int ucb1x00_ts_add(struct ucb1x00 __set_bit(ABS_Y, idev->absbit); __set_bit(ABS_PRESSURE, idev->absbit); + input_set_drvdata(idev, ts); + err = input_register_device(idev); if (err) goto fail; diff --git a/include/linux/usb.h b/include/linux/usb.h index 94bd38a..56aa2ee 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -729,6 +729,22 @@ #define USB_DEVICE_VER(vend,prod,lo,hi) .bcdDevice_lo = (lo), .bcdDevice_hi = (hi) /** + * USB_DEVICE_INTERFACE_PROTOCOL - macro used to describe a usb + * device with a specific interface protocol + * @vend: the 16 bit USB Vendor ID + * @prod: the 16 bit USB Product ID + * @pr: bInterfaceProtocol value + * + * This macro is used to create a struct usb_device_id that matches a + * specific interface protocol of devices. + */ +#define USB_DEVICE_INTERFACE_PROTOCOL(vend,prod,pr) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ + .idVendor = (vend), \ + .idProduct = (prod), \ + .bInterfaceProtocol = (pr) + +/** * USB_DEVICE_INFO - macro used to describe a class of usb devices * @cl: bDeviceClass value * @sc: bDeviceSubClass value