VOID VDDDispatch(VOID) { FUNCTIONCODE functioncode; CBM_FILE cbmfile; BOOLEAN error; FUNC_ENTER(); functioncode = getDL(); error = FALSE; // convert to BX value into a CBM_FILE switch (functioncode) { case FC_VDD_USLEEP: case FC_DRIVER_OPEN: case FC_GET_DRIVER_NAME: // FC_VDD_USLEEP, FC_DRIVER_OPEN and FC_GET_DRIVER_NAME are special, // they do not have a BX input. break; default: cbmfile = vdd_cbmfile_get(getBX()); if (cbmfile == INVALID_HANDLE_VALUE) { DBG_ERROR((DBG_PREFIX "invalid BX given: %04x", getBX())); error = TRUE; } break; } if (!error) { switch (functioncode) { case FC_DRIVER_OPEN: error = vdd_driver_open(); break; case FC_DRIVER_CLOSE: error = vdd_driver_close(cbmfile); break; case FC_LISTEN: error = vdd_listen(cbmfile); break; case FC_TALK: error = vdd_talk(cbmfile); break; case FC_OPEN: error = vdd_open(cbmfile); break; case FC_CLOSE: error = vdd_close(cbmfile); break; case FC_RAW_READ: error = vdd_raw_read(cbmfile); break; case FC_RAW_WRITE: error = vdd_raw_write(cbmfile); break; case FC_UNLISTEN: error = vdd_unlisten(cbmfile); break; case FC_UNTALK: error = vdd_untalk(cbmfile); break; case FC_GET_EOI: error = vdd_get_eoi(cbmfile); break; case FC_CLEAR_EOI: error = vdd_clear_eoi(cbmfile); break; case FC_RESET: error = vdd_reset(cbmfile); break; case FC_PP_READ: error = vdd_pp_read(cbmfile); break; case FC_PP_WRITE: error = vdd_pp_write(cbmfile); break; case FC_IEC_POLL: error = vdd_iec_poll(cbmfile); break; case FC_IEC_GET: error = vdd_iec_get(cbmfile); break; case FC_IEC_SET: error = vdd_iec_set(cbmfile); break; case FC_IEC_RELEASE: error = vdd_iec_release(cbmfile); break; case FC_IEC_SETRELEASE: error = vdd_iec_setrelease(cbmfile); break; case FC_IEC_WAIT: error = vdd_iec_wait(cbmfile); break; case FC_UPLOAD: error = vdd_upload(cbmfile); break; case FC_DEVICE_STATUS: error = vdd_device_status(cbmfile); break; case FC_EXEC_COMMAND: error = vdd_exec_command(cbmfile); break; case FC_IDENTIFY: error = vdd_identify(cbmfile); break; case FC_IDENTIFY_XP1541: error = vdd_identify_xp1541(cbmfile); break; case FC_GET_DRIVER_NAME: error = vdd_get_driver_name(); break; case FC_VDD_USLEEP: error = vdd_usleep(); break; case FC_VDD_INSTALL_IOHOOK: error = vdd_install_iohook(cbmfile); break; case FC_VDD_UNINSTALL_IOHOOK: error = vdd_uninstall_iohook(cbmfile); break; default: // this function is not implemented: DBG_ERROR((DBG_PREFIX "unknown function code in DL: %02x", functioncode)); error = TRUE; break; } } setCF(error ? 1 : 0); FUNC_LEAVE(); }
/*static*/ VOID WINAPI BiosDiskService(LPWORD Stack) { BYTE Drive; PDISK_IMAGE DiskImage; switch (getAH()) { /* Disk -- Reset Disk System */ case 0x00: { Drive = getDL(); if (Drive & 0x80) { AllDisksReset(); /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } Drive &= ~0x80; if (Drive >= ARRAYSIZE(FloppyDrive)) { DPRINT1("BiosDiskService(0x00): Drive number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } // TODO: Reset drive /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } /* Disk -- Get Status of Last Operation */ case 0x01: { BYTE LastOperationStatus = 0x00; Drive = getDL(); DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x01): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } LastOperationStatus = DiskImage->LastOperationStatus; if (Drive & 0x80) Bda->LastDiskOperation = LastOperationStatus; else Bda->LastDisketteOperation = LastOperationStatus; /* Return last error */ setAH(LastOperationStatus); if (LastOperationStatus == 0x00) Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; else Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Disk -- Read Sectors into Memory */ case 0x02: { BYTE Status; BYTE Head = getDH(); BYTE NumSectors = getAL(); // CH: Low eight bits of cylinder number // CL: High two bits of cylinder (bits 6-7, hard disk only) WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02); // CL: Sector number 1-63 (bits 0-5) BYTE Sector = (getCL() & 0x3F); // 1-based Drive = getDL(); DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x02): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Read the sectors */ Status = ReadDisk(DiskImage, Cylinder, Head, Sector, NumSectors); if (Status == 0x00) { /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } else { DPRINT1("BiosDiskService(0x02): Error when reading from disk number 0x%02X (0x%02X)\n", Drive, Status); /* Return error */ setAH(Status); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; } break; } /* Disk -- Write Disk Sectors */ case 0x03: { BYTE Status; BYTE Head = getDH(); BYTE NumSectors = getAL(); // CH: Low eight bits of cylinder number // CL: High two bits of cylinder (bits 6-7, hard disk only) WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02); // CL: Sector number 1-63 (bits 0-5) BYTE Sector = (getCL() & 0x3F); // 1-based Drive = getDL(); DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x03): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Write the sectors */ Status = WriteDisk(DiskImage, Cylinder, Head, Sector, NumSectors); if (Status == 0x00) { /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } else { DPRINT1("BiosDiskService(0x03): Error when writing to disk number 0x%02X (0x%02X)\n", Drive, Status); /* Return error */ setAH(Status); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; } break; } /* Disk -- Verify Disk Sectors */ case 0x04: /* Floppy/Fixed Disk -- Format Track */ case 0x05: /* Fixed Disk -- Format Track and Set Bad Sector Flags */ case 0x06: /* Fixed Disk -- Format Drive starting at Given Track */ case 0x07: goto Default; /* Disk -- Get Drive Parameters */ case 0x08: { WORD MaxCylinders; BYTE MaxHeads; BYTE PresentDrives = 0; BYTE i; Drive = getDL(); DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x08): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } // Minus 2 because it's the maximum cylinder number (not count), // and the last cylinder is reserved (for compatibility with BIOSes // which reserve it for testing purposes). MaxCylinders = DiskImage->DiskInfo.Cylinders - 2; // Minus 1 because it's the maximum head number (not count). MaxHeads = DiskImage->DiskInfo.Heads - 1; // CL: Sector number 1-63 (bits 0-5) // High two bits of cylinder (bits 6-7, hard disk only) setCL((DiskImage->DiskInfo.Sectors & 0x3F) | ((HIBYTE(MaxCylinders) & 0x02) << 6)); // CH: Low eight bits of cylinder number setCH(LOBYTE(MaxCylinders)); setDH(MaxHeads); if (Drive & 0x80) { /* Count the number of active HDDs */ for (i = 0; i < ARRAYSIZE(HardDrive); ++i) { if (IsDiskPresent(HardDrive[i])) ++PresentDrives; } /* Reset ES:DI to NULL */ // FIXME: NONONO!! Apps expect (for example, MS-DOS kernel) // that this function does not modify ES:DI if it was called // for a HDD. // setES(0x0000); // setDI(0x0000); } else { /* Count the number of active floppies */ for (i = 0; i < ARRAYSIZE(FloppyDrive); ++i) { if (IsDiskPresent(FloppyDrive[i])) ++PresentDrives; } /* ES:DI points to the floppy parameter table */ setES(HIWORD(((PULONG)BaseAddress)[0x1E])); setDI(LOWORD(((PULONG)BaseAddress)[0x1E])); } setDL(PresentDrives); setBL(DiskImage->DiskType); // DiskGeometryList[DiskImage->DiskType].biosval setAL(0x00); /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } /* Hard Disk -- Initialize Controller with Drive Parameters */ case 0x09: /* Hard Disk -- Read Long Sectors */ case 0x0A: /* Hard Disk -- Write Long Sectors */ case 0x0B: goto Default; /* Hard Disk -- Seek to Cylinder */ case 0x0C: { BYTE Status; BYTE Head = getDH(); // CH: Low eight bits of cylinder number // CL: High two bits of cylinder (bits 6-7, hard disk only) WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02); // CL: Sector number 1-63 (bits 0-5) BYTE Sector = (getCL() & 0x3F); // 1-based Drive = getDL(); if (!(Drive & 0x80)) { DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X is not a HDD\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Set position */ Status = SeekDisk(DiskImage, Cylinder, Head, Sector); if (Status == 0x00) { /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } else { DPRINT1("BiosDiskService(0x0C): Error when seeking in disk number 0x%02X (0x%02X)\n", Drive, Status); /* Return error */ setAH(Status); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; } break; } /* Hard Disk -- Reset Hard Disks */ case 0x0D: { // FIXME: Should do what 0x11 does. UNIMPLEMENTED; } /* Hard Disk -- Read Sector Buffer (XT only) */ case 0x0E: /* Hard Disk -- Write Sector Buffer (XT only) */ case 0x0F: goto Default; /* Hard Disk -- Check if Drive is ready */ case 0x10: { Drive = getDL(); if (!(Drive & 0x80)) { DPRINT1("BiosDiskService(0x10): Disk number 0x%02X is not a HDD\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x10): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } /* Hard Disk -- Recalibrate Drive */ case 0x11: { BYTE Status; Drive = getDL(); if (!(Drive & 0x80)) { DPRINT1("BiosDiskService(0x11): Disk number 0x%02X is not a HDD\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x11): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Set position to zero */ Status = SeekDisk(DiskImage, /*Cylinder*/ 0, /*Head*/ 0, /*Sector*/ 1); if (Status == 0x00) { /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } else { DPRINT1("BiosDiskService(0x11): Error when recalibrating disk number 0x%02X (0x%02X)\n", Drive, Status); /* Return error */ setAH(Status); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; } break; } /* Hard Disk -- Controller RAM Diagnostic */ case 0x12: /* Hard Disk -- Drive Diagnostic */ case 0x13: /* Hard Disk -- Controller Internal Diagnostic */ case 0x14: goto Default; /* Disk -- Get Disk Type */ case 0x15: { Drive = getDL(); DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x15): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } if (Drive & 0x80) { ULONG NumSectors; /* Hard disk */ setAH(0x03); /* Number of 512-byte sectors in CX:DX */ NumSectors = (ULONG)((ULONG)DiskImage->DiskInfo.Cylinders * DiskImage->DiskInfo.Heads) * DiskImage->DiskInfo.Sectors; setCX(HIWORD(NumSectors)); setDX(LOWORD(NumSectors)); } else { /* Floppy */ setAH(0x01); } /* Return success */ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } /* Floppy Disk -- Detect Disk Change */ case 0x16: /* Floppy Disk -- Set Disk Type for Format */ case 0x17: /* Disk -- Set Media Type for Format */ case 0x18: goto Default; default: Default: { DPRINT1("BIOS Function INT 13h, AH = 0x%02X, AL = 0x%02X, BH = 0x%02X NOT IMPLEMENTED\n", getAH(), getAL(), getBH()); } } }