原文地址:http://fpcfjf.blog.163.com/blog/static/5546979320129249420884/
这里有一处说明,因为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;
}
不要轻易放弃你的理想和追求。
向着梦中的地方去,错了我也不悔过。