WINCE6.0+S3C2443下的usb function(功能)驱动
********************************LoongEmbedded************************
作者:LoongEmbedded(kandi)
時間:2011.03.16
類別:WINCE驅動開發
********************************LoongEmbedded************************
?
注:這里提到的MDD層和PDD層是對于usb function controller driver來說的
主要基于activesync功能的實現來學習,也即Serial:用于支持USB Device作為串口設備。
?
1.?????? usb function驅動架構
圖1
Architecturally, a USB function client driver is above a USB function controller driver. A USB function client driver interfaces with a USB function controller driver through the USB function controller driver's hardware independent MDD. The USB function controller driver's MDD and all USB function client drivers are hardware platform independent. Multiple USB function client drivers interface with the same USB function controller driver. Each client interfaces with the USB function controller driver through the USB function controller driver's MDD. Along with the MDD, a USB function controller driver is also comprised of a PDD, which is architecturally below the MDD. The PDD interfaces directly with the USB function controller hardware.
?
從架構上來說,USB function client驅動位于USB function controller驅動的之上,USB function controller驅動的MDD層是USB function client驅動和USB function controller驅動之間的接口,多個USB function client驅動共用可以同一個USB function controller驅動,USB function controller驅動的PDD層直接和USB function controller hardware打交道。
?
2.?????? usb function驅動組件
下圖是WINCE6.0中usb function
圖2
3.?????? usb function硬件設計
圖3
?
?
4.?????? usb function驅動的實現
4.1?? USB設備端點的概念
每個端點都是一個簡單的連接點,或者支持數據流進設備,或者支持其流出設備,兩者不可兼得。基于PnP機制,設備被枚舉時,它必須向主機報告各個端點的特性,包括端點號,通信方向,端點支持的最大包大小,帶寬要求等(其中端點支持的最大包大小叫做數據有效負載)。每個設備必須有端點0,它用于設備枚舉和對設備進行一些基本的控制功能。除了端點0,其余的端點在設備配置之前不能與主機通信,只有向主機報告這些端點的特性并被確認后才能被激活。
?
特別地,缺省控制通道也是一個消息通道。當客戶程序通過USB管道發送或接收數據時,它首先調用Win32 APl,調用最終將使功能驅動程序收到一個IRP。而驅動程序的工作就是把客戶的請求引導到有正確端點的管道上。它把請求提交到總線驅動程序,總線驅動程序再把請求分解成多個事務,然后這些事務被送往總線。總線上的信息流以每毫秒一幀數據的形式流動。總線驅動程序必須安排好多個事務以使它們能被裝入同一幀中。在主機和設備的端口之間,可視為一個通道。USB中有一個特殊的通道一缺省控制通道,它屬于消息通道,設備一啟動即存在,從而為設備的設置、狀態查詢和輸入控制信息提供一個入口。
?
端點有三個狀態:空閑,數據流入和數據流出。
?
?
?
4.2?? USB function client驅動總線接口
USB function controller驅動的MDD層實現并導出了總線接口,這樣就可以利用這個接口來加載USB function client驅動。IOCTL的初始化之后,USB function controller驅動的MDD層根據注冊表項HKEY_LOCAL_MACHINE/Drivers/USB/FunctionDrivers下面的鍵值來加載默認的USB function client驅動,比如加了Device Drivers->USB Function->USB Function Clients->serial組件之后在common.reg中有此client驅動對應的注冊表項
[HKEY_LOCAL_MACHINE/Drivers/USB/FunctionDrivers]
?? "DefaultClientDriver"=- ; erase previous default
[HKEY_LOCAL_MACHINE/Drivers/USB/FunctionDrivers]
?? "DefaultClientDriver"="Serial_Class"
如果此鍵值不存在,那么在IOCTL的初始化也會成功,但不能使能function controller。當然應用程序可以稍后增加這個注冊表項,并且調用MDD層的IOCTL_BUS_ACTIVATE_CHILD來加載client驅動。
?
為了增加我們應用的靈活性,可以在platform.reg中增加注冊表項HKEY_LOCAL_MACHINE/Drivers/USB/FunctionDrivers來替代common.reg中相應的內容,下面是我們的platform.reg中的相關注冊表信息
圖4
享有特權的應用程序可以通過DeviceIoControl函數獲取MDD層總線接口的句柄,并且通過IOCTL_BUS_UFN_ENUMERATE_AVAILABLE_CLIENTS可以枚舉不同的客戶端程序,當然也可以獲取當前的客戶程序的名字,可以下載當前的客戶程序并且加載新的客戶程序等等,關于USB function controller驅動的IO控制碼,見下面的描述
圖5
對上面IOCTLs的支持和實現是在MDD層的Ufnbus.cpp下面的CUfnBus::IOControl()來實現的,
在此需要注意的是MDD層支持的總線訪問IOCTLs不包含IOCTL_BUS_GET_CONFIGURE_DATA 和IOCTL_BUS_SET_CONFIGURE_DATA。
?
4.3?? USB function controller驅動MDD層及DDI接口
MDD層和client的接口函數如下,在public/common/oak/inc/usbfntypes.h下定義
圖6
既然是MDD層提供給Client調用的接口函數,就必須在MDD層來實現這些函數并且填充些個函數指針,先看MDD層的UFN_Init()函數中下面部分:
圖7
而CUfnBus類主要是用于加載client驅動并且處理USB function controller驅動的IOCTLs,見圖5,創建CUfnBus后會調用其成員函數CUfnBus::PostInit()
圖8
Client驅動被加載后,此后此client就是usb bus下的一個child,接著client會調用ufnclient.cpp下面的函數UfnInitializeInterface()向usb bus發出IOCTL_UFN_GET_CLIENT_DATA_EX請求
圖9
下面就來看CUfnBus::IOControl()函數對這個case的處理
圖10
下面看看GetClientFunctions()函數
圖11
到這里client就獲取到MDD層為其提供的函數接口了,后面就可以調用這些函數了。
?
MDD層的主要工作如下:
4.3.1根據usb描述符來注冊usb設備(在此指WINCE的usb function接口)
這里先來了解一下usb描述符,USB采用USB標準描述符說明一個USB設備,這些描述符包括設備描述符、配置描述符、接口描述符、端點描述符和字符串描述符。
(1)設備描述符 (Device Descriptor)用于指出USB設備的總體信息,其內容對該設備中同一傳輸模式下的所有配置都有效。一個設備只能有一個設備描述符,但是一個設備允許多個配置描述符。設備描述符的結構體如下:
typedef struct _USB_DEVICE_DESCRIPTOR {
??? UCHAR bLength;
??? UCHAR bDescriptorType;
??? USHORT bcdUSB;
??? UCHAR bDeviceClass;
??? UCHAR bDeviceSubClass;
??? UCHAR bDeviceProtocol;
??? UCHAR bMaxPacketSize0;
?
??? USHORT idVendor;
??? USHORT idProduct;
??? USHORT bcdDevice;
??? UCHAR iManufacturer;
??? UCHAR iProduct;
??? UCHAR iSerialNumber;
??? UCHAR bNumConfigurations;
} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
?
(2)配置描述符? (Configuration Descriptor)為USB設備的配置指出其配置信息。USB設備的一個配置可以包含一個或者多個接口,且每個接口都可以相互獨立工作,所有的USB設備都至少支持一個配置描述符,每個配置都必須有自己的配置描述符。當主機請求配置描述符時,其所有相關的接口描述符和端點描述符都將被返回。
typedef struct _USB_CONFIGURATION_DESCRIPTOR {
??? UCHAR bLength;
??? UCHAR bDescriptorType;
??? USHORT wTotalLength;
??? UCHAR bNumInterfaces;
??? UCHAR bConfigurationValue;
??? UCHAR iConfiguration;
??? UCHAR bmAttributes;
??? UCHAR MaxPower;
} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
?
(3)接口描述符(interface DescriPtor)用于指定usB設備中各個接口的特性,設備的每個接口都必須有一個描述符。USB設備的接口是一個端點的集合,負責完成設備的特定功能,接口可以包含一個或者多個可替換配置,它們能夠在USB設備處于配置狀態時,改變當前接口所含端點的個數和特性。USB設備同一配置的各個接口間不能使用相同的端點,但是同一接口的各個可替換配置間可以使用相同的端點。
typedef struct _USB_INTERFACE_DESCRIPTOR {
??? UCHAR bLength;
??? UCHAR bDescriptorType;
??? UCHAR bInterfaceNumber;
??? UCHAR bAlternateSetting;
??? UCHAR bNumEndpoints;
??? UCHAR bInterfaceClass;
??? UCHAR bInterfaceSubClass;
??? UCHAR bInterfaceProtocol;
??? UCHAR iInterface;
} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;
?
(4)端點描述符(EndPointDescriptor)用于指出usB設備端點的特性,如其所支持的傳輸類型、傳輸方向等信息。除端點O外,USB設備的每個端點都必須有一個端點描述符。
???????? typedef struct _USB_ENDPOINT_DESCRIPTOR {
??? UCHAR bLength;
??? UCHAR bDescriptorType;
??? UCHAR bEndpointAddress;
??? UCHAR bmAttributes;
??? USHORT wMaxPacketSize;
??? UCHAR bInterval;
} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR;
????? (5)字符串描述符(stringDescriptor)用于保存一些文本信息,它是可選的。在USB設備的其他描述符中,可以含有指向字符串描述符的索引值。
???????? typedef struct _USB_STRING_DESCRIPTOR {
??? UCHAR bLength;
??? UCHAR bDescriptorType;
??? WCHAR bString[1];
} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR;
?
USB function clients調用lpRegisterDevice函數(最終會調用MDD層的UfnMdd_RegisterDevice())把預先填充的描述符傳遞給MDD層,這些描述符包含端點數據包(endpoint packet)期望的最大包大小(在此為字節數)。MDD和PDD層在client指定的最大限制條件下協調使用的端點數據大小,MDD和PDD層可以使用小于端點本身供給的包大小,但不能大于。Client通過使用調整后的包長度來打開管道到端點的通道。
?
為了處理注冊過程,client提供總線速度最大可能的端點大小,比如,對于USB1.1來說,支持的大塊端點數據包是64個字節,而USB2.0支持的大塊端點數據包是512個字節,這樣允許MDD和PDD層可以靈活指定其大小。
?
4.3.2 處理client的枚舉請求
對于USB1.1和2.0,client驅動傳遞usb描述符給MDD和PDD,除非PDD先處理標準的枚舉的請求,否從由MDD來處理這些請求。當枚舉完成后,MDD或PDD傳遞一個枚舉完成事件給client,然后,client就適當地初始化端點。MDD需要處理下面的設置請求(setup request)
⑴Get device descriptor
⑵Get device qualifier
⑶Get high speed configuration descriptor, if the MDD is on a high speed bus
⑷Get Full Speed Configuration Descriptor, if the MDD is on a full speed bus
⑸Get string descriptor
⑹Set address
?
下面是help文檔中對MDD層的描述,為避免誤導大家,故貼出來稍加談談自己的理解。
Before interacting with the host(PC的usb host端), a function driver(usb function controller driver) must configure the underlying(下面的) USB function controller to support the function that it implements. The model device driver (MDD) must provide a mounted function driver(在此為總線驅動,見/PUBLIC/COMMON/OAK/DRIVERS/USBFN/CONTROLLER/MDD/ufnbus.cpp) with a way to configure the underlying USB function controller through a USB descriptor set. In addition, a mounted function driver must address a logical endpoint or pipe, through the endpoint address specified in a USB endpoint descriptor(通過端點描述符的bEndpointAddress為端點或通道編址). The MDD must provide a mapping between a pipe and a physical endpoint.
?
MDD functions wrap most of the similarly named PDD functions(這些函數見下圖). This indirection provides the function driver with the ability to access logical endpoints or pipes. The indirection allows the MDD to map the specified pipe to a physical endpoint.
圖12
The MDD provides functions to activate a particular configuration or interface. These functions handle configuration and pipe access.
?
The following steps show how the USB function driver is configured and how pipe access is set up:
⑴The function driver initializes the MDD, which initializes the PDD.
調用UfnPdd_Init()來初始化PDD,見圖7
⑵The function driver registers a configuration with the MDD.
這個在UfnMdd_RegisterDevice函數中實現。
By querying the capabilities of the USB function controller, through the PDD, the MDD determines whether the supplied configuration can be supported.
在UfnPdd_Init函數中實現
?
⑶The function driver starts the USB function controller if the configuration can be supported.
主要是通過調用UfnPdd_Start函數來實現,在這里會創建線程ISTMain來檢測usb function中斷。
?
⑷The function driver specifies notification functions for device events and default pipe events.
?
⑸The PDD maps the interrupt to a USB event when an interrupt occurs, and then the PDD notifies the device associated with the interrupt.
?
In other words, the function driver starts the interrupt service thread (IST) of the USB function controller, and supplies the PDD with a set of functions to call on the when an interrupt occurs(中斷發生的時候,MDD層調用PDD層為其提供的函數集). Handle USB events generated by the USB function controller as interrupts(在PDD層的HandleUSBEvent函數處理), and handle notification functions as interrupt service routines (ISRs).
?
?
⑺The USB function controller driver begins to service interrupts when the USB function controller is running and the default pipe is open.
默認控制管道是一個消息管道,用于在主機和USB設備的端點0之間傳送控制和狀態信息。
?
⑻The PDD calls the notification functions during USB enumeration.
These functions are supplied by the function driver in response to USB events. The notification function associated with the default pipe is required to read and parse setup token packets and respond to the associated USB standard requests associated with USB enumeration.
?
4.4?? USB function controller驅動PDD層及DDI接口
圖13
PDD主要的主要工作如下:
⑴為mounted function driver(usb總線驅動)呈現抽象的USB function controller,這樣可以保證mounted function driver訪問不同的USB function controller時可以移植過來。
?
⑵PDD層有能力檢查USB function controller的,并且允許usb function controller driver驅動(準確來說應該是其MDD層)配置和分配端點。
?
⑶USB總線事件發生的時候通知mounted function driver,并且允許function driver處理和關閉此事件。
?
4.5?? USB function controller驅動PDD層的實現
4.5.1????????? USB function controller驅動PDD層用到的中斷及對應的線程的概述
⑴檢測是否插入usb device線的中斷及線程
根據圖3可知是用GPF2/EINT2來檢測WINCE設備是否和PC端接入usb device線,檢測到之后由線程PLUG_IST函數來處理,具體的處理見下面的描述。
?
⑵檢測usb device中斷及處理線程
線程ISTMain函數用于檢測并處理usb deivce中斷,具體處理見下面的描述。
?
4.5.2????????? PDD層的初始化函數UfnPdd_Init
⑴初始化MDD層和PDD層的接口
圖14
⑵讀取注冊表項中FunctionDrivers的內容來獲取usb function client driver的信息
比如讀取到下面的內容
[HKEY_LOCAL_MACHINE/Drivers/USB/FunctionDrivers]
???????? ?? "DefaultClientDriver"=- ; erase previous default
???????? ?? "DefaultClientDriver"="Serial_Class"
然后確定client驅動
?
⑶設置端口的信息
圖15
這里涉及到端口的結構,如下
// Transfer structure passed to the PDD from the MDD in IssueTransfer.
typedef struct _STransfer {
??? DWORD?????????????? dwFlags;
??? PVOID?????????????? pvBuffer;
??? DWORD?????????????? dwBufferPhysicalAddress;
??? DWORD?????????????? cbBuffer;
??? DWORD?????????????? cbTransferred;
??? DWORD?????????????? dwUsbError; // Possible values are in usbfntypes.h
?
??? PVOID?????????????? pvPddData; // PDD can do whatever it likes with this
??? PVOID?????????????? pvPddTransferInfo; // Specific to PDD from client
} STransfer, *PSTransfer;
需要傳輸的數量,已經傳輸的數量
typedef struct EP_STATUS {
??? DWORD????????????????? ?dwEndpointNumber;
??? DWORD?????????????????? dwDirectionAssigned;
??? DWORD?????????????????? dwPacketSizeAssigned;
??? BOOL??????????????????? fInitialized;
??? DWORD?????????????????? dwEndpointType;
??? PSTransfer????????????? pTransfer;
??? CRITICAL_SECTION??????? cs;
} *PEP_STATUS;
這個結構體保存著一個端點傳輸中的基本信息:端點的Index號,傳輸方向,每次最大傳輸數量,端點的類型,此次傳輸的數據存放內存首地址
?
⑷調用DDKReg_GetWindowInfo()和DDKReg_GetIsrInfo()來讀取注冊表項[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SC2443USBFN]下保存的IRQ、SysIntr、IoBase、IoLen、等信息。
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SC2443USBFN]
?? "Dll"="sc2443usbfn.dll"
?? "Prefix"="UFN"
?? "Priority256"=dword:64
?? "IoBase"=dword:B0B00000
?? "IoLen"=dword:1000??????? ; Use one page
?? "Irq"=dword:19
?? "BusIoctl"=dword:2a0048
?? "IClass"=multi_sz:"{E2BDC372-598F-4619-BC50-54B3F7848D35}=%b","{6F40791D-300E-44E4-BC38-E0E63CA8375C}=%b"
?
⑸創建訪問總線放入句柄pContext->hBusAccess,調用MapRegisterSet將USB device controller register地址映射到虛擬地址空間.,然后設置attachedState為UFN_DETACH,調用ResetDevice函數復位usb function device和端點。
圖16
?
⑹傳遞MDD層和PDD層的接口,創建usb device線插拔的事件,中斷及IST。
圖17
下面來學習檢測usb device線的插拔的線程PLUG_IST
圖18
?
4.5.3????????? 處理USB device中斷的ISTMain()
CUsbFn::Init()->CUsbFn::StartUSBFunction()->UfnMdd_Start()->UfnPdd_Start(),ISTMain在UfnPdd_Start()被創建,先來看這個IST的函數體的前面部分
圖19
下面來看后部分
圖20
下面來學習HandleUSBEvent()
圖21
接著分別介紹HandleUSBEvent函數中調用到的主要函數
⑴ HandleUSBBusIrq()
介紹這個函數之前先來認識一下USB2.0 function的系統狀態寄存器(SSR),
圖22
HandleUSBBusIrq()函數主要是處理來usb總線中斷,記得當系統狀態的改變導致的中斷發生后,要對SSR寄存器相應的位置1來清除相應的位。如果是下面幾種usb總線中斷時,如果處于已連接的狀態,就需要告訴MDD層來做相應的處理
圖23
比如當檢查到host發送過來的suspend信號,這時先要判斷usb device是否處于連接的狀態,如果是就要告訴MDD層來處理,
圖24
這樣就可以調用UfnMdd_Notify函數來處理這個總線中斷請求,其他總線中斷請求的處理可做類似的分析
圖25
?
⑵ HandleEndpoint0Event()
先來看端點0相關寄存器
端點0中斷寄存器(EIR)
圖26
?
端點0狀態寄存器(ESR)
圖27
端點0控制寄存器(ECR)
圖28
下面來看HandleEndpoint0Event的函數體部分
圖29
圖30
上面部分的主要工作是準備發送配置包,讀取要發送包的字節數,獲得USB Device Request指針,讀取FIFO數據(EP0 Buffer Register)到pbUdr中。然后對讀到的數據進行解析,如果數據長度大于0,獲得傳輸方向,如果數據長度為0,設置sendDataEnd為TRUE表示數據傳輸完成.
圖31
上面部分是根據圖30中準備發送的數據包獲得是發出數據還是接收數據狀態,調用不同的處理流程
圖32
?
⑶HandleEndpointEvent()
圖33
?
圖34
?
圖35
?
?
?
CreateBusAccessHandle(LPCTSTR lpActiveRegPath)
該函數用于創建一個可以訪問Bus設備驅動的句柄,一個客戶端驅動(Client Driver)會在它的XXX_Init函數中調用該函數來獲得Bus設備的句柄。lpActiveRegPath為Bus設備的注冊表路徑,返回值為句柄。pszActiveKey=Drivers/Active/51
?
?
?
?
Windows CE USB Function Driver驅動簡析(1)-
http://blog.csdn.net/shevsten/archive/2010/07/15/5736889.aspx
?
2410 UDC driver 分析1
http://www.cevx.com/Bbs/viewthread.php?tid=13370
?
usb驅動
http://www.188928.com/sqd1/20110217/15727.htm
?
USB 軟件、端點和管道
http://blog.csdn.net/Augusdi/archive/2009/05/13/4170026.aspx
?
wince USB設備驅動程序導讀
http://yzcyn.blog.163.com/blog/static/38484300200831834045507/
?
WinCE系統USB Mass Storage實現
http://www.docin.com/p-55309404.html
?
WinCE USB驅動開發
http://blog.sina.com.cn/s/blog_4ad0a9940100g11a.html
?
WinCE系統USB功能定制
http://blog.csdn.net/nanjianhui/archive/2009/08/12/4438599.aspx
?
有關OHCI、UHCI、EHCI的知識
http://zhuairlunjj.blog.163.com/blog/static/8005094520107203058470/
?
?
?
總結
以上是生活随笔為你收集整理的WINCE6.0+S3C2443下的usb function(功能)驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WinCE CEDDK之Bus操作函数
- 下一篇: 关键字static、const、vola