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

原文地址: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设备驱动模型已经建立完了。哥儿三个,手挽了手,心连了心。

时刻准备着学习和干活。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值