zoukankan      html  css  js  c++  java
  • 设备节点注册和操作方法连接

    今天把驱动程序乱七八糟的看了一通,简单总结一下。
    一个完整的驱动,需要提供如下的东西,
    第一,用户空间/dev下面的设备节点。当然,如果该设备仅仅是内核的使用,例如I2C,则不需要在/dev下面建立设备节点。
    第二,驱动程序,就是能到映射到/dev下面的fopen等系列操作。
    中间有些负责,不过这些基本的东西都还是能够找到,具体细节上的联系,还需要后面认真分析。从简单的sd卡驱动来看这些内容都是可以找到的。
    add_disk(md->disk)----》最终会向/dev下面添加节点。
    md  =  mmc_blk_alloc(card); ----》会连接上实际的fopen等系列操作


    -----------------------------------------------------华丽的分割线-------------------------------------------------------------------------
    SD卡属于块设备,card驱动部分为了将SD卡驱动成为块设备。介绍该部分的内容时先介绍驱动结构体和接口函数结构体,然后介绍几个关键的驱动函数。

    1.驱动的结构体mmc_driver

    该结构体定义驱动的名字,驱动探针函数、驱动移除函数、驱动阻塞和驱动重启等函数。

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

    2.块设备操作结构体mmc_bdops

    结构体mmc_bdops中定义了块设备操作的接口函数。

        static struct block_device_operations mmc_bdops = {  
            .open           = mmc_blk_open,  
            .release             = mmc_blk_release,  
            .getgeo         = mmc_blk_getgeo,  
            .owner          = THIS_MODULE,  
        };

    3.块设备探针函数mmc_blk_probe()

    该函数主要完成检验卡支持的命令,分配mmc_blk_data结构体空间,设置块的大小,最后设置card的driver_data 字段,并注册mmc信息到系统。

        static int mmc_blk_probe(struct mmc_card *card)  
        {  
            struct mmc_blk_data *md;  
            int err;  
            char cap_str[10];  
            /*检查卡支持的命令*/  
            if (!(card->csd.cmdclass & CCC_BLOCK_READ))  
                return -ENODEV;  
            /*为card分配mmc_blk_data结构体空间*/  
            md  =  mmc_blk_alloc(card);  
            /*设置块的大小*/  
            mmc_blk_set_blksize(md, card);  
            /*将md设置为card的driver_data 字段*/  
            mmc_set_drvdata(card, md);  
            /*把mmc包含的信息向系统进行注册,注册成功后就可以在文
        件系统对应目录下找到 mmc_card对应的结点设备*/  
            add_disk(md->disk);  
            return 0;  
        }

    4.驱动的入口函数mmc_blk_init()

    加载驱动时该函数被调用,该函数向内核申请注册一个块设备,然后进入核心层进行注册。

        static int __init mmc_blk_init(void)  
        {  
            /*向内核申请注册一个块设备*/  
            res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");  
            /*进入核心层进行注册*/  
            mmc_register_driver(&mmc_driver);  
            return 0;  
        }

    5.为块设备分配空间函数mmc_blk_alloc()

    函数mmc_blk_alloc()为块设备分配空间,并初始化一个请求队列,设置设备队列的sector大小。

        static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)  
        {  
            struct mmc_blk_data *md;  
            int devidx, ret;  
            /*在内存中查找第一个被清理过的bit*/  
            devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);  
            if (devidx >= MMC_NUM_MINORS)  
                return ERR_PTR(-ENOSPC);  
            /*从地址 dev_use开始设置bit,设置为devidx*/  
            __set_bit(devidx, dev_use);  
            /*分配结构体mmc_blk_data空间并初始化*/  
            md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);  
            /*设置卡的状态为只读*/  
            md->read_only = mmc_blk_readonly(card);  
            /*分配设备的次设备号为8*/  
            md->disk = alloc_disk(1 << MMC_SHIFT);  
            }  
            spin_lock_init(&md->lock);  
            md->usage = 1;  
            /*初始化一个请求队列,并将该队列与卡关联*/  
            mmc_init_queue(&md->queue, card, &md->lock);  
            /*注册 mmc_blk_issue_rq到md->queue,当md->queue上
        有request待处理时,    mmc_blk_issue_rq就会被调用*/  
            md->queue.issue_fn = mmc_blk_issue_rq;  
            md->queue.data = md;  
            /*注册相关的mmc_blk _data包含的块设备区*/  
            md->disk->major     = MMC_BLOCK_MAJOR;  
            md->disk->first_minor = devidx << MMC_SHIFT;  
            md->disk->fops = &mmc_bdops;  
            md->disk->private_data = md;  
            md->disk->queue = md->queue.queue;  
            md->disk->driverfs_dev = &card->dev;  
            sprintf(md->disk->disk_name, "mmcblk%d", devidx);  
            /*设置传输sector大小*/  
            blk_queue_hardsect_size(md->queue.queue, 512);  
            /*根据卡的类型设置容量*/  
            if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {  
                /*  
                 * The EXT_CSD sector count is in number or 512 byte  
                 * sectors.  
                */  
                set_capacity(md->disk, card->ext_csd.sectors);  
            } else {  
                /*  
                 * The CSD capacity field is in units of read_blkbits.  
                 * set_capacity takes units of 512 bytes.  
                */  
                set_capacity(md->disk,  
                    card->csd.capacity << (card->csd.read_blkbits - 9));  
            }  
            return md;  
        }

    在该驱动部分还包括一些对块操作的函数,如mmc_blk_open()、mmc_blk_get()、mmc_blk_put()、mmc_blk_release()和mmc_blk_getgeo()

  • 相关阅读:
    Java面试——VUE2&VUE3概览
    Golang 面试笔录
    数据科学完整流程概述
    周志华 机器学习 西瓜书 主要符号表
    数据分析师的发展方向?
    404 GET /nbextensions/jupyter-js-widgets/extension.js
    如何使用Conda源快速安装PyTorch?
    美化React组件之CSS Modules
    react如何全局配置sass
    nuxt api缓存,组件缓存,页面缓存
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3019674.html
Copyright © 2011-2022 走看看