【I2C设备驱动】必须将id_table[]数组的最后一个元素设置为空的原因

56 篇文章 6 订阅
42 篇文章 2 订阅

  忘记了在哪本书上看到过,说必须给 I2C 设备驱动的 id 表数组添加上一个空元素作为最后一个元素,就像下面的代码所展示的那样:

struct i2c_device_id {
    char name[I2C_NAME_SIZE];
    kernel_ulong_t driver_data;  /* Data private to the driver */
}


static const struct i2c_device_id rt5677_i2c_id[] = {
    { "rt5677", 0 },
    { }    // 末尾需要是一个空元素
};


struct i2c_driver rt5677_i2c_driver = {
    .driver = {
        .name = "rt5677",
        .owner = THIS_MODULE,
#ifdef CONFIG_PM
        .pm = &rt5677_pm_ops,
#endif
#ifdef RTACPI_I2C
        .acpi_match_table = ACPI_PTR(rt5677_acpi_match),
#endif
    },
    .probe = rt5677_i2c_probe,
    .remove   = rt5677_i2c_remove,
    .shutdown = rt5677_i2c_shutdown,
    .id_table = rt5677_i2c_id,    // 指定id_table
};

  那么原因是什么呢?这样的声明方式一定和它的使用方式有关,所以我们一起在代码中看看 id_table[] 数组被使用的地方:

/**
 * hda_match - bind hda device to hda driver.
 * @dev: device.
 * @drv: driver.
 *
 */
static int soc_hda_match(struct device *dev, struct device_driver *drv)
{
    struct snd_soc_hda_device *pdev = to_soc_hda_device(dev);
    struct snd_soc_hda_driver *pdrv = to_soc_hda_driver(drv);

    /* Then try to match against the id table */
    if (pdrv->id_table)
        return soc_hda_match_id(pdrv->id_table, pdev) != NULL;    // 传入 id_table 指针进行匹配

    /* fall-back to driver name match */
    return (strcmp(pdev->name, drv->name) == 0);
}

  从上方我们看到 id_table 被 soc_hda_match_id() 函数作为入口参数使用,继续深入查看该函数中的操作:

static const struct snd_soc_hda_device_id *soc_hda_match_id(
            const struct snd_soc_hda_device_id *id,
            struct snd_soc_hda_device *pdev)
{
    while (id->name[0]) {  // 如果 name 不为空,则执行下列匹配
        if (pdev->id == id->id) {
            pdev->id_entry = id;
            return id;
        } else if (strcmp(pdev->name, id->name) == 0) {
                pdev->id_entry = id;
                return id;
        }
        id++;  // 继续处理 id_table 中的下一个元素
    }
    return NULL;
}

  看到这里,原因就很清楚了:while语句只有在检测到 id_table 中某一个元素的 name 成员为空时,才会跳出循环,所以在定义 id_table 时必须使用一个空元素{}来作为结束标记。这个用法就类似字符数组必须使用\0字符来作为结束符一样(或者表述为:字符串必须以\0字符结尾),否则程序在处理字符串时将不知何时终止而出现错误。
  

很抱歉,作为AI语言模型,我无法编写实际的Linux驱动程序。但是,我可以给您提供一些参考和指导,帮助您开始编写自己的i2c驱动程序。 在Linux中,i2c驱动程序通常使用i2c-dev和i2c-algo-bit内核模块。i2c-dev模块允许用户间程序通过文件系统接口与i2c总线通信,而i2c-algo-bit模块提供了一种算法,用于在i2c总线上实现位操作。 以下是编写i2c驱动程序的一般步骤: 1. 包含必要的头文件 #include <linux/i2c.h> #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> 2. 定义i2c_driver结构体 static struct i2c_driver my_i2c_driver = { .driver = { .name = "my_i2c_driver", .owner = THIS_MODULE, }, .id_table = my_i2c_idtable, .probe = my_i2c_probe, .remove = my_i2c_remove, }; 在这里,您需要定义一个i2c_driver结构体,其中包括驱动程序的名称、所有者以及probe和remove函数指针。 3. 实现i2c_driver的probe和remove函数 static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { // 处理i2c设备的初始化 return 0; } static int my_i2c_remove(struct i2c_client *client) { // 处理i2c设备的卸载 return 0; } 在probe函数中,您需要编写初始化i2c设备的代码。在remove函数中,您需要编写卸载i2c设备的代码。 4. 注册i2c_driver static struct i2c_device_id my_i2c_idtable[] = { { "my_i2c_device", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, my_i2c_idtable); static int __init my_i2c_init(void) { return i2c_add_driver(&my_i2c_driver); } static void __exit my_i2c_exit(void) { i2c_del_driver(&my_i2c_driver); } module_init(my_i2c_init); module_exit(my_i2c_exit); 在这里,您需要定义一个i2c_device_id结构体数组,其中包括i2c设备的名称和ID。然后,您需要使用i2c_add_driver函数注册i2c_driver,并使用i2c_del_driver函数注销i2c_driver。 5. 实现i2c设备的读写函数 您还需要实现i2c设备的读写函数,以便用户间程序可以通过文件系统接口与i2c设备通信。以下是一个简单的读函数的示例: static ssize_t my_i2c_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct i2c_client *client = file->private_data; int ret; // 从i2c设备读取数据 ret = i2c_master_recv(client, buf, count); if (ret < 0) { return ret; } return ret; } 对于写函数,您需要使用i2c_master_send函数向i2c设备发送数据。 总的来说,编写i2c驱动程序需要深入了解Linux内核和i2c总线的工作原理。因此,如果您是初学者,建议先学习一些基本的Linux驱动程序编写知识,并在尝试编写i2c驱动程序之前对i2c总线进行更深入的了解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值