drivers/usb/gadget/function/f_hid.c

Source file repositories/reference/linux-study-clean/drivers/usb/gadget/function/f_hid.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/gadget/function/f_hid.c
Extension
.c
Size
44291 bytes
Lines
1701
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct file_operations f_hidg_fops = {
	.owner		= THIS_MODULE,
	.open		= f_hidg_open,
	.release	= f_hidg_release,
	.write		= f_hidg_write,
	.read		= f_hidg_read,
	.poll		= f_hidg_poll,
	.unlocked_ioctl	= f_hidg_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = f_hidg_compat_ioctl,
#endif
	.llseek		= noop_llseek,
};

static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_ep		*ep;
	struct f_hidg		*hidg = func_to_hidg(f);
	struct usb_string	*us;
	int			status;

	hidg->get_req = usb_ep_alloc_request(c->cdev->gadget->ep0, GFP_ATOMIC);
	if (!hidg->get_req)
		return -ENOMEM;

	hidg->get_req->zero = 0;
	hidg->get_req->complete = hidg_get_report_complete;
	hidg->get_req->context = hidg;
	hidg->get_report_returned = true;

	/* maybe allocate device-global string IDs, and patch descriptors */
	us = usb_gstrings_attach(c->cdev, ct_func_strings,
				 ARRAY_SIZE(ct_func_string_defs));
	if (IS_ERR(us))
		return PTR_ERR(us);
	hidg_interface_desc.iInterface = us[CT_FUNC_HID_IDX].id;

	/* allocate instance-specific interface IDs, and patch descriptors */
	status = usb_interface_id(c, f);
	if (status < 0)
		goto fail;
	hidg_interface_desc.bInterfaceNumber = status;

	/* allocate instance-specific endpoints */
	status = -ENODEV;
	ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);
	if (!ep)
		goto fail;
	hidg->in_ep = ep;

	hidg->out_ep = NULL;
	if (hidg->use_out_ep) {
		ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc);
		if (!ep)
			goto fail;
		hidg->out_ep = ep;
	}

	/* used only if use_out_ep == 1 */
	hidg->set_report_buf = NULL;

	/* set descriptor dynamic values */
	hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;
	hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
	hidg_interface_desc.bNumEndpoints = hidg->use_out_ep ? 2 : 1;
	hidg->protocol = HID_REPORT_PROTOCOL;
	hidg->idle = 1;
	hidg_ss_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
	hidg_ss_in_comp_desc.wBytesPerInterval =
				cpu_to_le16(hidg->report_length);
	hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
	hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
	hidg_ss_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);

	/* IN endpoints: FS default=10ms, HS default=4ยต-frame; user override if set */
	if (!hidg->interval_user_set) {
		hidg_fs_in_ep_desc.bInterval = 10;
		hidg_hs_in_ep_desc.bInterval = 4;
		hidg_ss_in_ep_desc.bInterval = 4;
	} else {
		hidg_fs_in_ep_desc.bInterval = hidg->interval;
		hidg_hs_in_ep_desc.bInterval = hidg->interval;
		hidg_ss_in_ep_desc.bInterval = hidg->interval;
	}

	hidg_ss_out_comp_desc.wBytesPerInterval =
				cpu_to_le16(hidg->report_length);
	hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
	hidg_fs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
	/*

Annotation

Implementation Notes