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

📄 hid.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * $Id: hid.c,v 1.16 2000/09/18 21:38:55 vojtech Exp $ * *  Copyright (c) 1999 Andreas Gal *  Copyright (c) 2000 Vojtech Pavlik * *  USB HID support for the Linux input drivers * *  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/module.h>#include <linux/malloc.h>#include <linux/input.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/list.h>#include <linux/mm.h>#include <linux/smp_lock.h>#include <linux/spinlock.h>#undef DEBUG#undef DEBUG_DATA#include <linux/usb.h>#include <asm/unaligned.h>#include "hid.h"#ifdef DEBUG#include "hid-debug.h"#else#define hid_dump_input(a,b)	do { } while (0)#define hid_dump_device(c)	do { } while (0)#endif#define unk	KEY_UNKNOWNstatic unsigned char hid_keyboard[256] = {	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,	 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,	 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95,	120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113,	115,114,unk,unk,unk,124,unk,181,182,183,184,185,186,187,188,189,	190,191,192,193,194,195,196,197,198,unk,unk,unk,unk,unk,unk,unk,	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,	150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk};static struct {	__s32 x;	__s32 y;}  hid_hat_to_axis[] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}, { 0, 0}};static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",				"Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};/* * Register a new report for a device. */static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id){	struct hid_report_enum *report_enum = device->report_enum + type;	struct hid_report *report;	 	if (report_enum->report_id_hash[id])		return report_enum->report_id_hash[id];	if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL)))		return NULL;	memset(report, 0, sizeof(struct hid_report));	if (id != 0) report_enum->numbered = 1;	report->id = id;	report->type = type;	report->size = 0;	report->device = device;	report_enum->report_id_hash[id] = report;	list_add_tail(&report->list, &report_enum->report_list);	return report;}/* * Register a new field for this report. */static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values){	if (report->maxfield < HID_MAX_FIELDS) {		struct hid_field *field;		if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)				+ values * sizeof(unsigned), GFP_KERNEL)))			return NULL;		memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)				+ values * sizeof(unsigned));		report->field[report->maxfield++] = field;		field->usage = (struct hid_usage *)(field + 1);		field->value = (unsigned *)(field->usage + usages);		field->report = report;		return field;	}	dbg("too many fields in report");	return NULL;}/* * Open a collection. The type/usage is pushed on the stack. */static int open_collection(struct hid_parser *parser, unsigned type){	unsigned usage;	usage = parser->local.usage[0];	if (type == HID_COLLECTION_APPLICATION && !parser->device->application)		parser->device->application = usage;	if (parser->collection_stack_ptr < HID_COLLECTION_STACK_SIZE) { /* PUSH on stack */		struct hid_collection *collection = parser->collection_stack + parser->collection_stack_ptr++;		collection->type = type;		collection->usage = usage;		return 0;	}	dbg("collection stack overflow");	return -1;}/* * Close a collection. */static int close_collection(struct hid_parser *parser){	if (parser->collection_stack_ptr > 0) {	/* POP from stack */		parser->collection_stack_ptr--;		return 0;	}	dbg("collection stack underflow");	return -1;}/* * Climb up the stack, search for the specified collection type * and return the usage. */static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type){	int n;	for (n = parser->collection_stack_ptr - 1; n >= 0; n--)		if (parser->collection_stack[n].type == type)			return parser->collection_stack[n].usage;	return 0; /* we know nothing about this usage type */}/* * Add a usage to the temporary parser table. */static int hid_add_usage(struct hid_parser *parser, unsigned usage){	if (parser->local.usage_index >= HID_MAX_USAGES) {		dbg("usage index exceeded");		return -1;	}	parser->local.usage[parser->local.usage_index++] = usage;	return 0;}/* * Register a new field for this report. */static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags){	struct hid_report *report;	struct hid_field *field;	int usages;	unsigned offset;	int i;	if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {    		dbg("hid_register_report failed");		return -1;	}	if (HID_MAIN_ITEM_VARIABLE & ~flags) { /* ARRAY */		if (parser->global.logical_maximum <= parser->global.logical_minimum) {			dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);			return -1;		}		usages = parser->local.usage_index;		/* Hint: we can assume usages < MAX_USAGE here */	} else { /* VARIABLE */		usages = parser->global.report_count;	}	offset = report->size;	report->size += parser->global.report_size *			parser->global.report_count;	if (usages == 0)		return 0; /* ignore padding fields */	if ((field = hid_register_field(report, usages,			     parser->global.report_count)) == NULL)		return 0;	field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);	field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);	for (i = 0; i < usages; i++) field->usage[i].hid = parser->local.usage[i];	field->maxusage = usages;	field->flags = flags;	field->report_offset = offset;	field->report_type = report_type;	field->report_size = parser->global.report_size;	field->report_count = parser->global.report_count;	field->logical_minimum = parser->global.logical_minimum;	field->logical_maximum = parser->global.logical_maximum;	field->physical_minimum = parser->global.physical_minimum;	field->physical_maximum = parser->global.physical_maximum;	field->unit_exponent = parser->global.unit_exponent;	field->unit = parser->global.unit;	return 0;}/* * Read data value from item. */static __inline__ __u32 item_udata(struct hid_item *item){	switch (item->size) {		case 1: return item->data.u8;		case 2: return item->data.u16;		case 4: return item->data.u32;	}	return 0;}static __inline__ __s32 item_sdata(struct hid_item *item){	switch (item->size) {		case 1: return item->data.s8;		case 2: return item->data.s16;		case 4: return item->data.s32;	}	return 0;}/* * Process a global item. */static int hid_parser_global(struct hid_parser *parser, struct hid_item *item){	switch (item->tag) {		case HID_GLOBAL_ITEM_TAG_PUSH:			if (parser->global_stack_ptr < HID_GLOBAL_STACK_SIZE) {				memcpy(parser->global_stack + parser->global_stack_ptr++,					&parser->global, sizeof(struct hid_global));				return 0;			}			dbg("global enviroment stack overflow");			return -1;		case HID_GLOBAL_ITEM_TAG_POP:			if (parser->global_stack_ptr > 0) {				memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,					sizeof(struct hid_global));				return 0;			}			dbg("global enviroment stack underflow");			return -1;		case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:			parser->global.usage_page = item_udata(item);			return 0;		case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:			parser->global.logical_minimum = item_sdata(item);			return 0;		case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:			parser->global.logical_maximum = item_sdata(item);			return 0;		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:			parser->global.physical_minimum = item_sdata(item);			return 0;		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:			parser->global.physical_maximum = item_sdata(item);			return 0;		case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:			parser->global.unit_exponent = item_udata(item);			return 0;		case HID_GLOBAL_ITEM_TAG_UNIT:			parser->global.unit = item_udata(item);			return 0;		case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:			if ((parser->global.report_size = item_udata(item)) > 32) {				dbg("invalid report_size %d", parser->global.report_size);				return -1;			}			return 0;		case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:			if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {				dbg("invalid report_count %d", parser->global.report_count);				return -1;			}			return 0;		case HID_GLOBAL_ITEM_TAG_REPORT_ID:			if ((parser->global.report_id = item_udata(item)) == 0) {				dbg("report_id 0 is invalid");				return -1;			}			return 0;		default:			dbg("unknown global tag 0x%x", item->tag);			return -1;	}}/* * Process a local item. */static int hid_parser_local(struct hid_parser *parser, struct hid_item *item){	__u32 data;	if (item->size == 0) {		dbg("item data expected for local item");		return -1;	}	data = item_udata(item);	switch (item->tag) {		case HID_LOCAL_ITEM_TAG_DELIMITER:			if (data) {				/*				 * We treat items before the first delimiter				 * as global to all usage sets (branch 0).				 * In the moment we process only these global				 * items and the first delimiter set.				 */				if (parser->local.delimiter_depth != 0) {					dbg("nested delimiters");					return -1;				}				parser->local.delimiter_depth++;				parser->local.delimiter_branch++;			} else {				if (parser->local.delimiter_depth < 1) {					dbg("bogus close delimiter");					return -1;				}				parser->local.delimiter_depth--;			}			return 1;		case HID_LOCAL_ITEM_TAG_USAGE:			if (parser->local.delimiter_branch < 2) {				if (item->size <= 2)					data = (parser->global.usage_page << 16) + data;				return hid_add_usage(parser, data);			}			dbg("alternative usage ignored");			return 0;		case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:			if (parser->local.delimiter_branch < 2) {				if (item->size <= 2)					data = (parser->global.usage_page << 16) + data;				parser->local.usage_minimum = data;				return 0;			}			dbg("alternative usage ignored");			return 0;		case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:			if (parser->local.delimiter_branch < 2) {				unsigned n;				if (item->size <= 2)					data = (parser->global.usage_page << 16) + data;				for (n = parser->local.usage_minimum; n <= data; n++)					if (hid_add_usage(parser, n)) {						dbg("hid_add_usage failed\n");						return -1;					}				return 0;			}			dbg("alternative usage ignored");			return 0;		default:			dbg("unknown local item tag 0x%x", item->tag);			return 0;	}}/* * Process a main item. */static int hid_parser_main(struct hid_parser *parser, struct hid_item *item){	__u32 data;	int ret;	data = item_udata(item);		switch (item->tag) {		case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:			ret = open_collection(parser, data & 3);			break;		case HID_MAIN_ITEM_TAG_END_COLLECTION:			ret = close_collection(parser);			break;		case HID_MAIN_ITEM_TAG_INPUT:			ret = hid_add_field(parser, HID_INPUT_REPORT, data);			break;		case HID_MAIN_ITEM_TAG_OUTPUT:			ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);			break;		case HID_MAIN_ITEM_TAG_FEATURE:			ret = hid_add_field(parser, HID_FEATURE_REPORT, data);			break;		default:			dbg("unknown main item tag 0x%x", item->tag);			ret = 0;	}	memset(&parser->local, 0, sizeof(parser->local));	/* Reset the local parser environment */	return ret;}/* * Process a reserved item. */static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item){	dbg("reserved item type, tag 0x%x", item->tag);	return 0;}/* * Free a report and all registered fields. The field->usage and * field->value table's are allocated behind the field, so we need * only to free(field) itself. */static void hid_free_report(struct hid_report *report){	unsigned n;	for (n = 0; n < report->maxfield; n++)		kfree(report->field[n]);	kfree(report);}/* * Free a device structure, all reports, and all fields. */static void hid_free_device(struct hid_device *device){	unsigned i,j;

⌨️ 快捷键说明

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