diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-25 12:38:14 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-25 12:38:14 -0700 |
commit | ce1d5b23a8d1e19866ab82bdec0dc41fde5273d8 (patch) | |
tree | 028c80655ee8853ebf607d435bc3d6ab223aef1f /drivers | |
parent | ad5e1b0f5d913d2c8bddfba81049cc07228da1a6 (diff) | |
parent | 308f0a5898033691d050374a949bbfe173987a16 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (40 commits)
Input: wacom - add support for Cintiq 20WSX
Input: ucb1400_ts - IRQ probe fix
Input: at32psif - update MODULE_AUTHOR with new email
Input: mac_hid - add lockdep annotation to emumousebtn
Input: i8042 - fix incorrect usage of strncpy and strncat
Input: bf54x-keys - add infrastructure for keypad wakeups
Input: add MODULE_ALIAS() to hotpluggable platform modules
Input: drivers/char/keyboard.c - use time_after
Input: fix ordering in joystick Makefile
Input: wm97xx-core - support use as a wakeup source
Input: wm97xx-core - use IRQF_SAMPLE_RANDOM
Input: wm97xx-core - only schedule interrupt handler if not already scheduled
Input: add Zhen Hua driver
Input: aiptek - add support for Genius G-PEN 560 tablet
Input: wacom - implement suspend and autosuspend
Input: xpad - set proper buffer length for outgoing requests
Input: omap-keypad - fix build warning
Input: gpio_keys - irq handling cleanup
Input: add PS/2 serio driver for AVR32 devices
Input: put ledstate in the keyboard notifier
...
Diffstat (limited to 'drivers')
43 files changed, 3574 insertions, 112 deletions
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 9769bf8279a..60b934adea6 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -42,6 +42,7 @@ #include <linux/input.h> #include <linux/reboot.h> #include <linux/notifier.h> +#include <linux/jiffies.h> extern void ctrl_alt_del(void); @@ -928,7 +929,8 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) if (up_flag) { if (brl_timeout) { if (!committing || - jiffies - releasestart > (brl_timeout * HZ) / 1000) { + time_after(jiffies, + releasestart + msecs_to_jiffies(brl_timeout))) { committing = pressed; releasestart = jiffies; } @@ -1238,6 +1240,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) } param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate; + param.ledstate = kbd->ledflagstate; key_map = key_maps[shift_final]; if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYCODE, ¶m) == NOTIFY_STOP || !key_map) { @@ -1286,6 +1289,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) (*k_handler[type])(vc, keysym & 0xff, !down); + param.ledstate = kbd->ledflagstate; atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, ¶m); if (type != KT_SLOCK) diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 28ddc3fdd3d..d3f8d9194f3 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -405,6 +405,9 @@ #define USB_VENDOR_ID_YEALINK 0x6993 #define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001 +#define USB_VENDOR_ID_KYE 0x0458 +#define USB_DEVICE_ID_KYE_GPEN_560 0x5003 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -698,6 +701,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_63, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_64, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560, HID_QUIRK_IGNORE }, { 0, 0 } }; diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 490918a5d19..0d3ce7a50fb 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -73,7 +73,7 @@ static void input_polled_device_work(struct work_struct *work) static int input_open_polled_device(struct input_dev *input) { - struct input_polled_dev *dev = input->private; + struct input_polled_dev *dev = input_get_drvdata(input); int error; error = input_polldev_start_workqueue(); @@ -91,7 +91,7 @@ static int input_open_polled_device(struct input_dev *input) static void input_close_polled_device(struct input_dev *input) { - struct input_polled_dev *dev = input->private; + struct input_polled_dev *dev = input_get_drvdata(input); cancel_delayed_work_sync(&dev->work); input_polldev_stop_workqueue(); @@ -151,10 +151,10 @@ int input_register_polled_device(struct input_polled_dev *dev) { struct input_dev *input = dev->input; + input_set_drvdata(input, dev); INIT_DELAYED_WORK(&dev->work, input_polled_device_work); if (!dev->poll_interval) dev->poll_interval = 500; - input->private = dev; input->open = input_open_polled_device; input->close = input_close_polled_device; diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 7c662ee594a..be5c14a5a0a 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -193,6 +193,18 @@ config JOYSTICK_TWIDJOY To compile this driver as a module, choose M here: the module will be called twidjoy. +config JOYSTICK_ZHENHUA + tristate "5-byte Zhenhua RC transmitter" + select SERIO + help + Say Y here if you have a Zhen Hua PPM-4CH transmitter which is + supplied with a ready to fly micro electric indoor helicopters + such as EasyCopter, Lama, MiniCopter, DragonFly or Jabo and want + to use it via serial cable as a joystick. + + To compile this driver as a module, choose M here: the + module will be called zhenhua. + config JOYSTICK_DB9 tristate "Multisystem, Sega Genesis, Saturn joysticks and gamepads" depends on PARPORT diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile index e855abb0cc5..fdbf8c4c287 100644 --- a/drivers/input/joystick/Makefile +++ b/drivers/input/joystick/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o obj-$(CONFIG_JOYSTICK_GRIP) += grip.o obj-$(CONFIG_JOYSTICK_GRIP_MP) += grip_mp.o obj-$(CONFIG_JOYSTICK_GUILLEMOT) += guillemot.o +obj-$(CONFIG_JOYSTICK_IFORCE) += iforce/ obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o @@ -27,5 +28,5 @@ obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o obj-$(CONFIG_JOYSTICK_TWIDJOY) += twidjoy.o obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o +obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o -obj-$(CONFIG_JOYSTICK_IFORCE) += iforce/ diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 0380597249b..52ddb04644a 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -1,5 +1,5 @@ /* - * X-Box gamepad - v0.0.6 + * X-Box gamepad driver * * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de> * 2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>, @@ -68,6 +68,8 @@ * - dance pads will map D-PAD to buttons, not axes * - pass the module paramater 'dpad_to_buttons' to force * the D-PAD to map to buttons if your pad is not detected + * + * Later changes can be tracked in SCM. */ #include <linux/kernel.h> @@ -77,7 +79,6 @@ #include <linux/module.h> #include <linux/usb/input.h> -#define DRIVER_VERSION "v0.0.6" #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>" #define DRIVER_DESC "X-Box pad driver" @@ -87,10 +88,12 @@ but we map them to axes when possible to simplify things */ #define MAP_DPAD_TO_BUTTONS 0 #define MAP_DPAD_TO_AXES 1 -#define MAP_DPAD_UNKNOWN -1 +#define MAP_DPAD_UNKNOWN 2 #define XTYPE_XBOX 0 #define XTYPE_XBOX360 1 +#define XTYPE_XBOX360W 2 +#define XTYPE_UNKNOWN 3 static int dpad_to_buttons; module_param(dpad_to_buttons, bool, S_IRUGO); @@ -107,8 +110,10 @@ static const struct xpad_device { { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX }, + { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, + { 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, @@ -135,18 +140,26 @@ static const struct xpad_device { { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, + { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, - { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_XBOX } + { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN } }; -static const signed short xpad_btn[] = { - BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, /* "analog" buttons */ +/* buttons shared with xbox and xbox360 */ +static const signed short xpad_common_btn[] = { + BTN_A, BTN_B, BTN_X, BTN_Y, /* "analog" buttons */ BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */ -1 /* terminating entry */ }; +/* original xbox controllers only */ +static const signed short xpad_btn[] = { + BTN_C, BTN_Z, /* "analog" buttons */ + -1 /* terminating entry */ +}; + /* only used if MAP_DPAD_TO_BUTTONS */ static const signed short xpad_btn_pad[] = { BTN_LEFT, BTN_RIGHT, /* d-pad left, right */ @@ -173,12 +186,27 @@ 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. */ +/* Xbox 360 has a vendor-specific class, so we cannot match it with only + * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we + * match against vendor id as well. Wired Xbox 360 devices have protocol 1, + * wireless controllers have protocol 129. */ +#define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \ + .idVendor = (vend), \ + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \ + .bInterfaceSubClass = 93, \ + .bInterfaceProtocol = (pr) +#define XPAD_XBOX360_VENDOR(vend) \ + { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \ + { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) } + static struct usb_device_id xpad_table [] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ - { USB_DEVICE_INTERFACE_PROTOCOL(0x045e, 0x028e, 1) }, /* X-Box 360 controller */ + XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */ + XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ { } }; @@ -188,10 +216,15 @@ struct usb_xpad { struct input_dev *dev; /* input device interface */ struct usb_device *udev; /* usb device */ + int pad_present; + struct urb *irq_in; /* urb for interrupt in report */ unsigned char *idata; /* input data */ dma_addr_t idata_dma; + struct urb *bulk_out; + unsigned char *bdata; + #if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS) struct urb *irq_out; /* urb for interrupt out report */ unsigned char *odata; /* output data */ @@ -227,13 +260,13 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d input_report_abs(dev, ABS_X, (__s16) le16_to_cpup((__le16 *)(data + 12))); input_report_abs(dev, ABS_Y, - (__s16) le16_to_cpup((__le16 *)(data + 14))); + ~(__s16) le16_to_cpup((__le16 *)(data + 14))); /* right stick */ input_report_abs(dev, ABS_RX, (__s16) le16_to_cpup((__le16 *)(data + 16))); input_report_abs(dev, ABS_RY, - (__s16) le16_to_cpup((__le16 *)(data + 18))); + ~(__s16) le16_to_cpup((__le16 *)(data + 18))); /* triggers left/right */ input_report_abs(dev, ABS_Z, data[10]); @@ -321,13 +354,13 @@ static void xpad360_process_packet(struct usb_xpad *xpad, input_report_abs(dev, ABS_X, (__s16) le16_to_cpup((__le16 *)(data + 6))); input_report_abs(dev, ABS_Y, - (__s16) le16_to_cpup((__le16 *)(data + 8))); + ~(__s16) le16_to_cpup((__le16 *)(data + 8))); /* right stick */ input_report_abs(dev, ABS_RX, (__s16) le16_to_cpup((__le16 *)(data + 10))); input_report_abs(dev, ABS_RY, - (__s16) le16_to_cpup((__le16 *)(data + 12))); + ~(__s16) le16_to_cpup((__le16 *)(data + 12))); /* triggers left/right */ input_report_abs(dev, ABS_Z, data[4]); @@ -336,6 +369,39 @@ static void xpad360_process_packet(struct usb_xpad *xpad, input_sync(dev); } +/* + * xpad360w_process_packet + * + * Completes a request by converting the data into events for the + * input subsystem. It is version for xbox 360 wireless controller. + * + * Byte.Bit + * 00.1 - Status change: The controller or headset has connected/disconnected + * Bits 01.7 and 01.6 are valid + * 01.7 - Controller present + * 01.6 - Headset present + * 01.1 - Pad state (Bytes 4+) valid + * + */ + +static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) +{ + /* Presence change */ + if (data[0] & 0x08) { + if (data[1] & 0x80) { + xpad->pad_present = 1; + usb_submit_urb(xpad->bulk_out, GFP_ATOMIC); + } else + xpad->pad_present = 0; + } + + /* Valid pad data */ + if (!(data[1] & 0x1)) + return; + + xpad360_process_packet(xpad, cmd, &data[4]); +} + static void xpad_irq_in(struct urb *urb) { struct usb_xpad *xpad = urb->context; @@ -358,10 +424,16 @@ static void xpad_irq_in(struct urb *urb) goto exit; } - if (xpad->xtype == XTYPE_XBOX360) + switch (xpad->xtype) { + case XTYPE_XBOX360: xpad360_process_packet(xpad, 0, xpad->idata); - else + break; + case XTYPE_XBOX360W: + xpad360w_process_packet(xpad, 0, xpad->idata); + break; + default: xpad_process_packet(xpad, 0, xpad->idata); + } exit: retval = usb_submit_urb (urb, GFP_ATOMIC); @@ -399,6 +471,23 @@ exit: __FUNCTION__, retval); } +static void xpad_bulk_out(struct urb *urb) +{ + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + break; + default: + dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + } +} + static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { struct usb_endpoint_descriptor *ep_irq_out; @@ -408,7 +497,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) return 0; xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN, - GFP_ATOMIC, &xpad->odata_dma ); + GFP_KERNEL, &xpad->odata_dma); if (!xpad->odata) goto fail1; @@ -469,6 +558,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, xpad->odata[5] = 0x00; xpad->odata[6] = 0x00; xpad->odata[7] = 0x00; + xpad->irq_out->transfer_buffer_length = 8; usb_submit_urb(xpad->irq_out, GFP_KERNEL); } @@ -477,6 +567,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data, static int xpad_init_ff(struct usb_xpad *xpad) { + if (xpad->xtype != XTYPE_XBOX360) + return 0; + input_set_capability(xpad->dev, EV_FF, FF_RUMBLE); return input_ff_create_memless(xpad->dev, NULL, xpad_play_effect); @@ -502,6 +595,7 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command) xpad->odata[0] = 0x01; xpad->odata[1] = 0x03; xpad->odata[2] = command; + xpad->irq_out->transfer_buffer_length = 3; usb_submit_urb(xpad->irq_out, GFP_KERNEL); mutex_unlock(&xpad->odata_mutex); } @@ -574,6 +668,10 @@ static int xpad_open(struct input_dev *dev) { struct usb_xpad *xpad = input_get_drvdata(dev); + /* URB was submitted in probe */ + if(xpad->xtype == XTYPE_XBOX360W) + return 0; + xpad->irq_in->dev = xpad->udev; if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) return -EIO; @@ -585,7 +683,8 @@ static void xpad_close(struct input_dev *dev) { struct usb_xpad *xpad = input_get_drvdata(dev); - usb_kill_urb(xpad->irq_in); + if(xpad->xtype != XTYPE_XBOX360W) + usb_kill_urb(xpad->irq_in); xpad_stop_output(xpad); } @@ -632,7 +731,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto fail1; xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN, - GFP_ATOMIC, &xpad->idata_dma); + GFP_KERNEL, &xpad->idata_dma); if (!xpad->idata) goto fail1; @@ -644,7 +743,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id 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->dpad_mapping = !dpad_to_buttons; + if (xpad->xtype == XTYPE_UNKNOWN) { + if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) { + if (intf->cur_altsetting->desc.bInterfaceProtocol == 129) + xpad->xtype = XTYPE_XBOX360W; + else + xpad->xtype = XTYPE_XBOX360; + } else + xpad->xtype = XTYPE_XBOX; + } xpad->dev = input_dev; usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); @@ -662,11 +770,14 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); /* 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; xpad_common_btn[i] >= 0; i++) + set_bit(xpad_common_btn[i], input_dev->keybit); + if ((xpad->xtype == XTYPE_XBOX360) || (xpad->xtype == XTYPE_XBOX360W)) for (i = 0; xpad360_btn[i] >= 0; i++) set_bit(xpad360_btn[i], input_dev->keybit); + else + for (i = 0; xpad_btn[i] >= 0; i++) + set_bit(xpad_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); @@ -703,8 +814,57 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto fail4; usb_set_intfdata(intf, xpad); + + /* + * Submit the int URB immediatly rather than waiting for open + * because we get status messages from the device whether + * or not any controllers are attached. In fact, it's + * exactly the message that a controller has arrived that + * we're waiting for. + */ + if (xpad->xtype == XTYPE_XBOX360W) { + xpad->irq_in->dev = xpad->udev; + error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); + if (error) + goto fail4; + + /* + * Setup the message to set the LEDs on the + * controller when it shows up + */ + xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL); + if(!xpad->bulk_out) + goto fail5; + + xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL); + if(!xpad->bdata) + goto fail6; + + xpad->bdata[2] = 0x08; + switch (intf->cur_altsetting->desc.bInterfaceNumber) { + case 0: + xpad->bdata[3] = 0x42; + break; + case 2: + xpad->bdata[3] = 0x43; + break; + case 4: + xpad->bdata[3] = 0x44; + break; + case 6: + xpad->bdata[3] = 0x45; + } + + ep_irq_in = &intf->cur_altsetting->endpoint[1].desc; + usb_fill_bulk_urb(xpad->bulk_out, udev, + usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress), + xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad); + } + return 0; + fail6: usb_free_urb(xpad->bulk_out); + fail5: usb_kill_urb(xpad->irq_in); fail4: usb_free_urb(xpad->irq_in); fail3: xpad_deinit_output(xpad); fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); @@ -723,6 +883,11 @@ static void xpad_disconnect(struct usb_interface *intf) xpad_led_disconnect(xpad); input_unregister_device(xpad->dev); xpad_deinit_output(xpad); + if (xpad->xtype == XTYPE_XBOX360W) { + usb_kill_urb(xpad->bulk_out); + usb_free_urb(xpad->bulk_out); + usb_kill_urb(xpad->irq_in); + } usb_free_urb(xpad->irq_in); usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); @@ -741,7 +906,7 @@ static int __init usb_xpad_init(void) { int result = usb_register(&xpad_driver); if (result == 0) - info(DRIVER_DESC ":" DRIVER_VERSION); + info(DRIVER_DESC); return result; } diff --git a/drivers/input/joystick/zhenhua.c b/drivers/input/joystick/zhenhua.c new file mode 100644 index 00000000000..b5853125c89 --- /dev/null +++ b/drivers/input/joystick/zhenhua.c @@ -0,0 +1,243 @@ +/* + * derived from "twidjoy.c" + * + * Copyright (c) 2008 Martin Kebert + * Copyright (c) 2001 Arndt Schoenewald + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2000 Mark Fletcher + * + */ + +/* + * Driver to use 4CH RC transmitter using Zhen Hua 5-byte protocol (Walkera Lama, + * EasyCopter etc.) as a joystick under Linux. + * + * RC transmitters using Zhen Hua 5-byte protocol are cheap four channels + * transmitters for control a RC planes or RC helicopters with possibility to + * connect on a serial port. + * Data coming from transmitter is in this order: + * 1. byte = synchronisation byte + * 2. byte = X axis + * 3. byte = Y axis + * 4. byte = RZ axis + * 5. byte = Z axis + * (and this is repeated) + * + * For questions or feedback regarding this driver module please contact: + * Martin Kebert <gkmarty@gmail.com> - but I am not a C-programmer nor kernel + * coder :-( + */ + +/* + * 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 + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/serio.h> +#include <linux/init.h> + +#define DRIVER_DESC "RC transmitter with 5-byte Zhen Hua protocol joystick driver" + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* + * Constants. + */ + +#define ZHENHUA_MAX_LENGTH 5 + +/* + * Zhen Hua data. + */ + +struct zhenhua { + struct input_dev *dev; + int idx; + unsigned char data[ZHENHUA_MAX_LENGTH]; + char phys[32]; +}; + + +/* bits in all incoming bytes needs to be "reversed" */ +static int zhenhua_bitreverse(int x) +{ + x = ((x & 0xaa) >> 1) | ((x & 0x55) << 1); + x = ((x & 0xcc) >> 2) | ((x & 0x33) << 2); + x = ((x & 0xf0) >> 4) | ((x & 0x0f) << 4); + return x; +} + +/* + * zhenhua_process_packet() decodes packets the driver receives from the + * RC transmitter. It updates the data accordingly. + */ + +static void zhenhua_process_packet(struct zhenhua *zhenhua) +{ + struct input_dev *dev = zhenhua->dev; + unsigned char *data = zhenhua->data; + + input_report_abs(dev, ABS_Y, data[1]); + input_report_abs(dev, ABS_X, data[2]); + input_report_abs(dev, ABS_RZ, data[3]); + input_report_abs |