USB协议 http://www.usb.org/

Windows CE.NET 的USB系统软件分为两层: USB Client设备驱动程序和底层的Windows CE实现的函数层。USB设备驱动程序主要负责利用系统提供的底层接口配置设备,和设备进行通讯。底层的函数提本身又由两部分组成,通用串行总线驱动程序(USBD)模块和较低的主控制器驱动程序(HCD)模块。HCD负责最最底层的处理,USBD模块实现较高的USBD函数接口。USB设备驱动主要利用USBD接口函数和他们的外围设备打交道。

USB设备驱动程序主要和USBD打交道,所以我们必须详细的了解USBD提供的函数。

主要的传输函数有:

AbourtTransfer IssueControlTransfer

CloseTransfer IssueInterrupTransfer

GetIsochResult IssueIsochTransfer

GetTransferStatus IstransferComplete

IssueBulkTransfer IssueVendorTransfer

主要的用于打开和关闭USBD和USB设备之间的通信通道的函数有:

AbortPipeTransfers ClosePipe

IsDefaultPipeHalted IsPipeHalted

OpenPipe ResetDefaultPipe

ResetPipe

相应的打包函数接口有:

GetFrameLength GetFrameNumber ReleaseFrameLengthControl

SetFrameLength TakeFrameLengthControl

取得设置设备配置函数:

ClearFeature SetDescriptor

GetDescriptor SetFeature

GetInterface SetInterface

GetStatus SyncFrame

与USB进行交互的实现方法相关的多任务函数:

FindInterface RegisterClientDeviceId

GetDeviceInfo RegisterClientSettings

GetUSBDVersion RegisterNotificationRoutine

LoadGenericInterfaceDriver TranslateStringDescr

OpenClientRegisterKey UnRegisterNotificationRoutine

常见的Windows CE.NET下USB的设备驱动程序的编写有以下几种方法:

● 流式接口函数

这种驱动程序主要呈现流式函数接口,主要输出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必须为三个字符,否则会出错。但是此类的驱动程序不是通过设备管理接口来加载的,所以必须手工的调用RegisterDevice()和DeregisterDevice()函数来加载和卸载驱动程序。用户可以将此类的设备作为标准的文件来操作,只要调用相应的文件操作就可以和驱动程序打交道。

● 使用现有的Window CE.NET的应用程序接口

此类设备主要是利用Windows CE.NET中已经有了现成的函数接口,例如USB Mass Storage Disk,它主要利用现有的Windows CE.Net中已经有的可安装文件系统接口,呈现给系统可用的文件系统,对于用户来讲,它是透明的,用户仅仅感觉在操作一个文件夹。

● 创建指定到特定的USBD的用户指定的API

这种方法在USBD呈现设备时不需要任何限制,主要是特制的提供API给用户,一般不太常见。

USB设备驱动程序必须输出的函数有:

● USBDeviecAttach

当USB设备连接到计算机上时,USBD模块就会调用此函数,这个函数主要用于初始化USB设备,取得USB设备信息,配置USB设备,并且申请必需的资源。

● USBInstallDriver

主要用于创建一个驱动程序加载所需的注册表信息,例如读写超时,设备名称等。

● USBUninstallDriver

主要用于释放驱动程序所占用的资源,以及删除USBInstallDriver函数创建的注册表等。

上述的三个函数接口是所有的USB驱动程序必须提供的,缺一不可。

另外比较重要的是USB设备驱动程序的注册表配置,一般的USB设备驱动程序的注册表配置在HKEY_LOCAL_MACHINE\Drivers\USB\LoadClients下,每个驱动程序的子键都有Group1_ID\Group2_ID\Group3_ID\DriverName格式,如果注册表信息与USB设备信息符合,USBD就会加载此驱动程序。否则设备的子键应该由供应商,设备类和协议信息通过下划线组成。

具体的配置举个例子:

例如你有个PDA设备,它具有一个USB接口,它的供应厂商ID假设为0x0888,设备ID为0x0999,没有使用特殊的协议,那么它的加载注册表应该写为:

[HKEY_LOCAL_MACHINE\Drivers\USB\LoadClients\2184_2457\Default\Default\PDA] "DLL"="pdausb.dll"

需要注意的是注册表构成都是十进制数值来标识的,注意一下十进制和十六进制的转换。

再举个USB鼠标的例子,USB鼠标是标准的HID设备,它的协议为:InterfaceClassCode为3(HID类),InterfaceSubclassCode为1(引导接口类),InterfaceProtocolCode为2(鼠标协议类),所以它的注册如下:

[HKEY_LOCAL_MACHINE\Drivers\USB\LoadClients\Default\Default\3_1_2\USBMouse] "DLL"="usbmouse.dll"

到此为止,我们可以看出,其实驱动开发无非做两件事情,一件是和硬件打交道,另外一件是和操作系统打交道。举个简单的例子,例如:我们需要开发一个USB鼠标驱动程序,我们就需要了解USB鼠标硬件上是怎么发送数据的?操作系统怎么才能得到鼠标的控制事件?其实USB鼠标是有一个中断PIPE的,用于传送鼠标产生的数据,Windwos CE.NET中有个接口函数叫做mouse_event(),专门用于产生鼠标事件,但是它是不关心具体什么硬件的,甚至我们自己在应用程序中调用这个函数都可以实现模拟鼠标,对应的有个keybd_event(),用于产生键盘事件,知道了这个就好办多了,只要将相应的数据转换一下,调用一下mouse_event()即可,

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

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

Device Descriptor:

bcdUSB: 0x0100

bDeviceClass: 0x00

bDeviceSubClass: 0x00

bDeviceProtocol: 0x00

bMaxPacketSize0: 0x08 (8)

idVendor: 0x05E3 (Genesys Logic Inc.)

idProduct: 0x0001

bcdDevice: 0x0101

iManufacturer: 0x00

iProduct: 0x01

iSerialNumber: 0x00

bNumConfigurations: 0x01

ConnectionStatus: DeviceConnected

Current Config Value: 0x01

Device Bus Speed: Low

Device Address: 0x02

Open Pipes: 1

Endpoint Descriptor:

bEndpointAddress: 0x81

Transfer Type: 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_HANDLE hDevice, // USB设备句柄

LPCUSB_FUNCS lpUsbFuncs, // USBDI的函数集合

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:%u\r\n"), lpInterface->Descriptor.bInterfaceNumber,lpInterface->Descriptor.bNumEndpoints, lpInterface->Descriptor.bInterfaceClass,lpInterface->Descriptor.bInterfaceSubClass,lpInterface->Descriptor.bInterfaceProtocol));

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

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

if (pMouse == NULL)

return FALSE;

if (!pMouse->Initialize())

{

delete pMouse;

return FALSE;

}

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

(*lpUsbFuncs->lpRegisterNotificationRoutine)(hDevice,

USBDeviceNotifications, pMouse);

*fAcceptControl = TRUE;

return TRUE;

}

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

一些基本定义如下:

const WCHAR gcszRegisterClientDriverId[] = L"RegisterClientDriverID";

const WCHAR gcszRegisterClientSettings[] = L"RegisterClientSettings";

const WCHAR gcszUnRegisterClientDriverId[] = L"UnRegisterClientDriverID";

const WCHAR gcszUnRegisterClientSettings[] = L"UnRegisterClientSettings";

const WCHAR gcszMouseDriverId[] = L"Generic_Sample_Mouse_Driver";

函数接口如下:

extern "C" BOOL

USBInstallDriver(

LPCWSTR szDriverLibFile) // @parm [IN] - Contains client driver DLL name

{

BOOL fRet = FALSE;

HINSTANCE hInst = LoadLibrary(L"USBD.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 pointers\r\n")));

}

FreeLibrary(hInst);

}

return fRet;

}

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

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

extern "C" BOOL

USBUnInstallDriver()

{

BOOL fRet = FALSE;

HINSTANCE hInst = LoadLibrary(L"USBD.DLL");

if(hInst)

{

LPUN_REGISTER_CLIENT_DRIVER_ID pUnRegisterId =

(LPUN_REGISTER_CLIENT_DRIVER_ID)

GetProcAddress(hInst, gcszUnRegisterClientDriverId);

LPUN_REGISTER_CLIENT_SETTINGS pUnRegisterSettings =

(LPUN_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,

&DriverSettings);

}

if(pUnRegisterId)

{

BOOL fRetTemp = (*pUnRegisterId)(gcszMouseDriverId);

fRet = fRet ? fRetTemp : fRet;

}

FreeLibrary(hInst);

}

return fRet;

}

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

另外一个需要处理的注册的监控通知函数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:

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

static DWORD CALLBACK MouseTransferCompleteStub(LPVOID lpvNotifyParameter);

// 中断处理函数

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;

// 数据接受缓冲区。

BYTE m_pbDataBuffer[8];

};

具体实现如下:

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

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

}

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

CMouse::~CMouse()

{

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

m_fClosing = TRUE;

// Wake up the connection thread again and give it time to die.

if (m_hEvent != NULL)

{

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

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)!\r\n"),

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

return FALSE;

}

DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: EP 0:MaxPacket: %u, Interval: %u\r\n"),

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: Error opening interrupt pipe\r\n")));

return (FALSE);

}

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

if (m_hEvent == NULL)

{

RETAILMSG(1,(TEXT("USBMouse: Error on CreateEvent for connect event\r\n")));

return(FALSE);

}

// 创建数据接受线程

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

if (m_hThread == NULL)

{

RETAILMSG(1,(TEXT("USBMouse: Error on CreateThread\r\n")));

return(FALSE);

}

return(TRUE);

}

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

BOOL CMouse::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: Error in IssueInterruptTransfer\r\n"));

return FALSE;

}

else

{

DEBUGMSG(ZONE_TRANSFER,(L"USBMouse::SubmitInterrupt,Transfer:0x%X\r\n",

m_hInterruptTransfer));

}

return TRUE;

}

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

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)\r\n"),

m_hInterruptTransfer));

return FALSE;

}

else

{

DEBUGMSG(ZONE_TRANSFER,(TEXT("USBMouse::HandleInterrupt, hTransfer 0x%X complete (%u bytes, Error:%X)\r\n"),

m_hInterruptTransfer,dwBytes,dwError));

}

if (!SubmitInterrupt())

return FALSE;

if(dwError != USB_NO_ERROR)

{

DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error 0x%X in interrupt transfer\r\n"),dwError));

return TRUE;

}

if(dwBytes < 3)

{

DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Invalid byte cnt %u from interrupt transfer\r\n"),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,

(TEXT("USBMouse event: dx:%d, dy:%d, dwFlags:0x%X (B1:%u, B2:%u, B3:%u)\r\n"),

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

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

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

}

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

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 started\r\n")));

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 complete\r\n")));

// 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 exiting\r\n")));

return(0);

}

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

微软的Windows CE.NET的Platform Build中已经带有USB Printer和USB Mass Storage Disk的驱动的源代码了,好好研究一下,你一定回受益非浅的。

转载于:https://www.cnblogs.com/jiegekaoyan/archive/2010/07/31/1789099.html

WinCE的USB驱动开发相关推荐

  1. 2008年12月13日上海USB驱动开发深度解析讲座PPT

    讲座PPT:宋宝华2008年12月13日上海USB驱动开发深度解析讲座PPT [url]http://www.linuxdriver.cn/200812/20081213172619_836.rar[ ...

  2. MF Porting之USB驱动开发

    花费了近三个礼拜的时间,终于完成了TI开发板的USB驱动开发,现在回头想一想,其实也没有什么,具体硬件方面的通信由DM355实现了,软件层面的数据交互由MF Porting实现了,所做的也就是熟悉了解 ...

  3. Linux USB 驱动开发(五)—— USB驱动程序开发过程简单总结

    http://blog.csdn.net/zqixiao_09/article/details/51057086 设备驱动程序是操作系统内核和机器硬件之间的接口,由一组函数和一些私有数据组成,是应用程 ...

  4. 【.Net Micro Framework PortingKit(补) – 1】USB驱动开发

    在前段时间我连续写了15篇关于[.Net Micro Framework PortingKit–?]的系列文章,初步介绍了.Net Micro Framework在Cortex-M3平台上的移植过程, ...

  5. 【.Net Micro Framework PortingKit(补) – 1】USB驱动开发 1

    前段时间我连续写了15篇关于[.Net Micro Framework PortingKit–?]的系列文章,初步介绍了.Net Micro Framework在Cortex-M3平台上的移植过程,最 ...

  6. Linux USB 驱动开发实例(七)—— 基于USB 总线的无线网卡浅析

    回顾一下USB的相关知识 USB(Universal Serial Bus)总线又叫通用串行外部总线, 它是20世纪90年代发展起来的.USB接口现在得到了广泛的应用和普及,现在的PC机中都带有大量的 ...

  7. c语言+usb驱动开发,usb驱动程序分析

    usb驱动是linux内核中比较复杂的驱动之一,因此,大多数usb教程建议从usb-skeleton开始学习usb驱动.个人认为这是相当正确的,usb-sekelton提供了一个usb驱动开发的模板, ...

  8. linux 下usb驱动开发,LINUX_ARM下的USB驱动开发.pdf

    LINUX_ARM下的USB驱动开发 CN 431258 / TP 计算机工程与科学 2006年第 28卷第 3期 ISSN 1007130X COM PU TER EN GIN EER IN G & ...

  9. usb扫描枪驱动下载 wince_WinCE系列全站仪USB驱动程序(WinCE全站仪USB驱动) 最新中文版...

    WinCE系列全站仪USB驱动程序(WinCE全站仪USB驱动) 最新中文版 WinCE系列全站仪usb驱动程序是一款WinCE系列全站仪连接USB驱动同步软件,适合全系列Windows操作系统,支持 ...

最新文章

  1. 【Kali渗透全方位实战】Linux终端和基本Linux命令terminator
  2. 耳鼻喉专科服务机构“仁树医疗”完成数千万元A轮融资...
  3. 配置 VIM 英语字典
  4. python phpstudy_Java、python及phpstudy的环境配置
  5. C++ Opengl 3D世界源码
  6. 基于Docker的TensorFlow机器学习框架搭建和实例源码解读
  7. 如何更改Docker默认的images存储位置
  8. java容器类继承_JAVA容器 - weslie - OSCHINA - 中文开源技术交流社区
  9. RabbitMQ工作笔记-新建用户及创建虚拟主机
  10. 芯烨打印机api密钥php,CCXT中文开发手册
  11. 网吧服务器ip地址修改,BXP服务器下的网吧ip地址怎么更改
  12. 思科CCNP培训中OSPF协议之详细图解-IELAB
  13. c# cad二次开发图表绘制
  14. java block报错图_Poi读取Excle报错 java.util.zip.ZipException: invalid stored block lengths
  15. spoon mysql_spoon(kettle)基本配置(连接Mysql和Oracle)
  16. 断言(C++大师Andrei Alexandrescu的文章)
  17. 自己开发了一个JsonViewer工具--FrogJson
  18. 大数据入门看哪些书比较好
  19. 如何在在网站上下载视频
  20. 休谟与人机、因果、实践

热门文章

  1. c++ 数据结构之 线段树
  2. Lucas+阶乘打表+费马小定理模板2.0
  3. vscode 使用技巧(持续更新)
  4. python实现tkinter可视化一
  5. 【Proteus仿真8086】将IO接口电路封装成子电路CCT001
  6. 记2020年秋季学期的微波期末考试
  7. 贺利坚老师汇编课程54笔记:CF进位标志CARRY FLAG
  8. AD的小知识贴片的template
  9. 葡萄城报表介绍:数据钻取
  10. 第一个ExtJS练习(添加用户面板)