HDF(Hardware Driver Foundation)驱动框架是HarmonyOS硬件生态凋谢的根底,为开发者提供了驱动加载、驱动服务治理和驱动音讯机制等驱动能力,让开发者能精准且高效的开发驱动程序。本期,咱们将为大家带来HDF驱动框架中USB DDK的解析与领导。
一、USB DDK介绍
USB(Universal Serial Bus)通用串行总线,用于标准电脑与外部设备的连贯和通信,蕴含了主机端(Host)和设施端(Device)。其中,主机端负责USB总线中的数据传输及端口治理,设施端则能够连贯各种外设,所以USB驱动开发又分为主机端驱动开发和设施端驱动开发。
因为基于内核态开发的USB驱动性能扩展性较差,目前开发者通常抉择Libusb库进行USB驱动开发。该库是一种跨平台的用户态开源USB通信库,能够满足开发者基于用户态开发性能驱动的需要。然而,因为Libusb库是齐全依照USB协定来封装接口的,所以须要开发者对USB协定要有较深的理解能力很好的应用,对开发者的要求绝对较高,让很多比拟高级的开发者望而生畏。为了让更多的开发者都能进行基于用户态的USB驱动开发,HDF引入了USB DDK开发套件。
USB DDK(USB DriverDevelop Kit)是HDF驱动框架为开发者提供的USB驱动程序开发套件,包含USB Host DDK及USB Device DDK两局部,反对基于用户态开发USB设施驱动的同时,还提供了丰盛的USB驱动开发能力,让宽广开发者能精准且高效的开发USB驱动程序。上面,咱们将一一道来。
- USB Host DDK
USB Host DDK给开发者提供了主机端USB驱动开发能力,依照性能分类三大类,别离是DDK初始化类、interface对象操作类及request对象操作类。并为开发者提供了一般模式和专家模式两种开发模式。一般模式下,开发者可通过USBDDK API间接实现相干USB数据读写操作,不须要过多关注底层传输细节。专家模式下,开发者通过USB RAW API间接拜访OS平台USB通道的接口,自定义实现更加简单的性能。目标是给驱动层留有更灵便,更弱小的扩大计划,同时也可能兼容现有驱动,便于移植。USBHost DDK架构如图1所示:
图1 USB Host DDK架构
(1)USB Interface Pool负责USBInterface治理。提供USB Interface申请和回收,USB Interface记录设施端口信息以及资源。USB Interface Pool依照USB Port对USB Interface进行分类管理。同时,此模块还提供了USB DDK API,不便开发者USB数据读写操作。
(2)USB Protocol Layer提供USB协定封装,依据USB协定对设施IO/管制命令的“翻译/解析”,同时负责设施描述符的治理,依据USB Device上报的枚举信息,匹配对应的描述符,并构建对应的USB Interface,并退出到USB Interface Pool中治理。
(3)Device IO Manager负责USBIO申请治理,提供了同步IO和异步IO管理机制,对于异步IO,IO Manager负责将该申请记录下来,而后通过Raw API Library提供的接口顺次解决待发送的IO申请;当收到USB控制器应答的处理结果后,IO接管线程负责解析并上报处理结果给下层调用者。
(4)Raw API Library形象了底层OS能力,定义了对立的OS能力接口,对外提供了USB RAW API,让开发者自定义实现更加简单的驱动性能。
(5)OS Adapter用于封装与平台(Linux和LiteOS)相干的操作,依据不同平台配置编译对应平台的封装接口。在Linux平台上,拜访USBFS的操作,全副都封装在这个模块中;而在LiteOS平台上,基于FreeBSD USB框架的设施拜访操作,对应的也都全副封装在这个模块中。
(6)PNP Notify用于动静监测USB状态变动,当有新设施增加/移除时,变动设施信息。同时将所有USB设施信息都通过KHDF上报给UHDF侧的PNPNotify Manager模块来实现加载/卸载第三方性能驱动。
2.USB Device DDK
USB Device DDK给开发者提供了设施端USB驱动开发能力。例如,USB端口动静注册和去注册能力,开发者能够基于能力实现USB端口的动静增加和组合;动静实例化能力,反对依据动静下发设施、配置、接口及端点描述符创立设施实例及传输通道;用户态的数据发送及接管能力,反对用户态下发送及接收数据;复合设施能力,反对一个物理设施上多个逻辑设备,实现多个逻辑设备间隔离,并反对不同逻辑设备同时被不同的利用过程拜访。USB Device DDK架构如图2所示:
图2 USB Device DDK架构
(1)SDK IF负责将USB设施依照设施、接口、管道进行逻辑划分,对配置管理、设施治理、IO治理进行封装。此模块还向开发者提供了设施创立、获取接口、接管Event事件、收发数据等设施测驱动开发的能力接口。
(2)Configuration Manager负责解析HCS文件形容的USB描述符信息,失去的USB描述符信息用于设施创立,同时模块还提供了自定义属性的读取、创立、删除、批改等操作。
(3)Device Manager负责依据配置模块解析的USB描述符,并依据USB描述符创立设施。同时模块还负责获取设施、删除设施、获取设施状态,获取设施下面接口信息。
(4)IO Manager负责数据的读写,包含Events事件、数据读写实现事件的承受,反对同步和异步模式数据读写。
(5)Adapter IF次要是对复合设施配置驱动及通用性能驱动设施节点操作进行封装,为下层提供对立的设施治理接口。
(6)Adapter该模块由复合设施配置驱动及通用性能驱动提供。
二、USB DDK开发领导
置信大家已对USB DDK曾经有了肯定的意识。上面,咱们来看看如何应用USB DDK来开发USB Host和USB Device驱动程序吧。
1.USB Host的开发
USB Host(主机端驱动)次要实现协定封装、设施治理、驱动装置与卸载等。通过上文的介绍,开发者可通过USB DDK API和USB RAW API来实现主机端驱动。
- USB DDK API的应用
USB DDK API次要实现主机端USB数据读写操作,如图3所示,是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];};
其中matchFlag示意驱动匹配规定,每个bit示意一种匹配形式,其取值如下:
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,};
(2) USB主机端驱动开发工具包初始化,应用如下接口:
int32_t UsbInitHostSdk(struct UsbSession **session)
(3) 待步骤2初始化完后获取UsbInterface对象,应用如下接口:
const struct UsbInterface *UsbClaimInterface(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr, uint8_t interfaceIndex);
(4) 关上步骤3获取到的UsbInterface接口对象,获取对应接口的UsbInterfaceHandle对象,应用如下接口:
UsbInterfaceHandle *UsbOpenInterface(const struct UsbInterface *interfaceObj);
(5) 依据步骤4获取到的UsbInterfaceHandle对象,获取指定索引为pinpeIndex的pipeInfo信息,应用如下接口:
int32_t UsbGetPipeInfo(const UsbInterfaceHandle *interfaceHandle, uint8_t settingIndex, uint8_t pipeId, struct UsbPipeInfo *pipeInfo);
(6) 为步骤4获取到的UsbInterfaceHandle事后调配待发送的IO Request对象,应用如下接口:
struct UsbRequest *UsbAllocRequest(const UsbInterfaceHandle *interfaceHandle, int isoPackets, int length);
(7) 依据输出参数params填充步骤6事后调配的IO Request,应用如下接口:
int32_t UsbFillRequest(const struct UsbRequest *request, const UsbInterfaceHandle *interfaceHandle, const struct UsbRequestParams *params);
(8) 提交IO Request对象,能够抉择同步或异步两种模式,应用如下接口:
int32_t UsbSubmitRequestSync(const struct UsbRequest *request);//发送同步IO申请int32_t UsbSubmitRequestAsync(const struct UsbRequest *request);//发送异步IO申请
- USB RAW API 的应用
USB RAW API次要实现USB更加简单的性能,如获取描述符信息、获取设施指针、复位设施、提交传输申请等,如图4所示,是USB RAW API提供的局部接口。
图4 USB RAW API
应用步骤如下:
(1) 同USB DDK API的步骤1一样,需先进行驱动匹配表配置。
(2) 初始化Host RAW,应用如下接口:
int32_t UsbRawInit(struct UsbSession **session);
(3) 待步骤2实现后关上USB设施,应用如下接口:
UsbRawHandle *UsbRawOpenDevice(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr);
(4) 待步骤3实现后获取描述符,通过描述符获取接口、端点信息,应用如下接口:
int32_t UsbRawGetConfigDescriptor(const UsbRawDevice *rawDev, uint8_t configIndex, struct UsbRawConfigDescriptor **config);
(5) 调配Request,并依据不同的传输类型应用相应的接口对Request进行填充:
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);// 填充用于同步传输的申请
(6) 提交IO Request对象,能够抉择同步或异步两种模式,别离应用如下接口:
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申请
感兴趣的小伙伴可点击下方链接查看残缺的USB Host开发代码:
https://gitee.com/openharmony...
2.USB Device的开发
USB Device(设施端驱动)次要实现设施治理、配置管理、IO治理、数据通信等。USB Deivce DDK给开发者提供了设施创立、获取接口、接管Event事件、收发数据等驱动能力接口,如图5所示:
图5 USB Device DDK凋谢的API
上面,咱们将依据USB Deivce DDK提供的驱动能力接口来开发设施端驱动。
- 结构描述符
首先,需结构描述符来阐明设施的总体信息。开发者能够通过设施性能代码及设施公有数据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[] = {#ifdef CDC_ECM &g_ecmFunction,#endif#ifdef CDC_ACM &g_acmFunction,#endifNULL};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,};
(2) 在设施公有数据HCS中配置,配置代码如下:
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";//设施描述符的节点UsbDeviceDescriptor usb_dev_string = "UsbDeviceStrings"; //设施字符串的节点为UsbDeviceStrings usb_configuration = "UsbConfigs"; //配置描述符的节点为UsbConfigs ... }}
设施描述符的节点为UsbDeviceDescriptor,配置如下:
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);3.获取接口设施创立后,应用UsbFnDeviceGetInterface函数获取UsbInterface接口对象,并通过```UsbFnGetInterfacePipeInfo函数获取USB管道信息,实现代码如下:
//获取接口
fnIface = (struct UsbFnInterface *)UsbFnGetInterface(fnDev, i);
//获取Pipe信息
UsbFnGetInterfacePipeInfo(fnIface, i, &pipeInfo);
//获取Handle
handle = UsbFnOpenInterface(fnIface);
//获取管制(EP0)Request
req = UsbFnAllocCtrlRequest(acm->ctrlIface.handle,sizeof(struct UsbCdcLineCoding) + sizeof(struct UsbCdcLineCoding));
//获取Request
req = UsbFnAllocCtrlRequest(acm->ctrlIface.handle,sizeof(struct UsbCdcLineCoding) + sizeof(struct UsbCdcLineCoding));
- 接管Event事件
通过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);//异步发送
感兴趣的小伙伴可点击https://gitee.com/openharmony... 查看残缺的设施测开发代码。
以上就是本期全部内容,通过本文的介绍置信你曾经对USB DDK有了粗浅的意识,期待宽广的开发者退出咱们,一起丰盛基于USB DDK的第三方驱动。