text: /*
   * Disc image handling
   */
  
  #include "appmake.h"
  #include "diskio.h"
  
  
  // d88 media type
  #define MEDIA_TYPE_2D   0x00
  #define MEDIA_TYPE_2DD  0x10
  #define MEDIA_TYPE_2HD  0x20
  #define MEDIA_TYPE_144  0x30
  #define MEDIA_TYPE_UNK  0xff
  
  typedef struct {
          char title[17];
          uint8_t rsrv[9];
          uint8_t protect;
          uint8_t type;
          uint32_t size;
          uint32_t trkptr[164];
  } d88_hdr_t;
  
  typedef struct {
          uint8_t c, h, r, n;
          uint16_t nsec;
          uint8_t dens, del, stat;
          uint8_t rsrv[5];
          uint16_t size;
  } d88_sct_t;
  
  
  struct disc_handle_s {
      disc_spec  spec;
  
      uint8_t      *image;
  
      // CP/M information
      uint8_t      *extents;
      int           num_extents;
  
      // FAT information
      FATFS         fatfs;
  
      // Routine delegation
      void         (*write_file)(disc_handle *h, char *filename, void *data, size_t bin);
  };
  
  
  static void cpm_write_file(disc_handle* h, char *filename, void* data, size_t len);
  static void fat_write_file(disc_handle* h, char *filename, void* data, size_t len);
  
  // Generic routines
  
  disc_handle *disc_create(disc_spec* spec)
  {
      disc_handle* h = calloc(1, sizeof(*h));
      size_t len;
  
      h->spec = *spec;
      len = spec->tracks * spec->sectors_per_track * spec->sector_size * spec->sides;
      h->image = calloc(len, sizeof(char));
      memset(h->image, spec->filler_byte, len);
  
  
  #if 0
      // Code that marks each sector so we can see what is actually loaded
      for ( int t = 0, offs = 0; t < spec->tracks; t++ ) {
          for ( int head = 0; head < spec->sides; head++ ) {
             for ( int s = 0; s < spec->sectors_per_track; s++ ) {
                for ( int b = 0; b < spec->sector_size / 4 ; b++ ) {
                   h->image[offs++] = t; //^ 255;
                   h->image[offs++] = head; //^ 255;
                   h->image[offs++] = s; //^ 255;
                   h->image[offs++] = 0; //^ 255;
                }
             }
          }
      }
  #endif
      return h;
  }
  
  void disc_write_file(disc_handle* h, char *filename, void* data, size_t len)
  {
      h->write_file(h, filename, data, len);
  }
  
  
  void disc_write_boot_track(disc_handle* h, void* data, size_t len)
  {
      memcpy(h->image, data, len);
  }
  
  void disc_write_sector_lba(disc_handle *h, int sector_nr, int count, const void *data)
  {
      const uint8_t *ptr = data;
      int      i;
  
      for ( i = 0; i < count; i++ ) {
          int track = sector_nr / h->spec.sectors_per_track;
          int sector = sector_nr % h->spec.sectors_per_track;
          int head;
  
          if ( h->spec.alternate_sides == 0 ) {
              head = track % 2;
                     track /= 2;
              } else {
                     head = track >= h->spec.tracks ? 1 : 0;
          }
          disc_write_sector(h, track, sector, head, ptr);
          sector_nr++;
          ptr += h->spec.sector_size;
      }
  }
  
  void disc_write_sector(disc_handle *h, int track, int sector, int head, const void *data)
  {
      size_t offset;
      size_t track_length = h->spec.sectors_per_track * h->spec.sector_size;
  
      if ( h->spec.alternate_sides == 0 ) {
          offset = track_length * track + (head * track_length * h->spec.tracks);
      } else {
          offset = track_length * ( 2* track + head);
      }
  
      offset += sector * h->spec.sector_size;
      memcpy(&h->image[offset], data, h->spec.sector_size);
  }
  
  void disc_read_sector_lba(disc_handle *h, int sector_nr, int count, void *data)
  {
      uint8_t *ptr = data;
      int      i;
  
      for ( i = 0; i < count; i++ ) {
          int track = sector_nr / h->spec.sectors_per_track;
          int sector = sector_nr % h->spec.sectors_per_track;
          int head;
  
          if ( h->spec.alternate_sides == 0 ) {
              head = track % 2;
                     track /= 2;
              } else {
                     head = track >= h->spec.tracks ? 1 : 0;
          }
          disc_read_sector(h, track, sector, head, ptr);
          sector_nr++;
          ptr += h->spec.sector_size;
      }
  }
  
  void disc_read_sector(disc_handle *h, int track, int sector, int head, void *data)
  {
      size_t offset;
      size_t track_length = h->spec.sectors_per_track * h->spec.sector_size;
  
      if ( h->spec.alternate_sides == 0 ) {
          offset = track_length * track + (head * track_length * h->spec.tracks);
      } else {
          offset = track_length * ( 2* track + head);
      }
  
      offset += sector * h->spec.sector_size;
      memcpy(data, &h->image[offset], h->spec.sector_size);
  }
  
  
  
  
  int disc_get_sector_size(disc_handle *h)
  {
      return h->spec.sector_size;
  }
  
  int disc_get_sector_count(disc_handle *h)
  {
      return h->spec.sides  * h->spec.sectors_per_track * h->spec.tracks;
  }
  
  
  void disc_free(disc_handle* h)
  {
      free(h->image);
      free(h->extents);
      free(h);
  }
  
  // Image writing routines
  
  struct container {
      const char        *name;
      const char        *extension;
      const char        *description;
      disc_writer_func   writer;
  } containers[] = {
      { "dsk",        ".dsk", "CPC extended .dsk format",    disc_write_edsk },
      { "d88",        ".D88", "d88 format",                  disc_write_d88 },
      { "ana",        ".dump", "Anadisk format",             disc_write_anadisk },
      { "imd",        ".imd", "IMD (Imagedisk) format",      disc_write_imd },
      { "raw",        ".img", "Raw image",                   disc_write_raw },
      { NULL, NULL, NULL }
  };
  
  disc_writer_func disc_get_writer(const char *container_name, const char **extension)
  {
      struct container *c = &containers[0];
      while (c->name != NULL) {
          *extension = c->extension;
          if (strcasecmp(container_name, c->name) == 0) {
              return c->writer;
          }
          c++;
      }
      return NULL;
  }
  
  void disc_print_writers(FILE *fp)
  {
      struct container *c = &containers[0];
  
      while ( c->name ) {
          fprintf(fp, "%-20s%s\n", c->name, c->description);
          c++;
      }
  }
  
  
  
  // Write a raw disk, no headers for tracks etc
  int disc_write_raw(disc_handle* h, const char* filename)
  {
      size_t offs;
      FILE* fp;
      int i, j, s;
      int track_length = h->spec.sector_size * h->spec.sectors_per_track;
  
      if ((fp = fopen(filename, "wb")) == NULL) {
          return -1;
      }
  
      for (i = 0; i < h->spec.tracks; i++) {
          for (s = 0; s < h->spec.sides; s++) {
              if ( h->spec.alternate_sides == 0 ) {
                  offs = track_length * i + (s * track_length * h->spec.tracks);
              } else {
                  offs = track_length * ( 2* i + s);
              }
              for (j = 0; j < h->spec.sectors_per_track; j++) {
                   int sect = j; // TODO: Skew
                   if ( h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
                       for ( sect = 0; sect < h->spec.sectors_per_track; sect++ ) {
                          if ( h->spec.skew_tab[sect] == j ) break;
                       }
                   }
                   fwrite(h->image + offs + (sect * h->spec.sector_size), h->spec.sector_size, 1, fp);
              }
          }
      }
      fclose(fp);
      return 0;
  }
  
  
  int disc_write_edsk(disc_handle* h, const char* filename)
  {
      uint8_t header[256] = { 0 };
      char    title[15];
      size_t offs;
      FILE* fp;
      int i, j, s;
      int track_length = h->spec.sector_size * h->spec.sectors_per_track;
      int sector_size = 0;
  
      i = h->spec.sector_size;
      while (i > 128) {
          sector_size++;
          i /= 2;
      }
  
      if ((fp = fopen(filename, "wb")) == NULL) {
          return -1;
      }
      memset(header, 0, 256);
      memcpy(header, "EXTENDED CPC DSK FILE\r\nDisk-Info\r\n", 34);
      snprintf(title,sizeof(title),"z88dk/%s", h->spec.name ? h->spec.name : "appmake");
      memcpy(header + 0x22, title, strlen(title));
      header[0x30] = h->spec.tracks;
      header[0x31] = h->spec.sides;
      for (i = 0; i < h->spec.tracks * h->spec.sides; i++) {
          header[0x34 + i] = (h->spec.sector_size * h->spec.sectors_per_track + 256) / 256;
      }
      fwrite(header, 256, 1, fp);
  
      for (i = 0; i < h->spec.tracks; i++) {
          for (s = 0; s < h->spec.sides; s++) {
              uint8_t* ptr;
  
              if ( h->spec.alternate_sides == 0 ) {
                  offs = track_length * i + (s * track_length * h->spec.tracks);
              } else {
                  offs = track_length * ( 2* i + s);
              }
              memset(header, 0, 256);
              memcpy(header, "Track-Info\r\n", 12);
              header[0x10] = i;
              header[0x11] = s; // side
              header[0x14] = sector_size;
              header[0x15] = h->spec.sectors_per_track;
              header[0x16] = h->spec.gap3_length;
              header[0x17] = h->spec.filler_byte;
              ptr = header + 0x18;
              for (j = 0; j < h->spec.sectors_per_track; j++) {
                  *ptr++ = i; // Track
                  *ptr++ = s; // Side
                  if ( 0 && h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
                      *ptr++ = h->spec.skew_tab[j] + h->spec.first_sector_offset; // Sector ID
                  } else if (  i + (i*h->spec.sides) <= h->spec.boottracks && h->spec.boot_tracks_sector_offset ) {
                      *ptr++ = j + h->spec.boot_tracks_sector_offset; // Sector ID
                  } else {
                      *ptr++ = j + h->spec.first_sector_offset; // Sector ID
                  }
                  *ptr++ = sector_size;
                  *ptr++ = 0; // FDC status register 1
                  *ptr++ = 0; // FDC status register 2
                  *ptr++ = h->spec.sector_size % 256;
                  *ptr++ = h->spec.sector_size / 256;
              }
              fwrite(header, 256, 1, fp);
              for (j = 0; j < h->spec.sectors_per_track; j++) {
                   int sect = j; // TODO: Skew
                   if ( h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
                       for ( sect = 0; sect < h->spec.sectors_per_track; sect++ ) {
                          if ( h->spec.skew_tab[sect] == j ) break;
                       }
                   }
                   fwrite(h->image + offs + (sect * h->spec.sector_size), h->spec.sector_size, 1, fp);
              }
          }
      }
      fclose(fp);
      return 0;
  }
  
  
  
  int disc_write_d88(disc_handle* h, const char* filename)
  {
      uint8_t header[1024] = { 0 };
      char    title[18];
      uint8_t *ptr;
      size_t offs;
      FILE* fp;
      int i, j, s;
      int sector_size = 0;
      int track_length = h->spec.sector_size * h->spec.sectors_per_track;
  
  
      if ((fp = fopen(filename, "wb")) == NULL) {
          return -1;
      }
  
  
      i = h->spec.sector_size;
      while (i > 128) {
          sector_size++;
          i /= 2;
      }
  
      ptr = header;
      snprintf(title,sizeof(title),"z88dk/%s", h->spec.name ? h->spec.name : "appmake");
      memcpy(ptr, title, strlen(title)); ptr += 17;
      ptr += 9;  // Reserved
      *ptr++ = 0; // Protect
      // Calculate data size of the disc
      offs = track_length * h->spec.tracks * h->spec.sides;
      *ptr++ =  (offs < (368640 + 655360) / 2) ? MEDIA_TYPE_2D : (offs < (737280 + 1228800) / 2) ? MEDIA_TYPE_2DD : MEDIA_TYPE_2HD;
      // Calculate the file length of the disc image
      offs = sizeof(d88_hdr_t) + (sizeof(d88_sct_t) * h->spec.sectors_per_track + track_length) * (h->spec.tracks * h->spec.sides);
      *ptr++ = offs % 256;
      *ptr++ = (offs / 256) % 256;
      *ptr++ = (offs / 65536) % 256;
      *ptr++ = (offs / 65536) / 256;
      
      for ( i = 0; i < h->spec.tracks * h->spec.sides; i++ ) {
          offs = sizeof(d88_hdr_t) + (sizeof(d88_sct_t) * h->spec.sectors_per_track +  track_length) * i;
          *ptr++ = offs % 256;
          *ptr++ = (offs / 256) % 256;
          *ptr++ = (offs / 65536) % 256;
          *ptr++ = (offs / 65536) / 256;
          if ( h->spec.sides == 1 ) {
             *ptr++ = 0;
             *ptr++ = 0;
             *ptr++ = 0;
             *ptr++ = 0;
          }
      }
      fwrite(header, sizeof(d88_hdr_t), 1, fp);
  
      for (i = 0; i < h->spec.tracks; i++) {
          for (s = 0; s < h->spec.sides; s++) {
  
              if ( h->spec.alternate_sides == 0 ) {
                  offs = track_length * i + (s * track_length * h->spec.tracks);
              } else {
                  offs = track_length * ( 2* i + s);
              }
              for (j = 0; j < h->spec.sectors_per_track; j++) {
                   uint8_t *ptr = header;
  
                   int sect = j; // TODO: Skew
                   if ( h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
                       for ( sect = 0; sect < h->spec.sectors_per_track; sect++ ) {
                          if ( h->spec.skew_tab[sect] == j ) break;
                       }
                   }
                   *ptr++ = i;                 //track
                   *ptr++ = s;                //head
                   *ptr++ = j+1;                //sector
                   *ptr++ = sector_size;  //n
                   *ptr++ = (h->spec.sectors_per_track) % 256;
                   *ptr++ = (h->spec.sectors_per_track) / 256;
                   *ptr++ = 0;                //dens
                   *ptr++ = 0;                //del
                   *ptr++ = 0;                //stat
                   *ptr++ = 0;                //reserved
                   *ptr++ = 0;                //reserved
                   *ptr++ = 0;                //reserved
                   *ptr++ = 0;                //reserved
                   *ptr++ = 0;                //reserved
                   *ptr++ = (h->spec.sector_size % 256);
                   *ptr++ = (h->spec.sector_size / 256);
                   fwrite(header, ptr - header, 1, fp);
                   fwrite(h->image + offs + (sect * h->spec.sector_size), h->spec.sector_size, 1, fp);
              }
          }
      }
      fclose(fp);
      return 0;
  }
  
  int disc_write_anadisk(disc_handle* h, const char* filename)
  {
      size_t offs;
      FILE* fp;
      int i, j, s;
      int sector_size = 0;
      int track_length = h->spec.sector_size * h->spec.sectors_per_track;
  
  
      if ((fp = fopen(filename, "wb")) == NULL) {
          return -1;
      }
  
  
      i = h->spec.sector_size;
      while (i > 128) {
          sector_size++;
          i /= 2;
      }
  
      for (i = 0; i < h->spec.tracks; i++) {
          for (s = 0; s < h->spec.sides; s++) {
  
              if ( h->spec.alternate_sides == 0 ) {
                  offs = track_length * i + (s * track_length * h->spec.tracks);
              } else {
                  offs = track_length * ( 2* i + s);
              }
              for (j = 0; j < h->spec.sectors_per_track; j++) {
                  uint8_t header[8] = { 0 };
  
  
                  int sect = j; // TODO: Skew
                  if ( h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
                      for ( sect = 0; sect < h->spec.sectors_per_track; sect++ ) {
                      if ( h->spec.skew_tab[sect] == j ) break;
                      }
                  }
  
                  // Track header:
                  // physical cylinder
                  // physical head
                  // cylinder
                  // head
                  // secotr number
                  // size code
                  // length (little endian) word
                  header[0] = i;
                  header[1] = s;
                  header[2] = i;
                  header[3] = s;
                  header[4] = sect + h->spec.first_sector_offset;
                  header[5] = sector_size;
                  header[6] = h->spec.sector_size % 256;
                  header[7] = h->spec.sector_size / 256;
  
                  fwrite(header, 8, 1, fp);
                  fwrite(h->image + offs + (sect * h->spec.sector_size), h->spec.sector_size, 1, fp);
              }
          }
      }
      fclose(fp);
      return 0;
  }
  
  int disc_write_imd(disc_handle* h, const char* filename)
  {
      size_t offs;
      FILE* fp;
      int i, j, s;
      int sector_size = 0;
      int track_length = h->spec.sector_size * h->spec.sectors_per_track;
      uint8_t buffer[80];
      uint8_t *ptr;
      time_t tim;
      struct tm *tm;
  
  
      if ((fp = fopen(filename, "wb")) == NULL) {
          return -1;
      }
  
      // Write header
      time(&tim);
      tm = localtime(&tim);
      fprintf(fp, "IMD z88dk: %2d/%2d/%4d %02d:%02d:%02d\r\n%s\x1a",
            tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900,
            tm->tm_hour, tm->tm_min, tm->tm_sec, h->spec.name);
  
  
      i = h->spec.sector_size;
      while (i > 128) {
          sector_size++;
          i /= 2;
      }
  
      for (i = 0; i < h->spec.tracks; i++) {
          for (s = 0; s < h->spec.sides; s++) {
              ptr = buffer;
  
              *ptr++ = 3; // Mode + transfer rate
              *ptr++ = i; // track
              *ptr++ = s; // head
              *ptr++ = h->spec.sectors_per_track; // Sectors per track
              *ptr++ = sector_size; // Size of sector
  
              // Write sector map
              for ( j = 0; j < h->spec.sectors_per_track; j++ ) {
                  *ptr++ = j  +  h->spec.first_sector_offset;
              }
              // And write the header
              fwrite(buffer, ptr - buffer, 1, fp);
  
              // And now write each sector - we don't do compression and all sectors are good
              if ( h->spec.alternate_sides == 0 ) {
                  offs = track_length * i + (s * track_length * h->spec.tracks);
              } else {
                  offs = track_length * ( 2* i + s);
              }
              for (j = 0; j < h->spec.sectors_per_track; j++) {
                  int sect = j;
                  if ( h->spec.has_skew && i + (i*h->spec.sides) >= h->spec.skew_track_start ) {
                      for ( sect = 0; sect < h->spec.sectors_per_track; sect++ ) {
                          if ( h->spec.skew_tab[sect] == j ) break;
                      }
                  }
  
                  fputc(1, fp);   // Sector type 1  = has data
                  fwrite(h->image + offs + (sect * h->spec.sector_size), h->spec.sector_size, 1, fp);
              }
          }
      }
      fclose(fp);
      return 0;
  }
  
  
  // CP/M routines
  static int first_free_extent(disc_handle* h)
  {
      int i;
  
      for (i = 0; i < h->num_extents; i++) {
          if (h->extents[i] == 0) {
              return i;
          }
      }
      exit_log(1,"No free extents on disc\n");
      return -1;
  }
  
  static size_t find_first_free_directory_entry(disc_handle* h)
  {
      size_t directory_offset = h->spec.offset ? h->spec.offset : (h->spec.boottracks * h->spec.sectors_per_track * h->spec.sector_size * 1);
      int i;
  
      for (i = 0; i < h->spec.directory_entries; i++) {
          if (h->image[directory_offset] == h->spec.filler_byte) {
              return directory_offset;
          }
          directory_offset += 32;
      }
      exit_log(1,"No free directory entries on disc\n");
      return 0;
  }
  
  disc_handle *cpm_create(disc_spec* spec)
  {
      disc_handle* h = disc_create(spec);
      int directory_extents;
      int i;
  
  
      directory_extents = (h->spec.directory_entries * 32) / h->spec.extent_size;
      h->num_extents = ((spec->tracks - h->spec.boottracks) * h->spec.sectors_per_track * h->spec.sector_size) / h->spec.extent_size + 1;
      h->extents = calloc(h->num_extents, sizeof(uint8_t));
  
      /* Now reserve the directory extents */
      for (i = 0; i < directory_extents; i++) {
          h->extents[i] = 1;
      }
  
      h->write_file = cpm_write_file;
      size_t directory_offset = h->spec.offset ? h->spec.offset : (h->spec.boottracks * h->spec.sectors_per_track * h->spec.sector_size * 1);
      memset(h->image +directory_offset, 0xe5, 512);
      return h;
  }
  
  
  static void cpm_write_file(disc_handle* h, char *filename, void* data, size_t len)
  {
      size_t num_extents = (len / h->spec.extent_size) + 1;
      size_t directory_offset;
      size_t offset;
      uint8_t direntry[32];
      int i, j, current_extent;
      int extents_per_entry = h->spec.byte_size_extents ? 16 : 8;
  
      directory_offset = find_first_free_directory_entry(h);
      // Now, write the directory entry, we can start from extent 1
      current_extent = first_free_extent(h);
      // We need to turn that extent into an offset into the disc
      if ( h->spec.offset ) {
          offset = h->spec.offset + (current_extent * h->spec.extent_size);
      } else {
          offset = (h->spec.boottracks * h->spec.sectors_per_track * h->spec.sector_size * 1) + (current_extent * h->spec.extent_size);
      }
      memcpy(h->image + offset, data, len);
  
      for (i = 0; i <= (num_extents / extents_per_entry); i++) {
          int extents_to_write;
  
          memset(direntry, 0, sizeof(direntry));
  
          direntry[0] = 0; // User 0
          memcpy(direntry + 1, filename, 11);
          direntry[12] = i; // Extent number
          direntry[13] = 0;
          direntry[14] = 0;
          if (num_extents - (i * extents_per_entry) > extents_per_entry) {
              direntry[15] = 0x80;
              extents_to_write = extents_per_entry;
          } else {
              direntry[15] = ((len % (extents_per_entry * h->spec.extent_size)) / 128) + 1;
              extents_to_write = (num_extents - (i * extents_per_entry));
          }
          for (j = 0; j < extents_per_entry; j++) {
              if (j < extents_to_write) {
                  h->extents[current_extent] = 1;
                  if (h->spec.byte_size_extents) {
                      direntry[j + 16] = (current_extent) % 256;
                  } else {
                      direntry[j * 2 + 16] = (current_extent) % 256;
                      direntry[j * 2 + 16 + 1] = (current_extent) / 256;
                  }
                  current_extent++;
              }
          }
          memcpy(h->image + directory_offset, direntry, 32);
          directory_offset += 32;
      }
  }
  
  // FAT filesystem - we delegate mostly to FatFS
  
  // Nasty static reference to file, TODO, I can do this better
  static disc_handle *current_fat_handle = NULL;
  
  disc_handle *fat_create(disc_spec* spec)
  {
      disc_handle *h = disc_create(spec);
      char         buf[1024];
      FRESULT      res;
  
      current_fat_handle = h;
      // Create a file system
      if ( (res = f_mkfs("1", spec->fat_format_flags, spec->cluster_size, buf, sizeof(buf), spec->number_of_fats, spec->directory_entries)) != FR_OK) {
          exit_log(1, "Cannot create FAT filesystem: %d\n",res);
      }
  
      // And now we need to mount it
      if ( (res = f_mount(&h->fatfs, "1", 1)) != FR_OK ) {
          exit_log(1, "Cannot mount newly create FAT filesystem: %d\n",res);
      }
  
      h->write_file = fat_write_file;
      return h;
  }
  
  static void fat_write_file(disc_handle* h, char *filename, void* data, size_t len)
  {
      FIL file={{0}};
      UINT written;
  
      if ( f_open(&file, filename, FA_WRITE|FA_CREATE_ALWAYS) != FR_OK ) {
          exit_log(1, "Cannot create file <%s> on FAT image", filename);
      }
  
      if ( f_write(&file, data, len, &written) != FR_OK ) {
          exit_log(1, "Cannot write file contents to FAT image");
      }
  
      f_close(&file);
  }
  
  
  // FATFs interface
  
  DSTATUS disk_status (
  	BYTE pdrv		/* Physical drive nmuber to identify the drive */
  )
  {
      return RES_OK;
  }
  
  DSTATUS disk_initialize (
  	BYTE pdrv				/* Physical drive nmuber to identify the drive */
  )
  {
      return RES_OK;
  }
  
  
  DRESULT disk_read (
  	BYTE pdrv,		/* Physical drive nmuber to identify the drive */
  	BYTE *buff,		/* Data buffer to store read data */
  	DWORD sector,	/* Start sector in LBA */
  	UINT count		/* Number of sectors to read */
  )
  {
      disc_read_sector_lba(current_fat_handle, sector, count, buff);
  
      return RES_OK;
  }
  
  
  DRESULT disk_write (
  	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
  	const BYTE *buff,	/* Data to be written */
  	DWORD sector,		/* Start sector in LBA */
  	UINT count			/* Number of sectors to write */
  )
  {
      disc_write_sector_lba(current_fat_handle, sector, count, buff);
  
      return RES_OK;
  }
  
  DRESULT disk_ioctl (
  	BYTE pdrv,		/* Physical drive nmuber (0..) */
  	BYTE cmd,		/* Control code */
  	void *buff		/* Buffer to send/receive control data */
  )
  {
      int    val;
      switch ( cmd ) {
      case GET_SECTOR_COUNT:
          val = disc_get_sector_count(current_fat_handle);
          *(DWORD *)buff = val;
          break;
  
      case GET_SECTOR_SIZE:
      case GET_BLOCK_SIZE:
          val = disc_get_sector_size(current_fat_handle);
          *(WORD *)buff = val;
          break;
      }
      return RES_OK;
  }
  
  