411 lines
12 KiB
C
411 lines
12 KiB
C
/**
|
|
* \defgroup c64fs C64 file system and disk functions.
|
|
* @{
|
|
*
|
|
* The C64 file system functions are divided into two categories:
|
|
* those that deal with C64 files and the C64 disk directory, and
|
|
* those that allow direct block access to the disk. The former
|
|
* functions can be used for accessing regular files, whereas the
|
|
* latter functions are used e.g. to download D64 files onto 1541
|
|
* disks.
|
|
*
|
|
* \note The C64 filesystem functions currently only work with the
|
|
* 1541/1541-II/1571 and compatible drives, and not with the IDE64
|
|
* hard disks or the 1581/FD2000 3.5" drives.
|
|
*
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* \file
|
|
* C64 file system operations interface for Contiki.
|
|
* \author Adam Dunkels <adam@dunkels.com>
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2003, Adam Dunkels.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote
|
|
* products derived from this software without specific prior
|
|
* written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* This file is part of the Contiki desktop environment
|
|
*
|
|
* $Id: c64-fs.c,v 1.1 2007/05/23 23:11:28 oliverschmidt Exp $
|
|
*
|
|
*/
|
|
|
|
#include "c64-dio.h"
|
|
#include "c64-dio-asm.h"
|
|
#include "c64-fs.h"
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
struct directory_entry {
|
|
unsigned char type;
|
|
unsigned char track, sect;
|
|
unsigned char name[16];
|
|
unsigned char reltrack, relsect, relreclen;
|
|
unsigned char unused1, unused2, unused3, unused4;
|
|
unsigned char tmptrack, tmpsect;
|
|
unsigned char blockslo, blockshi;
|
|
};
|
|
|
|
unsigned char _c64_fs_dirbuf[256];
|
|
unsigned char _c64_fs_dirbuftrack = 0, _c64_fs_dirbufsect = 0;
|
|
|
|
unsigned char _c64_fs_filebuf[256];
|
|
unsigned char _c64_fs_filebuftrack = 0, _c64_fs_filebufsect = 0;
|
|
|
|
static struct c64_fs_dirent lastdirent;
|
|
|
|
static struct c64_fs_dir opendir;
|
|
static struct c64_fs_dirent opendirent;
|
|
|
|
/*-----------------------------------------------------------------------------------*/
|
|
/**
|
|
* Open a file.
|
|
*
|
|
* The file description must be allocated by the caller and a pointer
|
|
* to it is passed to this function.
|
|
*
|
|
* \param name A pointer to the name of the file to be opened.
|
|
* \param f A pointer to the file descriptor struct.
|
|
*
|
|
* \retval 0 If the file was successfully opened.
|
|
* \retval -1 If the file does not exist.
|
|
*/
|
|
/*-----------------------------------------------------------------------------------*/
|
|
int
|
|
c64_fs_open(const char *name, register struct c64_fs_file *f)
|
|
{
|
|
/* First check if we already have the file cached. If so, we don't
|
|
need to do an expensive directory lookup. */
|
|
if(strncmp(lastdirent.name, name, 16) == 0) {
|
|
f->track = lastdirent.track;
|
|
f->sect = lastdirent.sect;
|
|
f->ptr = 2;
|
|
return 0;
|
|
}
|
|
|
|
/* Not in cache, so we walk through directory instead. */
|
|
c64_fs_opendir(&opendir);
|
|
|
|
do {
|
|
c64_fs_readdir_dirent(&opendir, &opendirent);
|
|
if(strncmp(opendirent.name, name, 16) == 0) {
|
|
f->track = opendirent.track;
|
|
f->sect = opendirent.sect;
|
|
f->ptr = 2;
|
|
return 0;
|
|
}
|
|
} while(c64_fs_readdir_next(&opendir) == 0);
|
|
|
|
/* The file was not found in the directory. We flush the directory
|
|
buffer cache now in order to prevent a nasty problem from
|
|
happening: If the first directory block of an empty disk was
|
|
cached, *all* subsequent file opens would return "file not
|
|
found". */
|
|
_c64_fs_dirbuftrack = 0; /* There are no disk blocks on track 0. */
|
|
return -1;
|
|
}
|
|
/*-----------------------------------------------------------------------------------*/
|
|
/**
|
|
* Read data from an open file.
|
|
*
|
|
* This function reads data from an open file into a buffer than must
|
|
* be allocated by the caller.
|
|
*
|
|
* \param f A pointer to a file descriptor structure that must have
|
|
* been opened with c64_fs_open().
|
|
*
|
|
* \param buf A pointer to the buffer in which the data should be placed.
|
|
*
|
|
* \param len The maxiumum amount of bytes to read.
|
|
*
|
|
* \return The number of bytes that actually was read, or 0 if an end
|
|
* of file was encountered.
|
|
*/
|
|
/*-----------------------------------------------------------------------------------*/
|
|
#if !NOASM
|
|
#pragma optimize(push, off)
|
|
#endif /* !NOASM */
|
|
int __fastcall__
|
|
c64_fs_read(register struct c64_fs_file *f, char *buf, int len)
|
|
{
|
|
static int i;
|
|
|
|
/* Check if current block is already in buffer, and if not read it
|
|
from disk. */
|
|
|
|
#if NOASM
|
|
if(f->track != _c64_fs_filebuftrack ||
|
|
_c64_fs_filebufsect != f->sect) {
|
|
_c64_fs_filebuftrack = f->track;
|
|
_c64_fs_filebufsect = f->sect;
|
|
c64_dio_read_block(_c64_fs_filebuftrack, _c64_fs_filebufsect,
|
|
_c64_fs_filebuf);
|
|
}
|
|
#else /* NOASM */
|
|
asm("ldy #%b", offsetof(struct c64_fs_file, track));
|
|
asm("lda (regbank+%b),y", 4);
|
|
asm("cmp %v", _c64_fs_filebuftrack);
|
|
asm("bne doblock");
|
|
|
|
asm("ldy #%b", offsetof(struct c64_fs_file, sect));
|
|
asm("lda (regbank+%b),y", 4);
|
|
asm("cmp %v", _c64_fs_filebufsect);
|
|
asm("bne doblock");
|
|
|
|
asm("jmp noblock");
|
|
|
|
asm("doblock:");
|
|
|
|
asm("ldy #%b", offsetof(struct c64_fs_file, track));
|
|
asm("lda (regbank+%b),y", 4);
|
|
asm("sta %v", _c64_fs_filebuftrack);
|
|
asm("sta %v", c64_dio_asm_track);
|
|
|
|
asm("ldy #%b", offsetof(struct c64_fs_file, sect));
|
|
asm("lda (regbank+%b),y", 4);
|
|
asm("sta %v", _c64_fs_filebufsect);
|
|
asm("sta %v", c64_dio_asm_sector);
|
|
|
|
asm("lda #<(%v)", _c64_fs_filebuf);
|
|
asm("sta %v", c64_dio_asm_ptr);
|
|
asm("lda #>(%v)", _c64_fs_filebuf);
|
|
asm("sta %v+1", c64_dio_asm_ptr);
|
|
|
|
asm("jsr %v", c64_dio_asm_read_block);
|
|
|
|
asm("noblock:");
|
|
|
|
#endif /* NOASM */
|
|
|
|
if(_c64_fs_filebuf[0] == 0 &&
|
|
f->ptr == _c64_fs_filebuf[1]) {
|
|
return 0; /* EOF */
|
|
}
|
|
|
|
for(i = 0; i < len; ++i) {
|
|
#if NOASM
|
|
*buf = _c64_fs_filebuf[f->ptr];
|
|
++f->ptr;
|
|
#else /* NOASM */
|
|
asm("ldy #%o+1", buf);
|
|
asm("jsr ldaxysp");
|
|
asm("sta ptr2");
|
|
asm("stx ptr2+1");
|
|
|
|
asm("ldy #%b", offsetof(struct c64_fs_file, ptr));
|
|
asm("lda (regbank+%b),y", 4);
|
|
asm("tax");
|
|
|
|
asm("ldy #0");
|
|
asm("lda %v,x", _c64_fs_filebuf);
|
|
asm("sta (ptr2),y");
|
|
|
|
asm("inx");
|
|
asm("txa");
|
|
asm("ldy #%b", offsetof(struct c64_fs_file, ptr));
|
|
asm("sta (regbank+%b),y", 4);
|
|
#endif /* NOASM */
|
|
|
|
|
|
if(_c64_fs_filebuf[0] == 0) {
|
|
if(f->ptr == _c64_fs_filebuf[1]) {
|
|
/* End of file reached, we return the amount of bytes read so
|
|
far. */
|
|
return i + 1;
|
|
}
|
|
} else if(f->ptr == 0) {
|
|
|
|
/* Read new block into buffer and set buffer state
|
|
accordingly. */
|
|
_c64_fs_filebuftrack = f->track = _c64_fs_filebuf[0];
|
|
_c64_fs_filebufsect = f->sect = _c64_fs_filebuf[1];
|
|
f->ptr = 2;
|
|
c64_dio_read_block(_c64_fs_filebuftrack,
|
|
_c64_fs_filebufsect, _c64_fs_filebuf);
|
|
}
|
|
|
|
++buf;
|
|
}
|
|
return i;
|
|
}
|
|
#if !NOASM
|
|
#pragma optimize(pop)
|
|
#endif /* !NOASM */
|
|
/*-----------------------------------------------------------------------------------*/
|
|
/**
|
|
* Close an open file.
|
|
*
|
|
* \param f A pointer to a file descriptor struct that previously has
|
|
* been opened with c64_fs_open().
|
|
*/
|
|
/*-----------------------------------------------------------------------------------*/
|
|
void
|
|
c64_fs_close(struct c64_fs_file *f)
|
|
{
|
|
|
|
}
|
|
/*-----------------------------------------------------------------------------------*/
|
|
/**
|
|
* \internal
|
|
* Read a directory buffer into the _c64_fs_dirbuf buffer.
|
|
*
|
|
* This function is shared between this and the c64-fs-raw module.
|
|
*
|
|
* \param track The track of the directory block.
|
|
* \param sect The sector of the directory block.
|
|
*/
|
|
/*-----------------------------------------------------------------------------------*/
|
|
void
|
|
_c64_fs_readdirbuf(unsigned char track, unsigned char sect)
|
|
{
|
|
if(_c64_fs_dirbuftrack == track &&
|
|
_c64_fs_dirbufsect == sect) {
|
|
/* Buffer already contains requested block, return. */
|
|
return;
|
|
}
|
|
c64_dio_read_block(track, sect, _c64_fs_dirbuf);
|
|
_c64_fs_dirbuftrack = track;
|
|
_c64_fs_dirbufsect = sect;
|
|
}
|
|
/*-----------------------------------------------------------------------------------*/
|
|
/**
|
|
* Open the disk directory for reading.
|
|
*
|
|
* The caller must supply a pointer to a directory descriptor.
|
|
*
|
|
* \param d A pointer to a directory description that must be
|
|
* allocated by the caller.
|
|
*/
|
|
/*-----------------------------------------------------------------------------------*/
|
|
unsigned char
|
|
c64_fs_opendir(register struct c64_fs_dir *d)
|
|
{
|
|
d->track = 18;
|
|
d->sect = 1;
|
|
d->ptr = 2;
|
|
|
|
return 0;
|
|
}
|
|
/*-----------------------------------------------------------------------------------*/
|
|
/**
|
|
* Read the current directory entry.
|
|
*
|
|
* This function reads the directory entry to which the directory
|
|
* descriptor currently points into a struct c64_fs_dirent supplied by
|
|
* the caller.
|
|
*
|
|
* The function c64_fs_readdir_next() is used to move the directory
|
|
* entry pointer forward in the directory.
|
|
*
|
|
* \param d A pointer to a directory descriptor previously opened with c64_fs_opendir().
|
|
*
|
|
* \param f A pointer to a directory entry that must have been
|
|
* previously allocated by the caller.
|
|
*/
|
|
/*-----------------------------------------------------------------------------------*/
|
|
void
|
|
c64_fs_readdir_dirent(register struct c64_fs_dir *d,
|
|
register struct c64_fs_dirent *f)
|
|
{
|
|
struct directory_entry *de;
|
|
int i;
|
|
register char *nameptr;
|
|
|
|
_c64_fs_readdirbuf(d->track, d->sect);
|
|
de = (struct directory_entry *)&_c64_fs_dirbuf[d->ptr];
|
|
nameptr = de->name;
|
|
for(i = 0; i < 16; ++i) {
|
|
if(*nameptr == 0xa0) {
|
|
*nameptr = 0;
|
|
break;
|
|
}
|
|
++nameptr;
|
|
}
|
|
strncpy(f->name, de->name, 16);
|
|
f->track = de->track;
|
|
f->sect = de->sect;
|
|
f->size = de->blockslo + (de->blockshi >> 8);
|
|
memcpy(&lastdirent, f, sizeof(struct c64_fs_dirent));
|
|
}
|
|
/*-----------------------------------------------------------------------------------*/
|
|
/**
|
|
* Move the directory pointer forward.
|
|
*
|
|
* This function moves the directory entry pointer in the directory
|
|
* descriptor forward so that it points to the next file.
|
|
*
|
|
* \param d A pointer to a directory descriptor previously opened with
|
|
* c64_fs_opendir().
|
|
*
|
|
* \retval 1 If there are no more directory entried in the directory.
|
|
* \retval 0 There were more directory entries and the pointer has
|
|
* been moved to point to the next one.
|
|
*/
|
|
/*-----------------------------------------------------------------------------------*/
|
|
unsigned char
|
|
c64_fs_readdir_next(struct c64_fs_dir *d)
|
|
{
|
|
struct directory_entry *de;
|
|
again:
|
|
_c64_fs_readdirbuf(d->track, d->sect);
|
|
if(d->ptr == 226) {
|
|
if(_c64_fs_dirbuf[0] == 0) {
|
|
return 1;
|
|
}
|
|
d->track = _c64_fs_dirbuf[0];
|
|
d->sect = _c64_fs_dirbuf[1];
|
|
d->ptr = 2;
|
|
} else {
|
|
d->ptr += 32;
|
|
}
|
|
|
|
de = (struct directory_entry *)&_c64_fs_dirbuf[d->ptr];
|
|
if(de->type == 0) {
|
|
goto again;
|
|
}
|
|
return 0;
|
|
}
|
|
/*-----------------------------------------------------------------------------------*/
|
|
/**
|
|
* Close a directory descriptor previously opened by c64_fs_opendir().
|
|
*
|
|
* \param d A poitner to a directory descriptor previously opened with
|
|
* c64_fs_opendir().
|
|
*/
|
|
/*-----------------------------------------------------------------------------------*/
|
|
void
|
|
c64_fs_closedir(struct c64_fs_dir *d)
|
|
{
|
|
|
|
}
|
|
/*-----------------------------------------------------------------------------------*/
|
|
/** @} */
|