23 #include <sys/types.h> 
   43 static int enable_mode_transient_callback = -1;
 
   46 #define D64_SIZE        174848 
   47 #define D71_SIZE        349696 
   48 #define D65_SIZE        2785280 
   50 #define IS_RO(p)        (!!((p) & D81ACCESS_RO)) 
   51 #define IS_RW(p)        (!((p) & D81ACCESS_RO)) 
   52 #define HAS_DISK(p)     (((p)&& 0xFF) != D81ACCESS_EMPTY) 
   53 #define IS_AUTOCLOSE(p) (!!((p) & D81ACCESS_AUTOCLOSE)) 
   59         if (enable_mode_transient_callback != -1)
 
   60                 FATAL(
"d81access_init(): trying to re-run d81access_init()?!");
 
   61         enable_mode_transient_callback = 1;
 
   62         for (
int i = 0; i < 8; i++) {
 
   74         return d81[which].mode;
 
   80         if (d81[which].
fd >= 0) {
 
   83                         DEBUGPRINT(
"D81: previous file descriptor (%d) closed because of auto-close policy" NL, d81[which].
fd);
 
   85                         DEBUGPRINT(
"D81: previous file descriptor (%d) is NOT closed, because marked as non-autoclose!" NL, d81[which].
fd);
 
   89                 closedir(d81[which].
dir);
 
   91                 d81[which].dir = NULL;
 
   94         d81[which].start_at = 0;
 
   95         if (enable_mode_transient_callback)
 
  102         for (
int i = 0; i < 8; i++)
 
  107 static void d81access_close_internal ( 
int which )
 
  109         enable_mode_transient_callback = 0;
 
  111         enable_mode_transient_callback = 1;
 
  115 static void d81access_attach_fd_internal ( 
int which, 
int fd, off_t offset, 
int mode )
 
  118                 FATAL(
"d81access_attach_fd_internal() tries to attach invalid fd");
 
  119         d81access_close_internal(which);
 
  122                 d81[which].mode = 
mode;
 
  133                 DEBUGPRINT(
"D81: using empty access (no disk in drive) by request" NL);
 
  136         d81[which].start_at = offset;
 
  147         int check_mode = 
mode & 0xFF;
 
  149                 FATAL(
"d81access_attach_fd() mode low bits must have D81ACCESS_IMG or D81ACCESS_EMPTY");
 
  150         d81access_attach_fd_internal(which, 
fd, offset, 
mode);
 
  158 void d81access_attach_cb ( 
int which, off_t offset, d81access_rd_cb_t rd_callback, d81access_wr_cb_t wr_callback )
 
  160         d81access_close_internal(which);
 
  164         d81[which].read_cb = rd_callback;
 
  165         d81[which].write_cb = wr_callback;
 
  166         d81[which].start_at = offset;
 
  167         DEBUGPRINT(
"D81: attaching D81 via provided callbacks, read=%p, write=%p" NL, rd_callback, wr_callback);
 
  176                 DEBUGPRINT(
"D81: attach file request with empty file name, not using FS based disk attachment." NL);
 
  185                 DIR *
dir = opendir(
fn);
 
  188                         d81access_close_internal(which);
 
  189                         d81[which].dir = 
dir;
 
  192                         DEBUGPRINT(
"D81: file system object \"%s\" opened as a directory." NL, 
fn);
 
  195                 } 
else if (errno != ENOTDIR && errno != ENOENT) {
 
  196                         ERROR_WINDOW(
"D81: cannot open directory %s for virtual D81 mode: %s", 
fn, strerror(errno));
 
  203                         DEBUGPRINT(
"D81: could not open file system object \"%s\" as a directory.", 
fn);
 
  205                         FATAL(
"d81access_attach_fsobj(): insane mode argument, no DIR,IMG,PRG given");
 
  209         char fnbuf[PATH_MAX + 1];
 
  214                 ERROR_WINDOW(
"D81: image/program file was specified (%s) but it cannot be opened: %s", 
fn, strerror(errno));
 
  219                 ERROR_WINDOW(
"D81: Cannot query the size of external D81 image/program file %s ERROR: %s", 
fn, strerror(errno));
 
  227                         d81[which].prg_size = 
size;     
 
  228                         d81[which].prg_blk_size = 
size / 254;
 
  229                         d81[which].prg_blk_last_size = 
size % 254;
 
  231                                 d81[which].prg_blk_size++;
 
  233                                 d81[which].prg_blk_last_size = 254;
 
  238                         ERROR_WINDOW(
"Specified size for D81 seems to be a program file (too small for real D81), but PRG mode virtual disk feature was not requested");
 
  275         ERROR_WINDOW(
"Cannot guess the type of object (from its size) wanted to use for floppy emulation");
 
  280 static int file_io_op ( 
const int which, 
const int is_write, 
const int image_offset, 
Uint8 *buffer, 
const int size )
 
  282         off_t offset = d81[which].start_at + (off_t)image_offset;
 
  283         if (lseek(d81[which].
fd, offset, SEEK_SET) != offset)
 
  284                 FATAL(
"D81: SEEK: seek host-OS failure: %s", strerror(errno));
 
  288         FATAL(
"D81: %s: host-OS error: %s", is_write ? 
"WRITE" : 
"READ", strerror(errno));
 
  293 static int read_fake64 ( 
const int which, 
Uint8 *buffer, 
int d81_offset, 
int number_of_logical_sectors )
 
  295         for (; number_of_logical_sectors; number_of_logical_sectors--, d81_offset += 0x100, buffer += 0x100) {
 
  296                 int track  =  d81_offset / 0x2800 + 1;  
 
  297                 int sector = (d81_offset % 0x2800) >> 8;
 
  299                         memset(buffer, 0, 0x100);
 
  300                         DEBUGPRINT(
"D81: FAKE64: D81 track 18 tried to be read, which would be the D64 dir/sys track. Ignoring!" NL);
 
  305                 if (!track || track > 35) {     
 
  306                         memset(buffer, 0, 0x100);
 
  307                         DEBUGPRINT(
"D81: FAKE64: invalid track for D64 %d" NL, track);
 
  312                 int d64_max_sectors, d64_track_ofs;
 
  314                         d64_track_ofs   = 21 * 256 * (track -  1) + 0x00000;
 
  315                         d64_max_sectors = 21;
 
  316                 } 
else if (track <= 24) {       
 
  317                         d64_track_ofs   = 19 * 256 * (track - 18) + 0x16500;
 
  318                         d64_max_sectors = 19;
 
  319                 } 
else if (track <= 30) {       
 
  320                         d64_track_ofs   = 18 * 256 * (track - 25) + 0x1EA00;
 
  321                         d64_max_sectors = 18;
 
  323                         d64_track_ofs   = 17 * 256 * (track - 31) + 0x25600;
 
  324                         d64_max_sectors = 17;
 
  326                 if (sector >= d64_max_sectors) {        
 
  327                         memset(buffer, 0, 0x100);
 
  328                         DEBUGPRINT(
"D81: FAKE64: invalid sector for D64 %d on track %d" NL, sector, track);
 
  335                                 sector_to_read = sector - 2;
 
  339                         sector_to_read = sector;
 
  340                 if (track == 18 || sector_to_read != sector)
 
  341                         DEBUGPRINT(
"D81: FAKE64: translated to D64 track:sector %d:%d from the orginal requested %d:%d" NL, track, sector_to_read, track == 18 ? 40 : track, sector);
 
  342                 if (file_io_op(which, 0, d64_track_ofs + sector_to_read * 256, buffer, 0x100) != 0x100) {
 
  353                                 memcpy(buffer + 4, buffer + 0x90, 16);  
 
  356                                 buffer[0x16] = buffer[0xA2];    
 
  357                                 buffer[0x17] = buffer[0xA3];    
 
  363                                 memset(buffer + 0x1D, 0, 0x100 - 0x1D);
 
  364                         } 
else if (sector == 1 || sector == 2) {
 
  366                                 Uint8 obuffer[0x100];
 
  367                                 memcpy(obuffer, buffer, 0x100); 
 
  368                                 memset(buffer, 0, 0x100);
 
  372                                         for (
int tf0 = 0; tf0 < 35; tf0++) {
 
  373                                                 Uint8 *obam = obuffer + 4 + (4 * tf0);
 
  374                                                 Uint8 *nbam = buffer + 0x10 + (6 * tf0);
 
  376                                                         memcpy(nbam, obam, 4);
 
  384                                 buffer[4] = obuffer[0xA2];      
 
  385                                 buffer[5] = obuffer[0xA3];      
 
  388                         } 
else if (buffer[0] == 18) {   
 
  390                                 if (buffer[1] > 0 && buffer[1] < 19)
 
  399 static int read_prg ( 
const int which, 
Uint8 *buffer, 
int d81_offset, 
int number_of_logical_sectors )
 
  401         static const Uint8 vdsk_head_sect[] = {
 
  404                 'X', 
'E', 
'M', 
'U', 
' ', 
'V', 
'R', 
'-', 
'D', 
'I', 
'S', 
'K', 
' ', 
'R', 
'/', 
'O',
 
  408                 0x33, 0x44, 0xA0, 0xA0
 
  410         static const Uint8 vdsk_file_name[16] = {
 
  411                 'F', 
'I', 
'L', 
'E', 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0
 
  414         memset(buffer, 0, 512);
 
  417         for (; number_of_logical_sectors; number_of_logical_sectors--, d81_offset += 0x100, buffer += 0x100) {
 
  418                 DEBUGPRINT(
"D81VIRTUAL: reading sub-sector @ $%X" NL, d81_offset);
 
  419                 if (d81_offset == 0x61800) {            
 
  420                         memcpy(buffer, vdsk_head_sect, 
sizeof vdsk_head_sect);
 
  421                 } 
else if (d81_offset == 0x61900 || d81_offset == 0x61A00) {    
 
  422                         if (d81_offset == 0x61900) {
 
  429                         buffer[4] = vdsk_head_sect[0x16];
 
  430                         buffer[5] = vdsk_head_sect[0x17];
 
  432                 } 
else if (d81_offset == 0x61B00) {     
 
  436                         memcpy(buffer + 5, vdsk_file_name, 16);
 
  437                         buffer[0x1E] = d81[which].prg_blk_size & 0xFF;
 
  438                         buffer[0x1F] = d81[which].prg_blk_size >> 8;
 
  439                         memcpy(buffer + 0x22, buffer + 2, 0x20 - 2);    
 
  445                         int block = d81_offset >> 8;    
 
  449                                         reqsize = d81[which].prg_blk_last_size;
 
  453                                         buffer[0] = ((
block + 1) / 40) + 1;
 
  454                                         buffer[1] = (
block + 1) % 40;
 
  456                                 ret = file_io_op(which, 0, 
block * 254, buffer + 2, reqsize);
 
  457                                 DEBUGPRINT(
"D81VIRTUAL: ... data block, block number %d, next_track = $%02X next_sector = $%02X" NL, 
block, buffer[0], buffer[1]);
 
  459                                 if (host_seek_to(NULL, 
block * 254, 
"reading[PRG81VIRT@HOST]", d81_is_prg + 512, d81fd) < 0)
 
  463                                 DEBUGPRINT(
"D81VIRTUAL: ... reading result: expected %d retval %d" NL, reqsize, ret);
 
  477 static int check_io_req_params ( 
const int which, 
const Uint8 side, 
const Uint8 track, 
const Uint8 sector, 
const int sector_size, 
int *io_size_p )
 
  479         if (
XEMU_UNLIKELY(sector_size != 0x100 && sector_size != 0x200))
 
  480                 FATAL(
"D81ACCESS: check_io_req_params(): invalid sector size %d", sector_size);
 
  482                 DEBUGPRINT(
"D81ACCESS: warning, trying file op on sector-0 within track %d" NL, track);
 
  491                 offset = (((
const int)track << 7) + (sector - 1)) * 512;
 
  496                 offset = 40 * (track - 0) * 256 + (sector - 1) * 512 + side * 20 * 256; 
 
  505         if (
XEMU_UNLIKELY(num_of_sides != -1 && side >= num_of_sides)) {        
 
  506                 DEBUGPRINT(
"D81ACCESS: trying to access non-existing side (%d)" NL, side);
 
  510                 DEBUGPRINT(
"D81ACCESS: trying to access non-existing track (%d)" NL, track);
 
  514                 DEBUGPRINT(
"D81ACCESS: trying to access non-exisiting sector (%d) on track %d" NL, sector, track);
 
  520                 DEBUGPRINT(
"D81ACCESS: trying to R/W beyond the end of disk image (offset %d, size %d)" NL, offset, d81[which].
image_size);
 
  524         const int io_size = d81[which].image_size - offset;
 
  526                 DEBUGPRINT(
"D81ACCESS: partial R/W with %d bytes" NL, io_size);
 
  527                 if (io_size != 256) {
 
  529                         ERROR_WINDOW(
"Partial R/W on D81 access which is not 256 byte in length but %d (at offset %d, image size is %d bytes)!", io_size, offset, d81[which].
image_size);
 
  532                 *io_size_p = io_size;
 
  534                 *io_size_p = sector_size;
 
  542         const int offset = check_io_req_params(which, side, track, sector, sector_size, &io_size);
 
  545         switch (d81[which].
mode & 0xFF) {
 
  550                                 return read_fake64(which, buffer, offset, sector_size >> 8);
 
  554                                         memset(buffer, 0xFF, sector_size);
 
  555                                 return file_io_op(which, 0, offset, buffer, io_size) == io_size ? 0 : -1;
 
  558                         return read_prg(which, buffer, offset, sector_size >> 8);
 
  560                         FATAL(
"D81ACCESS: DIR access method is not yet implemented in Xemu, sorry :-(");
 
  562                         FATAL(
"D81: D81ACCESS_CALLBACKS is not implemented!");
 
  565                         FATAL(
"D81ACCESS: d81access_read_sect(): invalid value for 'd81[%d].mode & 0xFF' = %d", which, d81[which].
mode & 0xFF);
 
  567         FATAL(
"D81ACCESS: d81access_read_sect() unhandled case" NL);
 
  575         const int offset = check_io_req_params(which, side, track, sector, sector_size, &io_size);
 
  580         switch (d81[which].
mode & 0xFF) {
 
  584                         return file_io_op(which, 1, offset, buffer, io_size) == io_size ? 0 : -1;
 
  589                         FATAL(
"D81: D81ACCESS_CALLBACKS is not implemented!");
 
  592                         FATAL(
"D81ACCESS: d81access_write_sect(): invalid d81[%d].mode & 0xFF", which);
 
  594         FATAL(
"D81ACCESS: d81access_write_sect() unhandled case" NL);
 
  608         static const char diskname_default[] = 
"XEMU-NAMELESS";
 
  610                 diskname = diskname_default;
 
  611         static const Uint8 mods_at_61800[] = {
 
  613                  0x28,0x03,0x44,0x00,0x44,0x45,0x4d,0x4f,0x45,0x4d,0x50,0x54,0x59,0xa0,0xa0,0xa0,    
 
  615                  0x28,0x03,0x44,0x00,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,    
 
  616                  0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0x30,0x30,0xa0,0x33,0x44,0xa0,0xa0                    
 
  618         static const Uint8 mods_at_61900[] = {
 
  619                  0x28,0x02,0x44,0xbb,0x30,0x30,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    
 
  620                  0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,    
 
  621                  0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,    
 
  622                  0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,    
 
  623                  0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,    
 
  624                  0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,    
 
  625                  0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,    
 
  626                  0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,    
 
  627                  0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,    
 
  628                  0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,    
 
  629                  0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,    
 
  630                  0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,    
 
  631                  0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,    
 
  632                  0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,    
 
  633                  0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,    
 
  634                  0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x24,0xf0,0xff,0xff,0xff,0xff,    
 
  635                  0x00,0xff,0x44,0xbb,0x30,0x30,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,    
 
  636                  0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,    
 
  637                  0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,    
 
  638                  0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,    
 
  639                  0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,    
 
  640                  0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,    
 
  641                  0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,    
 
  642                  0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,    
 
  643                  0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,    
 
  644                  0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,    
 
  645                  0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,    
 
  646                  0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,    
 
  647                  0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,    
 
  648                  0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,    
 
  649                  0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,    
 
  650                  0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,0x28,0xff,0xff,0xff,0xff,0xff,    
 
  654         memcpy(img + 0x61800, mods_at_61800, 
sizeof mods_at_61800);
 
  655         memcpy(img + 0x61900, mods_at_61900, 
sizeof mods_at_61900);
 
  659                 if (diskname[0] == 
'@' || diskname[0] == 
'#')
 
  664                 namelen = strlen(diskname);
 
  665                 if (namelen > 4 && !strcasecmp(diskname + namelen - 4, 
".D81"))
 
  668                 namelen = strlen(diskname);
 
  671         } 
else if (!namelen) {
 
  672                 diskname = diskname_default;
 
  673                 namelen = strlen(diskname_default);
 
  675         unsigned int diskid = namelen + ((namelen + 1) << 8);
 
  676         DEBUGPRINT(
"D81ACCESS: creating memory image of a new D81 disk \"");
 
  677         for (
unsigned int i = 0; i < namelen; i++) {
 
  679                 diskid += (
unsigned int)c + (i << 5);
 
  680                 if (c >= 
'a' && c <= 
'z')
 
  682                 else if (c < 32 || c >= 0x7F)
 
  684                 img[0x61804 + i] = c;
 
  687         diskid = (diskid ^ (diskid >> 5));
 
  688         for (
unsigned int i = 0; i < 2; i++, diskid /= 36) {
 
  689                 const Uint8 c = diskid % 36;
 
  690                 img[0x61816 + i] = c < 26 ? c + 
'A' : c - 26 + 
'0';
 
  692         DEBUGPRINT(
"\",\"%c%c\"" NL, img[0x61816], img[0x61817]);
 
  703         char fullpath[PATH_MAX + 1];
 
  704         const int fd = 
xemu_open_file(
fn, O_WRONLY | O_CREAT | O_TRUNC | (!do_overwrite ? O_EXCL : 0), NULL, fullpath);
 
  706                 const int ret = (errno == EEXIST) ? -2 : -1;
 
  708                         ERROR_WINDOW(
"%s [D81-CREATE]\n%s\n%s", cry, 
fn, strerror(errno));
 
  719                         ERROR_WINDOW(
"%s [D81-WRITE]\n%s\n%s", cry, fullpath, strerror(errno));
 
  723         DEBUGPRINT(
"D81ACCESS: new disk image file \"%s\" has been successfully created (overwrite policy %d)." NL, fullpath, do_overwrite);