OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/trunk/ecos-2.0/packages/redboot/v2_0/src/fs
    from Rev 1254 to Rev 1765
    Reverse comparison

Rev 1254 → Rev 1765

/e2fs.c
0,0 → 1,613
//==========================================================================
//
// e2fs.c
//
// RedBoot support for second extended filesystem
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2003 Gary Thomas <gary@mind.be>
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): msalter
// Contributors: msalter
// Date: 2001-07-14
// Purpose:
// Description:
//
// This code is part of RedBoot (tm).
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <redboot.h>
#include <fs/disk.h>
#include <fs/e2fs.h>
 
#define DEBUG_E2FS 0
 
#if DEBUG_E2FS > 4
static void dump_sb(struct e2fs_super_block *s);
static void dump_inode(struct e2fs_inode *i);
#endif
 
static void *e2fs_open(partition_t *p, const char *path);
static int e2fs_read(void *fp, char *buf, cyg_uint32 nbytes);
 
// This structure is the only thing exported by this module.
// These filesystem function pointers are attached to disk
// partitions in the generic disk handling code.
//
fs_funs_t redboot_e2fs_funs = {
e2fs_open,
e2fs_read
};
 
// A single block buffer to be shared carefully.
static cyg_uint32 blockbuf[E2FS_MAX_BLOCK_SIZE/sizeof(cyg_uint32)];
 
#define __READ_BLOCK(n) \
PARTITION_READ(e2fs->part, E2FS_BLOCK_TO_SECTOR(e2fs, (n)), \
blockbuf, e2fs->blocksize/SECTOR_SIZE)
 
// Get a group descriptor. Returns non-zero for success.
//
static int
e2fs_get_gdesc(e2fs_desc_t *e2fs, cyg_uint32 group_nr, e2fs_group_t *gdesc)
{
cyg_uint32 sec_nr;
 
if (group_nr < e2fs->gdesc_first ||
group_nr >= (e2fs->gdesc_first + E2FS_GDESC_CACHE_SIZE)) {
 
// cache miss
sec_nr = E2FS_BLOCK_TO_SECTOR(e2fs, e2fs->gdesc_block);
sec_nr += (group_nr / E2FS_GDESC_PER_SECTOR);
 
#if DEBUG_E2FS > 2
diag_printf("%s: group[%d] cache miss, sec_nr[%d]\n",
__FUNCTION__, group_nr, sec_nr);
#endif
if (!PARTITION_READ(e2fs->part, sec_nr, (cyg_uint32 *)e2fs->gdesc_cache,
sizeof(e2fs->gdesc_cache)/SECTOR_SIZE))
return 0;
 
e2fs->gdesc_first = (group_nr / E2FS_GDESC_CACHE_SIZE) * E2FS_GDESC_CACHE_SIZE;
}
*gdesc = e2fs->gdesc_cache[group_nr - e2fs->gdesc_first];
 
return 1;
}
 
// Read the requested inode from disk. Return non-zero if successful
//
static int
e2fs_get_inode(e2fs_desc_t *e2fs, int ino, e2fs_inode_t *ip)
{
cyg_uint32 offset, sec_nr, buf[SECTOR_SIZE/sizeof(cyg_uint32)];
e2fs_group_t gdesc;
 
// get descriptor for group which this inode belongs to
if (!e2fs_get_gdesc(e2fs, (ino - 1) / e2fs->inodes_per_group, &gdesc))
return 0;
if (gdesc.inode_table == 0)
return 0;
 
// byte offset within group inode table
offset = ((ino - 1) % e2fs->inodes_per_group) * sizeof(struct e2fs_inode);
 
// figure out which sector holds the inode
sec_nr = E2FS_BLOCK_TO_SECTOR(e2fs, SWAB_LE32(gdesc.inode_table));
sec_nr += offset / SECTOR_SIZE;
 
// and the offset within that sector.
offset %= SECTOR_SIZE;
 
#if DEBUG_E2FS > 0x08
diag_printf("%s: ino[%d], sec_nr[%d] offset[%d]\n", __FUNCTION__,
ino, sec_nr, offset);
#endif
 
if (!PARTITION_READ(e2fs->part, sec_nr, buf, 1))
return 0;
 
*ip = *(e2fs_inode_t *)((char *)buf + offset);
 
#if DEBUG_E2FS > 0
diag_printf("%s: inode size[%d]\n", __FUNCTION__, SWAB_LE32(ip->size));
#endif
 
return 1;
}
 
// Mount an e2fs filesystem on the given partition.
// Return 0 if successful.
//
static int
e2fs_mount(partition_t *part, e2fs_desc_t *e2fs)
{
int sb_block = 1;
cyg_uint32 sb_buf[E2FS_MIN_BLOCK_SIZE/sizeof(cyg_uint32)];
struct e2fs_super_block *sb = (struct e2fs_super_block *)sb_buf;
 
e2fs->part = part;
 
if (!PARTITION_READ(part, sb_block*(E2FS_MIN_BLOCK_SIZE/SECTOR_SIZE),
(cyg_uint32 *)sb, E2FS_MIN_BLOCK_SIZE/SECTOR_SIZE))
return -1;
 
if (SWAB_LE16(sb->magic) != E2FS_SUPER_MAGIC) {
diag_printf("ext2_mount: bad magic 0x%x\n", SWAB_LE16(sb->magic));
return -1;
}
 
// save some stuff for easy access
e2fs->blocksize = E2FS_BLOCK_SIZE(sb);
e2fs->nr_ind_blocks = (e2fs)->blocksize / sizeof(cyg_uint32);
e2fs->nr_dind_blocks = e2fs->nr_ind_blocks * ((e2fs)->blocksize / sizeof(cyg_uint32));
e2fs->nr_tind_blocks = e2fs->nr_dind_blocks * ((e2fs)->blocksize / sizeof(cyg_uint32));
e2fs->blocks_per_group = SWAB_LE32(sb->blocks_per_group);
e2fs->ngroups = (SWAB_LE32(sb->blocks_count) + e2fs->blocks_per_group - 1) /
e2fs->blocks_per_group;
e2fs->inodes_per_group = SWAB_LE32(sb->inodes_per_group);
 
// Find the group descriptors which follow superblock
e2fs->gdesc_block = ((sb_block * E2FS_MIN_BLOCK_SIZE) / e2fs->blocksize) + 1;
e2fs->gdesc_first = 0; // cache group 0 initially
 
if (!PARTITION_READ(part, E2FS_BLOCK_TO_SECTOR(e2fs,e2fs->gdesc_block),
(cyg_uint32 *)e2fs->gdesc_cache, 1))
return -1;
 
#if DEBUG_E2FS > 1
diag_printf("E2FS superblock:\n");
diag_printf(" [%d] inodes\n", SWAB_LE32(sb->inodes_count));
diag_printf(" [%d] blocks\n", SWAB_LE32(sb->blocks_count));
diag_printf(" [%d] blocksize\n", e2fs->blocksize);
diag_printf(" [%d] blocks per group\n", e2fs->blocks_per_group);
diag_printf(" [%d] ngroups\n", e2fs->ngroups);
#endif
 
#if DEBUG_E2FS > 4
dump_sb(sb);
#endif
 
return 0;
}
 
// Convert a block index into inode data into a block_nr.
// If successful, store block number in pblknr and return non-zero.
//
// NB: This needs some block/sector caching to be speedier. But
// that takes memory and speed is not too bad now for files
// small enough to avoid double and triple indirection.
//
static int
e2fs_inode_block(e2fs_desc_t *e2fs, e2fs_inode_t *inode,
cyg_uint32 bindex, cyg_uint32 *pblknr)
{
if (bindex < E2FS_NR_DIR_BLOCKS) {
*pblknr = SWAB_LE32(inode->block[bindex]);
return 1;
}
bindex -= E2FS_NR_DIR_BLOCKS;
 
if (bindex < e2fs->nr_ind_blocks) {
// Indirect block
if (!__READ_BLOCK(SWAB_LE32(inode->block[E2FS_IND_BLOCK])))
return 0;
*pblknr = SWAB_LE32(blockbuf[bindex]);
return 1;
}
bindex -= e2fs->nr_ind_blocks;
 
if (bindex < e2fs->nr_dind_blocks) {
// Double indirect block
if (!__READ_BLOCK(SWAB_LE32(inode->block[E2FS_DIND_BLOCK])))
return 0;
if (!__READ_BLOCK(SWAB_LE32(blockbuf[bindex / e2fs->nr_ind_blocks])))
return 0;
*pblknr = SWAB_LE32(blockbuf[bindex % e2fs->nr_ind_blocks]);
return 1;
}
bindex -= e2fs->nr_dind_blocks;
 
// Triple indirect block
if (!__READ_BLOCK(SWAB_LE32(inode->block[E2FS_TIND_BLOCK])))
return 0;
if (!__READ_BLOCK(SWAB_LE32(blockbuf[bindex / e2fs->nr_dind_blocks])))
return 0;
bindex %= e2fs->nr_dind_blocks;
if (!__READ_BLOCK(SWAB_LE32(blockbuf[bindex / e2fs->nr_ind_blocks])))
return 0;
*pblknr = SWAB_LE32(blockbuf[bindex % e2fs->nr_ind_blocks]);
return 1;
}
 
 
// search a single directory block in memory looking for an
// entry with the given name. Return pointer to entry if
// found, NULL if not.
//
static e2fs_dir_entry_t *
search_dir_block(e2fs_desc_t *e2fs, cyg_uint32 *blkbuf,
const char *name, int namelen)
{
e2fs_dir_entry_t *dir;
cyg_uint16 reclen, len;
cyg_uint32 offset;
 
#if DEBUG_E2FS > 0
diag_dump_buf(blkbuf, e2fs->blocksize);
#endif
offset = 0;
while (offset < e2fs->blocksize) {
dir = (e2fs_dir_entry_t *)((char *)blkbuf + offset);
reclen = SWAB_LE16(dir->reclen);
offset += reclen;
len = dir->namelen;
 
// terminate on anything which doesn't make sense
if (reclen < 8 || (len + 8) > reclen || offset > (e2fs->blocksize + 1))
return NULL;
 
if (dir->inode && len == namelen && !strncmp(dir->name, name, len))
return dir;
}
return NULL;
}
 
 
// Look in the given directory for an entry with the given name.
// If found, return a pointer to that entry. Return NULL if not
// found.
//
static e2fs_dir_entry_t *
e2fs_dir_lookup(e2fs_desc_t *e2fs, cyg_uint32 dir_ino,
const char *name, int namelen)
{
e2fs_inode_t inode;
e2fs_dir_entry_t *dir;
cyg_uint32 nblocks, last_block_size, i, block_nr, nbytes;
 
#if DEBUG_E2FS > 0
diag_printf("%s: looking for %s [%d] in ino[%d]\n",
__FUNCTION__, name, namelen, dir_ino);
#endif
 
if (!e2fs_get_inode(e2fs, dir_ino, &inode)) {
#if DEBUG_E2FS > 0
diag_printf("%s: e2fs_get_inode [%d] failed\n", __FUNCTION__, dir_ino);
#endif
return NULL;
}
 
nbytes = SWAB_LE32(inode.size);
nblocks = (nbytes + e2fs->blocksize - 1) / e2fs->blocksize;
 
last_block_size = nbytes % e2fs->blocksize;
if (last_block_size == 0)
last_block_size = e2fs->blocksize;
 
for (i = 0; i < nblocks; i++) {
if (!e2fs_inode_block(e2fs, &inode, i, &block_nr))
return NULL;
 
if (block_nr) {
if (!__READ_BLOCK(block_nr))
return NULL;
} else
memset(blockbuf, 0, e2fs->blocksize);
 
dir = search_dir_block(e2fs, blockbuf, name, namelen);
 
if (dir != NULL)
return dir;
}
return NULL;
}
 
typedef struct ino_info {
cyg_uint32 ino;
cyg_uint32 parent_ino;
cyg_uint8 filetype;
} ino_info_t;
 
static int e2fs_inode_lookup(e2fs_desc_t *e2fs, cyg_uint32 dir_ino,
const char *pathname, ino_info_t *info);
 
// Starting from the given directory, find the inode number, filetype, and
// parent inode for the file pointed to by the given symbolic link inode.
// If successful, fills out ino_info_t and return true.
//
static int
e2fs_follow_symlink(e2fs_desc_t *e2fs, cyg_uint32 dir_ino, cyg_uint32 sym_ino, ino_info_t *info)
{
#define MAX_SYMLINK_NAME 255
char symlink[MAX_SYMLINK_NAME+1];
int pathlen;
cyg_uint32 block_nr;
e2fs_inode_t inode;
 
if (!e2fs_get_inode(e2fs, sym_ino, &inode)) {
#if DEBUG_E2FS > 0
diag_printf("%s: e2fs_get_inode [%d] failed\n", __FUNCTION__, sym_ino);
#endif
return 0;
}
 
pathlen = SWAB_LE32(inode.size);
if (pathlen > MAX_SYMLINK_NAME)
return 0;
 
if (inode.blocks) {
if (!e2fs_inode_block(e2fs, &inode, 0, &block_nr))
return 0;
if (block_nr) {
if (!PARTITION_READ(e2fs->part, E2FS_BLOCK_TO_SECTOR(e2fs, block_nr),
blockbuf, e2fs->blocksize/SECTOR_SIZE))
return 0;
memcpy(symlink, blockbuf, pathlen);
} else
return 0;
} else {
// small enough path to fit in inode struct
memcpy(symlink, (char *)&inode.block[0], pathlen);
}
symlink[pathlen] = 0;
 
return e2fs_inode_lookup(e2fs, dir_ino, symlink, info);
}
 
 
// Starting from the given directory, find the inode number, filetype, and
// parent inode for the given file pathname.
// If successful, fills out ino_info_t and return true.
//
static int
e2fs_inode_lookup(e2fs_desc_t *e2fs, cyg_uint32 dir_ino, const char *pathname, ino_info_t *info)
{
int len, pathlen;
const char *p;
e2fs_dir_entry_t *dir = NULL;
if (!pathname || (pathlen = strlen(pathname)) == 0)
return 0;
 
if (*pathname == '/') {
if (--pathlen == 0) {
info->ino = info->parent_ino = E2FS_ROOT_INO;
info->filetype = E2FS_FTYPE_DIR;
return 1;
}
++pathname;
dir_ino = E2FS_ROOT_INO;
}
 
while (pathlen) {
// find next delimiter in path.
for (p = pathname, len = 0; len < pathlen; len++, p++) {
// skip delimiter if found.
if (*p == '/') {
++p;
--pathlen;
break;
}
}
dir = e2fs_dir_lookup(e2fs, dir_ino, pathname, len);
if (dir == NULL)
return 0;
 
pathlen -= len;
pathname = p;
 
switch (dir->filetype) {
case E2FS_FTYPE_SYMLINK:
// follow the symbolic link (this will cause recursion)
if (!e2fs_follow_symlink(e2fs, dir_ino, SWAB_LE32(dir->inode), info))
return 0;
if (pathlen == 0)
return 1;
// must be a dir if we want to continue
if (info->filetype != E2FS_FTYPE_DIR)
return 0;
dir_ino = info->ino;
break;
 
case E2FS_FTYPE_DIR:
if (pathlen)
dir_ino = SWAB_LE32(dir->inode);
break;
 
case E2FS_FTYPE_REG_FILE:
if (pathlen)
return 0; // regular file embedded in middle of path
break;
 
case E2FS_FTYPE_UNKNOWN:
case E2FS_FTYPE_CHRDEV:
case E2FS_FTYPE_BLKDEV:
case E2FS_FTYPE_FIFO:
case E2FS_FTYPE_SOCK:
default:
return 0;
}
}
info->ino = SWAB_LE32(dir->inode);
info->parent_ino = dir_ino;
info->filetype = dir->filetype;
return 1;
}
 
struct read_info {
e2fs_desc_t e2fs_desc;
e2fs_inode_t inode;
cyg_uint32 fsize;
cyg_uint32 fpos;
};
 
static void *
e2fs_open(partition_t *p, const char *filepath)
{
static struct read_info rinfo;
ino_info_t ino_info;
 
// mount partition
if (e2fs_mount(p, &rinfo.e2fs_desc) != 0) {
diag_printf("mount failed.\n");
return NULL;
}
 
// find file inode
if (!e2fs_inode_lookup(&rinfo.e2fs_desc, E2FS_ROOT_INO, filepath, &ino_info)) {
diag_printf("%s: e2fs_inode_lookup failed\n", __FUNCTION__);
return NULL;
}
 
// read inode
if (!e2fs_get_inode(&rinfo.e2fs_desc, ino_info.ino, &rinfo.inode)) {
diag_printf("%s: e2fs_get_inode failed for ino[%d]\n", __FUNCTION__, ino_info.ino);
return NULL;
}
 
rinfo.fsize = SWAB_LE32(rinfo.inode.size);
rinfo.fpos = 0;
 
return &rinfo;
}
 
static int
e2fs_read(void *fp, char *buf, cyg_uint32 nbytes)
{
struct read_info *info = fp;
e2fs_desc_t *e2fs;
cyg_uint32 nread = 0, rem, block_nr, bindex, to_read;
 
if ((info->fpos + nbytes) > info->fsize)
nbytes = info->fsize - info->fpos;
 
e2fs = &info->e2fs_desc;
 
// see if we need to copy leftover data from last read call
rem = e2fs->blocksize - (info->fpos % e2fs->blocksize);
if (rem != e2fs->blocksize) {
char *p = (char *)blockbuf + e2fs->blocksize - rem;
 
if (rem > nbytes)
rem = nbytes;
 
memcpy(buf, p, rem);
 
nread += rem;
buf += rem;
info->fpos += rem;
}
// now loop through blocks if we're not done
bindex = info->fpos / e2fs->blocksize;
while (nread < nbytes) {
if (!e2fs_inode_block(e2fs, &info->inode, bindex, &block_nr))
return -1;
 
if (block_nr) {
if (!PARTITION_READ(e2fs->part, E2FS_BLOCK_TO_SECTOR(e2fs, block_nr),
blockbuf, e2fs->blocksize/SECTOR_SIZE))
return 0;
} else
memset(blockbuf, 0, e2fs->blocksize);
to_read = nbytes - nread;
if (to_read > e2fs->blocksize)
to_read = e2fs->blocksize;
 
memcpy(buf, blockbuf, to_read);
 
nread += to_read;
buf += to_read;
info->fpos += to_read;
++bindex;
}
 
return nread;
}
 
#if DEBUG_E2FS > 4
static void dump_sb(struct e2fs_super_block *s)
{
diag_printf("inode_count: %d\n", SWAB_LE32(s->inodes_count));
diag_printf("blocks_count: %d\n", SWAB_LE32(s->blocks_count));
diag_printf("r_blocks_count: %d\n", SWAB_LE32(s->r_blocks_count));
diag_printf("free_blocks_count: %d\n", SWAB_LE32(s->free_blocks_count));
diag_printf("free_inodes_count: %d\n", SWAB_LE32(s->free_inodes_count));
diag_printf("first_data_block: %d\n", SWAB_LE32(s->first_data_block));
diag_printf("log_block_size: %d\n", SWAB_LE32(s->log_block_size));
diag_printf("log_frag_size: %d\n", SWAB_LE32(s->log_frag_size));
diag_printf("blocks_per_group: %d\n", SWAB_LE32(s->blocks_per_group));
diag_printf("frags_per_group: %d\n", SWAB_LE32(s->frags_per_group));
diag_printf("inodes_per_group: %d\n", SWAB_LE32(s->inodes_per_group));
diag_printf("mnt_count: %d\n", SWAB_LE16(s->mnt_count));
diag_printf("max_mnt_count: %d\n", SWAB_LE16(s->max_mnt_count));
diag_printf("magic: %d\n", SWAB_LE16(s->magic));
diag_printf("state: %d\n", SWAB_LE16(s->state));
diag_printf("errors: %d\n", SWAB_LE16(s->errors));
diag_printf("minor_rev_level: %d\n", SWAB_LE16(s->minor_rev_level));
diag_printf("lastcheck: %d\n", SWAB_LE32(s->lastcheck));
diag_printf("checkinterval: %d\n", SWAB_LE32(s->checkinterval));
diag_printf("creator_os: %d\n", SWAB_LE32(s->creator_os));
diag_printf("rev_level: %d\n", SWAB_LE32(s->rev_level));
}
 
static void dump_inode(struct e2fs_inode *i)
{
int j, n;
 
diag_printf("mode: %o\n", SWAB_LE16(i->mode));
diag_printf("uid: %o\n", SWAB_LE16(i->uid));
diag_printf("size: %d\n", SWAB_LE32(i->size));
diag_printf("gid: %o\n", SWAB_LE16(i->gid));
diag_printf("links: %d\n", SWAB_LE16(i->links_count));
diag_printf("blocks: %d\n", SWAB_LE32(i->blocks));
 
n = i->blocks;
if (n > E2FS_N_BLOCKS)
n = E2FS_N_BLOCKS;
 
for (j = 0; j < n; j++)
diag_printf(" block: %d\n", SWAB_LE32(i->block[j]));
}
#endif
 
 
/ide.c
0,0 → 1,490
//==========================================================================
//
// ide.c
//
// RedBoot IDE support
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2003 Gary Thomas <gary@mind.be>
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): msalter
// Contributors: msalter
// Date: 2001-07-14
// Purpose:
// Description:
//
// This code is part of RedBoot (tm).
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <redboot.h>
#include <cyg/hal/hal_io.h>
#include <fs/disk.h>
#include <fs/ide.h>
 
static int ide_read(struct disk *d,
cyg_uint32 start_sector,
cyg_uint32 *buf,
cyg_uint8 nr_sectors);
 
static disk_funs_t ide_funs = { ide_read };
 
static struct ide_priv ide_privs[HAL_IDE_NUM_CONTROLLERS * 2];
 
static inline void
__wait_for_ready(int ctlr)
{
cyg_uint8 status;
do {
HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
} while (status & (IDE_STAT_BSY | IDE_STAT_DRQ));
}
 
static inline int
__wait_for_drq(int ctlr)
{
cyg_uint8 status;
 
CYGACC_CALL_IF_DELAY_US(10);
do {
HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
if (status & IDE_STAT_DRQ)
return 1;
} while (status & IDE_STAT_BSY);
 
return 0;
}
 
static int
ide_reset(int ctlr)
{
cyg_uint8 status;
int delay;
 
HAL_IDE_WRITE_CONTROL(ctlr, 6); // polled mode, reset asserted
CYGACC_CALL_IF_DELAY_US(5000);
HAL_IDE_WRITE_CONTROL(ctlr, 2); // polled mode, reset cleared
CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
 
// wait 30 seconds max for not busy
for (delay = 0; delay < 300; ++delay) {
CYGACC_CALL_IF_DELAY_US((cyg_uint32)100000);
HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
// bail out early on bogus status
if ((status & (IDE_STAT_BSY|IDE_STAT_DRDY)) == (IDE_STAT_BSY|IDE_STAT_DRDY))
break;
if (!(status & IDE_STAT_BSY))
return 1;
}
return 0;
}
 
static int
ide_ident(int ctlr, int dev, int is_packet_dev, cyg_uint16 *buf)
{
int i;
 
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, is_packet_dev ? 0xA1 : 0xEC);
CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
 
if (!__wait_for_drq(ctlr))
return 0;
 
for (i = 0; i < (SECTOR_SIZE / sizeof(cyg_uint16)); i++, buf++)
HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
 
return 1;
}
 
static int
ide_read_sectors(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
{
int i, j;
cyg_uint16 *p;
 
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, count);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >> 8) & 0xff);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (start >> 16) & 0xff);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE,
((start >> 24) & 0xf) | (dev << 4) | 0x40);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x20);
 
for(p = buf, i = 0; i < count; i++) {
 
if (!__wait_for_drq(ctlr)) {
diag_printf("%s: NO DRQ for ide%d, device %d.\n",
__FUNCTION__, ctlr, dev);
return 0;
}
 
for (j = 0; j < (SECTOR_SIZE / sizeof(cyg_uint16)); j++, p++)
HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *p);
}
return 1;
}
 
// max number of sectors to xfer during a single packet command
#define MAX_CD_XFER 16
 
static inline int
send_packet_command(int ctlr, int dev, cyg_uint16 len, cyg_uint16 *pkt, int pktlen)
{
int i;
cyg_uint8 status, reason;
 
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_FEATURES, 0);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 0);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, 0);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, len & 0xff);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (len >> 8) & 0xff);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0xA0);
 
if (!__wait_for_drq(ctlr)) {
diag_printf("%s: NO DRQ for ide%d, device %d.\n",
__FUNCTION__, ctlr, dev);
return 0;
}
 
// send packet
for (i = 0; i < (pktlen/sizeof(cyg_uint16)); i++)
HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, pkt[i]);
 
// wait for not busy transferring packet
do {
HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
 
if ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ)
if (reason & IDE_REASON_COD)
continue; // still wanting packet data (should timeout here)
 
} while (status & IDE_STAT_BSY);
 
return 1;
}
 
#define READ_COUNT(x) \
{ unsigned char tmp; \
HAL_IDE_READ_UINT8(ctlr, IDE_REG_LBAMID, tmp); \
(x) = tmp; \
HAL_IDE_READ_UINT8(ctlr, IDE_REG_LBAHI, tmp); \
(x) = cdcount |= (tmp << 8); \
}
 
 
// Read the sense data
static int
request_sense(int ctlr, int dev, cyg_uint16 count, cyg_uint16 *buf)
{
int i;
cyg_uint16 cdcount, pkt[6];
unsigned char status, *cpkt = (unsigned char *)pkt;
 
 
// Fill in REQUEST SENSE packet command block
memset(cpkt, 0, sizeof(pkt));
cpkt[0] = 0x03;
cpkt[4] = 254; // allocation length
if (!send_packet_command(ctlr, dev, count, pkt, sizeof(pkt)))
return 0;
 
HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
if (!(status & IDE_STAT_DRQ)) {
if (status & IDE_STAT_SERVICE) {
unsigned char reason;
HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
diag_printf("%s: SERVICE request for ide%d, device %d, status[%02x], reason[%02x].\n",
__FUNCTION__, ctlr, dev, status, reason);
}
return 0;
}
 
READ_COUNT(cdcount);
if (cdcount != count)
diag_printf("%s: ide%d, dev%d: his cnt[%d] our count[%d].\n",
__FUNCTION__, ctlr, dev, cdcount, count);
 
for(i = 0; i < (cdcount / sizeof(*buf)); i++, buf++)
HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
 
// wait for not busy transferring data
do {
HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
} while ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ);
 
return cdcount;
}
 
// Interpret the sense data
static int
handle_sense(int ctlr, int dev, cyg_uint8 count, cyg_uint16 *buf)
{
#if 0
unsigned char *p = (char *)buf;
 
diag_printf("%s: %d bytes:\n", __FUNCTION__, count);
diag_printf("sense key[%02x] additional sense[%02x]\n",
p[2], p[12]);
#endif
return 1;
}
 
static int
do_packet_read(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
{
int i, retry_cnt;
cyg_uint16 cdcount, pkt[6], sense[127];
unsigned char status, *cpkt = (unsigned char *)pkt;
 
// get count number of whole cdrom sectors
while (count) {
 
retry_cnt = 3;
 
i = (count > MAX_CD_XFER) ? MAX_CD_XFER : count;
 
retry:
// Fill in READ(10) packet command block
memset(cpkt, 0, sizeof(pkt));
cpkt[0] = 0x28; // READ(10)
cpkt[2] = (start >> 24) & 0xff;
cpkt[3] = (start >> 16) & 0xff;
cpkt[4] = (start >> 8) & 0xff;
cpkt[5] = (start >> 0) & 0xff;
cpkt[7] = (i >> 8) & 0xff;
cpkt[8] = i & 0xff;
if (!send_packet_command(ctlr, dev, i * CDROM_SECTOR_SIZE,
pkt, sizeof(pkt)))
return 0;
 
HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
if (!(status & IDE_STAT_DRQ)) {
if (status & IDE_STAT_SERVICE) {
unsigned char reason;
int sense_count;
HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
#if 1
diag_printf("%s: SERVICE request for ide%d, device %d, status[%02x], reason[%02x].\n",
__FUNCTION__, ctlr, dev, status, reason);
#endif
sense_count = request_sense(ctlr, dev, sizeof(sense), sense);
if (sense_count) {
handle_sense(ctlr, dev, sense_count, sense);
if (retry_cnt--)
goto retry;
}
}
return 0;
}
 
count -= i;
start += i;
 
READ_COUNT(cdcount);
if (cdcount != (i * CDROM_SECTOR_SIZE))
diag_printf("%s: ide%d, dev%d: his cnt[%d] our count[%d].\n",
__FUNCTION__, ctlr, dev,
cdcount, i * CDROM_SECTOR_SIZE);
 
for(i = 0; i < (cdcount / sizeof(*buf)); i++, buf++)
HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
 
// wait for not busy transferring data
do {
HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
} while ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ);
}
return 1;
}
 
 
static int
ide_packet_read_sectors(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
{
int i, extra;
cyg_uint32 cdstart;
static cyg_uint16 cdsec_buf[CDROM_SECTOR_SIZE/sizeof(cyg_uint16)];
 
cdstart = (start + SECTORS_PER_CDROM_SECTOR-1) / SECTORS_PER_CDROM_SECTOR;
// align to cdrom sector boundary.
if (start % SECTORS_PER_CDROM_SECTOR) {
if (!ide_packet_read_sectors(ctlr, dev,
cdstart * SECTORS_PER_CDROM_SECTOR,
SECTORS_PER_CDROM_SECTOR, cdsec_buf))
return 0;
 
i = SECTORS_PER_CDROM_SECTOR - (start % SECTORS_PER_CDROM_SECTOR);
if (i > count)
i = count;
memcpy(buf, cdsec_buf + ((start % CDROM_SECTOR_SIZE) * SECTOR_SIZE),
i * SECTOR_SIZE);
 
count -= i;
buf += (i * SECTOR_SIZE) / sizeof(*buf);
++cdstart;
}
 
extra = count % SECTORS_PER_CDROM_SECTOR;
count /= SECTORS_PER_CDROM_SECTOR;
 
if (count) {
if (!do_packet_read(ctlr, dev, cdstart, count, buf))
return 0;
buf += count * SECTORS_PER_CDROM_SECTOR * SECTOR_SIZE;
}
 
if (extra) {
// read cdrom sector
if (!ide_packet_read_sectors(ctlr, dev,
cdstart * SECTORS_PER_CDROM_SECTOR,
extra, cdsec_buf))
return 0;
memcpy(buf, cdsec_buf, extra * SECTOR_SIZE);
}
 
return 1;
}
 
static int
ide_read(struct disk *d,
cyg_uint32 start_sec, cyg_uint32 *buf, cyg_uint8 nr_secs)
{
struct ide_priv *p = (struct ide_priv *)(d->private);
 
if (p->flags & IDE_DEV_PACKET)
return ide_packet_read_sectors(p->controller, p->drive,
start_sec, nr_secs, (cyg_uint16 *)buf);
 
return ide_read_sectors(p->controller, p->drive,
start_sec, nr_secs, (cyg_uint16 *)buf);
}
 
 
static void
ide_init(void)
{
cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)], u32;
cyg_uint16 u16;
cyg_uint8 u8;
int i, j;
disk_t disk;
struct ide_priv *priv;
 
#define DEV_INIT_VAL ((j << 4) | 0xA0)
 
HAL_IDE_INIT();
 
CYGACC_CALL_IF_DELAY_US(5);
 
priv = ide_privs;
for (i = 0; i < HAL_IDE_NUM_CONTROLLERS; i++) {
 
// soft reset the devices on this controller
if (!ide_reset(i))
continue;
 
// 2 devices per controller
for (j = 0; j < 2; j++, priv++) {
 
priv->controller = i;
priv->drive = j;
priv->flags = 0;
// This is reminiscent of a memory test. We write a value
// to a certain location (device register), then write a
// different value somewhere else so that the first value
// is not hanging on the bus, then we read back the first
// value to see if the write was succesful.
//
HAL_IDE_WRITE_UINT8(i, IDE_REG_DEVICE, DEV_INIT_VAL);
HAL_IDE_WRITE_UINT8(i, IDE_REG_FEATURES, 0);
CYGACC_CALL_IF_DELAY_US(50000);
HAL_IDE_READ_UINT8(i, IDE_REG_DEVICE, u8);
if (u8 != DEV_INIT_VAL) {
diag_printf("IDE failed to identify unit %d - wrote: %x, read: %x\n",
i, DEV_INIT_VAL, u8);
continue;
}
 
// device present
priv->flags |= IDE_DEV_PRESENT;
 
if (ide_ident(i, j, 0, (cyg_uint16 *)buf) <= 0) {
if (ide_ident(i, j, 1, (cyg_uint16 *)buf) <= 0) {
priv->flags = 0;
continue; // can't identify device
} else {
u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_GENCONFIG);
if (((u16 >> 8) & 0x1f) != 5) {
diag_printf("Non-CDROM ATAPI device #%d - skipped\n", i);
continue;
}
priv->flags |= IDE_DEV_PACKET;
}
}
memset(&disk, 0, sizeof(disk));
disk.funs = &ide_funs;
disk.private = priv;
 
disk.kind = DISK_IDE_HD; // until proven otherwise
 
if (priv->flags & IDE_DEV_PACKET) {
u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_GENCONFIG);
if (((u16 >> 8) & 0x1f) == 5)
disk.kind = DISK_IDE_CDROM;
} else {
u32 = *(cyg_uint32 *)((char *)buf + IDE_DEVID_LBA_CAPACITY);
disk.nr_sectors = u32;
}
 
if (!disk_register(&disk))
return;
}
}
}
 
RedBoot_init(ide_init, RedBoot_INIT_FIRST);
 
/disk.c
0,0 → 1,435
//==========================================================================
//
// disk.c
//
// RedBoot disk support
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002 Gary Thomas
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): msalter
// Contributors: msalter
// Date: 2001-07-14
// Purpose:
// Description:
//
// This code is part of RedBoot (tm).
//
//####DESCRIPTIONEND####
//
//==========================================================================
 
#include <redboot.h>
#include <fs/disk.h>
 
#ifdef CYGSEM_REDBOOT_DISK_EXT2FS
#include <fs/e2fs.h>
#endif
#ifdef CYGSEM_REDBOOT_DISK_ISO9660
#include <fs/iso9660fs.h>
#endif
 
static void do_disks(int argc, char *argv[]);
 
RedBoot_cmd("disks",
"Display disks/partitions.",
"",
do_disks
);
 
static disk_t disk_table[CYGNUM_REDBOOT_MAX_DISKS];
static int disk_count = 0;
 
static int
find_dos_partitions(disk_t *d, cyg_uint8 *mbr)
{
cyg_uint32 s, n, tmp;
struct mbr_partition *p;
int i, found = 0;
 
p = (struct mbr_partition *)(mbr + MBR_PTABLE_OFFSET);
 
// Look for primary partitions
for (i = 0; i < 4 && i < CYGNUM_REDBOOT_MAX_PARTITIONS; i++) {
 
// Have to use memcpy because of alignment
memcpy(&tmp, p->start_sect, 4);
s = SWAB_LE32(tmp);
memcpy(&tmp, p->nr_sects, 4);
n = SWAB_LE32(tmp);
 
if (s && n) {
++found;
d->partitions[i].disk = d;
d->partitions[i].start_sector = s;
d->partitions[i].nr_sectors = n;
d->partitions[i].systype = p->sys_ind;
d->partitions[i].bootflag = p->boot_ind;
}
p++;
}
 
#if CYGNUM_REDBOOT_MAX_PARTITIONS > 4
{
cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)], xoffset;
cyg_uint16 magic;
int nextp;
 
// Go back through and find extended partitions
for (i = 0, nextp = 4; i < 4 && nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; i++) {
if (d->partitions[i].systype == SYSTYPE_EXTENDED) {
// sector offsets in partition tables are relative to start
// of extended partition.
xoffset = d->partitions[i].start_sector;
for ( ; nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; ++nextp) {
 
// read partition boot record (same format as mbr except
// there should only be 2 entries max: a normal partition
// and another extended partition
if (DISK_READ(d, xoffset, buf, 1) <= 0)
break;
 
magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET);
if (SWAB_LE16(magic) != MBR_MAGIC)
break;
 
p = (struct mbr_partition *)((char *)buf + MBR_PTABLE_OFFSET);
 
// Have to use memcpy because of alignment
memcpy(&tmp, p->start_sect, 4);
s = SWAB_LE32(tmp);
memcpy(&tmp, p->nr_sects, 4);
n = SWAB_LE32(tmp);
 
if (s && n) {
++found;
d->partitions[nextp].disk = d;
d->partitions[nextp].start_sector = s + xoffset;
d->partitions[nextp].nr_sectors = n;
d->partitions[nextp].systype = p->sys_ind;
d->partitions[nextp].bootflag = p->boot_ind;
}
++p;
 
memcpy(&tmp, p->start_sect, 4);
s = SWAB_LE32(tmp);
memcpy(&tmp, p->nr_sects, 4);
n = SWAB_LE32(tmp);
 
// more extended partitions?
if (p->sys_ind != SYSTYPE_EXTENDED || !s || !n)
break;
 
xoffset += s;
}
}
}
}
#endif
return found;
}
 
 
// Find partitions on given disk.
// Return number of partitions found
static int
find_partitions(disk_t *d)
{
cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)];
cyg_uint16 magic;
partition_t *p;
int i, found = 0;
 
 
if (d->kind == DISK_IDE_CDROM) {
#ifdef CYGSEM_REDBOOT_DISK_ISO9660
// no partition table, so fake it
p = d->partitions;
p->disk = d;
p->start_sector = 0;
p->nr_sectors = d->nr_sectors;
p->funs = &redboot_iso9660fs_funs;
return 1;
#else
return 0;
#endif
}
 
// read Master Boot Record
if (DISK_READ(d, 0, buf, 1) <= 0)
return 0;
 
// Check for DOS MBR
magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET);
if (SWAB_LE16(magic) == MBR_MAGIC) {
found = find_dos_partitions(d, (cyg_uint8 *)buf);
} else {
// Might want to handle other MBR types, here...
}
 
// Now go through all partitions and install the correct
// funcs for supported filesystems.
for (i = 0, p = d->partitions; i < CYGNUM_REDBOOT_MAX_PARTITIONS; i++, p++) {
switch (p->systype) {
#ifdef CYGSEM_REDBOOT_DISK_EXT2FS
case SYSTYPE_LINUX:
p->funs = &redboot_e2fs_funs;
break;
#endif
#ifdef CYGSEM_REDBOOT_DISK_FAT16
case SYSTYPE_FAT16:
p->funs = &redboot_fat16_funs;
break;
#endif
#ifdef CYGSEM_REDBOOT_DISK_FAT32
case SYSTYPE_FAT32:
p->funs = &redboot_fat32_funs;
break;
#endif
default:
break; // ignore unsupported filesystems
}
}
 
return found;
}
 
// Add a disk to the disk table.
// Return zero if no more room in table.
externC int
disk_register(disk_t *d)
{
int i;
 
// make sure we have room for it
if (disk_count >= CYGNUM_REDBOOT_MAX_DISKS)
return 0;
 
// Set the index
d->index = 0;
for (i = 0; i < disk_count; i++)
if (disk_table[i].kind == d->kind)
d->index++;
 
// put it in the table
disk_table[disk_count] = *d;
 
// fill in partition info
find_partitions(&disk_table[disk_count++]);
 
return 1;
}
 
// Convert a filename in the form <partition_name>:<filename> into
// a partition and path.
//
static int
disk_parse_filename(const char *name, partition_t **part, const char **path)
{
int i, kind, index, pindex;
 
kind = index = pindex = 0;
 
if (name[0] == 'h' && name[1] == 'd') {
// IDE hard drives
kind = DISK_IDE_HD;
if (name[2] < 'a' || name[2] > 'z')
return 0;
index = name[2] - 'a';
if (name[3] < '1' || name[3] >= ('1' + CYGNUM_REDBOOT_MAX_PARTITIONS))
return 0;
pindex = name[3] - '1';
if (name[4] != ':')
return 0;
*path = &name[5];
}
#ifdef CYGSEM_REDBOOT_DISK_ISO9660
else if (name[0] == 'c' && name[1] == 'd') {
// CD drives
kind = DISK_IDE_CDROM;
if (name[2] < '0' || name[2] > '9')
return 0;
index = name[2] - '0';
if (name[3] != ':')
return 0;
*path = &name[4];
}
#endif
 
if (kind) {
for (i = 0; i < CYGNUM_REDBOOT_MAX_DISKS; i++) {
if (disk_table[i].kind == kind && disk_table[i].index == index) {
*part = &disk_table[i].partitions[pindex];
return 1;
}
}
}
return 0;
}
 
static const struct {
int kind;
const char *str;
} systype_names[] = {
{ SYSTYPE_FAT12, "FAT12" },
{ SYSTYPE_FAT16_32M, "FAT16 <32M" },
{ SYSTYPE_FAT16, "FAT16" },
{ SYSTYPE_EXTENDED, "Extended" },
{ SYSTYPE_LINUX_SWAP, "Linux Swap" },
{ SYSTYPE_LINUX, "Linux" }
};
 
static const char *
systype_name(int systype)
{
int i;
for (i = 0; i < sizeof(systype_names)/sizeof(systype_names[0]); i++)
if (systype_names[i].kind == systype)
return systype_names[i].str;
return "Unknown";
}
 
// List disk partitions
static void
do_disks(int argc, char *argv[])
{
int i, j;
disk_t *d;
partition_t *p;
char name[16];
 
for (i = 0, d = disk_table; i < disk_count; i++, d++) {
switch (d->kind) {
case DISK_IDE_HD:
for (j = 0, p = d->partitions;
j < CYGNUM_REDBOOT_MAX_PARTITIONS;
j++, p++) {
if (p->systype) {
diag_sprintf(name, "hd%c%d", 'a' + d->index, j+1);
diag_printf("%-8s %s\n", name, systype_name(p->systype));
}
}
break;
case DISK_IDE_CDROM:
diag_sprintf(name, "cd%d", d->index);
diag_printf("%-8s ISO9660\n", name);
break;
}
}
}
 
static void *fileptr;
static partition_t *file_part;
 
externC int
disk_stream_open(connection_info_t *info, int *err)
{
const char *filepath;
char *filename = info->filename;
 
// The filename is in <disk>:<path> format.
// Convert to a partition and path.
if (!disk_parse_filename(filename, &file_part, &filepath)) {
*err = diskerr_badname;
return -1;
}
 
if (file_part->disk->kind != DISK_IDE_CDROM && file_part->systype == 0) {
*err = diskerr_partition;
return -1;
}
 
if (file_part->funs == (fs_funs_t *)0) {
*err = diskerr_partition;
return -1;
}
 
fileptr = (file_part->funs->open)(file_part, filepath);
if (fileptr == NULL) {
*err = diskerr_open;
return -1;
}
return 0;
}
 
externC int
disk_stream_read(char *buf, int size, int *err)
{
int nread;
 
if ((nread = (file_part->funs->read)(fileptr, buf, size)) < 0) {
*err = diskerr_read;
return -1;
}
return nread;
}
 
externC void
disk_stream_close(int *err)
{
fileptr = NULL;
}
 
externC char *
disk_error(int err)
{
switch (err) {
case diskerr_badname:
return "Bad filename";
break;
case diskerr_partition:
return "Unsupported filesystem";
break;
case diskerr_open:
return "Can't open file";
break;
case diskerr_read:
return "Can't read file";
break;
default:
return "Unknown error";
break;
}
}
 
//
// RedBoot interface
//
GETC_IO_FUNCS(disk_io, disk_stream_open, disk_stream_close,
0, disk_stream_read, disk_error);
RedBoot_load(disk, disk_io, true, true, 0);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.