blob: d0b8f47bb2f5147664cb412a3160ef76102d2cf5 [file] [log] [blame]
kthacker62e146c2006-04-17 15:11:35 +00001/**
2 * \defgroup c64fs C64 file system and disk functions.
3 * @{
4 *
5 * The C64 file system functions are divided into two categories:
6 * those that deal with C64 files and the C64 disk directory, and
7 * those that allow direct block access to the disk. The former
8 * functions can be used for accessing regular files, whereas the
9 * latter functions are used e.g. to download D64 files onto 1541
10 * disks.
11 *
12 * \note The C64 filesystem functions currently only work with the
13 * 1541/1541-II/1571 and compatible drives, and not with the IDE64
14 * hard disks or the 1581/FD2000 3.5" drives.
15 *
16 *
17 */
18
19/**
20 * \file
21 * C64 file system operations interface for Contiki.
22 * \author Adam Dunkels <adam@dunkels.com>
23 *
24 */
25
26/*
27 * Copyright (c) 2003, Adam Dunkels.
28 * All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above
36 * copyright notice, this list of conditions and the following
37 * disclaimer in the documentation and/or other materials provided
38 * with the distribution.
39 * 3. The name of the author may not be used to endorse or promote
40 * products derived from this software without specific prior
41 * written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
44 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
47 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
49 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
51 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
52 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
53 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 *
55 * This file is part of the Contiki desktop environment
56 *
57 * $Id: c64-fs.c,v 1.1 2006/04/17 15:11:57 kthacker Exp $
58 *
59 */
60
61#include "c64-dio.h"
62#include "c64-dio-asm.h"
63#include "c64-fs.h"
64
65#include <string.h>
66#include <stdio.h>
67
68struct directory_entry {
69 unsigned char type;
70 unsigned char track, sect;
71 unsigned char name[16];
72 unsigned char reltrack, relsect, relreclen;
73 unsigned char unused1, unused2, unused3, unused4;
74 unsigned char tmptrack, tmpsect;
75 unsigned char blockslo, blockshi;
76};
77
78unsigned char _c64_fs_dirbuf[256];
79unsigned char _c64_fs_dirbuftrack = 0, _c64_fs_dirbufsect = 0;
80
81unsigned char _c64_fs_filebuf[256];
82unsigned char _c64_fs_filebuftrack = 0, _c64_fs_filebufsect = 0;
83
84static struct c64_fs_dirent lastdirent;
85
86static struct c64_fs_dir opendir;
87static struct c64_fs_dirent opendirent;
88
89/*-----------------------------------------------------------------------------------*/
90/**
91 * Open a file.
92 *
93 * The file description must be allocated by the caller and a pointer
94 * to it is passed to this function.
95 *
96 * \param name A pointer to the name of the file to be opened.
97 * \param f A pointer to the file descriptor struct.
98 *
99 * \retval 0 If the file was successfully opened.
100 * \retval -1 If the file does not exist.
101 */
102/*-----------------------------------------------------------------------------------*/
103int
104c64_fs_open(const char *name, register struct c64_fs_file *f)
105{
106 /* First check if we already have the file cached. If so, we don't
107 need to do an expensive directory lookup. */
108 if(strncmp(lastdirent.name, name, 16) == 0) {
109 f->track = lastdirent.track;
110 f->sect = lastdirent.sect;
111 f->ptr = 2;
112 return 0;
113 }
114
115 /* Not in cache, so we walk through directory instead. */
116 c64_fs_opendir(&opendir);
117
118 do {
119 c64_fs_readdir_dirent(&opendir, &opendirent);
120 if(strncmp(opendirent.name, name, 16) == 0) {
121 f->track = opendirent.track;
122 f->sect = opendirent.sect;
123 f->ptr = 2;
124 return 0;
125 }
126 } while(c64_fs_readdir_next(&opendir) == 0);
127
128 /* The file was not found in the directory. We flush the directory
129 buffer cache now in order to prevent a nasty problem from
130 happening: If the first directory block of an empty disk was
131 cached, *all* subsequent file opens would return "file not
132 found". */
133 _c64_fs_dirbuftrack = 0; /* There are no disk blocks on track 0. */
134 return -1;
135}
136/*-----------------------------------------------------------------------------------*/
137/**
138 * Read data from an open file.
139 *
140 * This function reads data from an open file into a buffer than must
141 * be allocated by the caller.
142 *
143 * \param f A pointer to a file descriptor structure that must have
144 * been opened with c64_fs_open().
145 *
146 * \param buf A pointer to the buffer in which the data should be placed.
147 *
148 * \param len The maxiumum amount of bytes to read.
149 *
150 * \return The number of bytes that actually was read, or 0 if an end
151 * of file was encountered.
152 */
153/*-----------------------------------------------------------------------------------*/
154#if !NOASM
155#pragma optimize(push, off)
156#endif /* !NOASM */
157int __fastcall__
158c64_fs_read(register struct c64_fs_file *f, char *buf, int len)
159{
160 static int i;
161
162 /* Check if current block is already in buffer, and if not read it
163 from disk. */
164
165#if NOASM
166 if(f->track != _c64_fs_filebuftrack ||
167 _c64_fs_filebufsect != f->sect) {
168 _c64_fs_filebuftrack = f->track;
169 _c64_fs_filebufsect = f->sect;
170 c64_dio_read_block(_c64_fs_filebuftrack, _c64_fs_filebufsect,
171 _c64_fs_filebuf);
172 }
173#else /* NOASM */
174 asm("ldy #%b", offsetof(struct c64_fs_file, track));
175 asm("lda (regbank+%b),y", 4);
176 asm("cmp %v", _c64_fs_filebuftrack);
177 asm("bne doblock");
178
179 asm("ldy #%b", offsetof(struct c64_fs_file, sect));
180 asm("lda (regbank+%b),y", 4);
181 asm("cmp %v", _c64_fs_filebufsect);
182 asm("bne doblock");
183
184 asm("jmp noblock");
185
186 asm("doblock:");
187
188 asm("ldy #%b", offsetof(struct c64_fs_file, track));
189 asm("lda (regbank+%b),y", 4);
190 asm("sta %v", _c64_fs_filebuftrack);
191 asm("sta %v", c64_dio_asm_track);
192
193 asm("ldy #%b", offsetof(struct c64_fs_file, sect));
194 asm("lda (regbank+%b),y", 4);
195 asm("sta %v", _c64_fs_filebufsect);
196 asm("sta %v", c64_dio_asm_sector);
197
198 asm("lda #<(%v)", _c64_fs_filebuf);
199 asm("sta %v", c64_dio_asm_ptr);
200 asm("lda #>(%v)", _c64_fs_filebuf);
201 asm("sta %v+1", c64_dio_asm_ptr);
202
203 asm("jsr %v", c64_dio_asm_read_block);
204
205 asm("noblock:");
206
207#endif /* NOASM */
208
209 if(_c64_fs_filebuf[0] == 0 &&
210 f->ptr == _c64_fs_filebuf[1]) {
211 return 0; /* EOF */
212 }
213
214 for(i = 0; i < len; ++i) {
215#if NOASM
216 *buf = _c64_fs_filebuf[f->ptr];
217 ++f->ptr;
218#else /* NOASM */
219 asm("ldy #%o+1", buf);
220 asm("jsr ldaxysp");
221 asm("sta ptr2");
222 asm("stx ptr2+1");
223
224 asm("ldy #%b", offsetof(struct c64_fs_file, ptr));
225 asm("lda (regbank+%b),y", 4);
226 asm("tax");
227
228 asm("ldy #0");
229 asm("lda %v,x", _c64_fs_filebuf);
230 asm("sta (ptr2),y");
231
232 asm("inx");
233 asm("txa");
234 asm("ldy #%b", offsetof(struct c64_fs_file, ptr));
235 asm("sta (regbank+%b),y", 4);
236#endif /* NOASM */
237
238
239 if(_c64_fs_filebuf[0] == 0) {
240 if(f->ptr == _c64_fs_filebuf[1]) {
241 /* End of file reached, we return the amount of bytes read so
242 far. */
243 return i + 1;
244 }
245 } else if(f->ptr == 0) {
246
247 /* Read new block into buffer and set buffer state
248 accordingly. */
249 _c64_fs_filebuftrack = f->track = _c64_fs_filebuf[0];
250 _c64_fs_filebufsect = f->sect = _c64_fs_filebuf[1];
251 f->ptr = 2;
252 c64_dio_read_block(_c64_fs_filebuftrack,
253 _c64_fs_filebufsect, _c64_fs_filebuf);
254 }
255
256 ++buf;
257 }
258 return i;
259}
260#if !NOASM
261#pragma optimize(pop)
262#endif /* !NOASM */
263/*-----------------------------------------------------------------------------------*/
264/**
265 * Close an open file.
266 *
267 * \param f A pointer to a file descriptor struct that previously has
268 * been opened with c64_fs_open().
269 */
270/*-----------------------------------------------------------------------------------*/
271void
272c64_fs_close(struct c64_fs_file *f)
273{
274
275}
276/*-----------------------------------------------------------------------------------*/
277/**
278 * \internal
279 * Read a directory buffer into the _c64_fs_dirbuf buffer.
280 *
281 * This function is shared between this and the c64-fs-raw module.
282 *
283 * \param track The track of the directory block.
284 * \param sect The sector of the directory block.
285 */
286/*-----------------------------------------------------------------------------------*/
287void
288_c64_fs_readdirbuf(unsigned char track, unsigned char sect)
289{
290 if(_c64_fs_dirbuftrack == track &&
291 _c64_fs_dirbufsect == sect) {
292 /* Buffer already contains requested block, return. */
293 return;
294 }
295 c64_dio_read_block(track, sect, _c64_fs_dirbuf);
296 _c64_fs_dirbuftrack = track;
297 _c64_fs_dirbufsect = sect;
298}
299/*-----------------------------------------------------------------------------------*/
300/**
301 * Open the disk directory for reading.
302 *
303 * The caller must supply a pointer to a directory descriptor.
304 *
305 * \param d A pointer to a directory description that must be
306 * allocated by the caller.
307 */
308/*-----------------------------------------------------------------------------------*/
309unsigned char
310c64_fs_opendir(register struct c64_fs_dir *d)
311{
312 d->track = 18;
313 d->sect = 1;
314 d->ptr = 2;
315
316 return 0;
317}
318/*-----------------------------------------------------------------------------------*/
319/**
320 * Read the current directory entry.
321 *
322 * This function reads the directory entry to which the directory
323 * descriptor currently points into a struct c64_fs_dirent supplied by
324 * the caller.
325 *
326 * The function c64_fs_readdir_next() is used to move the directory
327 * entry pointer forward in the directory.
328 *
329 * \param d A pointer to a directory descriptor previously opened with c64_fs_opendir().
330 *
331 * \param f A pointer to a directory entry that must have been
332 * previously allocated by the caller.
333 */
334/*-----------------------------------------------------------------------------------*/
335void
336c64_fs_readdir_dirent(register struct c64_fs_dir *d,
337 register struct c64_fs_dirent *f)
338{
339 struct directory_entry *de;
340 int i;
341 register char *nameptr;
342
343 _c64_fs_readdirbuf(d->track, d->sect);
344 de = (struct directory_entry *)&_c64_fs_dirbuf[d->ptr];
345 nameptr = de->name;
346 for(i = 0; i < 16; ++i) {
347 if(*nameptr == 0xa0) {
348 *nameptr = 0;
349 break;
350 }
351 ++nameptr;
352 }
353 strncpy(f->name, de->name, 16);
354 f->track = de->track;
355 f->sect = de->sect;
356 f->size = de->blockslo + (de->blockshi >> 8);
357 memcpy(&lastdirent, f, sizeof(struct c64_fs_dirent));
358}
359/*-----------------------------------------------------------------------------------*/
360/**
361 * Move the directory pointer forward.
362 *
363 * This function moves the directory entry pointer in the directory
364 * descriptor forward so that it points to the next file.
365 *
366 * \param d A pointer to a directory descriptor previously opened with
367 * c64_fs_opendir().
368 *
369 * \retval 1 If there are no more directory entried in the directory.
370 * \retval 0 There were more directory entries and the pointer has
371 * been moved to point to the next one.
372 */
373/*-----------------------------------------------------------------------------------*/
374unsigned char
375c64_fs_readdir_next(struct c64_fs_dir *d)
376{
377 struct directory_entry *de;
378 again:
379 _c64_fs_readdirbuf(d->track, d->sect);
380 if(d->ptr == 226) {
381 if(_c64_fs_dirbuf[0] == 0) {
382 return 1;
383 }
384 d->track = _c64_fs_dirbuf[0];
385 d->sect = _c64_fs_dirbuf[1];
386 d->ptr = 2;
387 } else {
388 d->ptr += 32;
389 }
390
391 de = (struct directory_entry *)&_c64_fs_dirbuf[d->ptr];
392 if(de->type == 0) {
393 goto again;
394 }
395 return 0;
396}
397/*-----------------------------------------------------------------------------------*/
398/**
399 * Close a directory descriptor previously opened by c64_fs_opendir().
400 *
401 * \param d A poitner to a directory descriptor previously opened with
402 * c64_fs_opendir().
403 */
404/*-----------------------------------------------------------------------------------*/
405void
406c64_fs_closedir(struct c64_fs_dir *d)
407{
408
409}
410/*-----------------------------------------------------------------------------------*/
411/** @} */