LinuxDown.com
Linux系统下载网——精选每一篇高品质的技术干货
  1. 首页
  2. 开源快讯
  3. 正文

通俗来讲就是字符设备与块设备的区别字符驱动程序讲解

2023年3月18日 63点热度

英语词组

gen

disk

gendisk

之前讲解了字符驱动程序嵌入式linux高级驱动教程 pdf,这期开始讲解块设备驱动程序

字符设备与块设备的区别

字符设备驱动:

linux驱动高级视频_嵌入式linux高级驱动教程 pdf_python高级教程教程pdf

当应用层读写(read()/write())字符设备驱动时,是按字节/字符来读写数据的,期间没有任何缓存区,由于数据量小,不能随机读取数据,比如:按钮、LED、鼠标、键盘等

块设备:

块设备是i/o设备中的一类,当我们的应用层对该设备读写时,是按磁道大小来读写数据的,若读写的数据大于磁道的大小,都会须要缓存区,可以随机读写设备的任意位置处的数据嵌入式linux高级驱动教程 pdf,比如硬碟,U盘linux操作系统原理linux软件下载,SD卡。

总结:浅显来讲就是:块设备相当于是多个字符设备组成

块设备结构:重要的结构体定义

buffer_head

struct buffer_head {
	unsigned long b_state;		/* buffer state bitmap (see above) */
	struct buffer_head *b_this_page;/* circular list of page's buffers */
	struct page *b_page;		/* the page this bh is mapped to */
	sector_t b_blocknr;		/* start block number */
	size_t b_size;			/* size of mapping */
	char *b_data;			/* pointer to data within the page */
	struct block_device *b_bdev;
	bh_end_io_t *b_end_io;		/* I/O completion */
 	void *b_private;		/* reserved for b_end_io */
	struct list_head b_assoc_buffers; /* associated with another mapping */
	struct address_space *b_assoc_map;	/* mapping this buffer is
						   associated with */
	atomic_t b_count;		/* users using this buffer_head */
};

bio

struct bio {
	sector_t		bi_sector;	/* device address in 512 byte
						   sectors */
	struct bio		*bi_next;	/* request queue link */
	struct block_device	*bi_bdev;
	unsigned long		bi_flags;	/* status, command, etc */
	unsigned long		bi_rw;		/* bottom bits READ/WRITE,
						 * top bits priority
						 */
	unsigned short		bi_vcnt;	/* how many bio_vec's */
	unsigned short		bi_idx;		/* current index into bvl_vec */
	/* Number of segments in this BIO after
	 * physical address coalescing is performed.
	 */
	unsigned short		bi_phys_segments;
	/* Number of segments after physical and DMA remapping
	 * hardware coalescing is performed.
	 */
	unsigned short		bi_hw_segments;
	unsigned int		bi_size;	/* residual I/O count */
	/*
	 * To keep track of the max hw size, we account for the
	 * sizes of the first and last virtually mergeable segments
	 * in this bio
	 */
	unsigned int		bi_hw_front_size;
	unsigned int		bi_hw_back_size;
	unsigned int		bi_max_vecs;	/* max bvl_vecs we can hold */
	struct bio_vec		*bi_io_vec;	/* the actual vec list */
	bio_end_io_t		*bi_end_io;
	atomic_t		bi_cnt;		/* pin count */
	void			*bi_private;
	bio_destructor_t	*bi_destructor;	/* destructor */
};

block_device


struct block_device {
	dev_t			bd_dev;  /* not a kdev_t - it's a search key */
	struct inode *		bd_inode;	/* will die */
	int			bd_openers;
	struct mutex		bd_mutex;	/* open/close mutex */
	struct semaphore	bd_mount_sem;
	struct list_head	bd_inodes;
	void *			bd_holder;
	int			bd_holders;
#ifdef CONFIG_SYSFS
	struct list_head	bd_holder_list;
#endif
	struct block_device *	bd_contains;
	unsigned		bd_block_size;
	struct hd_struct *	bd_part;
	/* number of times partitions within this device have been opened. */
	unsigned		bd_part_count;
	int			bd_invalidated;
	struct gendisk *	bd_disk;
	struct list_head	bd_list;
	struct backing_dev_info *bd_inode_backing_dev_info;
	/*
	 * Private data.  You must have bd_claim'ed the block_device
	 * to use this.  NOTE:  bd_claim allows an owner to claim
	 * the same device multiple times, the owner must take special
	 * care to not mess up bd_private for that case.
	 */
	unsigned long		bd_private;
};

gendisk


struct gendisk {
	int major;			/* major number of driver */
	int first_minor;
	int minors;                     /* maximum number of minors, =1 for
                                         * disks that can't be partitioned. */
	char disk_name[32];		/* name of major driver */
	struct hd_struct **part;	/* [indexed by minor] */
	int part_uevent_suppress;
	struct block_device_operations *fops;
	struct request_queue *queue;
	void *private_data;
	sector_t capacity;
	int flags;
	struct device *driverfs_dev;
	struct kobject kobj;
	struct kobject *holder_dir;
	struct kobject *slave_dir;
	struct timer_rand_state *random;
	int policy;
	atomic_t sync_io;		/* RAID */
	unsigned long stamp;
	int in_flight;
#ifdef	CONFIG_SMP
	struct disk_stats *dkstats;
#else
	struct disk_stats dkstats;
#endif
	struct work_struct async_notify;
};

block_device_operations

struct block_device_operations {
	int (*open) (struct inode *, struct file *);
	int (*release) (struct inode *, struct file *);
	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;
};

python高级教程教程pdf_嵌入式linux高级驱动教程 pdf_linux驱动高级视频

buffer_head上面重要的成员结构体:

linux驱动高级视频_python高级教程教程pdf_嵌入式linux高级驱动教程 pdf

bio上面重要的成员结构体:

嵌入式linux高级驱动教程 pdf_linux驱动高级视频_python高级教程教程pdf

备注:typedefvoid(bh_end_io_t)(structbuffer_head*bh,intuptodate);

linux驱动高级视频_python高级教程教程pdf_嵌入式linux高级驱动教程 pdf

在块设备操作中重要的函数ll_rw_block

ll_rw_block:low-levelaccesstoblockdevices(块设备低级访问)

函数原型:voidll_rw_block(intrw,intnr,structbuffer_head*bhs[])

其调用过程:

1,ll_rw_block
2,struct buffer_head *bh = bhs[i];
3,submit_bh
4,struct bio *bio;  bio = bio_alloc(GFP_NOIO, 1);
5,bio->bi_end_io = end_bio_bh_io_sync;
6,bio_get
7,submit_bio
8,bio_sectors
9,generic_make_request(bio);
10,__generic_make_request(bio);
11,q = bdev_get_queue(bio->bi_bdev);
12,return bdev->bd_disk->queue;
13,blk_partition_remap(bio);
14,ret = q->make_request_fn(q, bio);

编撰一个最简单的块设备驱动程序


/* 参考:
 * driversblockxd.c
 * driversblockz2ram.c
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
static struct gendisk *ramblock_disk;
static request_queue_t *ramblock_queue;
static int major;
static DEFINE_SPINLOCK(ramblock_lock);
#define RAMBLOCK_SIZE (1024*1024)
static unsigned char *ramblock_buf;
static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
	/* 容量=heads*cylinders*sectors*512 */
	geo->heads     = 2;
	geo->cylinders = 32;
	geo->sectors   = RAMBLOCK_SIZE/2/32/512;
	return 0;
}
static struct block_device_operations ramblock_fops = {
	.owner	= THIS_MODULE,
	.getgeo	= ramblock_getgeo,
};
static void do_ramblock_request(request_queue_t * q)
{
	static int r_cnt = 0;
	static int w_cnt = 0;
	struct request *req;
	
	//printk("do_ramblock_request %dn", ++cnt);
	while ((req = elv_next_request(q)) != NULL) {
		/* 数据传输三要素: 源,目的,长度 */
		/* 源/目的: */
		unsigned long offset = req->sector * 512;
		/* 目的/源: */
		// req->buffer
		/* 长度: */		
		unsigned long len = req->current_nr_sectors * 512;
		if (rq_data_dir(req) == READ)
		{
			//printk("do_ramblock_request read %dn", ++r_cnt);
			memcpy(req->buffer, ramblock_buf+offset, len);
		}
		else
		{
			//printk("do_ramblock_request write %dn", ++w_cnt);
			memcpy(ramblock_buf+offset, req->buffer, len);
		}		
		
		end_request(req, 1);
	}
}
static int ramblock_init(void)
{
	ramblock_disk = alloc_disk(16); 
	ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock);
	ramblock_disk->queue = ramblock_queue;
	
	major = register_blkdev(0, "ramblock");  
	ramblock_disk->major       = major;
	ramblock_disk->first_minor = 0;
	sprintf(ramblock_disk->disk_name, "ramblock");
	ramblock_disk->fops        = &ramblock_fops;
	set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512);
	ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);
	add_disk(ramblock_disk);
	return 0;
}
static void ramblock_exit(void)
{
	unregister_blkdev(major, "ramblock");
	del_gendisk(ramblock_disk);
	put_disk(ramblock_disk);
	blk_cleanup_queue(ramblock_queue);
	kfree(ramblock_buf);
}
module_init(ramblock_init);
module_exit(ramblock_exit);
MODULE_LICENSE("GPL");

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: 块设备 字符
最后更新:2023年3月18日

Linux系统下载网

每日更新,欢迎收藏♥ 不积跬步无以至千里,加油,共勉。

点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论

Linux系统下载网

每日更新,欢迎收藏♥
不积跬步无以至千里,加油,共勉。

最新 热点 随机
最新 热点 随机
掌握Linux内核链接脚本:详解、实践与优化 文本编辑器Vim有个内置功能很强加密功能 Linux安装MySQL5.6:详细步骤及下载地址 字符集1.计算机的存储规则(ASCII)计算机解码规则 linux goldendict Linux黄金词典:英语学习高效利器 Linux中解压缩zip文件乱码怎么办?如何解决问题? Linux轻松搭建网站:安装Apache服务攻略 Linux操作系统多数Intemet设备内核移植过程及方法 轻松安装CentOS,EasyBCD教程上手 Windows端完全转入了Linux服务器端,语言也彻底变成C Golang开发者乱码问题的原因及解决方法设置中解析 企业Linux安全运维:10大分析实战经验 轻松搞定CentOS本地域名解析与静态IP设置 Linux命令用于显示内存使用情况的free(-bkmotV) Linux必备:64位Tomcat下载安装教程 精通Linux设备驱动开发,掌握9大关键技巧! Linux下MySQL下载安装教程,快速学会MySQL安装! 升级到7.10完成后执行一下sudo-getclean释放空间 玩转Linux C索引:3.1版本安装指南 轻松掌握Linux启动应用程序命令,提高工作效率
RedHat虚拟机网络配置:9大详细分析,让你轻松上手掌握Linux内核链接脚本:详解、实践与优化Linux虚拟机必备:轻松安装VMwareTools网络安装Linux系统:多种方法全解析高效、易用的Linux笔记整理下载工具关于嵌入式Linux操作系统的原理和实现的详细分析Linux发行版在开机启动时拉起的服务进程中如何关闭?Linux内核通信方式详细解析:探讨八种实现方法CentOS如何安装中文输入法,让Linux操作系统更方便?有个发行版居然模仿起了Win11系统,还内置安卓虚拟机深入了解Linux内核开发,掌握基本技巧!Linux登录认证失败的8个问题,让你不再孤单一个如何记录ssh命令操作的小技巧-OpenSSH命令Linux轻松安装:VirtualBox虚拟机指南Fedora 25轻松安装智能fcitx输入法Linux系统在启动过程中都加载了哪些内容?Linux系统连接服务器:从入门到精通的技巧!Linux安装内核开发包及编译器,轻松开发!学习linux内核是需要一步一步内核的一些建议吧!Linux操作系统进程内核文件的设置文件是什么
centos portmap 提高服务器安全性:CentOS中Portmap的应用与优化 Linux内核版本的命令(3种方法) CentOS如何安装中文输入法,让Linux操作系统更方便? Linux系统轻松运行exe文件,实现跨平台应用 安装后系统默认不会自动启动的服务,避免不必要损失和麻烦 解锁Linux声卡创新 KX驱动,音效焕发新生! Linux下载必备:优化Portmap提升速度 升级到7.10完成后执行一下sudo-getclean释放空间 抢占Linux开发招聘先机,这些技能你必须掌握! Linux系统中的默认字符集和常用文件系统格式的详细内容 轻松安装CentOS,EasyBCD教程上手 轻松下载Linux系统界面版,尽享高效办公! 深入了解Linux服务器系统的优点和应用 轻松掌握Linux库版本查看技巧-操作系统详解 深入了解Linux键盘驱动:8个基础知识与工作原理 Golang开发者乱码问题的原因及解决方法设置中解析 深入了解Linux内核开发,掌握基本技巧! Linux编写文件,轻松创建和编辑! 《命令》cp命令的基本格式:软链接 linux reuse Linux系统代码复用技巧,提高工作效率
标签聚合
u盘启动 软件 linux服务器 centos 电脑 文件目录 sudo 虚拟机 linux系统 linux社区
书籍
课程
技术群
技术干货大合集↓
  • 2023年3月 / 249篇
友情链接:

Linux书籍 | Linux命令 | Linux系统 | RHCE红帽认证 | Linux软件 | Linux教程 | CentOS系统 | Linux内核 | Linux服务器 | Linux大神 | IT资源

COPYRIGHT © 2023 LinuxDown.com ALL RIGHTS RESERVED.

京ICP备14023444号-2