編寫Windows CE.net的usb驅動程序教程
出處:互聯(lián)網(wǎng) 發(fā)布于:2011-09-03 08:12:23
Windows CE.NET 是微軟推出的功能強大的嵌入式操作系統(tǒng),國內(nèi)采用此操作系統(tǒng)的廠商已經(jīng)很多了,本文就以windows ce.net為例,簡單介紹一下如何開發(fā)windows ce.net下的USB驅動程序。
Windows CE.NET 的USB系統(tǒng)軟件分為兩層: USB Client設備驅動程序和底層的Windows CE實現(xiàn)的函數(shù)層。USB設備驅動程序主要負責利用系統(tǒng)提供的底層接口配置設備,和設備進行通訊。底層的函數(shù)提本身又由兩部分組成,通用串行總線驅動程序(USBD)模塊和較低的主控制器驅動程序(HCD)模塊。HCD負責層的處理,USBD模塊實現(xiàn)較高的USBD函數(shù)接口。USB設備驅動主要利用 USBD接口函數(shù)和他們的外圍設備打交道。
USB設備驅動程序主要和USBD打交道,所以我們必須詳細的了解USBD提供的函數(shù)。
主要的傳輸函數(shù)有:
abourttransferissuecontroltransfer
closetransfer issueinterruptransfer
getisochresultissueisochtransfer
gettransferstatus istransfercomplete
issuebulktransfer issuevendortransfer
主要的用于打開和關閉usbd和usb設備之間的通信通道的函數(shù)有:
abortpipetransfersclosepipe
isdefaultpipehalted ispipehalted
openpiperesetdefaultpipe
resetpipe
相應的打包函數(shù)接口有:
getframelengthgetframenumberreleaseframelengthcontrol
setframelengthtakeframelengthcontrol
取得設置設備配置函數(shù):
clearfeature setdescriptor
getdescriptorsetfeature
getinterface setinterface
getstatussyncframe
與usb進行交互的實現(xiàn)方法相關的多任務函數(shù):
findinterfaceregisterclientdeviceid
getdeviceinforegisterclientsettings
getusbdversion registernotificationroutine
loadgenericinterfacedriver translatestringdescr
openclientregisterkeyunregisternotificationroutine
常見的Windows CE.NET下USB的設備驅動程序的編寫有以下幾種方法:
● 流式接口函數(shù)這種驅動程序主要呈現(xiàn)流式函數(shù)接口,主要輸出XXX_Init,XXX_Deinit,XXX_Open,XXX_Close,XXX_Open,XXX_Close,XXX_Read,XXX_Write,XXX_Seek, XXX_IOControl,XXX_PowerUp,XXX_PowerDown等流式接口,注意上述的幾個接口一定都要輸出,另外XXX必須為三個字符,否則會出錯。但是此類的驅動程序不是通過設備管理接口來加載的,所以必須手工的調(diào)用RegisterDevice()和 DeregisterDevice()函數(shù)來加載和卸載驅動程序。用戶可以將此類的設備作為標準的文件來操作,只要調(diào)用相應的文件操作就可以和驅動程序打交道。
● 使用現(xiàn)有的Window CE.NET的應用程序接口此類設備主要是利用Windows CE.NET中已經(jīng)有了現(xiàn)成的函數(shù)接口,例如USB Mass Storage Disk,它主要利用現(xiàn)有的Windows CE.Net中已經(jīng)有的可安裝文件系統(tǒng)接口,呈現(xiàn)給系統(tǒng)可用的文件系統(tǒng),對于用戶來講,它是透明的,用戶僅僅感覺在操作一個文件夾。
● 創(chuàng)建指定到特定的USBD的用戶指定的API這種方法在USBD呈現(xiàn)設備時不需要任何限制,主要是特制的提供API給用戶,一般不太常見。
USB設備驅動程序必須輸出的函數(shù)有:
● USBDeviecAttach當USB設備連接到計算機上時,USBD模塊就會調(diào)用此函數(shù),這個函數(shù)主要用于初始化USB設備,取得USB設備信息,配置USB設備,并且申請必需的資源。
● USBInstallDriver主要用于創(chuàng)建一個驅動程序加載所需的注冊表信息,例如讀寫超時,設備名稱等。
● USBUninstallDriver主要用于釋放驅動程序所占用的資源,以及刪除USBInstallDriver函數(shù)創(chuàng)建的注冊表等。
上述的三個函數(shù)接口是所有的USB驅動程序必須提供的,缺一不可。
另外比較重要的是USB設備驅動程序的注冊表配置,一般的USB設備驅動程序的注冊表配置HKEY_LOCAL_MACHINE\Drivers\USB \LoadClients下,每個驅動程序的子鍵都有Group1_ID\Group2_ID\Group3_ID\DriverName格式,如果注冊表信息與USB設備信息符合,USBD就會加載此驅動程序。否則設備的子鍵應該由供應商,設備類和協(xié)議信息通過下劃線組成。
例如你有個PDA設備,它具有一個USB接口,它的供應廠商ID假設為0x0888,設備ID為0x0999,沒有使用特殊的協(xié)議,那么它的加載注冊表應該寫為:
[HKEY_LOCAL_MACHINE\Drivers\USB\LoadClients\2184_2457\Default\Default\PDA] "DLL"="pdausb.dll"需要注意的是注冊表構成都是十進制數(shù)值來標識的,注意一下十進制和十六進制的轉換。
有了這些基本信息,就可以編寫USB設備了。
首先,必須輸出USBD要求調(diào)用的三個函數(shù),首先到設備插入到USB端口時,USBD會調(diào)用USBDeviceAttach()函數(shù),相應的代碼如下:
extern c bool
usbdeviceattach(
usb_handle hdevice, // usb設備句柄
lpcusb_funcs lpusbfuncs, // usbdi的函數(shù)集合
lpcusb_interface lpinterface, // 設備接口描述信息
lpcwstr szuniquedriverid, // 設備id描述字符串。
lpbool facceptcontrol, // 返回true,標識我們可以控制此設備, 反之表示不能控制
dword dwunused)
{
*facceptcontrol = false;
// 我們的鼠標設備有特定的描述信息,要檢測是否是我們的設備。
if (lpinterface == null)
return false;
// 打印相關的usb設備接口描述信息。
debugmsg(zone_init,(text(usbmouse: deviceattach, if %u, #ep:%u, class:%u, sub:%u,prot:%urn), lpinterface->descriptor.binterfacenumber,lpinterface->descriptor.bnumendpoints, lpinterface->descriptor.binterfaceclass,lpinterface->descriptor.binterfacesubclass,lpinterface->descriptor.binterfaceprotocol));
// 初試數(shù)據(jù)usb鼠標類,產(chǎn)生一個接受usb鼠標數(shù)據(jù)的線程
cmouse * pmouse = new cmouse(hdevice, lpusbfuncs, lpinterface);
if (pmouse == null)
return false;
if (!pmouse->initialize())
{
delete pmouse;
return false;
}
// 注冊一個監(jiān)控usb設備事件的回調(diào)函數(shù),用于監(jiān)控usb設備是否已經(jīng)拔掉。
?。?lpusbfuncs->lpregisternotificationroutine)(hdevice,
usbdevicenotifications, pmouse);
*facceptcontrol = true;
return true;
}
第二個函數(shù)是 usbinstalldriver()函數(shù),
一些基本定義如下:
const wchar gcszregisterclientdriverid[] = lregisterclientdriverid;
const wchar gcszregisterclientsettings[] = lregisterclientsettings;
const wchar gcszunregisterclientdriverid[] = lunregisterclientdriverid;
const wchar gcszunregisterclientsettings[] = lunregisterclientsettings;
const wchar gcszmousedriverid[] = lgeneric_sample_mouse_driver;
函數(shù)接口如下:
extern c bool
usbinstalldriver(
lpcwstr szdriverlibfile) // @parm [in] - contains client driver dll name
{
bool fret = false;
hinstance hinst = loadlibrary(lusbd.dll);
// 注冊usb設備信息
if(hinst)
{
lpregister_client_driver_id pregisterid = (lpregister_client_driver_id)
getprocaddress(hinst, gcszregisterclientdriverid);
lpregister_client_settings pregistersettings =
(lpregister_client_settings) getprocaddress(hinst,
gcszregisterclientsettings);
if(pregisterid && pregistersettings)
{
usb_driver_settings driversettings;
driversettings.dwcount = sizeof(driversettings);
// 設置我們的特定的信息。
driversettings.dwvendorid = usb_no_info;
driversettings.dwproductid = usb_no_info;
driversettings.dwreleasenumber = usb_no_info;
driversettings.dwdeviceclass = usb_no_info;
driversettings.dwdevicesubclass = usb_no_info;
driversettings.dwdeviceprotocol = usb_no_info;
driversettings.dwinterfaceclass = 0x03; // hid
driversettings.dwinterfacesubclass = 0x01; // boot device
driversettings.dwinterfaceprotocol = 0x02; // mouse
fret = (*pregisterid)(gcszmousedriverid);
if(fret)
{
fret = (*pregistersettings)(szdriverlibfile,
gcszmousedriverid, null, &driversettings);
if(!fret)
{
//bugbug unregister the client drivers id
}
}
}
else
{
retailmsg(1,(text(!usbmouse: error getting usbd function pointersrn)));
}
freelibrary(hinst);
}
return fret;
}
上述代碼主要用于產(chǎn)生USB設備驅動程序需要的注冊表信息,要注意的是:USB設備驅動程序不使用標準的注冊表函數(shù),而是使用RegisterClientDriverID()與RegisterClientSettings來注冊相應的設備信息。
另外一個函數(shù)是usbuninstalldriver()函數(shù),具體代碼如下:
extern c bool
usbuninstalldriver()
{
bool fret = false;
hinstance hinst = loadlibrary(lusbd.dll);
if(hinst)
{
lpun_register_client_driver_id punregisterid =
(lpun_register_client_driver_id)
getprocaddress(hinst, gcszunregisterclientdriverid);
lpun_register_client_settings punregistersettings =
?。╨pun_register_client_settings) getprocaddress(hinst,
gcszunregisterclientsettings);
if(punregistersettings)
{
usb_driver_settings driversettings;
driversettings.dwcount = sizeof(driversettings);
// 必須填入與注冊時相同的信息。
driversettings.dwvendorid = usb_no_info;
driversettings.dwproductid = usb_no_info;
driversettings.dwreleasenumber = usb_no_info;
driversettings.dwdeviceclass = usb_no_info;
driversettings.dwdevicesubclass = usb_no_info;
driversettings.dwdeviceprotocol = usb_no_info;
driversettings.dwinterfaceclass = 0x03; // hid
driversettings.dwinterfacesubclass = 0x01; // boot device
driversettings.dwinterfaceprotocol = 0x02; // mouse
fret = (*punregistersettings)(gcszmousedriverid, null,
?。riversettings);
}
if(punregisterid)
{
bool frettemp = (*punregisterid)(gcszmousedriverid);
fret = fret ? frettemp : fret;
}
freelibrary(hinst);
}
return fret;
}
此函數(shù)主要用于刪除USBInstallDriver()時創(chuàng)建的注冊表信息,同樣的它使用自己的函數(shù)接口UnRegisterClientDriverID()和UnRegisterClientSettings()來做相應的處理。
另外一個需要處理的注冊的監(jiān)控通知函數(shù)usbdevicenotifications():
extern c bool usbdevicenotifications(lpvoid lpvnotifyparameter, dword dwcode,
lpdword * dwinfo1, lpdword * dwinfo2, lpdword * dwinfo3,
lpdword * dwinfo4)
{
cmouse * pmouse = (cmouse *)lpvnotifyparameter;
switch(dwcode)
{
case usb_close_device:
//刪除相關的資源。
delete pmouse;
return true;
}
return false;
}
usb鼠標的類的定義如下:
class cmouse
{
public:
cmouse::cmouse(usb_handle hdevice, lpcusb_funcs lpusbfuncs,
lpcusb_interface lpinterface);
~cmouse();
bool initialize();
private:
// 傳輸完畢調(diào)用的回調(diào)函數(shù)
static dword callback mousetransfercompletestub(lpvoid lpvnotifyparameter);
// 中斷處理函數(shù)
static ulong callback cmouse::mousethreadstub(pvoid context);
dword mousetransfercomplete();
dword mousethread();
bool submitinterrupt();
bool handleinterrupt();
bool m_fclosing;
bool m_freadyformouseevents;
handle m_hevent;
handle m_hthread;
usb_handle m_hdevice;
usb_pipe m_hinterruptpipe;
usb_transfer m_hinterrupttransfer;
lpcusb_funcs m_lpusbfuncs;
lpcusb_interface m_pinterface;
bool m_fprevbutton1;
bool m_fprevbutton2;
bool m_fprevbutton3;
// 數(shù)據(jù)接受緩沖區(qū)。
byte m_pbdatabuffer[8];
};
具體實現(xiàn)如下:
// 構造函數(shù),初始化時調(diào)用
cmouse::cmouse(usb_handle hdevice, lpcusb_funcs lpusbfuncs,
lpcusb_interface lpinterface)
{
m_fclosing = false;
m_freadyformouseevents = false;
m_hevent = null;
m_hthread = null;
m_hdevice = hdevice;
m_hinterruptpipe = null;
m_hinterrupttransfer = null;
m_lpusbfuncs = lpusbfuncs;
m_pinterface = lpinterface;
m_fprevbutton1 = false;
m_fprevbutton2 = false;
m_fprevbutton3 = false;
memset(m_pbdatabuffer, 0, sizeof(m_pbdatabuffer));
}
// 析構函數(shù),用于清除申請的資源。
cmouse::~cmouse()
{
// 通知系統(tǒng)去關閉相關的函數(shù)接口。
m_fclosing = true;
// wake up the connection thread again and give it time to die.
if (m_hevent != null)
{
// 通知關閉數(shù)據(jù)接受線程。
setevent(m_hevent);
if (m_hthread != null)
{
dword dwwaitreturn;
dwwaitreturn = waitforsingleobject(m_hthread, 1000);
if (dwwaitreturn != wait_object_0)
{
terminatethread(m_hthread, dword(-1));
}
closehandle(m_hthread);
m_hthread = null;
}
closehandle(m_hevent);
m_hevent = null;
}
if(m_hinterrupttransfer)
?。?m_lpusbfuncs->lpclosetransfer)(m_hinterrupttransfer);
if(m_hinterruptpipe)
?。?m_lpusbfuncs->lpclosepipe)(m_hinterruptpipe);
}
// 初始化usb鼠標驅動程序
bool cmouse::initialize()
{
lpcusb_device lpdeviceinfo = (*m_lpusbfuncs->lpgetdeviceinfo)(m_hdevice);
// 檢測配置:usb鼠標應該只有一個中斷管道
if ((m_pinterface->lpendpoints[0].descriptor.bmattributes & usb_endpoint_type_mask) != usb_endpoint_type_interrupt)
{
retailmsg(1,(text(!usbmouse: ep 0 wrong type (%u)!rn),
m_pinterface->lpendpoints[0].descriptor.bmattributes));
return false;
}
debugmsg(zone_init,(text(usbmouse: ep 0:maxpacket: %u, interval: %urn),
m_pinterface->lpendpoints[0].descriptor.wmaxpacketsize,
m_pinterface->lpendpoints[0].descriptor.binterval));
m_hinterruptpipe = (*m_lpusbfuncs->lpopenpipe)(m_hdevice,
?。_pinterface->lpendpoints[0].descriptor);
if (m_hinterruptpipe == null) {
retailmsg(1,(text(mouse: error opening interrupt pipern)));
return (false);
}
m_hevent = createevent(null, false, false, null);
if (m_hevent == null)
{
retailmsg(1,(text(usbmouse: error on createevent for connect eventrn)));
return(false);
}
// 創(chuàng)建數(shù)據(jù)接受線程
m_hthread = createthread(0, 0, mousethreadstub, this, 0, null);
if (m_hthread == null)
{
retailmsg(1,(text(usbmouse: error on createthreadrn)));
return(false);
}
return(true);
}
// 從usb鼠標設備中讀出數(shù)據(jù),產(chǎn)生相應的鼠標事件。
bool cmouse::submitinterrupt()
{
if(m_hinterrupttransfer)
?。?m_lpusbfuncs->lpclosetransfer)(m_hinterrupttransfer);
// 從usb鼠標pipe中讀數(shù)據(jù)
m_hinterrupttransfer = (*m_lpusbfuncs->lpissueinterrupttransfer)
?。╩_hinterruptpipe, mousetransfercompletestub, this,
usb_in_transfer | usb_short_transfer_ok, // 表示讀數(shù)據(jù)
min(m_pinterface->lpendpoints[0].descriptor.wmaxpacketsize,
sizeof(m_pbdatabuffer)),
m_pbdatabuffer,
null);
if (m_hinterrupttransfer == null)
{
debugmsg(zone_error,(l !usbmouse: error in issueinterrupttransferrn));
return false;
}
else
{
debugmsg(zone_transfer,(lusbmouse::submitinterrupt,transfer:0x%xrn,
m_hinterrupttransfer));
}
return true;
}
// 處理鼠標中斷傳輸?shù)臄?shù)據(jù)
bool cmouse::handleinterrupt()
{
dword dwerror;
dword dwbytes;
dword dwflags = 0;
int dx = (signed char)m_pbdatabuffer[1];
int dy = (signed char)m_pbdatabuffer[2];
bool fbutton1 = m_pbdatabuffer[0] & 0x01 ? true : false;
bool fbutton2 = m_pbdatabuffer[0] & 0x02 ? true : false;
bool fbutton3 = m_pbdatabuffer[0] & 0x04 ? true : false;
if (?。?m_lpusbfuncs->lpgettransferstatus)(m_hinterrupttransfer, &dwbytes,&dwerror))
{
debugmsg(zone_error,(text(!usbmouse: error in gettransferstatus(0x%x)rn),
m_hinterrupttransfer));
return false;
}
else
{
debugmsg(zone_transfer,(text(usbmouse::handleinterrupt, htransfer 0x%x complete (%u bytes, error:%x)rn),
m_hinterrupttransfer,dwbytes,dwerror));
}
if (!submitinterrupt())
return false;
if(dwerror != usb_no_error)
{
debugmsg(zone_error,(text(!usbmouse: error 0x%x in interrupt transferrn),dwerror));
return true;
}
if(dwbytes < 3)
{
debugmsg(zone_error,(text(!usbmouse: invalid byte cnt %u from interrupt transferrn),dwbytes));
return true;
}
if(dx || dy)
dwflags |= mouseeventf_move;
if(fbutton1 != m_fprevbutton1)
{
if(fbutton1)
dwflags |= mouseeventf_leftdown;
else
dwflags |= mouseeventf_leftup;
}
if(fbutton2 != m_fprevbutton2)
{
if(fbutton2)
dwflags |= mouseeventf_rightdown;
else
dwflags |= mouseeventf_rightup;
}
if(fbutton3 != m_fprevbutton3)
{
if(fbutton3)
dwflags |= mouseeventf_middledown;
else
dwflags |= mouseeventf_middleup;
}
m_fprevbutton1 = fbutton1;
m_fprevbutton2 = fbutton2;
m_fprevbutton3 = fbutton3;
debugmsg(zone_events,
?。╰ext(usbmouse event: dx:%d, dy:%d, dwflags:0x%x (b1:%u, b2:%u, b3:%u)rn),
dx,dy,dwflags,fbutton1,fbutton2,fbutton3));
// 通知系統(tǒng)產(chǎn)生鼠標事件
if (m_freadyformouseevents)
mouse_event(dwflags, dx, dy, 0, 0);
else
m_freadyformouseevents = isapiready(sh_wmgr);
return true;
}
dword callback cmouse::mousetransfercompletestub(lpvoid lpvnotifyparameter)
{
cmouse * pmouse = (cmouse *)lpvnotifyparameter;
return(pmouse->mousetransfercomplete());
}
// 數(shù)據(jù)傳輸完畢回調(diào)函數(shù)
dword cmouse::mousetransfercomplete()
{
if (m_hevent)
setevent(m_hevent);
return 0;
}
ulong callback cmouse::mousethreadstub(pvoid context)
{
cmouse * pmouse = (cmouse *)context;
return(pmouse->mousethread());
}
// usb鼠標線程
dword cmouse::mousethread()
{
debugmsg(zone_init,(text(usbmouse: worker thread startedrn)));
setthreadpriority(getcurrentthread(), thread_priority_highest);
if (submitinterrupt())
{
while (!m_fclosing)
{
waitforsingleobject(m_hevent, infinite);
if (m_fclosing)
break;
if ((*m_lpusbfuncs->lpistransfercomplete)(m_hinterrupttransfer))
{
if (!handleinterrupt())
break;
}
else
{
retailmsg(1,(text(!usbmouse: event signalled, but transfer not completern)));
// the only time this should happen is if we get an error on the transfer
assert(m_fclosing || (m_hinterrupttransfer == null));
break;
}
}
}
retailmsg(1,(text(usbmouse: worker thread exitingrn)));
return(0);
}
其實USB的驅動程序編寫就這么簡單,類似的其他設備,比如打印機設備,就有Bulk OUT PIPE,需Bulk傳輸,那就要了解一下IssueBulkTransfer()應用。如果是開發(fā)USB Mass Storage Disk的驅動,就要了解更多的協(xié)議,如Bulk-Only Transport協(xié)議等。
微軟的Windows CE.NET的Platform Build中已經(jīng)帶有USB Printer和USB Mass Storage Disk的驅動的源代碼了,好好研究一下,你一定會受益非淺的。
版權與免責聲明
凡本網(wǎng)注明“出處:維庫電子市場網(wǎng)”的所有作品,版權均屬于維庫電子市場網(wǎng),轉載請必須注明維庫電子市場網(wǎng),http://www.hbjingang.com,違反者本網(wǎng)將追究相關法律責任。
本網(wǎng)轉載并注明自其它出處的作品,目的在于傳遞更多信息,并不代表本網(wǎng)贊同其觀點或證實其內(nèi)容的真實性,不承擔此類作品侵權行為的直接責任及連帶責任。其他媒體、網(wǎng)站或個人從本網(wǎng)轉載時,必須保留本網(wǎng)注明的作品出處,并自負版權等法律責任。
如涉及作品內(nèi)容、版權等問題,請在作品發(fā)表之日起一周內(nèi)與本網(wǎng)聯(lián)系,否則視為放棄相關權利。
- ARM技術架構與應用開發(fā)實踐指南2026/1/6 10:40:19
- 嵌入式實時操作系統(tǒng)(RTOS)選型與移植技術指南2025/12/31 10:42:31
- 工業(yè)嵌入式系統(tǒng):通信接口技術選型與抗干擾設計實踐2025/12/15 14:36:53
- 深入解析嵌入式 OPENAMP 框架:開啟異核通信新時代2025/7/22 16:27:29
- 一文快速了解OPENWRT基礎知識2025/7/14 16:59:04









