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;
}
不要輕易放棄你的理想和追求。
向著夢中的地方去,錯了我也不悔過。