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