您的位置:首页 > 运维架构 > Linux

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

2017-09-15 11:17 471 查看
原文地址: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. } &n
4000
bsp;

可以看大调用了具体的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设备驱动模型已经建立完了。哥儿三个,手挽了手,心连了心。
时刻准备着学习和干活。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: