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

📄 hid-core.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	return 0;}/* * Interrupt input handler. */static void hid_irq(struct urb *urb){	if (urb->status) {		dbg("nonzero status in irq %d", urb->status);		return;	}	hid_input_report(HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, urb->context);}/* * hid_read_report() reads in report values without waiting for an irq urb. */void hid_read_report(struct hid_device *hid, struct hid_report *report){	int len = ((report->size - 1) >> 3) + 1 + hid->report_enum[report->type].numbered;	u8 data[len];	int read;	if ((read = usb_get_report(hid->dev, hid->ifnum, report->type + 1, report->id, data, len)) != len) {		dbg("reading report type %d id %d failed len %d read %d", report->type + 1, report->id, len, read);		return;	}	hid_input_report(report->type, data, len, 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. */void hid_output_report(struct hid_report *report, __u8 *data){	unsigned n;	for (n = 0; n < report->maxfield; n++)		hid_output_field(report->field[n], data);}/* * Set a field value. The report this field belongs to has to be * created and transfered to the device, to set this value in the * device. */int hid_set_field(struct hid_field *field, unsigned offset, __s32 value){	unsigned size = field->report_size;	hid_dump_input(field->usage + offset, value);	if (offset >= field->report_count) {		dbg("offset exceeds report_count");		return -1;	}	if (field->logical_minimum < 0) {		if (value != snto32(s32ton(value, size), size)) {			dbg("value %d is out of range", value);			return -1;		}	}	if (   (value > field->logical_maximum)	    || (value < field->logical_minimum)) {		dbg("value %d is invalid", value);		return -1;	}	field->value[offset] = value;	return 0;}int hid_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field){	struct hid_report_enum *report_enum = hid->report_enum + HID_OUTPUT_REPORT;	struct list_head *list = report_enum->report_list.next;	int i, j;	while (list != &report_enum->report_list) {		struct hid_report *report = (struct hid_report *) list;		list = list->next;		for (i = 0; i < report->maxfield; i++) {			*field = report->field[i];			for (j = 0; j < (*field)->maxusage; j++)				if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)					return j;		}	}	return -1;}static int hid_submit_out(struct hid_device *hid){	hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.length);	hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer;	hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr);	hid->urbout.dev = hid->dev;	if (usb_submit_urb(&hid->urbout)) {		err("usb_submit_urb(out) failed");		return -1;	}	return 0;}static void hid_ctrl(struct urb *urb){	struct hid_device *hid = urb->context;	if (urb->status)		warn("ctrl urb status %d received", urb->status);	hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);	if (hid->outhead != hid->outtail)		hid_submit_out(hid);}void hid_write_report(struct hid_device *hid, struct hid_report *report){	hid_output_report(report, hid->out[hid->outhead].buffer);	hid->out[hid->outhead].dr.value = cpu_to_le16(0x200 | report->id);	hid->out[hid->outhead].dr.length = cpu_to_le16((report->size + 7) >> 3);	hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1);	if (hid->outhead == hid->outtail)		hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);	if (hid->urbout.status != -EINPROGRESS)		hid_submit_out(hid);}int hid_open(struct hid_device *hid){	if (hid->open++)		return 0;	hid->urb.dev = hid->dev;	if (usb_submit_urb(&hid->urb))		return -EIO;	return 0;}void hid_close(struct hid_device *hid){	if (!--hid->open)		usb_unlink_urb(&hid->urb);}/* * Initialize all readable reports */void hid_init_reports(struct hid_device *hid){	int i;	struct hid_report *report;	struct hid_report_enum *report_enum;	struct list_head *list;	for (i = 0; i < HID_REPORT_TYPES; i++) {		if (i == HID_FEATURE_REPORT || i == HID_INPUT_REPORT) {			report_enum = hid->report_enum + i;			list = report_enum->report_list.next;			while (list != &report_enum->report_list) {				report = (struct hid_report *) list;				usb_set_idle(hid->dev, hid->ifnum, 0, report->id);				hid_read_report(hid, report);				list = list->next;			}		}	}}#define USB_VENDOR_ID_WACOM		0x056a#define USB_DEVICE_ID_WACOM_GRAPHIRE	0x0010#define USB_DEVICE_ID_WACOM_INTUOS	0x0020struct hid_blacklist {	__u16 idVendor;	__u16 idProduct;} hid_blacklist[] = {	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE },	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS },	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1},	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2},	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3},	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4},	{ 0, 0 }};static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum){	struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0;	struct hid_descriptor *hdesc;	struct hid_device *hid;	unsigned rsize = 0;	char *buf;	int n;	for (n = 0; hid_blacklist[n].idVendor; n++)		if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) &&			(hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL;	if (usb_get_extra_descriptor(interface, USB_DT_HID, &hdesc) && ((!interface->bNumEndpoints) ||		usb_get_extra_descriptor(&interface->endpoint[0], USB_DT_HID, &hdesc))) {			dbg("class descriptor not present\n");			return NULL;	}	for (n = 0; n < hdesc->bNumDescriptors; n++)		if (hdesc->desc[n].bDescriptorType == USB_DT_REPORT)			rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);	if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {		dbg("weird size of report descriptor (%u)", rsize);		return NULL;	}	{		__u8 rdesc[rsize];		if ((n = usb_get_class_descriptor(dev, interface->bInterfaceNumber, USB_DT_REPORT, 0, rdesc, rsize)) < 0) {			dbg("reading report descriptor failed");			return NULL;		}#ifdef DEBUG_DATA		printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);		for (n = 0; n < rsize; n++)			printk(" %02x", (unsigned) rdesc[n]);		printk("\n");#endif		if (!(hid = hid_parse_report(rdesc, rsize))) {			dbg("parsing report descriptor failed");			return NULL;		}	}	for (n = 0; n < interface->bNumEndpoints; n++) {		struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n];		int pipe, maxp;		if ((endpoint->bmAttributes & 3) != 3)		/* Not an interrupt endpoint */			continue;		if (!(endpoint->bEndpointAddress & 0x80))	/* Not an input endpoint */			continue;		pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);		maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));		FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval);		break;	}	if (n == interface->bNumEndpoints) {		dbg("couldn't find an input interrupt endpoint");		hid_free_device(hid);		return NULL;	}	hid->version = hdesc->bcdHID;	hid->country = hdesc->bCountryCode;	hid->dev = dev;	hid->ifnum = interface->bInterfaceNumber;	for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) {		hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;		hid->out[n].dr.request = USB_REQ_SET_REPORT;		hid->out[n].dr.index = cpu_to_le16(hid->ifnum);	}	hid->name[0] = 0;	if (!(buf = kmalloc(63, GFP_KERNEL)))		return NULL;	if (usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) {		strcat(hid->name, buf);		if (usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)			sprintf(hid->name, "%s %s", hid->name, buf);	} else		sprintf(hid->name, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct);	kfree(buf);	FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0),		(void*) &hid->out[0].dr, hid->out[0].buffer, 1, hid_ctrl, hid);/* * Some devices don't like this and crash. I don't know of any devices * needing this, so it is disabled for now. */#if 0	if (interface->bInterfaceSubClass == 1)		usb_set_protocol(dev, hid->ifnum, 1);#endif	return hid;}static void* hid_probe(struct usb_device *dev, unsigned int ifnum,		       const struct usb_device_id *id){	struct hid_device *hid;	int i;	char *c;	dbg("HID probe called for ifnum %d", ifnum);	if (!(hid = usb_hid_configure(dev, ifnum)))		return NULL;	hid_init_reports(hid);	hid_dump_device(hid);	if (!hidinput_connect(hid))		hid->claimed |= HID_CLAIMED_INPUT;#ifdef CONFIG_USB_HIDDEV	if (!hiddev_connect(hid))		hid->claimed |= HID_CLAIMED_HIDDEV;#endif	printk(KERN_INFO);	if (hid->claimed & HID_CLAIMED_INPUT)		printk("input%d", hid->input.number);	if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))		printk(",");	if (hid->claimed & HID_CLAIMED_HIDDEV)		printk("hiddev%d", hid->minor);	c = "Device";	for (i = 0; i < hid->maxapplication; i++)		if ((hid->application[i] & 0xffff) < ARRAY_SIZE(hid_types)) {			c = hid_types[hid->application[i] & 0xffff];			break;		}	printk(": USB HID v%x.%02x %s [%s] on usb%d:%d.%d\n",		hid->version >> 8, hid->version & 0xff, c, hid->name,		dev->bus->busnum, dev->devnum, ifnum);	return hid;}static void hid_disconnect(struct usb_device *dev, void *ptr){	struct hid_device *hid = ptr;	dbg("cleanup called");	usb_unlink_urb(&hid->urb);	if (hid->claimed & HID_CLAIMED_INPUT)		hidinput_disconnect(hid);#ifdef CONFIG_USB_HIDDEV	if (hid->claimed & HID_CLAIMED_HIDDEV)		hiddev_disconnect(hid);#endif	hid_free_device(hid);}static struct usb_device_id hid_usb_ids [] = {	{ match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,	    bInterfaceClass: USB_INTERFACE_CLASS_HID },	{ }						/* Terminating entry */};MODULE_DEVICE_TABLE (usb, hid_usb_ids);static struct usb_driver hid_driver = {	name:		"hid",	probe:		hid_probe,	disconnect:	hid_disconnect,	id_table:	hid_usb_ids,};static int __init hid_init(void){#ifdef CONFIG_USB_HIDDEV	hiddev_init();#endif	usb_register(&hid_driver);	info(DRIVER_VERSION " " DRIVER_AUTHOR);	info(DRIVER_DESC);	return 0;}static void __exit hid_exit(void){#ifdef CONFIG_USB_HIDDEV	hiddev_exit();#endif	usb_deregister(&hid_driver);}module_init(hid_init);module_exit(hid_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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