📄 nvram.txt
字号:
#define MODULE
#include <linux/ioport.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/errno.h> /* error codes */
#include <linux/timer.h>
#include <linux/types.h> /* size_t */
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/kdev_t.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#define MAJOR_NR rd_major /* force definitions on in blk.h */
static int rd_major; /* must be declared before including blk.h */
MODULE_LICENSE("Dual BSD/GPL");
static unsigned long port_addr=0x148; /*ioport address*/
static unsigned int ctlmask=0xc0; /*a part of control signal of nvram stand for 0x1100000*/
static unsigned long mem_addr=0xD0000; /*io memory address*/
static unsigned long mem_len=0x10000; /*io memory lenth*/
static char *ptr; /*the point for the ioremap*/
static int major=0;
static int hardsect=512;
static int rd_make_request(request_queue_t *queue, int rw, struct buffer_head *bh)
{
char *rdptr,*result;
unsigned long offset; /*the offset in one 64K window*/
unsigned long index; /*the number of the window in all 64 windows in this request*/
int time; /*how many times the ioremap will do */
int i;
unsigned long r_size; /*the size of data in one request*/
unsigned long t_size; /*the size of data in one tansfer*/
/*check if the request out of the disk size or not*/
if (bh->b_rsector * hardsect+bh->b_size > 0x400000) {
static int count = 0;
if (count++ < 5)
printk("ram: request past end of device\n");
bh->b_end_io(bh, 0);
return 0;
}
offset=(bh->b_rsector * hardsect) & (mem_len-1); /*get the offset in this request*/
index=(bh->b_rsector * hardsect)>>16; /*get the index in this request*/
rdptr = ptr + offset; /*get the actual address in the memory*/
r_size=bh->b_size; /*record the size of data for translation in r_size*/
if(r_size>(mem_len-offset)){ /*calculate the variable time*/
time=(r_size-(mem_len-offset))>>16 + 2;
}else time=1;
/* Do the transfer */
switch(rw) {
/*read progess*/
case READ:
case READA: /* Readahead */
while(time){
outb(index|ctlmask,port_addr);
if(time==1) t_size=r_size;
else t_size=mem_len-offset;
result=memcpy_fromio(bh->b_data,rdptr,t_size);
r_size-=t_size;
time--;
index++;
offset=0;
}
bh->b_end_io(bh, 1);
break;/*read end*/
/*write progess*/
case WRITE:
refile_buffer(bh);
while(time){
outb(index|ctlmask,port_addr);
if(time==1)t_size=r_size;
else t_size=mem_len-offset;
result=memcpy_toio(rdptr,bh->b_data,t_size);
r_size-=t_size;
time--;
index++;
offset=0;
}
mark_buffer_uptodate(bh, 1);
bh->b_end_io(bh, 1);
break;/*write end*/
default:
/* can't happen */
bh->b_end_io(bh, 0);
break;
}
return 0;
}
int rd_open(struct inode *inode, struct file *filp)
{
MOD_INC_USE_COUNT;
return 0;
}
int rd_release(struct inode *inode, struct file *filp)
{
MOD_DEC_USE_COUNT;
return 0;
}
int rd_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
int err;
long size; /*amount of hardsects*/
struct hd_geometry geo;
printk("ioctl 0x%x 0x%lx\n", cmd, arg);
switch(cmd) {
case BLKGETSIZE:
/* Return the device size, expressed in sectors */
if (!arg) return -EINVAL; /* NULL pointer: not valid */
err = ! access_ok (VERIFY_WRITE, arg, sizeof(long));
if (err) return -EFAULT;
size = 0x400000/512;
if (copy_to_user((long *) arg, &size, sizeof (long)))
return -EFAULT;
return 0;
case BLKRRPART: /* re-read partition table: can't do it */
return -ENOTTY;
case HDIO_GETGEO:
/*
* Get geometry: since we are a virtual device, we have to make
* up something plausible. So we claim 16 sectors, four heads,
* and calculate the corresponding number of cylinders. We set the
* start of data at sector four.
*/
err = ! access_ok(VERIFY_WRITE, arg, sizeof(geo));
if (err) return -EFAULT;
size = 0x400000/512;
geo.cylinders = (size & ~0x3f) >> 6;
geo.heads = 4;
geo.sectors = 16;
geo.start = 4;
if (copy_to_user((void *) arg, &geo, sizeof(geo)))
return -EFAULT;
return 0;
default:
/*
* For ioctls we don't understand, let the block layer handle them.
*/
return blk_ioctl(inode->i_rdev, cmd, arg);
}
return -ENOTTY; /* unknown command */
}
struct block_device_operations rd_bdops ={
open: rd_open,
release: rd_release,
ioctl: rd_ioctl,
check_media_change: NULL,
revalidate: NULL,
};
static int rd_init(void){
int result;
int rd_major=major;
/*check the io memory*/
if(check_mem_region(mem_addr,mem_len)){
printk("memory busy\n");
return -1;
}
/*request the io memory*/
request_mem_region(mem_addr,mem_len,"NVRAM DRIVER");
/*mapping*/
outb(ctlmask,port_addr);
ptr=ioremap(mem_addr,mem_len);
printk("Virtual Memory Address: 0x%x\n",ptr);
/*register the device*/
result = register_blkdev(rd_major, "nvram", &rd_bdops);
if (result < 0) {
printk("Nvram: can't get major %d\n",rd_major);
return result;
}
if (rd_major == 0) rd_major = result; /* dynamic */
major = rd_major;
printk("Devie Major Number: %d\n",major);
/*register the request*/
blk_queue_make_request(BLK_DEFAULT_QUEUE(major), rd_make_request);
/*register the disk*/
register_disk(NULL, MKDEV(rd_major, 0),1, &rd_bdops, 0x400000);
printk("Nvram is Initialized\n");
return 0;
}
static void rd_exit(void){
fsync_dev(MKDEV(major, 0)); /*reflash the device*/
unregister_blkdev(major,"nvram"); /*unregister the device*/
iounmap(ptr); /**/
release_mem_region(mem_addr,mem_len); /*release the io memory*/
printk("Devie release...OK!\n");
}
module_init(rd_init);
module_exit(rd_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -