#ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE #define MODULE #endif
#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> /* printk() */ #include <linux/init.h> /* __init __exit */
#include <linux/types.h> /* size_t */ #include <linux/fs.h> /* file_operation */ #include <linux/blk.h> #include <linux/hdreg.h> /* geo */ //#include /* Error number */
//#include /* udelay */
#include <asm/uaccess.h> /* copy_to_user, copy_from_user */
#define DRIVER_NAME "Ram Disk" #define PRINTK(fmt, arg...) printk(KERN_NOTICE fmt, ##arg) static int myBlockDriver_Major = 0; /* Driver Major Number */
/* Vitual Driver Buffer */ #define NUM_RAMDISKS 1 #define DISK_SIZE (1UL*1024UL*1024UL) #define BYTE_PER_SECTOR (512) static unsigned char rd_buffer[NUM_RAMDISKS][DISK_SIZE];/* Vitual Buffer */ static unsigned long rd_length[NUM_RAMDISKS]; /* Size of RAM disks in bytes */ static int rd_hardsec[NUM_RAMDISKS]; /* Size of real blocks in bytes */ static int rd_blocksizes[NUM_RAMDISKS]; /* Size of 1024 byte blocks :) */ static int rd_kbsize[NUM_RAMDISKS]; /* Size in blocks of 1024 bytes */ //static devfs_handle_t devfs_handle;
//static struct block_device *rd_bdev[NUM_RAMDISKS]; /* Protected device data */
/* Block Driver Operation Functions */ static int myBlockDriver_open(struct inode *inode, struct file *filp) { int Minor = MINOR(inode->i_rdev); //这里的从设备号是有意义的,和字符设备要区分,
if (Minor >= NUM_RAMDISKS) //这里从设备号可以用来区别具体的盘符。
return -ENXIO; MOD_INC_USE_COUNT; PRINTK("myBlockDriver open called!\n"); return 0; }
static int myBlockDriver_release(struct inode *inode, struct file *filp) { int Minor = MINOR(inode->i_rdev); //这里的从设备号是有意义的,和字符设备要区分,
if (Minor >= NUM_RAMDISKS) return -ENXIO; MOD_DEC_USE_COUNT; PRINTK("myBlockDriver release called!\n"); return 0; }
static int myBlockDriver_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int error = -EINVAL; int Minor; //对一些命令的响应
// long size;
struct hd_geometry geo;
PRINTK("myBlockDriver ioctl called(%d)!\n", cmd); if (!inode || !inode->i_rdev) return error;
Minor = MINOR(inode->i_rdev); switch(cmd) { case BLKGETSIZE: /* Return device size */ if (!arg) break; error = put_user(rd_kbsize[Minor] << 1, (unsigned long *) arg); error = 0; break; case BLKGETSIZE64: error = put_user((u64)rd_kbsize[Minor]<<10, (u64*)arg); break; case HDIO_GETGEO: PRINTK("HDIO_GETGEO called!\n"); geo.cylinders = rd_length[Minor] >> 6;// 除(4*16)相当于右移6位
geo.heads = 4; geo.sectors = 16; geo.start = 0; copy_to_user((void *)arg, &geo, sizeof(geo)); break; default: return blk_ioctl(inode->i_rdev, cmd, arg); } return error; }
static int myBlockDriver_check_media_change(kdev_t dev)//对于热插拔的设备需要在这里填充代码
{ return 0; }
static int myBlockDriver_revalidate(kdev_t dev)//通常的磁盘的大小、具体数据信息的更新在这里完成
{ return 0; }
/* Block Driver Operation structure */ static struct block_device_operations myBlockDriver_fops = { owner: THIS_MODULE, open: myBlockDriver_open, release: myBlockDriver_release, ioctl: myBlockDriver_ioctl, check_media_change:myBlockDriver_check_media_change, revalidate: myBlockDriver_revalidate, };
/* Block Driver Data Transfer Function */ static int myBlockDriver_make_request(request_queue_t *queue, int rw, struct buffer_head *bh) { unsigned long flag; int Minor = MINOR(bh->b_rdev); long offset = bh->b_rsector * 512; /* 0 means the start sector of the disk*/ unsigned char *start_addr = bh->b_data; size_t len = bh->b_size;
switch(rw) { case READA: case READ: local_irq_save(flag);//进入临界区
memcpy(start_addr, &rd_buffer[Minor][offset], len); local_irq_restore(flag);//推出临界区
bh->b_end_io(bh, 1);//调用回调函数,通知内核成功完成操作
break; case WRITE: local_irq_save(flag); memcpy(&rd_buffer[Minor][offset], start_addr, len); local_irq_restore(flag); bh->b_end_io(bh, 1); break; default: bh->b_end_io(bh,0); break; } return 0; }
/* Module Init & Exit function */ #ifdef CONFIG_DEVFS_FS devfs_handle_t devfs_myDriver_dir; #endif static int __init myModule_init(void) { int i; /* Module init code */ PRINTK("myModule_init\n"); /* Init device structure*/ for(i = 0; i < NUM_RAMDISKS; i++) { rd_length[i] = DISK_SIZE; /* Size of RAM disks in bytes */ rd_hardsec[i] = BYTE_PER_SECTOR; /* Size of real blocks in bytes */ rd_blocksizes[i] = 1024; /* Size of 1024 byte blocks :) */ rd_kbsize[i] = DISK_SIZE/1024; /* Size in blocks of 1024 bytes */ } /* Driver register */ myBlockDriver_Major = register_blkdev(0, DRIVER_NAME, &myBlockDriver_fops); if(myBlockDriver_Major < 0) { PRINTK("register char device fail!\n"); return myBlockDriver_Major; } PRINTK("register myDriver OK! Major = %d\n", myBlockDriver_Major); //一下的部分是字符型设备与块设备最主要区别的地方,真正的数据传输在这里发生。
//调用blk_queue_make_request来替换内核的make_request
blk_queue_make_request(BLK_DEFAULT_QUEUE(myBlockDriver_Major), myBlockDriver_make_request); PRINTK("register make request function OK\n"); #ifdef CONFIG_DEVFS_FS devfs_myDriver_dir = devfs_mk_dir(NULL, "blkdrv", NULL); devfs_register_series(devfs_myDriver_dir, "%u", NUM_RAMDISKS, DEVFS_FL_DEFAULT, myBlockDriver_Major, 0, S_IFBLK | S_IRUSR | S_IWUSR, &myBlockDriver_fops, NULL); PRINTK("add dev file OK!\n"); #endif return 0; }
static void __exit myModule_exit(void) { /* Module exit code */ PRINTK("myModule_exit\n"); /* Driver unregister */ if(myBlockDriver_Major > 0) { #ifdef CONFIG_DEVFS_FS devfs_unregister(devfs_myDriver_dir); #endif unregister_blkdev(myBlockDriver_Major, DRIVER_NAME); } return; }
MODULE_AUTHOR("xxxx"); MODULE_LICENSE("Dual BSD/GPL"); module_init(myModule_init); module_exit(myModule_exit);
|