1 /*
2 * Disc image handling
3 */
4
5 #include "appmake.h"
6 #include "diskio.h"
7
8
9 // d88 media type
10 #define MEDIA_TYPE_2D 0x00
11 #define MEDIA_TYPE_2DD 0x10
12 #define MEDIA_TYPE_2HD 0x20
13 #define MEDIA_TYPE_144 0x30
14 #define MEDIA_TYPE_UNK 0xff
15
16 typedef struct {
17 char title[17];
18 uint8_t rsrv[9];
19 uint8_t protect;
20 uint8_t type;
21 uint32_t size;
22 uint32_t trkptr[164];
23 } d88_hdr_t;
24
25 typedef struct {
26 uint8_t c, h, r, n;
27 uint16_t nsec;
28 uint8_t dens, del, stat;
29 uint8_t rsrv[5];
30 uint16_t size;
31 } d88_sct_t;
32
33
34 struct disc_handle_s {
35 disc_spec spec;
36
37 uint8_t *image;
38
39 // CP/M information
40 uint8_t *extents;
41 int num_extents;
42
43 // FAT information
44 FATFS fatfs;
45
46 // Routine delegation
47 void (*write_file)(disc_handle *h, char *filename, void *data, size_t bin);
48 };
49
50
51 static void cpm_write_file(disc_handle* h, char *filename, void* data, size_t len);
52 static void fat_write_file(disc_handle* h, char *filename, void* data, size_t len);
53
54 // Generic routines
55
disc_create(disc_spec * spec)56 disc_handle *disc_create(disc_spec* spec)
57 {
58 disc_handle* h = calloc(1, sizeof(*h));
59 size_t len;
60
61 h->spec = *spec;
62 len = spec->tracks * spec->sectors_per_track * spec->sector_size * spec->sides;
63 h->image = calloc(len, sizeof(char));
64 memset(h->image, spec->filler_byte, len);
65
66
67 #if 0
68 // Code that marks each sector so we can see what is actually loaded
69 for ( int t = 0, offs = 0; t < spec->tracks; t++ ) {
70 for ( int head = 0; head < spec->sides; head++ ) {
71 for ( int s = 0; s < spec->sectors_per_track; s++ ) {
72 for ( int b = 0; b < spec->sector_size / 4 ; b++ ) {
73 h->image[offs++] = t; //^ 255;
74 h->image[offs++] = head; //^ 255;
75 h->image[offs++] = s; //^ 255;
76 h->image[offs++] = 0; //^ 255;
77 }
78 }
79 }
80 }
81 #endif
82 return h;
83 }
84
disc_write_file(disc_handle * h,char * filename,void * data,size_t len)85 void disc_write_file(disc_handle* h, char *filename, void* data, size_t len)
86 {
87 h->write_file(h, filename, data, len);
88 }
89
90
disc_write_boot_track(disc_handle * h,void * data,size_t len)91 void disc_write_boot_track(disc_handle* h, void* data, size_t len)
92 {
93 memcpy(h->image, data, len);
94 }
95
disc_write_sector_lba(disc_handle * h,int sector_nr,int count,const void * data)96 void disc_write_sector_lba(disc_handle *h, int sector_nr, int count, const void *data)
97 {
98 const uint8_t *ptr = data;
99 int i;
100
101 for ( i = 0; i < count; i++ ) {
102 int track = sector_nr / h->spec.sectors_per_track;
103 int sector = sector_nr % h->spec.sectors_per_track;
104 int head;
105
106 if ( h->spec.alternate_sides == 0 ) {
107 head = track % 2;
108 track /= 2;
109 } else {
110 head = track >= h->spec.tracks ? 1 : 0;
111 }
112 disc_write_sector(h, track, sector, head, ptr);
113 sector_nr++;
114 ptr += h->spec.sector_size;
115 }
116 }
117
disc_write_sector(disc_handle * h,int track,int sector,int head,const void * data)118 void disc_write_sector(disc_handle *h, int track, int sector, int head, const void *data)
119 {
120 size_t offset;
121 size_t track_length = h->spec.sectors_per_track * h->spec.sector_size;
122
123 if ( h->spec.alternate_sides == 0 ) {
124 offset = track_length * track + (head * track_length * h->spec.tracks);
125 } else {
126 offset = track_length * ( 2* track + head);
127 }
128
129 offset += sector * h->spec.sector_size;
130 memcpy(&h->image[offset], data, h->spec.sector_size);
131 }
132
disc_read_sector_lba(disc_handle * h,int sector_nr,int count,void * data)133 void disc_read_sector_lba(disc_handle *h, int sector_nr, int count, void *data)
134 {
135 uint8_t *ptr = data;
136 int i;
137
138 for ( i = 0; i < count; i++ ) {
139 int track = sector_nr / h->spec.sectors_per_track;
140 int sector = sector_nr % h->spec.sectors_per_track;
141 int head;
142
143 if ( h->spec.alternate_sides == 0 ) {
144 head = track % 2;
145 track /= 2;
146 } else {
147 head = track >= h->spec.tracks ? 1 : 0;
148 }
149 disc_read_sector(h, track, sector, head, ptr);
150 sector_nr++;
151 ptr += h->spec.sector_size;
152 }
153 }
154
disc_read_sector(disc_handle * h,int track,int sector,int head,void * data)155 void disc_read_sector(disc_handle *h, int track, int sector, int head, void *data)
156 {
157 size_t offset;
158 size_t track_length = h->spec.sectors_per_track * h->spec.sector_size;
159
160 if ( h->spec.alternate_sides == 0 ) {
161 offset = track_length * track + (head * track_length * h->spec.tracks);
162 } else {
163 offset = track_length * ( 2* track + head);
164 }
165
166 offset += sector * h->spec.sector_size;
167 memcpy(data, &h->image[offset], h->spec.sector_size);
168 }
169
170
171
172
disc_get_sector_size(disc_handle * h)173 int disc_get_sector_size(disc_handle *h)
174 {
175 return h->spec.sector_size;
176 }
177
disc_get_sector_count(disc_handle * h)178 int disc_get_sector_count(disc_handle *h)
179 {
180 return h->spec.sides * h->spec.sectors_per_track * h->spec.tracks;
181 }
182
183
disc_free(disc_handle * h)184 void disc_free(disc_handle* h)
185 {
186 free(h->image);
187 free(h->extents);
188 free(h);
189 }
190
191 // Image writing routines
192
193 struct container {
194 const char *name;
195 const char *extension;
196 const char *description;
197 disc_writer_func writer;
198 } containers[] = {
199 { "dsk", ".dsk", "CPC extended .dsk format", disc_write_edsk },
200 { "d88", ".D88", "d88 format", disc_write_d88 },
201 { "ana", ".dump", "Anadisk format", disc_write_anadisk },
202 { "imd", ".imd", "IMD (Imagedisk) format", disc_write_imd },
203 { "raw", ".img", "Raw image", disc_write_raw },
204 { NULL, NULL, NULL }
205 };
206
disc_get_writer(const char * container_name,const char ** extension)207 disc_writer_func disc_get_writer(const char *container_name, const char **extension)
208 {
209 struct container *c = &containers[0];
210 while (c->name != NULL) {
211 *extension = c->extension;
212 if (strcasecmp(container_name, c->name) == 0) {
213 return c->writer;
214 }
215 c++;
216 }
217 return NULL;
218 }
219
disc_print_writers(FILE * fp)220 void disc_print_writers(FILE *fp)
221 {
222 struct container *c = &containers[0];
223
224 while ( c->name ) {
225 fprintf(fp, "%-20s%s\n", c->name, c->description);
226 c++;
227 }
228 }
229
230
231
232 // Write a raw disk, no headers for tracks etc
disc_write_raw(disc_handle * h,const char * filename)233 int disc_write_raw(disc_handle* h, const char* filename)
234 {
235 size_t offs;
236 FILE* fp;
237 int i, j, s;
238 int track_length = h->spec.sector_size * h->spec.sectors_per_track;
239
240 if ((fp = fopen(filename, "wb")) == NULL) {
241 return -1;
242 }
243
244 for (i = 0; i < h->spec.tracks; i++) {
245 for (s = 0; s < h->spec.sides; s++) {
246 if ( h->spec.alternate_sides == 0 ) {
247 offs = track_length * i + (s * track_length * h->spec.tracks);
248 } else {
249 offs = track_length * ( 2* i + s);
250 }
251 for (j = 0; j < h->spec.sectors_per_track; j++) {
252 int sect = j; // TODO: Skew
253 if ( h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
254 for ( sect = 0; sect < h->spec.sectors_per_track; sect++ ) {
255 if ( h->spec.skew_tab[sect] == j ) break;
256 }
257 }
258 fwrite(h->image + offs + (sect * h->spec.sector_size), h->spec.sector_size, 1, fp);
259 }
260 }
261 }
262 fclose(fp);
263 return 0;
264 }
265
266
disc_write_edsk(disc_handle * h,const char * filename)267 int disc_write_edsk(disc_handle* h, const char* filename)
268 {
269 uint8_t header[256] = { 0 };
270 char title[15];
271 size_t offs;
272 FILE* fp;
273 int i, j, s;
274 int track_length = h->spec.sector_size * h->spec.sectors_per_track;
275 int sector_size = 0;
276
277 i = h->spec.sector_size;
278 while (i > 128) {
279 sector_size++;
280 i /= 2;
281 }
282
283 if ((fp = fopen(filename, "wb")) == NULL) {
284 return -1;
285 }
286 memset(header, 0, 256);
287 memcpy(header, "EXTENDED CPC DSK FILE\r\nDisk-Info\r\n", 34);
288 snprintf(title,sizeof(title),"z88dk/%s", h->spec.name ? h->spec.name : "appmake");
289 memcpy(header + 0x22, title, strlen(title));
290 header[0x30] = h->spec.tracks;
291 header[0x31] = h->spec.sides;
292 for (i = 0; i < h->spec.tracks * h->spec.sides; i++) {
293 header[0x34 + i] = (h->spec.sector_size * h->spec.sectors_per_track + 256) / 256;
294 }
295 fwrite(header, 256, 1, fp);
296
297 for (i = 0; i < h->spec.tracks; i++) {
298 for (s = 0; s < h->spec.sides; s++) {
299 uint8_t* ptr;
300
301 if ( h->spec.alternate_sides == 0 ) {
302 offs = track_length * i + (s * track_length * h->spec.tracks);
303 } else {
304 offs = track_length * ( 2* i + s);
305 }
306 memset(header, 0, 256);
307 memcpy(header, "Track-Info\r\n", 12);
308 header[0x10] = i;
309 header[0x11] = s; // side
310 header[0x14] = sector_size;
311 header[0x15] = h->spec.sectors_per_track;
312 header[0x16] = h->spec.gap3_length;
313 header[0x17] = h->spec.filler_byte;
314 ptr = header + 0x18;
315 for (j = 0; j < h->spec.sectors_per_track; j++) {
316 *ptr++ = i; // Track
317 *ptr++ = s; // Side
318 if ( 0 && h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
319 *ptr++ = h->spec.skew_tab[j] + h->spec.first_sector_offset; // Sector ID
320 } else if ( i + (i*h->spec.sides) <= h->spec.boottracks && h->spec.boot_tracks_sector_offset ) {
321 *ptr++ = j + h->spec.boot_tracks_sector_offset; // Sector ID
322 } else {
323 *ptr++ = j + h->spec.first_sector_offset; // Sector ID
324 }
325 *ptr++ = sector_size;
326 *ptr++ = 0; // FDC status register 1
327 *ptr++ = 0; // FDC status register 2
328 *ptr++ = h->spec.sector_size % 256;
329 *ptr++ = h->spec.sector_size / 256;
330 }
331 fwrite(header, 256, 1, fp);
332 for (j = 0; j < h->spec.sectors_per_track; j++) {
333 int sect = j; // TODO: Skew
334 if ( h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
335 for ( sect = 0; sect < h->spec.sectors_per_track; sect++ ) {
336 if ( h->spec.skew_tab[sect] == j ) break;
337 }
338 }
339 fwrite(h->image + offs + (sect * h->spec.sector_size), h->spec.sector_size, 1, fp);
340 }
341 }
342 }
343 fclose(fp);
344 return 0;
345 }
346
347
348
disc_write_d88(disc_handle * h,const char * filename)349 int disc_write_d88(disc_handle* h, const char* filename)
350 {
351 uint8_t header[1024] = { 0 };
352 char title[18];
353 uint8_t *ptr;
354 size_t offs;
355 FILE* fp;
356 int i, j, s;
357 int sector_size = 0;
358 int track_length = h->spec.sector_size * h->spec.sectors_per_track;
359
360
361 if ((fp = fopen(filename, "wb")) == NULL) {
362 return -1;
363 }
364
365
366 i = h->spec.sector_size;
367 while (i > 128) {
368 sector_size++;
369 i /= 2;
370 }
371
372 ptr = header;
373 snprintf(title,sizeof(title),"z88dk/%s", h->spec.name ? h->spec.name : "appmake");
374 memcpy(ptr, title, strlen(title)); ptr += 17;
375 ptr += 9; // Reserved
376 *ptr++ = 0; // Protect
377 // Calculate data size of the disc
378 offs = track_length * h->spec.tracks * h->spec.sides;
379 *ptr++ = (offs < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (offs < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
380 // Calculate the file length of the disc image
381 offs = sizeof(d88_hdr_t) + (sizeof(d88_sct_t) * h->spec.sectors_per_track + track_length) * (h->spec.tracks * h->spec.sides);
382 *ptr++ = offs % 256;
383 *ptr++ = (offs / 256) % 256;
384 *ptr++ = (offs / 65536) % 256;
385 *ptr++ = (offs / 65536) / 256;
386
387 for ( i = 0; i < h->spec.tracks * h->spec.sides; i++ ) {
388 offs = sizeof(d88_hdr_t) + (sizeof(d88_sct_t) * h->spec.sectors_per_track + track_length) * i;
389 *ptr++ = offs % 256;
390 *ptr++ = (offs / 256) % 256;
391 *ptr++ = (offs / 65536) % 256;
392 *ptr++ = (offs / 65536) / 256;
393 if ( h->spec.sides == 1 ) {
394 *ptr++ = 0;
395 *ptr++ = 0;
396 *ptr++ = 0;
397 *ptr++ = 0;
398 }
399 }
400 fwrite(header, sizeof(d88_hdr_t), 1, fp);
401
402 for (i = 0; i < h->spec.tracks; i++) {
403 for (s = 0; s < h->spec.sides; s++) {
404
405 if ( h->spec.alternate_sides == 0 ) {
406 offs = track_length * i + (s * track_length * h->spec.tracks);
407 } else {
408 offs = track_length * ( 2* i + s);
409 }
410 for (j = 0; j < h->spec.sectors_per_track; j++) {
411 uint8_t *ptr = header;
412
413 int sect = j; // TODO: Skew
414 if ( h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
415 for ( sect = 0; sect < h->spec.sectors_per_track; sect++ ) {
416 if ( h->spec.skew_tab[sect] == j ) break;
417 }
418 }
419 *ptr++ = i; //track
420 *ptr++ = s; //head
421 *ptr++ = j+1; //sector
422 *ptr++ = sector_size; //n
423 *ptr++ = (h->spec.sectors_per_track) % 256;
424 *ptr++ = (h->spec.sectors_per_track) / 256;
425 *ptr++ = 0; //dens
426 *ptr++ = 0; //del
427 *ptr++ = 0; //stat
428 *ptr++ = 0; //reserved
429 *ptr++ = 0; //reserved
430 *ptr++ = 0; //reserved
431 *ptr++ = 0; //reserved
432 *ptr++ = 0; //reserved
433 *ptr++ = (h->spec.sector_size % 256);
434 *ptr++ = (h->spec.sector_size / 256);
435 fwrite(header, ptr - header, 1, fp);
436 fwrite(h->image + offs + (sect * h->spec.sector_size), h->spec.sector_size, 1, fp);
437 }
438 }
439 }
440 fclose(fp);
441 return 0;
442 }
443
disc_write_anadisk(disc_handle * h,const char * filename)444 int disc_write_anadisk(disc_handle* h, const char* filename)
445 {
446 size_t offs;
447 FILE* fp;
448 int i, j, s;
449 int sector_size = 0;
450 int track_length = h->spec.sector_size * h->spec.sectors_per_track;
451
452
453 if ((fp = fopen(filename, "wb")) == NULL) {
454 return -1;
455 }
456
457
458 i = h->spec.sector_size;
459 while (i > 128) {
460 sector_size++;
461 i /= 2;
462 }
463
464 for (i = 0; i < h->spec.tracks; i++) {
465 for (s = 0; s < h->spec.sides; s++) {
466
467 if ( h->spec.alternate_sides == 0 ) {
468 offs = track_length * i + (s * track_length * h->spec.tracks);
469 } else {
470 offs = track_length * ( 2* i + s);
471 }
472 for (j = 0; j < h->spec.sectors_per_track; j++) {
473 uint8_t header[8] = { 0 };
474
475
476 int sect = j; // TODO: Skew
477 if ( h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
478 for ( sect = 0; sect < h->spec.sectors_per_track; sect++ ) {
479 if ( h->spec.skew_tab[sect] == j ) break;
480 }
481 }
482
483 // Track header:
484 // physical cylinder
485 // physical head
486 // cylinder
487 // head
488 // secotr number
489 // size code
490 // length (little endian) word
491 header[0] = i;
492 header[1] = s;
493 header[2] = i;
494 header[3] = s;
495 header[4] = sect + h->spec.first_sector_offset;
496 header[5] = sector_size;
497 header[6] = h->spec.sector_size % 256;
498 header[7] = h->spec.sector_size / 256;
499
500 fwrite(header, 8, 1, fp);
501 fwrite(h->image + offs + (sect * h->spec.sector_size), h->spec.sector_size, 1, fp);
502 }
503 }
504 }
505 fclose(fp);
506 return 0;
507 }
508
disc_write_imd(disc_handle * h,const char * filename)509 int disc_write_imd(disc_handle* h, const char* filename)
510 {
511 size_t offs;
512 FILE* fp;
513 int i, j, s;
514 int sector_size = 0;
515 int track_length = h->spec.sector_size * h->spec.sectors_per_track;
516 uint8_t buffer[80];
517 uint8_t *ptr;
518 time_t tim;
519 struct tm *tm;
520
521
522 if ((fp = fopen(filename, "wb")) == NULL) {
523 return -1;
524 }
525
526 // Write header
527 time(&tim);
528 tm = localtime(&tim);
529 fprintf(fp, "IMD z88dk: %2d/%2d/%4d %02d:%02d:%02d\r\n%s\x1a",
530 tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900,
531 tm->tm_hour, tm->tm_min, tm->tm_sec, h->spec.name);
532
533
534 i = h->spec.sector_size;
535 while (i > 128) {
536 sector_size++;
537 i /= 2;
538 }
539
540 for (i = 0; i < h->spec.tracks; i++) {
541 for (s = 0; s < h->spec.sides; s++) {
542 ptr = buffer;
543
544 *ptr++ = 3; // Mode + transfer rate
545 *ptr++ = i; // track
546 *ptr++ = s; // head
547 *ptr++ = h->spec.sectors_per_track; // Sectors per track
548 *ptr++ = sector_size; // Size of sector
549
550 // Write sector map
551 for ( j = 0; j < h->spec.sectors_per_track; j++ ) {
552 *ptr++ = j + h->spec.first_sector_offset;
553 }
554 // And write the header
555 fwrite(buffer, ptr - buffer, 1, fp);
556
557 // And now write each sector - we don't do compression and all sectors are good
558 if ( h->spec.alternate_sides == 0 ) {
559 offs = track_length * i + (s * track_length * h->spec.tracks);
560 } else {
561 offs = track_length * ( 2* i + s);
562 }
563 for (j = 0; j < h->spec.sectors_per_track; j++) {
564 int sect = j;
565 if ( h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
566 for ( sect = 0; sect < h->spec.sectors_per_track; sect++ ) {
567 if ( h->spec.skew_tab[sect] == j ) break;
568 }
569 }
570
571 fputc(1, fp); // Sector type 1 = has data
572 fwrite(h->image + offs + (sect * h->spec.sector_size), h->spec.sector_size, 1, fp);
573 }
574 }
575 }
576 fclose(fp);
577 return 0;
578 }
579
580
581 // CP/M routines
first_free_extent(disc_handle * h)582 static int first_free_extent(disc_handle* h)
583 {
584 int i;
585
586 for (i = 0; i < h->num_extents; i++) {
587 if (h->extents[i] == 0) {
588 return i;
589 }
590 }
591 exit_log(1,"No free extents on disc\n");
592 return -1;
593 }
594
find_first_free_directory_entry(disc_handle * h)595 static size_t find_first_free_directory_entry(disc_handle* h)
596 {
597 size_t directory_offset = h->spec.offset ? h->spec.offset : (h->spec.boottracks * h->spec.sectors_per_track * h->spec.sector_size * 1);
598 int i;
599
600 for (i = 0; i < h->spec.directory_entries; i++) {
601 if (h->image[directory_offset] == h->spec.filler_byte) {
602 return directory_offset;
603 }
604 directory_offset += 32;
605 }
606 exit_log(1,"No free directory entries on disc\n");
607 return 0;
608 }
609
cpm_create(disc_spec * spec)610 disc_handle *cpm_create(disc_spec* spec)
611 {
612 disc_handle* h = disc_create(spec);
613 int directory_extents;
614 int i;
615
616
617 directory_extents = (h->spec.directory_entries * 32) / h->spec.extent_size;
618 h->num_extents = ((spec->tracks - h->spec.boottracks) * h->spec.sectors_per_track * h->spec.sector_size) / h->spec.extent_size + 1;
619 h->extents = calloc(h->num_extents, sizeof(uint8_t));
620
621 /* Now reserve the directory extents */
622 for (i = 0; i < directory_extents; i++) {
623 h->extents[i] = 1;
624 }
625
626 h->write_file = cpm_write_file;
627 size_t directory_offset = h->spec.offset ? h->spec.offset : (h->spec.boottracks * h->spec.sectors_per_track * h->spec.sector_size * 1);
628 memset(h->image +directory_offset, 0xe5, 512);
629 return h;
630 }
631
632
cpm_write_file(disc_handle * h,char * filename,void * data,size_t len)633 static void cpm_write_file(disc_handle* h, char *filename, void* data, size_t len)
634 {
635 size_t num_extents = (len / h->spec.extent_size) + 1;
636 size_t directory_offset;
637 size_t offset;
638 uint8_t direntry[32];
639 int i, j, current_extent;
640 int extents_per_entry = h->spec.byte_size_extents ? 16 : 8;
641
642 directory_offset = find_first_free_directory_entry(h);
643 // Now, write the directory entry, we can start from extent 1
644 current_extent = first_free_extent(h);
645 // We need to turn that extent into an offset into the disc
646 if ( h->spec.offset ) {
647 offset = h->spec.offset + (current_extent * h->spec.extent_size);
648 } else {
649 offset = (h->spec.boottracks * h->spec.sectors_per_track * h->spec.sector_size * 1) + (current_extent * h->spec.extent_size);
650 }
651 memcpy(h->image + offset, data, len);
652
653 for (i = 0; i <= (num_extents / extents_per_entry); i++) {
654 int extents_to_write;
655
656 memset(direntry, 0, sizeof(direntry));
657
658 direntry[0] = 0; // User 0
659 memcpy(direntry + 1, filename, 11);
660 direntry[12] = i; // Extent number
661 direntry[13] = 0;
662 direntry[14] = 0;
663 if (num_extents - (i * extents_per_entry) > extents_per_entry) {
664 direntry[15] = 0x80;
665 extents_to_write = extents_per_entry;
666 } else {
667 direntry[15] = ((len % (extents_per_entry * h->spec.extent_size)) / 128) + 1;
668 extents_to_write = (num_extents - (i * extents_per_entry));
669 }
670 for (j = 0; j < extents_per_entry; j++) {
671 if (j < extents_to_write) {
672 h->extents[current_extent] = 1;
673 if (h->spec.byte_size_extents) {
674 direntry[j + 16] = (current_extent) % 256;
675 } else {
676 direntry[j * 2 + 16] = (current_extent) % 256;
677 direntry[j * 2 + 16 + 1] = (current_extent) / 256;
678 }
679 current_extent++;
680 }
681 }
682 memcpy(h->image + directory_offset, direntry, 32);
683 directory_offset += 32;
684 }
685 }
686
687 // FAT filesystem - we delegate mostly to FatFS
688
689 // Nasty static reference to file, TODO, I can do this better
690 static disc_handle *current_fat_handle = NULL;
691
fat_create(disc_spec * spec)692 disc_handle *fat_create(disc_spec* spec)
693 {
694 disc_handle *h = disc_create(spec);
695 char buf[1024];
696 FRESULT res;
697
698 current_fat_handle = h;
699 // Create a file system
700 if ( (res = f_mkfs("1", spec->fat_format_flags, spec->cluster_size, buf, sizeof(buf), spec->number_of_fats, spec->directory_entries)) != FR_OK) {
701 exit_log(1, "Cannot create FAT filesystem: %d\n",res);
702 }
703
704 // And now we need to mount it
705 if ( (res = f_mount(&h->fatfs, "1", 1)) != FR_OK ) {
706 exit_log(1, "Cannot mount newly create FAT filesystem: %d\n",res);
707 }
708
709 h->write_file = fat_write_file;
710 return h;
711 }
712
fat_write_file(disc_handle * h,char * filename,void * data,size_t len)713 static void fat_write_file(disc_handle* h, char *filename, void* data, size_t len)
714 {
715 FIL file={{0}};
716 UINT written;
717
718 if ( f_open(&file, filename, FA_WRITE|FA_CREATE_ALWAYS) != FR_OK ) {
719 exit_log(1, "Cannot create file <%s> on FAT image", filename);
720 }
721
722 if ( f_write(&file, data, len, &written) != FR_OK ) {
723 exit_log(1, "Cannot write file contents to FAT image");
724 }
725
726 f_close(&file);
727 }
728
729
730 // FATFs interface
731
disk_status(BYTE pdrv)732 DSTATUS disk_status (
733 BYTE pdrv /* Physical drive nmuber to identify the drive */
734 )
735 {
736 return RES_OK;
737 }
738
disk_initialize(BYTE pdrv)739 DSTATUS disk_initialize (
740 BYTE pdrv /* Physical drive nmuber to identify the drive */
741 )
742 {
743 return RES_OK;
744 }
745
746
disk_read(BYTE pdrv,BYTE * buff,DWORD sector,UINT count)747 DRESULT disk_read (
748 BYTE pdrv, /* Physical drive nmuber to identify the drive */
749 BYTE *buff, /* Data buffer to store read data */
750 DWORD sector, /* Start sector in LBA */
751 UINT count /* Number of sectors to read */
752 )
753 {
754 disc_read_sector_lba(current_fat_handle, sector, count, buff);
755
756 return RES_OK;
757 }
758
759
disk_write(BYTE pdrv,const BYTE * buff,DWORD sector,UINT count)760 DRESULT disk_write (
761 BYTE pdrv, /* Physical drive nmuber to identify the drive */
762 const BYTE *buff, /* Data to be written */
763 DWORD sector, /* Start sector in LBA */
764 UINT count /* Number of sectors to write */
765 )
766 {
767 disc_write_sector_lba(current_fat_handle, sector, count, buff);
768
769 return RES_OK;
770 }
771
disk_ioctl(BYTE pdrv,BYTE cmd,void * buff)772 DRESULT disk_ioctl (
773 BYTE pdrv, /* Physical drive nmuber (0..) */
774 BYTE cmd, /* Control code */
775 void *buff /* Buffer to send/receive control data */
776 )
777 {
778 int val;
779 switch ( cmd ) {
780 case GET_SECTOR_COUNT:
781 val = disc_get_sector_count(current_fat_handle);
782 *(DWORD *)buff = val;
783 break;
784
785 case GET_SECTOR_SIZE:
786 case GET_BLOCK_SIZE:
787 val = disc_get_sector_size(current_fat_handle);
788 *(WORD *)buff = val;
789 break;
790 }
791 return RES_OK;
792 }
793
794