当前位置:首页 > 电源 > 数字电源
[导读]上述讲了堆理论,可能读者脑袋都已经大了,为此,我们举个简单的例子来详细说明一下驱动程序的开发过程。例如我们有个USBMouse设备,设备信息描述如下:DeviceDescriptor:bcdUSB:0x0100bDeviceClass:0x00bDeviceSubC

上述讲了堆理论,可能读者脑袋都已经大了,为此,我们举个简单的例子来详细说明一下驱动程序的开发过程。

例如我们有个USBMouse设备,设备信息描述如下:

DeviceDescriptor:

bcdUSB:0x0100

bDeviceClass:0x00

bDeviceSubClass:0x00

bDeviceProtocol:0x00

bMaxPacketSize0:0x08(8)

idVendor:0x05E3(GenesysLogicInc.)

idProduct:0x0001

bcdDevice:0x0101

iManufacturer:0x00

iProduct:0x01

iSerialNumber:0x00

bNumConfigurations:0x01

ConnectionStatus:DeviceConnected

CurrentConfigValue:0x01

DeviceBusSpeed:Low

DeviceAddress:0x02

OpenPipes:1

EndpointDescriptor:

bEndpointAddress:0x81

TransferType:Interrupt

wMaxPacketSize:0x0003(3)

bInterval:0x0A

可以看出上述设备有一个中断PIPE,包的最大值为3。可能有人问上述的值怎么得到的,win2k的DDK中有个usbview的例程,编译一下,将你的USB设备插到PC机的USB口中,运行usbview.exe即可看得相应的设备信息。

有了这些基本信息,就可以编写USB设备了,首先声明一下,下面的代码取自微软的USB鼠标样本程序,版权归微软所有,此处仅仅借用来描述一下USB鼠标驱动的开发过程,读者如需要引用此代码,需要得到微软的同意。

首先,必须输出USBD要求调用的三个函数,首先到设备插入到USB端口时,USBD会调用USBDeviceAttach()函数,相应的代码如下:

extern"C"BOOL

USBDeviceAttach(

USB_HANDLEhDevice,//USB设备句柄

LPCUSB_FUNCSlpUsbFuncs,//USBDI的函数集合

LPCUSB_INTERFACElpInterface,//设备接口描述信息

LPCWSTRszUniqueDriverId,//设备ID描述字符串。

LPBOOLfAcceptControl,//返回TRUE,标识我们可以控制此设备,反之表示不能控制

DWORDdwUnused)

{

*fAcceptControl=FALSE;

//我们的鼠标设备有特定的描述信息,要检测是否是我们的设备。

if(lpInterface==NULL)

returnFALSE;

//打印相关的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));

//初试数据USB鼠标类,产生一个接受USB鼠标数据的线程

CMouse*pMouse=newCMouse(hDevice,lpUsbFuncs,lpInterface);

if(pMouse==NULL)

returnFALSE;

if(!pMouse->Initialize())

{

deletepMouse;

returnFALSE;

}

//注册一个监控USB设备事件的回调函数,用于监控USB设备是否已经拔掉。

(*lpUsbFuncs->lpRegisterNotificationRoutine)(hDevice,

USBDeviceNotifications,pMouse);

*fAcceptControl=TRUE;

returnTRUE;

}

第二个函数是USBInstallDriver()函数,

一些基本定义如下:

constWCHARgcszRegisterClientDriverId[]=L"RegisterClientDriverID";

constWCHARgcszRegisterClientSettings[]=L"RegisterClientSettings";

constWCHARgcszUnRegisterClientDriverId[]=L"UnRegisterClientDriverID";

constWCHARgcszUnRegisterClientSettings[]=L"UnRegisterClientSettings";

constWCHARgcszMouseDriverId[]=L"Generic_Sample_Mouse_Driver";

函数接口如下:

extern"C"BOOL

USBInstallDriver(

LPCWSTRszDriverLibFile)//@parm[IN]-ContainsclientdriverDLLname

{

BOOLfRet=FALSE;

HINSTANCEhInst=LoadLibrary(L"USBD.DLL");

//注册USB设备信息

if(hInst)

{

LPREGISTER_CLIENT_DRIVER_IDpRegisterId=(LPREGISTER_CLIENT_DRIVER_ID)

GetProcAddress(hInst,gcszRegisterClientDriverId);

LPREGISTER_CLIENT_SETTINGSpRegisterSettings=

(LPREGISTER_CLIENT_SETTINGS)GetProcAddress(hInst,

gcszRegisterClientSettings);

if(pRegisterId&&pRegisterSettings)

{

USB_DRIVER_SETTINGSDriverSettings;

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;//bootdevice

DriverSettings.dwInterfaceProtocol=0x02;//mouse

fRet=(*pRegisterId)(gcszMouseDriverId);

if(fRet)

{

fRet=(*pRegisterSettings)(szDriverLibFile,

gcszMouseDriverId,NULL,&DriverSettings);

if(!fRet)

{

//BUGBUGunregistertheClientDriver’sID

}

}

}

else

{

RETAILMSG(1,(TEXT("!USBMouse:ErrorgettingUSBDfunctionpointersrn")));

}

FreeLibrary(hInst);

}

returnfRet;

}

上述代码主要用于产生USB设备驱动程序需要的注册表信息,需要注意的是:USB设备驱动程序不使用标准的注册表函数,而是使用RegisterClientDriverID()和RegisterClientSettings来注册相应的设备信息。[!--empirenews.page--]

另外一个函数是USBUninstallDriver()函数,具体代码如下:

extern"C"BOOL

USBUnInstallDriver()

{

BOOLfRet=FALSE;

HINSTANCEhInst=LoadLibrary(L"USBD.DLL");

if(hInst)

{

LPUN_REGISTER_CLIENT_DRIVER_IDpUnRegisterId=

(LPUN_REGISTER_CLIENT_DRIVER_ID)

GetProcAddress(hInst,gcszUnRegisterClientDriverId);

LPUN_REGISTER_CLIENT_SETTINGSpUnRegisterSettings=

(LPUN_REGISTER_CLIENT_SETTINGS)GetProcAddress(hInst,

gcszUnRegisterClientSettings);

if(pUnRegisterSettings)

{

USB_DRIVER_SETTINGSDriverSettings;

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;//bootdevice

DriverSettings.dwInterfaceProtocol=0x02;//mouse

fRet=(*pUnRegisterSettings)(gcszMouseDriverId,NULL,

&DriverSettings);

}

if(pUnRegisterId)

{

BOOLfRetTemp=(*pUnRegisterId)(gcszMouseDriverId);

fRet=fRet?fRetTemp:fRet;

}

FreeLibrary(hInst);

}

returnfRet;

}

此函数主要用于删除USBInstallDriver()时创建的注册表信息,同样的它使用自己的函数接口UnRegisterClientDriverID()和UnRegisterClientSettings()来做相应的处理。

另外一个需要处理的注册的监控通知函数USBDeviceNotifications():

extern"C"BOOLUSBDeviceNotifications(LPVOIDlpvNotifyParameter,DWORDdwCode,

LPDWORD*dwInfo1,LPDWORD*dwInfo2,LPDWORD*dwInfo3,

LPDWORD*dwInfo4)

{

CMouse*pMouse=(CMouse*)lpvNotifyParameter;

switch(dwCode)

{

caseUSB_CLOSE_DEVICE:

//删除相关的资源。

deletepMouse;

returnTRUE;

}

returnFALSE;

}

USB鼠标的类的定义如下:

classCMouse

{

public:

CMouse::CMouse(USB_HANDLEhDevice,LPCUSB_FUNCSlpUsbFuncs,

LPCUSB_INTERFACElpInterface);

~CMouse();

BOOLInitialize();

private:

//传输完毕调用的回调函数

staticDWORDCALLBACKMouseTransferCompleteStub(LPVOIDlpvNotifyParameter);

//中断处理函数

staticULONGCALLBACKCMouse::MouseThreadStub(PVOIDcontext);

DWORDMouseTransferComplete();

DWORDMouseThread();

BOOLSubmitInterrupt();

BOOLHandleInterrupt();

BOOLm_fClosing;

BOOLm_fReadyForMouseEvents;

HANDLEm_hEvent;

HANDLEm_hThread;

USB_HANDLEm_hDevice;

USB_PIPEm_hInterruptPipe;

USB_TRANSFERm_hInterruptTransfer;

LPCUSB_FUNCSm_lpUsbFuncs;

LPCUSB_INTERFACEm_pInterface;

BOOLm_fPrevButton1;

BOOLm_fPrevButton2;

BOOLm_fPrevButton3;

//数据接受缓冲区。

BYTEm_pbDataBuffer[8];

};

具体实现如下:

//构造函数,初始化时调用

CMouse::CMouse(USB_HANDLEhDevice,LPCUSB_FUNCSlpUsbFuncs,

LPCUSB_INTERFACElpInterface)

{

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));

}

//析构函数,用于清除申请的资源。

CMouse::~CMouse()

{

//通知系统去关闭相关的函数接口。

m_fClosing=TRUE;

//Wakeuptheconnectionthreadagainandgiveittimetodie.

if(m_hEvent!=NULL)

{

//通知关闭数据接受线程。

SetEvent(m_hEvent);

if(m_hThread!=NULL)

{

DWORDdwWaitReturn;

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鼠标驱动程序

BOOLCMouse::Initialize()

{

LPCUSB_DEVICElpDeviceInfo=(*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:EP0wrongtype(%u)!rn"),[!--empirenews.page--]

m_pInterface->lpEndpoints[0].Descriptor.bmAttributes));

returnFALSE;

}

DEBUGMSG(ZONE_INIT,(TEXT("USBMouse:EP0:MaxPacket:%u,Interval:%urn"),

m_pInterface->lpEndpoints[0].Descriptor.wMaxPacketSize,

m_pInterface->lpEndpoints[0].Descriptor.bInterval));

m_hInterruptPipe=(*m_lpUsbFuncs->lpOpenPipe)(m_hDevice,

&m_pInterface->lpEndpoints[0].Descriptor);

if(m_hInterruptPipe==NULL){

RETAILMSG(1,(TEXT("Mouse:Erroropeninginterruptpipern")));

return(FALSE);

}

m_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);

if(m_hEvent==NULL)

{

RETAILMSG(1,(TEXT("USBMouse:ErroronCreateEventforconnecteventrn")));

return(FALSE);

}

//创建数据接受线程

m_hThread=CreateThread(0,0,MouseThreadStub,this,0,NULL);

if(m_hThread==NULL)

{

RETAILMSG(1,(TEXT("USBMouse:ErroronCreateThreadrn")));

return(FALSE);

}

return(TRUE);

}

//从USB鼠标设备中读出数据,产生相应的鼠标事件。

BOOLCMouse::SubmitInterrupt()

{

if(m_hInterruptTransfer)

(*m_lpUsbFuncs->lpCloseTransfer)(m_hInterruptTransfer);

//从USB鼠标PIPE中读数据

m_hInterruptTransfer=(*m_lpUsbFuncs->lpIssueInterruptTransfer)

(m_hInterruptPipe,MouseTransferCompleteStub,this,

USB_IN_TRANSFER|USB_SHORT_TRANSFER_OK,//表示读数据

min(m_pInterface->lpEndpoints[0].Descriptor.wMaxPacketSize,

sizeof(m_pbDataBuffer)),

m_pbDataBuffer,

NULL);

if(m_hInterruptTransfer==NULL)

{

DEBUGMSG(ZONE_ERROR,(L"!USBMouse:ErrorinIssueInterruptTransferrn"));

returnFALSE;

}

else

{

DEBUGMSG(ZONE_TRANSFER,(L"USBMouse::SubmitInterrupt,Transfer:0x%Xrn",

m_hInterruptTransfer));

}

returnTRUE;

}

//处理鼠标中断传输的数据

BOOLCMouse::HandleInterrupt()

{

DWORDdwError;

DWORDdwBytes;

DWORDdwFlags=0;

INTdx=(signedchar)m_pbDataBuffer[1];

INTdy=(signedchar)m_pbDataBuffer[2];

BOOLfButton1=m_pbDataBuffer[0]&0x01?TRUE:FALSE;

BOOLfButton2=m_pbDataBuffer[0]&0x02?TRUE:FALSE;

BOOLfButton3=m_pbDataBuffer[0]&0x04?TRUE:FALSE;

if(!(*m_lpUsbFuncs->lpGetTransferStatus)(m_hInterruptTransfer,&dwBytes,&dwError))

{

DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse:ErrorinGetTransferStatus(0x%X)rn"),

m_hInterruptTransfer));

returnFALSE;

}

else

{

DEBUGMSG(ZONE_TRANSFER,(TEXT("USBMouse::HandleInterrupt,hTransfer0x%Xcomplete(%ubytes,Error:%X)rn"),

m_hInterruptTransfer,dwBytes,dwError));

}

if(!SubmitInterrupt())

returnFALSE;

if(dwError!=USB_NO_ERROR)

{

DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse:Error0x%Xininterrupttransferrn"),dwError));

returnTRUE;

}

if(dwBytes<3)

{

DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse:Invalidbytecnt%ufrominterrupttransferrn"),dwBytes));

returnTRUE;

}

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,

(TEXT("USBMouseevent:dx:%d,dy:%d,dwFlags:0x%X(B1:%u,B2:%u,B3:%u)rn"),

dx,dy,dwFlags,fButton1,fButton2,fButton3));

//通知系统产生鼠标事件

if(m_fReadyForMouseEvents)

mouse_event(dwFlags,dx,dy,0,0);

else

m_fReadyForMouseEvents=IsAPIReady(SH_WMGR);

returnTRUE;

}

DWORDCALLBACKCMouse::MouseTransferCompleteStub(LPVOIDlpvNotifyParameter)

{

CMouse*pMouse=(CMouse*)lpvNotifyParameter;

return(pMouse->MouseTransferComplete());

}

//数据传输完毕回调函数

DWORDCMouse::MouseTransferComplete()

{

if(m_hEvent)

SetEvent(m_hEvent);

return0;

}

ULONGCALLBACKCMouse::MouseThreadStub(PVOIDcontext)

{

CMouse*pMouse=(CMouse*)context;

return(pMouse->MouseThread());

}

//USB鼠标线程

DWORDCMouse::MouseThread()

{

DEBUGMSG(ZONE_INIT,(TEXT("USBMouse:Workerthreadstartedrn")));

SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_HIGHEST);[!--empirenews.page--]

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:Eventsignalled,buttransfernotcompletern")));

//Theonlytimethisshouldhappenisifwegetanerroronthetransfer

ASSERT(m_fClosing||(m_hInterruptTransfer==NULL));

break;

}

}

}

RETAILMSG(1,(TEXT("USBMouse:Workerthreadexitingrn")));

return(0);

}

看到了没有,其实USB的驱动程序编写就这么简单,类似的其他设备,例如打印机设备,就有BulkOUTPIPE,需要Bulk传输,那就需要了解一下IssueBulkTransfer()的应用。当然如果是开发USBMassStorageDisk的驱动,那就需要了解更多的协议,例如Bulk-OnlyTransport协议等。

微软的WindowsCE.NET的PlatformBuild中已经带有USBPrinter和USBMassStorageDisk的驱动的源代码了,好好研究一下,你一定回受益非浅的。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

深圳2024年4月17日 /美通社/ -- 今日,华为举办全球分析师大会,在"加速迈向网络智能化"主题论坛中,华为数据通信产品线副总裁赵志鹏发表了主题演讲,阐述了华为全面引入AI技术,从组件级、任务级...

关键字: NET 华为 智能化 网络

德国斯图加特和加利福尼亚州普莱森顿2024年4月16日 /美通社/ -- 全球高科技设施设计、工程和交付的领先企业Exyte宣布,计划收购全球领先的安装服务、设备和技术设施管理提供商—Kinetics集团(简称"Kine...

关键字: NET TI TE IC

好用、高效的多合一传感器开发工具,支持给新一代高科技 MEMS 传感器产品开发应用软件

关键字: 传感器 Windows MacOS

双系统将是下述内容的主要介绍对象,通过这篇文章,小编希望大家可以对双系统的相关情况以及信息有所认识和了解,详细内容如下。

关键字: 双系统 Windows Linux

今天,小编将在这篇文章中为大家带来Windows 11系统的有关报道,通过阅读这篇文章,大家可以对Windows 11系统具备清晰的认识,主要内容如下。

关键字: Windows 操作系统

(全球TMT2023年9月8日讯)亚马逊云科技日前在一年一度的存储服务创新日上宣布推出诸多亚马逊云科技存储服务的新功能,其中重点包括为支持人工智能/机器学习、大数据分析等数据密集型工作负载进一步提升Amazon Ela...

关键字: 亚马逊 FOR IC Windows

(全球TMT2023年8月24日讯)第三十届北京国际广播电影电视展览会(BIRTV2023)正在北京如火如荼地进行中。在展会上,成都索贝数码科技股份有限公司与深圳市洲明科技股份有限公司宣布签署战略合作协议,双方将携手布...

关键字: 模型 TV 编写 网络视频

此芯科技自去年加入Linaro Windows on Arm工作组之后,发起成立了Client PC合作项目,旨在推动基于UEFI + ACPI标准的Arm PC启动架构标准化,通过统一的系统固件支持Windows和Li...

关键字: Arm PC生态 Windows Linux操作系统

北京2023年3月13日 /美通社/ -- 近日,亚马逊云科技宣布针对其广泛的存储服务推出诸多可帮助客户进一步优化成本的新功能,功能更新涵盖Amazon Simple Storage Service(Amazo...

关键字: 亚马逊 STORAGE LM Windows

妇科大咖云集 共话日间诊疗新模式 北京2023年3月7日 /美通社/ -- 为进一步推广由郎景和院士牵头,朱兰教授等我国多位著名妇科医学专家共同编著《日间宫腔镜手术中心设置及管理流程中国专家共识》,普及日间宫腔镜诊疗理...

关键字: 东风 内窥镜 编写 调试
关闭
关闭