现在的位置: 首页 > 综合 > 正文

linux内核启动设备探测过程

2013年09月24日 ⁄ 综合 ⁄ 共 3637字 ⁄ 字号 评论关闭

前段时间研究nandflash驱动,很好奇,到底是怎么探测nandflash,以及驱动等等。好吧,现在开始不说了。

首先在板级文件里面必须添加设备信息,

static struct resource s5pv210_nand_resource[] = {
[0] = {
.start = 0xB0E00000,
.end   = 0xB0E00000 + 0x00100000 - 1,
.flags = IORESOURCE_MEM,
}
}; 

struct platform_device s5pv210_device_nand = {
.name     = "s5pv210-nand",
.id       = -1,
.num_resources    = ARRAY_SIZE(s5pv210_nand_resource),
.resource
 = s5pv210_nand_resource,
};

并将s5pv210_device_nand添加到struct platform_device *smdkv210_devices[] ,

在smdkv210_machine_init会调用platform_add_devices(smdkv210_devices, ARRAY_SIZE(smdkv210_devices));

该函数会将所有的设备注册。以后注册相应的driver时会查找对应设备的信息,此时设备早已注册。

先看s5pv210_nand.c文件,这个不是官方内核源码的文件,不过也差不多。

static int __init s3c_nand_init(void)
{
printk("S3C NAND Driver, (c) 2008 Samsung Electronics\n");
return
 platform_driver_register(&s5pc110_nand_driver);
}

在内核初始化后肯定有S3C NAND Driver, (c) 2008 Samsung Electronics 这个信息输出。

这个函数被放在init节,会被调用。进而调用关键的platform_driver_register(&s5pc110_nand_driver);

进入platform_driver_register会调用driver_register(&drv->driver)(相当重要的设备驱动架构的函数)

driver_register->bus_add_driver(struct device_driver *drv),这个就是在/sys/ bus里面添加该driver的信息。

总之一系列的操作,要和内核驱动架构对接。下面来到了重要的地方,

if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}

显然如果drivers_autoprobe为真的话就会自动探测设备。进入driver_attach,该函数很简单调用bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

bus_for_each_dev就是迭代寻找该bus下的设备,进行匹配。用这个函数__driver_attach进行判断。

static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;

/*
* Lock device and try to bind to it. We drop the error
* here and always return 0, because we need to keep trying
* to bind to devices and some drivers will return an error
* simply if it didn't support the device.
*
* driver_probe_device() will spit a warning if there
* is an error.
*/

if (!driver_match_device(drv, dev))
return 0;

if (dev->parent)/* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
if (!dev->driver)
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);

return 0;

}

driver_match_device会调用drv->bus->match(dev, drv),即该总线的match函数,如果成功,并且dev没有绑定,

则会调用driver_probe_device(drv, dev)  --》really_probe(dev, drv);

static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = 0;

atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));

dev->driver = drv;  //将driver和dev真正绑定
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}

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

driver_bound(dev);
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;

probe_failed:
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;

if (ret != -ENODEV && ret != -ENXIO) {
/* driver matched but the probe failed */
printk(KERN_WARNING
      "%s: probe of %s failed with error %d\n",
      drv->name, dev_name(dev), ret);
}
/*
* Ignore errors returned by ->probe so that the next driver can try
* its luck.
*/
ret = 0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}

最后我们来看看设备探测函数是哪个

static struct platform_driver s5pc110_nand_driver = {
        .probe          = s5pc110_nand_probe,
        .remove         = s3c_nand_remove,
        .suspend        = s3c_nand_suspend,
        .resume         = s3c_nand_resume,
        .driver         = {
                .name   = "s5pv210-nand",
                .owner  = THIS_MODULE,
        },
};

即最终会调用s5pc110_nand_probe--->>s3c_nand_probe

在s3c_nand_probe里面,会读取s5pv210_device_nand(板级文件里面定义的)结构信息,该结构包括nand分区信息,访问io的地址等等。

根据这些信息,访问io,获得nand的设备信息

tmp = readb(nand->IO_ADDR_R); /* Maf. ID */
tmp = readb(nand->IO_ADDR_R); /* Device ID */

会进行匹配,成功则,继续进行nand的初始化。这个可以自己去看看该文件。

转自:http://blog.csdn.net/f22jay/article/details/7856598

抱歉!评论已关闭.