USB HID 设备驱动程序设计
usbhid 触摸屏驱动实现原理
USB HID(Human Interface Device)触摸屏驱动的实现原理涉及到USB HID协议和触摸屏设备的工作原理。
1. USB HID协议:USB HID是一种用于描述人机交互设备(如键盘、鼠标、触摸屏等)通讯协议的标准。
通过USB HID协议,计算机可以与支持HID的设备进行通讯,获取设备所提供的数据。
触摸屏作为一种HID设备,其驱动程序需要遵循USB HID协议与计算机进行通讯,接收和发送数据。
2. 触摸屏工作原理:触摸屏设备通过感应用户手指触摸位置并将其转换成电信号。
常见的触摸屏技术包括电阻式触摸屏、电容式触摸屏、表面声波触摸屏等。
不同类型的触摸屏有不同的工作原理,但它们都会将用户的触摸位置信息转换成数字信号,并通过USB接口传输给计算机。
基于以上原理,USB HID触摸屏驱动的实现需要完成以下步骤:- 设备识别:计算机通过USB接口识别触摸屏设备,并加载相应的驱动程序。
- 数据通讯:驱动程序遵循USB HID协议与触摸屏设备进行数据通讯,获取触摸位置、手势等信息,并将其传输给操作系统。
- 数据处理:驱动程序接收到来自触摸屏设备的原始数据后,需要进行适当的处理,将其转换成操作系统能够理解的格式,如将触摸位置信息转换成鼠标移动事件或触摸手势事件。
- 与操作系统交互:驱动程序与操作系统进行交互,将处理后的触摸屏数据传递给操作系统,使得操作系统能够正确地响应触摸操作。
总的来说,USB HID触摸屏驱动的实现依赖于对USB HID协议的理解和遵循,以及对触摸屏设备工作原理的理解和数据处理能力。
驱动程序需要负责与设备通讯、数据处理和操作系统交互等任务,以实现对触摸屏设备的控制和数据传输。
c++mfc界面读写usbhid设备数据程序
第一步:列举所有的HID设备:(); .");continue;}=sizeof(HIDD_ATTRIBUTES);if (!HidD_GetAttributes(hCom,&devAttr)){CloseHandle(hCom);AfxMessageBox("Cannot get the parameters of the HID..."); return 0;}.");return 0;}if(!HidP_GetCaps(PreparsedData,&Capabilities)){CloseHandle(hCom);AfxMessageBox("Cannot get the Cap Data...");return 0;}if == venderID && == productID){while(1){result1 = ReadFile(hCom, &inbuffer[0], , &numBytesReturned, 0); temp=inbuffer;.");return 0;readValue=inbuffer[1];p->("%d",readValue);.");return 0;}}}}if (i==j){AfxMessageBox("There is no such HID device...");}return 0;第三步:向HID设备写数据(根据用户提供的HID的vendorID和productID),用户输入的是二进制数据:与读的程序一样,唯一区别就是红色那部分!UpdateData(true);bStopHID=false;CString temp;CString DevicePath;temp="";int Count = 0; .");continue;}=sizeof(HIDD_ATTRIBUTES);if (!HidD_GetAttributes(hCom,&devAttr)){CloseHandle(hCom);AfxMessageBox("Cannot get the parameters of the HID...");return;}.");return;if(!HidP_GetCaps(PreparsedData,&Capabilities)) {CloseHandle(hCom);AfxMessageBox("Cannot get the Cap Data..."); return;}.");return;}AfxMessageBox("Suncess...");break;}}if (i==j){AfxMessageBox("There is no such HID device..."); }return;。
C++MFC界面读写USBHID设备数据程序文件
第一步:列举所有的HID设备:m_ctllHIDdevices.ResetContent(); //这是MFC里面一个list控件,用来显示所有的HID 设备的,如果你没有界面,可以不需要此行UpdateData(FALSE); //更新界面CString temp;int Count = 0; //Total number of devices foundDWORD strSize=0,requiredSize=0;BOOL result1,result2;ULONG DeviceInterfaceDetailDataSize;//定义一些变量,以后会用到SP_DEVINFO_DATA DeviceInfoData;SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;//PSP_DEVICE_INTERFACE_DETAIL_DATA test;//第一步:获取deviceIDGUID deviceId;HidD_GetHidGuid(&deviceId);//第二步:获取设备信息HDEVINFO handle;handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devices//第三步:对所有的设备进行枚举//SetupDiEnumDeviceInterfaces();result1=false; //定义一些变量result2=false;CString temp11="";do{DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);result1 = SetupDiEnumDeviceInterfaces(handle,NULL, // IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL&deviceId,Count,&DeviceInterfaceData);//获得设备详细数据(初步)SetupDiGetDeviceInterfaceDetail(handle,&DeviceInterfaceData,NULL,0,&strSize,NULL);requiredSize=strSize;DeviceInterfaceDetailData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize );DeviceInterfaceDetailData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); DeviceInfoData.cbSize=s第一步:列举所有的HID设备:m_ctllHIDdevices.ResetContent(); //这是MFC里面一个list控件,用来显示所有的HID 设备的,如果你没有界面,可以不需要此行UpdateData(FALSE); //更新界面CString temp;int Count = 0; //Total number of devices foundDWORD strSize=0,requiredSize=0;BOOL result1,result2;ULONG DeviceInterfaceDetailDataSize;//定义一些变量,以后会用到SP_DEVINFO_DATA DeviceInfoData;SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;//PSP_DEVICE_INTERFACE_DETAIL_DATA test;//第一步:获取deviceIDGUID deviceId;HidD_GetHidGuid(&deviceId);//第二步:获取设备信息HDEVINFO handle;handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devices//第三步:对所有的设备进行枚举//SetupDiEnumDeviceInterfaces();result1=false; //定义一些变量result2=false;CString temp11="";do{DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);result1 = SetupDiEnumDeviceInterfaces(handle,NULL, // IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL&deviceId,Count,&DeviceInterfaceData);//获得设备详细数据(初步)SetupDiGetDeviceInterfaceDetail(handle,&DeviceInterfaceData,NULL,0,&strSize,NULL);requiredSize=strSize;DeviceInterfaceDetailData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize );DeviceInterfaceDetailData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); DeviceInfoData.cbSize=sizeof(SP_DEVINFO_DATA);//再次获得详细数据result2=SetupDiGetDeviceInterfaceDetail(handle,&DeviceInterfaceData,DeviceInterfaceDetailData,strSize,&requiredSize,&DeviceInfoData);//获得设备路径(最重要的部分)temp=DeviceInterfaceDetailData->DevicePath;UpdateData(FALSE);m_ctllHIDdevices.AddString(temp);Count++;} while (result1);UpdateData(false);izeof(SP_DEVINFO_DATA);//再次获得详细数据result2=SetupDiGetDeviceInterfaceDetail(handle,&DeviceInterfaceData,DeviceInterfaceDetailData,strSize,&requiredSize,&DeviceInfoData);//获得设备路径(最重要的部分)temp=DeviceInterfaceDetailData->DevicePath;UpdateData(FALSE);m_ctllHIDdevices.AddString(temp);Count++;} while (result1);UpdateData(false);第二步:循环读取HID设备数据(根据用户提供的HID的vendorID和productID),并且把字节解码成二进制,在MFC界面上用LED展示:为了不影响主线程的运行,我把读取数据的操作,放在一个子线程里!每隔50ms去读取一次数据!首先创建一个线程:HANDLE hThread1;bStopHID=false; //这个变量,以后用来停止线程UpdateData(true); //更新界面,获取变量UpdateData(false);hThread1 = CreateThread(NULL,0,Thread_Enable_Read,(LPVOID)this, NULL, NULL);在线程的程序里:CusbhidDlg *p = ( CusbhidDlg *)pvParam; //获取主窗口的指针,用来调用主窗口的变量和函数p->UpdateData(true);p->bStopHID=false;CString temp;CString DevicePath;temp="";int Count = 0; //Total number of devices foundDWORD strSize=0,requiredSize=0;BOOL result1,result2;ULONG DeviceInterfaceDetailDataSize;SP_DEVINFO_DATA DeviceInfoData;SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;//PSP_DEVICE_INTERFACE_DETAIL_DATA test;//1GUID deviceId;HidD_GetHidGuid(&deviceId);int venderID=p->v_eVendorID; //从窗口里获取用户输入的VendorIDint productID=p->v_eProductID;//从窗口里获取用户输入的ProductIDunsigned char inbuffer[2]; //用来存放读取的数据,请在这里定义你自己需要的长度,我每次读一个字节进来unsigned long numBytesReturned;HIDD_ATTRIBUTES devAttr;PHIDP_PREPARSED_DATA PreparsedData;HIDP_CAPS Capabilities;int readValue;bool LED;int flag=0;//2HDEVINFO handle;handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devicesint i=0;int j=p->m_ctllHIDdevices.GetCount();for (i=0;i<p->m_ctllHIDdevices.GetCount();i++){p->m_ctllHIDdevices.GetText(i,temp);DevicePath=temp;//CreateFile是非常重要的一步,用来建立于HID通信的句柄HANDLE hCom = CreateFile (DevicePath,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING, 0,NULL);if (hCom == INVALID_HANDLE_VALUE){//AfxMessageBox("Invalide Device Path...");continue;}devAttr.Size=sizeof(HIDD_ATTRIBUTES);if (!HidD_GetAttributes(hCom,&devAttr)){CloseHandle(hCom);AfxMessageBox("Cannot get the parameters of the HID...");return 0;}//temp.Format("Vendor ID: %d, Product ID:%d",devAttr.VendorID,devAttr.ProductID); //Compare with the Vendor ID and Product ID from Nakamura-san//AfxMessageBox(temp);if (!HidD_GetPreparsedData(hCom,&PreparsedData)){CloseHandle(hCom);AfxMessageBox("Cannot get the Preparsed Data...");return 0;}if(!HidP_GetCaps(PreparsedData,&Capabilities)){CloseHandle(hCom);AfxMessageBox("Cannot get the Cap Data...");return 0;}if (devAttr.VendorID == venderID && devAttr.ProductID == productID){while(1){result1 = ReadFile(hCom, &inbuffer[0], Capabilities.InputReportByteLength, &numBytesReturned, 0);temp=inbuffer;//p->m_eDataRead=CString(inbuffer);//p->UpdateData(false);if(!result1){AfxMessageBox("Cannot Read Data...");return 0;}readValue=inbuffer[1];p->m_eDataRead.Format("%d",readValue);//下面是我把数据从10进制转换成二进制,并且点亮LED (一个字节有8个bits,可以点亮8个LEDfor (int k=0;k<8;k++){flag=readValue%2;readValue=readValue/2;if (k==0){if (flag==0)p->m_sDynLED0.SwitchOff();elsep->m_sDynLED0.SwitchOn();}else if (k==1){if (flag==0)p->m_sDynLED1.SwitchOff();elsep->m_sDynLED1.SwitchOn();}else if (k==2){if (flag==0)p->m_sDynLED2.SwitchOff(); elsep->m_sDynLED2.SwitchOn(); }else if (k==3){if (flag==0)p->m_sDynLED3.SwitchOff(); elsep->m_sDynLED3.SwitchOn(); }else if (k==4){if (flag==0)p->m_sDynLED4.SwitchOff(); elsep->m_sDynLED4.SwitchOn(); }else if (k==5){if (flag==0)p->m_sDynLED5.SwitchOff(); elsep->m_sDynLED5.SwitchOn(); }else if (k==6){if (flag==0)p->m_sDynLED6.SwitchOff();elsep->m_sDynLED6.SwitchOn();}else if (k==7){if (flag==0)p->m_sDynLED7.SwitchOff();elsep->m_sDynLED7.SwitchOn();}}p->UpdateData(false);::Sleep(50);//判断用户是否点击停止按钮,若是,则退出if(p->bStopHID){AfxMessageBox("stopped...");return 0;}}}}if (i==j){AfxMessageBox("There is no such HID device..."); }return 0;第三步:向HID设备写数据(根据用户提供的HID的vendorID和productID),用户输入的是二进制数据:与读的程序一样,唯一区别就是红色那部分!UpdateData(true);bStopHID=false;CString temp;CString DevicePath;temp="";int Count = 0; //Total number of devices foundDWORD strSize=0,requiredSize=0;BOOL result1,result2;ULONG DeviceInterfaceDetailDataSize;SP_DEVINFO_DATA DeviceInfoData;SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;//PSP_DEVICE_INTERFACE_DETAIL_DATA test;//1GUID deviceId;HidD_GetHidGuid(&deviceId);int venderID=v_eVendorID;int productID=v_eProductID;unsigned char inbuffer[2];unsigned long numBytesReturned;HIDD_ATTRIBUTES devAttr;PHIDP_PREPARSED_DATA PreparsedData;HIDP_CAPS Capabilities;int readValue;bool LED;int flag=0;inbuffer[0]=0;//把界面里的二进制转换成10进制inbuffer[1]=m_eByte0*1+m_eByte1*2+m_eByte2*4+m_eByte3*8+m_eByte4*16+m_eByte5*32 +m_eByte6*64+m_eByte7*128;v_eDataToWrite=inbuffer[1];UpdateData(false);//2HDEVINFO handle;handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devicesint i=0;int j=m_ctllHIDdevices.GetCount();for (i=0;i<m_ctllHIDdevices.GetCount();i++){m_ctllHIDdevices.GetText(i,temp);DevicePath=temp;HANDLE hCom = CreateFile (DevicePath,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING, 0,NULL);if (hCom == INVALID_HANDLE_VALUE){//AfxMessageBox("Invalide Device Path...");continue;}devAttr.Size=sizeof(HIDD_ATTRIBUTES);if (!HidD_GetAttributes(hCom,&devAttr)){CloseHandle(hCom);AfxMessageBox("Cannot get the parameters of the HID...");return;}//temp.Format("Vendor ID: %d, Product ID:%d",devAttr.VendorID,devAttr.ProductID); //Compare with the Vendor ID and Product ID from Nakamura-san//AfxMessageBox(temp);if (!HidD_GetPreparsedData(hCom,&PreparsedData)){CloseHandle(hCom);AfxMessageBox("Cannot get the Preparsed Data...");return;}if(!HidP_GetCaps(PreparsedData,&Capabilities)){CloseHandle(hCom);AfxMessageBox("Cannot get the Cap Data...");return;}// Write Fileif (devAttr.VendorID == venderID && devAttr.ProductID == productID) {result1 = WriteFile(hCom, inbuffer, 2, &numBytesReturned, NULL);//temp=inbuffer;//p->m_eDataRead=CString(inbuffer);//p->UpdateData(false);if(!result1){AfxMessageBox("Cannot Write Data...");return;}AfxMessageBox("Suncess...");break;}}if (i==j){AfxMessageBox("There is no such HID device...");}return;。
USB_HID协议中文版——USB接口HID设备
USB_HID协议中文版——USB接口HID设备
一、什么是USBHID协议
USB HID(Human Interface Device)协议是一种应用在USB接口上
的应用层通信协议,它不仅定义了用于特定应用的设备的接口规范,而且
可以帮助开发者更快捷、更准确地实现其产品化。
USB HID是USB接口应用层通信协议中最常用的一种协议,它通过主
机和设备之间的endpoints来建立简单的通信框架,从而实现设备连接和
输入输出控制。
最初被设计用于用户界面(如鼠标、键盘等),但它的应
用领域已经不仅限于此,无论是电源管理控制、温度控制器、读卡器、按键、触摸板或其他交互式设备,都可以通过USB HID来实现。
二、USBHID协议框架
USBHID协议规范定义了主机与设备之间的通信机制,其使用形式类
似于USB驱动程序,主要有以下几个部分:
1、Device Definition:描述支持HID协议的设备的特性,包括设备
所具备的功能,如鼠标按键、键盘、触摸板等;
2、Descriptor:定义设备的接口,描述设备与用户界面之间的结构
关系;
3、Report Descriptor:描述报告的格式,定义HID设备的所有输入
和输出数据;
4、Input Report:指从键盘、鼠标、按钮等设备向主机发送的数据;
5、Output Report:指从主机向设备发送的数据,以从设备更改状态
或进行其他操作;
6、Feature Report:当输入输出数据不足以满足需求时。
USB多点触摸设备的固件程序设计
t h e USB mu l t i — t ou ch d e vi ce s b as ed on t h e ST C89 C52 RC mi c r o co n t r ol u ni t a nd PDI USBD1 2 c hi p. I t f i r s t l y i n t r odu c es t h e ba s i c k n o wl edg e o f USB an d HI D Se co ndl y , r e pr es en t t he ha r d wa r e de s i gn o f t h e de v i ce i n de t a i l . Fi n al l y , t hi s p ape r di s cu s s e s t h e
和 R S 一 2 3 2的调 试 功 能 。 整体 的系 统 结 构 如 图 1所 示 。 R S 一 2 3 2
串 口部 分 , 一 方 面用 于 调 试 时 查 看 主 机 返 回的 数 据 信 息 ; 另 一 方 面 向 单 片机 传 送 模 拟 的 触 摸 点信 息 ,如 触点 个 数 和各 触 摸 点 的
关键词 : 通 用 串行 总线 , 人 机 接 口设 备 , 多点 触摸 , 描述符, S T C 8 9 C5 2 R C, P DI U S BD 1 2
Ab s t r a c t
I n t h e s e d a y s , U S B D e v i c e s h a v e a l r e a d y b e c o m e v e r y p o p u l a r , e s p e c i a l l y t h e H I D ( H u ma n I n t e r f a c e D e v i c e ) D e v i c e s I t
USB HID协议中文版——USB接口HID设备
第8章USB接口HID设备HID(Human Interface Device,人机接口设备)是USB设备中常用的设备类型,是直接与人交互的USB设备,例如键盘、鼠标与游戏杆等。
在USB设备中,HID设备的成本较低。
另外,HID设备并不一定要有人机交互功能,只要符合HID类别规范的设备都是HID设备。
Wndows操作系统最先支持的HID设备。
在windows 98以及后来的版本中内置有HID 设备的驱动程序,应用程序可以直接使用这些驱动程序来与设备通信。
在设计一个USB接口的计算机外部设备时,如果HID类型的设备可以满足需要,可以将其设计为HID类型设备,这样可以省去比较复杂的USB驱动程序的编写,直接利用Windows操作系统对标准的HID类型USB设备的支持。
8.1 HID设备简介8.1.1 HID设备的特点•交换的数据储存在称为报表(Report)的结构内,设备的固件必须支持HlD报表的格式。
主机通过控制和中断传输中的传送和请求报表来传送和接收数据。
报表的格式非常灵活。
•每一笔事务可以携带小量或中量的数据。
低速设备每一笔事务最大是8B,全速设备每一笔事务最大是64B,高速设备每一笔事务最大是1024B。
一个报表可以使用多笔事务。
•设备可以在未预期的时间传送信息给主机,例如键盘的按键或是鼠标的移动。
所以主机会定时轮询设备,以取得最新的数据。
•HID设备的最大传输速度有限制。
主机可以保证低速的中断端点每10ms内最多1笔事务,每一秒最多是800B。
保证全速端点每lms一笔事务,每一秒最多是64000B。
保证高速端点每125 us三笔事务,每一秒最多是24.576MB。
•HID设备没有保证的传输速率。
如果设备是设置在10ms的时距,事务之间的时间可能等于或小于10ms。
除非设备是设置在全速时在每个帧传输数据,或是在高速时在每个微帧传输数据。
这是最快的轮询速率,所以端点可以保证有正确的带宽可供使用。
CE中USB HID设备驱动开发
一. 理解: CE中USB HID设备的工作流程要想知道如何去设计一个自己的HID设备的驱动程序. 那么对CE中的USB HID设备工作的流程的初步了解是十分必要的. Microsoft公司已经在CE系统中增加了键盘/鼠标两种HID设备的驱动. 我们就从键盘驱动入手.CE的所有USB程序都在public\common\oak\drivers\usb下面. 在该文件夹下,分成了CLASS,CLIENTS,COMMON,HCD,INC,USBD几个文件夹,其中INC和COMMON里面有一个lock.c的程序,这个程序很明显是将要被其他USB有关的驱动程序所使用的一个锁,代码很简单,只是一个类似临界区的封装体,可以保护多线程对同一内存区域的读写访问,可以先不去管它。
CLIENTS文件夹可能最初微软的开发人员是用来放置设备驱动程序的,但是后来没有放,而发布的时候也没有删除,所以遗留了下来,里面是个空的文件夹,所以没用实际用处。
USBD和HCD是前述的底层驱动,里面含有很多子文件夹和程序,由于我们只针对USB设备驱动,因此对这两部分不做分析,有兴趣的朋友可以自己去了解. 重点就在CLASS文件夹了,展开来看,里面又包含了COMMON、HID、PRINTER、STORAGE几个文件夹,同样,COMMON里面存放的源程序是为HID、PRINTER、STORAGE 所共有的。
HID是USB输入设备如键盘/鼠标的样例驱动程序,PRINTER是USB打印机的样例驱动程序,STORAGE 是USB存储设备如U盘的样例程序.我们在这篇文章中只讲如何设备USB HID设备驱动. 因此我们只看HID路径下的所有程序.在HID下有CLIENTS和HIDCLASS两个文件夹. HIDCLASS里有所有HID设备驱动的共用代码(MDD和PDD). 我们在这里暂时不讲述.对于一个对CE系统不是非常熟悉的新手来说. 要想知道USB HID设备自插入后. 在Windows CE这个黑盒子里是怎么运行的. 里面到底发生了什么事. 我个人觉得最好在每个程序里设置一些标记. 通过串口将里面所发生的事情传出来并打印到我们的调试PC上面. 我们可以用:RETAILMSG(1, (TEXT(“HIDDeviceNotifications---conshid\r\n”)));来告诉程序员此时调用了conshid.cpp文件下的HIDDeviceNotifications函数.在将HID路径下所有的函数中增加了标记后. 编译.. 下栽…运行… 插入一个USB键盘后. 从串口处的到的信息如下:>DllEntry--usbhid (1)>HidMdd_DllEntry--hidmdd>USBDeviceAttach--usbhid>ParseUsbDescriptors--setup (4)>CreateHidInterface--setup (5)>Init--hidmdd>HID_Init--usbhid>SetUsbInterface--setup>SetReportProtocol--setup>GetReportDescriptor--setup>SetQueuedTransfers--setup>HidMdd_Attach--hidmdd (6)InitializeTLCStructures--hidmdd>LoadHidClients--hidmdd>FindClientRegKey--hidmdd>OpenClientRegKey--hidmdd>OpenSpecificClientRegKey--hidmddOpenSpecificClientRegKey key string:2362_9488_256>OpenSpecificClientRegKey--hidmddOpenSpecificClientRegKey key string:2362_9488>OpenSpecificClientRegKey--hidmddOpenSpecificClientRegKey key string:2362>OpenSpecificClientRegKey--hidmdd>OpenSpecificClientRegKey--hidmddOpenSpecificClientRegKey key string:0_1>OpenSpecificClientRegKey--hidmddOpenSpecificClientRegKey key string:0>OpenSpecificClientRegKey--hidmdd>OpenSpecificClientRegKey--hidmddOpenSpecificClientRegKey key string:1_2MOUHID DllEntry! (7)Mouse Attached!>AllocateUsageLists--mouhidCreateInterruptThread--setupMouseThreadProc!>InterruptThreadProc--setup>StartInterruptTransfer--setup>StartInterruptTransfer--setup>StartInterruptTransfer--setup>StartInterruptTransfer--setup>USBDeviceNotifications--usbhid>USB_CLOSE_DEVICE>HidMdd_Notifications--hidmddFreeHidContext--hidmdd>HIDDeviceNotifications--mouhidMouse moved!MOUHID DllEntry!>StartInterruptTransfer--setup>DllEntry--usbhid>HidMdd_DllEntry--hidmdd从以上的信息我们可以看出. 一插入USB鼠标. 系统就会调用usbdhid.cpp中的DllEntry这个动态链接库的入口函数. 这个比较好理解. 然后系统将调用hidmdd中的HidMdd_DllEntry函数. 这两个函数所做的工作不多. 我们基本可以不用太关心这两个函数.一旦系统发现有新的HID设备.usbhid中的USBDeviceAttach这个函数被调用. USBDeviceAttach中又调用(4)ParseUsbDescriptors主要是分析此USB设备的描述符. 在分析此USB设备为HID类设备后. 调用(5)CreateHidInterface. 主要是建立一个HID设备上下文. 并给这个设备上下文赋值. 这里的提一下. 在CreateHidInterface函数中调用了HidMdd_Attach这个函数. 传给这个函数的参数为分析得到的USB设备的描述符.这个在第(6)步可以看的出来. 在HidMdd_Attach中产生一个HID设备上下文.我怀疑这个函数中调用的那个HidP_GetCollectionDescription是处理HID设备的驱动文件位置有关系.但这个函数只是PUBLIC\COMMON\OAK\LIB\ARMV4I\RETAIL下的一个库文件中的函数. 见hidparse.def. 这个函数的参数主要是设备报告描述符和PHID_CONTEXT指向HID设备上下文的指针. 在*PHID_CONTEXT结构中我们看到有HidTLCQueue *pQueues.和一个struct _HID_CLIENT_HANDLE元素. 还有就是HID设备的其他描述符号HIDP_DEVICE_DESC及设备句柄._HID_CLIENT_HANDLE结构在hiddi.h中可以看出来. 里面有DWORD dwUsagePage;和DWORD dwUsage;在HidMdd_Attach用InitializeTLCStructures初始化该上下文. 最后用LoadHidClients 函数加载这个USB HID设备. 在LoadHidClients中寻找并注册本USB设备注册键.调用FindClientRegKey. 这个函数的参数有两个. &driverSettings. pClientHandle->driverSettings.类型分别是:HID_DRIVRE_SETTINGS 和PHID_CLIENT_HANDLEFindClientRegKey调用OpenClientRegKey函数. 这是根据HID设备的信息来寻找驱动.在OpenClientRegKey函数中多次调用OpenSpecificClientRegKey寻找匹配的HID设备.在OpenSpecificClientRegKey中我们在pszKey = szBuf;后面加一条调试信息:RETAILMSG(1,(TEXT("OpenSpecificClientRegKey key string:%s\r\n"),pszKey));调试信息如下. OpenSpecificClientRegKey key string:2362_9488_256 (21A)>OpenSpecificClientRegKey--hidmddOpenSpecificClientRegKey key string:2362_9488 (21B)>OpenSpecificClientRegKey--hidmddOpenSpecificClientRegKey key string:2362 (21C)>OpenSpecificClientRegKey--hidmdd>OpenSpecificClientRegKey--hidmddOpenSpecificClientRegKey key string:0_1 (31A)>OpenSpecificClientRegKey--hidmddOpenSpecificClientRegKey key string:0 (31B)>OpenSpecificClientRegKey--hidmdd>OpenSpecificClientRegKey--hidmddOpenSpecificClientRegKey key string:1_2 (41A)通过PC上的USB device viewer软件可以看出这个鼠标的idVendor/idProduct/bcdDevice分别是:0x093A/0x2510/0x0100. 转成十进制为:2362/9488/256与第一次得到的注册字键字符串吻合.这个鼠标的接口描述符中的bInterfaceClass/bInterfaceSubClass/bInterfaceProtocol分别是: 0x03 / 0x01 / 0x02. 这个与最后一个字符串相符. 但中间的0_1和0就不明白.当我一直在为驱动程序的注册表位置与HID设备类型的关系而绞尽脑汁时候.看到OpenClientRegKey函数有一段Microsoft的注释:可能是微软为了加快读者对这个问题的理解而特别写的注释.// The order of verndor precedence is described below.//// idVendor_idProduct_bcdDevice (21A)// idVendor_idProduct (21B)// idVendor (21C)// Default// The order of interface precedence is described below.//// bInterface_bCollection (31A)// bInterface (31B)// Default// The order of TLC precedence is//// UsagePage_Usage (41A)// UsagePage// Default// So the order of checking would be (50A)// 1.idVendor_idProduct_bcdDevice\bInterface_bCollection\UsagePage_Usage// 2.idVendor_idProduct_bcdDevice\bInterface_bCollection\UsagePage// .....// 42.Default\bInterface_bCollection\Default// 43.Default\bInterface\UsagePage_Usage// 44.Default\bInterface\UsagePage// 45.Default\bInterface\Default// 46.Default\Default\UsagePage_Usage (54_7A)// 47.Default\Default\UsagePage// 48.Default\Default\Default大家再看下common.reg下的[HKEY_LOCAL_MACHINE\Drivers\HID\LoadClients\Default\Default\1_2\Mouse] (61A)"DLL" = "MOUHID.DLL"这里的MOUHID.DLL正是我们的的USB鼠标的驱动程序. 那么在注册表文件中. 这个1_2是什么意思呢?从以上的注释的出的结论就是1_2原来就是设备的UsagePage_Usage. 而不是设备描述符的bInterfaceSubClass/bInterfaceProtocol.搜索的顺序应该是以50A以下的48种方式搜索. 我们在common.reg下定义的注册位置就是按照(54_7A)方式来存放的.这两个数据在FindClientRegKey中是由rgdwTLCVals[]传给OpenClientRegKey函数的.首先看bInterface_bCollection两个数据是怎么的到的.在FindClientRegKey函数中.看到:const DWROD rgdwInterfaceVals[]={pDriverSettings->dwInterfaceNumber,pDriverSettings->dwCollection};这个rgdwInterfaceVals是OpenClientRegKey的一个参数. 这个也是在寻找驱动时候的一个依据bInterface_bCollection. rgdwInterfaceVals是由LoadHidClients函数的第5个参数DWORD dwInterface赋值pDriverSettings->dwInterfaceNumber = dwInterface;pDriverSettings->dwCollection = pCollection->CollectionNumber;而PHIDP_COLLECTION_DESC pCollection = &pHidContext->hidpDeviceDesc.CollectionDesc[dwIdx]赋值的. 首先跟踪dwInterface其实是HidMdd_Attach中第7个参数. HidMdd_Attach是被setup.cpp中的CreateUsbHidDevice函数调用的. 看到CreateUsbHidDevice调用HidMdd_Attach的第7个参数其实就是pUsbHid->pUsbInterface->Descreiptor.bInterfaceNumber.这个其实就是在USB设备的接口描述符Interface Descriptor中的接口序列号. 在我的USB鼠标中只有一个接口. 因此在结构描述符(Configuration Descriptor)中的bNumInterfaces数值为1. bInterfaceNumber也就是只有0了. 而在我的USB键盘结构描述符(Configuration Descriptor)中的bNumInterfaces数值为2. 因此这个设备就有两个接口啦. 两个接口从0开始. 分别为0和1. 可以从下面的USB键盘所打印的信息看出以上的理解也是对的;还有bCollection是由&pHidContext->hidpDeviceDesc.CollectionDesc[dwIdx]->CollectionNumber的来的. 最后是从USB设备上下文HID_CONTEXT中的HIDP_DEVICE_DESC hidpDeviceDesc的来的.HIDP_DEVICE_DESC 就是HID设备的HID描述符. 比如下是另一个USB键盘的HID描述符组合:U8 HID_ReportDescriptor[63] = { //键盘. 可以通过使用HID Descriptor tool来生成,这个工具可以到下载//表示用途页为通用桌面设备0x05, 0x01, // USAGE_PAGE (Generic Desktop)//表示用途为键盘0x09, 0x06, // USAGE (Keyboard)//表示应用集合,必须要以END_COLLECTION来结束它,见最后的END_COLLECTION0xa1, 0x01, // COLLECTION (Application)//表示用途页为按键0x05, 0x07, // USAGE_PAGE (Keyboard)//用途最小值,这里为左ctrl键0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)//用途最大值,这里为右GUI键,即window键0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)//逻辑最小值为00x15, 0x00, // LOGICAL_MINIMUM (0)//逻辑最大值为10x25, 0x01, // LOGICAL_MAXIMUM (1)//报告大小(即这个字段的宽度)为1bit,所以前面的逻辑最小值为0,逻辑最大值为10x75, 0x01, // REPORT_SIZE (1)//报告的个数为8,即总共有8个bits0x95, 0x08, // REPORT_COUNT (8)//输入用,变量,值,绝对值。
USB设备的驱动程序实现
USB设备的驱动程序实现
USB驱动是用来控制使用USB接口的设备的软件程序,其实现是将实
际的硬件设备抽象为虚拟的设备,使其能够在计算机操作系统上应用。
一
般来讲,当你将USB设备插入你的计算机时,它将通过计算机的USB主控
芯片找到USB设备,然后测试它的功能,并决定它是否能够被用来通信,
最后安装相应的驱动程序。
实际的USB驱动程序的实现有若干方法,其中
有两种常用的技术:应用程序编程接口(API)和驱动程序模板。
1、应用程序编程接口(API)
API是一组用于访问操作系统提供的服务和功能的特殊指令序列。
应
用程序编程接口(API)可以用来创建USB驱动程序,其实现包括以下步骤:
(1)定义硬件设备的描述
在编写USB驱动程序时,首先需要定义硬件设备,即定义设备的功能,记录其编号、最大支持通信速率、硬件连接方式、发送和接收设备数据的
方式以及支持的驱动软件要求等信息。
(2)实现设备驱动的关键函数
关键函数是控制USB设备正常工作所必需的函数,包括初始化函数、
发送和接收数据的函数、获取设备状态的函数以及关闭设备的函数等。
USB HID设备驱动程序设计
USB HID设备驱动程序设计
杨晶晶;江春华
【期刊名称】《微计算机信息》
【年(卷),期】2006(000)06Z
【摘要】USB(Universal Serial Bus)即“通用串行总线”是一种应用在计算机领域的新型接口技术。
它的出现大大简化了PC机和外围设备的连接过程,使PC 机接口的扩展变得更加容易。
USB作为近年来计算机和嵌入式领域中的热点,推动了计算机外设的飞速发展。
本文介绍了适用于PC的嵌入式操作系统的USB HID设备驱动的设计,并给出了具体的实现方法。
【总页数】4页(P140-142,183)
【作者】杨晶晶;江春华
【作者单位】成都电子科技大学
【正文语种】中文
【中图分类】TP3
【相关文献】
B设备驱动程序设计 [J], 陈新忠
2.Linux环境下USB设备驱动程序设计 [J], 朱恩亮;赵腊才;茹伟;胡宇凡
3.基于安全机制的USB设备驱动程序设计与实现 [J], 暴占彪
4.一种实现USB随机中断传输的设备驱动程序设计方法 [J], 周洪建;蔡桂艳
5.Android系统下的USB设备驱动程序设计 [J], 孙洁;付友涛;孔凡鹏;韦宏;刘金涛
因版权原因,仅展示原文概要,查看原文内容请购买。
USB接口HID设备说明书
第8章USB接口HID设备HID(Human Interface Device,人机接口设备)是USB设备中常用的设备类型,是直接与人交互的USB设备,例如键盘、鼠标与游戏杆等。
在USB设备中,HID设备的成本较低。
另外,HID设备并不一定要有人机交互功能,只要符合HID类别规范的设备都是HID 设备。
Wndows操作系统最先支持的HID设备。
在windows 98以及后来的版本中内置有 HID 设备的驱动程序,应用程序可以直接使用这些驱动程序来与设备通信。
在设计一个USB接口的计算机外部设备时,如果HID类型的设备可以满足需要,可以将其设计为HID类型设备,这样可以省去比较复杂的USB驱动程序的编写,直接利用Windows 操作系统对标准的HID类型USB设备的支持。
8.1HID设备简介8.1.1HID设备的特点交换的数据储存在称为报表(Report)的结构内,设备的固件必须支持HlD报表的格式。
主机通过控制和中断传输中的传送和请求报表来传送和接收数据。
报表的格式非常灵活。
每一笔事务可以携带小量或中量的数据。
低速设备每一笔事务最大是8B,全速设备每一笔事务最大是64B,高速设备每一笔事务最大是1024B。
一个报表可以使用多笔事务。
设备可以在未预期的时间传送信息给主机,例如键盘的按键或是鼠标的移动。
所以主机会定时轮询设备,以取得最新的数据。
HID设备的最大传输速度有限制。
主机可以保证低速的中断端点每10ms内最多1笔事务,每一秒最多是800B。
保证全速端点每lms一笔事务,每一秒最多是64000B。
保证高速端点每125 us一笔事务,每一秒最多是。
HID设备没有保证的传输速率。
如果设备是设置在10ms的时距,事务之间的时间可能等于或小于10ms。
除非设备是设置在全速时在每个帧传输数据,或是在高速时在每个微帧传输数据。
这是最快的轮询速率,所以端点可以保证有正确的带宽可供使用。
HID设备除了传送数据给主机外,它也会从主机接收数据。
C++ MFC界面读写USB HID设备数据程序
第一步:列举所有的HID设备:m_ctllHIDdevices.ResetContent(); //这是MFC里面一个list控件,用来显示所有的HID设备的,如果你没有界面,可以不需要此行UpdateData(FALSE); //更新界面CString temp;int Count = 0; //Total number of devices foundDWORD strSize=0,requiredSize=0;BOOL result1,result2;ULONG DeviceInterfaceDetailDataSize;//定义一些变量,以后会用到SP_DEVINFO_DA TA DeviceInfoData;SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;//PSP_DEVICE_INTERFACE_DETAIL_DATA test;//第一步:获取deviceIDGUID deviceId;HidD_GetHidGuid(&deviceId);//第二步:获取设备信息HDEVINFO handle;handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devices//第三步:对所有的设备进行枚举//SetupDiEnumDeviceInterfaces();result1=false; //定义一些变量result2=false;CString temp11="";do{DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DA TA);result1 = SetupDiEnumDeviceInterfaces(handle,NULL, // IN PSP_DEVINFO_DA TA DeviceInfoData, OPTIONAL&deviceId,Count,&DeviceInterfaceData);//获得设备详细数据(初步)SetupDiGetDeviceInterfaceDetail(handle,&DeviceInterfaceData,NULL,0,&strSize,NULL);requiredSize=strSize;DeviceInterfaceDetailData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize); DeviceInterfaceDetailData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); DeviceInfoData.cbSize=s第一步:列举所有的HID设备:m_ctllHIDdevices.ResetContent(); //这是MFC里面一个list控件,用来显示所有的HID设备的,如果你没有界面,可以不需要此行UpdateData(FALSE); //更新界面CString temp;int Count = 0; //Total number of devices foundDWORD strSize=0,requiredSize=0;BOOL result1,result2;ULONG DeviceInterfaceDetailDataSize;//定义一些变量,以后会用到SP_DEVINFO_DA TA DeviceInfoData;SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;//PSP_DEVICE_INTERFACE_DETAIL_DATA test;//第一步:获取deviceIDGUID deviceId;HidD_GetHidGuid(&deviceId);//第二步:获取设备信息HDEVINFO handle;handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devices//第三步:对所有的设备进行枚举//SetupDiEnumDeviceInterfaces();result1=false; //定义一些变量result2=false;CString temp11="";do{DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DA TA);result1 = SetupDiEnumDeviceInterfaces(handle,NULL, // IN PSP_DEVINFO_DA TA DeviceInfoData, OPTIONAL&deviceId,Count,&DeviceInterfaceData);//获得设备详细数据(初步)SetupDiGetDeviceInterfaceDetail(handle,&DeviceInterfaceData,NULL,0,&strSize,NULL);requiredSize=strSize;DeviceInterfaceDetailData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize); DeviceInterfaceDetailData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); DeviceInfoData.cbSize=sizeof(SP_DEVINFO_DA TA);//再次获得详细数据result2=SetupDiGetDeviceInterfaceDetail(handle,&DeviceInterfaceData,DeviceInterfaceDetailData,strSize,&requiredSize,&DeviceInfoData);//获得设备路径(最重要的部分)temp=DeviceInterfaceDetailData->DevicePath;UpdateData(FALSE);m_ctllHIDdevices.AddString(temp);Count++;} while (result1);UpdateData(false);izeof(SP_DEVINFO_DATA);//再次获得详细数据result2=SetupDiGetDeviceInterfaceDetail(handle,&DeviceInterfaceData,DeviceInterfaceDetailData,strSize,&requiredSize,&DeviceInfoData);//获得设备路径(最重要的部分)temp=DeviceInterfaceDetailData->DevicePath;UpdateData(FALSE);m_ctllHIDdevices.AddString(temp);Count++;} while (result1);UpdateData(false);第二步:循环读取HID设备数据(根据用户提供的HID的vendorID和productID),并且把字节解码成二进制,在MFC界面上用LED展示:为了不影响主线程的运行,我把读取数据的操作,放在一个子线程里!每隔50ms去读取一次数据!首先创建一个线程:HANDLE hThread1;bStopHID=false; //这个变量,以后用来停止线程UpdateData(true); //更新界面,获取变量UpdateData(false);hThread1 = CreateThread(NULL,0,Thread_Enable_Read,(LPVOID)this, NULL, NULL);在线程的程序里:CusbhidDlg *p = ( CusbhidDlg *)pvParam; //获取主窗口的指针,用来调用主窗口的变量和函数p->UpdateData(true);p->bStopHID=false;CString temp;CString DevicePath;temp="";int Count = 0; //Total number of devices foundDWORD strSize=0,requiredSize=0;BOOL result1,result2;ULONG DeviceInterfaceDetailDataSize;SP_DEVINFO_DA TA DeviceInfoData;SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;//PSP_DEVICE_INTERFACE_DETAIL_DATA test;//1GUID deviceId;HidD_GetHidGuid(&deviceId);int venderID=p->v_eVendorID; //从窗口里获取用户输入的VendorIDint productID=p->v_eProductID;//从窗口里获取用户输入的ProductIDunsigned char inbuffer[2]; //用来存放读取的数据,请在这里定义你自己需要的长度,我每次读一个字节进来unsigned long numBytesReturned;HIDD_ATTRIBUTES devAttr;PHIDP_PREPARSED_DATA PreparsedData;HIDP_CAPS Capabilities;int readValue;bool LED;int flag=0;//2HDEVINFO handle;handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devicesint i=0;int j=p->m_ctllHIDdevices.GetCount();for (i=0;i<p->m_ctllHIDdevices.GetCount();i++){p->m_ctllHIDdevices.GetText(i,temp);DevicePath=temp;//CreateFile是非常重要的一步,用来建立于HID通信的句柄HANDLE hCom = CreateFile (DevicePath,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING, 0,NULL);if (hCom == INV ALID_HANDLE_V ALUE){//AfxMessageBox("Invalide Device Path...");continue;}devAttr.Size=sizeof(HIDD_ATTRIBUTES);if (!HidD_GetAttributes(hCom,&devAttr)){CloseHandle(hCom);AfxMessageBox("Cannot get the parameters of the HID...");return 0;}//temp.Format("Vendor ID: %d, Product ID:%d",devAttr.VendorID,devAttr.ProductID); //Compare with the Vendor ID and Product ID from Nakamura-san//AfxMessageBox(temp);if (!HidD_GetPreparsedData(hCom,&PreparsedData)){CloseHandle(hCom);AfxMessageBox("Cannot get the Preparsed Data...");return 0;}if(!HidP_GetCaps(PreparsedData,&Capabilities)){CloseHandle(hCom);AfxMessageBox("Cannot get the Cap Data...");return 0;}if (devAttr.VendorID == venderID && devAttr.ProductID == productID){while(1){result1 = ReadFile(hCom, &inbuffer[0], Capabilities.InputReportByteLength, &numBytesReturned, 0);temp=inbuffer;//p->m_eDataRead=CString(inbuffer);//p->UpdateData(false);if(!result1){AfxMessageBox("Cannot Read Data...");return 0;}readValue=inbuffer[1];p->m_eDataRead.Format("%d",readValue);//下面是我把数据从10进制转换成二进制,并且点亮LED (一个字节有8个bits,可以点亮8个LEDfor (int k=0;k<8;k++){flag=readValue%2;readValue=readValue/2;if (k==0){if (flag==0)p->m_sDynLED0.SwitchOff();elsep->m_sDynLED0.SwitchOn();}else if (k==1){if (flag==0)p->m_sDynLED1.SwitchOff();elsep->m_sDynLED1.SwitchOn();}else if (k==2){if (flag==0)p->m_sDynLED2.SwitchOff(); elsep->m_sDynLED2.SwitchOn(); }else if (k==3){if (flag==0)p->m_sDynLED3.SwitchOff(); elsep->m_sDynLED3.SwitchOn(); }else if (k==4){if (flag==0)p->m_sDynLED4.SwitchOff(); elsep->m_sDynLED4.SwitchOn(); }else if (k==5){if (flag==0)p->m_sDynLED5.SwitchOff(); elsep->m_sDynLED5.SwitchOn(); }else if (k==6){if (flag==0)p->m_sDynLED6.SwitchOff(); elsep->m_sDynLED6.SwitchOn();}else if (k==7){if (flag==0)p->m_sDynLED7.SwitchOff();elsep->m_sDynLED7.SwitchOn();}}p->UpdateData(false);::Sleep(50);//判断用户是否点击停止按钮,若是,则退出if(p->bStopHID){AfxMessageBox("stopped...");return 0;}}}}if (i==j){AfxMessageBox("There is no such HID device..."); }return 0;第三步:向HID设备写数据(根据用户提供的HID的vendorID和productID),用户输入的是二进制数据:与读的程序一样,唯一区别就是红色那部分!UpdateData(true);bStopHID=false;CString temp;CString DevicePath;temp="";int Count = 0; //Total number of devices foundDWORD strSize=0,requiredSize=0;BOOL result1,result2;ULONG DeviceInterfaceDetailDataSize;SP_DEVINFO_DA TA DeviceInfoData;SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;//PSP_DEVICE_INTERFACE_DETAIL_DATA test;//1GUID deviceId;HidD_GetHidGuid(&deviceId);int venderID=v_eVendorID;int productID=v_eProductID;unsigned char inbuffer[2];unsigned long numBytesReturned;HIDD_ATTRIBUTES devAttr;PHIDP_PREPARSED_DATA PreparsedData;HIDP_CAPS Capabilities;int readValue;bool LED;int flag=0;inbuffer[0]=0;//把界面里的二进制转换成10进制inbuffer[1]=m_eByte0*1+m_eByte1*2+m_eByte2*4+m_eByte3*8+m_eByte4*16+m_eByte5*32 +m_eByte6*64+m_eByte7*128;v_eDataToWrite=inbuffer[1];UpdateData(false);//2HDEVINFO handle;handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devicesint i=0;int j=m_ctllHIDdevices.GetCount();for (i=0;i<m_ctllHIDdevices.GetCount();i++){m_ctllHIDdevices.GetText(i,temp);DevicePath=temp;HANDLE hCom = CreateFile (DevicePath,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING, 0,NULL);if (hCom == INV ALID_HANDLE_V ALUE){//AfxMessageBox("Invalide Device Path...");continue;}devAttr.Size=sizeof(HIDD_ATTRIBUTES);if (!HidD_GetAttributes(hCom,&devAttr)){CloseHandle(hCom);AfxMessageBox("Cannot get the parameters of the HID...");return;}//temp.Format("Vendor ID: %d, Product ID:%d",devAttr.VendorID,devAttr.ProductID); //Compare with the Vendor ID and Product ID from Nakamura-san//AfxMessageBox(temp);if (!HidD_GetPreparsedData(hCom,&PreparsedData)){CloseHandle(hCom);AfxMessageBox("Cannot get the Preparsed Data...");return;}if(!HidP_GetCaps(PreparsedData,&Capabilities)){CloseHandle(hCom);AfxMessageBox("Cannot get the Cap Data...");return;}// Write Fileif (devAttr.VendorID == venderID && devAttr.ProductID == productID) {result1 = WriteFile(hCom, inbuffer, 2, &numBytesReturned, NULL); //temp=inbuffer;//p->m_eDataRead=CString(inbuffer);//p->UpdateData(false);if(!result1){AfxMessageBox("Cannot Write Data...");return;}AfxMessageBox("Suncess...");break;}}if (i==j){AfxMessageBox("There is no such HID device...");}return;。
STM32 USB HID
void USB_Reset (void) { /* Double Buffering is not yet supported */
ISTR = 0; /* Clear Interrupt Status */ //:CNTR_RESETM 在使能连接时被中断使能 //:CNTR_CTRM 此处添加(正确传输中断使能==>某个端点成功完成一次传输.) //:下一次事件中断将检测 CNTR_CTRM 中断 // 究竟是哪个端点成功传输(ISTR:EP_ID[3:0]),数据方向(ISTR:DIR) CNTR = CNTR_CTRM | CNTR_RESETM | (USB_SUSPEND_EVENT ? CNTR_SUSPM : 0) | (USB_WAKEUP_EVENT ? CNTR_WKUPM : 0) | (USB_ERROR_EVENT ? CNTR_ERRM : 0) | (USB_ERROR_EVENT ? CNTR_PMAOVRM : 0) | (USB_SOF_EVENT ? CNTR_SOFM : 0) | (USB_SOF_EVENT ? CNTR_ESOFM : 0); FreeBufAddr = EP_BUF_ADDR; BTABLE = 0x00; /* Setup Control Endpoint 0 */ pBUF_DSCR->ADDR_TX = FreeBufAddr; //: FreeBufAddr += USB_MAX_PACKET0; //: pBUF_DSCR->ADDR_RX = FreeBufAddr; //: FreeBufAddr += USB_MAX_PACKET0; //: if (USB_MAX_PACKET0 > 62) { pBUF_DSCR->COUNT_RX = ((USB_MAX_PACKET0 << 5) - 1) | 0x8000; } else { pBUF_DSCR->COUNT_RX = USB_MAX_PACKET0 << 9; } //配置端点 0: //1: EP_CONTROL(控制端点) bit[10:9](EP_TYPE[1:0]) //自由缓冲区地址 /* set BTABLE Address */
如何编写应用程序与USBHID设备通讯
如何编写应用程序与USBHID设备通讯编写应用程序与USBHID设备通讯的过程可以分为以下几个步骤:设备初始化、数据读取与写入以及释放资源。
下面将详细介绍如何完成每个步骤。
1.设备初始化:首先,需要获取系统中的所有HID设备信息,并找到目标设备的相关信息,如厂商ID、产品ID等。
可以使用操作系统提供的API函数来实现这一步骤,例如,Windows系统可以使用SetupAPI、DeviceIoControl等函数来获取设备信息。
2.打开设备:找到目标设备后,需要使用操作系统提供的API函数打开设备。
在Windows系统下,使用CreateFile函数打开设备句柄。
在Linux系统下,可以通过打开特定的文件来获取设备句柄。
3.读取数据:打开设备后,可以使用ReadFile函数从设备中读取数据。
需要设置好读取的缓冲区大小和读取的超时时间等相关参数。
读取的数据通常以报文形式传输,需要根据设备的通信协议进行解析和处理。
4.写入数据:使用WriteFile函数将数据写入设备。
写入的数据也通常以报文形式进行传输,需要按照设备的通信协议来填充报文的内容。
5.释放资源:通信完成后,需要关闭设备句柄并释放相关资源。
在Windows系统下,使用CloseHandle函数关闭设备句柄;在Linux系统下,使用close函数关闭设备文件描述符。
总结起来,编写应用程序与USBHID设备通讯的过程包括设备初始化、打开设备、读取数据、写入数据以及释放资源等步骤。
具体实现过程需要根据操作系统和编程语言的不同而有所调整,但总体思路相似。
通过调用操作系统提供的API函数来完成和USBHID设备的通信,可以实现读取和写入数据的功能。
如何编写应用程序与USB HID 设备通讯(读写USB HID设备)
如何编写应用程序与USB HID 设备通讯(读写USB HID设备)说明:本实例所使用的上位机程序开发工具为Visual C++6.0。
一、修改下位机固件程序我们如果想实现一个USB的HID类设备,不需要在Windows下开发自己的驱动程序。
HID 不一定要是标准的外设类型,唯一的要求是交换的数据存储在报文的结构内,设备固件必须支持报文的格式。
任何工作在该限制之内的设备都可以成为一个HID,例如温度计、电压计、读卡机等。
报文的格式是由报告描述符决定的,所以只要修改描述符就能实现我们需要的报文格式。
下面我们来实现一个简单的报文格式:上位机发送固定64字节数据给设备,这个数据可以是命令,也可是数据,具体含义并不是由报告描述符来决定的,是由开发人员事先约定好的。
设备返回的数据也是64个字节,同样这个数据流的每个字节(甚至每个位)的具体含义由开发人员事先约定好。
1、修改报告描述符A、在Descriptor.C中找到以MouseReportDescriptor函数,将其内容修改如下:1.code char MouseReportDescriptor[29] = {2. 0x06,0x00,0xFF, //USAGE_PAGE (Vendor Defined Page 1)3. 0x09,0x01, //USAGE (Vendor Usage 1)4. 0xA1,0x01, //COLLECTION (Application)5.6. 0x19,0x01, //(Vendor Usage 1)7. 0x29,0x08, //(Vendor Usage 1)8. 0x15,0x00, //LOGICAL_MINIMUM (0)9. 0x26,0xFF,0x00, //LOGICAL_MAXIMUM (255)10. 0x75,0x08, //REPORT_SIZE (8)11. 0x95,0x40, //REPORT_COUNT (64)12. 0x81,0x02, //INPUT (Data,Var,Abs)13.14. 0x19,0x01, //(Vendor Usage 1)15. 0x29,0x08, //(Vendor Usage 1)16. 0x91,0x02, //OUTPUT (Data,Var,Abs)17.18. 0xC0 // END_COLLECTION19.};此报告描述符定义了64个字节的输入输出数据。
USB设备驱动程序的设计
USB设备驱动程序的设计是1995年微软、IBM等公司推出的一种新型通信标准总线,特点是速度快、价格低、自立供电、支持热插拔等,其版本从早期的1.0、1.1已经进展到目前的2.0版本,2.0版本的最高数据传输速度达到480Mbit/s,能满足包括视频在内的多种高速外部设备的数据传输要求,因为其众多的优点,USB总线越来越多的被应用到计算机与外设的接口中,芯片厂家也提供了多种USB接口芯片供设计者用法,为了开发出功能强大的USB设备,设计者往往需要自己开发USB设备驱动程序,驱动程序开发向来是WINDOWS开发中较难的一个方面,但是通过用法特地的驱动程序开发包能减小开发的难度,提高工作效率,本文用法Compuware Numega公司的DriverStudio3.2开发包,开发了基于PHILIPS公司USB2.0控制芯片ISP1581的USB设备驱动程序。
USB设备驱动程序的模型图1 USB驱动程序模型USB设备驱动程序是一种典型的WDM(Windows Driver Model)驱动程序,其程序模型1所示。
用户应用程序工作在Windows操作系统的用户模式层,它不能挺直拜访USB设备,当需要拜访时,通过调用操作系统的API(Application programminginterface)函数生成I/O哀求信息包(IRP),IRP被传输到工作于内核模式层的设备驱动程序,并通过驱动程序完成与UBS外设通信。
设备驱动程序包括两层:函数驱动程序层和总线驱动程序层,函数驱动程序一方面通过IRP及API函数与应用程序通信,另一方面调用相应的总线驱动程序,总线驱动程序完成和外设硬件通信。
USB总线驱动程序已经由操作系统提供,驱动程序开发的重点是函数驱动程序。
USB设备驱动程序的设计用法DriverStudio3.2开发USB设备驱动程序该驱动程序的主要功能包括:从控制端点0读取规定个数的数据、向端点0发出控制指令、从端点2批量读数据、向端点2批量写数据,驱动程序的开发采纳DriverStudio3.2驱动程序开发包及VC++6.0,用法开发包中的向导程序DriverWizard就可以便利的生成驱动程序框架、模块及部分程序源代码,开发者只需要在功能模块中加入自己的实现程序就能完成复杂的USB设备驱动程序设计,下面介绍用法DriverWizard 生成ISP1581驱动程序的过程:1)启动DriverWizard,挑选DriverWorks Project制造一个名为USBDIO 的VC++项目;2)在驱动程序类型中挑选WDM Driver,WDM Function Driver,在硬件设备所支持的总线类型中挑选USB(WDM Only),在USB Vendor ID(厂商识别码)中填写0741,在USB Product ID(产品识别码)中填写0821;3)增强USB设备端点,设置端点2为批量输入/输出传输方式;4)在驱动程序支持的功能项中挑选Read、Write、Device Control、Cleanup;5)挑选自动产生批量读及批量写程序代码; 6)在I/O哀求IRP处理方式中挑选None,即IRP不排队;7)在接口的打开方式中挑选Symbolic link:UsbdioDevice,即应用程序以符号链接名打开设备;8)定义应用程序调用DeviceIoControl函数对WDM驱动程序通信的控制指令,结果2所示。
c++mfc界面读写usbhid设备数据程序
第一步:列举所有的HID设备:(); .");continue;}=sizeof(HIDD_ATTRIBUTES);if (!HidD_GetAttributes(hCom,&devAttr)){CloseHandle(hCom);AfxMessageBox("Cannot get the parameters of the HID..."); return 0;}.");return 0;}if(!HidP_GetCaps(PreparsedData,&Capabilities)){CloseHandle(hCom);AfxMessageBox("Cannot get the Cap Data...");return 0;}if == venderID && == productID){while(1){result1 = ReadFile(hCom, &inbuffer[0], , &numBytesReturned, 0); temp=inbuffer;.");return 0;}readValue=inbuffer[1];p->("%d",readValue);.");return 0;}}}}if (i==j){AfxMessageBox("There is no such HID device...");}return 0;第三步:向HID设备写数据(根据用户提供的HID的vendorID和productID),用户输入的是二进制数据:与读的程序一样,唯一区别就是红色那部分!UpdateData(true);bStopHID=false;CString temp;CString DevicePath;temp="";int Count = 0; .");continue;}=sizeof(HIDD_ATTRIBUTES);if (!HidD_GetAttributes(hCom,&devAttr)){CloseHandle(hCom);AfxMessageBox("Cannot get the parameters of the HID..."); return;}.");return;}if(!HidP_GetCaps(PreparsedData,&Capabilities)){CloseHandle(hCom);AfxMessageBox("Cannot get the Cap Data...");return;}.");return;}AfxMessageBox("Suncess...");break;}}if (i==j){AfxMessageBox("There is no such HID device...");}return;。
stm32F107 USB从设备HID 鼠标程序详解
STM32F107USB从设备HID程序编写一、前提准备本文是基于STM32F107官方库文件3.5.0基础上完成的,首先要有以下资料准备:(1)stm32基于3.5.0库的工程模板;(2)stm32官方USB库文件(由于3.5.0官方库函数中不包括USB的官方库,因此需要单独加入),下载地址:/disk/home#path=%252F%25E5%25AD%25A6%25E4%25B9%25A0%25E 5%2585%25B1%25E4%25BA%25AB%252Fstm32%2520study%252Fusb%2520%25E5%2588 %2586%25E4%25BA%25AB(3)stm32USB基础知识(这里不再赘述,网上有蛮多资料,推荐《STM32USB固件的中文资料》和官方提供的本文讲述的USB库文件的官方说明);(4)编程软件keil for arm;(以上资料文件在链接中都有贡献!@^@多多支持)注意:下面的内容:有颜色标注的是用户需要修改的内容二、USB官方库详细介绍:在下载官方库之后,从命名上可以明白,该库为stm32105,107,f2和F4等USB控制器的主设备和从设备的官方库;接下来,我们继续进入库文件介绍:_hemresc:ST官方LOGOLibraries:CMSIS:ST官方内核说明及相应的源码(STM32F2xx_StdPeriph_Driver.....等等);STM_USB_Device_Library:USB器件类的库函数;STM_USB_HOST_Library:USB主设备类的库函数;STM32_USB_OTG_Driver:USB OTG类的驱动和库函数;Project:USB_Device_Examples:USB器件类的官方例程;USB_Host_Device_Examples:USB主从设备的官方例程;USB_Host_Examples:USB主设备官方例程;Utilities:该文件夹下包括STM32的扩展,比如SDIO、文件系统和官方评估板的简单驱动;至此大家应该明白官方USB库中,重点就在USB_device_Library、Host_Library和OTG_Library中了,由于本文主要讲解HID(人机接口设备)程序的实现,因此就不对HOST 做分析了;对于USB_Device_Library中的文件,官方分为了core和Class进行分装;对于core文件夹的源文件:Scr:包含了USB device内核,USB IO请求和USB数据请求的源代码;Inc:USB内核头文件,(usbd_conf_template.h为模板,用户需要自行添加使用到的USb功能定义,usbd_usr.h:用户需要添加用户自定义的函数声明和变量定义);再看Class文件下,包括USB device的所有设备的源文件和头文件;Audio:USB音频类设备,诸如喇叭、扩音器、低音炮之类;CDC:通信类设备,比如USB虚拟串口等;Dfu:固件升级;Hid:人机接口设备,比如鼠标、键盘、游戏手柄等;MSC:大容量存储设备,比如硬盘、读卡器等;接下来是OTG_library;该文件夹下包括了USB_core,USB_device、USB_Host、USB_OTG 的底层驱动:内核驱动:usb_core.cUSB_device驱动:usb_dcd.c usb_dcd_int.cUSB_Host驱动:usb_hcd.c usb_hcd_init.cUSB_OTG驱动:usb_otg,c头文件与之对应;看完这个大家就有疑问了,文件夹下还有其他的头文件和源文件,这些又是干嘛的呢?摆设?哈哈……这些文件就重要了,usb_defines.h、usb_regs,h廊括了USB的寄存器的相关定义,而usb_bsp.h、usb_conf_template.h、usb-dap_template.c则都是用户需要修改或增加USB相关代码的文件了;GG~~总算是把官方库给读完了(第一次写这种东西,真为自己捏把汗!哈哈……希望大家多多支持),从官方库中可以看出,官方代码需要修改的重要文件都用xxx_template.c和xxx_template.h命名,大大的方便了用户啊(真贴切);三、官方库的移植和修改了解了官方库的架构,对于本次USB HID设备的程序结构我们就相当清晰了:(1)底层驱动,(2)USB device内核;(3)USB HID设备源码;这三个部分的代码是我们需要添加的;打开我们的STM32工程模板文件夹,在文件夹下新建文件夹usb,在usb文件夹下新建usb_usr、usb_lib、usb_driver三个文件夹,文件夹内容添加如下:Usb_driver:官方库中OTG_library中内容,(可不用理睬HOST设备相关内容);Usb_lib:device_library中core文件夹所有内容和class下的HID内容;Usb_usr:将OTG_driver中的usb_bsp_template.c和usb__conf_template.h、上面所述的usbd_desc.c和usbd_usr.c,device Library/core/inc下的usbd_conf_template.h复制到usb_usr 文件夹中,并将xxxxx_template.重命名为xxxx.c(去掉_template);下面的都要在keil下进行了,过程如下:在工程下新建usb_driver、usb_lib_core、usb_lib_hid、usb_usr分组,并添加如图的源文件(切记要添加相应头文件路径target->c/c++->include path),添加结果如下:到了这一步,USB的工程模板就基本差不多了,但编译一下,还是会出现很多错误:(1)错误1:这个错误提示很明显,提示USB_OTG_HS_CORE和USB_OTG_FS_CORE至少要定义一种,这个错误提示的源码在usb_conf.h中,仔细查看该文件可知:官方将这两个定义都注释了,我们只要取消其中一个即可,这里我们采用USB全速模式,因此我们取消对USE_USB_OTG_FS的注释(HS是指USB高速模式,这种模式下需要外接PHY器件);(2)错误2:提示xxxx未定义,我们可以找到USBD_ITF_MAX_NUM出现在usbd_req.c中,其他均出现在usbd_hid_core.c中,这些都是我们需要单独实现的,这里我们同样在usb_conf.h中给出定义:这些定义我们会在后续的代码分析中进行一一讲解;注意:usb_bsp.c文件中,我们得注释掉函数的内容:void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE*pdev);void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE*pdev);至此我们再进行编译,就没有错误了,咱们USB的工程模板算是建立好了;四、HID程序代码编写工程模板是建立好了,开始对于程序该如何出手呢?从哪里开始编写呢?似乎还是一头雾水(痛哭流涕中)。
USB固件开发(HID设备)
USB固件开发(HID设备)收藏USB固件开发(HID设备)1. HID设备的识别HID设备类除了有文档第一部分所述的一些标准描述符(包括设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符)外,还有自己的类专有描述符:HID描述符报告描述符物理描述符正确实现HID设备类专用描述符是主机成功识别HID设备的关键。
HID描述符和报告描述符是必须要使用的,物理描述符一般不被使用。
1.1 HID描述符HID描述符跟接口描述符、端点描述符类似,也是随配置信息一起返回给主机的,主机并不会单独发出请求来读取它。
HID描述符在配置信息中的位置是紧接接口描述符。
例如:_Config_Descriptor:.dw _Config_Descriptor_End-_Config_Descriptor //bLength: 0x09 byte.dw 0x02 //bDescriptorType: CONFIGURATION.dw _Config_Descriptor_Total-_Config_Descriptor //wTotalLength:.dw 0x00.dw 0x01 //bNumInterfaces: 1 interfaces.dw 0x01 //bConfigurationValue: configuration 1.dw 0x00 //iConfiguration: index of string.dw 0xC0 //bmAttributes: self powered, Not Support Remote-Wakeup.dw 0x32 //MaxPower: 100 mA_Config_Descriptor_End:_HID_Interface_Descriptor://Interface 1 (0x09 byte).dw 0x09 //bLength: 0x09 byte.dw 0x04 //bDescriptorType: INTERFACE.dw 0x01 //bInterfaceNumber: interface 0.dw 0x00 //bAlternateSetting: alternate setting 0.dw 0x01 //bNumEndpoints: 1 endpoints(EP1).dw 0x03 //bInterfaceClass: 人机接口设备(HID)类.dw 0xff //bInterfaceSubClass: 供应商定义.dw 0xff //bInterfaceProtocol 使用的协议:供应商定义.dw 0x00 //iInterface: index of string_HID_Interface_Descriptor_End:HID_Descriptor:.dw 0x09 //bLength: 0x09 byte.dw 0x21 //bDescriptorType: HID描述符类型编号.dw 0x01, 0x10 //HID类协议版本号,为1.1.dw 0x21 //固件的国家地区代号,0x21为美国.dw 0x01 //下级描述符的数量.dw 0x22 //下级描述符为报告描述符.dw _ReportDescriptor_End-_ReportDescriptor, 0x00 //下级描述符的长度_HID_Descriptor_End:_Endpoint3:.dw 0x07 //bLength: 0x07 byte.dw 0x05 //bDescriptorType: ENDPOINT.dw 0x83 //bEndpointAddress: IN endpoint 3.dw 0x03 //bmAttributes: Interrupt.dw 0x02, 0x00 //wMaxPacketSize: 2 byte.dw 0x0A //bInterval: polling interval is 10 ms_Config_Descriptor_Total:HID描述符其实是为了提供下级描述符(如报告描述符)的信息。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
USB HID 设备驱动程序设计引自:/hudaweikevin/archive/2009/11/02/4756394.aspx摘要:USB(Universal Serial Bus)即“通用串行总线”是一种应用在计算机领域的新型接口技术。
它的出现大大简化了PC机和外围设备的连接过程,使PC机接口的扩展变得更加容易。
USB作为近年来计算机和嵌入式领域中的热点,推动了计算机外设的飞速发展。
本文介绍了适用于PC的嵌入式操作系统的USB HID设备驱动的设计,并给出了具体的实现方法。
关键词:USB HID设备PC 嵌入式驱动程序从USB 1.1到USB2.0再到目前的USB OTG(On-The-Go),USB在不断自我完善,并走向成熟。
USB具有高速度、低成本、低功耗、即插即用和使用维护方便等优点,不仅成为了PC主板上的标准接口,而且成为了所有PC外部设备如键盘、鼠标、显示器、打印机、数码相机等与PC相连的标准协议之一,迅速占领了计算机中、低速外部设备的市场。
USB(Universal Serial Bus)即“通用串行总线”是一种应用在计算机领域的新型接口技术。
USB的拓扑结构中居于核心地位的是Host(也称为主机)。
任何一次USB的数据传输都必须由主机来发起和控制,所有的USB外设都只能和主机建立连接,任何两个外设之间或是两个主机之间无法直接通信。
而目前,大量的扮演主机角色的是个人电脑PC。
随着USB应用领域的逐渐扩大,对于USB的期望也越来越高。
我们希望USB能应用在各种计算机领域中,希望能通过PDA等移动设备直接和USB外设通信,使得USB能应用在没有PC的领域中。
而我们目前所使用的USB移动设备,大多数都是USB的外设,比如USB的移动硬盘、USB 接口的数码相机等。
所有这些设备都只能在PC上使用,只能通过PC来进行相互的文件和数据交换。
本驱动程序是为完善我们自行设计的嵌入式操作系统,使得它具备能识别USB HID设备的功能而开发的。
所使用的编程语言为C语言,并下载到目标机上,通过测试验证可以识别USB HID设备,如USB键盘,USB鼠标等。
本文探讨的即是PC上实现USB HID设备驱动的方法。
⒈HID 设备驱动简介为简化USB设备的开发过程,USB提出了设备类的概念。
HID设备类,即人机接口设备。
典型的HID设备如键盘、鼠标。
所有设备类都必须支持标准USB描述符和标准USB设备请求。
如果有必要,设备类还可以自行定义其专用的描述符和设备请求,这分别被称为设备类定义描述符和设备类定义请求。
另外,一个完整的设备类还将指明其接口和端点的使用方法,如如接口所包含端点的个数、端点的最大数据包长度等。
HID设备既可以是低速设备也可以是全速设备,其典型的数据传输类型为中断IN传输,即它适用于主机接收USB设备发来的小量到中等量的数据。
HID具有以下的功能特点:1)适用于传输少量或中量的数据;2)传输的数据具有突发性;3)传输的最大速率有限制;4)无固定的传输率。
HID设备类除支持标准USB描述符外(设备描述符、配置描述符、接口描述符、端点描述符和字符串描述符),还自行定义了3种类描述符,分别为HID描述符(主要用于识别HID 设备所包含的其他类描述符)、报告描述符(提供HID设备和主机间交换数据的格式)和物理描述符。
一个HID设备只能支持一个HID描述符;可以支持一个或多个报告描述符;物理描述符是可选的,大多数HID设备不需要使用它。
⒉USB HID设备驱动原理设备的USB 人机交互设备必须遵循以下的USB开始程序:1) 插入设备USB设备第一次连接到总线时,虽然接上了电源,但是总线仍然没有任何功能,一定要到重置总线为止才可以开始运作。
注意,一旦USB在D端使用了1.5kΩ的提升电阻,就会立即通知总线的集线器,有一个低速设备(1.5Mb/s)刚被连接上。
而程序以设备地址0开始运行。
设备插上时,电源打开重置的过程:重置->执行初始设置并出发总线重置中断->位于中止模式下知道总线被重置为止->等待设备列举->执行程序循环2) 总线重置接着主机将会辨认新的USB设备并重置它。
在总线重置过程中,除了设定堆栈指针外,也出发所有被使用到的中断。
(总线重置的中断服务程序ISR功能)3) 设备列举。
主机会负责检测与设定所有连接至根集线器的设备,辨别与设定一个USB设备的程序,称为设备列举。
主机首先会送出SETUP封包以读取默认地址0的设备描述符。
当收到描述符后,主机将会指定新的USB地址给设备。
从设备所返回的信息中,主机就会知道设备所支持的数据端点的数量。
完成设备列举。
4) 数据捕捉与转换这里以键盘为例,在固件中将以周期性的方式,把扫描的形式写入到扫描矩阵的列I/O 端口伤(接口2),并且在行I/O接口伤读取结果值以决定哪个键被按下了。
通过键盘扫描后所得到的数据码,可以使用中断传输以端点1来传送给主机。
设备就将键盘的8B数据放置在IN令牌包随后跟随的资料封包的数据域位内,再返回给主机。
当含有LED的按键(如NumLock ,Caps lock 与Scroll lock)被按下或放开时,主机就会送出含有设定报告(Set_Report)要求的SETUP封包,通过控制传输传至设备的端口0上。
⒊USB HID设备驱动程序设计的流程说明USB总线与设备间的交互都是通过USBD即USB总线驱动程序完成。
USBD起着中间桥梁作用,解释USB设备类驱动程序发来的命令并将其划分为一系列的USB事务,然后发送给USB 主控制器驱动程序。
具体流程是插入一个USB设备后,主机检测到有设备接入,USBD就从链表中查找匹配HID 设备类。
为每一个接入的HID设备驱动建立一个对应的USB_HID_SIO_CHAN结构来对该HID 设备驱动进行管理。
这里的USB_HID_SIO_CHAN结构是USBD为每一个HID设备所分配的一个关键的内部数据结构。
此后由USB主控制器驱动程序来负责硬件底层的驱动。
而HID设备移除时,会调用函数usbHIDDeviceAttachCallback(),这时先判断是否有与该HID设备绑定的结构,有则清除该结构。
成功注册一个没有被初始化的USB HID设备的程序流程如下:⒋USB HID设备驱动程序的实现因为键盘和鼠标同为HID设备,具体驱动程序实现极为相似,这里仅以键盘的驱动程序实现为例,给出最主要的函数说明:1.STATUS usbKeyboardDevInit()功能:键盘初始化函数,依次初始化与USBD的连接,和其他所需的内部资源。
返回值:操作成功返回OK,失败返回ERROR注意:在调用usbKeyboardDevInit ( )前,必须保证USBD层已经初始化-至少调用了usbdInitialize().还要保证至少一个USB HCD(USB Host Controller Driver)连接到了USBD层。
2.STATUS usbdClientRegister(T_BYTE* pClientName, /* Client name */pUSBD_CLIENT_HANDLE pClientHandle /* Client hdl returned by USBD */ )功能:向USBD注册一个新客户(键盘,鼠标等)返回值:操作成功返回OK,失败返回ERROR3。
STATUS usbdDynamicAttachRegister(USB_KBD_ATTACH_CALLBACK callback, /* new callback to be registered */ T_VOID* arg /* user-defined arg to callback */)功能:每次插上或者移除键盘时,都会由回调函数调用,该函数实现USB设备动态插拔。
返回值:操作成功返回OK,失败返回ERROR4.T_MODULE T_VOID usbKeyboardAttachCallback(USBD_NODE_ID nodeId,T_UHWORD attachAction,T_UHWORD configuration,T_UHWORD interface,T_UHWORD deviceClass,T_UHWORD deviceSubClass,T_UHWORD deviceProtocol)功能:每次插上或者移除键盘时由USBD调用注意:有可能同一个设备会多次插拔,对这种情况USBD会忽略除第一次外的callback 返回值:无5.T_ MODULE pUSB_KBD_SIO_CHAN createSioChan(USBD_NODE_ID nodeId,T_UHWORD configuration,T_UHWORD interface)功能:给USBD分配的nodeId创建一个新的USB_KBD_SIO_CHAN结构返回值:成功返回指向该结构的指针,失败返回NULL6.T_MODULE T_BOOL configureSioChan(pUSB_KBD_SIO_CHAN pSioChan)功能:配置键盘信息返回值:成功返回TRUE,失败返回FALSE7.T_MODULE T_VOID usbKeyboardIrpCallback(T_VOID* p /* completed IRP */)功能:IRP完成或取消时调用返回值:无8.T_MODULE T_VOID interpKbdReport(pUSB_KBD_SIO_CHAN pSioChan)功能:解释USB键盘的BOOT REPORT,得到键盘扫描码。
返回值:无⒌USB HID设备的数据获取方式必须注意的是这里鼠标和键盘的处理方式完全不一样。
键盘是以轮询方式获得数据。
使用如下的函数:T_MODULE T_WORD usbKeyboardPollInput(SIO_CHAN *pChan,T_BYTE *thisChar /*按键值*/)返回值:收到字符返回OK;设备错误返回EIO;如果输入缓冲为空返回EAGAIN;设备只能在中断模式下工作返回ENOSYS.所获取的按键值都将存放在给键盘分配的对应的USB_KBD_SIO_CHAN结构里的inQueue [KBD_Q_DEPTH]。
而鼠标驱动程序的设计则是在IRP成功返回的时候,直接由函数usbMouseIrpCallback()通过调用函数interpMseReport()取得USB_MSE_SIO_CHAN结构结构里的pReport项。
该pReport项即包含的是鼠标按键的状态。
随着USB2.0的发布,USB越来越流行,它已经成为绝大多数PC外设上的标准接口。