LINUX驱动之SPI子系统之六spi_driver的注册和挂载流程

本文深入解析了Linux SPI子系统的驱动模型,包括SPI控制器、设备和驱动三者之间的交互过程。重点介绍了spidev驱动的注册流程及文件操作接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:http://fpcfjf.blog.163.com/blog/static/55469793201292991952106/

歇了个周末,养了下精神,今天接着说上回没说完的事儿。

既然主机控制器,设备都准备好,那么下来,自然是驱动要出场了,而且他不但要出场,还要和另外两个勾搭上,才能一起干活。先看代码:spidev.c中:


1.   static int __init spidev_init(void)  

2.   {  

3.       int status;  

4.       BUILD_BUG_ON(N_SPI_MINORS > 256);  

5.       status = register_chrdev(SPIDEV_MAJOR, “spi”, &spidev_fops);  

6.       if (status < 0)  

7.           return status;  

8.       spidev_class = class_create(THIS_MODULE, “spidev”);  

9.       if (IS_ERR(spidev_class)) {  

10.          unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);  

11.          return PTR_ERR(spidev_class);  

12.      }  

13.      status = spi_register_driver(&spidev_spi);  

14.      if (status < 0) {  

15.          class_destroy(spidev_class);  

16.          unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);  

17.      }  

18.      return status;  

19.  }  


第十三行:spi_register_driver,这个跟前面的spi_register_master,是不是有些眼熟。确实是目的一样。

注册了名为”spi”的字符驱动,然后注册了spidev_spi驱动,这个就是图中sys/Bus/Spi/Drivers/下的spidev。

1.   static struct spi_driver spidev_spi = {  

2.       .driver = {  

3.           .name =     “spidev”,  

4.           .owner =    THIS_MODULE,  

5.       },  

6.       .probe =    spidev_probe,  

7.       .remove =   __devexit_p(spidev_remove),  

8.   };  


1.   static struct spi_driver spidev_spi = {  

2.       .driver = {  

3.           .name =     “spidev”,  


        .owner =    THIS_MODULE,  
    },  
    .probe =    spidev_probe,  
    .remove =   __devexit_p(spidev_remove),  
};  

调用过程不外乎最后到__driver_attach这个函数,其中分别调用了driver_match_device,driver_probe_device函数。这两个函数前面都讲过,不过是主机的,但到这里也是一样的。如果匹配成果调用probe函数,否则返回。

1.   static int __driver_attach(struct device dev, void *data)    

2.   {    

3.       struct device_driver *drv = data;    

4.       if (!driver_match_device(drv, dev))    

5.           return 0;    

6.       

7.       if (dev->parent) / Needed for USB /    

8.           down(&dev->parent->sem);    

9.       down(&dev->sem);    

10.      if (!dev->driver)    

11.          driver_probe_device(drv, dev);    

12.      up(&dev->sem);    

13.      if (dev->parent)    

14.          up(&dev->parent->sem);    

15.      

16.      return 0;    

17.  }    


匹配的时候调用的bus的match函数。

1.   struct bus_type spi_bus_type = {  

2.          .name             = “spi”,  

3.          .dev_attrs       = spi_dev_attrs,  

4.          .match           = spi_match_device,  

5.          .uevent           = spi_uevent,  

6.          .suspend  = spi_suspend,  

7.          .resume          = spi_resume,  

8.   };  

9.   static int spi_match_device(struct device *dev, struct device_driver *drv)  

10.  {  

11.      const struct spi_device *spi = to_spi_device(dev);  

12.    

13.    

14.      return strcmp(spi->modalias, drv->name) == 0;  

15.  }  


可以看到这里根据驱动和设备的名字进行匹配,这里说一下这个spi_buf_type这个变量是在哪里被赋值的,其实和上面的主机注册一样,都是在spi_register_driver(类似这种函数,或者其它的平台类似的函数都如此)这个函数调用一开始的部分就设置了,sdrv->driver.bus = &spi_bus_type;所以说:

1.   static int spi_drv_probe(struct device *dev)  

2.   {  

3.       const struct spi_driver     *sdrv = to_spi_driver(dev->driver);  

4.     

5.     

6.       return sdrv->probe(to_spi_device(dev));  

7.   }  


可以看大调用了具体的probe函数,这里实现了把spidev添加到device_list,这样这个虚拟的字符驱动就注册并初始化完毕。

1.   static int spidev_remove(struct spi_device *spi)  

2.   {  

3.       struct spidev_data  *spidev = spi_get_drvdata(spi);  

4.     

5.     

6.       / make sure ops on existing fds can abort cleanly /  

7.       spin_lock_irq(&spidev->spi_lock);  

8.       spidev->spi = NULL;  

9.       spi_set_drvdata(spi, NULL);  

10.      spin_unlock_irq(&spidev->spi_lock);  

11.    

12.    

13.      / prevent new opens /  

14.      mutex_lock(&device_list_lock);  

15.      list_del(&spidev->device_entry);  

16.      device_destroy(spidev_class, spidev->devt);  

17.      clear_bit(MINOR(spidev->devt), minors);  

18.      if (spidev->users == 0)  

19.          kfree(spidev);  

20.      mutex_unlock(&device_list_lock);  

21.    

22.    

23.      return 0;  

24.  }  


在spidev的注册函数中注册了文件操作集合file_operations,为用户空间提供了操作SPI controller的接口。

1.   static struct file_operations spidev_fops = {  

2.       .owner =    THIS_MODULE,  

3.       / REVISIT switch to aio primitives, so that userspace 

4.         gets more complete API coverage.  It’ll simplify things 

5.         too, except for the locking. 

6.        */  

7.       .write =    spidev_write,  

8.       .read =     spidev_read,  

9.       .unlocked_ioctl = spidev_ioctl,  

10.      .open =     spidev_open,  

11.      .release =  spidev_release,  

12.  };  


到此为止spi子系统与spi_master,spi_device,spi_driver这个Linux设备驱动模型已经建立完了。哥儿三个,手挽了手,心连了心。

时刻准备着学习和干活。

<think>好的,用户现在问的是执行`spi_register_driver`函数是否可以进入probe函数。之前用户已经问过probe函数在驱动加载时的情况,现在更具体地涉及到SPI总线的驱动注册。 首先,我需要回忆一下Linux驱动模型中SPI子系统的结构。SPI驱动属于总线驱动的一种,类似platform、I2C等,它们都有类似的驱动设备匹配机制。当驱动注册到总线时,内核会尝试将已注册的设备与驱动进行匹配,匹配成功后会调用probe函数。 用户可能已经知道`platform_driver_register`会触发probe,但SPI的情况是否相同呢?需要确认`spi_register_driver`的工作机制。根据Linux内核的代码,`spi_register_driver`实际上是对`driver_register`的封装,将驱动注册SPI总线上。当驱动注册后,内核会遍历总线上所有已存在的设备,检查是否与驱动的`id_table`或`of_match_table`匹配,如果匹配则调用probe。 接下来要考虑的是注册驱动时的顺序。如果设备已经存在于SPI总线上(比如通过设备树静态定义或之前已注册),那么注册驱动时会立即触发probe。反之,如果驱动注册,设备后注册,那么设备注册时也会触发probe。这一点platform驱动的情况是一致的。 用户可能存在的疑惑是,是否在调用`spi_register_driver`之后就会立即进入probe,或者需要其他条件。需要明确触发probe的条件是驱动设备匹配成功,而不仅仅是注册驱动。因此,如果此时总线上已有匹配的设备,probe会被调用;如果没有,则不会,直到有设备注册时才会检查。 另外,用户可能在调试时遇到probe没有执行的情况,需要了解可能的原因,比如设备未正确注册、匹配表不正确等。这时候可能需要查看内核日志,检查设备树中的compatible属性是否正确,或者SPI设备是否成功添加到总线。 最后,需要提供一个清晰的回答,解释`spi_register_driver`的作用,触发probe的条件,以及相关的验证方法。同时,结合之前的回答,保持一致性,帮助用户建立完整的知识结构。</think>### **问题解答** 是的,调用`spi_register_driver()`函数注册SPI驱动时,**如果系统中已存在与该驱动匹配的SPI设备**,则会触发`probe`函数的执行。其核心逻辑与平台设备驱动(`platform_driver`)类似,但具体实现依赖**SPI总线设备匹配机制**。 --- #### **1. `spi_register_driver()`的作用** - **功能**:将SPI驱动注册到内核的SPI总线(`spi_bus_type`)上,使驱动SPI设备能够匹配。 - **关键行为**: - 驱动注册后,内核会遍历SPI总线上所有已注册的设备(`spi_device`)。 - 若设备与驱动的匹配条件满足(如设备名匹配或设备树`compatible`匹配),则调用驱动的`probe`函数。 --- #### **2. 触发`probe`的条件** - **条件1:设备已注册SPI总线** 若设备通过以下方式已存在: - 设备树(Device Tree)中定义的SPI设备节点(需`status = "okay"`)。 - 动态注册SPI设备(如通过`spi_new_device()`)。 则驱动注册时会立即触发匹配`probe`。 - **条件2:设备与驱动匹配成功** - **匹配规则**: 1. **设备树匹配**:设备树中设备的`compatible`属性与驱动定义的`of_match_table`匹配。 2. **ID表匹配**:设备的`modalias`与驱动`id_table`中的条目匹配(传统非设备树方式)。 --- #### **3. 典型流程示例** 以**设备树中定义的SPI设备**为例: ```text 驱动加载(insmod) └── 调用module_init └── spi_register_driver() └── 内核遍历SPI总线上的设备 └── 匹配设备树节点compatible与驱动的of_match_table └── 匹配成功 → 调用probe() └── 匹配失败 → 无操作 ``` --- #### **4. 关键代码验证** - **驱动注册代码示例** ```c // 定义驱动的of_match_table(设备树匹配) static const struct of_device_id my_spi_driver_of_match[] = { { .compatible = "myvendor,spi-device" }, // 必须与设备树的compatible一致 {} }; // 定义驱动的id_table(传统ID匹配) static const struct spi_device_id my_spi_driver_id_table[] = { { "spi-device-id", 0 }, // 需与spi_device的modalias一致 {} }; static struct spi_driver my_spi_driver = { .driver = { .name = "my_spi_driver", .of_match_table = my_spi_driver_of_match, .owner = THIS_MODULE, }, .id_table = my_spi_driver_id_table, // 非设备树匹配时使用 .probe = my_spi_probe, // probe函数入口 .remove = my_spi_remove, }; // 驱动注册入口 static int __init my_spi_driver_init(void) { return spi_register_driver(&my_spi_driver); // 注册驱动SPI总线 } module_init(my_spi_driver_init); ``` - **设备树节点定义** ```dts &spi0 { status = "okay"; my_spi_device@0 { compatible = "myvendor,spi-device"; // 与驱动的of_match_table匹配 reg = <0>; // SPI片选号 spi-max-frequency = <1000000>; }; }; ``` --- #### **5. 调试与验证方法** - **场景1:`probe`未执行** - **可能原因**: 1. 设备树中`compatible`与驱动不匹配。 2. SPI设备未正确注册(检查设备树节点状态是否为`okay`)。 3. SPI控制器(如`spi0`)未启用或初始化失败。 - **调试命令**: ```bash dmesg | grep -i "spi" # 查看SPI控制器设备注册日志 dmesg | grep -i "probe" # 检查probe是否被调用 ls /sys/bus/spi/devices/ # 确认SPI设备已注册 ls /sys/bus/spi/drivers/ # 确认驱动注册 ``` - **场景2:`probe`被多次调用** - **可能原因**: 同一驱动匹配了多个SPI设备(如多个相同设备挂载在同一SPI总线上)。 - **解决方法**: 在`probe`函数中通过`spi_device`参数区分不同设备实例(如片选号`reg`属性)。 --- #### **6. 总结** - **`spi_register_driver()`是否会触发`probe`?** **是**,但需满足以下条件: 1. 驱动与设备匹配成功(设备树或ID表匹配)。 2. 设备已注册SPI总线。 - **关键检查点**: - 设备树`compatible`与驱动`of_match_table`的一致性。 - SPI控制器设备的使能状态(`status = "okay"`)。 - 内核日志中SPI设备驱动注册记录。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值