linux驱动开发之块设备学习笔记

学习参考:http://www.cnblogs.com/yuanfang/archive/2010/12/24/1916231.html

1、块设备  块设备将数据按照固定块大小的块中,每个块的大小通常在512字节到32768字节之间,磁盘、SD卡都是常见的块设备。

2、字符设备和块设备的区别:
	字符设备				块设备
	----------------------------------------------
	按字节访问		  按块进行访问
	只能按照数据流访问 		  随机访问
	直接访问设备		  挂在文件系统的方式访问

3、Linux块设备处理模型
   |-------------------------------------------------------------|
   |                           VFS                               |
   |-------------------------------------------------------------|
   |     |                                         |             |
   |Disk Caches                                    |             |
   |     |                                         |             |
   |-------------------------------------------------------------|
   |Disk Filesystem  |  Disk Filesystem  |  Block Device File    |
   |-----------------                     -----------------------|
   |                     Mapping Layer                           |
   |-------------------------------------------------------------|
   |                   Generic Block Layer                       |
   |-------------------------------------------------------------|
   |                  I/O Scheduler Layer                        |
   |-------------------------------------------------------------|
   |    Block Device Driver      |      Block Device Driver      |
   |------------------------     |        --------------------   |
   |       Hard Disk             |            Hard Disk          |
   |------------------------------------------------------------—|

  

VFS:虚拟文件系统,VFS是对各种具体文件系统的一种封装,为用户程序提供访问文件的统一接口。
Disk Cache:当用户发起文件访问请求的时候,首先会到Disk Cache中寻找文件是否被缓存,如果缓存中有则在Cache中读取,如果数据没有被缓存,那就必须到文件系统中去读取。

Mapping Layer:
  1、首先确定文件系统的block size,然后计算所请求的数据包含多少个block,
  2、调用具体文件系统的函数来访问文件的inode,确定所请求数据在磁盘上面的逻辑地址。

Generic block layer:
  Linux内核为快设备抽象成了统一的模型,把块设备看做是若干个扇区组成的数据空间。来完成块设备的相关核心功能。

I/O scheduler layer:
  I/O调度层负责将I/O操作顺序,采用电梯算法。提高 I/O 调度器的效率也是影响整个系统对块设备上数据管理效率的一个方面。

Block Device Driver:
  快设备驱动程序,完成和硬件的具体交互,块设备相关数据结构

4、设备描述 gendisk结构体
  内核使用 gendisk 结构来表示一个独立的磁盘设备,内核还使用 gendisk 结构来表示分区,在此结构中,很多程序必须由驱动程序来进行初始化。该结构体定义<linux/genhd.h>中。
4.1、gendisk结构体解析
    struct gendisk {
        int major;                    /*设备主设备号*/
        int first_minor;            /*起始次设备号*/
        int minors;                    /*次设备号的数量,也称为分区数量,如果改值为1,表示无法分区*/
        char disk_name[32];            /*设备名称*/
        struct hd_struct **part;    /*分区表的信息*/
        int part_uevent_suppress;
        struct block_device_operations *fops;/*块设备操作集合 */
        struct request_queue *queue;         /*请求队列,用于管理该设备IO请求队列的指针*/
        void *private_data;                     /*私有数据*/
        sector_t capacity;                     /*扇区数,512字节为1个扇区,描述设备容量*/
        ....
    };

    struct gendisk *alloc_disk(int minors)
    分配一个gendisk结构,minors为此设备好的个数 = 分区数+1

    void del_gendisk(struct gendisk *disk)
    当不需要这个磁盘的时候,释放gendisk结构

    endisk中包含一个kobject成员, 它是一个可被引用计数的结构体。通过get_disk()和put_disk()函数可用来操作引用计数。驱动通常不需要做这个。
    struct kobject *get_disk(struct gendisk *disk);
    void put_disk(struct gendisk *disk);

    void add_disk(struct gendisk *gd);
    对gendisk初始化之后还不能使用和这个设备,应该使用add_disk注册磁盘设备

    static inline void set_capacity(struct gendisk *disk, sector_t size)
    设置gendisk容量,块设备中最小单位是扇区,扇区的大小一般是2的整数倍,最常见的大小是512kb (xx>>9)表示/512 (xx<<9)表示*512。扇区大小是物理设备所决定的。
5、block_device_operationse结构体
    类似与字符设备驱动程序中的file_operations结构,该集合用于控制设备的操作,但是在大多数情况下都是以mount的方式进行访问,用户程序一般不会直接访问块设备中的文件。需要包含<linux/blkdev.h>头文件。
    struct block_device_operations {
        /*打开这个设备时候调用*/
        int (*open) (struct inode *, struct file *);

        /*关闭/释放 时候调用*/
        int (*release) (struct inode *, struct file *);

        /*ioctl()系统调用的实现,块设备包含大量的标准请求,这些标准请求由 Linux 块设备层处理,因此大部分块设备驱动的*/
        int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);

        long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned, unsigned long);
        int (*direct_access) (struct block_device *, sector_t, unsigned long *);

        /*内核周期调用检查驱动器介质有没有发生改变,改变返回非0,没有改变返回0。用于支持可移动设备,非可以移动设备不用实现*/
        int (*media_changed) (struct gendisk *);

        /*被调用响应介质被改变,驱动进行必要的工作*/
        int (*revalidate_disk) (struct gendisk *);

        /*根据驱动器的几何信息填充hd_geometry,包含磁头,柱面,扇区等信息.*/
        int (*getgeo)(struct block_device *, struct hd_geometry *);

        /*模块拥有者,一般初始化为THIS_MODULE*/
        struct module *owner;
    };
    block_device_operations 结构中没有实际读或写数据的函数,在块 I/O 子系统中,这些操作由请求函数处理。

6、request 和 bio 结构体

    struct request {
        struct list_head queuelist;/*请求链表*/
        struct list_head donelist;
        request_queue_t *q;           /*请求所属队列*/
        unsigned int cmd_flags;
        enum rq_cmd_type_bits cmd_type;
        sector_t sector;         /* 当前扇区 */
        sector_t hard_sector;     /*要传输的下一个扇区*/
        unsigned long nr_sectors;/* 要传输的扇区数目*/
        unsigned long hard_nr_sectors;  /*要被完成扇区的数目 */
        unsigned int current_nr_sectors;/*当前传送的扇区*/
        unsigned int hard_cur_sectors;  /*当前要被完成的扇区数目*/
        struct bio *bio;    /*请求的block i/o(bio)结构体链表首 request请求 第一个bio*/
        struct bio *biotail;/*请求的bio结构体链表尾 request请求 最后个bio*/
        char *buffer; /*request请求中断 第一个bio*/
        int ref_count;/*引用计数*/
        .....................
    };

笔记未完!!!!!!

时间: 2025-01-05 07:24:21

linux驱动开发之块设备学习笔记的相关文章

[linux驱动]linux块设备学习笔记(一)

1,区别块设备和字符设备:块设备是系统中能随机访问固定大小的数据片的硬件.,扇区是所有块设备物理上的最小可寻址单位,通常大小为512Byte,块是文件系统的最小寻址单位,大小是扇区的整数倍,同时不能超过一个页的大小~ 操作块设备的时候需要在内存中有一个对应的缓冲区,用struct buffer_head结构体表示. [cpp] view plaincopy struct buffer_head { unsigned long b_state;        /* buffer state bit

[linux驱动]linux块设备学习笔记(四)——请求处理

一,请求处理 块设备的处理函数里没有read write等函数,所有对块设备的请求如读取 写入等都是通过request函数处理的.request函数的原型是void request(request_queue_t *queue);request函数的处理是异步的.每一个设备都有一个请求队列,当请求队列生成的时候,request函数就与该请求队列绑定在一起了,request函数总是与一个自旋锁一起使用,当request函数拥有自旋锁的时候,该锁防止内核为设备安排其它请求.构request代表了挂起

[linux驱动]linux块设备学习笔记(二)

1,gendisk结构体在linux内核中,使用gendisk结构体来表示一个实际的磁盘设备的抽象,结构体定义如下所示: [cpp] view plaincopy struct gendisk { int major; //主设备号 int first_minor;//次设备号 int minors;        //最大次设备数,如果不能分区则为1 char disk_name[DISK_NAME_LEN]; //设备名称,显示在/proc/partitions和sysfs中 struct 

Linux驱动开发之字符设备模板

/***************************** ** 驱动程序模板* 版本:V1* 使用方法(末行模式下):* :%s/xxx/"你的驱动名称"/g********************************/ #include <linux/mm.h>#include <linux/miscdevice.h>#include <linux/slab.h>#include <linux/vmalloc.h>#includ

Linux内核(17) - 高效学习Linux驱动开发

这本<Linux内核修炼之道>已经开卖(网上的链接为: 卓越.当当.china-pub ),虽然是严肃文学,但为了保证流畅性,大部分文字我还都是斟词灼句,反复的念几遍才写上去的,尽量考虑到写上去的每段话能够让读者产生什么疑惑,然后也都会紧接着尽量的去进行解释清楚,中间的很多概念也有反复纠结过怎么解释能够更容易的理解,力求即使对于初学者也可以有很少阻碍的一气读完.同时我也把书中一部分自己的感悟抽出来整理了精华版,share出来.当然水平有限,错漏之处有发现而修订时遗漏的,也有尚没有发现的.这本书

Linux 驱动开发笔记(一)

1.查看printk函数日记输出 (1)使用字符终端:通常使用ctrl+alt+f1切换查看: (2)使用cat /proc/kmsg命令:(在Linux系统启动后,/proc/kmsg文件可以查看内核对外所用的符号表,可以用cat命令查看器内容.) (3)使用dmesg命令查看. linux/kernel.h文件定义的printk函数的Log Level: 常数定义语句 意义 #define KERN_EMERG "<0>"/*系统不运行*/ #define KERN_A

Linux驱动开发学习的一些必要步骤

1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, lsmod, rmmod. 在驱动的init函数里打印hello world, insmod后应该能够通过dmesg看到输出. 5. 写一完整驱动, 加上read, write, ioctl, polling等各种函数的驱动实现. 在ioctl里完成从用户空间向内核空间传递结构体的实现. 6. 写一bl

s3c6410 Linux 驱动开发环境搭建

s3c6410 Linux 驱动开发环境搭建 -- 既然你是做Linux开发的,你还用虚拟机? 非常多人都在win下做开发,于是SD_writer.exe之类的烧写工具"大行其道",多是用虚拟机Linux. 全然转到Linux下学习開始蛮不爽的,开发板制作商送的教程都是些讲Win-CE的东东,感觉实质性的东西没什么.对于全然用Linux做开发的技术解说非常少,连烧写SD卡都用的win以下的程序.后来找了些资料,整理在这里,希望留给有心人.共同营造一个更好的共同学习的环境. 当别人遇到困

驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED

这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的住,不然真像一些人说的,学了一年嵌入式感觉还没找到门. 不能再扯了,涉及到linux的驱动开发知识面灰常广,再扯文章就会变得灰常长.首先还是回到led驱动的本身上,自从linux被移植到arm上后,做驱动开发的硬件知识要求有所降低,很多都回归到了软件上,这是系统编程的一大特点,当然 ,也不排除有很多