学習を促進する-日次ノートday10

[1]ブロックデバイスブロックデバイスの
特徴:
セクターに応じたアクセス、アクセスの単位は512バイトで、
シーケンシャルまたは順不同でアクセスできます。

块设备的硬件知识:
比如一个移动硬盘:
磁头:有多少个盘面
磁道:一个面内有多少环
扇区:一个环内有多少个扇区,一个扇区512字节

磁盘的数据的读取:
磁盘数据的读取不会按照存储顺序来读取,因为磁头它是机械结构,
通过旋转来访问数据,如果按照数据来访问,需要反复的切换这个
物理结构,比较浪费时间。所以磁盘在访问的时候采用电梯优化的算法
来完成。即一次将一个盘面上的数据全部读取到,然后切换物理结构,
在读取下面的数据。将所有的数据读取完之后,进行数据的排序,排序
之后进行操作。


页 4K                    段 :可以包含多个block
block 512字节 1K 2K 4K   扇区 512字节

[2]ブロックデバイス
ユーザーのフレーム構造
open read write close(すべてがファイル)
------------------ |(io request)-------- --------------
kernel:| VFS:(struct block_device)
| ext2 ext3 ext4 yaffs jiffs
|
|上記のファイルシステムは、ioリクエストをブロックに変換するために使用されます
| request bio(block input出力)、Linuxカーネル
は、物理アドレスに対する連続したbio要求を1つの要求に結合します。
|要求はキューに入れられます。
| -----------------------------------------
|ブロックデバイスドライバー:struct gendisk
| 1.割り当てられたオブジェクト
| 2.オブジェクトの初期化、キューの初期化
| 3.ハードディスクハードウェアの操作
| 4.登録と登録解除

ハードウェア:ハードディスク

[3]ブロックデバイスドライバの構造と機能
1.ブロックデバイス構造の
構造体gendisk { INT主要; //メジャーデバイス番号のint first_minor; //マイナーデバイス番号の値開始INTの未成年者; //番号デバイスのチャーDISK_NAME [DISK_NAME_LEN]; //ブロックデバイスの名前struct disk_part_tbl * part_tbl; //ハードディスクパーティションテーブルstruct hd_struct part0; // ハードディスクのパーティションconst struct block_device_operations * fops; // ブロックデバイスの操作メソッド構造struct request_queue * queue; // Request queue void * private_data; // private data }; 2.パーティション構造struct hd_struct { ector_t start_sect; //セクターの開始ector_t nr_sects; // セクターのsector_t alignment_offset; //アライメント方法int partno; //パーティション番号};

















3.操作方法结构体
struct block_device_operations {
	int (*open) (struct block_device *, fmode_t);
	int (*release) (struct gendisk *, fmode_t);
	int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
	int (*getgeo)(struct block_device *, struct hd_geometry *);
	//设置磁盘有多少个磁头,有多少个磁道,有多少扇区
};


4.队列的操作的方法
struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
功能:初始化一个队列
参数:
	@rfn  :队列处理函数
	typedef void (request_fn_proc) (struct request_queue *q);
	//这个是队列处理函数的原型,在这个函数中要进行读写操作
	@lock :自旋锁
返回值:成功返回初始化好的队列的指针
		失败返回NULL
		
		
struct request *blk_fetch_request(struct request_queue *q)
功能:从队列中取出一个请求
参数:
	@q :队列
返回值:成功返回request结构体指针
		失败返回NULL

void blk_cleanup_queue(struct request_queue *q)
功能:清除队列
参数:
	@q:被清除的队列
返回值:无

5.关于request的操作
 sector_t blk_rq_pos(const struct request *rq)
 功能:从请求中获取本次操作的起始的函数

 unsigned int blk_rq_cur_sectors(const struct request *rq)
 功能:获取本次想读写的扇区的个数
 
 int blk_rq_cur_bytes(const struct request *rq)
 功能:获取本次想读写的字节的个数

 rq_data_dir(rq)
 功能:从request中获取本次是读还是写
 rq_data_dir(rq) == READ  读
 rq_data_dir(rq) == WRITE 写

bool __blk_end_request_cur(struct request *rq, 0)
功能:判断request的读写是否处理完了
参数:
	@rq :请求队列
返回值:真:表示数据没有处理完
		假:数据处理完成了
	
2.gendisk内存分配并初始化的函数
	struct gendisk *alloc_disk(int minors)
	功能:分配内存并初始一些内容
	参数:
		@minors :设备的个数
		
2.申请块设备的设备号
int register_blkdev(unsigned int major, const char *name)
功能:申请块设备的设备号
参数:
	@major :如果填写的是大于0的值静态指定设备号
			如果填写的是0表示动态申请设备号
	@name  :cat /proc/devices		
返回值:
	major > 0   成功返回0,失败返回错误码
	major = 0   成功返回主设备号,失败返回小于等于0的值
	
	
void unregister_blkdev(unsigned int major, const char *name)
功能:失败块设备的设备号
参数:
	@major :主设备号
	@name  :名字
返回值:无

3.块设备驱动的注册/注销
void add_disk(struct gendisk *disk)
功能:注册gendisk
参数:
	@disk :gendisk对象的地址
void del_gendisk(struct gendisk *disk)
功能:注销gendisk
参数:
	@disk :gendisk对象的地址


块设备驱动的测试:
1.安装驱动
	sudo  insmod  mydisk.ko 
2.查看
	cat /proc/devices
	ls /dev/mydisk
	sudo fdisk -l
3.分区
	sudo fdisk /dev/mydisk
	:m  --->打印帮助信息
	:n  --->新建一个分区
	:p  --->打印分区
	:w  --->保存退出
	:q  --->退出
	
4.格式化
	sudo mkfs.ext3 /dev/mydisk1
5.将磁盘挂载到一个目录下
	sudo mount /dev/mydisk1 ~/udisk
	
	在udisk中存放文件和目录
6.取消挂载
	sudo umount ~/udisk
	
7.将刚才写进磁盘的数据给读出来
	cat /dev/mydisk1 > mydisk_file.bin
	
8.查看.bin中是否有文件
	sudo mount -o loop mydisk_file.bin ~/udisk
	在udisk中可以看到刚才写进入的文件和目录
	表示块设备驱动是成功的。

メモリ割り当て機能:
仮想メモリ:
1.アドレス
物理アドレス:データシートで見つけることができるアドレスは、物理アドレス、実際のデバイスの操作アドレスと呼ばれます;
仮想アドレス、線形アドレス:オペレーティングシステムプログラマーが操作できるアドレスそれは仮想アドレスです;
論理アドレス:プログラムを分解した後、見ることができるアドレスは論理アドレスと呼ばれます;

2.内存管理
	段式管理
	页式管理
	
3.内存映射关系
	4g------------------------------------
                  4k
	 -----------------------------------
		       固定内存映射区 4m-4k
     -----------------------------------
	           高端内存映射区 4m(alloc_page)
	 ------------------------------------
				NULL 8K(保护)
	 ------------------------------------vmalloc  end
			 vmalloc内存区120m-8m-8k(低端或者高端内存)
	 ------------------------------------vmalloc  start
				vmalloc offset 8m
	 ------------------------------------
				物理内存映射区896M(kmalloc get_free_page低端内存)
   3g------------------------------------  物理内存 3g 偏移   4k + 3g
					用户空间
   0g------------------------------------
   
	
4.linux内存分配函数
	void *kmalloc(size_t s, gfp_t gfp)
	功能:分配对应的虚拟内存
	参数:size:分配内存区的大小(2的次幂,最大是128K,连续)
		  flags:内存分配标志
			  GFP_KERNEL:内核可能被休眠,进程上下文,不能用于中断上下文中
			  GFP_ATOMIC:处理紧急的事务,用在中断上下文
		  
	返回值:对应虚拟地址
	特点:最大128k   , 分配虚拟地址,其虚拟地址空间连续,物理地址空间也是连续
	类似函数:kzalloc:kmalloc+memset(buf,0,sizeof(buf));


	void kfree(const void *x)
	功能:释放对应的虚拟内存
	参数:x:虚拟内存的起始地址
	返回值:无
	
	void *vmalloc(unsigned long size)
	功能:分配对应的虚拟内存
	参数:size:分配内存区的大小
	返回值:对应虚拟地址
	特点:分配虚拟地址,其虚拟地址空间连续,但是物理地址空间不一定连续
	
	void vfree(const void *addr)
	功能:释放对应的虚拟内存
	参数:addr:虚拟内存区的首地址
	返回值:无
	
	unsigned long __get_free_page(gfp_t gfp)
	功能:分配一个物理页
	参数:
		@gfp
		GFP_KERNEL:内核可能被休眠,进程上下文,不能用于中断上下文中
		GFP_ATOMIC:处理紧急的事务,用在中断上下文
	void free_page(unsigned long addr)
	
	unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
	功能:分配多个物理页
	参数:
		@gfp_mask:
		GFP_KERNEL:内核可能被休眠,进程上下文,不能用于中断上下文中
		GFP_ATOMIC:处理紧急的事务,用在中断上下文
		@order:填写的是想分配内存的次值n=get_order(57600)
			57600 = 2^n
			
	void free_pages(unsigned long addr, unsigned long order)

[1]カメラドライバー
V4L2:Linuxのビデオ2:Linuxカーネルのカメラドライバーのフレームワークであり、
アプリケーションに/ dev / video0 提供ます。
1.video:カメラドライバー
2.vbi:垂直ブランキングビデオ信号(ケーブルテレビ)
3.radio:無線機器(radio)

虚拟摄像头:vivi
linux lxr :在线查看linux内核源码的网站:
https://lxr.missinglinkelectronics.com/linux/

1.下载虚拟摄像头驱动
	在网站中找到3.5内核的vivi.c的代码
	点击下载:vivi.c

2.使用Makefile对vivi.c进行编译
	编译完成之后生成vivi.ko

3.安装驱动
	insmod: error inserting 'vivi.ko': -1 Unknown symbol in module
	
	insmod安装驱动的时候不会安装依赖文件
	modprobe:在安装驱动的时候会检查依赖
	sudo modprobe -i vivi
	sudo modprobe -r vivi

	在安装成功之后就会产生一个/dev/video0的设备节点。
	
4.安装应用程序来读取摄像头的数据
	 sudo apt-get install xawtv
	 sudo apt-get install cheese

[2]カメラドライバー
1.カメラオブジェクト
struct video_device * vfd;
vfd = video_device_alloc();

2.初始化摄像头的对象
	static struct video_device vfd = {                                                       
		.name       = "vivi",
		.fops       = &vivi_fops,  //v4l2的操作方法结构体
		.ioctl_ops  = &vivi_ioctl_ops, //v4l2的ioctl函数
		.release    = video_device_release,
	};

3.注册
	video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);   
	完成摄像头设备的初始化
		__video_register_device(vdev, type, nr, 1, vdev->fops->owner);
	   switch (type) {
		case VFL_TYPE_GRABBER:                                                                         
			name_base = "video";  //注册的是摄像头设备驱动
			break;
		case VFL_TYPE_VBI:
			name_base = "vbi";   //场消隐设备驱动
			break;
		case VFL_TYPE_RADIO:     //无线电设备的驱动
			name_base = "radio";
			break;
		}

	  switch (type) {
		case VFL_TYPE_GRABBER:
			minor_offset = 0;
			minor_cnt = 64;
			break;
		case VFL_TYPE_RADIO:
			minor_offset = 64;                                                                         
			minor_cnt = 64;
			break;
		case VFL_TYPE_VBI:
			minor_offset = 224;
			minor_cnt = 32;
			break;
		}

	字符设备驱动的注册:
	static const struct file_operations v4l2_fops = {
		.read = v4l2_read,
		.write = v4l2_write,
		.open = v4l2_open,
		.mmap = v4l2_mmap,
		.unlocked_ioctl = v4l2_ioctl,
		.release = v4l2_release,
		.poll = v4l2_poll,
	};   
	
	vdev->cdev = cdev_alloc();
	vdev->cdev->ops = &v4l2_fops;
	ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
	#define VIDEO_MAJOR 81  摄像头的主设备号是81
	//创建了设备节点相当于class_create  device_create
	   vdev->dev.class = &video_class;
		vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
		if (vdev->parent)
			vdev->dev.parent = vdev->parent;
		dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
		ret = device_register(&vdev->dev);   

ユーザー:
open( "/ dev / video0")読み取り書き込みioctl close
---------- | ------------------------ ------------------------
|
字符设备驱动:v4l2_fops
static const struct file_operations v4l2_fops = { .read = v4l2_read、.write = v4l2_write、.open = v4l2_open、の.mmap = v4l2_mmap、.unlocked_ioctl = v4l2_ioctl、.release = v4l2_release、.poll = v4l2_poll、; 上述的オープン読み取りと書き込みのioctl ...会调用v4l2_file_operations ***************** ******************************************* static const struct v4l2_file_operations vivi_fops = { .open = v4l2_fh_open、.release = vivi_close、.read = vivi_read、.poll = vivi_poll、















.unlocked_ioctl = video_ioctl2、/ * V4L2 ioctlハンドラ* /
.mmap = vivi_mmap、
};

上述的ioctl函数会调用v4l2_ioctl_ops 
***************************************************************
static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_querycap      = vidioc_querycap,
//查询设备的类型是否是摄像头设备

.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
//枚举,获取,尝试,设置摄像头格式

.vidioc_reqbufs       = vidioc_reqbufs,
.vidioc_querybuf      = vidioc_querybuf,
.vidioc_qbuf          = vidioc_qbuf,
.vidioc_dqbuf         = vidioc_dqbuf, 
//申请,查询,存放,取出buf等操作

.vidioc_streamon      = vidioc_streamon,
.vidioc_streamoff     = vidioc_streamoff,
//启动关闭摄像头
};

おすすめ

転載: blog.csdn.net/weixin_48430195/article/details/108681530