xpad.c

来自「linux 内核源代码」· C语言 代码 · 共 760 行 · 第 1/2 页

C
760
字号
/* * X-Box gamepad - v0.0.6 * * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de> *               2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>, *                    Steven Toth <steve@toth.demon.co.uk>, *                    Franz Lehner <franz@caos.at>, *                    Ivan Hawkes <blackhawk@ivanhawkes.com> *               2005 Dominic Cerquetti <binary1230@yahoo.com> *               2006 Adam Buchbinder <adam.buchbinder@gmail.com> *               2007 Jan Kratochvil <honza@jikos.cz> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * This driver is based on: *  - 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 *  - Vojtech Pavlik     - iforce driver / input subsystem *  - Greg Kroah-Hartman - usb-skeleton driver *  - XBOX Linux project - extra USB id's * * TODO: *  - fine tune axes (especially trigger axes) *  - fix "analog" buttons (reported as digital now) *  - get rumble working *  - need USB IDs for other dance pads * * History: * * 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller" * * 2002-07-02 - 0.0.2 : basic working version *  - all axes and 9 of the 10 buttons work (german InterAct device) *  - the black button does not work * * 2002-07-14 - 0.0.3 : rework by Vojtech Pavlik *  - indentation fixes *  - usb + input init sequence fixes * * 2002-07-16 - 0.0.4 : minor changes, merge with Vojtech's v0.0.3 *  - verified the lack of HID and report descriptors *  - verified that ALL buttons WORK *  - fixed d-pad to axes mapping * * 2002-07-17 - 0.0.5 : simplified d-pad handling * * 2004-10-02 - 0.0.6 : DDR pad support *  - borrowed from the XBOX linux kernel *  - USB id's for commonly used dance pads are present *  - 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 */#include <linux/kernel.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/stat.h>#include <linux/module.h>#include <linux/moduleparam.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"#define XPAD_PKT_LEN 32/* xbox d-pads should map to buttons, as is required for DDR pads   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 XTYPE_XBOX        0#define XTYPE_XBOX360     1static 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");static const struct xpad_device {	u16 idVendor;	u16 idProduct;	char *name;	u8 dpad_mapping;	u8 xtype;} xpad_device[] = {	{ 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, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },	{ 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 },	{ 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },	{ 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[] = {	BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,	/* "analog" buttons */	BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */	-1						/* terminating entry */};/* only used if MAP_DPAD_TO_BUTTONS */static const signed short xpad_btn_pad[] = {	BTN_LEFT, BTN_RIGHT,		/* d-pad left, right */	BTN_0, BTN_1,			/* d-pad up, down (XXX names??) */	-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 */	ABS_Z, ABS_RZ,		/* triggers left/right */	-1			/* terminating entry */};/* only used if MAP_DPAD_TO_AXES */static const signed short xpad_abs_pad[] = {	ABS_HAT0X, ABS_HAT0Y,	/* d-pad axes */	-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 */	{ }};MODULE_DEVICE_TABLE (usb, xpad_table);struct usb_xpad {	struct input_dev *dev;		/* input device interface */	struct usb_device *udev;	/* usb device */	struct urb *irq_in;		/* urb for interrupt in report */	unsigned char *idata;		/* input data */	dma_addr_t idata_dma;#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 */	dma_addr_t odata_dma;	struct mutex odata_mutex;#endif#if defined(CONFIG_JOYSTICK_XPAD_LEDS)	struct xpad_led *led;#endif	char phys[64];			/* physical device path */	int dpad_mapping;		/* map d-pad to buttons or to axes */	int xtype;			/* type of xbox device */};/* *	xpad_process_packet * *	Completes a request by converting the data into events for the *	input subsystem. * *	The used report descriptor was taken from ITO Takayukis website: *	 http://euc.jp/periphs/xbox-controller.ja.html */static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data){	struct input_dev *dev = xpad->dev;	/* left stick */	input_report_abs(dev, ABS_X,			 (__s16) le16_to_cpup((__le16 *)(data + 12)));	input_report_abs(dev, ABS_Y,			 (__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)));	/* triggers left/right */	input_report_abs(dev, ABS_Z, data[10]);	input_report_abs(dev, ABS_RZ, data[11]);	/* digital pad */	if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {		input_report_abs(dev, ABS_HAT0X,				 !!(data[2] & 0x08) - !!(data[2] & 0x04));		input_report_abs(dev, ABS_HAT0Y,				 !!(data[2] & 0x02) - !!(data[2] & 0x01));	} else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {		input_report_key(dev, BTN_LEFT,  data[2] & 0x04);		input_report_key(dev, BTN_RIGHT, data[2] & 0x08);		input_report_key(dev, BTN_0,     data[2] & 0x01); /* up */		input_report_key(dev, BTN_1,     data[2] & 0x02); /* down */	}	/* start/back buttons and stick press left/right */	input_report_key(dev, BTN_START,  data[2] & 0x10);	input_report_key(dev, BTN_BACK,   data[2] & 0x20);	input_report_key(dev, BTN_THUMBL, data[2] & 0x40);	input_report_key(dev, BTN_THUMBR, data[2] & 0x80);	/* "analog" buttons A, B, X, Y */	input_report_key(dev, BTN_A, data[4]);	input_report_key(dev, BTN_B, data[5]);	input_report_key(dev, BTN_X, data[6]);	input_report_key(dev, BTN_Y, data[7]);	/* "analog" buttons black, white */	input_report_key(dev, BTN_C, data[8]);	input_report_key(dev, BTN_Z, data[9]);	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] & 0x08) - !!(data[2] & 0x04));		input_report_abs(dev, ABS_HAT0Y,				 !!(data[2] & 0x02) - !!(data[2] & 0x01));	} else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) {		/* dpad as buttons (right, left, down, up) */		input_report_key(dev, BTN_LEFT, data[2] & 0x04);		input_report_key(dev, BTN_RIGHT, data[2] & 0x08);		input_report_key(dev, BTN_0, data[2] & 0x01);	/* up */		input_report_key(dev, BTN_1, data[2] & 0x02);	/* down */	}	/* start/back buttons */	input_report_key(dev, BTN_START,  data[2] & 0x10);	input_report_key(dev, BTN_BACK,   data[2] & 0x20);	/* 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);	input_report_key(dev, BTN_B,	data[3] & 0x20);	input_report_key(dev, BTN_X,	data[3] & 0x40);	input_report_key(dev, BTN_Y,	data[3] & 0x80);	input_report_key(dev, BTN_TL,	data[3] & 0x01);	input_report_key(dev, BTN_TR,	data[3] & 0x02);	input_report_key(dev, BTN_MODE,	data[3] & 0x04);	/* left stick */	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)));	/* 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)));	/* 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;	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;	}	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);	if (retval)		err ("%s - usb_submit_urb failed with result %d",		     __FUNCTION__, retval);}#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)static void xpad_irq_out(struct urb *urb){	int retval;	switch (urb->status) {		case 0:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?