diff -Naur spediv_v0.1/divide.c spediv_v0.2/divide.c --- spediv_v0.1/divide.c 2005-06-25 21:57:21.000000000 +0200 +++ spediv_v0.2/divide.c 2005-07-04 13:30:58.000000000 +0200 @@ -107,6 +107,10 @@ // active drive (0='A:', 1='B:') int divide_active_drive=0; +struct divide_part_struct { // partition info + int fd, len, ptr; +}; + struct divide_drive_struct { char *path; // image path int c,h,s; // C/H/S geometry of disk @@ -116,13 +120,8 @@ byte identify[512]; // identify virtual sector // See README.divIDE for more information - int mbr_fd; // Master Boot Record info - int mbr_len; - int mbr_ptr; - - int partition_fd; // partition info - int partition_len; - int partition_ptr; + struct divide_part_struct mbr; // Master Boot Record info + struct divide_part_struct partition[4]; // partition info // byte buffer[512*DIVIDE_MAX_SEC_NR]; @@ -195,7 +194,7 @@ } // initialize variables void divide_init() { - int i,j,drive; + int i, j, drive, part; // make copy of original spectrum memory (to recover it after unmaping divide memory) memcpy(orig_rom, PRNM(proc).mem, 16384); @@ -230,8 +229,9 @@ DISK.in_port_A7=0; DISK.in_port_BF=0; DISK.path=NULL; - DISK.mbr_fd=-1; - DISK.partition_fd=-1; + DISK.mbr.fd=-1; + for (part=0; part<4; part++) + DISK.partition[part].fd=-1; } } @@ -250,13 +250,13 @@ // it must contain files: // .identify (virtual sector containing drive firmware information) // .mbr (master boot record [and rest of track) -// part1 (partition image) -// part2..partN, .ebr (other partitions, not implemented in this stage) +// part1, part2, part3, part4 (partition image) +// part5..partN, .ebr (other partitions, not implemented in this stage) // this model was choosed to easy mount divide images under linux void divide_attach_drive(int drive, char *path) { char *fname; - int fd, r, len; + int fd, r, len, part; byte identify[512]; if (!path) return; @@ -280,26 +280,36 @@ memcpy(DISK.identify, identify, 512); - // read Master Boot Record information + // open Master Boot Record file snprintf(fname, len, "%s/.mbr", path); - if ((DISK.mbr_fd=open(fname, O_RDWR))!=-1) { + if ((DISK.mbr.fd=open(fname, O_RDWR))!=-1) { // length is in sectors (512bytes blocks), extra chunk is ignored (if size is not divisible by 512) - DISK.mbr_len=(lseek(DISK.mbr_fd, 0, SEEK_END))>>9; - DISK.mbr_ptr=0; + DISK.mbr.len=(lseek(DISK.mbr.fd, 0, SEEK_END))>>9; + DISK.mbr.ptr=0; // this is for realistic emulation of moving disk head (not used now) - lseek(DISK.mbr_fd, DISK.mbr_ptr, SEEK_SET); + lseek(DISK.mbr.fd, DISK.mbr.ptr, SEEK_SET); + } else { + DISK.mbr.fd = -1; + DISK.mbr.len = 0; + DISK.mbr.ptr = 0; } - // read first partition - snprintf(fname, len, "%s/part1", path); - if ((DISK.partition_fd=open(fname, O_RDWR))!=-1) { - // length is in sectors (512bytes blocks), extra chunk is ignored (if size is not divisible by 512) - DISK.partition_len=(lseek(DISK.partition_fd, 0, SEEK_END))>>9; - DISK.partition_ptr=0; - // this is for realistic emulation of moving disk head (not used now) - lseek(DISK.partition_fd, DISK.partition_ptr, SEEK_SET); + // open partition files + for (part=0; part<4; part++) { + snprintf(fname, len, "%s/part%d", path, (part+1)); + if ((DISK.partition[part].fd=open(fname, O_RDWR))!=-1) { + // length is in sectors (512bytes blocks), extra chunk is ignored (if size is not divisible by 512) + DISK.partition[part].len=(lseek(DISK.partition[part].fd, 0, SEEK_END))>>9; + DISK.partition[part].ptr=0; + // this is for realistic emulation of moving disk head (not used now) + lseek(DISK.partition[part].fd, DISK.partition[part].ptr, SEEK_SET); + } else { + DISK.partition[part].fd = -1; + DISK.partition[part].len = 0; + DISK.partition[part].ptr = 0; + } } - + DISK.buffer_ptr=0; DISK.buffer_len=0; DISK.cmd=0; @@ -319,18 +329,27 @@ void divide_detach_drive(int drive) { - if (DISK.path) { - free(DISK.path); - DISK.path=NULL; - } - if (DISK.mbr_fd!=-1) { - close(DISK.mbr_fd); - DISK.mbr_fd=-1; - } - if (DISK.partition_fd!=-1) { - close(DISK.partition_fd); - DISK.partition_fd=-1; - } + int part; + + if (!DISK.path) + return; + + free(DISK.path); + DISK.path=NULL; + + if (DISK.mbr.fd!=-1) { + close(DISK.mbr.fd); + DISK.mbr.fd=-1; + DISK.mbr.len=0; + DISK.mbr.ptr=0; + } + for (part=0; part<4; part++) + if (DISK.partition[part].fd!=-1) { + close(DISK.partition[part].fd); + DISK.partition[part].fd=-1; + DISK.partition[part].len=0; + DISK.partition[part].ptr=0; + } if (!drive) put_msg("Image successfully detached from drive 'A:'."); else @@ -409,8 +428,8 @@ // OUT wrapper void divide_port_out(int portl, byte data) { - int i,drive; - int lba; + int i, drive, part; + int lba, tlba; long size; drive = divide_active_drive; @@ -430,6 +449,9 @@ drive = divide_active_drive; DISK.port_BB = data; DISK2.port_BB = data; + + DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DF & STATUS_CLR_DRQ & STATUS_CLR_ERR); + DISK.in_port_BF |= (STATUS_SET_DRDY); break; case 0xB7: // cylinder register high DISK.port_B7 = data; @@ -469,7 +491,7 @@ break; case 0x91: // initialise drive parameters - if ((DISK.mbr_fd == -1) || (DISK.partition_fd == -1)) { + if (!DISK.path || (DISK.port_AB == 0)) { // error DISK.in_port_A7 |= ERROR_SET_ABRT; DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DRQ); @@ -477,16 +499,15 @@ break; } // recalculate new geometry to fit CHS configuration - size = DISK.identify[112] + (DISK.identify[113] << 16); - if (size>16514064) size=16,514,064; + size = DISK.identify[120] | (DISK.identify[121] << 8) | (DISK.identify[122] << 16) | (DISK.identify[123] << 24); + if (size>16514064) size=16514064; - DISK.h = (DISK.port_BB&15)+1; + DISK.h = (DISK.port_BB&15) + 1; DISK.s = DISK.port_AB; - if ( (DISK.h * DISK.s) == 0 ) - DISK.c = size / (DISK.h * DISK.s); - else - DISK.c = 0; + DISK.c = size / (DISK.h * DISK.s); if (DISK.c>65535) DISK.c=65535; + + size = DISK.c * DISK.h * DISK.s; DISK.identify[108] = DISK.c & 0xFF; DISK.identify[109] = DISK.c >> 8; @@ -497,12 +518,17 @@ DISK.identify[112] = DISK.s & 0xFF; DISK.identify[113] = DISK.s >> 8; + DISK.identify[114] = size & 0xFF; + DISK.identify[115] = (size >> 8) & 0xFF; + DISK.identify[116] = (size >> 16) & 0xFF; + DISK.identify[117] = (size >> 24); + DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DF & STATUS_CLR_DRQ & STATUS_CLR_ERR); break; case 0xA1: // identify drive (ATAPI) case 0xEC: // identify drive (ATA) - if ((DISK.mbr_fd == -1) || (DISK.partition_fd == -1)) { + if (!DISK.path) { DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DRDY & STATUS_CLR_DRQ); DISK.in_port_BF |= (STATUS_SET_DF | STATUS_SET_ERR); break; @@ -524,7 +550,7 @@ case 0xC8: // read DMA with retry case 0xC9: // read DMA without retry - if ((DISK.mbr_fd == -1) || (DISK.partition_fd == -1) || (DISK.port_AB>DIVIDE_MAX_SEC_NR)) { + if (!DISK.path || (DISK.port_AB>DIVIDE_MAX_SEC_NR)) { DISK.in_port_A7 &= (ERROR_CLR_MC & ERROR_CLR_MCR); DISK.in_port_A7 |= (ERROR_SET_UNC | ERROR_SET_IDNF | ERROR_SET_ABRT | ERROR_SET_NM); DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DF & STATUS_CLR_DRQ); @@ -545,12 +571,20 @@ for (i=0; i<((DISK.port_AB == 0) ? 256 : DISK.port_AB); i++) // 0 means 256 sectors { // read 1 sector only. we cannot read all sectors at once because we have disk splitted into blocks - if (lba < DISK.mbr_len) { - DISK.mbr_ptr = lseek(DISK.mbr_fd, (lba << 9), SEEK_SET); - read(DISK.mbr_fd, DISK.buffer + DISK.buffer_len, 512); + tlba=lba; + if (tlba < DISK.mbr.len) { + DISK.mbr.ptr = lseek(DISK.mbr.fd, (tlba << 9), SEEK_SET); + read(DISK.mbr.fd, DISK.buffer + DISK.buffer_len, 512); } else { - DISK.partition_ptr = lseek(DISK.partition_fd, ((lba - DISK.mbr_len) << 9), SEEK_SET); - read(DISK.partition_fd, DISK.buffer + DISK.buffer_len, 512); + tlba-=DISK.mbr.len; + for (part=0; part<4; part++) { + if (tlba < DISK.partition[part].len) { + DISK.partition[part].ptr = lseek(DISK.partition[part].fd, (tlba << 9), SEEK_SET); + read(DISK.partition[part].fd, DISK.buffer + DISK.buffer_len, 512); + break; + } + tlba-=DISK.partition[part].len; + } } DISK.buffer_len += 512; lba++; @@ -563,7 +597,7 @@ case 0x31: // write sectors without retry case 0x32: // write long with retry case 0x33: // write long without retry - if ((DISK.mbr_fd == -1) || (DISK.partition_fd == -1) || (DISK.port_AB>DIVIDE_MAX_SEC_NR)) { + if (!DISK.path || (DISK.port_AB>DIVIDE_MAX_SEC_NR)) { DISK.in_port_A7 &= (ERROR_CLR_WP & ERROR_CLR_MC & ERROR_CLR_MCR); DISK.in_port_A7 |= (ERROR_SET_IDNF | ERROR_SET_ABRT | ERROR_SET_NM); DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DF & STATUS_CLR_DRQ); @@ -582,7 +616,7 @@ } break; case 0xA3: // data register - if (DISK.mbr_fd==-1 || DISK.partition_fd==-1 || DISK.port_AB>DIVIDE_MAX_SEC_NR) { + if (!DISK.path || DISK.port_AB>DIVIDE_MAX_SEC_NR) { break; } if (DISK.cmd!=DIVIDE_WRITE_BUFF) @@ -601,12 +635,20 @@ lba = chs2lba(drive, (DISK.port_B7 << 8) | DISK.port_B3, DISK.port_BB & 0x0F, DISK.port_AF); // write sector to disk - if (lba < DISK.mbr_len) { - DISK.mbr_ptr = lseek(DISK.mbr_fd, (lba << 9), SEEK_SET); - write(DISK.mbr_fd, DISK.buffer + DISK.buffer_ptr, 512); + tlba=lba; + if (tlba < DISK.mbr.len) { + DISK.mbr.ptr = lseek(DISK.mbr.fd, (tlba << 9), SEEK_SET); + write(DISK.mbr.fd, DISK.buffer + DISK.buffer_len, 512); } else { - DISK.partition_ptr = lseek(DISK.partition_fd, ((lba - DISK.mbr_len) << 9), SEEK_SET); - write(DISK.partition_fd, DISK.buffer + DISK.buffer_ptr, 512); + tlba-=DISK.mbr.len; + for (part=0; part<4; part++) { + if (tlba < DISK.partition[part].len) { + DISK.partition[part].ptr = lseek(DISK.partition[part].fd, (tlba << 9), SEEK_SET); + write(DISK.partition[part].fd, DISK.buffer + DISK.buffer_len, 512); + break; + } + tlba-=DISK.partition[part].len; + } } DISK.buffer_ptr += 512; DISK.port_AB--;