注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

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

2012-10-29 21:19:52|  分类: LINUX内核驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

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

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

既然主机控制器,设备都准备好,那么下来,自然是驱动要出场了,而且他不但要出场,还要和另外两个勾搭上,才能一起干活。先看代码: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设备驱动模型已经建立完了。哥儿三个,手挽了手,心连了心。

时刻准备着学习和干活。

  评论这张
 
阅读(4214)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017