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