1. 程式人生 > >LINUX驅動之SPI子系統之三基本的呼叫流程

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;

}

不要輕易放棄你的理想和追求。

向著夢中的地方去,錯了我也不悔過。