HDF(Hardware Driver Foundation)驱动框架是鸿蒙系统硬件生态开放的基础,为驱动提供驱动加载、驱动服务管理和驱动消息机制,让开发者精准高效地开发驱动。本期,我们将为您带来HDF驱动框架中USB DDK的分析和指导。
一、USB DDK介绍USB(通用串行总线),用于规范计算机与外部设备的连接和通信,包括主机和设备。其中主机端负责USB总线中的数据传输和端口管理,设备端可以连接各种外设,所以USB驱动开发可以分为主机端驱动开发和设备端驱动开发。由于基于内核状态的usb驱动扩展性差,目前开发人员通常选择Libusb库进行USB驱动开发。该库是一个跨平台的用户态开源USB通信库,可以满足开发者开发基于用户态的函数驱动的需求。但是由于Libusb库完全按照usb协议封装接口,所以需要开发者对USB协议有很深的理解才能用好。对开发者的要求比较高,让很多初级开发者望而却步。为了让更多的开发者开发基于用户模式的USB驱动程序,HDF推出了USB DDK开发包。USB DDK(USB DriverDevelop Kit)是HDF驱动框架为开发者提供的USB驱动开发套件,包括USB主机DDK和USB设备DDK。它支持基于用户状态的USB设备驱动开发,并提供丰富的USB驱动开发能力,使开发者能够准确高效地开发USB驱动。接下来,我们一起来。
1USB主机DDK
USB主机DDK为开发者提供了在主机端开发USB驱动程序的能力。根据它们的功能,可以分为三类:DDK初始化类、接口对象操作类和请求对象操作类。它还为开发者提供了两种开发模式:通用模式和专家模式。正常模式下,开发者可以通过USBDDK API直接完成相关的USB数据读写操作,无需过多关注底层传输细节。在专家模式下,开发者可以通过USB RAW API直接访问OS平台USB通道的接口,并进行定制实现更复杂的功能。目的是给驱动层留下更加灵活强大的扩展方案,同时可以兼容现有的驱动,便于移植。USBHost DDK架构如图1所示:
图1 USB主机DDK架构(1)USB接口池负责USB接口管理。提供USB接口申请和恢复,USB接口记录设备端口信息和资源。USB接口池根据USB端口对USB接口进行分类和管理。同时,该模块还提供了USB DDK API,方便开发者读写USB数据。(2)USB协议层提供USB协议封装,翻译/解析设备IO/根据USB协议控制命令,并负责管理设备描述符。根据USB设备上报的枚举信息,匹配相应的描述符,建立相应的USB接口,并将其添加到USB接口池中进行管理。(3)设备IO管理器负责管理USBIO请求,提供同步IO和异步IO管理机制。对于异步IO,IO Manager负责记录请求,然后通过Raw API库提供的接口处理要依次发送的IO请求;IO接收线程收到USB控制器应答的处理结果后,负责解析处理结果并上报给上层调用者。(4)4)Raw API库抽象了底层OS能力,定义了统一的OS能力接口,提供USB RAW API,供开发者定制和实现更复杂的驱动函数。(5)OS适配器用于封装平台(Linux和LiteOS)相关的操作,根据不同的平台配置编写相应平台的封装接口。在Linux平台上,所有访问USBFS的操作都封装在这个模块中;在LiteOS平台上,基于FreeBSD USB框架的设备访问操作都封装在这个模块中。(6)PNP Notify用于动态监控USB状态变化,并在添加/移除新设备时更改设备信息。同时将所有USB设备信息通过KHDF上报给UHDF侧的PNPNotify Manager模块,完成第三方函数驱动的加载/卸载。2USB设备DDK
USB设备DDK为开发者提供了在设备端开发USB驱动程序的能力。比如USB端口的动态注册和注销能力,开发者可以根据能力动态添加和组合USB端口;动态实例化能力,支持根据动态发布的设备、配置、接口和端点描述符创建设备实例和传输通道;用户的数据发送和接收能力,支持在用户模式下发送和接收数据;复合设备能力,在一个物理设备上支持多个逻辑设备,实现多个逻辑设备之间的隔离,支持不同的逻辑设备同时被不同的应用进程访问。USB设备DDK的架构如图2所示:
图2 USB设备DDK架构(1)SDK IF负责将USB设备按照设备、接口、管道进行逻辑划分,封装配置管理、设备管理、IO管理。该模块还为开发者提供了设备试驾开发的能力接口,如设备创建、接口获取、接收事件事件、发送和接收数据等。(2)配置管理器负责解析HCS文件描述的USB描述符信息,获取的USB描述符信息用于设备创建。同时,该模块还提供了读取、新建、删除、修改自定义属性等操作。(3)设备管理器负责根据配置模块解析的USB描述符创建设备。同时,该模块还负责获取设备、删除设备、获取设备状态、获取设备上的接口信息。(4)IO Manager负责数据读写,包括接受事件和数据读写完成事件,支持同步和异步模式数据读写。(5)适配器IF主要用于封装复合设备配置驱动和通用功能驱动的设备节点操作,为上层提供统一的设备管理接口。(6)适配器该模块由复合设备配置驱动和通用功能驱动提供。二、USB DDK开发指南相信你对USB DDK有一定的了解。让让我们看看如何使用USB DDK来开发USB主机和USB设备驱动程序。1 1 USB主机的开发
USB主机(主机驱动程序)主要完成协议封装、设备管理、驱动安装
图3 USB DDK API接口使用步骤如下:
(1)配置驱动匹配表,完成主机驱动整体信息的配置,如下:
structusbpnmatchdtable {//驱动程序模块的名称,该字段的值必须与驱动程序门户结构const char *moduleName的moduleName一致;//驱动外部发布的服务的名称必须是唯一的const char * serviceName//驱动私有数据匹配关键字constchar * DeviceMatchChattr//从本字段(包括本字段)开始的数据长度,单位为字节uint8 _ t length//USB驱动匹配规则uint16 _ t matchFlag//厂商编号uint16 _ t vendorId//产品编号uint16 _ t productId//设备的出厂编号,低位16位uint16 _ t bcdDeviceLow//设备的出厂编号,16位高的uint16 _ t bcdDeviceHigh//USB分配的设备类代码uint8 _ t deviceClass//USB赋值的子类代码uint8 _ t deviceSubClass//USB分配的设备协议代码uint8 _ t deviceProtocol//接口类型,可根据实际需要填写多个uint8 _ t接口类[USB _ PNP _ info _ max _ interfaces];//接口子类,可根据实际需要填写多个uint8 _ t接口子类[USB _ PNP _ info _ max _ interfaces];//接口遵循的协议,可根据实际需要填写多个uint8 _ t接口协议[USB _ PNP _ info _ max _ interfaces];//接口的编号,可以根据实际需要填写多个uint8 _ t接口编号[USB _ PNP _ info _ max _ interfaces];};(左右滑动查看更多)其中matchFlag代表驾驶匹配规则,每一位代表一种匹配模式。其值如下:enum { USB _ PNP _ NOTIFY _ MATCH _ vendor=0x 0001,USB _ PNP _ NOTIFY _ MATCH _ product=0x 0002,USB _ PNP _ NOTIFY _ MATCH _ DEV _ LOW=0x 0004,USB _ PNP _ NOTIFY _ MATCH _ DEV _ HIGH=0x 0008,USB _ PNP _ MATCH _ DEV _ CLASS=0x 0010,USB _ PNP _ NOTIFY _ MATCH _ DEV _ SUBCLASS=0x 020,USB _ PNP _ NOTIFY _ MATCH _ DEV _ PROTOCOL=0x 040,USB _ PNP(左右滑动查看更多)(2)初始化USB主机驱动开发包,使用以下接口:int 32 _ t USB host SDK(struct USB session * * session)(左右滑动查看更多)(3)获取UsbInterface对象在步骤2初始化后,使用以下接口:const struct USB interface * USB interface(const struct USB session * session,uint8 _ t bus num,uint8 _ t USB addr,uint 8 _ t interface index);(左右滑动查看更多)(4)打开步骤3中获取的UsbInterface对象,获取对应接口的USB BinterfaceHandle对象,使用以下接口:USB BinterfaceHandle * USB Bopen接口(const struct USB Interface * Interface obj);(左右滑动查看更多)(5)根据步骤4中获取的UsbInterfaceHandle对象,获取指定索引pinpeIndex的pipeInfo信息,使用如下接口:int 32 _ t USBGETPipeInfo(const UsbInterfaceHandle *接口句柄,uint8_t settingIndex,uint8_t pipeId,struct UsbPipeInfo * pipeInfo);(左右滑动查看更多)(6)为步骤4得到的UsbInterfaceHandle预分配要发送的IO请求对象,使用如下接口:struct USB Request * USBallocRequest(const UsbInterfaceHandle *接口句柄,int isopackets,int length);(左右滑动查看更多)(7)根据输入参数params填充第6步预分配的IO请求,使用如下接口:int 32 _ t USB Fill Request(const struct USB Request * Request,const USB interface handle * interface handle,const struct USB Request parameters * params);(左右滑动查看更多)(8)提交IO请求对象时,可以选择同步或异步模式,使用如下接口:int 32 _ t usbsubmitrequestSync(const struct USB Request * Request);//发送同步IO请求int 32 _ t usbsubmitrequestasync(const struct USB request * request);//发送异步IO请求(左右滑动查看更多)2。使用USB RAW API 2。USB RAW API主要实现USB更复杂的功能,如获取描述符信息、获取设备指针、重置设备、提交传输请求等。如图4所示,它是USB RAW API提供的接口的一部分。
图四个原始USB API使用步骤如下:(1)同USB DDK API的步骤一一样,需先进行驱动匹配表配置。
(2)初始化原始主机,使用如下接口:int32_t突出显示(struct UsbSession **session):(左右滑动,查看更多)(3)待步骤2完成后打开通用串行总线连接埠设备,使用如下接口:av handle * av awopen vie(const struct USB session * session,uint8_t busNum,uint 8 _ t USB addr);(左右滑动,查看更多)(4)待步骤3完成后获取描述符,通过描述符获取接口~我爱你~端点信息,使用如下接口:int 32 _ t转录测试描述符(const av awdevice * rawdev,uint8_t configIndex,struct av配置描述符* * config);(左右滑动,查看更多)(5)分配请求(请求),并根据不同的传输类型使用相应的接口对请求(请求)进行填充:int 32 _ t expabwlawfillbulkrequest(const struct av aw request * request,const usbrawhandle * devhandle,const struct av awfillrequestdata * fill data);//填充用于批量传输的请求int 32 _ t expabwlawfillcontrol setup(const signed char * setup,const struct USB control request data * request data);int 32 _ t versionawfillcontrol请求(const struct av awrequest * request,const usbrawhandle * devhandle,const struct av fillrequestdata * fill data);//填充用于控制传输的请求int 32 _ t transcend request(const struct av aw request * request,const usbrawhandle * devhandle,const struct av fillrequestdata * fill data);//填充用于中断传输的请求int 32 _ t expanawfillisorequest(const struct av aw request * request,const usbrawhandle * devhandle,const struct av fillrequestdata * fill data);//填充用于同步传输的请求(左右滑动,查看更多)(6)提交我请求你对象,可以选择同步或异步两种模式,分别使用如下接口:int 32 _ t abveawsendcontrol请求(const struct av awrequest * request,const av handle * devhandle,const struct USB control request data * request data);//发送同步通用串行总线连接埠控制传输请求int 32 _ t abveawsendbulkrequest(const struct abveawrequest * request,const usbrawhandle * devhandle,const struct abvezquetdata * request data);//发送同步通用串行总线连接埠批量传输请求int 32 _ t abveawsendinteruptrequest(const struct abveawrequest * request,const usbrawhandle * devhandle,const struct exppvemetdata * request data);//发送同步执行通用串行总线连接埠中断传输请求int 32 _ t wan boot提交者(const struct wan boot request * request);//提交异步我呢请求(左右滑动,查看更多)感兴趣的小伙伴可点击下方链接查看完整的通用串行总线主机开发代码:339吉提。com/open harmony/drivers _ peripheral/tree/master/USB/serial/src 2 USB设备的开发
通用串行总线设备(设备端驱动)主要实现设备管理~我爱你~配置管理-我管理~我爱你~数据通信等。usb设备ddk给开发者提供了设备创建~我爱你~获取接口~我爱你~接收事件(事件)事件~我爱你~收发数据等驱动能力接口,如图5所示:
图5个通用串行总线设备DDK开放的美国石油学会下面,我们将根据usb设备提供的驱动能力接口来开发设备端驱动。1 .构造描述符首先,需构造描述符来说明设备的总体信息。开发者可以通过设备功能代码及设备私有数据HCS(六氯环己烷)两种途径进行配置,下面将分别介绍。
(1) 在设备功能代码中配置描述符,配置代码如下:静态结构UsbFnFunction g_acmFunction={//功能描述符启用=真。funcName=f _ generic.a ,strings=g_acmStrings,fsDescriptors=g_acmFsFunction,hsDescriptors=g_acmHsFunction,ssDescriptors=g_acmSsFunction,2005 .sspDescriptors=NULL,};struct UsbFnFunction * g _ functions[]={ # ifdef CDC _ ECM g _ ECM function,# endif # ifdef CDC _ ACM g _ ACM function,# endif null };静态结构USB fn配置g _ master config={//配置描述符。配置值=1,I配置=USB _ FUNC _配置_IDX,2000年.属性=USB_CFG_BUS_POWERED,maxPower=功率,0.001。functions=g_functions,};静态结构UsbFnConfiguration * g _ configs[]={ g _ master config,NULL,};静态结构UsbDeviceDescriptor g _ cdcMasterDeviceDesc={//设备描述符bLength=sizeof(g _ cdcMasterDeviceDesc),bDescriptorType=USB _ DDK _ DT _设备,bcdUSB=CpuToLe16(BCD_USB),bDeviceClass=0,bDeviceSubClass=0,bDeviceProtocol=0,bmaxpacketsize 0=USB _ MAX _ PACKET _ SIZE,idVendor=CpuToLe16(设备_供应商_ID).idProduct=CpuToLe16(设备产品身份证).bcdDevice=CpuToLe16(设备版本)。I制造商=USB _ FUNC _制造商_IDX,2000年.iProduct=USB _ FUNC _产品_IDX,2000年.iSerialNumber=USB _ FUNC _串行_IDX,2000年.bNumConfigurations=1,};静态结构UsbFnDeviceDesc g _ master func device={//描述符入口设备desc=g _ cdcMasterDeviceDesc,deviceStrings=g_devStrings,configs=g_configs,};(左右滑动,查看更多)(2) 在设备私有数据人绒毛膜促性腺激素生化]人绒毛膜生长促乳素中配置,配置代码如下:root { module=master master _ config { match _ attr=USB fn _ master _ driver //该字段与设备中设备匹配属性保持一致,否则无法找到的这个节点的信息。use _ HCS=1;//用户可以用该值决定是否使用大灯清洁系统配置信息UDC _ name=100万。hid WC 3 _ 0 //UDC的名字USB _ dev _ desc=UsbDeviceDescriptor //设备描述符的节点UsbDeviceDescriptor USB _ dev _ string=UsbDeviceStrings //设备字符串的节点为USB device strings USB _ configuration=USB配置//配置描述符的节点为通用串行总线配置.}}(左右滑动,查看更多)设备描述符的节点为UsbDeviceDescriptor配置如下:UsbDeviceDescriptor { bLength=18;bDescriptorType=0x 01 BCD USB=0x 0200 bdeviceclass=0;bDeviceSubClass=0;bDeviceProtocol=0;bmaxpacketsize 0=0x 40 id vendor=0x 0525 id product=0x a4 a7 BCD device=0x 0100制造商=0;乘积=1;序列号=2;num配置s=1;}(左右滑动,查看更多)2.创建设备描述符构造完成后,使用UsbFnDeviceCreate函数创建一个通用串行总线设备,并传入城市发展管理机构控制器名和UsbFnDescriptorData结构体。实现代码如下:
if (useHcs==0) {//使用代码编写的描述符desc数据。TYPE=USB fn _ desc数据_类型_ desc;desc数据。descriptor=g _ acmFuncDevice} else { //使用大灯清洁系统编写的描述符desc数据。TYPE=USB fn _ desc数据_类型_道具;desc数据。属性=ACM-设备-属性;} //创建设备fnDev=(struct usbfndedevice *)UsbFnCreateDevice(ACM-UDC名称,desc数据);(左右滑动,查看更多)3.获取接口设备创建后,使用通用串行总线设备接口函数获取通用串行总线接口接口对象,并通过UsbFnGetInterfacePipeInfo函数获取通用串行总线管道信息,实现代码如下:
//获取接口fni face=(struct UsbFnInterface *)UsbFnGetInterface(fnDev,I);//获取管信息UsbFnGetInterfacePipeInfo(fnIface,I,pipe info);//获取handle handle=UsbFnOpenInterface(fnIface);//获取控制(EP0)请求req=usbfnalloctrlrequest(ACM-ctrl face。handle,sizeof(struct usbcdcline编码)sizeof(struct usbcdcline编码));//获取request req=usbfnalloctrlrequest(ACM-ctrl face。handle,sizeof(struct usbcdcline编码)sizeof(struct usbcdcline编码));(左右滑动,查看更多)4.接收事件事件通过UsbFnStartRecvInterfaceEvent函数接收事件事件,并通过UsbFnEventCallback回调函数对事件事件做出响应,实现代码如下:
//开始接收事件事件ret=UsbFnStartRecvInterfaceEvent(ACM-ctrl face。fn,0xff,UsbAcmEventCallback,ACM);//事件处理回调函数静态void UsbAcmEventCallback(struct UsbFnEvent * event){ struct UsbAcmDevice * ACM=NULL;if(event==NULL | | event-context==NULL){ HDF _日志(% s:事件为空_ _ func _ _);返回;} acm=(struct UsbAcmDevice *)事件上下文;开关(事件类型){ case USB fn _ STATE _ BIND:HDF _ LOGI(% s:接收绑定事件'_ _ func _ _);打破;案例美国bfn _ STATE _ un bind:LOGI HDF(% s:接收解除绑定事件'_ _ func _ _);打破;案例USB fn _ STATE _ ENABLE:HDF _ LOGI(% s:接收启用事件'_ _ func _ _);ACM nable(ACM);打破;案例USB fn _ STATE _ DISABLE:HDF _ LOGI(% s:接收禁用事件'_ _ func _ _);ACM禁用(ACM);ACM-enableEvtCnt=0;打破;案例USBFN _ STATE _ SETUP:LOGI HDF(%s:接收设置事件'_ _ func _ _);如果(事件-设置!=NULL) { AcmSetup(acm,event-setup);}破;案例USB fn _ STATE _ SUSPEND:HDF _ LOGI(% s:接收暂停事件'_ _ func _ _);ACM暂停(ACM);打破;案例美国bfn _ STATE _ RESUME:HDF _ LOGI(% s:接收简历事件'_ _ func _ _);ACM简历(ACM);打破;默认:break}}(左右滑动,查看更多)5.收发数据可以选择同步异步发送模式,实现代码如下:
notify=(struct UsbCdcNotification *)req-buf;if (memcpy_s((void *)(notify 1),length,data,length)!=EOK) {返回HDF _失败;} ret=UsbFnSubmitRequestAsync(req);//异步发送(左右滑动,查看更多)以上就是本期全部内容,通过本文的介绍相信你已经对USB DDK有了深刻的认识,期待广大的开发者加入我们,一起丰富基于USB DDK的第三方驱动。
原文标题:USB DDK助你轻松实现通用串行总线驱动开发
文章出处:【微信公众号:鸿蒙系统开发者】欢迎添加关注!文章转载请注明出处。审核汤梓红