Linux 块设备驱动 实例

任务:用一片虚拟地址连续的内存空间模拟一个块设备,并为其写一个驱动

/*
 * 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;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwsdjs.html