⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 grip_mp.c

📁 h内核
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * $Id: grip_mp.c,v 1.9 2002/07/20 19:28:45 bonnland Exp $ * *  Driver for the Gravis Grip Multiport, a gamepad "hub" that *  connects up to four 9-pin digital gamepads/joysticks. *  Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5. * *  Thanks to Chris Gassib for helpful advice. * *  Copyright (c)      2002 Brian Bonnlander, Bill Soudan *  Copyright (c) 1998-2000 Vojtech Pavlik */#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/gameport.h>#include <linux/input.h>#include <linux/delay.h>#include <linux/proc_fs.h>MODULE_AUTHOR("Brian Bonnlander");MODULE_DESCRIPTION("Gravis Grip Multiport driver");MODULE_LICENSE("GPL");#ifdef GRIP_DEBUG#define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)#else#define dbg(format, arg...) do {} while (0)#endif/* * Grip multiport state */struct grip_mp {	struct gameport *gameport;	struct timer_list timer;	struct input_dev dev[4];	int mode[4];	int registered[4];	int used;	int reads;	int bads;	/* individual gamepad states */	int buttons[4];	int xaxes[4];	int yaxes[4];	int dirty[4];     /* has the state been updated? */};/* * Multiport packet interpretation */#define PACKET_FULL          0x80000000       /* packet is full                        */#define PACKET_IO_FAST       0x40000000       /* 3 bits per gameport read              */#define PACKET_IO_SLOW       0x20000000       /* 1 bit per gameport read               */#define PACKET_MP_MORE       0x04000000       /* multiport wants to send more          */#define PACKET_MP_DONE       0x02000000       /* multiport done sending                *//* * Packet status code interpretation */#define IO_GOT_PACKET        0x0100           /* Got a packet                           */#define IO_MODE_FAST         0x0200           /* Used 3 data bits per gameport read     */#define IO_SLOT_CHANGE       0x0800           /* Multiport physical slot status changed */#define IO_DONE              0x1000           /* Multiport is done sending packets      */#define IO_RETRY             0x4000           /* Try again later to get packet          */#define IO_RESET             0x8000           /* Force multiport to resend all packets  *//* * Gamepad configuration data.  Other 9-pin digital joystick devices * may work with the multiport, so this may not be an exhaustive list! * Commodore 64 joystick remains untested. */#define GRIP_INIT_DELAY         2000          /*  2 ms */#define GRIP_REFRESH_TIME       HZ/50	      /* 20 ms */#define GRIP_MODE_NONE		0#define GRIP_MODE_RESET         1#define GRIP_MODE_GP		2#define GRIP_MODE_C64		3static int grip_btn_gp[]  = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 };static int grip_btn_c64[] = { BTN_JOYSTICK, -1 };static int grip_abs_gp[]  = { ABS_X, ABS_Y, -1 };static int grip_abs_c64[] = { ABS_X, ABS_Y, -1 };static int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 };static int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 };static char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" };static const int init_seq[] = {	1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,	1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,	1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,	0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 };/* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */static int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 };static void register_slot(int i, struct grip_mp *grip);/* * Returns whether an odd or even number of bits are on in pkt. */static int bit_parity(u32 pkt){	int x = pkt ^ (pkt >> 16);	x ^= x >> 8;	x ^= x >> 4;	x ^= x >> 2;	x ^= x >> 1;	return x & 1;}/* * Poll gameport; return true if all bits set in 'onbits' are on and * all bits set in 'offbits' are off. */static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data){	int i, nloops;	nloops = gameport_time(gp, u_sec);	for (i = 0; i < nloops; i++) {		*data = gameport_read(gp);		if ((*data & onbits) == onbits &&		    (~(*data) & offbits) == offbits)			return 1;	}	dbg("gameport timed out after %d microseconds.\n", u_sec);	return 0;}/* * Gets a 28-bit packet from the multiport. * * After getting a packet successfully, commands encoded by sendcode may * be sent to the multiport. * * The multiport clock value is reflected in gameport bit B4. * * Returns a packet status code indicating whether packet is valid, the transfer * mode, and any error conditions. * * sendflags:      current I/O status * sendcode:   data to send to the multiport if sendflags is nonzero */static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet){	u8  raw_data;            /* raw data from gameport */	u8  data_mask;           /* packet data bits from raw_data */	u32 pkt;                 /* packet temporary storage */	int bits_per_read;       /* num packet bits per gameport read */	int portvals = 0;        /* used for port value sanity check */	int i;	/* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */	*packet = 0;	raw_data = gameport_read(gameport);	if (raw_data & 1) 		return IO_RETRY;	for (i = 0; i < 64; i++) {		raw_data = gameport_read(gameport);		portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */	}	if (portvals == 1) {                            /* B4, B5 off */		raw_data = gameport_read(gameport);		portvals = raw_data & 0xf0;		if (raw_data & 0x31)			return IO_RESET;		gameport_trigger(gameport);		if (!poll_until(0x10, 0, 308, gameport, &raw_data))			return IO_RESET;	} else		return IO_RETRY;	/* Determine packet transfer mode and prepare for packet construction. */	if (raw_data & 0x20) {                 /* 3 data bits/read */		portvals |= raw_data >> 4;     /* Compare B4-B7 before & after trigger */		if (portvals != 0xb)			return 0;		data_mask = 7;		bits_per_read = 3;		pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28;	} else {                                 /* 1 data bit/read */		data_mask = 1;		bits_per_read = 1;		pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28;	}	/* Construct a packet.  Final data bits must be zero. */	while (1) {		if (!poll_until(0, 0x10, 77, gameport, &raw_data))			return IO_RESET;		raw_data = (raw_data >> 5) & data_mask;		if (pkt & PACKET_FULL)			break;		pkt = (pkt << bits_per_read) | raw_data;		if (!poll_until(0x10, 0, 77, gameport, &raw_data))			return IO_RESET;	}	if (raw_data)		return IO_RESET;	/* If 3 bits/read used, drop from 30 bits to 28. */	if (bits_per_read == 3) {		pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff);		pkt = (pkt >> 2) | 0xf0000000;	}	if (bit_parity(pkt) == 1)		return IO_RESET;	/* Acknowledge packet receipt */	if (!poll_until(0x30, 0, 77, gameport, &raw_data))		return IO_RESET;	raw_data = gameport_read(gameport);	if (raw_data & 1)		return IO_RESET;	gameport_trigger(gameport);	if (!poll_until(0, 0x20, 77, gameport, &raw_data))		return IO_RESET;        /* Return if we just wanted the packet or multiport wants to send more */	*packet = pkt;	if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE)))		return IO_GOT_PACKET;	if (pkt & PACKET_MP_MORE)		return IO_GOT_PACKET | IO_RETRY;	/* Multiport is done sending packets and is ready to receive data */	if (!poll_until(0x20, 0, 77, gameport, &raw_data))		return IO_GOT_PACKET | IO_RESET;	raw_data = gameport_read(gameport);	if (raw_data & 1)		return IO_GOT_PACKET | IO_RESET;	/* Trigger gameport based on bits in sendcode */	gameport_trigger(gameport);	do {		if (!poll_until(0x20, 0x10, 116, gameport, &raw_data))			return IO_GOT_PACKET | IO_RESET;		if (!poll_until(0x30, 0, 193, gameport, &raw_data))			return IO_GOT_PACKET | IO_RESET;		if (raw_data & 1)			return IO_GOT_PACKET | IO_RESET;		if (sendcode & 1)			gameport_trigger(gameport);		sendcode >>= 1;	} while (sendcode);	return IO_GOT_PACKET | IO_MODE_FAST;}/* * Disables and restores interrupts for mp_io(), which does the actual I/O. */static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet){	int status;	unsigned long flags;	local_irq_save(flags);	status = mp_io(gameport, sendflags, sendcode, packet);	local_irq_restore(flags);	return status;}/* * Puts multiport into digital mode.  Multiport LED turns green. * * Returns true if a valid digital packet was received, false otherwise. */static int dig_mode_start(struct gameport *gameport, u32 *packet){	int i, seq_len = sizeof(init_seq)/sizeof(int);	int flags, tries = 0, bads = 0;	for (i = 0; i < seq_len; i++) {     /* Send magic sequence */		if (init_seq[i])			gameport_trigger(gameport);		udelay(GRIP_INIT_DELAY);	}	for (i = 0; i < 16; i++)            /* Wait for multiport to settle */		udelay(GRIP_INIT_DELAY);	while (tries < 64 && bads < 8) {    /* Reset multiport and try getting a packet */		flags = multiport_io(gameport, IO_RESET, 0x27, packet);		if (flags & IO_MODE_FAST)			return 1;		if (flags & IO_RETRY)			tries++;

⌨️ 快捷键说明

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