linux内核启动设备探测过程

前段时间研究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");returnplatform_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

获致幸福的不二法门是珍视你所拥有的遗忘你所没有的

linux内核启动设备探测过程

相关文章:

你感兴趣的文章:

标签云: