实验描述:
块设备驱动程序(模拟内存)
内核版本:
Linux 2.6.38
开发板:
Mini 6410
程序实现:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
#define PRINTK printk
//#define PRINTK(...)
#define DEVICE_NAME "6410_ram_block"
#define RAMBLOCK_SIZE (1024*1024)
static int major;
static DEFINE_SPINLOCK(s3c6410_ram_lock);
static struct gendisk *s3c6410_ram_gendisk;
static struct request_queue *ramblock_queue;
static unsigned char *ramblock_buf;
static void do_ram_blk_request(struct request_queue *queue)
{
struct request *req;
static int r_cnt = 0;
static int w_cnt = 0;
while((req = blk_fetch_request(queue))){
int err = 0;
unsigned long offset = blk_rq_pos(req) << 9; //address
unsigned long len = blk_rq_cur_bytes(req);//len
if (rq_data_dir(req) == READ)
{
printk("do_ramblock_request read %d\n", ++r_cnt);
memcpy(req->buffer, ramblock_buf+offset, len);
}
else
{
printk("do_ramblock_request write %d\n", ++w_cnt);
memcpy(ramblock_buf+offset, req->buffer, len);
}
if (!__blk_end_request_cur(req, err))
req = blk_fetch_request(queue);
}
PRINTK(KERN_ALERT"do_ram_blk_request!\n");
}
static int ram_blk_getgeo(struct block_device *block_device, struct hd_geometry *hd_geometry)
{
hd_geometry->heads = 2; //fdisk
hd_geometry->cylinders = 32;
hd_geometry->sectors = RAMBLOCK_SIZE/2/32/512;
PRINTK(KERN_ALERT"ram_blk_getgeo!\n");
return 0;
}
static const struct block_device_operations s3c6410_ram_fops =
{
.owner = THIS_MODULE,
.getgeo = ram_blk_getgeo,
};
static int blk_driver_init(void)
{
int ret;
ret = -EBUSY;
if ((major = register_blkdev(0, DEVICE_NAME)) < 0)
goto out_err;
ret = -ENOMEM;
s3c6410_ram_gendisk = alloc_disk(16);//this will alloc minors
if (!s3c6410_ram_gendisk)
goto out_err;
ramblock_queue = blk_init_queue(do_ram_blk_request, &s3c6410_ram_lock);
if (!ramblock_queue)
goto out_err;
s3c6410_ram_gendisk->major = major;
s3c6410_ram_gendisk->first_minor = 2;
s3c6410_ram_gendisk->fops = &s3c6410_ram_fops;
s3c6410_ram_gendisk->queue = ramblock_queue;
sprintf(s3c6410_ram_gendisk->disk_name, "my_blk_ram");
ret = -ENOMEM;
ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL); //this will do handware settings, as we only do some request mem
if(!ramblock_buf){
goto out_err;
}
add_disk(s3c6410_ram_gendisk);
PRINTK(KERN_ALERT"init!\n");
return 0;
out_err:
if(major)
unregister_blkdev(major, DEVICE_NAME);
if (s3c6410_ram_gendisk)
put_disk(s3c6410_ram_gendisk);
if(ramblock_buf)
kfree(ramblock_buf);
if(ramblock_queue)
blk_cleanup_queue(ramblock_queue);
return ret;
}
static int blk_driver_exit(void)
{
if(major)
unregister_blkdev(major, DEVICE_NAME);
if (s3c6410_ram_gendisk){
del_gendisk(s3c6410_ram_gendisk);
put_disk(s3c6410_ram_gendisk);
}
if(ramblock_buf)
kfree(ramblock_buf);
if(ramblock_queue)
blk_cleanup_queue(ramblock_queue);
PRINTK(KERN_ALERT"exit!\n");
return 0;
}
module_init(blk_driver_init);
module_exit(blk_driver_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("S3C6410 block device driver");
MODULE_AUTHOR("Books, <uppour@sina.cn>");