赞
踩
鸿蒙为了支持多个内核,提出了HDF(HarmonyDiverFoundation),鸿蒙驱动框架。
使用“服务”的概念编写驱动程序:
(1)驱动程序中实现服务;(2)APP要先获得服务,然后调用服务跟驱动函数交互。
liteOS-a中驱动程序也跟linux类似:
linux使用设备树描述硬件信息,驱动程序从设备树中获得这些信息;
liteos-a使用HCS文件描述硬件信息,驱动程序从HCS文件中获得这些信息。
OpenharmonyFor6ull\kernel\liteos_a\kernel\common\virtual_serial.c
- STATIC const struct file_operations_vfs g_serialDevOps = {
- SerialOpen, /* open */
- SerialClose, /* close */
- SerialRead, /* read */
- SerialWrite,
- NULL,
- SerialIoctl,
- NULL,
- #ifndef CONFIG_DISABLE_POLL
- SerialPoll,
- #endif
- NULL,
- };
-
- INT32 virtual_serial_init(const CHAR *deviceName)
- {
- ...
- (VOID)memset_s(&g_serialFilep, sizeof(struct file), 0, sizeof(struct file));
- g_serialFilep.f_oflags = O_RDWR;
- g_serialFilep.f_inode = inode;
- (VOID)register_driver(SERIAL, &g_serialDevOps, DEFFILEMODE, &g_serialFilep);
- ...
- }

OpenharmonyFor6ull\vendor\nxp\imx6ull\config\device_info
- root {
- device_info {
- //1.
- match_attr = "hdf_manager";
- //2.
- template host {
- hostName = "";
- priority = 100;
- template device{
- template deviceNode {
- policy = 0;
- priority = 100;
- preload = 0;
- permission = 0664;
- moduleName = "";
- serviceName = "";
- deviceMatchAttr = "";
- }
- }
- }
- //3.
- platform :: host {
- hostName = "platform_host";
- priority = 50;
- //3.1 iic接口设备树描述
- device_i2c :: device {
- device0 :: deviceNode {
- policy = 1;
- priority = 50;
- permission = 0644;
- moduleName = "HDF_PLATFORM_I2C"; //对应的驱动程序名称
- serviceName = "HDF_PLATFORM_I2C_0"; //对应本驱动程序对外提供服务的名称,供app程序调用
- deviceMatchAttr = "nxp_imx6ull_i2c_0";//对应硬件初始化信息,根据这个名字在设备树中查找相应的节点来描述这些信息
- }
- }
- //3.2 触摸屏接口设备树描述
- device_touchscreen :: device {
- device0 :: deviceNode {
- policy = 1;
- priority = 100;
- preload = 0;
- permission = 0666;
- moduleName = "HDF_TOUCHSCREEN";
- serviceName = "HDF_TOUCHSCREEN";
- }
- }
-
- }
- //4.
- storage :: host {
- }
- media :: host {
- }
-
-
-
- }
- }

举个例子:找一下上面设备树中用于调用iic设备的HDF_PLATFORM_I2C驱动程序在内核代码中的位置:
OpenharmonyFor6ull\vendor\nxp\imx6ull\driver\imx6ull-i2c\i2c_imx6ull.c
- struct HdfDriverEntry g_i2cDriverEntry = {
- .moduleVersion = 1,
- .Bind = Imx6ullI2cBind,
- .Init = Imx6ullI2cInit,
- .Release = Imx6ullI2cRelease,
- .moduleName = "HDF_PLATFORM_I2C",//这里的名称和设备树中的名称一致,那么就对应起来了
- };
- HDF_INIT(g_i2cDriverEntry);
继续举例子:找一下上面设备树中用于调用iic设备的硬件描述信息deviceMatchAttr = "nxp_imx6ull_i2c_0"在内核代码中的位置:
OpenharmonyFor6ull\vendor\nxp\imx6ull\config\i2c\i2c_config.hcs
- root {
- platfrom {
- i2c_config {
- //描述IIC接口的模板i2c_controller
- template i2c_controller {
- bus = 0;
- match_attr = "";
- reg_pbase = 0x021A4000;//IIC控制器基地址
- reg_size = 0xd1;//IIC控制器寄存器占用的空间
- irq = 0;
- freq = 400000;//IIC通信频率400KHz
- clk = 50000000;//IIC时钟 50MHz
- }
- //定义一个设备controller_0x021A4000
- //使用上面定义的i2c_controller模板
- controller_0x021A4000 :: i2c_controller {
- bus = 0;
- match_attr = "nxp_imx6ull_i2c_0";//对应top层HCS
- }
-
- }
- }
- }

OpenharmonyFor6ull\vendor\nxp\imx6ull\driver\imx6ull-i2c\i2c_imx6ull.c
设备树和驱动程序的对应的源码一致的时候,会导致init函数被调用,即Imx6ullI2cInit函数被调用
- struct HdfDriverEntry g_i2cDriverEntry = {
- .moduleVersion = 1,
- .Bind = Imx6ullI2cBind,
- .Init = Imx6ullI2cInit, //init函数被调用
- .Release = Imx6ullI2cRelease,
- .moduleName = "HDF_PLATFORM_I2C",//HCS和这里名称一致
- };
- HDF_INIT(g_i2cDriverEntry);
init函数源码:
- static int32_t Imx6ullI2cInit(struct HdfDeviceObject *device)
- {
- (void)device;
- return HDF_SUCCESS;
- }
bind函数源码:
LINE94~97:服务结构体,放入dispatch函数
LINE80:驱动程序中把g_hello_val这个值放入reply里面。应用程序就可以把reply取出来。
继续分析该驱动程序对应的app程序:
LINE22 定义服务名称,
LINE26 相当于调用了对应驱动程序的bind函数,传入服务名称就获得了这个服务,该名称在HCS文件中有定义 serviceName = "hello_service"; 该函数里面肯定调用了open函数
LINE45 调用这个服务最终导致驱动程序dispatch函数调用,提供给服务(即驱动程序)的数据为data,服务(即驱动程序)回复的数据为reply;该函数里面肯定调用了read write函数
使用这套新框架隐藏了老框架中需要首先open然后write然后read函数,直接使用BInd函数后dispatch即可,更为简便。
ps:没有下载韦东山老师的源代码,视频截个图,凑合看看吧
hello_init函数:
g_helloDevOps结构体:就是上文说的file_operations_vfs结构体;
/dev/hello:设备节点,供app程序调用使用
看一下g_helloDevOps结构体的定义吧~跟linux的一毛一样。
继续分析该驱动程序对应的app程序:
注释:若使用本小节介绍的老框架,调用的时候调用设备节点-/dev/hello
(1)驱动程序:会发布服务。发布服务就是把该服务传入设备管理器(设备管理器的节点路径为“/dev/dev_mgr”);
(2)APP:从设备管理器(设备管理器的节点路径为“/dev/dev_mgr”)查找并获得服务即调用这个驱动。
如果app提供给设备管理器的服务存在,那么设备管理器会调用下面这个函数,在这个函数中注册驱动程序
OpenharmonyFor6ull\drivers\hdf\lite\adapter\vnode\src\hdf_vnode_adapter.c->HdfIoServiceAdapterObtain”
应用程序的动作:应用程序调用HdfIoServiceBind函数
struct HdfIoService *service = HdfIoServiceBind("hello_service",0);
分析HdfIoServiceBind函数
OpenharmonyFor6ull\drivers\hdf\frameworks\core\shared\src\hdf_io_service.c
- struct HdfIoService *HdfIoServiceBind(const char *serviceName, mode_t permission)
- {
- return HdfIoServiceAdapterObtain(serviceName, permission);
- }
-->
(1)分析一个“HdfIoServiceAdapterObtain”函数:
OpenharmonyFor6ull\drivers\hdf\lite\adapter\syscall\src\hdf_syscall_adapter.c(给应用程序使用的)
- struct HdfIoService *HdfIoServiceAdapterObtain(const char *serviceName, mode_t mode)
- {
- struct HdfSyscallAdapter *adapter = NULL;
- struct HdfIoService *ioService = NULL;
- char devNodePath[PATH_MAX] = {0};
- char realPath[PATH_MAX] = {0};
- ...
-
- if (realpath(devNodePath, realPath) == NULL) {
- //通过服务名称查找并加载驱动,根据上文HCS中的ServiceName定义
- //在这之前 /dev/dev_mgr会自动给hello_service注册一个驱动程序
- HdfLoadDriverByServiceName(serviceName);
- //获得设备节点路径
- realpath(devNodePath, realPath);
- }
- ...
- //realPath = “/dev/hello_service”
- adapter->fd = open(realPath, O_RDWR);
- ioService = &adapter->super;
- static struct HdfIoDispatcher dispatch = {
- .Dispatch = HdfSyscallAdapterDispatch,
- };
- ioService->dispatcher = &dispatch;
- return ioService;
- }

--->
OpenharmonyFor6ull\drivers\hdf\lite\adapter\syscall\src\hdf_syscall_adapter.c
- #define DEV_NODE_PATH "/dev/"
- #define DEV_MGR_NODE "dev_mgr"
- static int32_t HdfLoadDriverByServiceName(const char *serviceName)
- {
- int32_t ret = HDF_FAILURE;
- struct HdfSBuf *data = NULL;
- //通过访问驱动程序,让驱动程序加载服务发布服务
- struct HdfIoService *ioService = HdfIoServiceBind(DEV_MGR_NODE, 0);
- ...
- }
---->回到之前继续执行函数
OpenharmonyFor6ull\drivers\hdf\lite\adapter\vnode\src\hdf_vnode_adapter.c
- struct HdfIoService *HdfIoServiceAdapterObtain(const char *serviceName, mode_t mode)
- {
- // /dev/dev_mgr会给hello_service注册一个驱动程序/dev/hello_service
- HdfLoadDriverByServiceName(serviceName);
- //获得realPath的值为realPath="/dev/hello_service"
- realpath(devNodePath, realPath);
- //realPath="/dev/hello_service"
- adapter->fd = open(realPath, O_RDWR);
- }
(2)分析另一个“HdfIoServiceAdapterObtain”函数:
OpenharmonyFor6ull\drivers\hdf\lite\adapter\vnode\src\hdf_vnode_adapter.c//内核调用
- struct HdfIoService *HdfIoServiceAdapterObtain(const char *serviceName, mode_t mode)
- {
- static const struct file_operations_vfs fileOps = {
- .open = HdfVNodeAdapterOpen,
- .ioctl = HdfVNodeAdapterIoctl,
- .poll = HdfVNodeAdapterPoll,
- .close = HdfVNodeAdapterClose,
- };
- //注册file_operations结构体
- //vNodePath就是传进来的“/dev/hello_service”
- int ret = register_driver(vnodeAdapter->vNodePath, &fileOps, mode, vnodeAdapter);
-
- }
应用程序的动作:应用程序调用service->dispatcher->Dispatch(&service->object,0,data,reply)函数
- //OpenharmonyFor6ull\drivers\hdf\lite\adapter\syscall\src\hdf_syscall_adapter.c
- struct HdfIoService *HdfIoServiceAdapterObtain(const char *serviceName, mode_t mode)
- {
- ...
- ioService = &adapter->super;
- static struct HdfIoDispatcher dispatch = {
- .Dispatch = HdfSyscallAdapterDispatch,
- };
- ioService->dispatcher = &dispatch;
- ...
- }
->
从上面的代码可知,最终调用函数HdfSyscallAdapterDispatch
OpenharmonyFor6ull\drivers\hdf\lite\adapter\syscall\src\hdf_syscall_adapter.c
- tatic int HdfSyscallAdapterDispatch(struct HdfObject *object, int code, struct HdfSBuf *data, struct HdfSBuf *reply)
- {
- ...
- int ret = ioctl(ioService->fd, HDF_WRITE_READ, &wrBuf);
- ...
- return ret;
- }
->
从上面的代码可知,最终调用了ioctl,该函数最终进入到下面这个函数
OpenharmonyFor6ull\drivers\hdf\lite\adapter\vnode\src\hdf_vnode_adapter.c
- static int HdfVNodeAdapterIoctl(struct file *filep, int cmd, unsigned long arg)
- {
- struct HdfVNodeAdapterClient *client = (struct HdfVNodeAdapterClient *)filep->f_priv;
- if (client == NULL) {
- return HDF_DEV_ERR_NO_DEVICE;
- }
- switch (cmd) {
- case HDF_WRITE_READ:
- if (client->serv == NULL) {
- return HDF_DEV_ERR_NO_DEVICE;
- }
- return HdfVNodeAdapterServCall(client, arg);
- ...
- default:
- return HDF_FAILURE;
- }
-
- return HDF_SUCCESS;
- }

->
继续进入函数HdfVNodeAdapterServCall
OpenharmonyFor6ull\drivers\hdf\lite\adapter\vnode\src\hdf_vnode_adapter.c
- static int HdfVNodeAdapterServCall(const struct HdfVNodeAdapterClient *client, unsigned long arg)
- {
- ...
- if (LOS_ArchCopyFromUser(&bwr, (void*)bwrUser, sizeof(bwr)) != 0) {
- HDF_LOGE("Copy from user failed");
- return HDF_FAILURE;
- }
- ...
- int ret = client->adapter->ioService.dispatcher->Dispatch(client->adapter->ioService.target,
- bwr.cmdCode, data, reply);
- ...
- if (LOS_ArchCopyToUser(bwrUser, &bwr, sizeof(struct HdfWriteReadBuf)) != 0) {
- HDF_LOGE("%s: copy bwr fail", __func__);
- ret = HDF_FAILURE;
- }
- }

->
其中的Dispatcher函数进一步调用就是驱动程序的dispatch函数
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。