davinci sd卡驱动学习笔记(二)

简介:

接下来,我们看mmc_block.c,还是从初始化函数mmc_blk_init开始分析:

 

static int __init mmc_blk_init(void)

{

       int res = -ENOMEM;

       res = register_blkdev(major, "mmc");

       if (res < 0) {

              printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n",

                     major, res);

              goto out;

       }

       if (major == 0)

              major = res;

 

       return mmc_register_driver(&mmc_driver);

 

 out:

       return res;

}

mmc_blk_init, register_blkdev(major, "mmc")的作用是注册一个块设备。如果传递的major0,这内核将分派一个新的主设备号给设备。
    register_blkdev
的功能比较少,一是动态分配设备号,二是在/proc/devices中创建一个入口项 。故通过它之后,系统还是不能使用块设备的。
 
接着我们看 
    return mmc_register_driver(&mmc_driver);
 mmc_register_driver
mmc_sysfs.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); //mmc_bus总线上面注册驱动

}

 

这两句代码比较好理解吧。在注册一个struct driver之前,都要先设置它的bus,这个bus正是我们刚才core里面注册的那个mmc_bus_type类似的,在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.

 *

 *     The one interesting aspect is that we setup @drv->unloaded

 *     as a completion that gets complete when the driver reference

 *     count reaches 0.

 */

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, klist_devices_get, klist_devices_put);

       init_completion(&drv->unloaded);

       return bus_add_driver(drv);

}

/**

 *     bus_add_driver - Add a driver to the bus.

 *     @drv:     driver.

 *

 */

int bus_add_driver(struct device_driver * drv)

{

struct bus_type * bus = get_bus(drv->bus);

int error = 0;

 

if (bus) {

        pr_debug("bus %s: add driver %s\n", bus->name, drv->name);

        error = kobject_set_name(&drv->kobj, "%s", drv->name);

        if (error) {

               put_bus(bus);

               return error;

        }

       drv->kobj.kset = &bus->drivers;

        if ((error = kobject_register(&drv->kobj))) {

               put_bus(bus);

               return error;

        }

 

        driver_attach(drv);

        klist_add_tail(&drv->knode_bus, &bus->klist_drivers);

        module_add_driver(drv->owner, drv);

 

        driver_add_attrs(bus, drv);

        add_bind_files(drv);

}

return error;

}

 

/**

 *     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.

 */

void driver_attach(struct device_driver * drv)

{

       bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

}

 

/**

 *     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)//从总线上面找到每一个device,然后调用

      //回调函数fn,现在去看看回调函数

        error = fn(dev, data);

klist_iter_exit(&i);

return error;

}

 

回调函数如下:

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);//dev是刚从bus中取出的device

up(&dev->sem);

if (dev->parent)

        up(&dev->parent->sem);

 

return 0;

}

 

/**

 *     driver_probe_device - attempt to bind device & driver.

 *     @drv:     driver.

 *     @dev:     device.

 *

 *     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, an error if one

 *     occurs (that is not -ENODEV or -ENXIO), 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;

     //drv是我们当前插入的驱动数据

if (drv->bus->match && !drv->bus->match(dev, drv))//判断我们的bus中是否有match函数,并调用它

        goto Done;

 

pr_debug("%s: Matched Device %s with Driver %s\n",

         drv->bus->name, dev->bus_id, drv->name);

dev->driver = drv;  

if (dev->bus->probe) {

       ret = dev->bus->probe(dev);

        if (ret) {

               dev->driver = NULL;

               goto ProbeFailed;

        }

} else if (drv->probe) {

       ret = drv->probe(dev);

        if (ret) {

               dev->driver = NULL;

               goto ProbeFailed;

        }

}

device_bind_driver(dev); //如果匹配成功,驱动就加载好 了,但是我们现在还没有插入sd卡,干函数不会执行;

ret = 1;

pr_debug("%s: Bound Device %s to Driver %s\n",

         drv->bus->name, dev->bus_id, drv->name);

goto Done;

 

 ProbeFailed:

if (ret == -ENODEV || ret == -ENXIO) {

        /* Driver matched, but didn't support device

         * or device not found.

         * Not an error; keep going.

         */

        ret = 0;

} else {

        /* driver matched but the probe failed */

        printk(KERN_WARNING

               "%s: probe of %s failed with error %d\n",

               drv->name, dev->bus_id, ret);

}

 Done:

return ret;

}

 

在调用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已经注册到系统了。

执行玩block模块在drivers目录你将看到:

# insmod mmc_block.ko

# ls /sys/bus/mmc/drivers/

mmcblk

#

 



本文转自 曾永刚 51CTO博客,原文链接:http://blog.51cto.com/zyg0227/565382

相关文章
|
7月前
|
Linux 编译器 C语言
LVGL V8.2 嵌入式Linux平台使用tslib实现输入接口(以SSD212为例)
LVGL V8.2 嵌入式Linux平台使用tslib实现输入接口(以SSD212为例)
209 0
|
11月前
|
编解码 Linux 芯片
linux LCD 驱动框架分析
linux LCD 驱动框架分析
169 0
|
存储 异构计算 内存技术
|
异构计算 Windows
VHDL串口通信 在FPGA开发板上测试 并解决没有识别到下载接口USB_Blaster(No Hardware问题)
今天在调试 VHDL 串口通信,当使用 Quartus II 13.0 综合好的文件下载到 FPGA 开发板时发现,没有识别到下载USB_Blaster
470 0
VHDL串口通信 在FPGA开发板上测试 并解决没有识别到下载接口USB_Blaster(No Hardware问题)
|
存储 Linux 芯片
如何编写linux下nand flash驱动-3
【读(read)操作过程详解】 以最简单的read操作为例,解释如何理解时序图,以及将时序图 中的要求,转化为代码。   解释时序图之前,让我们先要搞清楚,我们要做的事情:那就是,要从nand flash的某个页里面,读取我们要的数据。
1016 0
|
存储 Linux 芯片
如何编写linux下nand flash驱动-1
1.       硬件特性: 【Flash的硬件实现机制】 Flash全名叫做Flash Memory,属于非易失性存储设备(Non-volatile Memory Device),与此相对应的是易失性存储设备(Volatile Memory Device)。
938 0
|
存储 算法 Linux
如何编写linux下nand flash驱动-4
2.       软件方面 如果想要在Linux下编写Nand Flash驱动,那么就先要搞清楚Linux下,关于此部分的整个框架。弄明白,系统是如何管理你的nand flash的,以及,系统都帮你做了那些准备工作,而剩下的,驱动底层实现部分,你要去实现哪些功能,才能使得硬件正常工作起来。
918 0