任务:用一片虚拟地址连续的内存空间模拟一个块设备,并为其写一个驱动
/*
* Sample disk driver, from the beginning.
*/
#include <linux/autoconf.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/timer.h>
#include <linux/types.h> /* size_t */
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/kdev_t.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h> /* invalidate_bdev */
#include <linux/bio.h>
MODULE_LICENSE("Dual BSD/GPL");
static int sbull_major = 0;
module_param(sbull_major, int, 0);
static int hardsect_size = 512;
module_param(hardsect_size, int, 0);
static int nsectors = 25600; /* How big the drive is */
module_param(nsectors, int, 0);
static int ndevices = 1;
module_param(ndevices, int, 0);
/*
* The different "request modes" we can use.
*/
enum {
RM_SIMPLE = 0, /* The extra-simple request function */
RM_FULL = 1, /* The full-blown version */
RM_NOQUEUE = 2, /* Use make_request */
};
//static int request_mode = RM_FULL;
static int request_mode = RM_SIMPLE;
//static int request_mode = RM_SIMPLE;
module_param(request_mode, int, 0);
/*
* Minor number and partition management.
*/
#define SBULL_MINORS 16
#define MINOR_SHIFT 4
#define DEVNUM(kdevnum) (MINOR(kdev_t_to_nr(kdevnum)) >> MINOR_SHIFT
/*
* We can tweak our hardware sector size, but the kernel talks to us
* in terms of small sectors, always.
*/
#define KERNEL_SECTOR_SIZE 512
/*
* After this much idle time, the driver will simulate a media change.
*/
#define INVALIDATE_DELAY 60*HZ
/*
* The internal representation of our device.
*/
struct sbull_dev {
int size; /* Device size in sectors */
// data 是本程序模拟的块设备,是一片连续的虚拟空间
// 在初始化函数里分配的虚拟地址连续的内存空间
u8 *data; /* The data array */
short users; /* How many users */
short media_change; /* Flag a media change? */
spinlock_t lock; /* For mutual exclusion */
struct request_queue *queue; /* The device request queue */
struct gendisk *gd; /* The gendisk structure */
struct timer_list timer; /* For simulated media changes */
};
static struct sbull_dev *Devices = NULL;
/*
* Handle an I/O request.
*/
static void sbull_transfer(struct sbull_dev *dev, unsigned long sector,
unsigned long nsect, char *buffer, int write)
{
unsigned long offset = sector*KERNEL_SECTOR_SIZE; // 需要读写的扇区的偏移地址
unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE; // 需要读写的字节数
if ((offset + nbytes) > dev->size) { // 判断输入参数是否合法,是否超出边界
printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
return;
}
// 实际的读写操作
// 由于本程序是用一片连续的内存空间模拟块设备
// 所以这里对硬件(内存空间)的读写操作,就是复制内存
// 在具体点,就是下面的memcpy
// 具体的项目,需修改为具体的接口函数
if (write)
// 写
memcpy(dev->data + offset, buffer, nbytes);
else
// 读
memcpy(buffer, dev->data + offset, nbytes);
}
/*The simple form of the request function.*/
static void sbull_request(struct request_queue *q)
{
struct request *req;