刚开始接触linux设备驱动程序的时候,我充满着各种疑惑,比如:
(1)在linux-2.6.24/drivers/rtc目录下已经存在了RTC芯片DS1307的驱动程序(rtc-ds1307.c)了,又由于在项目里面要用到DS1307,于是乎,我的问题就来了:内核里面已经有了,那我还要自己写吗?但是初步看了一下DS1307的驱动,貌似不是自己想要要的,于是各种困惑与纠结,到底要不要自己另外写?
(2)platform平台设备驱动又是什么东西?LDD3上貌似没有说过啊?他是字符型设备还是其他什么的?
等等。反正,那个纠结啊!
至今,仍然存在各种困惑。希望有朋友帮我解除这个困惑。
好了,废话少说,来分析一下platform驱动吧!
首先,看hinand.c的源代码,这里只挑重点给予解释:
点击(此处)折叠或打开
- /*
- * Main initialization routine
- */
- static int hinand_module_init(void)
- {
- int retval;
- // printk("hinand_module_init\n");
- retval = driver_register (&hinand_driver);
- if (retval < 0)
- {
- return retval;
- }
- retval = platform_device_register (&hinand_pdev);
- if (retval < 0)
- {
- driver_unregister(&hinand_driver);
- return retval;
- }
- return retval;
- }
- static void __exit hinand_module_exit (void)
- {
- driver_unregister (&hinand_driver);
- platform_device_unregister (&hinand_pdev);
- }
- module_init(hinand_module_init);
- module_exit(hinand_module_exit);
这个驱动里面的入口函数是hinand_module_init,这个大家都可以看出来,看上去还蛮简单的,就调用了2个主要的函数:
retval = driver_register (&hinand_driver);
retval = platform_device_register (&hinand_pdev);
第一个函数里面主要牵扯了hinand_driver这个结构体,这个结构体定义如下:
第一个函数里面主要牵扯了hinand_driver这个结构体,这个结构体定义如下:
点击(此处)折叠或打开
- static struct device_driver hinand_driver =
- {
- .name = "hinand",
- .bus = &platform_bus_type,
- .probe = hinand_probe,
- .remove = hinand_remove,
- };
点击(此处)折叠或打开
- struct device_driver {
- const char * name;
- struct bus_type * bus;
- struct kobject kobj;
- struct klist klist_devices;
- struct klist_node knode_bus;
- struct module * owner;
- const char * mod_name; /* used for built-in modules */
- struct module_kobject * mkobj;
- int (*probe) (struct device * dev);
- int (*remove) (struct device * dev);
- void (*shutdown) (struct device * dev);
- int (*suspend) (struct device * dev, pm_message_t state);
- int (*resume) (struct device * dev);
- };
结合上面两段代码,可以看出来hinand_driver只对其中的四个元素赋值了,即:
name -----> 驱动的名字,很重要。
bus -----> 驱动所挂载的总线的名字,注意这里的挂载只是表示一个依附的意思,并不是实际中的连到这个总线上了,实际中也不存在一条总线叫什么platform。
probe ----> 驱动函数的真正的入口
remove ---> 驱动函数的出口
其余的元素有的是要在后面的程序里面进行初始化,不过这里不影响我们的讨论。
那driver_register (&hinand_driver);(linux-2.6.24/drivers/base/driver.c)这个函数到底做了哪些事情呢?下面就要看他的定义了:
点击(此处)折叠或打开
- /**
- * driver_register - register driver with bus
- * @drv: driver to register
- *
- * We pass off most of the work to the bus_add_driver() call,
- * since most of the things we have to do deal with the bus
- * structures.
- */
- int driver_register(struct device_driver * drv)
- {
- if ((drv->bus->probe && drv->probe) ||
- (drv->bus->remove && drv->remove) ||
- (drv->bus->shutdown && drv->shutdown)) {
- printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
- }
- klist_init(&drv->klist_devices, NULL, NULL);
- return bus_add_driver(drv);
- }
这个函数就是把驱动注册到对应的总线上面去,当然,这个总线必须是已经存在了的,那platform这条总线已经存在了吗?答案显然是存在了的。于是乎,又来疑问了,这条总线是什么时候开始就存在了?或者说是什么时候注册到了系统中了呢?话说那还是盘古开天辟地的时候,呵呵!开个玩笑。至于platform总线是什么时候注册到系统里就要看linux启动的过程代码了。
start_kernel(void);(linux-2.6.24/init/main.c)
|
|
rest_init();(linux-2.6.24/init/main.c)
|
|
kernel_init();(linux-2.6.24/init/main.c)
|
|
do_basic_setup();(linux-2.6.24/init/main.c)
|
|
driver_init();(linux-2.6.24/drivers/base/init.c)
|
|
platform_bus_init()(linux-2.6.24/drivers/base/platform.c);
这个过程就是注册platform总线的过程。
再看driver_register()这个函数里面,主要就是调用了bus_add_driver()(linux-2.6.24/drivers/base/bus.c),看他的定义:
点击(此处)折叠或打开
- int bus_add_driver(struct device_driver *drv)
- {
- struct bus_type * bus = bus_get(drv->bus);
- int error = 0;
- if (!bus)
- return -EINVAL;
- pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
- error = kobject_set_name(&drv->kobj, "%s", drv->name);
- if (error)
- goto out_put_bus;
- drv->kobj.kset = &bus->drivers;
- error = kobject_register(&drv->kobj);
- if (error)
- goto out_put_bus;
- if (drv->bus->drivers_autoprobe) {
- error = driver_attach(drv);
- if (error)
- goto out_unregister;
- }
- klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
- module_add_driver(drv->owner, drv);
- error = driver_create_file(drv, &driver_attr_uevent);
- if (error) {
- printk(KERN_ERR "%s: uevent attr (%s) failed\n",
- __FUNCTION__, drv->name);
- }
- error = driver_add_attrs(bus, drv);
- if (error) {
- /* How the hell do we get out of this pickle? Give up */
- printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
- __FUNCTION__, drv->name);
- }
- error = add_bind_files(drv);
- if (error) {
- /* Ditto */
- printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
- __FUNCTION__, drv->name);
- }
- return error;
- out_unregister:
- kobject_unregister(&drv->kobj);
- out_put_bus:
- bus_put(bus);
- return error;
- }
挑重点看,这个函数主要就是这句话:
if (drv->bus->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
drv->bus->drivers_autoprobe如果为真就调用driver_attach()这个函数,这里我也不知道是不是为真,当然为真了,因为注册platform_bus_type总线的时候是这样的:
error = driver_attach(drv);
if (error)
goto out_unregister;
}
drv->bus->drivers_autoprobe如果为真就调用driver_attach()这个函数,这里我也不知道是不是为真,当然为真了,因为注册platform_bus_type总线的时候是这样的:
点击(此处)折叠或打开
- int __init platform_bus_init(void)
- {
- int error;
- error = device_register(&platform_bus);
- if (error)
- return error;
- error = bus_register(&platform_bus_type);
- if (error)
- device_unregister(&platform_bus);
- return error;
- }
上面代码中bus_register(&platform_bus_type);注册过程,但是再看platform_bus_type的定义:
点击(此处)折叠或打开
- struct bus_type platform_bus_type = {
- .name = "platform",
- .dev_attrs = platform_dev_attrs,
- .match = platform_match,
- .uevent = platform_uevent,
- .suspend = platform_suspend,
- .suspend_late = platform_suspend_late,
- .resume_early = platform_resume_early,
- .resume = platform_resume,
- };
再看struct bus_tpye的定义:
点击(此处)折叠或打开
- struct bus_type {
- const char * name;
- struct module * owner;
- struct kset subsys;
- struct kset drivers;
- struct kset devices;
- struct klist klist_devices;
- struct klist klist_drivers;
- struct blocking_notifier_head bus_notifier;
- struct bus_attribute * bus_attrs;
- struct device_attribute * dev_attrs;
- struct driver_attribute * drv_attrs;
- int (*match)(struct device * dev, struct device_driver * drv);
- int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
- int (*probe)(struct device * dev);
- int (*remove)(struct device * dev);
- void (*shutdown)(struct device * dev);
- int (*suspend)(struct device * dev, pm_message_t state);
- int (*suspend_late)(struct device * dev, pm_message_t state);
- int (*resume_early)(struct device * dev);
- int (*resume)(struct device * dev);
- unsigned int drivers_autoprobe:1;
- };
最后一行unsigned int drivers_autoprobe:1;
再看bus_register()这个函数:
点击(此处)折叠或打开
- int bus_register(struct bus_type * bus)
- {
- int retval;
- BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);
- retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name);
- if (retval)
- goto out;
- bus->subsys.kobj.kset = &bus_subsys;
- retval = subsystem_register(&bus->subsys);
- if (retval)
- goto out;
- retval = bus_create_file(bus, &bus_attr_uevent);
- if (retval)
- goto bus_uevent_fail;
- kobject_set_name(&bus->devices.kobj, "devices");
- bus->devices.kobj.parent = &bus->subsys.kobj;
- retval = kset_register(&bus->devices);
- if (retval)
- goto bus_devices_fail;
- kobject_set_name(&bus->drivers.kobj, "drivers");
- bus->drivers.kobj.parent = &bus->subsys.kobj;
- bus->drivers.ktype = &driver_ktype;
- retval = kset_register(&bus->drivers);
- if (retval)
- goto bus_drivers_fail;
- klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
- klist_init(&bus->klist_drivers, NULL, NULL);
- bus->drivers_autoprobe = 1;
- retval = add_probe_files(bus);
- if (retval)
- goto bus_probe_files_fail;
- retval = bus_add_attrs(bus);
- if (retval)
- goto bus_attrs_fail;
- pr_debug("bus type '%s' registered\n", bus->name);
- return 0;
- bus_attrs_fail:
- remove_probe_files(bus);
- bus_probe_files_fail:
- kset_unregister(&bus->drivers);
- bus_drivers_fail:
- kset_unregister(&bus->devices);
- bus_devices_fail:
- bus_remove_file(bus, &bus_attr_uevent);
- bus_uevent_fail:
- subsystem_unregister(&bus->subsys);
- out:
- return retval;
- }
这么一句话 bus->drivers_autoprobe = 1;
对drivers_autoprobe初始化为1了,所以还是会调用driver_attach()这个函数的。
再看这个函数的定义:
再看这个函数的定义:
点击(此处)折叠或打开
- /**
- * driver_attach - try to bind driver to devices.
- * @drv: driver.
- *
- * Walk the list of devices that the bus has on it and try to
- * match the driver with each one. If driver_probe_device()
- * returns 0 and the @dev->driver is set, we've found a
- * compatible pair.
- */
- int driver_attach(struct device_driver * drv)
- {
- return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
- }
看英文解释貌似是说将这条总线上的所有设备和这个驱动配对,当然有一定的配对条件,不能不管三七二十一胡乱配对,这是不行的。这里主要调用了bus_for_each_dev这个函数还有__driver_attach这个函数,先看bus_for_each_dev:
点击(此处)折叠或打开
- /**
- * bus_for_each_dev - device iterator.
- * @bus: bus type.
- * @start: device to start iterating from.
- * @data: data for the callback.
- * @fn: function to be called for each device.
- *
- * Iterate over @bus's list of devices, and call @fn for each,
- * passing it @data. If @start is not NULL, we use that device to
- * begin iterating from.
- *
- * We check the return of @fn each time. If it returns anything
- * other than 0, we break out and return that value.
- *
- * NOTE: The device that returns a non-zero value is not retained
- * in any way, nor is its refcount incremented. If the caller needs
- * to retain this data, it should do, and increment the reference
- * count in the supplied callback.
- */
- int bus_for_each_dev(struct bus_type * bus, struct device * start,
- void * data, int (*fn)(struct device *, void *))
- {
- struct klist_iter i;
- struct device * dev;
- int error = 0;
- if (!bus)
- return -EINVAL;
- klist_iter_init_node(&bus->klist_devices, &i,
- (start ? &start->knode_bus : NULL));
- while ((dev = next_device(&i)) && !error)
- error = fn(dev, data);
- klist_iter_exit(&i);
- return error;
- }
最主要的还是其中的fn(dev,data);其实从上面可以看出来这个就是__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 (dev->parent) /* Needed for USB */
- down(&dev->parent->sem);
- down(&dev->sem);
- if (!dev->driver)
- driver_probe_device(drv, dev);
- up(&dev->sem);
- if (dev->parent)
- up(&dev->parent->sem);
- return 0;
- }
主要就是调用driver_probe_device(drv, dev);那么再看这个函数的定义,怎么写着写着觉得自己好烦啊!
点击(此处)折叠或打开
- /**
- * driver_probe_device - attempt to bind device & driver together
- * @drv: driver to bind a device to
- * @dev: device to try to bind to the driver
- *
- * First, we call the bus's match function, if one present, which should
- * compare the device IDs the driver supports with the device IDs of the
- * device. Note we don't do this ourselves because we don't know the
- * format of the ID structures, nor what is to be considered a match and
- * what is not.
- *
- * This function returns 1 if a match is found, -ENODEV if the device is
- * not registered, and 0 otherwise.
- *
- * This function must be called with @dev->sem held. When called for a
- * USB interface, @dev->parent->sem must be held as well.
- */
- int driver_probe_device(struct device_driver * drv, struct device * dev)
- {
- int ret = 0;
- if (!device_is_registered(dev))
- return -ENODEV;
- if (drv->bus->match && !drv->bus->match(dev, drv))
- goto done;
- pr_debug("%s: Matched Device %s with Driver %s\n",
- drv->bus->name, dev->bus_id, drv->name);
- ret = really_probe(dev, drv);
- done:
- return ret;
- }
主要就是really_probe()这个函数,注意上面
if (drv->bus->match && !drv->bus->match(dev, drv))
goto done;
goto done;
这句话,就是调用platform_bus_type里面的match,也就是platform_match,看这个match到底干嘛了:
点击(此处)折叠或打开
- /**
- * platform_match - bind platform device to platform driver.
- * @dev: device.
- * @drv: driver.
- *
- * Platform device IDs are assumed to be encoded like this:
- * "
, where <name> is a short description of the" - * type of device, like "pci" or "floppy", and <instance> is the
- * enumerated instance of the device, like '0' or '42'.
- * Driver IDs are simply "
" . - * So, extract the <name> from the platform_device structure,
- * and compare it against the name of the driver. Return whether
- * they match or not.
- */
- static int platform_match(struct device * dev, struct device_driver * drv)
- {
- struct platform_device *pdev = container_of(dev, struct platform_device, dev);
- return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
- }
再看really_probe()这个函数的定义,我靠,突然发现自己用了n多个“再看”了。妈的,语文太差,不知道还有什么词可以替换一下。
点击(此处)折叠或打开
- static int really_probe(struct device *dev, struct device_driver *drv)
- {
- int ret = 0;
- atomic_inc(&probe_count);
- pr_debug("%s: Probing driver %s with device %s\n",
- drv->bus->name, drv->name, dev->bus_id);
- WARN_ON(!list_empty(&dev->devres_head));
- dev->driver = drv;
- if (driver_sysfs_add(dev)) {
- printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
- __FUNCTION__, dev->bus_id);
- 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("%s: Bound Device %s to Driver %s\n",
- drv->bus->name, dev->bus_id, 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->bus_id, 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;
- }
主要还是看这几句话:
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;
}
根据上面的分析,platform_bus_type总线里面的probe函数是空的,所以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;
}
根据上面的分析,platform_bus_type总线里面的probe函数是空的,所以dev->bus->probe为假,所以执行
drv->probe(dev);
这个probe函数你知道是什么吗?正是hinand_probe,就是hinand_driver里面的probe啊!我操,现在才看出来,也明白了那句“驱动的真正入口是probe函数”这句不知道是哪个家伙说的话,于是乎。。。接下来就没什么好分析的了,说是分析其实也是照搬源代码而已。
这个probe函数你知道是什么吗?正是hinand_probe,就是hinand_driver里面的probe啊!我操,现在才看出来,也明白了那句“驱动的真正入口是probe函数”这句不知道是哪个家伙说的话,于是乎。。。接下来就没什么好分析的了,说是分析其实也是照搬源代码而已。
至于platform_device_register (&hinand_pdev);这句话的分析过程和上面差不多,感兴趣的可以自己分析一下,这里就不说了。。。最后附上一张图: