今天把驱动程序乱七八糟的看了一通,简单总结一下。
一个完整的驱动,需要提供如下的东西,
第一,用户空间/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()

设备节点注册和操作方法连接相关推荐

  1. 九、linux设备节点注册

    临时占位,还没弄好,后期再修改 一.杂项设备 杂项设备可以说是对一部分字符设备的封装,还有一部分不好归类驱动也归到杂项设备. 为什么会引入杂项设备?         • 第一.节省主设备号       ...

  2. Linux驱动编程 step-by-step (四) 字符设备的注册与设备节点的自动创建

    字符设备的注册与设备节点的自动创建 cdev 结构 内核内部使用struct cdev<linux/cdev.h>来表示一个字符设备 struct cdev {     struct ko ...

  3. linux设备和驱动注册,Linux驱动第五篇-----驱动注册和生成设备节点

    加载驱动的指令是:insmod xx.ko 查看驱动的指令是: lsmod 卸载驱动的指令是:rmmod xx 在include/linux/platform_device.h这个文件中定义了平台驱动 ...

  4. 新字符设备驱动实验(自动分配设备号、自动创建应用层设备节点、新字符设备注册到内核的结构体)

    目录 自动分配和释放设备号 示例代码 新的字符设备注册到内核方法 字符设备结构体(前面的设备号也放进来) cdev_init结构体初始化函数 cdev_add 添加到linux内核 cdev_del内 ...

  5. 驱动中动态创建设备号、设备节点

    在Linux驱动(三)字符设备驱动框架中,我们简要介绍了如何编写一个简单的驱动框架,并总结了步骤 1.生成设备号 2.向内核注册该设备号 3.初始化设备对象,完成操作方法集 4.向内核注册该设备对象 ...

  6. linux下spi添加设备,Linux Kernl添加spidev的设备节点

    一.spidev介绍 如果在内核中配置spidev,会在/dev目录下产生设备节点,通过此节点可以操作挂载在该SPI总线上的设备.用户空间通过该节点可以访问内核空间. 二.配置spidev设备步骤 在 ...

  7. 设备、设备节点和设备驱动详解

    Linux下的设备通常分为三类,字符设备,块设备和网络设备. 设备驱动程序也分为对应的三类:字符设备驱动程序.块设备驱动程序和网络设备驱动程序. 常见的字符设备有鼠标.键盘.串口.控制台等. 常见的块 ...

  8. 字符设备驱动注册时资源浪费问题

    目录 1.原因 2.对策 2.1注册流程及API 2.2注销流程及API 3.字符设备驱动分步注册\注销实例 字符设备驱动内部实现原理https://blog.csdn.net/liu31929396 ...

  9. Linux字符驱动中动态分配设备号与动态生成设备节点

    在编写Linux内核驱动程序的时候,如果不动态生成设备号的话,需要自己手动分配设备号,有可能你分配的设备号会与已有设备号相同而产生冲突.因此推荐自动分配设备号.使用下面的函数: int alloc_c ...

最新文章

  1. Go 学习笔记(43)— Go 标准库之 os/exec(执行外部命令、非阻塞等待、阻塞等待、命令输出)
  2. 单链表-单链表拆分为两个线性表(尾插法+尾插法)
  3. 使用FuncT, TResult 委托实现API日志的记录
  4. markdown html vue,vue项目引入markdown
  5. windows添加删除程序打不开解决方案
  6. Python学习笔记之用户输入
  7. [Java] 蓝桥杯BASIC-22 基础练习 FJ的字符串
  8. Android MVP开发模式及Retrofit + RxJava封装
  9. vue中的循环v-for
  10. 全面详解c语言使用cJSON解析JSON字符
  11. JavaSE 编写第一个程序
  12. python自动修改论文格式_如何轻轻松松修改论文格式?
  13. Python编程实现点到直线距离计算
  14. Vscode latex插件生成pdf目录空白问题
  15. 接入微信universal link微信校验不通过
  16. android 中止应用程序,如何终止Xamarin应用程序?
  17. ORACLE锁定账户的原因及解决办法
  18. Win7系统怎么共享文件夹 win7设置共享文件夹的步骤
  19. 一些完整的Android开源app项目
  20. tf.keras.layers.MaxPooling2D

热门文章

  1. apktoolkit apk反编译没有文件_重新编译mono——修改apk中Assembly-CSharp.dll并重新打包...
  2. react登录页面_「开源」React-Admin终极后台管理项目解决方案
  3. Java学习总结:19
  4. Java项目:在线旅游系统(java+jsp+SSM+Spring+mysql+maven)
  5. mac 配置 php,mac如何配置php环境
  6. linux test数字txt,Linux26期 7月4日预习笔记
  7. Java获取Mybatis动态生成的sql
  8. 10个你必须知道的ios框架
  9. JS同时上传表单图片和表单信息并把上传信息存入数据库,带php后端源码
  10. Storybook 5.0正式发布:有史以来变化最大的版本\n