http://www.linuxidc.com/Linux/2007-12/10106.htm
最近在做Linux下USB從裝置的驅動,程式寫的差不多了,做一個整理小結。歡迎交流,如有錯誤請指正,謝謝!--Jason
一、USB從裝置驅動介紹
USB匯流排上主要有三類裝置:主控制器(Host Controller, such as EHCI、UHCI、OHCI)、集線器(hub)和裝置(device)。Host controller(HC)負責匯流排的管理,是匯流排的指揮官,匯流排上一切傳輸都是由HC發起的,支援OTG的Device也能發起傳輸;Hub是匯流排的節點,用來擴充匯流排上可接入裝置的數量,對於驅動來說是透明的;Device就是各種各樣的裝置了,每個裝置都有自己的功能,比如隨身碟、USB網路攝影機等等。
Linux下主機端USB裝置的驅動(device driver)編寫的資料有很多,LDD3中有相應的介紹。主要是通過核心中USB core這個模組與裝置互動。本文只介紹運行Linux的嵌入式USB裝置驅動的編寫。因為Host端已經使用了device driver一詞,為了避免混淆,使用USB gadget driver一次表示從裝置驅動。In USB protocol interactions, the device driver is the master (or client driver) and the gadget driver is the slave (or function driver).
Linux USB gadget driver API定義了一個通用的gadget driver的介面,gadget driver通過API與底層USB controller driver通訊。該API屏蔽了底層硬體的不同,使gadget driver注重功能的實現,盡量與硬體無關。Slave端系統的架構如所示:
其中,gadgetfs提供給使用者空間程式直接與USB device controller互動的能力。
二、相關資料
USB gadget API Layer的相關資料:
1. http://www.linux-usb.org/gadget/
2. 核心中/KernelDoc/gadget/目錄下的文檔
3.最重要的就是/include/linux/usb_gadget.h檔案,該檔案中有gadget API介面資料結構和方法的詳細定義及注釋。
Gadget Driver的例子:
4. 核心/drivers/usb/gadget/目錄下有一些gadget driver的例子,zero.c為最簡單的例子,file_storage.c是存放裝置的gadget driver。
三、gadget API
要瞭解gadget API,只需要理解標頭檔(usb_gadget.h)中幾個重要的資料結構就可以了。詳細的欄位介紹看h檔案注釋。
(1)
struct usb_gadget {
const struct usb_gadget_ops *ops;
struct usb_ep *ep0;
struct list_head ep_list;
enum usb_device_speed speed;
unsigned is_dualspeed:1;
unsigned is_otg:1;
unsigned is_a_peripheral:1;
unsigned b_hnp_enable:1;
unsigned a_hnp_support:1;
unsigned a_alt_hnp_support:1;
const char *name;
struct device dev;
};
該結構表示一個USB device controller(UDC),在udc driver中初始化,它對gadget driver是唯讀。
(2)
struct usb_gadget_driver {
char *function;
enum usb_device_speed speed;
int (*bind)(struct usb_gadget *);
void (*unbind)(struct usb_gadget *);
int (*setup)(struct usb_gadget *,
const struct usb_ctrlrequest *);
void (*disconnect)(struct usb_gadget *);
void (*suspend)(struct usb_gadget *);
void (*resume)(struct usb_gadget *);
struct device_driver driver;
};
這個結構表示我們的gadget驅動,其中的函數需要在gadget driver中實現,是編碼的重點之一。具體實現可參考zero.c檔案,下面簡單介紹一下各個函數的功能:
Bind中主要執行gadget driver的初始化,它會被usb_gadget_register_driver函數調用,而usb_gadget_register_driver 一般在模組初始化時調用。usb_gadget_register_driver執行完之後,device可以被主機探測到。
Unbind與bind相反,被usb_gadget_unregister_driver調用。
Setup處理主機發過來的request,例如讀decriptors,配置configuration等。因此,setup函數中一般包含switch,case語句。
Disconnect在裝置與主機斷開時被調用。
(3)
struct usb_request {
void *buf;
unsigned length;
dma_addr_t dma;
unsigned no_interrupt:1;
unsigned zero:1;
unsigned short_not_ok:1;
void (*complete)(struct usb_ep *ep,
struct usb_request *req);
void *context;
struct list_head list;
int status;
unsigned actual;
};
usb_request 表示一個傳輸的請求,與host端的urb很相似。它有一個complete欄位,指定當request完成時的回呼函數。
(4)
struct usb_ep {
void *driver_data;
const char *name;
const struct usb_ep_ops *ops;
struct list_head ep_list;
unsigned maxpacket:16;
};
struct usb_ep 表示一個端點(EP),usb_gadget中有所有EP的list。
(5)
struct usb_ep_ops {
int (*enable) (struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc);
int (*disable) (struct usb_ep *ep);
struct usb_request *(*alloc_request) (struct usb_ep *ep,
gfp_t gfp_flags);
void (*free_request) (struct usb_ep *ep, struct usb_request *req);
void *(*alloc_buffer) (struct usb_ep *ep, unsigned bytes,
dma_addr_t *dma, gfp_t gfp_flags);
void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma,
unsigned bytes);
// NOTE: on 2.6, drivers may also use dma_map() and
// dma_sync_single_*() to directly manage dma overhead.
int (*queue) (struct usb_ep *ep, struct usb_request *req,
gfp_t gfp_flags);
int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
int (*set_halt) (struct usb_ep *ep, int value);
int (*fifo_status) (struct usb_ep *ep);
void (*fifo_flush) (struct usb_ep *ep);
};
struct usb_ep_ops表示端點的操作,其中queue函數將一個usb_request提交給某個EndPoint,是進行資料轉送的關鍵函數。
四、總結
本文是自己對學習使用Gadget API的一些總結,記錄下來以防時間一長就忘記了。