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

📄 iforce.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * $Id: iforce.c,v 1.56 2001/05/27 14:41:26 jdeneux Exp $ * *  Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz> *  Copyright (c) 2001 Johann Deneux <deneux@ifrance.com> * *  USB/RS232 I-Force joysticks and wheels. * *  Sponsored by SuSE *//* * 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 * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */#include <linux/kernel.h>#include <linux/slab.h>#include <linux/input.h>#include <linux/module.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/usb.h>#include <linux/serio.h>#include <linux/config.h>/* FF: This module provides arbitrary resource management routines. * I use it to manage the device's memory. * Despite the name of this module, I am *not* going to access the ioports. */#include <linux/ioport.h>MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>, Johann Deneux <deneux@ifrance.com>");MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");MODULE_LICENSE("GPL");#define IFORCE_MAX_LENGTH	16#if defined(CONFIG_INPUT_IFORCE_232) || defined(CONFIG_INPUT_IFORCE_232_MODULE)#define IFORCE_232	1#endif#if defined(CONFIG_INPUT_IFORCE_USB) || defined(CONFIG_INPUT_IFORCE_USB_MODULE)#define IFORCE_USB	2#endif#define FF_EFFECTS_MAX	32/* Each force feedback effect is made of one core effect, which can be * associated to at most to effect modifiers */#define FF_MOD1_IS_USED		0#define FF_MOD2_IS_USED		1#define FF_CORE_IS_USED		2#define FF_CORE_IS_PLAYED	3#define FF_MODCORE_MAX		3struct iforce_core_effect {	/* Information about where modifiers are stored in the device's memory */	struct resource mod1_chunk;	struct resource mod2_chunk;	unsigned long flags[NBITS(FF_MODCORE_MAX)];};#define FF_CMD_EFFECT		0x010e#define FF_CMD_SHAPE		0x0208#define FF_CMD_MAGNITUDE	0x0303#define FF_CMD_PERIOD		0x0407#define FF_CMD_INTERACT		0x050a#define FF_CMD_AUTOCENTER	0x4002#define FF_CMD_PLAY		0x4103#define FF_CMD_ENABLE		0x4201#define FF_CMD_GAIN		0x4301#define FF_CMD_QUERY		0xff01static signed short btn_joystick[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 };static signed short btn_wheel[] =    { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };static signed short abs_wheel[] =    { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 };static signed short ff_iforce[] =    { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION,	FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 };static struct iforce_device {	u16 idvendor;	u16 idproduct;	char *name;	signed short *btn;	signed short *abs;	signed short *ff;} iforce_device[] = {	{ 0x046d, 0xc281, "Logitech WingMan Force",			btn_joystick, abs_joystick, ff_iforce },	{ 0x046d, 0xc291, "Logitech WingMan Formula Force",		btn_wheel, abs_wheel, ff_iforce },	{ 0x05ef, 0x020a, "AVB Top Shot Pegasus",			btn_joystick, abs_joystick, ff_iforce },	{ 0x05ef, 0x8884, "AVB Mag Turbo Force",			btn_wheel, abs_wheel, ff_iforce },	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce },	{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }};struct iforce {	struct input_dev dev;		/* Input device interface */	struct iforce_device *type;	char name[64];	int open;	int bus;	unsigned char data[IFORCE_MAX_LENGTH];	unsigned char edata[IFORCE_MAX_LENGTH];	u16 ecmd;	u16 expect_packet;#ifdef IFORCE_232	struct serio *serio;		/* RS232 transfer */	int idx, pkt, len, id;	unsigned char csum;#endif#ifdef IFORCE_USB	struct usb_device *usbdev;	/* USB transfer */	struct urb irq, out, ctrl;	devrequest dr;#endif					/* Force Feedback */	wait_queue_head_t wait;	struct resource device_memory;	struct iforce_core_effect core_effects[FF_EFFECTS_MAX];};static struct {	__s32 x;	__s32 y;} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};/* Get hi and low bytes of a 16-bits int */#define HI(a)	((unsigned char)((a) >> 8))#define LO(a)	((unsigned char)((a) & 0xff))/* Encode a time value */#define TIME_SCALE(a)	((a) == 0xffff ? 0xffff : (a) * 1000 / 256)static void dump_packet(char *msg, u16 cmd, unsigned char *data){	int i;	printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd);	for (i = 0; i < LO(cmd); i++)		printk("%02x ", data[i]);	printk(")\n");}/* * Send a packet of bytes to the device */static void send_packet(struct iforce *iforce, u16 cmd, unsigned char* data){	switch (iforce->bus) {#ifdef IFORCE_232		case IFORCE_232: {			int i;			unsigned char csum = 0x2b ^ HI(cmd) ^ LO(cmd);			serio_write(iforce->serio, 0x2b);			serio_write(iforce->serio, HI(cmd));			serio_write(iforce->serio, LO(cmd));			for (i = 0; i < LO(cmd); i++) {				serio_write(iforce->serio, data[i]);				csum = csum ^ data[i];			}			serio_write(iforce->serio, csum);			return;		}#endif#ifdef IFORCE_USB		case IFORCE_USB: {			DECLARE_WAITQUEUE(wait, current);			int timeout = HZ; /* 1 second */			memcpy(iforce->out.transfer_buffer + 1, data, LO(cmd));			((char*)iforce->out.transfer_buffer)[0] = HI(cmd);			iforce->out.transfer_buffer_length = LO(cmd) + 2;			iforce->out.dev = iforce->usbdev;			set_current_state(TASK_INTERRUPTIBLE);			add_wait_queue(&iforce->wait, &wait);			if (usb_submit_urb(&iforce->out)) {				set_current_state(TASK_RUNNING);				remove_wait_queue(&iforce->wait, &wait);				return;			}			while (timeout && iforce->out.status == -EINPROGRESS)				timeout = schedule_timeout(timeout);			set_current_state(TASK_RUNNING);			remove_wait_queue(&iforce->wait, &wait);			if (!timeout)				usb_unlink_urb(&iforce->out);			return;		}#endif	}}static void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data){	struct input_dev *dev = &iforce->dev;	int i;#ifdef IFORCE_232	if (HI(iforce->expect_packet) == HI(cmd)) {		iforce->expect_packet = 0;		iforce->ecmd = cmd;		memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);		if (waitqueue_active(&iforce->wait))			wake_up(&iforce->wait);	}#endif	if (!iforce->type)		return;	switch (HI(cmd)) {		case 0x01:	/* joystick position data */		case 0x03:	/* wheel position data */			if (HI(cmd) == 1) {				input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));				input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));				input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);			} else {				input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));				input_report_abs(dev, ABS_GAS,   255 - data[2]);				input_report_abs(dev, ABS_BRAKE, 255 - data[3]);			}			input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);			input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);			for (i = 0; iforce->type->btn[i] >= 0; i++)				input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));			break;		case 0x02:	/* status report */			input_report_key(dev, BTN_DEAD, data[0] & 0x02);			break;	}}static int get_id_packet(struct iforce *iforce, char *packet){	DECLARE_WAITQUEUE(wait, current);	int timeout = HZ; /* 1 second */	switch (iforce->bus) {#ifdef IFORCE_USB		case IFORCE_USB:			iforce->dr.request = packet[0];			iforce->ctrl.dev = iforce->usbdev;			set_current_state(TASK_INTERRUPTIBLE);			add_wait_queue(&iforce->wait, &wait);			if (usb_submit_urb(&iforce->ctrl)) {				set_current_state(TASK_RUNNING);				remove_wait_queue(&iforce->wait, &wait);				return -1;			}			while (timeout && iforce->ctrl.status == -EINPROGRESS)				timeout = schedule_timeout(timeout);			set_current_state(TASK_RUNNING);			remove_wait_queue(&iforce->wait, &wait);			if (!timeout) {				usb_unlink_urb(&iforce->ctrl);				return -1;			}			break;#endif#ifdef IFORCE_232		case IFORCE_232:			iforce->expect_packet = FF_CMD_QUERY;			send_packet(iforce, FF_CMD_QUERY, packet);			set_current_state(TASK_INTERRUPTIBLE);			add_wait_queue(&iforce->wait, &wait);			while (timeout && iforce->expect_packet)				timeout = schedule_timeout(timeout);			set_current_state(TASK_RUNNING);			remove_wait_queue(&iforce->wait, &wait);			if (!timeout) {				iforce->expect_packet = 0;				return -1;			}			break;#endif	}	return -(iforce->edata[0] != packet[0]);}static int iforce_open(struct input_dev *dev){	struct iforce *iforce = dev->private;	switch (iforce->bus) {#ifdef IFORCE_USB		case IFORCE_USB:			if (iforce->open++)				break;			iforce->irq.dev = iforce->usbdev;			if (usb_submit_urb(&iforce->irq))					return -EIO;			break;#endif	}	return 0;}static void iforce_close(struct input_dev *dev){	struct iforce *iforce = dev->private;	switch (iforce->bus) {#ifdef IFORCE_USB		case IFORCE_USB:			if (!--iforce->open)				usb_unlink_urb(&iforce->irq);			break;#endif	}}/* * Start or stop playing an effect */static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value){	struct iforce* iforce = (struct iforce*)(dev->private);	unsigned char data[3];	printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value);	if (type != EV_FF)		return -1;	switch (code) {		case FF_GAIN:			data[0] = value >> 9;			send_packet(iforce, FF_CMD_GAIN, data);			return 0;		case FF_AUTOCENTER:			data[0] = 0x03;			data[1] = value >> 9;			send_packet(iforce, FF_CMD_AUTOCENTER, data);			data[0] = 0x04;			data[1] = 0x01;			send_packet(iforce, FF_CMD_AUTOCENTER, data);			return 0;		default: /* Play an effect */			if (code >= iforce->dev.ff_effects_max)				return -1;			data[0] = LO(code);			data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;			data[2] = LO(value);			send_packet(iforce, FF_CMD_PLAY, data);			return 0;	}	return -1;}/* * Set the magnitude of a constant force effect * Return error code * * Note: caller must ensure exclusive access to device */static int make_magnitude_modifier(struct iforce* iforce,	struct resource* mod_chunk, __s16 level){	unsigned char data[3];	if (allocate_resource(&(iforce->device_memory), mod_chunk, 2,		iforce->device_memory.start, iforce->device_memory.end, 2L,		NULL, NULL)) {		return -ENOMEM;	}	data[0] = LO(mod_chunk->start);	data[1] = HI(mod_chunk->start);	data[2] = HI(level);	send_packet(iforce, FF_CMD_MAGNITUDE, data);	return 0;}/* * Upload the component of an effect dealing with the period, phase and magnitude */static int make_period_modifier(struct iforce* iforce, struct resource* mod_chunk,	__s16 magnitude, __s16 offset, u16 period, u16 phase){	unsigned char data[7];	period = TIME_SCALE(period);	if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c,		iforce->device_memory.start, iforce->device_memory.end, 2L,		NULL, NULL)) {		return -ENOMEM;	}	data[0] = LO(mod_chunk->start);	data[1] = HI(mod_chunk->start);	data[2] = HI(magnitude);	data[3] = HI(offset);	data[4] = HI(phase);	data[5] = LO(period);	data[6] = HI(period);	send_packet(iforce, FF_CMD_PERIOD, data);	return 0;}/* * Uploads the part of an effect setting the shape of the force */static int make_shape_modifier(struct iforce* iforce, struct resource* mod_chunk,	u16 attack_duration, __s16 initial_level,	u16 fade_duration, __s16 final_level){	unsigned char data[8];	attack_duration = TIME_SCALE(attack_duration);	fade_duration = TIME_SCALE(fade_duration);	if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e,		iforce->device_memory.start, iforce->device_memory.end, 2L,		NULL, NULL)) {		return -ENOMEM;	}	data[0] = LO(mod_chunk->start);	data[1] = HI(mod_chunk->start);	data[2] = LO(attack_duration);	data[3] = HI(attack_duration);	data[4] = HI(initial_level);	data[5] = LO(fade_duration);	data[6] = HI(fade_duration);	data[7] = HI(final_level);	send_packet(iforce, FF_CMD_SHAPE, data);	return 0;}/* * Component of spring, friction, inertia... effects */static int make_interactive_modifier(struct iforce* iforce,	struct resource* mod_chunk,	__s16 rsat, __s16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center){	unsigned char data[10];	if (allocate_resource(&(iforce->device_memory), mod_chunk, 8,		iforce->device_memory.start, iforce->device_memory.end, 2L,		NULL, NULL)) {		return -ENOMEM;	}	data[0] = LO(mod_chunk->start);	data[1] = HI(mod_chunk->start);	data[2] = HI(rk);	data[3] = HI(lk);	data[4] = LO(center);	data[5] = HI(center);	data[6] = LO(db);	data[7] = HI(db);	data[8] = HI(rsat);	data[9] = HI(lsat);	send_packet(iforce, FF_CMD_INTERACT, data);	return 0;}static unsigned char find_button(struct iforce *iforce, signed short button){	int i;	for (i = 1; iforce->type->btn[i] >= 0; i++)		if (iforce->type->btn[i] == button)			return i + 1;	return 0;}/* * Send the part common to all effects to the device */static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2,	u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button,	u16 interval, u16 direction){	unsigned char data[14];	duration = TIME_SCALE(duration);	delay    = TIME_SCALE(delay);	interval = TIME_SCALE(interval);	data[0]  = LO(id);	data[1]  = effect_type;	data[2]  = LO(axes) | find_button(iforce, button);	data[3]  = LO(duration);	data[4]  = HI(duration);	data[5]  = HI(direction);	data[6]  = LO(interval);	data[7]  = HI(interval);	data[8]  = LO(mod_id1);	data[9]  = HI(mod_id1);	data[10] = LO(mod_id2);	data[11] = HI(mod_id2);	data[12] = LO(delay);	data[13] = HI(delay);	send_packet(iforce, FF_CMD_EFFECT, data);	return 0;}/* * Upload a periodic effect to the device

⌨️ 快捷键说明

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