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