HDF(Hardware Driver Foundation)驱动框架是HarmonyOS硬件生态开放的基础,为开发者提供了驱动加载、驱动服务管理和驱动消息机制等驱动能力,让开发者能精准且高效的开发驱动程序。本期,我们将为大家带来HDF驱动框架中USB DDK的解析与指导。
一、USB DDK介绍USB DDK(USB DriverDevelop Kit)是HDF驱动框架为开发者提供的USB驱动程序开发套件,包括USB Host DDK及USB Device DDK两部分,支持基于用户态开发USB设备驱动的同时,还提供了丰富的USB驱动开发能力,让广大开发者能精准且高效的开发USB驱动程序。下面,我们将一一道来。
1 USB Host DDK
USB Host DDK给开发者提供了主机端USB驱动开发能力,按照功能分类三大类,分别是DDK初始化类、interface对象操作类及request对象操作类。并为开发者提供了普通模式和专家模式两种开发模式。普通模式下,开发者可通过USBDDK API直接完成相关USB数据读写操作,不需要过多关注底层传输细节。专家模式下,开发者通过USB RAW API直接访问OS平台USB通道的接口,自定义实现更加复杂的功能。目的是给驱动层留有更灵活,更强大的扩展方案,同时也能够兼容现有驱动,便于移植。USBHost DDK架构如图1所示:

2 USB Device DDK
USB Device DDK给开发者提供了设备端USB驱动开发能力。例如,USB端口动态注册和去注册能力,开发者可以基于能力实现USB端口的动态添加和组合;动态实例化能力,支持根据动态下发设备、配置、接口及端点描述符创建设备实例及传输通道;用户态的数据发送及接收能力,支持用户态下发送及接收数据;复合设备能力,支持一个物理设备上多个逻辑设备,实现多个逻辑设备间隔离,并支持不同逻辑设备同时被不同的应用进程访问。USB Device DDK架构如图2所示:

1 USB Host的开发
USB Host(主机端驱动)主要完成协议封装、设备管理、驱动安装与卸载等。通过上文的介绍,开发者可通过USB DDK API和USB RAW API来实现主机端驱动。
1. USB DDK API的使用

图3 USB DDK API部分接口
使用步骤如下:
(1) 配置驱动匹配表,完成主机端驱动总体信息的配置,具体如下:
(左右滑动,查看更多)struct UsbPnpMatchIdTable {//驱动模块名,该字段的值必须和驱动入口结构的moduleName一致const char *moduleName;//驱动对外发布服务的名称,必须唯一const char *serviceName;//驱动私有数据匹配关键字const char *deviceMatchAttr;//从该字段开始(包含该字段)之后数据长度,以byte为单位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 interfaceClass[USB_PNP_INFO_MAX_INTERFACES];//接口子类型,根据实际需要可填写多个uint8_t interfaceSubClass[USB_PNP_INFO_MAX_INTERFACES];//接口所遵循的协议,根据实际需要可填写多个uint8_t interfaceProtocol[USB_PNP_INFO_MAX_INTERFACES];//接口的编号,根据实际需要可填写多个uint8_t interfaceNumber[USB_PNP_INFO_MAX_INTERFACES];};
(左右滑动,查看更多)enum {USB_PNP_NOTIFY_MATCH_VENDOR = 0x0001,USB_PNP_NOTIFY_MATCH_PRODUCT = 0x0002,USB_PNP_NOTIFY_MATCH_DEV_LOW = 0x0004,USB_PNP_NOTIFY_MATCH_DEV_HIGH = 0x0008,USB_PNP_NOTIFY_MATCH_DEV_CLASS = 0x0010,USB_PNP_NOTIFY_MATCH_DEV_SUBCLASS = 0x0020,USB_PNP_NOTIFY_MATCH_DEV_PROTOCOL = 0x0040,USB_PNP_NOTIFY_MATCH_INT_CLASS = 0x0080,USB_PNP_NOTIFY_MATCH_INT_SUBCLASS = 0x0100,USB_PNP_NOTIFY_MATCH_INT_PROTOCOL = 0x0200,USB_PNP_NOTIFY_MATCH_INT_NUMBER = 0x0400,};
int32_t UsbInitHostSdk(struct UsbSession **session)
(左右滑动,查看更多)
const struct UsbInterface *UsbClaimInterface(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr, uint8_t interfaceIndex);
(左右滑动,查看更多)
UsbInterfaceHandle *UsbOpenInterface(const struct UsbInterface *interfaceObj);
(左右滑动,查看更多)
int32_t UsbGetPipeInfo(const UsbInterfaceHandle *interfaceHandle, uint8_t settingIndex, uint8_t pipeId, struct UsbPipeInfo *pipeInfo);
(左右滑动,查看更多)
struct UsbRequest *UsbAllocRequest(const UsbInterfaceHandle *interfaceHandle, int isoPackets, int length);
(左右滑动,查看更多)
int32_t UsbFillRequest(const struct UsbRequest *request, const UsbInterfaceHandle *interfaceHandle, const struct UsbRequestParams *params);
(左右滑动,查看更多)(左右滑动,查看更多)int32_t UsbSubmitRequestSync(const struct UsbRequest *request);//发送同步IO请求int32_t UsbSubmitRequestAsync(const struct UsbRequest *request);//发送异步IO请求
USB RAW API主要实现USB更加复杂的功能,如获取描述符信息、获取设备指针、复位设备、提交传输请求等,如图4所示,是USB RAW API提供的部分接口。

(1) 同USB DDK API的步骤1一样,需先进行驱动匹配表配置。
(2) 初始化Host RAW,使用如下接口:
int32_t UsbRawInit(struct UsbSession **session);
(左右滑动,查看更多)
UsbRawHandle *UsbRawOpenDevice(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr);
(左右滑动,查看更多)
int32_t UsbRawGetConfigDescriptor(const UsbRawDevice *rawDev, uint8_t configIndex, struct UsbRawConfigDescriptor **config);
(左右滑动,查看更多)(左右滑动,查看更多)int32_t UsbRawFillBulkRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);// 填充用于批量传输的请求int32_t UsbRawFillControlSetup(const unsigned char *setup, const struct UsbControlRequestData *requestData);int32_t UsbRawFillControlRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);// 填充用于控制传输的请求int32_t UsbRawFillInterruptRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);// 填充用于中断传输的请求int32_t UsbRawFillIsoRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);// 填充用于同步传输的请求
(左右滑动,查看更多)int32_t UsbRawSendControlRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbControlRequestData *requestData);//发送同步USB控制传输请求int32_t UsbRawSendBulkRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRequestData *requestData);//发送同步USB批量传输请求int32_t UsbRawSendInterruptRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRequestData *requestData);//发送同步执行USB中断传输请求int32_t UsbRawSubmitRequest(const struct UsbRawRequest *request);//提交异步IO请求
2 USB Device的开发
USB Device(设备端驱动)主要实现设备管理、配置管理、IO管理、数据通信等。USB Deivce DDK给开发者提供了设备创建、获取接口、接收Event事件、收发数据等驱动能力接口,如图5所示:

首先,需构造描述符来说明设备的总体信息。开发者可以通过设备功能代码及设备私有数据HCS两种途径进行配置,下面将分别介绍。
(1) 在设备功能代码中配置描述符,配置代码如下:(左右滑动,查看更多)static struct UsbFnFunction g_acmFunction = {//功能描述符.enable = true,.funcName = "f_generic.a",.strings = g_acmStrings,.fsDescriptors = g_acmFsFunction,.hsDescriptors = g_acmHsFunction,.ssDescriptors = g_acmSsFunction,.sspDescriptors = NULL,};struct UsbFnFunction *g_functions[] = {&g_ecmFunction,&g_acmFunction,NULL};static struct UsbFnConfiguration g_masterConfig = {//配置描述符.configurationValue = 1,.iConfiguration = USB_FUNC_CONFIG_IDX,.attributes = USB_CFG_BUS_POWERED,.maxPower = POWER,.functions = g_functions,};static struct UsbFnConfiguration *g_configs[] = {&g_masterConfig,NULL,};static struct UsbDeviceDescriptor g_cdcMasterDeviceDesc = {//设备描述符.bLength = sizeof(g_cdcMasterDeviceDesc),.bDescriptorType = USB_DDK_DT_DEVICE,.bcdUSB = CpuToLe16(BCD_USB),.bDeviceClass = 0,.bDeviceSubClass = 0,.bDeviceProtocol = 0,.bMaxPacketSize0 = USB_MAX_PACKET_SIZE,.idVendor = CpuToLe16(DEVICE_VENDOR_ID),.idProduct = CpuToLe16(DEVICE_PRODUCT_ID),.bcdDevice = CpuToLe16(DEVICE_VERSION),.iManufacturer = USB_FUNC_MANUFACTURER_IDX,.iProduct = USB_FUNC_PRODUCT_IDX,.iSerialNumber = USB_FUNC_SERIAL_IDX,.bNumConfigurations = 1,};static struct UsbFnDeviceDesc g_masterFuncDevice = {//描述符入口.deviceDesc = &g_cdcMasterDeviceDesc,.deviceStrings = g_devStrings,.configs = g_configs,};
(左右滑动,查看更多)root {module = "master";master_config {match_attr = "usbfn_master_driver";//该字段与device中deviceMatchAttr保持一致,否则无法找到的这个节点的信息。use_hcs = 1; //用户可以用该值决定是否使用hcs配置信息udc_name = "100e0000.hidwc3_0"; //UDC的名字usb_dev_desc = "UsbDeviceDescriptor";//设备描述符的节点UsbDeviceDescriptorusb_dev_string = "UsbDeviceStrings"; //设备字符串的节点为UsbDeviceStringsusb_configuration = "UsbConfigs"; //配置描述符的节点为UsbConfigs...}}
(左右滑动,查看更多)UsbDeviceDescriptor {bLength = 18;bDescriptorType = 0x01;bcdUSB = 0x0200;bDeviceClass = 0;bDeviceSubClass = 0;bDeviceProtocol = 0;bMaxPacketSize0 = 0x40;idVendor = 0x0525;idProduct = 0xA4A7;bcdDevice = 0x0100;manufacturer = 0;product = 1;serialnumber = 2;numConfigurations = 1;}
描述符构造完成后,使用UsbFnDeviceCreate函数创建一个USB设备,并传入UDC控制器名和UsbFnDescriptorData结构体。实现代码如下:
(左右滑动,查看更多)if (useHcs == 0) {//使用代码编写的描述符descData.type = USBFN_DESC_DATA_TYPE_DESC;descData.descriptor = &g_acmFuncDevice;} else { //使用hcs编写的描述符descData.type = USBFN_DESC_DATA_TYPE_PROP;descData.property = acm->device->property;}//创建设备fnDev = (struct UsbFnDevice *) UsbFnCreateDevice(acm->udcName, &descData);
设备创建后,使用UsbFnDeviceGetInterface函数获取UsbInterface接口对象,并通过UsbFnGetInterfacePipeInfo函数获取USB管道信息,实现代码如下:
(左右滑动,查看更多)//获取接口fnIface = (struct UsbFnInterface *)UsbFnGetInterface(fnDev, i);//获取Pipe信息UsbFnGetInterfacePipeInfo(fnIface, i, &pipeInfo);//获取Handlehandle = UsbFnOpenInterface(fnIface);//获取控制(EP0)Requestreq = UsbFnAllocCtrlRequest(acm->ctrlIface.handle,sizeof(struct UsbCdcLineCoding) + sizeof(struct UsbCdcLineCoding));//获取Requestreq = UsbFnAllocCtrlRequest(acm->ctrlIface.handle,sizeof(struct UsbCdcLineCoding) + sizeof(struct UsbCdcLineCoding));
通过UsbFnStartRecvInterfaceEvent函数接收Event事件,并通过UsbFnEventCallback回调函数对Event事件做出响应,实现代码如下:
(左右滑动,查看更多)//开始接收Event事件ret = UsbFnStartRecvInterfaceEvent(acm->ctrlIface.fn, 0xff, UsbAcmEventCallback, acm);//Event处理回调函数static void UsbAcmEventCallback(struct UsbFnEvent *event){struct UsbAcmDevice *acm = NULL;if (event == NULL || event->context == NULL) {HDF_LOGE("%s: event is null", __func__);return;}acm = (struct UsbAcmDevice *)event->context;switch (event->type) {case USBFN_STATE_BIND:HDF_LOGI("%s: receive bind event", __func__);break;case USBFN_STATE_UNBIND:HDF_LOGI("%s: receive unbind event", __func__);break;case USBFN_STATE_ENABLE:HDF_LOGI("%s: receive enable event", __func__);AcmEnable(acm);break;case USBFN_STATE_DISABLE:HDF_LOGI("%s: receive disable event", __func__);AcmDisable(acm);acm->enableEvtCnt = 0;break;case USBFN_STATE_SETUP:HDF_LOGI("%s: receive setup event", __func__);if (event->setup != NULL) {AcmSetup(acm, event->setup);}break;case USBFN_STATE_SUSPEND:HDF_LOGI("%s: receive suspend event", __func__);AcmSuspend(acm);break;case USBFN_STATE_RESUME:HDF_LOGI("%s: receive resume event", __func__);AcmResume(acm);break;default:break;}}
可以选择同步异步发送模式,实现代码如下:
(左右滑动,查看更多)notify = (struct UsbCdcNotification *)req->buf;...if (memcpy_s((void *)(notify + 1), length, data, length) != EOK) {return HDF_FAILURE;}ret = UsbFnSubmitRequestAsync(req);//异步发送
以上就是本期全部内容,通过本文的介绍相信你已经对USB DDK有了深刻的认识,期待广大的开发者加入我们,一起丰富基于USB DDK的第三方驱动。
原文标题:USB DDK助你轻松实现USB驱动开发
文章出处:【微信公众号:HarmonyOS开发者】欢迎添加关注!文章转载请注明出处。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !