1331 lines · 36.2 KB · C
RawDownload
/* *  Force feedback driver for USB HID PID compliant devices * *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com> */ /* * 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 */ /* #define DEBUG */ #define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg) #include <linux/input.h>#include <linux/usb.h> #include <linux/hid.h> #include "usbhid.h" #define	PID_EFFECTS_MAX		64 /* Report usage table used to put reports into an array */ #define PID_SET_EFFECT		0#define PID_EFFECT_OPERATION	1#define PID_DEVICE_GAIN		2#define PID_POOL		3#define PID_BLOCK_LOAD		4#define PID_BLOCK_FREE		5#define PID_DEVICE_CONTROL	6#define PID_CREATE_NEW_EFFECT	7 #define PID_REQUIRED_REPORTS	7 #define PID_SET_ENVELOPE	8#define PID_SET_CONDITION	9#define PID_SET_PERIODIC	10#define PID_SET_CONSTANT	11#define PID_SET_RAMP		12static const u8 pidff_reports[] = {	0x21, 0x77, 0x7d, 0x7f, 0x89, 0x90, 0x96, 0xab,	0x5a, 0x5f, 0x6e, 0x73, 0x74}; /* device_control is really 0x95, but 0x96 specified as it is the usage ofthe only field in that report */ /* Value usage tables used to put fields and values into arrays */ #define PID_EFFECT_BLOCK_INDEX	0 #define PID_DURATION		1#define PID_GAIN		2#define PID_TRIGGER_BUTTON	3#define PID_TRIGGER_REPEAT_INT	4#define PID_DIRECTION_ENABLE	5#define PID_START_DELAY		6static const u8 pidff_set_effect[] = {	0x22, 0x50, 0x52, 0x53, 0x54, 0x56, 0xa7}; #define PID_ATTACK_LEVEL	1#define PID_ATTACK_TIME		2#define PID_FADE_LEVEL		3#define PID_FADE_TIME		4static const u8 pidff_set_envelope[] = { 0x22, 0x5b, 0x5c, 0x5d, 0x5e }; #define PID_PARAM_BLOCK_OFFSET	1#define PID_CP_OFFSET		2#define PID_POS_COEFFICIENT	3#define PID_NEG_COEFFICIENT	4#define PID_POS_SATURATION	5#define PID_NEG_SATURATION	6#define PID_DEAD_BAND		7static const u8 pidff_set_condition[] = {	0x22, 0x23, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65}; #define PID_MAGNITUDE		1#define PID_OFFSET		2#define PID_PHASE		3#define PID_PERIOD		4static const u8 pidff_set_periodic[] = { 0x22, 0x70, 0x6f, 0x71, 0x72 };static const u8 pidff_set_constant[] = { 0x22, 0x70 }; #define PID_RAMP_START		1#define PID_RAMP_END		2static const u8 pidff_set_ramp[] = { 0x22, 0x75, 0x76 }; #define PID_RAM_POOL_AVAILABLE	1static const u8 pidff_block_load[] = { 0x22, 0xac }; #define PID_LOOP_COUNT		1static const u8 pidff_effect_operation[] = { 0x22, 0x7c }; static const u8 pidff_block_free[] = { 0x22 }; #define PID_DEVICE_GAIN_FIELD	0static const u8 pidff_device_gain[] = { 0x7e }; #define PID_RAM_POOL_SIZE	0#define PID_SIMULTANEOUS_MAX	1#define PID_DEVICE_MANAGED_POOL	2static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 }; /* Special field key tables used to put special field keys into arrays */ #define PID_ENABLE_ACTUATORS	0#define PID_RESET		1static const u8 pidff_device_control[] = { 0x97, 0x9a }; #define PID_CONSTANT	0#define PID_RAMP	1#define PID_SQUARE	2#define PID_SINE	3#define PID_TRIANGLE	4#define PID_SAW_UP	5#define PID_SAW_DOWN	6#define PID_SPRING	7#define PID_DAMPER	8#define PID_INERTIA	9#define PID_FRICTION	10static const u8 pidff_effect_types[] = {	0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34,	0x40, 0x41, 0x42, 0x43}; #define PID_BLOCK_LOAD_SUCCESS	0#define PID_BLOCK_LOAD_FULL	1static const u8 pidff_block_load_status[] = { 0x8c, 0x8d }; #define PID_EFFECT_START	0#define PID_EFFECT_STOP		1static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b }; struct pidff_usage {	struct hid_field *field;	s32 *value;}; struct pidff_device {	struct hid_device *hid; 	struct hid_report *reports[sizeof(pidff_reports)]; 	struct pidff_usage set_effect[sizeof(pidff_set_effect)];	struct pidff_usage set_envelope[sizeof(pidff_set_envelope)];	struct pidff_usage set_condition[sizeof(pidff_set_condition)];	struct pidff_usage set_periodic[sizeof(pidff_set_periodic)];	struct pidff_usage set_constant[sizeof(pidff_set_constant)];	struct pidff_usage set_ramp[sizeof(pidff_set_ramp)]; 	struct pidff_usage device_gain[sizeof(pidff_device_gain)];	struct pidff_usage block_load[sizeof(pidff_block_load)];	struct pidff_usage pool[sizeof(pidff_pool)];	struct pidff_usage effect_operation[sizeof(pidff_effect_operation)];	struct pidff_usage block_free[sizeof(pidff_block_free)]; 	/* Special field is a field that is not composed of	   usage<->value pairs that pidff_usage values are */ 	/* Special field in create_new_effect */	struct hid_field *create_new_effect_type; 	/* Special fields in set_effect */	struct hid_field *set_effect_type;	struct hid_field *effect_direction; 	/* Special field in device_control */	struct hid_field *device_control; 	/* Special field in block_load */	struct hid_field *block_load_status; 	/* Special field in effect_operation */	struct hid_field *effect_operation_status; 	int control_id[sizeof(pidff_device_control)];	int type_id[sizeof(pidff_effect_types)];	int status_id[sizeof(pidff_block_load_status)];	int operation_id[sizeof(pidff_effect_operation_status)]; 	int pid_id[PID_EFFECTS_MAX];}; /* * Scale an unsigned value with range 0..max for the given field */static int pidff_rescale(int i, int max, struct hid_field *field){	return i * (field->logical_maximum - field->logical_minimum) / max +	    field->logical_minimum;} /* * Scale a signed value in range -0x8000..0x7fff for the given field */static int pidff_rescale_signed(int i, struct hid_field *field){	return i == 0 ? 0 : i >	    0 ? i * field->logical_maximum / 0x7fff : i *	    field->logical_minimum / -0x8000;} static void pidff_set(struct pidff_usage *usage, u16 value){	usage->value[0] = pidff_rescale(value, 0xffff, usage->field);	debug("calculated from %d to %d", value, usage->value[0]);} static void pidff_set_signed(struct pidff_usage *usage, s16 value){	if (usage->field->logical_minimum < 0)		usage->value[0] = pidff_rescale_signed(value, usage->field);	else {		if (value < 0)			usage->value[0] =			    pidff_rescale(-value, 0x8000, usage->field);		else			usage->value[0] =			    pidff_rescale(value, 0x7fff, usage->field);	}	debug("calculated from %d to %d", value, usage->value[0]);} /* * Send envelope report to the device */static void pidff_set_envelope_report(struct pidff_device *pidff,				      struct ff_envelope *envelope){	pidff->set_envelope[PID_EFFECT_BLOCK_INDEX].value[0] =	    pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; 	pidff->set_envelope[PID_ATTACK_LEVEL].value[0] =	    pidff_rescale(envelope->attack_level >			  0x7fff ? 0x7fff : envelope->attack_level, 0x7fff,			  pidff->set_envelope[PID_ATTACK_LEVEL].field);	pidff->set_envelope[PID_FADE_LEVEL].value[0] =	    pidff_rescale(envelope->fade_level >			  0x7fff ? 0x7fff : envelope->fade_level, 0x7fff,			  pidff->set_envelope[PID_FADE_LEVEL].field); 	pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length;	pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length; 	debug("attack %u => %d", envelope->attack_level,	      pidff->set_envelope[PID_ATTACK_LEVEL].value[0]); 	usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],			  USB_DIR_OUT);} /* * Test if the new envelope differs from old one */static int pidff_needs_set_envelope(struct ff_envelope *envelope,				    struct ff_envelope *old){	return envelope->attack_level != old->attack_level ||	       envelope->fade_level != old->fade_level ||	       envelope->attack_length != old->attack_length ||	       envelope->fade_length != old->fade_length;} /* * Send constant force report to the device */static void pidff_set_constant_force_report(struct pidff_device *pidff,					    struct ff_effect *effect){	pidff->set_constant[PID_EFFECT_BLOCK_INDEX].value[0] =		pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];	pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],			 effect->u.constant.level); 	usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],			  USB_DIR_OUT);} /* * Test if the constant parameters have changed between effects */static int pidff_needs_set_constant(struct ff_effect *effect,				    struct ff_effect *old){	return effect->u.constant.level != old->u.constant.level;} /* * Send set effect report to the device */static void pidff_set_effect_report(struct pidff_device *pidff,				    struct ff_effect *effect){	pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =		pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];	pidff->set_effect_type->value[0] =		pidff->create_new_effect_type->value[0];	pidff->set_effect[PID_DURATION].value[0] = effect->replay.length;	pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button;	pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] =		effect->trigger.interval;	pidff->set_effect[PID_GAIN].value[0] =		pidff->set_effect[PID_GAIN].field->logical_maximum;	pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;	pidff->effect_direction->value[0] =		pidff_rescale(effect->direction, 0xffff,				pidff->effect_direction);	pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay; 	usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],			  USB_DIR_OUT);} /* * Test if the values used in set_effect have changed */static int pidff_needs_set_effect(struct ff_effect *effect,				  struct ff_effect *old){	return effect->replay.length != old->replay.length ||	       effect->trigger.interval != old->trigger.interval ||	       effect->trigger.button != old->trigger.button ||	       effect->direction != old->direction ||	       effect->replay.delay != old->replay.delay;} /* * Send periodic effect report to the device */static void pidff_set_periodic_report(struct pidff_device *pidff,				      struct ff_effect *effect){	pidff->set_periodic[PID_EFFECT_BLOCK_INDEX].value[0] =		pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];	pidff_set_signed(&pidff->set_periodic[PID_MAGNITUDE],			 effect->u.periodic.magnitude);	pidff_set_signed(&pidff->set_periodic[PID_OFFSET],			 effect->u.periodic.offset);	pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);	pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period; 	usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],			  USB_DIR_OUT); } /* * Test if periodic effect parameters have changed */static int pidff_needs_set_periodic(struct ff_effect *effect,				    struct ff_effect *old){	return effect->u.periodic.magnitude != old->u.periodic.magnitude ||	       effect->u.periodic.offset != old->u.periodic.offset ||	       effect->u.periodic.phase != old->u.periodic.phase ||	       effect->u.periodic.period != old->u.periodic.period;} /* * Send condition effect reports to the device */static void pidff_set_condition_report(struct pidff_device *pidff,				       struct ff_effect *effect){	int i; 	pidff->set_condition[PID_EFFECT_BLOCK_INDEX].value[0] =		pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; 	for (i = 0; i < 2; i++) {		pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i;		pidff_set_signed(&pidff->set_condition[PID_CP_OFFSET],				 effect->u.condition[i].center);		pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT],				 effect->u.condition[i].right_coeff);		pidff_set_signed(&pidff->set_condition[PID_NEG_COEFFICIENT],				 effect->u.condition[i].left_coeff);		pidff_set(&pidff->set_condition[PID_POS_SATURATION],			  effect->u.condition[i].right_saturation);		pidff_set(&pidff->set_condition[PID_NEG_SATURATION],			  effect->u.condition[i].left_saturation);		pidff_set(&pidff->set_condition[PID_DEAD_BAND],			  effect->u.condition[i].deadband);		usbhid_wait_io(pidff->hid);		usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],				  USB_DIR_OUT);	}} /* * Test if condition effect parameters have changed */static int pidff_needs_set_condition(struct ff_effect *effect,				     struct ff_effect *old){	int i;	int ret = 0; 	for (i = 0; i < 2; i++) {		struct ff_condition_effect *cond = &effect->u.condition[i];		struct ff_condition_effect *old_cond = &old->u.condition[i]; 		ret |= cond->center != old_cond->center ||		       cond->right_coeff != old_cond->right_coeff ||		       cond->left_coeff != old_cond->left_coeff ||		       cond->right_saturation != old_cond->right_saturation ||		       cond->left_saturation != old_cond->left_saturation ||		       cond->deadband != old_cond->deadband;	} 	return ret;} /* * Send ramp force report to the device */static void pidff_set_ramp_force_report(struct pidff_device *pidff,					struct ff_effect *effect){	pidff->set_ramp[PID_EFFECT_BLOCK_INDEX].value[0] =		pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];	pidff_set_signed(&pidff->set_ramp[PID_RAMP_START],			 effect->u.ramp.start_level);	pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],			 effect->u.ramp.end_level);	usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],			  USB_DIR_OUT);} /* * Test if ramp force parameters have changed */static int pidff_needs_set_ramp(struct ff_effect *effect, struct ff_effect *old){	return effect->u.ramp.start_level != old->u.ramp.start_level ||	       effect->u.ramp.end_level != old->u.ramp.end_level;} /* * Send a request for effect upload to the device * * Returns 0 if device reported success, -ENOSPC if the device reported memory * is full. Upon unknown response the function will retry for 60 times, if * still unsuccessful -EIO is returned. */static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum){	int j; 	pidff->create_new_effect_type->value[0] = efnum;	usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],			  USB_DIR_OUT);	debug("create_new_effect sent, type: %d", efnum); 	pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;	pidff->block_load_status->value[0] = 0;	usbhid_wait_io(pidff->hid); 	for (j = 0; j < 60; j++) {		debug("pid_block_load requested");		usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],				  USB_DIR_IN);		usbhid_wait_io(pidff->hid);		if (pidff->block_load_status->value[0] ==		    pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {			debug("device reported free memory: %d bytes",			      pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?				pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);			return 0;		}		if (pidff->block_load_status->value[0] ==		    pidff->status_id[PID_BLOCK_LOAD_FULL]) {			debug("not enough memory free: %d bytes",			      pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?				pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);			return -ENOSPC;		}	}	printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n");	return -EIO;} /* * Play the effect with PID id n times

Lines 1–500 of 1331.