1. I2C硬件框架
I2C的硬件框架已经在i2c子系统_Hanrui的博客-优快云博客中详细说过了,上一个是基于Linux背景下的I2C驱动框架分析,现在是站在鸿蒙Harmony的角度来分析I2C驱动。
仔细对比的话,可以发现两种内核的思想是一样的。都是遵照这下面的层次结构。
如果之前分析过Linux下的I2C驱动程序,可以发现鸿蒙的驱动相对比较好理解。
但首先,一定要记清楚上面的层次图,不然的话,内核有很多函数来回跳转,很快就会晕掉。。
2. Openharmony I2C源码分析
2.1 I2C Device Driver层
在这一层,是I2C驱动的通用层,也就是对于所有的I2C驱动是通用的。
主要参考:openharmony/vendor/nxp/imx6ull/driver/imx6ull-i2c/i2c_dev.c
这个文件中与外界连接的函数是I2cAddVfsById,它主要负责与用户进行交互,比如,用户在用户程序中调用open函数,内核就会调用相应的函数进行处理。所以,鸿蒙也有像Linux的设备文件的概念。
static const struct file_operations_vfs g_i2cFops = {
.open = I2cFsOpen,
.close = I2cFsClose,
.read = I2cFsRead,
.write = I2cFsWrite,
.ioctl = I2cFsIoctl,
.mmap = I2cFsMap,
};
int32_t I2cAddVfsById(int16_t id)
{
name = (char *)OsalMemCalloc(I2C_NAME_SIZE);
ret = snprintf_s(name, I2C_NAME_SIZE, I2C_NAME_SIZE - 1, "/dev/i2c-%d", id);
ret = register_driver(name, &g_i2cFops, I2C_FS_MODE, (void *)((uintptr_t)id));
}
注意到上面的函数中,调用了register_driver函数,与Linux一样,向用户提供了设备文件的接口,如:/dev/i2c-0,当用户调用open, read, write,相应的驱动程序就会进行处理。
函数需要传入一个参数id,那么谁会传入呢?仔细想想的话,上一层的函数会调用到最底层的硬件I2C进行处理。那么谁注册I2C控制器,谁就会调用这个函数,并传入id。这里会由Imx6ullI2cBind调用,后面也会提到,它是属于底层的文件。
2.2 I2C Core层
在这一层,也是I2C驱动的通用层,也就是对于所有的I2C驱动是通用的。
主要参考:openharmony/vendor/nxp/imx6ull/driver/imx6ull-i2c/i2c_core.c;
openharmony/vendor/nxp/imx6ull/driver/imx6ull-i2c/i2c_if.c
这两个文件的函数相对较少,在我理解,他们仅仅起到了对上层Device Driver层传入参数的检查和向下层I2C Controller Driver传入可靠的参数,对于用户是不可见的。
2.3 I2C Controller Driver层
这一层就需要根据各个不同的开发板进行调整,我使用的是100ask_imx6ull。
主要参考:openharmony/vendor/nxp/imx6ull/driver/imx6ull-i2c/i2c_imx6ull.c
对于这个驱动,采用的鸿蒙HDF驱动框架,入口函数是
struct HdfDriverEntry g_i2cDriverEntry = {
.moduleVersion = 1,
.Bind = Imx6ullI2cBind,
.Init = Imx6ullI2cInit,
.Release = Imx6ullI2cRelease,
.mod