Linux Gadget的一點研究之常式分析__Linux

來源:互聯網
上載者:User
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)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.