origin: https://blog.csdn.net/wuyuwei45/article/details/8939716
學習Gadget比較有效辦法是掌握基本架構後,認真研讀常式。其實不單Gadget如此,其他Linux驅動或子系統都是如此。另外Linux下的外設驅動通常有分層的概念,有帶有物件導向的思想,因此研讀代碼是比較有效領悟辦法。
一般一個Linux的USB裝置驅動,包括兩大部分,一是CPU USB控制器部分的驅動,驅動檔案名稱往往是xxx_udc.c,此部分驅動很多是與硬體CPU相關,包含寄存器設定、DMA設定,同時此部分也柔和了USB Gadget架構的東西,通常此部分代碼是比較枯燥且難於理解的,每個CPU平台,此部分代碼差異很大,但幸好此部分代碼一般廠商會提供。二是gadget功能驅動,如果說USB控制器驅動是肉體,則此部分是靈魂,USB要在通訊中是屬於什麼類型裝置(HID。鍵盤。隨身碟。),怎樣傳輸等等都是在此部分驅動中實現的。
Linux核心源碼driver/usb/gadget/zero.c是一個很好的gadget功能驅動架構,本來核心開發人員是想通過這個驅動架構來來方便第三方USB控制器驅動開發人員測試UDC驅動的。
先上一個常式,這個常式是華清遠見劉洪濤老師在闡述USB驅動部分寫的一個常式,儘管常式尚有很多可最佳化、冗餘的東西,儘管常式中描述註冊字元裝置驅動的方式是陳舊的方式,但是這個常式還是精彩闡述的如何開發一個gadget功能驅動。
在放這個常式前,為方便閱讀,我更改部分代碼格式。 [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裝置結構 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 = { //裝置描述符 .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 = { //端點描述符 .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, //對主機端來說,輸出 .bmAttributes = USB_ENDPOINT_XFER_BULK, }; static struct usb_config_descriptor loopback_config = { //配置描述符 .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, .bMaxPower = 1, /* self-powered */ }; static const struct usb_interface_descriptor loopback_intf = { //介面描述符 .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_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, }; 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)//分配請求 { 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 usb_request *req)//請求完成函數 { struct zero_dev *dev = ep->driver_data; int status = req->status; switch (status) { case 0: /* normal completion */ if (ep == dev->out_ep) { memcpy(dev->data, req->buf, req->actual);//返回資料拷貝到req->buf中, //dev->data_size=req->length; dev->data_size=req->actual; //實際長度為req->actual;需要確認req –>short_not_ok為0。參考gadget.h中關於usb_request結構的注釋 } 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 */ 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 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); //喚醒讀函數 } static struct usb_request *source_sink_start_ep(struct usb_ep *ep)//構造並發送讀請求 { struct usb_request *req; int status; //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; //請求完成函數 status = usb_ep_queue(ep, req, GFP_ATOMIC); //遞交請求 if (status) { struct zero_dev *dev = ep->driver_data; 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) //開啟裝置 { struct zero_dev *dev = container_of (inode->i_cdev, struct zero_dev, cdev)