linux系统下块设备驱动程序
顾名思义,块设备驱动程序就是支持以块的方式进行读写的设备。块设备和字符设备最大的区别在于读写数据的基本单元不同。块设备读写数据的基本单元为块,例 如磁盘通常为一个sector,而字符设备的基本单元为字节。从实现角度来看,字符设备的实现比较简单,内核例程和用户态API一一对应,这种映射关系由 字符设备的file_operations维护。块设备接口则相对复杂,读写API没有直接到块设备层,而是直接到文件系统 层,然后再由文件系统层发起读写请求。
源代码(ramdisk.c)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h> #include <linux/fs.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/vmalloc.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h> #define RAMHD_NAME "ramhd"
#define RAMHD_MAX_DEVICE 2
#define RAMHD_MAX_PARTITIONS 4 #define RAMHD_SECTOR_SIZE 512
#define RAMHD_SECTORS 16
#define RAMHD_HEADS 4
#define RAMHD_CYLINDERS 256 #define RAMHD_SECTOR_TOTAL (RAMHD_SECTORS * RAMHD_HEADS *RAMHD_CYLINDERS)
#define RAMHD_SIZE (RAMHD_SECTOR_SIZE * RAMHD_SECTOR_TOTAL) //8mb typedef struct {
unsigned char* data;
struct request_queue* queue;
struct gendisk* gd;
}RAMHD_DEV; static char* sdisk[RAMHD_MAX_DEVICE] = {NULL};
static RAMHD_DEV* rdev[RAMHD_MAX_DEVICE] = {NULL}; static dev_t ramhd_major; static int ramhd_space_init(void)
{
int i;
int err = ;
for(i = ; i < RAMHD_MAX_DEVICE; i++){
sdisk[i] = vmalloc(RAMHD_SIZE);
if(!sdisk[i]){
err = -ENOMEM;
return err;
} memset(sdisk[i], , RAMHD_SIZE);
} return err;
} static void ramhd_space_clean(void)
{
int i;
for(i = ; i < RAMHD_MAX_DEVICE; i++){
vfree(sdisk[i]);
}
} static int ramhd_open(struct block_device* bdev, fmode_t mode)
{
return ;
} static int ramhd_release(struct gendisk*gd, fmode_t mode)
{
return ;
} static int ramhd_ioctl(struct block_device* bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
{
int err;
struct hd_geometry geo; switch(cmd)
{
case HDIO_GETGEO:
err = !access_ok(VERIFY_WRITE, arg, sizeof(geo));
if(err)
return -EFAULT; geo.cylinders = RAMHD_CYLINDERS;
geo.heads = RAMHD_HEADS;
geo.sectors = RAMHD_SECTORS;
geo.start = get_start_sect(bdev); if(copy_to_user((void*)arg, &geo, sizeof(geo)))
return -EFAULT; return ;
} return -ENOTTY;
} static struct block_device_operations ramhd_fops = {
.owner = THIS_MODULE,
.open = ramhd_open,
.release = ramhd_release,
.ioctl = ramhd_ioctl,
}; static int ramhd_make_request(struct request_queue* q, struct bio* bio)
{
char* pRHdata;
char* pBuffer;
struct bio_vec* bvec;
int i;
int err = ; struct block_device* bdev = bio->bi_bdev;
RAMHD_DEV* pdev = bdev->bd_disk->private_data; if(((bio->bi_sector * RAMHD_SECTOR_SIZE) + bio->bi_size) > RAMHD_SIZE){
err = -EIO;
return err;
} pRHdata = pdev->data + (bio->bi_sector * RAMHD_SECTOR_SIZE);
bio_for_each_segment(bvec, bio, i){
pBuffer = kmap(bvec->bv_page) + bvec->bv_offset;
switch(bio_data_dir(bio)){
case READ:
memcpy(pBuffer, pRHdata, bvec->bv_len);
flush_dcache_page(bvec->bv_page);
break; case WRITE:
flush_dcache_page(bvec->bv_page);
memcpy(pRHdata, pBuffer, bvec->bv_len);
break; default:
kunmap(bvec->bv_page);
goto out;
} kunmap(bvec->bv_page);
pRHdata += bvec->bv_len;
} out:
bio_endio(bio, err);
return ;
} static int alloc_ramdev(void)
{
int i;
for(i = ; i < RAMHD_MAX_DEVICE; i++){
rdev[i] = kzalloc(sizeof(RAMHD_DEV), GFP_KERNEL);
if(!rdev[i]){
return -ENOMEM;
}
} return ;
} static void clean_ramdev(void)
{
int i; for(i = ; i < RAMHD_MAX_DEVICE; i++){
if(rdev[i])
kfree(rdev[i]);
}
} static int __init ramhd_init(void)
{
int i; ramhd_space_init();
alloc_ramdev(); ramhd_major = register_blkdev(, RAMHD_NAME); for(i = ; i < RAMHD_MAX_DEVICE; i++){
rdev[i]->data = sdisk[i];
rdev[i]->queue = blk_alloc_queue(GFP_KERNEL);
blk_queue_make_request(rdev[i]->queue, ramhd_make_request); rdev[i]->gd = alloc_disk(RAMHD_MAX_PARTITIONS);
rdev[i]->gd->major = ramhd_major;
rdev[i]->gd->first_minor = i * RAMHD_MAX_PARTITIONS;
rdev[i]->gd->fops = &ramhd_fops;
rdev[i]->gd->queue = rdev[i]->queue;
rdev[i]->gd->private_data = rdev[i];
sprintf(rdev[i]->gd->disk_name, "ramhd%c", 'a' +i);
rdev[i]->gd->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
set_capacity(rdev[i]->gd, RAMHD_SECTOR_TOTAL);
add_disk(rdev[i]->gd);
} return ;
} static void __exit ramhd_exit(void)
{
int i;
for(i = ; i < RAMHD_MAX_DEVICE; i++){
del_gendisk(rdev[i]->gd);
put_disk(rdev[i]->gd);
blk_cleanup_queue(rdev[i]->queue);
} clean_ramdev();
ramhd_space_clean();
unregister_blkdev(ramhd_major, RAMHD_NAME);
} module_init(ramhd_init);
module_exit(ramhd_exit); MODULE_AUTHOR("dennis__chen@ AMDLinuxFGL");
MODULE_DESCRIPTION("The ramdisk implementation with request function");
MODULE_LICENSE("GPL");
Makefile文件
ifneq ($(KERNELRELEASE),)
obj-m := ramdisk.o else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.* Module.*
endif
操作步骤
先把Makefile 和ramdisk.c放在同一个文件夹下,然后make,
用ls命令看是否生成ramdisk.ko驱动模块
insmod ramdisk.ko //动态挂载驱动模块
lsmod //查看是否多了个ramdisk 模块
ls /dev //查看一下/dev目录下是否多了个block_dev节点(节点会自动创建)
mkfs.ext3 /dev/block_dev //在虚拟磁盘上建立ext3文件系统
mount /dev/block_dev /mnt/test //挂载到/mnt/test目录下,然后去看看mnt/test下面是不是多了lost+found文件夹
终端敲入mount,看一下mount的记录,是不是ext3格式
对它进行读写:
#cp *.c /mnt/test
#ls /mnt/test 看内容是否写过去了
#cp su.c /
#ls /su.c 看是否读OK
操作完之后就清除掉
umount /mnt/test
rmmod ramdisk.ko
linux系统下块设备驱动程序的更多相关文章
- 深入理解Linux内核-块设备驱动程序
扇区: 1.硬盘控制器将磁盘看成一大组扇区2.扇区就是一组相邻字节3.扇区按照惯例大小设置位512字节4.存放在块设备中的数据是通过它们在磁盘上的位置来标识,即首个扇区的下标和扇区的数目.5.扇区是硬 ...
- 【驱动】linux系统下nand flash驱动程序框架
linux操作系统下nand flash驱动框架 当我们需要在操作系统上读写普通文件的时候,总是需要一层层往下,最终到达硬件相关操作,当然底层设备大多数都是块设备 NAND FLASH就作为一个最底层 ...
- python基础——Linux系统下的文件目录结构
单用户操作系统和多用户操作系统 单用户操作系统:指一台计算机在同一时间只能由一个用户使用,一个用户独自享用系统的全部硬件和软件资源. 多用户操作系统:指一台计算机在同一时间可以由多个用户使用,多个用户 ...
- Linux中块设备驱动程序分析
基于<Linux设备驱动程序>书中的sbull程序以对Linux块设备驱动总结分析. 開始之前先来了解这个块设备中的核心数据结构: struct sbull_dev { i ...
- 【DSP开发】【Linux开发】Linux下PCI设备驱动程序开发
PCI是一种广泛采用的总线标准,它提供了许多优于其它总线标准(如EISA)的新特性,目前已经成为计算机系统中应用最为广泛,并且最为通用的总线标准.Linux的内核能较好地支持PCI总线,本文以Inte ...
- 最全最详细:ubuntu16.04下linux内核编译以及设备驱动程序的编写(针对新手而写)
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...
- linux 系统下有sda和hda的硬件设备分别代表什么意思
linux 系统下有sda和hda的硬件设备分别代表什么意思/dev/sda1 # SCSI设备,sda,sdb,sdc,三块盘,1,2,3代表分区(PV)/dev/sda2/dev/sdb1/dev ...
- Linux下PCI设备驱动程序开发 --- PCI驱动程序实现(三)
三.PCI驱动程序实现 1. 关键数据结构 PCI设备上有三种地址空间:PCI的I/O空间.PCI的存储空间和PCI的配置空间.CPU可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给 ...
- (linux)块设备驱动程序
1.4.1 Linux块设备驱动程序原理(1) 顾名思义,块设备驱动程序就是支持以块的方式进行读写的设备.块设备和字符设备最大的区别在于读写数据的基本单元不同.块设备读写数据的基本单元为块,例如 ...
随机推荐
- hibernate_08_关联映射_一对多
hibernate的映射关系 一对多.多对一.一对一.多对多. 常用的是一对多和多对一. 在数据库中可以通过添加主外键的关联,表现一对多的关系:在hibernate中通过在一方持有多方的集合实现,即在 ...
- 2星|《10W+走心文案是怎样炼成的》:标题党。实际是台湾创意总监的一些人生感悟和两三个很一般的创意文案
10W+走心文案是怎样炼成的 作者是台湾人,曾在台湾奥美担任创意总监,做过一些广告.本书是他的一些经验介绍. 总体来说是标题党,作者的广告基本是电视广告,跟文案也有关系,估计播放量也很容易过10W+, ...
- 教材配套PPT初稿
1-10章初稿,基本完整.有些粗糙,后面可能会稍作调整. 附更新情况如下: 1.增加了第10章内容: 2.第5章增加了一些内容: 3.第3章内容部分更新: 4.增加了第8-9章内容. 订正:更新了第8 ...
- Tinyxml2学习
转自http://www.360doc.com/content/13/1223/16/3684846_339528825.shtml,尊重原文 什么是XML? XML全称EXtensible Mark ...
- Vim入门基础知识集锦
1. 简介 Vim(Vi[Improved])编辑器是功能强大的跨平台文本文件编辑工具,继承自Unix系统的Vi编辑器,支持Linux/Mac OS X/Windows系统,利用它可以建立.修 ...
- LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度 LCT+SAM+线段树
Code: #include<bits/stdc++.h> #define maxn 200003 using namespace std; void setIO(string s) { ...
- Day 20 re模块(正则表达式)
re模块 作用:取文本或者字符串内找你所需要的东西 import re re.findall(参数一,参数二,参数三) #暂时用到前两个,第一个为正则表达式,第二个为字符串,也就是被搜索的文本 ^元字 ...
- loadrunner录制不了浏览器
Loadrunner11.0启动WebTours之总结1 第一次安装LR11时,安装安组件后没有对电脑进行重启,直接安装的LR112 安装完毕LR后,录制脚本时发现不能启动IE11.百度发现LR支持I ...
- ext4的一些特性
delalloc介绍 delalloc是ext4下的一个新特性,延迟分配技术Delay Allocation. 实现原理为: Buffer Write时数据会被保存到page cache中,但是系统并 ...
- 关于如何利用js判断IE浏览器各种版本问题
<!--[if IE 6]> IE 浏览器版本 6 <![endif]--> <!--[if IE 7]> IE 浏览器版本 7 <![endif]--& ...