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

📄 hid-pidff.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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 */static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n){	pidff->effect_operation[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;	if (n == 0) {		pidff->effect_operation_status->value[0] =			pidff->operation_id[PID_EFFECT_STOP];	} else {		pidff->effect_operation_status->value[0] =			pidff->operation_id[PID_EFFECT_START];		pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;	}	usbhid_wait_io(pidff->hid);	usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],			  USB_DIR_OUT);}/** * Play the effect with effect id @effect_id for @value times */static int pidff_playback(struct input_dev *dev, int effect_id, int value){	struct pidff_device *pidff = dev->ff->private;	pidff_playback_pid(pidff, pidff->pid_id[effect_id], value);	return 0;}/* * Erase effect with PID id */static void pidff_erase_pid(struct pidff_device *pidff, int pid_id){	pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;	usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],			  USB_DIR_OUT);}/* * Stop and erase effect with effect_id */static int pidff_erase_effect(struct input_dev *dev, int effect_id){	struct pidff_device *pidff = dev->ff->private;	int pid_id = pidff->pid_id[effect_id];	debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);	pidff_playback_pid(pidff, pid_id, 0);	pidff_erase_pid(pidff, pid_id);	return 0;}/* * Effect upload handler */static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,			       struct ff_effect *old){	struct pidff_device *pidff = dev->ff->private;	int type_id;	int error;	switch (effect->type) {	case FF_CONSTANT:		if (!old) {			error = pidff_request_effect_upload(pidff,					pidff->type_id[PID_CONSTANT]);			if (error)				return error;		}		if (!old || pidff_needs_set_effect(effect, old))			pidff_set_effect_report(pidff, effect);		if (!old || pidff_needs_set_constant(effect, old))			pidff_set_constant_force_report(pidff, effect);		if (!old ||		    pidff_needs_set_envelope(&effect->u.constant.envelope,					&old->u.constant.envelope))			pidff_set_envelope_report(pidff,					&effect->u.constant.envelope);		break;	case FF_PERIODIC:		if (!old) {			switch (effect->u.periodic.waveform) {			case FF_SQUARE:				type_id = PID_SQUARE;				break;			case FF_TRIANGLE:				type_id = PID_TRIANGLE;				break;			case FF_SINE:				type_id = PID_SINE;				break;			case FF_SAW_UP:				type_id = PID_SAW_UP;				break;			case FF_SAW_DOWN:				type_id = PID_SAW_DOWN;				break;			default:				printk(KERN_ERR				       "hid-pidff: invalid waveform\n");				return -EINVAL;			}			error = pidff_request_effect_upload(pidff,					pidff->type_id[type_id]);			if (error)				return error;		}		if (!old || pidff_needs_set_effect(effect, old))			pidff_set_effect_report(pidff, effect);		if (!old || pidff_needs_set_periodic(effect, old))			pidff_set_periodic_report(pidff, effect);		if (!old ||		    pidff_needs_set_envelope(&effect->u.periodic.envelope,					&old->u.periodic.envelope))			pidff_set_envelope_report(pidff,					&effect->u.periodic.envelope);		break;	case FF_RAMP:		if (!old) {			error = pidff_request_effect_upload(pidff,					pidff->type_id[PID_RAMP]);			if (error)				return error;		}		if (!old || pidff_needs_set_effect(effect, old))			pidff_set_effect_report(pidff, effect);		if (!old || pidff_needs_set_ramp(effect, old))			pidff_set_ramp_force_report(pidff, effect);		if (!old ||		    pidff_needs_set_envelope(&effect->u.ramp.envelope,					&old->u.ramp.envelope))			pidff_set_envelope_report(pidff,					&effect->u.ramp.envelope);		break;	case FF_SPRING:		if (!old) {			error = pidff_request_effect_upload(pidff,					pidff->type_id[PID_SPRING]);			if (error)				return error;		}		if (!old || pidff_needs_set_effect(effect, old))			pidff_set_effect_report(pidff, effect);		if (!old || pidff_needs_set_condition(effect, old))			pidff_set_condition_report(pidff, effect);		break;	case FF_FRICTION:		if (!old) {			error = pidff_request_effect_upload(pidff,					pidff->type_id[PID_FRICTION]);			if (error)				return error;		}		if (!old || pidff_needs_set_effect(effect, old))			pidff_set_effect_report(pidff, effect);		if (!old || pidff_needs_set_condition(effect, old))			pidff_set_condition_report(pidff, effect);		break;	case FF_DAMPER:		if (!old) {			error = pidff_request_effect_upload(pidff,					pidff->type_id[PID_DAMPER]);			if (error)				return error;		}		if (!old || pidff_needs_set_effect(effect, old))			pidff_set_effect_report(pidff, effect);		if (!old || pidff_needs_set_condition(effect, old))			pidff_set_condition_report(pidff, effect);		break;	case FF_INERTIA:		if (!old) {			error = pidff_request_effect_upload(pidff,					pidff->type_id[PID_INERTIA]);			if (error)				return error;		}		if (!old || pidff_needs_set_effect(effect, old))			pidff_set_effect_report(pidff, effect);		if (!old || pidff_needs_set_condition(effect, old))			pidff_set_condition_report(pidff, effect);		break;	default:		printk(KERN_ERR "hid-pidff: invalid type\n");		return -EINVAL;	}	if (!old)		pidff->pid_id[effect->id] =		    pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];	debug("uploaded");	return 0;}/* * set_gain() handler */static void pidff_set_gain(struct input_dev *dev, u16 gain){	struct pidff_device *pidff = dev->ff->private;	pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);	usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],			  USB_DIR_OUT);}static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude){	struct hid_field *field =		pidff->block_load[PID_EFFECT_BLOCK_INDEX].field;	if (!magnitude) {		pidff_playback_pid(pidff, field->logical_minimum, 0);		return;	}	pidff_playback_pid(pidff, field->logical_minimum, 1);	pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =		pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum;	pidff->set_effect_type->value[0] = pidff->type_id[PID_SPRING];	pidff->set_effect[PID_DURATION].value[0] = 0;	pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0;	pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0;	pidff_set(&pidff->set_effect[PID_GAIN], magnitude);	pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;	pidff->set_effect[PID_START_DELAY].value[0] = 0;	usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],			  USB_DIR_OUT);}/* * pidff_set_autocenter() handler */static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude){	struct pidff_device *pidff = dev->ff->private;	pidff_autocenter(pidff, magnitude);}/* * Find fields from a report and fill a pidff_usage */static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,			     struct hid_report *report, int count, int strict){	int i, j, k, found;	for (k = 0; k < count; k++) {		found = 0;		for (i = 0; i < report->maxfield; i++) {			if (report->field[i]->maxusage !=			    report->field[i]->report_count) {				debug("maxusage and report_count do not match, "				      "skipping");				continue;			}			for (j = 0; j < report->field[i]->maxusage; j++) {				if (report->field[i]->usage[j].hid ==				    (HID_UP_PID | table[k])) {					debug("found %d at %d->%d", k, i, j);					usage[k].field = report->field[i];					usage[k].value =						&report->field[i]->value[j];					found = 1;					break;				}			}			if (found)				break;		}		if (!found && strict) {			debug("failed to locate %d", k);			return -1;		}	}	return 0;}/* * Return index into pidff_reports for the given usage */static int pidff_check_usage(int usage){	int i;	for (i = 0; i < sizeof(pidff_reports); i++)		if (usage == (HID_UP_PID | pidff_reports[i]))			return i;	return -1;}/* * Find the reports and fill pidff->reports[] * report_type specifies either OUTPUT or FEATURE reports */static void pidff_find_reports(struct hid_device *hid, int report_type,			       struct pidff_device *pidff){	struct hid_report *report;	int i, ret;	list_for_each_entry(report,			    &hid->report_enum[report_type].report_list, list) {		if (report->maxfield < 1)			continue;		ret = pidff_check_usage(report->field[0]->logical);		if (ret != -1) {			debug("found usage 0x%02x from field->logical",			      pidff_reports[ret]);			pidff->reports[ret] = report;			continue;		}		/*		 * Sometimes logical collections are stacked to indicate		 * different usages for the report and the field, in which		 * case we want the usage of the parent. However, Linux HID		 * implementation hides this fact, so we have to dig it up		 * ourselves		 */		i = report->field[0]->usage[0].collection_index;		if (i <= 0 ||		    hid->collection[i - 1].type != HID_COLLECTION_LOGICAL)			continue;		ret = pidff_check_usage(hid->collection[i - 1].usage);		if (ret != -1 && !pidff->reports[ret]) {			debug("found usage 0x%02x from collection array",			      pidff_reports[ret]);			pidff->reports[ret] = report;		}	}}/* * Test if the required reports have been found */static int pidff_reports_ok(struct pidff_device *pidff){	int i;	for (i = 0; i <= PID_REQUIRED_REPORTS; i++) {		if (!pidff->reports[i]) {			debug("%d missing", i);			return 0;		}	}	return 1;}/* * Find a field with a specific usage within a report */static struct hid_field *pidff_find_special_field(struct hid_report *report,						  int usage, int enforce_min){	int i;	for (i = 0; i < report->maxfield; i++) {		if (report->field[i]->logical == (HID_UP_PID | usage) &&		    report->field[i]->report_count > 0) {			if (!enforce_min ||			    report->field[i]->logical_minimum == 1)				return report->field[i];			else {				printk(KERN_ERR "hid-pidff: logical_minimum "					"is not 1 as it should be\n");				return NULL;			}		}	}

⌨️ 快捷键说明

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