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) 顾名思义,块设备驱动程序就是支持以块的方式进行读写的设备.块设备和字符设备最大的区别在于读写数据的基本单元不同.块设备读写数据的基本单元为块,例如 ...
随机推荐
- 酷派 5267 刷入第三方 recovery教程 刷机 ROOT
准备工作: 一台电脑: 酷派5267手机: 一张内存卡: 下载好刷机资料: http://pan.baidu.com/s/1i4LoVh7 备用下载: http://pan.baidu.com/s/ ...
- WinXP SSH连接不上虚拟机的解决方法
问题现象描述: 在VMWare中安装好linux系统后,选择桥接,从宿主机Windows上使用Putty, SSH Secure Shell等客户端工具连接linux上的ssh服务,客户端一直没有反应 ...
- In Swift, typedef is called typealias:
It is used to create an alias name for another data type. The syntax of the typedef declaration is:[ ...
- java操作Excel的poi 格式设置
格式设置 package com.java.poi; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi. ...
- Java基础学习笔记三 正则表达式和校验、Date、DateFormat、Calendar
正则表达式 正则表达式(英语:Regular Expression,在代码中常简写为regex).正则表达式是一个字符串,使用单个字符串来描述.用来定义匹配规则,匹配一系列符合某个句法规则的字符串.在 ...
- Pytorch基础(5)——批数据训练
一.知识点: 相关包:torch.utils.data import torch import torch.utils.data as Data 包装数据类:TensorDataset [包装数据和目 ...
- LA 4327
Panagola, The Lord of city F likes to parade very much. He always inspects his city in his car and e ...
- [jzoj 5775]【NOIP2008模拟】农夫约的假期 (前缀和+递推)
传送门 Description 在某国有一个叫农夫约的人,他养了很多羊,其中有两头名叫mm和hh,他们的歌声十分好听,被当地人称为"魔音"······ 农夫约也有自己的假期呀!他要 ...
- cd:切换目录
cd命令 1.命令详解 [功能说明] cd命令是“change directory”中每个单词的首字母缩写,其功能是从当前工作目录切换到指定的工作目录. [语法格式] cd [option] ...
- mysql 怎样先排序再分组
权游游牧族:众所周知!一句SqL语句不能先排序再分组.所以这里给出几个案例 --表结构-- create table `shop` ( `id` int (10) PRIMARY KEY, `shop ...