今天看了下mmc/sd/sdio模块的代码,做下笔记,便于以后翻看。
有3个文件夹:
linux-2.6/drivers/mmc$ ls
card core host Kconfig Makefile
card--是支持sdcard用的
core--是支持sd总线协议的
host--是各种CPU的sd-host模块
sd模块开始是在/core/core.c 中的 mmc_init(), 如下:
static int __init mmc_init(void)
2204 {
2205 int ret;
2206
2207 wake_lock_init(&mmc_delayed_work_wake_lock, WAKE_LOCK_SUSPEND, "mmc_delayed_work");
2208
2209 workqueue = create_singlethread_workqueue("kmmcd");//创建单线程的工作队列
2210 if (!workqueue)
2211 return -ENOMEM;
2212
2213 ret = mmc_register_bus(); //调用到 bus.c 中去
2214 if (ret)
2215 goto destroy_workqueue;
2216
2217 ret = mmc_register_host_class(); //调用到 host.c 中去
2218 if (ret)
2219 goto unregister_bus;
2220
2221 ret = sdio_register_bus(); //调用到 sdio_bus.c 中去
2222 if (ret)
2223 goto unregister_host_class;
2224
2225 return 0;
2226
2227 unregister_host_class:
2228 mmc_unregister_host_class();
2229 unregister_bus:
2230 mmc_unregister_bus();
2231 destroy_workqueue:
2232 destroy_workqueue(workqueue);
2233
2234 return ret;
2235 }
2236
2237 static void __exit mmc_exit(void)
2238 {
2239 sdio_unregister_bus();
2240 mmc_unregister_host_class();
2241 mmc_unregister_bus();
2242 destroy_workqueue(workqueue);
2243 wake_lock_destroy(&mmc_delayed_work_wake_lock);
2244 }
2245
2246 subsys_initcall(mmc_init);
2247 module_exit(mmc_exit);
2248
2249 MODULE_LICENSE("GPL");
mmc_register_bus(); //注册总线,调用到 bus.c 中去
int mmc_register_bus(void)
{
return bus_register(&mmc_bus_type);
}
static struct bus_type mmc_bus_type = {
.name = "mmc",
.dev_attrs = mmc_dev_attrs,
.match = mmc_bus_match,
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
.remove = mmc_bus_remove,
.suspend = mmc_bus_suspend,
.resume = mmc_bus_resume,
.pm = MMC_PM_OPS_PTR,
};
这个数组mmc_bus_type里,包含了很多函数了,都是处理总线mmc_bus的.这里,我们主要关注mmc_bus_match与mmc_bus_probe,此两函数将要在device_register和driver_register向总线注册设备的时候被调用。
/*
* This currently matches any MMC driver to any MMC card - drivers
* themselves make the decision whether to drive this card in their
* probe method.
*/
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
return 1; //目前匹配所有的MMC卡。
}
static int mmc_bus_probe(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
return drv->probe(card);
}
在使用bus_register之后,我们可以在sysfs的/sys/bus目录里看到它。
总线注册完成后,接着是(); //调用到 host.c 中去
int mmc_register_host_class(void)
{
return class_register(&mmc_host_class);
}
mmc_register_host_classclass_register之后,在
/sys
/class目录下将出现mmc_host目录。
static struct class mmc_host_class = { .name = "mmc_host", .dev_release = mmc_host_classdev_release, };
static void mmc_host_classdev_release(struct device *dev) { struct mmc_host *host = cls_dev_to_mmc_host(dev); kfree(host); }
完成host_class 注册后,就轮到 sdio_bus 注册了。sdio_register_bus(); //调用到 sdio_bus.c 中去#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
int sdio_register_bus(void) { return bus_register(&sdio_bus_type); }
-----------------------------------------------------------------------static struct bus_type sdio_bus_type = { .name = "sdio", .dev_attrs = sdio_dev_attrs, .match = sdio_bus_match, .uevent = sdio_bus_uevent, .probe = sdio_bus_probe, .remove = sdio_bus_remove, .pm = SDIO_PM_OPS_PTR, };
这样,core.c , bus.c , host.c , sdio_bus.c 的内容就大概了解了。
driver/mmc/card/block.c
static int __init mmc_blk_init(void)
{
int res;
if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
pr_info("mmcblk: using %d minors per device\n", perdev_minors);
max_devices = 256 / perdev_minors;
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); //注册一个块设备,
if (res)
goto out;
res = mmc_register_driver(&mmc_driver);
if (res)
goto out2;
return 0;
out2:
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
out:
return res;
}
static void __exit mmc_blk_exit(void)
{
mmc_unregister_driver(&mmc_driver);
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
}
module_init(mmc_blk_init);
module_exit(mmc_blk_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
在mmc_blk_init中, register_blkdev(major, "mmc")的作用是注册一个块设备。
register_blkdev的功能比较少,一是动态分配设备号,二是在/proc/devices中创建一个入口项 。故通过它之后,系统还是不能使用块设备的。
接着我们看mmc_register_driver(&mmc_driver); 在/driver/mmc/core/bus.c中。
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmcblk",
},
.probe = mmc_blk_probe,
.remove = mmc_blk_remove,
.suspend = mmc_blk_suspend,
.resume = mmc_blk_resume,
};
/**
* mmc_register_driver - register a media driver
* @drv: MMC media driver
*/
int mmc_register_driver(struct mmc_driver *drv)
{
drv->drv.bus = &mmc_bus_type;
return driver_register(&drv->drv);
}
EXPORT_SYMBOL(mmc_register_driver);
这两句代码比较好理解吧。在注册一个struct driver之前,都要先设置它的bus,类似的,在platform_driver_register中我们也可所以看到:
drv->driver.bus=&platform_bus_type
driver_register将到相应总线mmc_bus_type上去搜索相应设备。找到设备后就设置dev->driver=drv,并调用mmc_bus_type总线的probe函数被调用,即mmmc_bus_probe函数.
我们跟踪driver_register(&drv->drv),它会调应bus_add_driver。
/**
* 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)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
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);
other = driver_find(drv->name, drv->bus);
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
EXPORT_SYMBOL_GPL(driver_register);
bus_add_driver --- add a driver to the bus.
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
*/
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->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",
__func__, 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",
__func__, drv->name);
}
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}
kobject_uevent(&priv->kobj, KOBJ_ADD);
return 0;
out_unregister:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}
在调用kobject_register之后,我们可以在/sys/bus/mmc/driver目录下看到mmcblk文件driver_attach函数会遍历相应总线(mmc_bus_type)上的dev,对这些dev执行总线的match函数(mmc_bus_match)。如果match成功,它会调用mmc_bus_type总线的probe函数mmc_bus_probe(如果总线的probe存在的话).我们在以上走过的流程中可以看到,我们并没有向总线添加任何设备,故mmc_bus_probe是不会调用的。但相应的driver已经注册到系统了。