origin:https://blog.csdn.net/wuyuwei45/article/details/8939716
The more effective way to learn gadget is to study routines carefully after mastering the basic structure. Not only gadget, but other Linux drivers or subsystems. In addition, the peripheral drivers of Linux usually have layered concept, with object-oriented ideas, so the study of code is a more effective way to understand.
Generally a Linux USB device driver, including two parts, one is the CPU USB controller part of the driver, driver file name is often xxx_udc.c, this part of the drive is related to the hardware CPU, including register settings, DMA settings, and this part also soft USB Gadget architecture of things, usually this part of the code is relatively boring and difficult to understand, each CPU platform, this part of the code is very different, but fortunately this part of the Code General Factory Chamber of Commerce to provide. The second is gadget function drive, if the USB controller driver is the body, then this part is the soul, USB to be in the communication is what type of equipment (HID. Keyboard. U disk. , how to transmit and so on are all implemented in this partial drive.
The Linux kernel source driver/usb/gadget/zero.c is a good gadget function-driven framework that is intended to be used by the kernel developers to facilitate Third-party USB controllers to drive developer Test UDC drivers.
First on a routine, this routine is Huaqingyuan see Liu Hongtao a routine written in the USB driver section, although routines still have a lot of optimizations and redundancies, this routine is a wonderful illustration of how to develop a gadget feature driver, although the way in which a registered character device driver is described in a routine is stale.
Before I put this routine on, I changed part of the code format for easy reading.[CPP] View Plain Copy/* * zero.c -- gadget zero, for simple usb development * All rights reserved. */ /* #define VERBOSE_DEBUG */ #include <linux/kernel.h> #include <linux/utsname.h> #include <linux/device.h> # include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include "Gadget_chips.h" #include <linux/slab.h> #include <linux/ module.h> #include <linux/init.h> #include <linux/usb/input.h> #include <linux/cdev.h> #include <asm/uaccess.h> # include <linux/fs.h> #include <linux/poll.h> #include < Linux/types.h> /* size_t */ #include <linux/errno.h> /* error codes */ #include <asm/system.h> #include <asm/io.h> # include <linux/sched.h> /*-------------------------------------------------- -----------------------*/ static const char shortname[] = "Zero"; static const char loopback[] = "Loop input to output"; static const char longname[] = "Gadget zero"; static const char source_sink[] = "Source and sink data"; #define string_manufacturer 25 #define STRING_PRODUCT 42 #define string_ serial 101 #define STRING_SOURCE_SINK 250 #define string_loopback 251 //#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ //# define driver_product_num 0xa4a0 /* linux-usb "Gadget zero" */ define driver_vendor_num 0x5345 /* netchip */ #define driver_product_ num 0x1234 /* linux-usb "Gadget zero" */ static int usb_zero_major = 251; /*----------------------------------------------------------- --------------*/ static const char *ep_out_name; /* sink */ /*-------------------------------------------------------------------------*/ /* big enough to hold our biggest descriptor */ #define usb_bufsiz 256 struct zero_dev { // Zero deviceStructure spinlock_t lock; struct usb _gadget *gadget; struct usb_request *req; /* for control responses */ struct usb_ep *out_ep; struct cdev cdev; unsigned char data[128]; unsigned int data_size; wait_queue_head_t bulkrq; }; #define config_loopback 2 static struct usb_device_descriptor device_desc = { //Device Descriptor .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, .bcdusb = __constant_cpu_to_le16 (0x0110), . bdeviceclass = usb_class_vendor_spec, .idvendor = __ Constant_cpu_to_le16 (driver_vendor_num), .idproduct = __constant_ Cpu_to_le16 (driver_product_num), .imanufacturer = string_ manufacturer, .iProduct = STRING_PRODUCT, .iSerialNumber = STRING_SERIAL, .bnumconfigurations = 1, }; Static struct usb_endpoint_descriptor fs_sink_desc = { //Endpoint Descriptor .bLength = USB_DT_ENDPOINT_SIZE, .bdescriptortype = usb_dt_endpoint, .bendpointaddress = usb_dir_out, //on the host side, output .bmAttributes = USB_ENDPOINT_XFER_BULK, }; static struct usb_config_descriptor loopback_config = { //Configuration Descriptor .bLength = sizeof loopback_config, .bDescriptorType = USB_DT_CONFIG, /* compute wTotalLength on the fly */ .bNumInterfaces = 1, .bConfigurationValue = config_loopback, .iConfiguration = STRING_LOOPBACK, .bmattributes = usb_config_att_one | usb_config_att_ Selfpower, &nbSp .bMaxPower = 1, /* self-powered */ }; static const struct usb_interface_descriptor loopback_intf = { //Interface descriptor . blength = sizeof loopback_intf, .bdescriptortype = USB_DT_INTERFACE, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, . iinterface = string_loopback, }; /* static strings, in UTF-8 */ #define STRING_MANUFACTURER 25 #define STRING_PRODUCT 42 #define STRING_SERIAL 101 #define STRING_SOURCE_SINK 250 #define STRING_LOOPBACK 251 static char manufacturer[50]; /* default serial number takes at least two packets */ static char serial[] = "0123456789.0123456789.0123456789"; static struct usb_string strings[] = { //String Descriptor { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, longname, }, { string_serial, serial, }, { string_loopback, loopback, }, { STRING_SOURCE_SINK, source_sink, }, { } /* end of list */ }; static struct usb_gadget_strings stringtab = { .language = 0x0409, /* en-us */ . strings = strings, }; static const struct usb_ descriptor_header *fs_loopback_function[] = { ( struct usb_descriptor_header *) &loopback_intf, (struct usb_descriptor_header *) &fs_sink_desc, NULL, }; &Nbsp; Static void free_ep_req (struct usb_ep *ep, struct usb_ Request *req) { kfree (req->buf); usb_ep_free_request (ep, req); } Static struct usb _request *alloc_ep_req (struct usb_ep *ep, unsigned length)/allocation request { struct usb_request *req; req = usb_ep_alloc_request (ep, gfp_atomic); if (req) { req->length = length; req->buf = kmalloc ( length, gfp_atomic); if (!REQ->BUF)   { usb_ep_free_request (ep, req); req = NULL; } } return req; } Static void source_sink_complete (struct usb_ep *ep, STRUCT&NBSP;USB_REQUEST&NBSP;*REQ)//Request completion function { struct zero_ dev *dev = ep->driver_data; int status = req->status; switch (status) { case 0: /* normal completion */ if (EP&NBSP;==&NBSP;DEV->OUT_EP) { memcpy (dev->data, req- >buf, req->actual)//Return data copy to Req->buf, //dev->data_size=req->length; dev->data_size=req->actual; //actual length for req->actual; needs confirmation req –>short_not_ OK is 0. Reference gadget.h comments on Usb_request structure } break;   /* this endpoint is normally active while we ' re configured */ case -ECONNABORTED: /* hardware forced ep reset */ case -econnreset: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;PRINTK ("%s gone (%d), %d/%d/n", ep- >name, status,req->actual, req->length); case -EOVERFLOW: /* buffer overrun on read means that * we Didn ' t provide a big enough * buffer. */ default: #if 1 &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;PRINTK ("%s complete --> %d, %d/%d/n ", ep->name, status, req->actual, req->length); #endif case - eremoteio: /* short read */ break; } free_ep_req (ep, req); wake_up_interruptible (&DEV->BULKRQ); //Wake read function } Static struct usb_request *source_sink_start_ep (struct usb_ep &NBSP;*EP)//constructs and sends read requests { struct usb_request *req; int status; &NBSP;&NBSP;&NBSP;&NBSP;//PRINTK ("in %s/n", __ function__); req = alloc_ep_req (ep, 128); if (!req) return NULL; memset (req->buf, 0, req->length); req->complete = source_sink_complete; //Request Completion function staTus = usb_ep_queue (ep, req, gfp_atomic) //Submit Request if (status) { struct zero_dev *dev = ep->driver_data; &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;PRINTK ("start %s --> %d/n", ep->name, Status); free_ep_req (ep, req); req = NULL; } return req; } Static int usb_zero_open (Struct inode *inode, struct file *file) // Open Equipment { struct zero_dev *dev = container_of (Inode->i_cdev, struct zero_dev, cdev)