一、块设备结构体
1. file_operations 结构体
和字符设备驱动中file_operations 结构体类似,块设备驱动中也有一个
block_device_operations 结构体,它的声明位于/include/linux 录下的fs.h 文件中,它是对
块操作的集合。
struct block_device_operations{ int(*open)(struct inode *, struct file*); //打开设备 int(*release)(struct inode *, struct file*); //关闭设备 //实现ioctl 系统调用 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*); //调用该函数用以检查用户是否更换了驱动器的介质 int(*media_changed)(struct gendisk*); int(*revalidate_disk)(struct gendisk*); //当介质被更换时,调用该函数做出响应 int(*getgeo)(struct block_device *, struct hd_geometry*);//获取驱动器信息 struct module *owner; //指向拥有这个结构体模块的指针,通常被初始化位THIS_MODULE }; |
与字符驱动不同的是在这个结构体中缺少了read()和write()函数,那是因为块设备的I/O 子系统中,这些操作都是有request 函数进行处理。
request 函数的原型如下:
void request(request_queue_t *queue);
2.gendisk结构体
gendisk 结构体的定义位于/include/linux 目录下的genhd.h 文件中,如下所示。
struct gendisk { /* *这三个成员的定义依次是:主设备号、第一个次设备号,次设备号。一个驱动中至有一个次设备号, *如果驱动器是一个可被分区,那么每一个分区都将分配一个次设号。 */ int major; int first_minor; int minors; //这个数组用以存储驱动设备的名字 char disk_name[DISK_NAME_LEN]; char *(*devnode)(struct gendisk *gd, umode_t *mode); unsigned int events; unsigned int async_events; struct disk_part_tbl __rcu *part_tbl; struct hd_struct part0; //这个结构体用以设置驱动中的各种设备操作 const struct block_device_operations *fops; //Linux 内核使用这个结构体为设备管理I/O 请求,具体详解见request_queue 结构。 struct request_queue *queue; void *private_data; int flags; struct device *driverfs_dev; struct kobject *slave_dir; struct timer_rand_state *random; atomic_t sync_io; struct disk_events *ev; #ifdef CONFIG_BLK_DEV_INTEGRITY struct blk_integrity *integrity; #endif int node_id; }; |
gendisk 结构体是是动态分配,但是驱动程序自己不能动态分配该结构,而是通过调用
alloc_disk()函数进行动态分配。
struct gendisk *alloc_disk(int minors);
其中minors 是该磁盘使用的次设备号。
但是分配了gendisk 结构并不意味着该磁盘就对系统可用,使用之前得初始化结构体并
且调用add_disk()函数。
//初始化结构体
struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
//添加分区
void add_disk(struct gendisk *gd)
如果不再需要这个磁盘,则对其进行卸载。
//删除分区
Void del_gendisk(struct gendisk *gd)
void blk_cleanup_queue(struct request_queue *q)
3.bio结构体
bio 结构体的定义位于/include/linux 目录下的linux_blk_types.h 文件中。
struct bio { //需要传输的第一个(512byte)扇区 sector_t bi_sector; struct bio *bi_next; struct block_device *bi_bdev; unsigned long bi_flags; unsigned long bi_rw; unsigned short bi_vcnt; unsigned short bi_idx; //BIO 中所包含的物理段数目 unsigned int bi_phys_segments; //所传输的数据大小(以byte 为单位) unsigned int bi_size; unsigned int bi_seg_front_size; unsigned int bi_seg_back_size; unsigned int bi_max_vecs; atomic_t bi_cnt; struct bio_vec *bi_io_vec; bio_end_io_t *bi_end_io; void *bi_private; #ifdef CONFIG_BLK_CGROUP struct io_context *bi_ioc; struct cgroup_subsys_state *bi_css; #endif #if defined(CONFIG_BLK_DEV_INTEGRITY) struct bio_integrity_payload *bi_integrity; #endif bio_destructor_t *bi_destructor; struct bio_vec bi_inline_vecs[0]; }; |
bio 结构体包含了驱动程序执行请求的所有信息。既描述了磁盘的位置,又描述了内存
的位置,是上层内核与下层驱动的连接纽带。
struct bio_vec *bi_io_vec;
而bio_vec 结构体的声明为:结构bio_vec 代表了内存中的一个数据段,数据段用页、偏移和长度描述
struct bio_vec { struct page *bv_page; /*数据段所在的页*/ unsigned short bv_len; /*数据段的长度*/ unsigned short bv_offset; /*数据段页内偏移*/ }; |
4. requeset 结构体
request 结构体代表了挂起的I/O 请求,每个请求用一个结构request 实例描述,存放
在请求队列链表中,由电梯算法进行排序,每个请求包含一个或多个结构bio 实例。requeest
结构体声明位于/include/linux 目录下的blkdev.h 文件中。
struct request { struct list_head queuelist; struct call_single_data csd; struct request_queue *q; unsigned int cmd_flags; enum rq_cmd_type_bits cmd_type; unsigned long atomic_flags; int cpu; unsigned int __data_len; sector_t __sector; struct bio *bio; struct bio *biotail; struct hlist_node hash; union { struct rb_node rb_node; void *completion_data; }; union { struct { struct io_cq *icq; void *priv[2]; } elv; struct { unsigned int seq; struct list_head list; rq_end_io_fn *saved_end_io; } flush; }; struct gendisk *rq_disk; struct hd_struct *part; unsigned long start_time; #ifdef CONFIG_BLK_CGROUP struct request_list *rl; unsigned long long start_time_ns; unsigned long long io_start_time_ns; #endif unsigned short nr_phys_segments; #if defined(CONFIG_BLK_DEV_INTEGRITY) unsigned short nr_integrity_segments; #endif unsigned short ioprio; int ref_count; void *special; char *buffer; int tag; int errors; unsigned char __cmd[BLK_MAX_CDB]; unsigned char *cmd; unsigned short cmd_len; unsigned int extra_len; unsigned int sense_len; unsigned int resid_len; void *sense; unsigned long deadline; struct list_head timeout_list; unsigned int timeout; int retries; rq_end_io_fn *end_io; void *end_io_data; struct request *next_rq; }; |
5. request_queue 结构体
每个块设备都有一个请求队列,每个请求队列单独执行I/O 调度,请求队列是由请求结
构实例链接成的双向链表,链表以及整个队列的信息用request_queue 结构体描述,称为请
求队列对象结构或请求队列结构。request_queue 结构体声明位于/include/linux 目录下的
blkdev.h 文件中。
struct request_queue{ /* * Together with queue_head for cacheline sharing */ struct list_head queue_head; struct request *last_merge; struct elevator_queue *elevator; /* * the queue request freelist, one for reads and one for writes */ struct request_list rq;
request_fn_proc *request_fn; make_request_fn *make_request_fn; prep_rq_fn *prep_rq_fn; unplug_fn *unplug_fn; prepare_discard_fn *prepare_discard_fn; merge_bvec_fn *merge_bvec_fn; prepare_flush_fn *prepare_flush_fn; softirq_done_fn *softirq_done_fn; rq_timed_out_fn *rq_timed_out_fn; dma_drain_needed_fn *dma_drain_needed; lld_busy_fn *lld_busy_fn;
/* * Dispatch queue sorting */ sector_t end_sector; struct request *boundary_rq;
/* * Auto-unplugging state */ struct timer_list unplug_timer; int unplug_thresh; /* After this many requests */ unsigned long unplug_delay; /* After this many jiffies */ struct work_struct unplug_work;
struct backing_dev_info backing_dev_info;
/* * The queue owner gets to use this for whatever they like. * ll_rw_blk doesn't touch it. */ void *queuedata;
/* * queue needs bounce pages for pages above this limit */ gfp_t bounce_gfp;
/* * various queue flags, see QUEUE_* below */ unsigned long queue_flags;
/* * protects queue structures from reentrancy. ->__queue_lock should * _never_ be used directly, it is queue private. always use * ->queue_lock. */ spinlock_t __queue_lock; spinlock_t *queue_lock;
/* * queue kobject */ struct kobject kobj;
/* * queue settings */ unsigned long nr_requests; /* Max # of requests */ unsigned int nr_congestion_on; unsigned int nr_congestion_off; unsigned int nr_batching;
void *dma_drain_buffer; unsigned int dma_drain_size; unsigned int dma_pad_mask; unsigned int dma_alignment;
struct blk_queue_tag *queue_tags; struct list_head tag_busy_list;
unsigned int nr_sorted; unsigned int in_flight[2];
[1] [2]
关键字:块设备 驱动程序 结构体
引用地址:块设备驱动程序
声明:本文内容及配图由平台用户或入驻媒体撰写。文章观点仅代表作者本人,不代表EEWorld网站立场。文章及其配图仅供工程师学习之用,如有内容侵权或违规,请联系本站处理,邮箱地址:bbs_service@eeworld.com.cn
上一篇:NandFlash驱动分析
0
推荐阅读最新更新时间:2024-08-29 10:46
USB驱动程序框架搭建
1.首先我们先从理论上浅谈一下USB驱动的框架
app:
-------------------------------------------
USB设备驱动程序 // 知道数据含义
内核 --------------------------------------
USB总线驱动程序 // 1. 识别, 2. 找到匹配的设备驱动, 3. 提供USB读写函数 (它不知道数据含义)
-------------------------------------------
[嵌入式]
基于51单片机RTL8019AS的网卡驱动程序
SNMP网管板使用了RTL8019AS 10M ISA网卡芯片接入以太网。选它的好处是:NE2000兼容,软件移植性好;接口简单不用转换芯片如PCI-ISA桥;价格便宜2.1$/片(我的购入价为22元RMB/片);带宽充裕(针对51);较长一段时间内不会停产。8019有3种配置模式:跳线方式、即插即用P&P方式、串行Flash配置方式。为了节省成本,我去掉了9346而使用X5045作为闪盘存储MAC地址和其他可配置信息。P&P模式用在PC机中,这里用不上。只剩下跳线配置模式可用,它的电路设计参考REALTEK提供的DEMO板图纸。一天时间就可以完成,相对来说硬件设计比较简单。 与这部分硬件相对应的软件是网卡驱动。所
[单片机]
基于MSP430F5438A的OV7670简单驱动程序
作为一个新手,因为课程设计要求,接触到了OV7670。因为课程设计要求使用MSP430F5438A驱动OV7670,而网上大多数都是使用STM32进行驱动。上网查找了很多资料,也仔细看过网上大佬发的相关寄存器的帖子,最后成功使用430单片机完成了设计。本着来源于网络,回馈于网络的原则,在此介绍一下,自己使用OV7670的一点经验。水平有限,偏颇之处,还请包涵! 首先简单的介绍一下所使用的摄像头OV7670。 OV7670是OV(OmniVision)公司生产的一颗1/6寸的CMOS VGA图像传感器。该传感器体积小、工作电压低,提供单片VGA摄像头和影像处理器的所有功能。通过SCCB 总线控制,可以输出整帧、子采样、取窗口等方
[单片机]
部分Mac用户称系统将打印机驱动程序当成恶意软件
一些用户报告,由于 macOS 错误声称某些软件为恶意软件,他们无法再使用惠普打印机进行打印,或者无法继续通过专用应用来播放 Amazon Music。 外媒 AppleInsider 称,用户报告他们的 Mac 突然弹出通知,称其 HP 打印机包含恶意软件:“会损坏您的计算机”。另外,其他用户报告的是同一问题,但与 Amazon Music 应用有关。 在这种情况下,尝试启动应用程序或仅使用 Mac,都会弹出一个对话框。报告说有恶意软件会损坏 Mac,并建议用户将特定文件移至废纸篓。 该文件可以是 Amazon Music 应用程序,也可以是称为 HP Device Monitoring.framework 的惠普打
[手机便携]
stm32专题十一:USART(三)初始化结构体和标准库函数分析
在之前的博客中分析了stm32串口的结构,和详细的发送、接受过程。现在来分析固件库中对于USART的标准函数 typedef struct { uint32_t USART_BaudRate; // 波特率 uint16_t USART_WordLength; // 帧数据长度(8位还是9位) uint16_t USART_StopBits; // 停止位 uint16_t USART_Parity; // 校验 uint16_t USART_Mode; // 模式:单收、单发或收发 uint16_t USART_HardwareFlowCo
[单片机]
MSP430与PCF8576驱动程序(可以借鉴IIC的使用方法)
#i nclude msp430x14x.h #define uint unsigned int #define uchar unsigned char #define Num_of_Results 8 unsigned int results ; uchar PCF8576=0x70;//器件地址 //内存数据定义 uchar ByteCnt; //I2C 数据字节计数器 uchar SlvAdr; //被控器地址 uchar SubAdr; //被控器单元地址 uchar XmtDat ; //发送数据缓冲区 uchar MODE2=0xCD; uchar B
[单片机]
IMX257 LED驱动程序实现
由于昨天对IMX257的地址分配不了解,所以前面只能用s3c24xx的驱动程序来了解ioremap等对IO端口的工作原理。 但是经过昨晚对IMX257芯片的细细梳理,今天早上起来又把IMX257的芯片资料看了一遍,终于成功看懂了,下面意义给大家道来。 我们此处使用ERR_LED 也就是GPIO3_23引脚 一、IMX257 芯片资料分析 1.确定相关寄存器基址 确定IOMUX地址 GPIO3的地址 2.确定相关寄存器的偏移地址 IOMUX的相关的模式配置寄存器,配置为ALT5模式 偏移地址: 寄存器描述: 接下来就是配置GPIO的相关信息,上拉,CMOS输入输出,等信息 偏移地址: 寄存器描述:
[单片机]
DS18B20驱动程序调试总结
DS18B20是一款精度比较好的温度传感器,最重要的是它通过一根导线,既完成通讯,又给芯片供电,在MCU引脚数量比较紧张的时候,确实是个不错的选择。这颗芯片看起来简单,但真正让它跑起来,从里面读出温度数据可没有想象的那么容易。这不,群里的Ryan Wang同学就被折磨得不行。难能可贵的是,在王同学终于搞定它之后,无私地分享出心得和代码。如果你觉得这篇文章能帮到更多的同学,就帮忙转发,或点个在看吧。 通过CUBE使能TIM2定时器,Clock Source使用internal Clock,MCU主频为32Mhz,故Prescaler=32-1=31,Counter Mode为UP,这里注意Counter Period 官方手册要
[单片机]
猜您喜欢
更多
小广播
添点儿料... 无论热点新闻、行业分析、技术干货…… 发布文章
推荐内容
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐
最新单片机文章
更多开源项目推荐
更多精选电路图
换一换
更多
相关热搜器件
更多热门文章
更多每日新闻
更多往期活动
09月03日历史上的今天
厂商技术中心
最能打国产芯 TI 培训 Qorvo 电源技术站 Vicor技术站
随便看看
|