LinuxDown

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

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

2023年3月18日 209点热度

英语词组

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系统下载网

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

最新 热点 随机
最新 热点 随机
高速无线网络畅享,tplink300M Linux驱动带你飞 Linux系统的秘密技巧:轻松修改文件创建日期 Windows远程连接Linux,轻松跨平台操作 关于linux下获取文件的创建时间与实战的相关资料 树莓派Linux系统:极简体验大比拼 Linux系统如何修改文件的时间touch命令的描述指令? Linux上运行exe文件的软件,你绝对不能错过这些 蓝牙耳机怎么连接电脑?笔记本蓝牙适配器的开启方法 全新Linux局域网聊天软件 系统启动时自动运行程序的三种功能方法介绍 Linux系统下载攻略:掌握这些技巧,轻松get Linux查看端口占用情况linux命令:ps、grep、kill 剖析ARM Linux内核:奥秘与精髓解读 康华:Linux内核空间和用户空间的区别及用法 LinuxWine:使用关关采集器的最佳选择 Linux对段式内存映射的支持 Linux课程报告对比:成为顶级Linux系统管理员的秘诀 中通过几个宏拓展的实现来完成设备号的分解和合成 Linux计划任务工具对比:Cron及更多 快速上手Linux系统的基本概念、常用命令和应用
IMAP和POP有什么区别?如何配置邮件客户端使用IMAP高速无线网络畅享,tplink300M Linux驱动带你飞unix系统和linux系统 Unix和Linux系统的经验技巧,你了解吗?lastb列出登入系统失败的用户相关信息补充说明命令嵌入式操作系统的特点及发展前景分析快速定位目标文件,Linux文档管理软件!Linux操作系统下载:选择适合你的发行版获取UbuntuLinux操作系统的PDF文件文件的基础知识介绍Linux下Python开发经验与技巧分享Linux,下的日志文件系统的载体介绍-苏州安嘉Linux编程:系统IO速度稳定性评测一种嵌入式Linux操作系统的构建方法:王晓辉,孙新贺Linux轻松下载文件,简单操作!Linux远程主机的指定目录内容的使用命令Linux解压RAR神器,一招搞定zxvf命令嵌入式Linux文件系统的结构是基于树状的根在顶部深入解析Linux网络内核的开发技巧英特尔发布migrate-pages函数中实现页面迁移的批量TLB刷新Win7上安装Linux虚拟机软件的经验分享!2018.11.05linux.pngLinux发行版线路图
(Linux基础知识)Linux内核中的五大子系统CPU OCRmyPDF-2.0项目主开发语言:将扫描文档转换为可搜索的PDF文件的工具 北京时间Asia/Shanghai时区语言和键盘7安装配置 端口默认情况下的协议使用端口中的20和21 掌握Linux FTP用户密码,提高密码安全性 Linux内核对设备树的数据存储格式以及源码描述语法 嵌入式Linux要如何学习内核原理?150多G Linux轻松驾驭 DOS,命令完美融合 Linux串口驱动移植经验:要点大揭秘! LinuxSCI演示:系统调用的函数 linux内核和系统的区别?系统和centos系统可能会使用 SUSE Linux虚拟机下载指南 Linux系统改IP地址:常见问题解决方案 Linux内核完全注释PDF:清晰推荐 Linux查杀木马攻略:平安二号·百日攻坚 微软放弃Windows转向Linux,转而将建立在Linux内核之上 我的共享文件夹路径为/mnt/hgfs/desktop centos教程:解决CentOS7没有图形化界面,以及怎么安装 2018.11.05linux.pngLinux发行版线路图 开源世界的“瑰宝”——Linux系统的应用分析
标签聚合
软件 内核 命令 linux服务器 操作 应用 linux系统 文件 电脑 文件目录
书籍
课程
技术群
技术干货大合集↓
  • 2023年9月 / 92篇
  • 2023年8月 / 122篇
  • 2023年7月 / 122篇
  • 2023年6月 / 119篇
  • 2023年5月 / 123篇
  • 2023年4月 / 113篇
  • 2023年3月 / 265篇
友情链接:

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

COPYRIGHT © 2023 LinuxDown.com ALL RIGHTS RESERVED.

京ICP备14023444号-2