Listing 2. epromdsk.c
/*
* linux/kernel/blk_drv/epromdsk.c
*
* from code by Theodore Ts'o, 12/2/91
* Dave Bennett 11/95
*
*/
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/ext2_fs.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
#define MAJOR_NR EPROM_MAJOR
#include "blk.h"
#define EPROMDISK_MINOR 1
#define EPROMIMAGE_MINOR 2
static int ed_length;
static int sector_map;
static int sector_offset;
static int ed_blocksizes[2] = {0, 0};
int get_edisk(unsigned char *buf, int sect, int num_sect);
int get_image(unsigned char *buf, int ofs, int len);
#define EPROM_WINDOW 0x0D0000
#define EPROM_START 0x080000
#define EPROM_START2 0x100000
#define EPROM_SIZE 0x100000
#define EPAGE_SIZE 0x010000
#define CONTROL_REG1 0x0274
#define CONTROL_REG2 0x0674
static void do_ed_request(void)
{
int len,
ofs;
repeat:
INIT_REQUEST;
ofs = CURRENT->sector << 9;
len = CURRENT->current_nr_sectors << 9;
/ if (!( (MINOR(CURRENT->dev) == EPROMDISK_MINOR) ||
(MINOR(CURRENT->dev) == EPROMIMAGE_MINOR) ) ||
(ofs+len > ed_length)) {
printk("EPROMDISK: minor=%d ofs=%d len=%d
ed_length=0x%x\n",MINOR(CURRENT->dev),ofs,len,ed_length);
end_request(0);
goto repeat;
}
if (CURRENT->cmd == READ) {
if (MINOR(CURRENT->dev) == EPROMDISK_MINOR) {
get_edisk(CURRENT->buffer,CURRENT->sector,CURRENT->current_nr_sectors);
}
if (MINOR(CURRENT->dev) == EPROMIMAGE_MINOR) {
get_image(CURRENT->buffer,ofs,len);
}
} else {
panic("EPROMDISK: unknown RAM disk command !\n");
}
end_request(1);
goto repeat;
}
static struct file_operations ed_fops = {
NULL, /* lseek - default */
block_read, /* read - general block-dev read */
NULL, /* write - general block-dev write */
NULL, /* readdir - bad */
NULL, /* select */
NULL, /* ioctl */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
NULL /* fsync */
};
/*
* Returns amount of memory which needs to be reserved.
*/
long ed_init(long mem_start, int mem_end)
{
int i,
ep;
short version,
length,
s_ofs;
if (register_blkdev(EPROM_MAJOR,"ed",&ed_fops)) {
printk("EPROMDISK: Unable to get major %d.\n",
EPROM_MAJOR);
return 0;
}
blk_dev[EPROM_MAJOR].request_fn = DEVICE_REQUEST;
for(i=0;i<2;i++) ed_blocksizes[i] = 1024;
blksize_size[MAJOR_NR] = ed_blocksizes;
/* Search for valid eprom disk */
ep = EPROM_START;
get_image((unsigned char *)&version,ep,sizeof(version));
if (version != 2) { /* Didnt find it */
ep = EPROM_START2;
get_image((unsigned char *)&version,ep,sizeof(version));
if (version != 2) { /* Didnt find it */
printk("EPROMDISK: Unable to find EPROM\n");
return 0;
}
}
get_image((unsigned char *)&length,ep+2,sizeof(length));
get_image((unsigned char *)&s_ofs,ep+4,sizeof(s_ofs));
if (length < 4) {
printk("EPROMDISK: Length (%d) Too short.\n", length);
return 0;
}
ed_length = length * 512;
sector_map = ep + 6;
sector_offset = ep + s_ofs;
printk("EPROMDISK: Version %d installed, %d bytes\n", (int)version,
ed_length);
return 0;
}
int get_edisk(unsigned char *buf, int sect, int num_sect)
{
short ss; /* Sector start */
int s; /* Sector offset */
for(s=0;s<num_sect;s++) {
get_image((unsigned char *)&ss,sector_map +
(s+sect)*sizeof(short), 2);
get_image(buf+s*512,sector_offset + (int)ss*512,512);
}
return 0;
}
int get_image(unsigned char *buf, int ofs, int len)
{
static int socket[4] = {0x00,0x01,0x04,0x05};
int nb,
bp,
bofs,
sock,
page,
offset,
cr1,
cr2;
bp = ofs;
bofs = 0;
for(;len>0;) {
sock = bp / EPROM_SIZE;
page = (bp % EPROM_SIZE) / EPAGE_SIZE;
offset = bp % EPAGE_SIZE;
nb =
(len+offset)>EPAGE_SIZE?EPAGE_SIZE-(offset%EPAGE_SIZE):len;
cr1 = socket[sock] | ((page << 4) & 0x30) | 0x40;
/* no board select for now */
cr2 = (page >> 2) & 0x03;
outb((char)cr1,CONTROL_REG1);
outb((char)cr2,CONTROL_REG2);
memcpy(buf+bofs,(char *)(EPROM_WINDOW + offset),nb);
len -= nb;
bp += nb;
bofs += nb;
}
return 0;
}