software.rar

ATmega8515 co wgrać do procesora

Witam wszystkich. Zaczynam właśnie nowy rozdział w dziedzinie elektroniki a mianowicie mikro-kontrolery. i już na samym początku spotkałem się z trudnościami. Budując kontroler HDD do Commodore 64 Ściągnąłem z internetu schematy i wsad do procesora ATmega8515 ,mój problem polega na tym że nie wiem co wgrać do procesora. W folderze załączonym w archiwum jest kilka plików i nie wiem co wgrać. Prosiłbym o pomoc w tej sprawie i o ewentualne wytłumaczenie do czego te pozostałe pliki służą. Z góry dziękuje i pozdrawiam.

  • software.rar
    • dos-init.c
    • flash.hex
    • INSTALL
    • dos-dir.c
    • Makefile
    • iecata.h
    • iec.c
    • dos-file.c
    • avr85xx-32k.x
    • iecata.c
    • ata.c


Pobierz plik - link do postu

software.rar > dos-init.c

/*
IEC-ATA, a hard drive controller for the CBM IEC bus
Copyright (C) 2002 Asbj?rn Djupdal

This program 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
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

----

The author of IEC-ATA may be reached by electronic mail:

djupdal@idi.ntnu.no

or if the email address no longer is valid, by paper mail:

Asbj?rn Djupdal
Gr?nngjelet 50
4640 S?GNE
NORWAY
*/

/*
dos-init.c V1.0
Contains the initialization, formatting and free block management
code for the file system
*/

#include " iecata.h "

#define FS_VERSION_STRING " adfs 1.0 "
#define SUPERBLOCK 0

struct superblockStruct {
block_t freeBlockList;
char versionString[sizeof (FS_VERSION_STRING)];
uint8_t reserved[BLOCKSIZE - sizeof (block_t) - sizeof (FS_VERSION_STRING)];
};

/* protos ****************************************************************/

/* variables *************************************************************/

static block_t freeBlocks[BLOCKSIZE / sizeof (block_t)];
static struct superblockStruct superblock;
static uint8_t freeBlocksIndex;
static char *fs_version_string;

/* functions *************************************************************/

bool_t dosInit (void) {
/* get pointer to version string */
fs_version_string = PSTR (FS_VERSION_STRING);

/* read superblock */
ataGetBlock (SUPERBLOCK, (uint8_t *) & superblock);

/* check if HD is formatted with correct file system */
if (strncmp_P (superblock.versionString, fs_version_string,
sizeof (FS_VERSION_STRING))) {
/* invalid disk */
return FALSE;
}

/* read first block of free block list */
ataGetBlock (superblock.freeBlockList, (uint8_t *)freeBlocks);
freeBlocksIndex = 0;

/* init the other dos modules */
dosDirInit();
dosFileInit();

return TRUE;
}

inline extern bool_t formatDrive (void) {
/* Set up and write superblock */
memcpy_P (superblock.versionString, fs_version_string,
sizeof (FS_VERSION_STRING));
superblock.freeBlockList = 2;
ataPutBlock (SUPERBLOCK, (uint8_t *) & superblock);

memset (freeBlocks, '\0', BLOCKSIZE);

/* create empty root directory */
ataPutBlock (ROOTBLOCK, (uint8_t *)freeBlocks);

{ /* create the free block list */
bool_t done = FALSE;
block_t blockCount = superblock.freeBlockList + 1;

/* one loop is one block in free block list */
while (!done) {
uint8_t i = 0;
block_t currentBlock = blockCount - 1;

memset (freeBlocks, '\0', BLOCKSIZE);

/* set up the pointers in the current free block list block */
while (!done & & (i & lt; (BLOCKSIZE / sizeof (block_t)))) {
freeBlocks[i] = blockCount++;
if (blockCount & gt; = totalDiskSize) {
done = TRUE;
}
i++;
}
ataPutBlock (currentBlock, (uint8_t *)freeBlocks);
}
}

/* Init FS to newly formatted disk */
return dosInit();
}

block_t allocateBlock (void) {
block_t block;

while (TRUE) {
/* if at the end, load next block in free block list */
if (freeBlocksIndex == ((BLOCKSIZE / sizeof (block_t)) - 1)) {
block_t nextFreeFileBlock;
/* if no more blocks, return 0 */
if (!(nextFreeFileBlock = freeBlocks[freeBlocksIndex])) {
return 0; /* FIXME: the last block don't get allocated */
}
/* load next block in the free block list */
ataGetBlock (nextFreeFileBlock, (uint8_t *)freeBlocks);
block = superblock.freeBlockList;
superblock.freeBlockList = nextFreeFileBlock;
freeBlocksIndex = 0;
ataPutBlock (SUPERBLOCK, (uint8_t *) & superblock);
/* return the previous free file block */
return block;
}
/* return next block in the list if != 0 */
if ((block = freeBlocks[freeBlocksIndex])) {
freeBlocks[freeBlocksIndex++] = 0;
return block;
}
freeBlocksIndex++;
}
return 0;
}

void freeBlock (block_t block) {
bool_t done = FALSE;
uint8_t index = 0;

while (!done) {
/* if block is full of ptrs to free blocks, extend
free block list with this one at the beginning */
if (index == ((BLOCKSIZE / sizeof (block_t)) - 1)) {
flushFreeBlockList();
memset (freeBlocks, '\0', BLOCKSIZE);
freeBlocks[(BLOCKSIZE / sizeof (block_t)) - 1] =
superblock.freeBlockList;
superblock.freeBlockList = block;
ataPutBlock (SUPERBLOCK, (uint8_t *) & superblock);
done = TRUE;
}
/* if empty place in free block list, put this one there */
if (!freeBlocks[index]) {
freeBlocks[index] = block;
freeBlocksIndex = 0;
done = TRUE;
}
index++;
}
}

void flushFreeBlockList (void) {
ataPutBlock (superblock.freeBlockList, (uint8_t *)freeBlocks);
}


software.rar > dos-dir.c

/*
IEC-ATA, a hard drive controller for the CBM IEC bus
Copyright (C) 2002 Asbj?rn Djupdal

This program 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
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

----

The author of IEC-ATA may be reached by electronic mail:

djupdal@idi.ntnu.no

or if the email address no longer is valid, by paper mail:

Asbj?rn Djupdal
Gr?nngjelet 50
4640 S?GNE
NORWAY
*/

/*
dos-dir.c V1.0
Contains the directory handling code for the file system
*/

#include " iecata.h "

#define DIR_ENTRIES_IN_BLOCK ((BLOCKSIZE - sizeof (block_t)) / \
sizeof (struct dirEntryStruct))

struct dirBlockStruct {
block_t nextBlock;
struct dirEntryStruct dirEntry[DIR_ENTRIES_IN_BLOCK];
uint8_t reserved[BLOCKSIZE - sizeof (block_t) -
(DIR_ENTRIES_IN_BLOCK * sizeof (struct dirEntryStruct))];
};

/* protos ****************************************************************/

struct dirEntryStruct *getUsedEntryInCurrentBlock (void);

/* variables *************************************************************/

static struct dirBlockStruct dirBuffer;
static block_t dirBufferBlock;
static entryIndex_t dirBufferBlockNumber;
bool_t dirBufferChanged;
block_t currentDir;

/* functions *************************************************************/

inline extern void dosDirInit (void) {
/* Remove contents from directory buffer */
dirBufferChanged = FALSE;
dirBufferBlock = 0;
dirBufferBlockNumber = ~0;

/* start with root dir */
currentDir = ROOTBLOCK;
}

bool_t setCurrentDir (char *path) {
struct dirEntryStruct *entry;
block_t nextCurrentDir = 0;

if (*path == '/') {
path++;
nextCurrentDir = ROOTBLOCK;
getBlock (ROOTBLOCK);
} else {
getBlock (currentDir);
}

while (TRUE) {
if (!(*path)) {
currentDir = nextCurrentDir;
dirBufferBlockNumber = ~0;
return TRUE;
}
if (!(entry = getEntryByName (path))) {
/* can't find dir */
return FALSE;
}
if (entry- & gt; fileType != DIR) {
/* not a dir */
return FALSE;
}
nextCurrentDir = entry- & gt; startBlock;
if (!(path = strchr (path, '/'))) {
/* no more elements in path */
currentDir = nextCurrentDir;
dirBufferBlockNumber = ~0;
return TRUE;
}
path++; /* skip '/' */
getBlock (entry- & gt; startBlock);
}
}

inline extern bool_t createDir (char *name) {
struct dirEntryStruct *entry;

getBlock (currentDir);

if (nameValid (name)) {
if ((entry = getUnusedEntry())) {
if (!getEntryByName (name)) {
if ((entry- & gt; startBlock = allocateBlock())) {

dirBufferChanged = TRUE;

/* set entry */
memcpy (entry- & gt; fileName, name, FILE_NAME_SIZE);
entry- & gt; fileSize = 0;
entry- & gt; fileType = DIR;
entry- & gt; readOnly = FALSE;
entry- & gt; splat = FALSE;

{ /* init new directory block */
getBlock (entry- & gt; startBlock);
memset ( & dirBuffer, '\0', BLOCKSIZE);
dirBuffer.dirEntry[0].startBlock = currentDir;
memcpy_P (dirBuffer.dirEntry[0].fileName, PSTR ( " .. " ), 3);
dirBuffer.dirEntry[0].fileSize = 0;
dirBuffer.dirEntry[0].fileType = DIR;
dirBuffer.dirEntry[0].readOnly = TRUE;
dirBuffer.dirEntry[0].splat = FALSE;
dirBufferChanged = TRUE;
}

flushDirBuffer();
flushFreeBlockList();
return TRUE;
}
}
}
}
return FALSE;
}

inline extern void deleteDir (char *pattern) {
struct dirEntryStruct *entry;
entryIndex_t entryIndex = 0;

while ((entry = getEntry (entryIndex++))) {
/* only process non-deleted dirs */
if (entry- & gt; startBlock) {
/* only delete dirs that match pattern */
if (filenameMatch (entry- & gt; fileName, pattern)) {
block_t blockWithEntry = dirBufferBlock;

/* only delete dirs */
if (entry- & gt; fileType == DIR) {
getBlock (entry- & gt; startBlock);
/* only delete empty dirs */
if (!getUsedEntryInCurrentBlock()) {
/* delete directory */
getBlock (blockWithEntry);
freeBlock (entry- & gt; startBlock);
deleteEntry (entry);
flushDirBuffer();
flushFreeBlockList();
/* begin counting at 0 because direntries may have been moved */
entryIndex = 0;
}
}
}
}
}
}

inline extern bool_t renameEntry (char *newName, char *oldNamePattern) {
struct dirEntryStruct *entry;

getBlock (currentDir);

if ((entry = getEntryByName (oldNamePattern))) {
block_t blockWithEntry = dirBufferBlock;
if (!getEntryByName (newName)) {
getBlock (blockWithEntry);
memcpy (entry- & gt; fileName, newName, FILE_NAME_SIZE);
dirBufferChanged = TRUE;
flushDirBuffer();
return TRUE;
}
}
return FALSE;
}

struct dirEntryStruct *getEntry (entryIndex_t entryIndex) {
entryIndex_t blockNumber = entryIndex / DIR_ENTRIES_IN_BLOCK;

if (dirBufferBlockNumber != blockNumber) {
entryIndex_t i;

/* find correct directory block */
getBlock (currentDir);
for (i = 0; i & lt; blockNumber; i++) {
if (!dirBuffer.nextBlock) {
return NULL;
}
getBlock (dirBuffer.nextBlock);
}
dirBufferBlockNumber = blockNumber;
}

return & dirBuffer.dirEntry[entryIndex % DIR_ENTRIES_IN_BLOCK];
}

struct dirEntryStruct *getUsedEntryInCurrentBlock (void) {
entryIndex_t i;

for (i = 0; i & lt; DIR_ENTRIES_IN_BLOCK; i++) {
if (dirBuffer.dirEntry[i].startBlock & &
!(dirBuffer.dirEntry[i].readOnly)) {
return & dirBuffer.dirEntry[i];
}
}
return NULL;
}

struct dirEntryStruct *getUnusedEntry (void) {
while (TRUE) {
entryIndex_t i;

/* search through current block for an empty entry */
for (i = 0; i & lt; DIR_ENTRIES_IN_BLOCK; i++) {
if (!dirBuffer.dirEntry[i].startBlock) {
return & dirBuffer.dirEntry[i];
}
}
/* if no more blocks in directory chain, make a new one */
if (!dirBuffer.nextBlock) {
if (!(dirBuffer.nextBlock = allocateBlock())) {
return NULL;
}
dirBufferChanged = TRUE;
flushDirBuffer();
dirBufferBlock = dirBuffer.nextBlock;
dirBufferBlockNumber = ~0;
memset ( & dirBuffer, '\0', BLOCKSIZE);
dirBufferChanged = TRUE;
} else { /* load the next dir block in chain */
getBlock (dirBuffer.nextBlock);
}
}
return NULL;
}

struct dirEntryStruct *getEntryByName (char *name) {
while (TRUE) {
entryIndex_t i;

/* search for entry in current block */
for (i = 0; i & lt; DIR_ENTRIES_IN_BLOCK; i++) {
if (dirBuffer.dirEntry[i].startBlock) { /* not deleted */
if (filenameMatch (dirBuffer.dirEntry[i].fileName, name)) {
return & dirBuffer.dirEntry[i];
}
}
}
/* if no more blocks in chain, return NULL */
if (!dirBuffer.nextBlock) {
return NULL;
}
/* get next block */
getBlock (dirBuffer.nextBlock);
}
return NULL;
}

void getBlock (block_t block) {
/* only read block if not allready in memory */
if (block != dirBufferBlock) {
flushDirBuffer();
dirBufferBlock = block;
dirBufferBlockNumber = ~0;
dirBufferChanged = FALSE;
ataGetBlock (block, (uint8_t *) & dirBuffer);
}
}

void flushDirBuffer (void) {
/* only flush if buffer has changed */
if (dirBufferChanged) {
ataPutBlock (dirBufferBlock, (uint8_t *) & dirBuffer);
}
}

void deleteEntry (struct dirEntryStruct *entry) {
block_t oldBlock = dirBufferBlock;

/* if directory has more blocks in chain, move an entry from
the last block in chain to this block */
if (dirBuffer.nextBlock) {
struct dirEntryStruct *entryToMove;
struct dirEntryStruct copyOfEntry;
block_t prevBlock = oldBlock;

/* find the last block in dir chain */
while (dirBuffer.nextBlock) {
prevBlock = dirBufferBlock;
getBlock (dirBuffer.nextBlock);
}
/* if no entries in last dir block, remove the last dir block */
if (!(entryToMove = getUsedEntryInCurrentBlock())) {
getBlock (prevBlock);
freeBlock (dirBuffer.nextBlock);
flushFreeBlockList();
dirBuffer.nextBlock = 0;
dirBufferChanged = TRUE;
/* get an entry to move */
if (!(entryToMove = getUsedEntryInCurrentBlock())) {
/* TODO: error recovery */
}
}
/* overwrite the entry to be deleted with the one just found */
if (dirBufferBlock != oldBlock) {
memcpy ( & copyOfEntry, entryToMove, sizeof (struct dirEntryStruct));
entryToMove- & gt; startBlock = 0;
dirBufferChanged = TRUE;
getBlock (oldBlock);
memcpy (entry, & copyOfEntry, sizeof (struct dirEntryStruct));
dirBufferChanged = TRUE;
} else { /* delete entry */
entry- & gt; startBlock = 0;
dirBufferChanged = TRUE;
}
} else { /* delete entry */
entry- & gt; startBlock = 0;
dirBufferChanged = TRUE;
}
}

bool_t nameValid (char *name) {
uint8_t bytes = 16;

/* don't accept empty file names */
if (!(*name)) {
return FALSE;
}

/* check up to 16 bytes for illegal characters */
while (*name & & (bytes-- != 0)) {
if ((*name == '?') || (*name == '*') || (*name == '/') ||
(*name == ':') || (*name == ',')) {
return FALSE;
}
name++;
}
return TRUE;
}

bool_t filenameMatch (char *name, char *pattern) {
bool_t done = FALSE;
uint8_t bytes = 16;

while (!done) {
if ((bytes-- == 0) || (*pattern == '/') || (*pattern == '*') ||
((*name == '\0') & & (*pattern == '\0'))) {
return TRUE;
}
if ((*pattern == '?') || (*name == *pattern)) {
name++;
pattern++;
} else {
done = TRUE;
}
}
return FALSE;
}


software.rar > iecata.h

/*
IEC-ATA, a hard drive controller for the CBM IEC bus
Copyright (C) 2002 Asbj?rn Djupdal

This program 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
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

----

The author of IEC-ATA may be reached by electronic mail:

djupdal@idi.ntnu.no

or if the email address no longer is valid, by paper mail:

Asbj?rn Djupdal
Gr?nngjelet 50
4640 S?GNE
NORWAY
*/

/*
iecata.h V1.0
The main header file for the IEC-ATA software.
*/

#ifndef IECATA_H
#define IECATA_H

#include & lt; string.h & gt;
#include & lt; ctype.h & gt;

#ifdef UNIX
/* compile for unix.
dos-init.c, dos-file.c and dos-dir.c may be compiled for unix,
making the file system code available for unix programs */
#include & lt; stdio.h & gt;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#define strncpy_P strncpy
#define memcpy_P memcpy
#define strncmp_P strncmp
#define PSTR(x) x

#else
/* compile for AVR */
#include & lt; inttypes.h & gt;
#include & lt; sig-avr.h & gt;
#include & lt; interrupt.h & gt;
#include & lt; io.h & gt;
#include & lt; eeprom.h & gt;
#include & lt; pgmspace.h & gt;
#endif

typedef uint8_t bool_t;
typedef uint32_t block_t;
typedef uint8_t entryIndex_t;
typedef uint16_t fileSize_t;
typedef uint16_t bufferSize_t;

#define FALSE 0
#define TRUE (~FALSE)

enum commands {
IDLE, LISTEN_OPEN, LISTEN_CLOSE, LISTEN_DATA, TALK_DATA
};

#define ROOTBLOCK 1
#define BLOCKSIZE 512
#define FILE_NAME_SIZE 16
#define MAX_OPEN_FILES 16
#define LED PD5
#define COMMAND_CHANNEL 0x0f

enum filetypes {
ANY, SEQ = 1, PRG = 2, DIR = 3
};

struct dirEntryStruct {
char fileName[FILE_NAME_SIZE];
block_t startBlock;
fileSize_t fileSize; /* number of blocks in file */
bufferSize_t bytesInLastBlock; /* number of bytes in the last block */
uint8_t fileType;
bool_t readOnly; /* TODO: this works like dm-dos TYPE_SYSTEM */
bool_t splat; /* file not closed properly */
uint8_t pad; /* dummy byte to get a structure of 28 bytes */
};

enum fileStates {
NO_FILE, READ_FILE, WRITE_FILE
};

enum readDirStates {
NOT_READ_DIR, READ_DIR_BEGIN, READ_DIR_PROGRESS, READ_DIR_FINISHED
};

struct channelTableStruct {
struct dirEntryStruct dirEntry;
uint8_t fileState;
uint8_t readDirState;
bufferSize_t bufferPtr;
bufferSize_t endOfBuffer;
block_t dirBlock;
block_t inodeBlock;
bufferSize_t inodePtr;
uint8_t buffer[BLOCKSIZE];
block_t inode[BLOCKSIZE / sizeof (block_t)];
};

/* protos & externs ******************************************************/

/* iecata.c */
extern uint8_t command;
extern uint8_t error;
extern uint8_t channelNumber;

/* iec.c */
bool_t iecListen (uint8_t *data, bufferSize_t maxBytes,
bufferSize_t *bytesReceived);
void iecTalk (uint8_t *data, bufferSize_t bytesToSend,
bufferSize_t *bytesSendt, bool_t eoi);
void iecAttention (void);

/* ata.c */
extern block_t totalDiskSize;
bool_t ataInit (void);
void ataGetBlock (block_t blockNumber, uint8_t *block);
void ataPutBlock (block_t blockNumber, uint8_t *block);

/* dos-init.c */
bool_t dosInit (void);
bool_t formatDrive (void);
block_t allocateBlock (void);
void freeBlock (block_t block);
void flushFreeBlockList (void);

/* dos-dir.c */
extern block_t currentDir;
extern bool_t dirBufferChanged;
void dosDirInit (void);
bool_t setCurrentDir (char *path);
bool_t createDir (char *name);
void deleteDir (char *pattern);
bool_t renameEntry (char *newName, char *oldNamePattern);
struct dirEntryStruct *getEntry (entryIndex_t entryIndex);
struct dirEntryStruct *getUnusedEntry (void);
struct dirEntryStruct *getEntryByName (char *name);
void deleteEntry (struct dirEntryStruct *entry);
void getBlock (block_t block);
void flushDirBuffer (void);
bool_t nameValid (char *name);
bool_t filenameMatch (char *name, char *pattern);

/* dos-file.c */
extern struct channelTableStruct channelTable[MAX_OPEN_FILES];
void dosFileInit (void);
bool_t openRead (char *pattern, uint8_t fileType, uint8_t channel);
bool_t openWrite (char *name, uint8_t fileType, uint8_t channel);
void closeFile (uint8_t channel);
bool_t readFile (uint8_t channel, bool_t *eof);
bool_t writeFile (uint8_t channel);
void deleteFile (char *pattern);

#endif


software.rar > iec.c

/*
IEC-ATA, a hard drive controller for the CBM IEC bus
Copyright (C) 2002 Asbj?rn Djupdal

This program 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
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

----

The author of IEC-ATA may be reached by electronic mail:

djupdal@idi.ntnu.no

or if the email address no longer is valid, by paper mail:

Asbj?rn Djupdal
Gr?nngjelet 50
4640 S?GNE
NORWAY
*/

/*
iec.c V1.0
Contains the IEC serial bus protocol code
*/

#include " iecata.h "

#define JUMPER PB0

#define IEC_CLK_OUT PD0
#define IEC_DATA_OUT PD1
#define IEC_ATN_IN PD2
#define IEC_CLK_IN PD3
#define IEC_DATA_IN PD4

#define DEVICENUMBER 10

#define LISTEN 0x20
#define TALK 0x40
#define UNLISTEN 0x3f
#define UNTALK 0x5f
#define OPEN 0xf0
#define CLOSE 0xe0
#define DATA 0x60

/* protos ****************************************************************/

static bool_t iecGetByte (uint8_t *data);
static void iecPutByte (uint8_t data, bool_t eoi);
static void iecDelay (void);

/* variables *************************************************************/

volatile bool_t attention;

/* functions *************************************************************/

bool_t iecListen (uint8_t *data, bufferSize_t maxBytes,
bufferSize_t *bytesReceived) {
bool_t eoi = FALSE;

/* init bytes received */
*bytesReceived = 0;

while (!eoi & & (*bytesReceived & lt; maxBytes)) {
/* wait for talker ready to send */
loop_until_bit_is_set (PIND, IEC_CLK_IN);
/* fetch next byte */
eoi = iecGetByte (data + (*bytesReceived)++);
}

/* Release line after a suitable (?) pause */
/* TODO: find the correct delay.
This seems to cause errors sometimes */
if (eoi) {
iecDelay();
cbi (PORTD, IEC_DATA_OUT);
}

return eoi;
}

/* bytesToSend must be & gt; 0 */
inline extern void iecTalk (uint8_t *data, bufferSize_t bytesToSend,
bufferSize_t *bytesSendt, bool_t eoi) {

/* init bytes sendt */
*bytesSendt = 0;

while (!attention & & (*bytesSendt & lt; bytesToSend)) {
/* signal ready to send */
cbi (PORTD, IEC_CLK_OUT);
/* wait for listener */
while (!attention & & bit_is_clear (PIND, IEC_DATA_IN));
if (!attention) {
if (*bytesSendt == (bytesToSend - 1)) {
/* send last byte */
iecPutByte (data[*bytesSendt], eoi);
} else {
/* send byte */
iecPutByte (data[*bytesSendt], FALSE);
}
/* increase byte counter */
(*bytesSendt)++;
}
}

/* Release line after a suitable (?) pause */
/* TODO: find the correct delay.
This seems to cause errors sometimes */
if (eoi) {
iecDelay();
cbi (PORTD, IEC_CLK_OUT);
}
}

inline extern void iecAttention (void) {
cli();
if (attention) {
static uint8_t data[2];
uint8_t *dataPtr = & data[0];

/* LED off */
sbi (PORTD, LED);

/* reset attention flag */
attention = FALSE;

/* default command */
command = IDLE;

/* fetch control bytes from iec talker */
while (TRUE) {
/* quit interrupt when IEC ATN is released */
if (bit_is_set (PIND, IEC_ATN_IN)) {
/* decode received control data */
if ((data[0] & 0x1f) == DEVICENUMBER) {
/* get secondary address */
channelNumber = data[1] & 0x0f;

if ((data[0] == UNLISTEN) || (data[0] == UNTALK)) {
/* release IEC DATA */
cbi (PORTD, IEC_DATA_OUT);
} else if ((data[0] & 0xe0) == LISTEN) {
if ((data[1] & 0xf0) == OPEN) {
command = LISTEN_OPEN;
error = 0;
} else if ((data[1] & 0xf0) == CLOSE) {
if (!error) {
command = LISTEN_CLOSE;
}
/* release IEC DATA */
cbi (PORTD, IEC_DATA_OUT);
} else if ((data[1] & 0xf0) == DATA) {
if (error) {
/* release IEC DATA */
cbi (PORTD, IEC_DATA_OUT);
} else {
command = LISTEN_DATA;
}
}
} else if ((data[0] & 0xe0) == TALK) {
/* do turn-around sequence */
/* wait for IEC CLK */
loop_until_bit_is_set (PIND, IEC_CLK_IN);
/* release IEC DATA */
cbi (PORTD, IEC_DATA_OUT);
/* delay */
iecDelay();
/* take IEC CLK */
sbi (PORTD, IEC_CLK_OUT);
/* delay */
iecDelay();
if (!error || (channelNumber == COMMAND_CHANNEL)) {
command = TALK_DATA;
} else {
/* release IEC CLK */
cbi (PORTD, IEC_CLK_OUT);
}
}
} else {
/* release IEC DATA */
cbi (PORTD, IEC_DATA_OUT);
}
break;
}
/* fetch new byte if IEC CLK is released */
if (bit_is_set (PIND, IEC_CLK_IN)) {
iecGetByte (dataPtr++);
}
}
}
sei();
}

bool_t iecGetByte (uint8_t *data) {
bool_t eoi = FALSE;

/* signal ready to listen */
cbi (PORTD, IEC_DATA_OUT);

/* wait for all other devices */
loop_until_bit_is_set (PIND, IEC_DATA_IN);

/* wait for talker, maximum 200us */
outp (0x00, TCNT0);
while (!eoi) {
if (inp (TCNT0) & gt; 100) {
eoi = TRUE;
}
if (bit_is_clear (PIND, IEC_CLK_IN)) {
break;
}
}

/* acknowledge if eoi */
if (eoi) {
/* set IEC DATA */
sbi (PORTD, IEC_DATA_OUT);
/* delay */
iecDelay();
/* clear IEC DATA */
cbi (PORTD, IEC_DATA_OUT);
/* wait for talker */
loop_until_bit_is_clear (PIND, IEC_CLK_IN);
}

{ /* fetch byte */
uint8_t bitnumber;

for (bitnumber = 0; bitnumber & lt; 8; bitnumber++) {
/* shift result right */
*data & gt; & gt; = 1;

/* wait for next bit */
loop_until_bit_is_set (PIND, IEC_CLK_IN);
/* fetch bit */
if (bit_is_set (PIND, IEC_DATA_IN)) {
*data |= 0x80;
}

/* wait for IEC CLK */
loop_until_bit_is_clear (PIND, IEC_CLK_IN);
}

/* acknowledge byte received */
sbi (PORTD, IEC_DATA_OUT);
}

return eoi;
}

void iecPutByte (uint8_t data, bool_t eoi) {
if (eoi) {
/* wait for listener to acknowledge EOI */
loop_until_bit_is_clear (PIND, IEC_DATA_IN);
/* wait for listener */
loop_until_bit_is_set (PIND, IEC_DATA_IN);
}

/* wait for listener to detect signal changes */
iecDelay();

/* set IEC CLK */
sbi (PORTD, IEC_CLK_OUT);

{ /* send byte */
uint8_t bitnumber;

for (bitnumber = 0; bitnumber & lt; 8; bitnumber++) {
/* delay */
iecDelay();
/* put data on line */
if (data & 0x01) {
cbi (PORTD, IEC_DATA_OUT);
} else {
sbi (PORTD, IEC_DATA_OUT);
}
/* signal data ready */
cbi (PORTD, IEC_CLK_OUT);
/* delay */
iecDelay();
/* set IEC CLK */
sbi (PORTD, IEC_CLK_OUT);
/* release IEC DATA */
cbi (PORTD, IEC_DATA_OUT);
/* shift data right */
data & gt; & gt; = 1;
}
/* wait for listener to ackowledge */
/* TODO: timeout */
loop_until_bit_is_clear (PIND, IEC_DATA_IN);
}
}

static void iecDelay (void) {
outp (0x00, TCNT0);

if (bit_is_set (PINB, JUMPER)) {
/* slow (C64) timing: & gt; 60us */
while (inp (TCNT0) & lt; 35);
} else {
/* fast (VIC20) timing: & gt; 20us */
while (inp (TCNT0) & lt; 15);
}
}

INTERRUPT (SIG_INTERRUPT0) {
/* wait a short delay to ensure host has all lines ready */
outp (0x00, TCNT0);
while (inp (TCNT0) & lt; 100);

/* release IEC CLK */
cbi (PORTD, IEC_CLK_OUT);

/* set IEC DATA */
sbi (PORTD, IEC_DATA_OUT);

/* set attention flag */
attention = TRUE;
}


software.rar > dos-file.c

/*
IEC-ATA, a hard drive controller for the CBM IEC bus
Copyright (C) 2002 Asbj?rn Djupdal

This program 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
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

----

The author of IEC-ATA may be reached by electronic mail:

djupdal@idi.ntnu.no

or if the email address no longer is valid, by paper mail:

Asbj?rn Djupdal
Gr?nngjelet 50
4640 S?GNE
NORWAY
*/

/*
dos-file.c V1.0
Contains the file system code that handles file access
*/

#include " iecata.h "

/* protos ****************************************************************/

/* variables *************************************************************/

struct channelTableStruct channelTable[MAX_OPEN_FILES];
static uint8_t tmpBuffer[BLOCKSIZE];

/* functions *************************************************************/

inline extern void dosFileInit (void) {
uint8_t i;
struct channelTableStruct *channelStruct;

for (i = 0; i & lt; MAX_OPEN_FILES; i++) {
channelStruct = & channelTable[i];
channelStruct- & gt; fileState = NO_FILE;
channelStruct- & gt; bufferPtr = 0;
channelStruct- & gt; endOfBuffer = 0;
}
}

inline extern bool_t openRead (char *pattern, uint8_t fileType,
uint8_t channel) {
struct dirEntryStruct *entry;
struct channelTableStruct *channelStruct = & channelTable[channel];

if (channelStruct- & gt; fileState == NO_FILE) {
getBlock (currentDir);
if ((entry = getEntryByName (pattern))) {
if ((fileType == ANY) || (entry- & gt; fileType == fileType)) {
/* TODO: should perhaps have some kind of file lock here */

/* set channel struct */
memcpy ( & channelStruct- & gt; dirEntry, entry,
sizeof (struct dirEntryStruct));
channelStruct- & gt; inodePtr = 0;
channelStruct- & gt; dirBlock = currentDir;
/* read first inode block into mem */
ataGetBlock (entry- & gt; startBlock,
(uint8_t *)(channelStruct- & gt; inode));

return TRUE;
}
}
}
return FALSE;
}

inline extern bool_t openWrite (char *name, uint8_t fileType,
uint8_t channel) {
struct dirEntryStruct *entry;
struct channelTableStruct *channelStruct = & channelTable[channel];

if (nameValid (name)) {
if (channelStruct- & gt; fileState == NO_FILE) {
getBlock (currentDir);
if (!getEntryByName (name)) {
if ((entry = getUnusedEntry())) {
/* create first inode */
memset ( & (channelStruct- & gt; inode), '\0', BLOCKSIZE);

if ((channelStruct- & gt; inodeBlock = allocateBlock())) {
/* set entry */
entry- & gt; startBlock = channelStruct- & gt; inodeBlock;
memcpy (entry- & gt; fileName, name, FILE_NAME_SIZE);
entry- & gt; fileSize = 0;
entry- & gt; fileType = fileType;
entry- & gt; splat = TRUE;
/* set channel struct */
memcpy ( & channelStruct- & gt; dirEntry, entry,
sizeof (struct dirEntryStruct));
channelStruct- & gt; dirBlock = currentDir;
channelStruct- & gt; inodePtr = 0;
/* save entry to disk */
dirBufferChanged = TRUE;
flushDirBuffer();

return TRUE;
}
}
}
}
}
return FALSE;
}

void closeFile (uint8_t channel) {
struct channelTableStruct *channelStruct = & channelTable[channel];

if ((channelStruct- & gt; readDirState == NOT_READ_DIR) & &
(channelStruct- & gt; fileState == WRITE_FILE)) {
struct dirEntryStruct *entry;

/* save last block */
writeFile (channel);
channelStruct- & gt; dirEntry.bytesInLastBlock = channelStruct- & gt; bufferPtr;

getBlock (channelStruct- & gt; dirBlock);
if (!(entry = getEntryByName (channelStruct- & gt; dirEntry.fileName))) {
return; /* FIXME, cleanup */
}
/* write inode */
ataPutBlock (channelStruct- & gt; inodeBlock,
(uint8_t *)(channelStruct- & gt; inode));
/* copy back direntry */
memcpy (entry, & channelStruct- & gt; dirEntry, sizeof (struct dirEntryStruct));
entry- & gt; splat = FALSE;
dirBufferChanged = TRUE;
flushDirBuffer();
/* flush free block list */
flushFreeBlockList();

}
channelStruct- & gt; fileState = NO_FILE;
}

inline extern bool_t readFile (uint8_t channel, bool_t *eof) {
struct channelTableStruct *channelStruct = & channelTable[channel];

if (!channelStruct- & gt; dirEntry.fileSize) {
/* don't read anything if file has no more bytes */
*eof = TRUE;
} else {

/* if at end of inode, get next inode */
if (channelStruct- & gt; inodePtr == (BLOCKSIZE / sizeof (block_t)) - 1) {
ataGetBlock (channelStruct- & gt; inode[channelStruct- & gt; inodePtr],
(uint8_t *)(channelStruct- & gt; inode));
channelStruct- & gt; inodePtr = 0;
}

/* get data block */
ataGetBlock (channelStruct- & gt; inode[channelStruct- & gt; inodePtr++],
channelStruct- & gt; buffer);

channelStruct- & gt; dirEntry.fileSize--;

if (!channelStruct- & gt; dirEntry.fileSize) {
*eof = TRUE;
}
}

return TRUE;
}

bool_t writeFile (uint8_t channel) {
struct channelTableStruct *channelStruct = & channelTable[channel];

/* if at end of inode, make new inode */
if (channelStruct- & gt; inodePtr ==
(BLOCKSIZE / sizeof (block_t)) - 1) {
if (!(channelStruct- & gt; inode[channelStruct- & gt; inodePtr] = allocateBlock())) {
return FALSE; /* FIXME, cleanup */
}
ataPutBlock (channelStruct- & gt; inodeBlock, (uint8_t *)(channelStruct- & gt; inode));
channelStruct- & gt; inodeBlock = channelStruct- & gt; inode[channelStruct- & gt; inodePtr];
memset (channelStruct- & gt; inode, '\0', BLOCKSIZE);
channelStruct- & gt; inodePtr = 0;
}
/* allocate new block */
if (!(channelStruct- & gt; inode[channelStruct- & gt; inodePtr] = allocateBlock())) {
return FALSE; /* FIXME, cleanup */
}
/* write block to disk */
ataPutBlock (channelStruct- & gt; inode[channelStruct- & gt; inodePtr++],
channelStruct- & gt; buffer);
channelStruct- & gt; dirEntry.fileSize++;

return TRUE;
}

void deleteFile (char *pattern) {
struct dirEntryStruct *entry;
entryIndex_t entryIndex = 0;

while ((entry = getEntry (entryIndex++))) {
/* only process non-deleted files */
if (entry- & gt; startBlock) {
/* only delete files that match pattern */
if (filenameMatch (entry- & gt; fileName, pattern)) {
/* only delete non-locked files */
if ((entry- & gt; fileType != DIR) & & !(entry- & gt; readOnly)) {
block_t tmpBufferBlock;
bufferSize_t tmpBufferPtr;

/* get inode of file to delete */
tmpBufferBlock = entry- & gt; startBlock;
ataGetBlock (tmpBufferBlock, tmpBuffer);
tmpBufferPtr = 0;

/* free all blocks belonging to file */
while (entry- & gt; fileSize) {
/* if at the end of inode, get next inode */
if (tmpBufferPtr == (BLOCKSIZE / sizeof (block_t)) - 1) {
freeBlock (tmpBufferBlock);
tmpBufferBlock = ((block_t *)tmpBuffer)[tmpBufferPtr];
ataGetBlock (tmpBufferBlock, tmpBuffer);
tmpBufferPtr = 0;
}
/* free block */
freeBlock (((block_t *)tmpBuffer)[tmpBufferPtr++]);
entry- & gt; fileSize--;
}
/* free last inode block */
freeBlock (tmpBufferBlock);

/* remove entry from directory */
deleteEntry (entry);

flushDirBuffer();
flushFreeBlockList();

/* begin counting at 0 because direntries may have been moved */
entryIndex = 0;
}
}
}
}
}


software.rar > iecata.c

/*
IEC-ATA, a hard drive controller for the CBM IEC bus
Copyright (C) 2002 Asbj?rn Djupdal

This program 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
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

----

The author of IEC-ATA may be reached by electronic mail:

djupdal@idi.ntnu.no

or if the email address no longer is valid, by paper mail:

Asbj?rn Djupdal
Gr?nngjelet 50
4640 S?GNE
NORWAY
*/

/*
iecata.c V1.0
The main source file for the IEC-ATA software, contains main()
*/

#include " iecata.h "

/* include c-files instead of linking; saves program space because
functions may be declared inline and extern */
#include " ata.c "
#include " iec.c "
#include " dos-file.c "
#include " dos-dir.c "
#include " dos-init.c "

#define BASIC_LINE_LENGTH 33 /* TODO: check this number */
#define CDOS_DIRENTRY_LENGTH 32

/* error numbers, given in bcd */
#define NO_ERROR 0x00
#define INIT_ERROR 0x20
#define CREATE_ERROR 0x21
#define NOT_OPEN_ERROR 0x22
#define NOT_FOUND_ERROR 0x23
#define SYNTAX_ERROR 0x24
#define VERSION_ERROR 0x25

/* protos ****************************************************************/

void init (void);
void updateLED (void);
bool_t readStatus (struct channelTableStruct *channel);
bool_t readDir (struct channelTableStruct *channel);
static void parseCommand (void);
void parseName (struct channelTableStruct *channel);
uint8_t filenamelen (char *filename);

int main (void);

/* variables *************************************************************/

uint8_t command;
uint8_t error;
uint8_t channelNumber;

/* functions *************************************************************/

inline extern void init (void) {
/* enable external SRAM */
sbi (MCUCR, SRE);

/* set up I/O pins */
outp (0x00, DDRA);
outp (0x00, PORTA);
outp (0xff, DDRB);
outp (0xff, PORTB);
outp (0x00, DDRC);
outp (0x00, PORTC);
outp (0xe3, DDRD);
outp (0xc0, PORTD);

/* enable timer */
outp (0x02, TCCR0);

/* setup interrupt */
sbi (MCUCR, ISC01);
cbi (MCUCR, ISC00);
sbi (GIMSK, INT0);

/* init variables */
command = IDLE;
attention = FALSE;

error = INIT_ERROR;
/* init submodules */
if (ataInit()) {
if (dosInit()) {
error = VERSION_ERROR;
}
}

/* turn off LED */
sbi (PORTD, LED);

/* Enable interrupts */
sei();
}

inline extern void updateLED (void) {
/* blink LED if error */
if (error & & (error != VERSION_ERROR)) {
static uint8_t cnt;

if (cnt & gt; 250) {
if (bit_is_set (PORTD, LED)) {
/* LED on */
cbi (PORTD, LED);
} else {
/* LED off */
sbi (PORTD, LED);
}
cnt = 0;
}
/* timer delay */
outp (0x00, TCNT0);
while (inp (TCNT0) & lt; 200);
/* update counter */
cnt++;
}
}

inline extern bool_t readStatus (struct channelTableStruct *channel) {
uint8_t *buffer = channel- & gt; buffer;

/* error number */
*(buffer++) = (error & gt; & gt; 4) | '0';
*(buffer++) = (error & 0x0f) | '0';

/* space */
*(buffer++) = ',';
*(buffer++) = ' ';

{ /* error message */
uint8_t bufferAdd;
char *errorMessage;

switch (error) {
case NO_ERROR:
errorMessage = PSTR ( " OK " );
bufferAdd = 2;
break;
case INIT_ERROR:
errorMessage = PSTR ( " INIT ERROR " );
bufferAdd = 10;
break;
case CREATE_ERROR:
errorMessage = PSTR ( " CREATE ERROR " );
bufferAdd = 12;
break;
case NOT_OPEN_ERROR:
errorMessage = PSTR ( " NOT OPEN " );
bufferAdd = 8;
break;
case NOT_FOUND_ERROR:
errorMessage = PSTR ( " NOT FOUND " );
bufferAdd = 9;
break;
case VERSION_ERROR:
errorMessage = PSTR ( " IEC-ATA V1.0 " );
bufferAdd = 12;
break;
default:
case SYNTAX_ERROR:
errorMessage = PSTR ( " SYNTAX ERROR " );
bufferAdd = 12;
break;
}
memcpy_P (buffer, errorMessage, bufferAdd);

buffer += bufferAdd;

/* clear error */
error = NO_ERROR;
}

/* track and sector (not used; always 0,0) */
memcpy_P (buffer, PSTR ( " ,00,00\x0d " ), 7);
buffer += 7;

/* record buffer length */
channel- & gt; endOfBuffer = buffer - channel- & gt; buffer;

return TRUE;
}

inline extern bool_t readDir (struct channelTableStruct *channel) {
bool_t eof = FALSE;
uint8_t *buffer = channel- & gt; buffer;
static entryIndex_t entryIndex;
static uint8_t writtenEntries;

if (channel- & gt; readDirState == READ_DIR_BEGIN) {
if (channelNumber == 0) {
memcpy_P (buffer, PSTR ( " \x01\x04\x01\x01\x00\x00 "
" \x12\ " IEC-ATA V1.0 \ " AD 2A\x00 " ), 32);
buffer += 32;
} else {
memset (buffer, 255, 142);
memcpy_P (buffer, PSTR ( " \x41\x00 " ), 2);
buffer += 142;
memset (buffer, 0, 112);
memcpy_P (buffer, PSTR ( " IEC-ATA V1.0\xa0\xa0\xa0\xa0\xa0\xa0 "
" AD\xa0 " " 2A\xa0\xa0\xa0\xa0 " ), 27);
buffer += 112;
}

/* not begin anymore */
channel- & gt; readDirState = READ_DIR_PROGRESS;
/* start at dir index 0 */
entryIndex = 0;
writtenEntries = 0;
}

/* put directory */
while ((channel- & gt; readDirState == READ_DIR_PROGRESS) & &
(buffer & lt; (channel- & gt; buffer + BLOCKSIZE - (BASIC_LINE_LENGTH + 20)))) {

struct dirEntryStruct *entry;

/* get entry */
if ((entry = getEntry (entryIndex))) {
/* only process non-deleted files */
if (entry- & gt; startBlock) {
/* only show files that match pattern */
if (filenameMatch (entry- & gt; fileName, channel- & gt; dirEntry.fileName) ||
!(channel- & gt; dirEntry.fileName)) {
fileSize_t fileSize = entry- & gt; fileSize;

{ /* convert fileSize to number of 254 byte blocks (like 1541) */
fileSize *= 2;
uint16_t extraBytes = entry- & gt; bytesInLastBlock + (fileSize * 2);

if (fileSize) {
fileSize--;
}

while (extraBytes & gt; = 254) {
fileSize++;
extraBytes -= 254;
}
}

if (channelNumber == 0) {
/* pointer to next line */
*(buffer++) = 1;
*(buffer++) = 1;
/* linenumber */
*(buffer++) = (uint8_t)fileSize;
*(buffer++) = (uint8_t)(fileSize & gt; & gt; 8);
/* clear line */
memset (buffer, ' ', BASIC_LINE_LENGTH - 5);
/* space in beginning of line */
if (fileSize & lt; 1000) buffer++;
if (fileSize & lt; 100) buffer++;
if (fileSize & lt; 10) buffer++;
{ /* filename */
uint8_t fileNameSize = filenamelen (entry- & gt; fileName);
/* quotes */
*(buffer++) = ' " ';
/* name */
memcpy (buffer, entry- & gt; fileName, fileNameSize);
buffer += fileNameSize;
/* quotes */
*(buffer++) = ' " ';
/* spaces */
buffer += FILE_NAME_SIZE - fileNameSize;
}
/* splat */
if (entry- & gt; splat) *buffer = '*';
buffer++;
/* filetype */
switch (entry- & gt; fileType) {
case PRG:
memcpy_P (buffer, PSTR ( " PRG " ), 3);
break;
case SEQ:
memcpy_P (buffer, PSTR ( " SEQ " ), 3);
break;
case DIR:
memcpy_P (buffer, PSTR ( " DIR " ), 3);
break;
}
buffer += 3;
/* TODO: locked */
/* end of line */
*(buffer++) = 0;
} else {
/* clear direntry */
memset (buffer, 0, CDOS_DIRENTRY_LENGTH);
/* file type */
*buffer = entry- & gt; fileType;
if (!entry- & gt; splat) *buffer |= 0x80;
/* todo: locked */
buffer += 3;
/* name */
memset (buffer, 160, FILE_NAME_SIZE);
memcpy (buffer, entry- & gt; fileName, filenamelen (entry- & gt; fileName));
buffer += (FILE_NAME_SIZE + 9);
/* file size */
*(buffer++) = (uint8_t)fileSize;
*(buffer++) = (uint8_t)(fileSize & gt; & gt; 8);
/* write to bytes of 0 if not at end of 1541 block */
writtenEntries++;
if (writtenEntries == 8) {
writtenEntries = 0;
} else {
buffer += 2;
}
}
}
}
entryIndex++;
} else {
if (channelNumber == 0) {
/* put blocks free */
memcpy_P (buffer,
PSTR ( " \x01\x01\xff\xf9 " " BLOCKS FREE.\x00\x00\x00\x00 " ),
20);
buffer += 20;
}
/* read dir finished */
channel- & gt; readDirState = READ_DIR_FINISHED;
}
}

if (channel- & gt; readDirState == READ_DIR_FINISHED) {
eof = TRUE;
}

/* number of bytes to save */
channel- & gt; endOfBuffer = buffer - channel- & gt; buffer;

return eof;
}

void parseCommand (void) {
static uint8_t command[255];
uint8_t *cmdArg1;
uint8_t *cmdArg2;

{ /* get message */
bufferSize_t bytesReceived;

iecListen (command, 255, & bytesReceived);

/* make message a proper string */
command[bytesReceived] = '\0';
}

/* get arg1 */
if ((cmdArg1 = strchr (command, ':'))) {
*(cmdArg1++) = '\0';
}

/* get arg2 */
if ((cmdArg2 = strchr (cmdArg1, '='))) {
*(cmdArg2++) = '\0';
} else {
cmdArg2 = cmdArg1;
}

{ /* erase possible CR at end of arg2 */
uint8_t *cr;

if ((cr = strchr (cmdArg2, 0x0d))) {
*cr = '\0';
}
}

{ /* interpret and execute command */
char c1 = *command;
char c2 = *(command + 1);

if ((c1 == 'C') & & (c2 == 'D')) {
/* change directory */
if (!setCurrentDir (cmdArg1)) {
error = NOT_FOUND_ERROR;
}
} else if ((c1 == 'M') & & (c2 == 'D')) {
/* create directory */
if (!createDir (cmdArg1)) {
error = CREATE_ERROR;
}
} else if ((c1 == 'S') & & (c2 == 'D')) {
/* delete directory */
deleteDir (cmdArg1);
} else if (c1 == 'S') {
/* delete file */
deleteFile (cmdArg1);
} else if (c1 == 'R') {
/* rename entry */
if (!renameEntry (cmdArg1, cmdArg2)) {
error = NOT_FOUND_ERROR;
}
} else if (c1 == 'N') {
/* format drive */
if (!formatDrive()) {
error = INIT_ERROR;
}
} else if (c1 == 'I') {
/* initialize */
} else {
/* not a valid command */
error = SYNTAX_ERROR;
}
}
}

inline extern void parseName (struct channelTableStruct *channel) {
static uint8_t commandBuffer[255];
uint8_t *bufferPtr = commandBuffer;

bool_t overwrite = FALSE;
char *filename;
uint8_t filetype;
bool_t read;

{ /* get string */
bufferSize_t bytesReceived;

iecListen (commandBuffer, 255, & bytesReceived);

/* make buffer a proper string */
commandBuffer[bytesReceived] = '\0';
}

channel- & gt; readDirState = NOT_READ_DIR;

switch (*bufferPtr) {
case '@':
/* overwrite */
overwrite = TRUE;
bufferPtr++;
break;
case '$':
/* directory */
channel- & gt; readDirState = READ_DIR_BEGIN;
bufferPtr++;
break;
}

{ /* skip drive specifier if present */
char *ptr;

if ((ptr = strchr (bufferPtr, ':'))) {
bufferPtr = ptr + 1;
}
}

filename = bufferPtr;

/* file type and direction */
switch (channelNumber) {
case 0:
/* read PRG */
filetype = PRG;
read = TRUE;
break;
case 1:
/* write PRG */
filetype = PRG;
read = FALSE;
break;
default:
filetype = ANY; /* read anything, write SEQ */
read = TRUE;
break;
}

{ /* override file type and direction with data extracted from file name */
char *ptr = NULL;

do {
if ((ptr = strchr (bufferPtr, ','))) {
*ptr = '\0'; /* to make sure filename is properly ended */
bufferPtr = ptr + 1;

switch (*bufferPtr) {
case 'S':
filetype = SEQ;
break;
case 'P':
filetype = PRG;
break;
case 'W':
read = FALSE;
if (filetype == ANY) {
filetype = SEQ;
}
break;
case 'R':
read = TRUE;
break;
}
}
} while (ptr);
}

if (channel- & gt; readDirState) {
/* directory */
if (read) {
channel- & gt; fileState = READ_FILE;
/* load " $ " or load " $0 " == & gt; filename = " * " */
if (((*filename == 0) & & (*(filename - 1) != ':')) ||
((*filename == '0') & & (*(filename + 1) == 0))) {
*filename = '*';
*(filename + 1) = 0;
}
/* copy filename (to be used by pattern matching) */
memcpy (channel- & gt; dirEntry.fileName, filename, FILE_NAME_SIZE);
} else {
error = CREATE_ERROR;
}
} else {
/* normal file */
if (read) {
/* open file */
if (!openRead (filename, filetype, channelNumber)) {
error = NOT_FOUND_ERROR;
} else {
channel- & gt; fileState = READ_FILE;
}
} else {
/* delete old file */
if (overwrite) {
deleteFile (filename);
}
/* open file */
if (!openWrite (filename, filetype, channelNumber)) {
error = CREATE_ERROR;
} else {
channel- & gt; fileState = WRITE_FILE;
}
}
}
}

int main (void) {
/* I/O register setup, etc. */
init();

/* main loop */
while (TRUE) {
struct channelTableStruct *channel;

/* blink LED if error condition */
updateLED();

/* service commanding device */
iecAttention();

/* get pointer to channel structure */
channel = & channelTable[channelNumber];

/* execute command */
switch (command) {

case LISTEN_OPEN: {
/* reset variables */
channel- & gt; bufferPtr = 0;
channel- & gt; endOfBuffer = 0;

if (channelNumber == COMMAND_CHANNEL) {
/* get command and execute it */
parseCommand();
} else {
/* normal data channel, get file name and open file */
parseName (channel);
}
break;
}

case LISTEN_CLOSE:
if (channelNumber == COMMAND_CHANNEL) {
/* close all files */
uint8_t i;
for (i = 0; i & lt; 15; i++) {
closeFile (i);
}
} else {
/* close requested file */
closeFile (channelNumber);
}
break;

case LISTEN_DATA: {
/* TODO: attention check may be necessary */
if (channelNumber == COMMAND_CHANNEL) {
/* status channel must be reset before each command */
channel- & gt; bufferPtr = 0;
channel- & gt; endOfBuffer = 0;
parseCommand();
} else {
if (channel- & gt; fileState == WRITE_FILE) {
bool_t eoi;

do {
bufferSize_t bytesReceived;
bufferSize_t *bufPtr = & (channel- & gt; bufferPtr);

/* receive bytes */
eoi = iecListen (channel- & gt; buffer + *bufPtr,
BLOCKSIZE - *bufPtr, & bytesReceived);

/* update bufferPtr */
*bufPtr += bytesReceived;

/* save to disk */
if (*bufPtr == BLOCKSIZE) {
writeFile (channelNumber);
*bufPtr = 0;
}
} while (!eoi);

} else {
error = NOT_OPEN_ERROR;
}
}
break;
}

case TALK_DATA: {
if ((channel- & gt; fileState == READ_FILE) ||
(channelNumber == COMMAND_CHANNEL)) {
bool_t done = FALSE;

while (!done & & !attention) {
static bool_t eof;

/* get new block of data */
if (channel- & gt; bufferPtr == channel- & gt; endOfBuffer) {

/* start new block at beginning */
channel- & gt; bufferPtr = 0;
eof = FALSE;

if (channelNumber == COMMAND_CHANNEL) {
eof = readStatus (channel);
} else if (channel- & gt; readDirState) {
eof = readDir (channel);
} else {
readFile (channelNumber, & eof);
if (eof) {
channel- & gt; endOfBuffer = channel- & gt; dirEntry.bytesInLastBlock;
} else {
channel- & gt; endOfBuffer = BLOCKSIZE;
}
}
}

{ /* send data block */
bufferSize_t bytesSendt;

iecTalk (channel- & gt; buffer + channel- & gt; bufferPtr,
channel- & gt; endOfBuffer - channel- & gt; bufferPtr,
& bytesSendt, eof);
channel- & gt; bufferPtr += bytesSendt;
}

done = eof;

}
} else {
error = NOT_OPEN_ERROR;
}
break;
}

}
command = IDLE;

}

return 0;
}

uint8_t filenamelen (char *filename) {
uint8_t len = 0;

while (*filename & & (len & lt; 16)) {
filename++;
len++;
}

return len;
}


software.rar > ata.c

/*
IEC-ATA, a hard drive controller for the CBM IEC bus
Copyright (C) 2002 Asbj?rn Djupdal

This program 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
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

----

The author of IEC-ATA may be reached by electronic mail:

djupdal@idi.ntnu.no

or if the email address no longer is valid, by paper mail:

Asbj?rn Djupdal
Gr?nngjelet 50
4640 S?GNE
NORWAY
*/

/*
ata.c V1.0
Contains the code for low level disk access
*/

#include " iecata.h "

#define ATA_DIOW PB1
#define ATA_DIOR PB2

#define ATA_REG_DATA 0x10
#define ATA_REG_ERROR 0x30
#define ATA_REG_SECTORS 0x50
#define ATA_REG_LBA0 0x70
#define ATA_REG_LBA1 0x90
#define ATA_REG_LBA2 0xb0
#define ATA_REG_LBA3 0xd0
#define ATA_REG_COMMAND 0xf0
#define ATA_REG_ALT_STATUS 0xc8
#define ATA_REG_DRIVE_ADDR 0xe8

#define ATA_CMD_READ_SECT 0x21
#define ATA_CMD_WRITE_SECT 0x31
#define ATA_CMD_IDENTIFY_DRIVE 0xec

#define STATUS_DRDY 0x40
#define STATUS_BSY 0x80
#define STATUS_DRQ 0x08

/* protos ****************************************************************/

static void setupRegisters (uint32_t blockNumber);
static void ataGetWord (uint8_t address, uint8_t *dataH, uint8_t *dataL);
static void ataPutWord (uint8_t address, uint8_t dataH, uint8_t dataL);
static void waitWhileDisk (uint8_t mask, bool_t cond);

/* variables *************************************************************/

block_t totalDiskSize;

/* functions *************************************************************/

inline extern bool_t ataInit (void) {
bool_t lba_mode = 0;

/* init disk */
ataPutWord (ATA_REG_LBA3, 0x00, 0xa0);
waitWhileDisk (STATUS_DRDY, FALSE);

/* set drive information command */
waitWhileDisk (STATUS_BSY, STATUS_BSY);
ataPutWord (ATA_REG_COMMAND, 0x00, ATA_CMD_IDENTIFY_DRIVE);
waitWhileDisk (STATUS_DRQ, FALSE);

{ /* read information bytes from disk */
uint8_t i;
uint8_t msb;
uint8_t lsb;

for (i = 0; i & lt; = 61; i++) {
ataGetWord (ATA_REG_DATA, & msb, & lsb);

if (i == 49) {
lba_mode = msb & 0x02;
} else if (i == 60) {
*((uint8_t *)( & totalDiskSize) + 0) = lsb;
*((uint8_t *)( & totalDiskSize) + 1) = msb;
} else if (i == 61) {
*((uint8_t *)( & totalDiskSize) + 2) = lsb;
*((uint8_t *)( & totalDiskSize) + 3) = msb;
}
}
}

/* not successful if drive don't use LBA */
return lba_mode;
}

void ataGetBlock (block_t blockNumber, uint8_t *block) {
bufferSize_t byteNumber;

setupRegisters (blockNumber);

/* write command */
ataPutWord (ATA_REG_COMMAND, 0x00, ATA_CMD_READ_SECT);

waitWhileDisk (STATUS_DRQ, FALSE);
/* TODO: why is the following necessary? Without it, some blocks
don't load correctly! */
waitWhileDisk (STATUS_BSY, STATUS_BSY);

/* collect all the bytes */
for (byteNumber = 0; byteNumber & lt; BLOCKSIZE; byteNumber += 2) {
ataGetWord (ATA_REG_DATA, & block[byteNumber + 1], & block[byteNumber]);
}
}

void ataPutBlock (block_t blockNumber, uint8_t *block) {
bufferSize_t byteNumber;

setupRegisters (blockNumber);

/* write command */
ataPutWord (ATA_REG_COMMAND, 0x00, ATA_CMD_WRITE_SECT);

waitWhileDisk (STATUS_DRQ, FALSE);
/* TODO: is the following necessary? */
waitWhileDisk (STATUS_BSY, STATUS_BSY);

/* write all the bytes */
for (byteNumber = 0; byteNumber & lt; BLOCKSIZE; byteNumber += 2) {
ataPutWord (ATA_REG_DATA, block[byteNumber + 1], block[byteNumber]);
}
}

static void setupRegisters (uint32_t blockNumber) {
waitWhileDisk (STATUS_BSY, STATUS_BSY);

/* init registers */
ataPutWord (ATA_REG_SECTORS, 0x00, 0x01);
ataPutWord (ATA_REG_LBA0, 0x00, blockNumber);
ataPutWord (ATA_REG_LBA1, 0x00, blockNumber & gt; & gt; 8);
ataPutWord (ATA_REG_LBA2, 0x00, blockNumber & gt; & gt; 16);
ataPutWord (ATA_REG_LBA3, 0x00, 0xe0 | ((blockNumber & gt; & gt; 24) & 0x0f));
}

static void ataGetWord (uint8_t address, uint8_t *dataH, uint8_t *dataL) {
/* to make sure variables are not in external SRAM */
uint8_t h, l;

/* disable interrupts */
cli();
/* set up address */
outp ((address & 0xf8) | (inp (PORTB) & 0x07), PORTB);
/* disable external SRAM */
cbi (MCUCR, SRE);
/* set ATA databus to input */
outp (0x00, DDRA);
outp (0x00, DDRC);
/* disable pullups */
outp (0x00, PORTA);
outp (0x00, PORTC);
/* assert DIOR */
cbi (PORTB, ATA_DIOR);
/* wait a short time */
asm volatile ( " nop " );
/* collect data */
l = inp (PINA);
h = inp (PINC);
/* reset DIOR*/
sbi (PORTB, ATA_DIOR);
/* enable external SRAM */
sbi (MCUCR, SRE);
/* copy to parameters */
*dataH = h;
*dataL = l;
/* enable interrupts */
sei();
}

static void ataPutWord (uint8_t address, uint8_t dataH, uint8_t dataL) {
/* disable interrupts */
cli();
/* set up address */
outp ((address & 0xf8) | (inp (PORTB) & 0x07), PORTB);
/* set ATA databus to output */
outp (0xff, DDRA);
outp (0xff, DDRC);
/* disable external SRAM */
cbi (MCUCR, SRE);
/* wait a short time */
asm volatile ( " nop " );
/* assert DIOW */
cbi (PORTB, ATA_DIOW);
/* wait a short time */
asm volatile ( " nop " );
/* put data on bus */
outp (dataL, PORTA);
outp (dataH, PORTC);
/* reset DIOW*/
sbi (PORTB, ATA_DIOW);
/* enable external SRAM */
sbi (MCUCR, SRE);
/* enable interrupts */
sei();
}

static void waitWhileDisk (uint8_t mask, bool_t cond) {
uint8_t status;
uint8_t dummy;

do {
ataGetWord (ATA_REG_COMMAND, & dummy, & status);
} while ((status & mask) == cond);
}