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

📄 hid-core.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		case -EPIPE:		/* report not available */			break;		default:		/* error */			warn("ctrl urb status %d received", urb->status);	}	if (unplug)		usbhid->ctrltail = usbhid->ctrlhead;	else		usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);	if (usbhid->ctrlhead != usbhid->ctrltail) {		if (hid_submit_ctrl(hid)) {			clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);			wake_up(&hid->wait);		}		spin_unlock_irqrestore(&usbhid->ctrllock, flags);		return;	}	clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);	spin_unlock_irqrestore(&usbhid->ctrllock, flags);	wake_up(&hid->wait);}void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir){	int head;	unsigned long flags;	struct usbhid_device *usbhid = hid->driver_data;	if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)		return;	if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {		spin_lock_irqsave(&usbhid->outlock, flags);		if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {			spin_unlock_irqrestore(&usbhid->outlock, flags);			warn("output queue full");			return;		}		usbhid->out[usbhid->outhead] = report;		usbhid->outhead = head;		if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))			if (hid_submit_out(hid))				clear_bit(HID_OUT_RUNNING, &usbhid->iofl);		spin_unlock_irqrestore(&usbhid->outlock, flags);		return;	}	spin_lock_irqsave(&usbhid->ctrllock, flags);	if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {		spin_unlock_irqrestore(&usbhid->ctrllock, flags);		warn("control queue full");		return;	}	usbhid->ctrl[usbhid->ctrlhead].report = report;	usbhid->ctrl[usbhid->ctrlhead].dir = dir;	usbhid->ctrlhead = head;	if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))		if (hid_submit_ctrl(hid))			clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);	spin_unlock_irqrestore(&usbhid->ctrllock, flags);}static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value){	struct hid_device *hid = input_get_drvdata(dev);	struct hid_field *field;	int offset;	if (type == EV_FF)		return input_ff_event(dev, type, code, value);	if (type != EV_LED)		return -1;	if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {		warn("event field not found");		return -1;	}	hid_set_field(field, offset, value);	usbhid_submit_report(hid, field->report, USB_DIR_OUT);	return 0;}int usbhid_wait_io(struct hid_device *hid){	struct usbhid_device *usbhid = hid->driver_data;	if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&					!test_bit(HID_OUT_RUNNING, &usbhid->iofl)),					10*HZ)) {		dbg_hid("timeout waiting for ctrl or out queue to clear\n");		return -1;	}	return 0;}static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle){	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),		HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report,		ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);}static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,		unsigned char type, void *buf, int size){	int result, retries = 4;	memset(buf, 0, size);	do {		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),				USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,				(type << 8), ifnum, buf, size, USB_CTRL_GET_TIMEOUT);		retries--;	} while (result < size && retries);	return result;}int usbhid_open(struct hid_device *hid){	struct usbhid_device *usbhid = hid->driver_data;	int res;	if (!hid->open++) {		res = usb_autopm_get_interface(usbhid->intf);		if (res < 0) {			hid->open--;			return -EIO;		}	}	if (hid_start_in(hid))		hid_io_error(hid);	return 0;}void usbhid_close(struct hid_device *hid){	struct usbhid_device *usbhid = hid->driver_data;	if (!--hid->open) {		usb_kill_urb(usbhid->urbin);		usb_autopm_put_interface(usbhid->intf);	}}/* * Initialize all reports */void usbhid_init_reports(struct hid_device *hid){	struct hid_report *report;	struct usbhid_device *usbhid = hid->driver_data;	int err, ret;	list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)		usbhid_submit_report(hid, report, USB_DIR_IN);	list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)		usbhid_submit_report(hid, report, USB_DIR_IN);	err = 0;	ret = usbhid_wait_io(hid);	while (ret) {		err |= ret;		if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl))			usb_kill_urb(usbhid->urbctrl);		if (test_bit(HID_OUT_RUNNING, &usbhid->iofl))			usb_kill_urb(usbhid->urbout);		ret = usbhid_wait_io(hid);	}	if (err)		warn("timeout initializing reports");}/* * Reset LEDs which BIOS might have left on. For now, just NumLock (0x01). */static int hid_find_field_early(struct hid_device *hid, unsigned int page,    unsigned int hid_code, struct hid_field **pfield){	struct hid_report *report;	struct hid_field *field;	struct hid_usage *usage;	int i, j;	list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {		for (i = 0; i < report->maxfield; i++) {			field = report->field[i];			for (j = 0; j < field->maxusage; j++) {				usage = &field->usage[j];				if ((usage->hid & HID_USAGE_PAGE) == page &&				    (usage->hid & 0xFFFF) == hid_code) {					*pfield = field;					return j;				}			}		}	}	return -1;}static void usbhid_set_leds(struct hid_device *hid){	struct hid_field *field;	int offset;	if ((offset = hid_find_field_early(hid, HID_UP_LED, 0x01, &field)) != -1) {		hid_set_field(field, offset, 0);		usbhid_submit_report(hid, field->report, USB_DIR_OUT);	}}/* * Traverse the supplied list of reports and find the longest */static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max){	struct hid_report *report;	int size;	list_for_each_entry(report, &hid->report_enum[type].report_list, list) {		size = ((report->size - 1) >> 3) + 1;		if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered)			size++;		if (*max < size)			*max = size;	}}static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid){	struct usbhid_device *usbhid = hid->driver_data;	if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma)))		return -1;	if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma)))		return -1;	if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma)))		return -1;	if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma)))		return -1;	return 0;}static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count){	struct usbhid_device *usbhid = hid->driver_data;	struct usb_device *dev = hid_to_usb_dev(hid);	struct usb_interface *intf = usbhid->intf;	struct usb_host_interface *interface = intf->cur_altsetting;	int ret;	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),		HID_REQ_SET_REPORT,		USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,		cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf),		interface->desc.bInterfaceNumber, buf + 1, count - 1,		USB_CTRL_SET_TIMEOUT);	/* count also the report id */	if (ret > 0)		ret++;	return ret;}static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid){	struct usbhid_device *usbhid = hid->driver_data;	usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);	usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);	usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);	usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);}/* * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller * to "operational".  Without this, the ps3 controller will not report any * events. */static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum){	int result;	char *buf = kmalloc(18, GFP_KERNEL);	if (!buf)		return;	result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),				 HID_REQ_GET_REPORT,				 USB_DIR_IN | USB_TYPE_CLASS |				 USB_RECIP_INTERFACE,				 (3 << 8) | 0xf2, ifnum, buf, 17,				 USB_CTRL_GET_TIMEOUT);	if (result < 0)		err_hid("%s failed: %d\n", __func__, result);	kfree(buf);}static struct hid_device *usb_hid_configure(struct usb_interface *intf){	struct usb_host_interface *interface = intf->cur_altsetting;	struct usb_device *dev = interface_to_usbdev (intf);	struct hid_descriptor *hdesc;	struct hid_device *hid;	u32 quirks = 0;	unsigned rsize = 0;	char *rdesc;	int n, len, insize = 0;	struct usbhid_device *usbhid;	quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),			le16_to_cpu(dev->descriptor.idProduct));	/* Many keyboards and mice don't like to be polled for reports,	 * so we will always set the HID_QUIRK_NOGET flag for them. */	if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {		if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD ||			interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)				quirks |= HID_QUIRK_NOGET;	}	if (quirks & HID_QUIRK_IGNORE)		return NULL;	if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&		(interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))			return NULL;	if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&	    (!interface->desc.bNumEndpoints ||	     usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {		dbg_hid("class descriptor not present\n");		return NULL;	}	for (n = 0; n < hdesc->bNumDescriptors; n++)		if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)			rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);	if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {		dbg_hid("weird size of report descriptor (%u)\n", rsize);		return NULL;	}	if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {		dbg_hid("couldn't allocate rdesc memory\n");		return NULL;	}	hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);	if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {		dbg_hid("reading report descriptor failed\n");		kfree(rdesc);		return NULL;

⌨️ 快捷键说明

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