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

📄 hid-core.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	kfree(report);}/* * Free a device structure, all reports, and all fields. */static void hid_free_device(struct hid_device *device){	unsigned i,j;	hid_ff_exit(device);	for (i = 0; i < HID_REPORT_TYPES; i++) {		struct hid_report_enum *report_enum = device->report_enum + i;		for (j = 0; j < 256; j++) {			struct hid_report *report = report_enum->report_id_hash[j];			if (report)				hid_free_report(report);		}	}	kfree(device->rdesc);	kfree(device);}/* * Fetch a report description item from the data stream. We support long * items, though they are not used yet. */static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item){	u8 b;	if ((end - start) <= 0)		return NULL;	b = *start++;	item->type = (b >> 2) & 3;	item->tag  = (b >> 4) & 15;	if (item->tag == HID_ITEM_TAG_LONG) {		item->format = HID_ITEM_FORMAT_LONG;		if ((end - start) < 2)			return NULL;		item->size = *start++;		item->tag  = *start++;		if ((end - start) < item->size)			return NULL;		item->data.longdata = start;		start += item->size;		return start;	}	item->format = HID_ITEM_FORMAT_SHORT;	item->size = b & 3;	switch (item->size) {		case 0:			return start;		case 1:			if ((end - start) < 1)				return NULL;			item->data.u8 = *start++;			return start;		case 2:			if ((end - start) < 2)				return NULL;			item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));			start = (__u8 *)((__le16 *)start + 1);			return start;		case 3:			item->size++;			if ((end - start) < 4)				return NULL;			item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start));			start = (__u8 *)((__le32 *)start + 1);			return start;	}	return NULL;}/* * Parse a report description into a hid_device structure. Reports are * enumerated, fields are attached to these reports. */static struct hid_device *hid_parse_report(__u8 *start, unsigned size){	struct hid_device *device;	struct hid_parser *parser;	struct hid_item item;	__u8 *end;	unsigned i;	static int (*dispatch_type[])(struct hid_parser *parser,				      struct hid_item *item) = {		hid_parser_main,		hid_parser_global,		hid_parser_local,		hid_parser_reserved	};	if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))		return NULL;	if (!(device->collection = kzalloc(sizeof(struct hid_collection) *				   HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {		kfree(device);		return NULL;	}	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;	for (i = 0; i < HID_REPORT_TYPES; i++)		INIT_LIST_HEAD(&device->report_enum[i].report_list);	if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) {		kfree(device->collection);		kfree(device);		return NULL;	}	memcpy(device->rdesc, start, size);	device->rsize = size;	if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {		kfree(device->rdesc);		kfree(device->collection);		kfree(device);		return NULL;	}	parser->device = device;	end = start + size;	while ((start = fetch_item(start, end, &item)) != NULL) {		if (item.format != HID_ITEM_FORMAT_SHORT) {			dbg("unexpected long global item");			kfree(device->collection);			hid_free_device(device);			kfree(parser);			return NULL;		}		if (dispatch_type[item.type](parser, &item)) {			dbg("item %u %u %u %u parsing failed\n",				item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);			kfree(device->collection);			hid_free_device(device);			kfree(parser);			return NULL;		}		if (start == end) {			if (parser->collection_stack_ptr) {				dbg("unbalanced collection at end of report description");				kfree(device->collection);				hid_free_device(device);				kfree(parser);				return NULL;			}			if (parser->local.delimiter_depth) {				dbg("unbalanced delimiter at end of report description");				kfree(device->collection);				hid_free_device(device);				kfree(parser);				return NULL;			}			kfree(parser);			return device;		}	}	dbg("item fetching failed at offset %d\n", (int)(end - start));	kfree(device->collection);	hid_free_device(device);	kfree(parser);	return NULL;}/* * Convert a signed n-bit integer to signed 32-bit integer. Common * cases are done through the compiler, the screwed things has to be * done by hand. */static __inline__ __s32 snto32(__u32 value, unsigned n){	switch (n) {		case 8:  return ((__s8)value);		case 16: return ((__s16)value);		case 32: return ((__s32)value);	}	return value & (1 << (n - 1)) ? value | (-1 << n) : value;}/* * Convert a signed 32-bit integer to a signed n-bit integer. */static __inline__ __u32 s32ton(__s32 value, unsigned n){	__s32 a = value >> (n - 1);	if (a && a != -1)		return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;	return value & ((1 << n) - 1);}/* * Extract/implement a data field from/to a report. */static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n){	report += (offset >> 5) << 2; offset &= 31;	return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1);}static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value){	report += (offset >> 5) << 2; offset &= 31;	put_unaligned((get_unaligned((__le64*)report)		& cpu_to_le64(~((((__u64) 1 << n) - 1) << offset)))		| cpu_to_le64((__u64)value << offset), (__le64*)report);}/* * Search an array for a value. */static __inline__ int search(__s32 *array, __s32 value, unsigned n){	while (n--) {		if (*array++ == value)			return 0;	}	return -1;}static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt, struct pt_regs *regs){	hid_dump_input(usage, value);	if (hid->claimed & HID_CLAIMED_INPUT)		hidinput_hid_event(hid, field, usage, value, regs);	if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt)		hiddev_hid_event(hid, field, usage, value, regs);}/* * Analyse a received field, and fetch the data from it. The field * content is stored for next report processing (we do differential * reporting to the layer). */static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt, struct pt_regs *regs){	unsigned n;	unsigned count = field->report_count;	unsigned offset = field->report_offset;	unsigned size = field->report_size;	__s32 min = field->logical_minimum;	__s32 max = field->logical_maximum;	__s32 *value;	if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))		return;	for (n = 0; n < count; n++) {			value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :						    extract(data, offset + n * size, size);			if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */			    && value[n] >= min && value[n] <= max			    && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)				goto exit;	}	for (n = 0; n < count; n++) {		if (HID_MAIN_ITEM_VARIABLE & field->flags) {			hid_process_event(hid, field, &field->usage[n], value[n], interrupt, regs);			continue;		}		if (field->value[n] >= min && field->value[n] <= max			&& field->usage[field->value[n] - min].hid			&& search(value, field->value[n], count))				hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt, regs);		if (value[n] >= min && value[n] <= max			&& field->usage[value[n] - min].hid			&& search(field->value, value[n], count))				hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt, regs);	}	memcpy(field->value, value, count * sizeof(__s32));exit:	kfree(value);}static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_regs *regs){	struct hid_device *hid = urb->context;	struct hid_report_enum *report_enum = hid->report_enum + type;	u8 *data = urb->transfer_buffer;	int len = urb->actual_length;	struct hid_report *report;	int n, size;	if (!len) {		dbg("empty report");		return -1;	}#ifdef DEBUG_DATA	printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un");#endif	n = 0;				/* Normally report number is 0 */	if (report_enum->numbered) {	/* Device uses numbered reports, data[0] is report number */		n = *data++;		len--;	}#ifdef DEBUG_DATA	{		int i;		printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len);		for (i = 0; i < len; i++)			printk(" %02x", data[i]);		printk("\n");	}#endif	if (!(report = report_enum->report_id_hash[n])) {		dbg("undefined report_id %d received", n);		return -1;	}	size = ((report->size - 1) >> 3) + 1;	if (len < size) {		dbg("report %d is too short, (%d < %d)", report->id, len, size);		memset(data + len, 0, size - len);	}	if (hid->claimed & HID_CLAIMED_HIDDEV)		hiddev_report_event(hid, report);	for (n = 0; n < report->maxfield; n++)		hid_input_field(hid, report->field[n], data, interrupt, regs);	if (hid->claimed & HID_CLAIMED_INPUT)		hidinput_report_event(hid, report);	return 0;}/* * Input submission and I/O error handler. */static void hid_io_error(struct hid_device *hid);/* Start up the input URB */static int hid_start_in(struct hid_device *hid){	unsigned long flags;	int rc = 0;	spin_lock_irqsave(&hid->inlock, flags);	if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) &&			!test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) {		rc = usb_submit_urb(hid->urbin, GFP_ATOMIC);		if (rc != 0)			clear_bit(HID_IN_RUNNING, &hid->iofl);	}	spin_unlock_irqrestore(&hid->inlock, flags);	return rc;}/* I/O retry timer routine */static void hid_retry_timeout(unsigned long _hid){	struct hid_device *hid = (struct hid_device *) _hid;	dev_dbg(&hid->intf->dev, "retrying intr urb\n");	if (hid_start_in(hid))		hid_io_error(hid);}/* Workqueue routine to reset the device */static void hid_reset(void *_hid){	struct hid_device *hid = (struct hid_device *) _hid;	int rc_lock, rc;	dev_dbg(&hid->intf->dev, "resetting device\n");	rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf);	if (rc_lock >= 0) {		rc = usb_reset_device(hid->dev);		if (rc_lock)			usb_unlock_device(hid->dev);	}	clear_bit(HID_RESET_PENDING, &hid->iofl);	if (rc == 0) {		hid->retry_delay = 0;		if (hid_start_in(hid))			hid_io_error(hid);	} else if (!(rc == -ENODEV || rc == -EHOSTUNREACH || rc == -EINTR))		err("can't reset device, %s-%s/input%d, status %d",				hid->dev->bus->bus_name,				hid->dev->devpath,				hid->ifnum, rc);}/* Main I/O error handler */static void hid_io_error(struct hid_device *hid){	unsigned long flags;	spin_lock_irqsave(&hid->inlock, flags);	/* Stop when disconnected */	if (usb_get_intfdata(hid->intf) == NULL)		goto done;	/* When an error occurs, retry at increasing intervals */	if (hid->retry_delay == 0) {		hid->retry_delay = 13;	/* Then 26, 52, 104, 104, ... */		hid->stop_retry = jiffies + msecs_to_jiffies(1000);	} else if (hid->retry_delay < 100)		hid->retry_delay *= 2;	if (time_after(jiffies, hid->stop_retry)) {		/* Retries failed, so do a port reset */		if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) {			if (schedule_work(&hid->reset_work))				goto done;			clear_bit(HID_RESET_PENDING, &hid->iofl);		}	}	mod_timer(&hid->io_retry,			jiffies + msecs_to_jiffies(hid->retry_delay));done:	spin_unlock_irqrestore(&hid->inlock, flags);}/* * Input interrupt completion handler. */static void hid_irq_in(struct urb *urb, struct pt_regs *regs){	struct hid_device	*hid = urb->context;	int			status;	switch (urb->status) {		case 0:			/* success */			hid->retry_delay = 0;			hid_input_report(HID_INPUT_REPORT, urb, 1, regs);			break;		case -ECONNRESET:	/* unlink */		case -ENOENT:		case -ESHUTDOWN:	/* unplug */			clear_bit(HID_IN_RUNNING, &hid->iofl);			return;		case -EILSEQ:		/* protocol error or unplug */		case -EPROTO:		/* protocol error or unplug */		case -ETIMEDOUT:	/* NAK */			clear_bit(HID_IN_RUNNING, &hid->iofl);			hid_io_error(hid);			return;		default:		/* error */			warn("input irq status %d received", urb->status);	}	status = usb_submit_urb(urb, SLAB_ATOMIC);	if (status) {		clear_bit(HID_IN_RUNNING, &hid->iofl);		if (status != -EPERM) {			err("can't resubmit intr, %s-%s/input%d, status %d",					hid->dev->bus->bus_name,					hid->dev->devpath,					hid->ifnum, status);			hid_io_error(hid);		}	}}/* * Output the field into the report. */static void hid_output_field(struct hid_field *field, __u8 *data){	unsigned count = field->report_count;	unsigned offset = field->report_offset;	unsigned size = field->report_size;	unsigned n;	for (n = 0; n < count; n++) {		if (field->logical_minimum < 0)	/* signed values */			implement(data, offset + n * size, size, s32ton(field->value[n], size));		else				/* unsigned values */			implement(data, offset + n * size, size, field->value[n]);	}}/* * Create a report. */static void hid_output_report(struct hid_report *report, __u8 *data){	unsigned n;	if (report->id > 0)		*data++ = report->id;

⌨️ 快捷键说明

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