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

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

LINUX驱动之SPI子系统之三基本的调用流程  

2012-10-24 21:04:20|  分类: LINUX内核驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

LINUX驱动之SPI子系统之三基本的调用流程

这里有一处说明,因为SPI用的是spi_device这个设备结构,其中与platform_device不同的是没有.resource这个成员,所以就不用再考虑它了。它通过在s3c24xx_spi_probe函数里:

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);来实现资源的生成。

SPI的基本调用流程与平台设备没有什么实质性的差异。主要如下(从spi_s3c24xx.c中开始):

1、static int __init s3c24xx_spi_init(void)这个函数中,调用:

int __init_or_module platform_driver_probe(struct platform_driver *drv,

                   int (*probe)(struct platform_device *))

{

        return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);

}

2、在platform_driver_probe调用:

int platform_driver_register(struct platform_driver *drv)

3、再调用:

int driver_register(struct device_driver *drv)

4、再调用:

int bus_add_driver(struct device_driver *drv)

5、再调用:

int driver_attach(struct device_driver *drv)

{

         return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

}

这里需要注意,bus_for_each_dev这个函数中调用的函数指针fn是__driver_attch,所以可以略过这个函数直接看匹配。

6、__driver_attch调用:

static inline int driver_match_device(struct device_driver *drv,

                                           struct device *dev)

{

         return drv->bus->match ? drv->bus->match(dev, drv) : 1;

}

大家都知道,在SPI.C中(前边也讲到了):


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.   };   


所以这里调用的是spi_match_device,跳过去:

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

{

         const struct spi_device   *spi = to_spi_device(dev);

         const struct spi_driver    *sdrv = to_spi_driver(drv);

 

         if (sdrv->id_table)

                   return !!spi_match_id(sdrv->id_table, spi);

 

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

}

比较名字罢了。

7、再调用int driver_probe_device(struct device_driver *drv, struct device *dev),然后再调用:

static int really_probe(struct device *dev, struct device_driver *drv)

8、在really_probe函数中,又回到了MTD子系统分析中:

         if (dev->bus->probe) {

                   ret = dev->bus->probe(dev);

                   if (ret)

                            goto probe_failed;

         } else if (drv->probe) {

                   ret = drv->probe(dev);

                   if (ret)

                            goto probe_failed;

         }

因为在BUS中并没有给 probe赋值,所以会直接调用驱动的probe,也就是最前面的:

s3c24xx_spi_probe这个探测函数。

上文说过,SPI是专门独立出来了一个子系统(如果不使用GPIO模拟的平台的话),所以他的平台初台化是专门在spi.c中用下面这个函数进行的,和在一般的 platform驱动还是稍微有一些区别的。大家要引起注意。(而平台总线因为是通用的,所以在platform.c中调用int __init platform_bus_init(void)函数来实现。)

static int __init spi_init(void)

{

         int    status;

 

         buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);

         if (!buf) {

                   status = -ENOMEM;

                   goto err0;

         }

    //注册总线

         status = bus_register(&spi_bus_type);//注意:platform_bus_init同样也调用这个函数来实现总线的注册

         if (status < 0)

                   goto err1;

   //注册主设备的class

         status = class_register(&spi_master_class);

         if (status < 0)

                   goto err2;

         return 0;

 

err2:

         bus_unregister(&spi_bus_type);

err1:

         kfree(buf);

         buf = NULL;

err0:

         return status;

}

不要轻易放弃你的理想和追求。

向着梦中的地方去,错了我也不悔过。

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

历史上的今天

在LOFTER的更多文章

评论

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

页脚

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