Applied all relevant PCem commits;

Extensively cleaned up and changed the CD-ROM code;
Removed CD-ROM IOCTTL (it was causing performance and stability issues);
Turned a lot of things into device_t's;
Added the PS/1 Model 2011 XTA and standalone XTA hard disk controllers, ported from Varcem;
Numerous FDC fixes for the PS/1 Model 2121;
NVR changes ported from Varcem;
The PCap code no longer requires libpcap to be compiled;
Numerous fixes to various SCSI controllers;
Updated NukedOPL to 1.8;
Fixes to OpenAL initialization and closing, should give less Audio issues now;
Revorked parts of the common (S)VGA code (also based on code from QEMU);
Removed the Removable SCSI hard disks (they were a never finished experiment so there was no need to keep them there);
Cleaned up the SCSI hard disk and Iomega ZIP code (but more cleanups of that are coming in the future);
In some occasions (IDE hard disks in multiple sector mode and SCSI hard disks) the status bar icon is no longer updated, should improve performance a bit;
Redid the way the tertiary and quaternary IDE controllers are configured (and they are now device_t's);
Extensively reworked the IDE code and fixed quite a few bugs;
Fixes to XT MFM, AT MFM, and AT ESDI code;
Some changes to XTIDE and MCA ESDI code;
Some fixes to the CD-ROM image handler.
This commit is contained in:
OBattler
2018-04-25 23:51:13 +02:00
parent 2789adca0e
commit a412ceb4d9
151 changed files with 21026 additions and 21058 deletions

View File

@@ -8,7 +8,7 @@
*
* Common code to handle all sorts of disk controllers.
*
* Version: @(#)hdc.c 1.0.12 2018/03/19
* Version: @(#)hdc.c 1.0.13 2018/04/04
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -25,6 +25,7 @@
#include "../device.h"
#include "hdc.h"
#include "hdc_ide.h"
#include "hdd.h"
char *hdc_name; /* configured HDC name */
@@ -106,6 +107,9 @@ static const struct {
{ "[ISA] [IDE] PS/2 AT XTIDE (1.1.5)", "xtide_at_ps2",
&xtide_at_ps2_device },
{ "[ISA] [IDE] WDXT-150 IDE (XTA) Adapter", "xta_wdxt150",
&xta_wdxt150_device },
{ "[ISA] [XT IDE] Acculogic XT IDE", "xtide_acculogic",
&xtide_acculogic_device },
@@ -146,6 +150,9 @@ hdc_init(char *name)
break;
}
}
/* Zero all the hard disk image arrays. */
hdd_image_init();
}
@@ -154,20 +161,17 @@ void
hdc_reset(void)
{
pclog("HDC: reset(current=%d, internal=%d)\n",
hdc_current, (machines[machine].flags & MACHINE_HDC)?1:0);
hdc_current, (machines[machine].flags & MACHINE_HDC) ? 1 : 0);
/* If we have a valid controller, add its device. */
if (hdc_current > 1)
device_add(controllers[hdc_current].device);
/* Reconfire and reset the IDE layer. */
ide_ter_disable();
ide_qua_disable();
if (ide_enable[2])
ide_ter_init();
if (ide_enable[3])
ide_qua_init();
ide_reset_hard();
/* Now, add the tertiary and/or quaternary IDE controllers. */
if (ide_ter_enabled)
device_add(&ide_ter_device);
if (ide_qua_enabled)
device_add(&ide_qua_device);
}
@@ -185,6 +189,22 @@ hdc_get_internal_name(int hdc)
}
int
hdc_get_from_internal_name(char *s)
{
int c = 0;
while (strlen((char *) controllers[c].internal_name))
{
if (!strcmp((char *) controllers[c].internal_name, s))
return c;
c++;
}
return 0;
}
const device_t *
hdc_get_device(int hdc)
{
@@ -192,6 +212,19 @@ hdc_get_device(int hdc)
}
int
hdc_has_config(int hdc)
{
const device_t *dev = hdc_get_device(hdc);
if (dev == NULL) return(0);
if (dev->config == NULL) return(0);
return(1);
}
int
hdc_get_flags(int hdc)
{

View File

@@ -8,7 +8,7 @@
*
* Definitions for the common disk controller handler.
*
* Version: @(#)hdc.h 1.0.7 2018/03/19
* Version: @(#)hdc.h 1.0.8 2018/04/05
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -22,7 +22,7 @@
#define MFM_NUM 2 /* 2 drives per controller supported */
#define ESDI_NUM 2 /* 2 drives per controller supported */
#define XTIDE_NUM 2 /* 2 drives per controller supported */
#define XTA_NUM 2 /* 2 drives per controller supported */
#define IDE_NUM 8
#define SCSI_NUM 16 /* theoretically the controller can have at
* least 7 devices, with each device being
@@ -47,6 +47,12 @@ extern const device_t ide_vlb_2ch_device; /* vlb_ide_2ch */
extern const device_t ide_pci_device; /* pci_ide */
extern const device_t ide_pci_2ch_device; /* pci_ide_2ch */
extern const device_t ide_ter_device;
extern const device_t ide_qua_device;
extern const device_t xta_wdxt150_device; /* xta_wdxt150 */
extern const device_t xta_hd20_device; /* EuroPC internal */
extern const device_t xtide_device; /* xtide_xt */
extern const device_t xtide_at_device; /* xtide_at */
extern const device_t xtide_acculogic_device; /* xtide_ps2 */
@@ -58,6 +64,8 @@ extern void hdc_reset(void);
extern char *hdc_get_name(int hdc);
extern char *hdc_get_internal_name(int hdc);
extern int hdc_get_from_internal_name(char *s);
extern int hdc_has_config(int hdc);
extern const device_t *hdc_get_device(int hdc);
extern int hdc_get_flags(int hdc);
extern int hdc_available(int hdc);

View File

@@ -8,7 +8,7 @@
*
* Driver for the ESDI controller (WD1007-vse1) for PC/AT.
*
* Version: @(#)hdc_esdi_at.c 1.0.9 2018/03/18
* Version: @(#)hdc_esdi_at.c 1.0.10 2018/04/17
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -104,35 +104,28 @@ typedef struct {
} esdi_t;
static __inline void irq_raise(esdi_t *esdi)
static inline void
irq_raise(esdi_t *esdi)
{
/* If not already pending.. */
if (! esdi->irqstat) {
/* If enabled in the control register.. */
if (! (esdi->fdisk & 0x02)) {
/* .. raise IRQ14. */
picint(1<<14);
}
if (!(esdi->fdisk&2))
picint(1 << 14);
/* Remember this. */
esdi->irqstat = 1;
}
esdi->irqstat=1;
}
static __inline void irq_lower(esdi_t *esdi)
static inline void
irq_lower(esdi_t *esdi)
{
/* If raised.. */
if (esdi->irqstat) {
/* If enabled in the control register.. */
if (! (esdi->fdisk & 0x02)) {
/* .. drop IRQ14. */
picintc(1<<14);
}
picintc(1 << 14);
}
/* Remember this. */
esdi->irqstat = 0;
}
static void
irq_update(esdi_t *esdi)
{
if (esdi->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(esdi->fdisk & 2))
picint(1 << 14);
}
@@ -384,6 +377,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
esdi->status = STAT_BUSY;
}
esdi->fdisk = val;
irq_update(esdi);
break;
}
}

View File

@@ -52,7 +52,7 @@
* however, are auto-configured by the system software as
* shown above.
*
* Version: @(#)hdc_esdi_mca.c 1.0.9 2018/03/18
* Version: @(#)hdc_esdi_mca.c 1.0.11 2018/04/17
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -101,8 +101,6 @@ typedef struct esdi_drive {
} drive_t;
typedef struct esdi {
uint16_t base;
int8_t irq;
int8_t dma;
uint32_t bios;
@@ -190,6 +188,7 @@ typedef struct esdi {
#define CMD_GET_POS_INFO 0x0a
#define STATUS_LEN(x) ((x) << 8)
#define STATUS_DEVICE(x) ((x) << 5)
#define STATUS_DEVICE_HOST_ADAPTER (7 << 5)
@@ -197,14 +196,14 @@ static __inline void
set_irq(esdi_t *dev)
{
if (dev->basic_ctrl & CTRL_IRQ_ENA)
picint(1 << dev->irq);
picint(1 << 14);
}
static __inline void
clear_irq(esdi_t *dev)
{
picintc(1 << dev->irq);
picintc(1 << 14);
}
@@ -250,23 +249,42 @@ device_not_present(esdi_t *dev)
set_irq(dev);
}
static void rba_out_of_range(esdi_t *dev)
{
dev->status_len = 9;
dev->status_data[0] = dev->command | STATUS_LEN(9) | dev->cmd_dev;
dev->status_data[1] = 0x0e01; /*Command block error, invalid parameter*/
dev->status_data[2] = 0x0007; /*RBA out of range*/
dev->status_data[3] = 0;
dev->status_data[4] = 0;
dev->status_data[5] = 0;
dev->status_data[6] = 0;
dev->status_data[7] = 0;
dev->status_data[8] = 0;
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE;
dev->irq_in_progress = 1;
set_irq(dev);
static void
rba_out_of_range(esdi_t *dev)
{
dev->status_len = 9;
dev->status_data[0] = dev->command | STATUS_LEN(9) | dev->cmd_dev;
dev->status_data[1] = 0x0e01; /*Command block error, invalid parameter*/
dev->status_data[2] = 0x0007; /*RBA out of range*/
dev->status_data[3] = 0;
dev->status_data[4] = 0;
dev->status_data[5] = 0;
dev->status_data[6] = 0;
dev->status_data[7] = 0;
dev->status_data[8] = 0;
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE;
dev->irq_in_progress = 1;
set_irq(dev);
}
static void
complete_command_status(esdi_t *dev)
{
dev->status_len = 7;
if (dev->cmd_dev == ATTN_DEVICE_0)
dev->status_data[0] = CMD_READ | STATUS_LEN(7) | STATUS_DEVICE(0);
else
dev->status_data[0] = CMD_READ | STATUS_LEN(7) | STATUS_DEVICE(1);
dev->status_data[1] = 0x0000; /*Error bits*/
dev->status_data[2] = 0x1900; /*Device status*/
dev->status_data[3] = 0; /*Number of blocks left to do*/
dev->status_data[4] = (dev->rba-1) & 0xffff; /*Last RBA processed*/
dev->status_data[5] = (dev->rba-1) >> 8;
dev->status_data[6] = 0; /*Number of blocks requiring error recovery*/
}
#define ESDI_ADAPTER_ONLY() do \
@@ -377,7 +395,8 @@ esdi_callback(void *priv)
break;
case 2:
dev->status = STATUS_IRQ;
complete_command_status(dev);
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
@@ -438,11 +457,11 @@ esdi_callback(void *priv)
hdd_image_write(drive->hdd_num, dev->rba, 1, (uint8_t *)dev->data);
dev->rba++;
dev->sector_pos++;
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1);
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI,
dev->cmd_dev == ATTN_DEVICE_0 ? 0 : 1);
dev->data_pos = 0;
}
ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0);
dev->status = STATUS_CMD_IN_PROGRESS;
dev->cmd_state = 2;
@@ -450,7 +469,8 @@ esdi_callback(void *priv)
break;
case 2:
dev->status = STATUS_IRQ;
complete_command_status(dev);
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
@@ -471,7 +491,9 @@ esdi_callback(void *priv)
return;
}
dev->status = STATUS_IRQ;
dev->rba += dev->sector_count;
complete_command_status(dev);
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
@@ -485,7 +507,8 @@ esdi_callback(void *priv)
return;
}
dev->status = STATUS_IRQ;
complete_command_status(dev);
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS;
dev->irq_in_progress = 1;
set_irq(dev);
@@ -499,8 +522,6 @@ esdi_callback(void *priv)
return;
}
if (dev->status_pos)
fatal("Status send in progress\n");
if ((dev->status & STATUS_IRQ) || dev->irq_in_progress)
fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress);
@@ -529,8 +550,6 @@ esdi_callback(void *priv)
return;
}
if (dev->status_pos)
fatal("Status send in progress\n");
if ((dev->status & STATUS_IRQ) || dev->irq_in_progress)
fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress);
@@ -557,8 +576,7 @@ esdi_callback(void *priv)
case CMD_GET_POS_INFO:
ESDI_ADAPTER_ONLY();
if (dev->status_pos)
fatal("Status send in progress\n");
if ((dev->status & STATUS_IRQ) || dev->irq_in_progress)
fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress);
@@ -567,8 +585,8 @@ esdi_callback(void *priv)
dev->status_data[1] = 0xffdd; /*MCA ID*/
dev->status_data[2] = dev->pos_regs[3] |
(dev->pos_regs[2] << 8);
dev->status_data[3] = 0xffff;
dev->status_data[4] = 0xffff;
dev->status_data[3] = 0xff;
dev->status_data[4] = 0xff;
dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL;
dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS;
@@ -688,8 +706,6 @@ esdi_callback(void *priv)
case 0x12:
ESDI_ADAPTER_ONLY();
if (dev->status_pos)
fatal("Status send in progress\n");
if ((dev->status & STATUS_IRQ) || dev->irq_in_progress)
fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress);
@@ -715,7 +731,7 @@ esdi_read(uint16_t port, void *priv)
esdi_t *dev = (esdi_t *)priv;
uint8_t ret = 0xff;
switch (port-dev->base) {
switch (port & 7) {
case 2: /*Basic status register*/
ret = dev->status;
break;
@@ -739,9 +755,9 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
esdi_t *dev = (esdi_t *)priv;
#if 0
pclog("ESDI: wr(%04x, %02x)\n", port-dev->base, val);
pclog("ESDI: wr(%04x, %02x)\n", port & 7, val);
#endif
switch (port-dev->base) {
switch (port & 7) {
case 2: /*Basic control register*/
if ((dev->basic_ctrl & CTRL_RESET) && !(val & CTRL_RESET)) {
dev->in_reset = 1;
@@ -751,7 +767,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
dev->basic_ctrl = val;
if (! (dev->basic_ctrl & CTRL_IRQ_ENA))
picintc(1 << dev->irq);
picintc(1 << 14);
break;
case 3: /*Attention register*/
@@ -765,6 +781,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
dev->cmd_dev = ATTN_HOST_ADAPTER;
dev->status |= STATUS_BUSY;
dev->cmd_pos = 0;
dev->status_pos = 0;
break;
case ATTN_EOI:
@@ -793,6 +810,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
dev->cmd_dev = ATTN_DEVICE_0;
dev->status |= STATUS_BUSY;
dev->cmd_pos = 0;
dev->status_pos = 0;
break;
case ATTN_EOI:
@@ -815,6 +833,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv)
dev->cmd_dev = ATTN_DEVICE_1;
dev->status |= STATUS_BUSY;
dev->cmd_pos = 0;
dev->status_pos = 0;
break;
case ATTN_EOI:
@@ -845,12 +864,11 @@ esdi_readw(uint16_t port, void *priv)
esdi_t *dev = (esdi_t *)priv;
uint16_t ret = 0xffff;
switch (port-dev->base) {
switch (port & 7) {
case 0: /*Status Interface Register*/
if (dev->status_pos >= dev->status_len)
return(0);
ret = dev->status_data[dev->status_pos++];
if (dev->status_pos >= dev->status_len) {
ret = dev->status_data[dev->status_pos++]; if (dev->status_pos >= dev->status_len) {
dev->status &= ~STATUS_STATUS_OUT_FULL;
dev->status_pos = dev->status_len = 0;
}
@@ -870,9 +888,9 @@ esdi_writew(uint16_t port, uint16_t val, void *priv)
esdi_t *dev = (esdi_t *)priv;
#if 0
pclog("ESDI: wrw(%04x, %04x)\n", port-dev->base, val);
pclog("ESDI: wrw(%04x, %04x)\n", port & 7, val);
#endif
switch (port-dev->base) {
switch (port & 7) {
case 0: /*Command Interface Register*/
if (dev->cmd_pos >= 4)
fatal("CIR pos 4\n");
@@ -919,123 +937,55 @@ esdi_mca_write(int port, uint8_t val, void *priv)
pclog("ESDI: mcawr(%04x, %02x) pos[2]=%02x pos[3]=%02x\n",
port, val, dev->pos_regs[2], dev->pos_regs[3]);
#endif
if (port < 0x102) return;
/*
* The PS/2 Model 80 BIOS always enables a card if it finds one,
* even if no resources were assigned yet (because we only added
* the card, but have not run AutoConfig yet...)
*
* So, remove current address, if any.
*
* Note by Kotori: Moved this to the beginning of esdi_mca_write,
* so the *old* base is removed rather than the
* new base.
*/
io_removehandler(dev->base, 8,
esdi_read, esdi_readw, NULL,
esdi_write, esdi_writew, NULL, dev);
mem_mapping_disable(&dev->bios_rom.mapping);
if (port < 0x102)
return;
/* Save the new value. */
dev->pos_regs[port & 7] = val;
/* Extract the new I/O base. */
switch(dev->pos_regs[2] & 0x02) {
case 0x00: /* PRIMARY [0]=XXxx xx0X 0x3510 */
dev->base = ESDI_IOADDR_PRI;
break;
io_removehandler(ESDI_IOADDR_PRI, 8,
esdi_read, esdi_readw, NULL,
esdi_write, esdi_writew, NULL, dev);
mem_mapping_disable(&dev->bios_rom.mapping);
case 0x02: /* SECONDARY [0]=XXxx xx1X 0x3518 */
dev->base = ESDI_IOADDR_SEC;
break;
}
/* Extract the new DMA channel. */
switch(dev->pos_regs[2] & 0x3c) {
case 0x14: /* DMA 5 [0]=XX01 01XX */
case 0x14:
dev->dma = 5;
break;
case 0x18: /* DMA 6 [0]=XX01 10XX */
case 0x18:
dev->dma = 6;
break;
case 0x1c: /* DMA 7 [0]=XX01 11XX */
case 0x1c:
dev->dma = 7;
break;
case 0x00: /* DMA 0 [0]=XX00 00XX */
case 0x00:
dev->dma = 0;
break;
case 0x01: /* DMA 1 [0]=XX00 01XX */
case 0x04:
dev->dma = 1;
break;
case 0x04: /* DMA 3 [0]=XX00 11XX */
case 0x0c:
dev->dma = 3;
break;
case 0x10: /* DMA 4 [0]=XX01 00XX */
case 0x10:
dev->dma = 4;
break;
}
/* Extract the new BIOS address. */
if (! (dev->pos_regs[3] & 0x08)) switch(dev->pos_regs[3] & 0x0f) {
case 0: /* ROM C000 [1]=XXXX 0000 */
dev->bios = 0xC0000;
break;
case 1: /* ROM C400 [1]=XXXX 0001 */
dev->bios = 0xC4000;
break;
case 2: /* ROM C800 [1]=XXXX 0010 */
dev->bios = 0xC8000;
break;
case 3: /* ROM CC00 [1]=XXXX 0011 */
dev->bios = 0xCC000;
break;
case 4: /* ROM D000 [1]=XXXX 0100 */
dev->bios = 0xD0000;
break;
case 5: /* ROM D400 [1]=XXXX 0101 */
dev->bios = 0xD4000;
break;
case 6: /* ROM D800 [1]=XXXX 0110 */
dev->bios = 0xD8000;
break;
case 7: /* ROM DC00 [1]=XXXX 0111 */
dev->bios = 0xDC000;
break;
} else {
/* BIOS ROM disabled. */
dev->bios = 0x000000;
}
if (dev->pos_regs[2] & 0x01) {
/* Card enabled; register (new) I/O handler. */
io_sethandler(dev->base, 8,
if (dev->pos_regs[2] & 1) {
io_sethandler(ESDI_IOADDR_PRI, 8,
esdi_read, esdi_readw, NULL,
esdi_write, esdi_writew, NULL, dev);
/* Enable or disable the BIOS ROM. */
if (dev->bios != 0x000000) {
if (!(dev->pos_regs[3] & 8)) {
mem_mapping_enable(&dev->bios_rom.mapping);
mem_mapping_set_addr(&dev->bios_rom.mapping,
dev->bios, 0x4000);
((dev->pos_regs[3] & 7) * 0x4000) + 0xc0000, 0x4000);
}
/* Say hello. */
pclog("ESDI: I/O=%04x, IRQ=%d, DMA=%d, BIOS @%05X\n",
dev->base, dev->irq, dev->dma, dev->bios);
pclog("ESDI: I/O=3510, IRQ=14, DMA=%d, BIOS @%05X\n",
dev->dma, dev->bios);
}
}
@@ -1054,9 +1004,6 @@ esdi_init(const device_t *info)
/* Mark as unconfigured. */
dev->irq_status = 0xff;
/* This is hardwired. */
dev->irq = ESDI_IRQCHAN;
rom_init_interleaved(&dev->bios_rom,
BIOS_FILE_H, BIOS_FILE_L,
0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
@@ -1080,7 +1027,7 @@ esdi_init(const device_t *info)
drive->spt = hdd[i].spt;
drive->hpc = hdd[i].hpc;
drive->tracks = hdd[i].tracks;
drive->sectors = hdd[i].spt*hdd[i].hpc*hdd[i].tracks;
drive->sectors = hdd_image_get_last_sector(i) + 1;
drive->hdd_num = i;
/* Mark drive as present. */

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
* Implementation of the IDE emulation for hard disks and ATAPI
* CD-ROM devices.
*
* Version: @(#)hdd_ide.h 1.0.8 2018/03/20
* Version: @(#)hdd_ide.h 1.0.9 2018/03/26
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -21,59 +21,53 @@
typedef struct {
int type;
int board;
uint8_t atastat;
uint8_t error;
int secount,sector,cylinder,head,drive,cylprecomp;
uint8_t command;
uint8_t fdisk;
int pos;
int packlen;
int spt,hpc;
int t_spt,t_hpc;
int tracks;
int packetstatus;
uint8_t asc;
int reset;
uint8_t atastat, error,
command, fdisk;
int type, board,
irqstat, service,
blocksize, blockcount,
hdd_num, channel,
pos, sector_pos,
lba, skip512,
reset, specify_success,
mdma_mode, do_initial_read,
spt, hpc,
tracks;
uint32_t secount, sector,
cylinder, head,
drive, cylprecomp,
t_spt, t_hpc,
lba_addr;
uint16_t *buffer;
int irqstat;
int service;
int lba;
int channel;
uint32_t lba_addr;
int skip512;
int blocksize, blockcount;
uint16_t dma_identify_data[3];
int hdi,base;
int hdd_num;
uint8_t specify_success;
int mdma_mode;
uint8_t *sector_buffer;
int do_initial_read;
int sector_pos;
} IDE;
} ide_t;
extern int ideboard;
extern int ide_ter_enabled, ide_qua_enabled;
extern int ide_enable[5];
extern int ide_irq[5];
extern IDE ide_drives[IDE_NUM + XTIDE_NUM];
extern ide_t *ide_drives[IDE_NUM];
extern int64_t idecallback[5];
extern void ide_irq_raise(IDE *ide);
extern void ide_irq_lower(IDE *ide);
extern void ide_irq_raise(ide_t *ide);
extern void ide_irq_lower(ide_t *ide);
extern void writeide(int ide_board, uint16_t addr, uint8_t val);
extern void writeidew(int ide_board, uint16_t val);
extern uint8_t readide(int ide_board, uint16_t addr);
extern uint16_t readidew(int ide_board);
extern void callbackide(int ide_board);
extern void * ide_xtide_init(void);
extern void ide_xtide_close(void);
extern void ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length), int (*write)(int channel, uint8_t *data, int transfer_length), void (*set_irq)(int channel));
extern void ide_writew(uint16_t addr, uint16_t val, void *priv);
extern void ide_write_devctl(uint16_t addr, uint8_t val, void *priv);
extern void ide_writeb(uint16_t addr, uint8_t val, void *priv);
extern uint8_t ide_readb(uint16_t addr, void *priv);
extern uint8_t ide_read_alt_status(uint16_t addr, void *priv);
extern uint16_t ide_readw(uint16_t addr, void *priv);
extern void ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length, void *priv),
int (*write)(int channel, uint8_t *data, int transfer_length, void *priv),
void (*set_irq)(int channel, void *priv),
void *priv0, void *priv1);
extern void win_cdrom_eject(uint8_t id);
extern void win_cdrom_reload(uint8_t id);
@@ -81,36 +75,20 @@ extern void win_cdrom_reload(uint8_t id);
extern void ide_set_base(int controller, uint16_t port);
extern void ide_set_side(int controller, uint16_t port);
extern void ide_init_first(void);
extern void ide_reset(void);
extern void ide_reset_hard(void);
extern void ide_set_all_signatures(void);
extern void ide_xtide_init(void);
extern void ide_pri_enable(void);
extern void ide_pri_enable_ex(void);
extern void ide_pri_disable(void);
extern void ide_sec_enable(void);
extern void ide_sec_disable(void);
extern void ide_ter_enable(void);
extern void ide_ter_disable(void);
extern void ide_ter_init(void);
extern void ide_qua_enable(void);
extern void ide_qua_disable(void);
extern void ide_qua_init(void);
extern void ide_set_callback(uint8_t channel, int64_t callback);
extern void secondary_ide_check(void);
extern void ide_padstr8(uint8_t *buf, int buf_size, const char *src);
extern void ide_destroy_buffers(void);
extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length);
extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length);
extern void (*ide_bus_master_set_irq)(int channel);
extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv);
extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv);
extern void (*ide_bus_master_set_irq)(int channel, void *priv);
extern void *ide_bus_master_priv[2];
#endif /*EMU_IDE_H*/

View File

@@ -12,7 +12,7 @@
* based design. Most cards were WD1003-WA2 or -WAH, where the
* -WA2 cards had a floppy controller as well (to save space.)
*
* Version: @(#)hdc_mfm_at.c 1.0.13 2018/03/18
* Version: @(#)hdc_mfm_at.c 1.0.14 2018/04/16
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -110,35 +110,28 @@ typedef struct {
} mfm_t;
static __inline void irq_raise(mfm_t *mfm)
static inline void
irq_raise(mfm_t *mfm)
{
/* If not already pending.. */
if (! mfm->irqstat) {
/* If enabled in the control register.. */
if (! (mfm->fdisk&0x02)) {
/* .. raise IRQ14. */
picint(1<<14);
}
if (!(mfm->fdisk&2))
picint(1 << 14);
/* Remember this. */
mfm->irqstat = 1;
}
mfm->irqstat=1;
}
static __inline void irq_lower(mfm_t *mfm)
static inline void
irq_lower(mfm_t *mfm)
{
/* If raised.. */
if (mfm->irqstat) {
/* If enabled in the control register.. */
if (! (mfm->fdisk&0x02)) {
/* .. drop IRQ14. */
picintc(1<<14);
}
picintc(1 << 14);
}
/* Remember this. */
mfm->irqstat = 0;
}
static void
irq_update(mfm_t *mfm)
{
if (mfm->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(mfm->fdisk & 2))
picint(1 << 14);
}
@@ -233,6 +226,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
}
irq_lower(mfm);
mfm->command = val;
mfm->error = 0;
switch (val & 0xf0) {
@@ -244,13 +238,13 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
#endif
drive->curcyl = 0;
mfm->status = STAT_READY|STAT_DSC;
mfm->command = 0x00;
mfm->command &= 0xf0;
irq_raise(mfm);
break;
case CMD_SEEK:
drive->steprate = (val & 0x0f);
mfm->command = (val & 0xf0);
mfm->command &= 0xf0;
mfm->status = STAT_BUSY;
timer_clock();
mfm->callback = 200LL*MFM_TIME;
@@ -258,6 +252,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
break;
default:
mfm->command = val;
switch (val) {
case CMD_READ:
case CMD_READ+1:
@@ -267,7 +262,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
pclog("WD1003(%d) read, opt=%d\n",
mfm->drvsel, val&0x03);
#endif
mfm->command = (val & 0xf0);
mfm->command &= 0xfc;
if (val & 2)
fatal("WD1003: READ with ECC\n");
mfm->status = STAT_BUSY;
@@ -284,7 +279,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
pclog("WD1003(%d) write, opt=%d\n",
mfm->drvsel, val & 0x03);
#endif
mfm->command = (val & 0xf0);
mfm->command &= 0xfc;
if (val & 2)
fatal("WD1003: WRITE with ECC\n");
mfm->status = STAT_DRQ|STAT_DSC;
@@ -293,7 +288,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
case CMD_VERIFY:
case CMD_VERIFY+1:
mfm->command = (val & 0xfe);
mfm->command &= 0xfe;
mfm->status = STAT_BUSY;
timer_clock();
mfm->callback = 200LL*MFM_TIME;
@@ -301,13 +296,11 @@ mfm_cmd(mfm_t *mfm, uint8_t val)
break;
case CMD_FORMAT:
mfm->command = val;
mfm->status = STAT_DRQ|STAT_BUSY;
mfm->pos = 0;
break;
case CMD_DIAGNOSE:
mfm->command = val;
mfm->status = STAT_BUSY;
timer_clock();
mfm->callback = 200LL*MFM_TIME;
@@ -417,7 +410,7 @@ mfm_write(uint16_t port, uint8_t val, void *priv)
mfm->drvsel = (val & 0x10) ? 1 : 0;
if (mfm->drives[mfm->drvsel].present)
mfm->status = STAT_READY|STAT_DSC;
else
else
mfm->status = 0;
return;
@@ -428,21 +421,22 @@ mfm_write(uint16_t port, uint8_t val, void *priv)
case 0x03f6: /* device control */
val &= 0x0f;
if ((mfm->fdisk & 0x04) && !(val & 0x04)) {
mfm->status = STAT_BUSY;
mfm->reset = 1;
timer_clock();
mfm->callback = 500LL*MFM_TIME;
timer_update_outstanding();
mfm->reset = 1;
mfm->status = STAT_BUSY;
}
if (val & 0x04) {
/* Drive held in reset. */
mfm->status = STAT_BUSY;
mfm->callback = 0LL;
timer_clock();
mfm->callback = 0LL;
timer_update_outstanding();
mfm->status = STAT_BUSY;
}
mfm->fdisk = val;
irq_update(mfm);
break;
}
}
@@ -619,19 +613,18 @@ do_callback(void *priv)
}
hdd_image_write(drive->hdd_num, addr, 1,(uint8_t *)mfm->buffer);
irq_raise(mfm);
mfm->secount = (mfm->secount - 1) & 0xff;
mfm->status = STAT_READY|STAT_DSC;
mfm->secount = (mfm->secount - 1) & 0xff;
if (mfm->secount) {
/* More sectors to do.. */
mfm->status |= STAT_DRQ;
mfm->pos = 0;
next_sector(mfm);
ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1);
} else {
} else
ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0);
}
irq_raise(mfm);
break;
case CMD_VERIFY:

View File

@@ -41,7 +41,7 @@
* Since all controllers (including the ones made by DTC) use
* (mostly) the same API, we keep them all in this module.
*
* Version: @(#)hdc_mfm_xt.c 1.0.14 2018/03/18
* Version: @(#)hdc_mfm_xt.c 1.0.15 2018/04/18
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -71,7 +71,8 @@
#include "hdd.h"
#define MFM_TIME (2000LL*TIMER_USEC)
// #define MFM_TIME (2000LL*TIMER_USEC)
#define MFM_TIME (50LL*TIMER_USEC)
#define XEBEC_BIOS_FILE L"roms/hdd/mfm_xebec/ibm_xebec_62x0822_1985.bin"
#define DTC_BIOS_FILE L"roms/hdd/mfm_xebec/dtc_cxd21a.bin"
@@ -429,7 +430,7 @@ mfm_callback(void *priv)
}
hdd_image_zero(drive->hdd_num, addr, 17);
mfm_complete(mfm);
break;
@@ -757,7 +758,7 @@ loadhd(mfm_t *mfm, int c, int d, const wchar_t *fn)
{
drive_t *drive = &mfm->drives[d];
if (! hdd_image_load(d)) {
if (! hdd_image_load(c)) {
drive->present = 0;
return;
}
@@ -859,7 +860,7 @@ mfm_close(void *priv)
static int
xebec_available(void)
{
return(rom_present(XEBEC_BIOS_FILE));
return(rom_present(XEBEC_BIOS_FILE));
}
@@ -884,7 +885,7 @@ dtc5150x_init(const device_t *info)
pclog("MFM: looking for disks..\n");
for (i=0; i<HDD_NUM; i++) {
if ((hdd[i].bus == HDD_BUS_MFM) && (hdd[i].mfm_channel < MFM_NUM)) {
pclog("Found MFM hard disk on channel %i\n", hdd[i].mfm_channel);
pclog("Found MFM hard disk on channel %i (%ls)\n", hdd[i].mfm_channel, hdd[i].fn);
loadhd(dtc, i, hdd[i].mfm_channel, hdd[i].fn);
if (++c > MFM_NUM) break;

1200
src/disk/hdc_xta.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@
* already on their way out, the newer IDE standard based on the
* PC/AT controller and 16b design became the IDE we now know.
*
* Version: @(#)hdc_xtide.c 1.0.11 2018/03/18
* Version: @(#)hdc_xtide.c 1.0.12 2018/04/05
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -52,6 +52,7 @@
typedef struct {
void *ide_board;
uint8_t data_high;
rom_t bios_rom;
} xtide_t;
@@ -64,7 +65,7 @@ xtide_write(uint16_t port, uint8_t val, void *priv)
switch (port & 0xf) {
case 0x0:
writeidew(4, val | (xtide->data_high << 8));
ide_writew(0x0, val | (xtide->data_high << 8), xtide->ide_board);
return;
case 0x1:
@@ -74,7 +75,7 @@ xtide_write(uint16_t port, uint8_t val, void *priv)
case 0x5:
case 0x6:
case 0x7:
writeide(4, (port & 0xf) | 0x1f0, val);
ide_writeb((port & 0xf), val, xtide->ide_board);
return;
case 0x8:
@@ -82,7 +83,7 @@ xtide_write(uint16_t port, uint8_t val, void *priv)
return;
case 0xe:
writeide(4, 0x3f6, val);
ide_write_devctl(0x0, val, xtide->ide_board);
return;
}
}
@@ -96,7 +97,7 @@ xtide_read(uint16_t port, void *priv)
switch (port & 0xf) {
case 0x0:
tempw = readidew(4);
tempw = ide_readw(0x0, xtide->ide_board);
xtide->data_high = tempw >> 8;
break;
@@ -107,7 +108,7 @@ xtide_read(uint16_t port, void *priv)
case 0x5:
case 0x6:
case 0x7:
tempw = readide(4, (port & 0xf) | 0x1f0);
tempw = ide_readb((port & 0xf), xtide->ide_board);
break;
case 0x8:
@@ -115,7 +116,7 @@ xtide_read(uint16_t port, void *priv)
break;
case 0xe:
tempw = readide(4, 0x3f6);
tempw = ide_read_alt_status(0x0, xtide->ide_board);
break;
default:
@@ -136,7 +137,7 @@ xtide_init(const device_t *info)
rom_init(&xtide->bios_rom, ROM_PATH_XT,
0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
ide_xtide_init();
xtide->ide_board = ide_xtide_init();
io_sethandler(0x0300, 16,
xtide_read, NULL, NULL,
@@ -186,7 +187,7 @@ xtide_acculogic_init(const device_t *info)
rom_init(&xtide->bios_rom, ROM_PATH_PS2,
0xc8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
ide_xtide_init();
xtide->ide_board = ide_xtide_init();
io_sethandler(0x0360, 16,
xtide_read, NULL, NULL,
@@ -203,6 +204,17 @@ xtide_acculogic_available(void)
}
static void
xtide_close(void *priv)
{
xtide_t *xtide = (xtide_t *)priv;
free(xtide);
ide_xtide_close();
}
static void *
xtide_at_ps2_init(const device_t *info)
{
@@ -227,7 +239,7 @@ xtide_at_ps2_available(void)
static void
xtide_close(void *priv)
xtide_at_close(void *priv)
{
xtide_t *xtide = (xtide_t *)priv;
@@ -248,7 +260,7 @@ const device_t xtide_at_device = {
"XTIDE (AT)",
DEVICE_ISA | DEVICE_AT,
0,
xtide_at_init, xtide_close, NULL,
xtide_at_init, xtide_at_close, NULL,
xtide_at_available, NULL, NULL, NULL,
NULL
};
@@ -266,7 +278,7 @@ const device_t xtide_at_ps2_device = {
"XTIDE (AT) (1.1.5)",
DEVICE_ISA | DEVICE_PS2,
0,
xtide_at_ps2_init, xtide_close, NULL,
xtide_at_ps2_init, xtide_at_close, NULL,
xtide_at_ps2_available, NULL, NULL, NULL,
NULL
};

View File

@@ -8,13 +8,13 @@
*
* Common code to handle all sorts of hard disk images.
*
* Version: @(#)hdd.c 1.0.7 2017/11/18
* Version: @(#)hdd.c 1.0.8 2018/04/24
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2016,2017 Miran Grca.
* Copyright 2017 Fred N. van Kempen.
* Copyright 2016-2018 Miran Grca.
* Copyright 2017,2018 Fred N. van Kempen.
*/
#include <stdio.h>
#include <stdint.h>
@@ -63,53 +63,35 @@ no_cdrom:
}
if (! strcmp(str, "ide_pio_only"))
return(HDD_BUS_IDE_PIO_ONLY);
return(HDD_BUS_IDE);
if (! strcmp(str, "ide"))
return(HDD_BUS_IDE_PIO_ONLY);
return(HDD_BUS_IDE);
if (! strcmp(str, "atapi_pio_only"))
return(HDD_BUS_IDE_PIO_ONLY);
return(HDD_BUS_IDE);
if (! strcmp(str, "atapi"))
return(HDD_BUS_IDE_PIO_ONLY);
return(HDD_BUS_IDE);
if (! strcmp(str, "eide"))
return(HDD_BUS_IDE_PIO_ONLY);
return(HDD_BUS_IDE);
if (! strcmp(str, "xtide"))
return(HDD_BUS_XTIDE);
if (! strcmp(str, "xta"))
return(HDD_BUS_XTA);
if (! strcmp(str, "atide"))
return(HDD_BUS_IDE_PIO_ONLY);
return(HDD_BUS_IDE);
if (! strcmp(str, "ide_pio_and_dma"))
return(HDD_BUS_IDE_PIO_AND_DMA);
return(HDD_BUS_IDE);
if (! strcmp(str, "atapi_pio_and_dma"))
return(HDD_BUS_IDE_PIO_AND_DMA);
return(HDD_BUS_IDE);
if (! strcmp(str, "scsi"))
return(HDD_BUS_SCSI);
if (! strcmp(str, "removable")) {
if (cdrom) goto no_cdrom;
return(HDD_BUS_SCSI_REMOVABLE);
}
if (! strcmp(str, "scsi_removable")) {
if (cdrom) goto no_cdrom;
return(HDD_BUS_SCSI_REMOVABLE);
}
if (! strcmp(str, "removable_scsi")) {
if (cdrom) goto no_cdrom;
return(HDD_BUS_SCSI_REMOVABLE);
}
if (! strcmp(str, "usb"))
ui_msgbox(MBX_ERROR, (wchar_t *)IDS_4110);
@@ -131,29 +113,21 @@ hdd_bus_to_string(int bus, int cdrom)
s = "mfm";
break;
case HDD_BUS_XTIDE:
s = "xtide";
case HDD_BUS_XTA:
s = "xta";
break;
case HDD_BUS_ESDI:
s = "esdi";
break;
case HDD_BUS_IDE_PIO_ONLY:
s = cdrom ? "atapi_pio_only" : "ide_pio_only";
break;
case HDD_BUS_IDE_PIO_AND_DMA:
s = cdrom ? "atapi_pio_and_dma" : "ide_pio_and_dma";
case HDD_BUS_IDE:
s = cdrom ? "atapi" : "ide";
break;
case HDD_BUS_SCSI:
s = "scsi";
break;
case HDD_BUS_SCSI_REMOVABLE:
s = "scsi_removable";
break;
}
return(s);
@@ -163,12 +137,14 @@ hdd_bus_to_string(int bus, int cdrom)
int
hdd_is_valid(int c)
{
if (hdd[c].bus == HDD_BUS_DISABLED) return(0);
if (hdd[c].bus == HDD_BUS_DISABLED)
return(0);
if ((wcslen(hdd[c].fn) == 0) &&
(hdd[c].bus != HDD_BUS_SCSI_REMOVABLE)) return(0);
if (wcslen(hdd[c].fn) == 0)
return(0);
if ((hdd[c].tracks==0) || (hdd[c].hpc==0) || (hdd[c].spt==0)) return(0);
if ((hdd[c].tracks==0) || (hdd[c].hpc==0) || (hdd[c].spt==0))
return(0);
return(1);
}

View File

@@ -8,12 +8,12 @@
*
* Definitions for the hard disk image handler.
*
* Version: @(#)hdd.h 1.0.3 2017/10/05
* Version: @(#)hdd.h 1.0.4 2018/03/29
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
* Copyright 2016,2017 Miran Grca.
* Copyright 2017 Fred N. van Kempen.
* Copyright 2016-2018 Miran Grca.
* Copyright 2017,2018 Fred N. van Kempen.
*/
#ifndef EMU_HDD_H
# define EMU_HDD_H
@@ -23,17 +23,53 @@
/* Hard Disk bus types. */
#if 0
/* Bit 4 = DMA supported (0 = no, 1 yes) - used for IDE and ATAPI only;
Bit 5 = Removable (0 = no, 1 yes). */
enum {
BUS_DISABLED = 0x00,
BUS_MFM = 0x01, /* These four are for hard disk only. */
BUS_XIDE = 0x02,
BUS_XTA = 0x03,
BUS_ESDI = 0x04,
BUS_PANASONIC = 0x21, / These four are for CD-ROM only. */
BUS_PHILIPS = 0x22,
BUS_SONY = 0x23,
BUS_MITSUMI = 0x24,
BUS_IDE_PIO_ONLY = 0x05,
BUS_IDE_PIO_AND_DMA = 0x15,
BUS_IDE_R_PIO_ONLY = 0x25,
BUS_IDE_R_PIO_AND_DMA = 0x35,
BUS_ATAPI_PIO_ONLY = 0x06,
BUS_ATAPI_PIO_AND_DMA = 0x16,
BUS_ATAPI_R_PIO_ONLY = 0x26,
BUS_ATAPI_R_PIO_AND_DMA = 0x36,
BUS_SASI = 0x07,
BUS_SASI_R = 0x27,
BUS_SCSI = 0x08,
BUS_SCSI_R = 0x28,
BUS_USB = 0x09,
BUS_USB_R = 0x29
};
#else
enum {
HDD_BUS_DISABLED = 0,
HDD_BUS_MFM,
HDD_BUS_XTIDE,
HDD_BUS_XTA,
HDD_BUS_ESDI,
HDD_BUS_IDE_PIO_ONLY,
HDD_BUS_IDE_PIO_AND_DMA,
HDD_BUS_IDE,
HDD_BUS_SCSI,
HDD_BUS_SCSI_REMOVABLE,
HDD_BUS_USB
};
#endif
/* Define the virtual Hard Disk. */
@@ -45,18 +81,16 @@ typedef struct {
uint8_t mfm_channel; /* should rename and/or unionize */
uint8_t esdi_channel;
uint8_t xtide_channel;
uint8_t xta_channel;
uint8_t ide_channel;
uint8_t scsi_id;
uint8_t scsi_lun;
uint32_t base;
uint64_t spt,
uint32_t base,
spt,
hpc, /* physical geometry parameters */
tracks;
uint64_t at_spt, /* [Translation] parameters */
tracks,
at_spt, /* [Translation] parameters */
at_hpc;
FILE *f; /* current file handle to image */
@@ -67,7 +101,7 @@ typedef struct {
extern hard_disk_t hdd[HDD_NUM];
extern uint64_t hdd_table[128][3];
extern unsigned int hdd_table[128][3];
extern int hdd_init(void);
@@ -75,6 +109,7 @@ extern int hdd_string_to_bus(char *str, int cdrom);
extern char *hdd_bus_to_string(int bus, int cdrom);
extern int hdd_is_valid(int c);
extern void hdd_image_init(void);
extern int hdd_image_load(int id);
extern void hdd_image_seek(uint8_t id, uint32_t sector);
extern void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer);

View File

@@ -8,7 +8,7 @@
*
* Handling of hard disk image files.
*
* Version: @(#)hdd_image.c 1.0.13 2018/03/19
* Version: @(#)hdd_image.c 1.0.14 2018/03/28
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -34,11 +34,11 @@
typedef struct
{
FILE *file;
uint32_t base;
uint32_t last_sector;
uint8_t type;
uint8_t loaded;
FILE *file;
uint32_t base;
uint32_t last_sector;
uint8_t type;
uint8_t loaded;
} hdd_image_t;
@@ -69,393 +69,442 @@ hdd_image_log(const char *fmt, ...)
}
int image_is_hdi(const wchar_t *s)
int
image_is_hdi(const wchar_t *s)
{
int len;
wchar_t ext[5] = { 0, 0, 0, 0, 0 };
char *ws = (char *) s;
len = wcslen(s);
if ((len < 4) || (s[0] == L'.'))
return 0;
memcpy(ext, ws + ((len - 4) << 1), 8);
if (! wcscasecmp(ext, L".HDI"))
return 1;
else
return 0;
int len;
wchar_t ext[5] = { 0, 0, 0, 0, 0 };
char *ws = (char *) s;
len = wcslen(s);
if ((len < 4) || (s[0] == L'.'))
return 0;
memcpy(ext, ws + ((len - 4) << 1), 8);
if (! wcscasecmp(ext, L".HDI"))
return 1;
else
return 0;
}
int
image_is_hdx(const wchar_t *s, int check_signature)
{
int len;
FILE *f;
uint64_t filelen;
uint64_t signature;
char *ws = (char *) s;
wchar_t ext[5] = { 0, 0, 0, 0, 0 };
len = wcslen(s);
if ((len < 4) || (s[0] == L'.'))
return 0;
memcpy(ext, ws + ((len - 4) << 1), 8);
if (wcscasecmp(ext, L".HDX") == 0) {
if (check_signature) {
f = plat_fopen((wchar_t *)s, L"rb");
if (!f)
return 0;
fseeko64(f, 0, SEEK_END);
filelen = ftello64(f);
fseeko64(f, 0, SEEK_SET);
if (filelen < 44)
return 0;
fread(&signature, 1, 8, f);
fclose(f);
if (signature == 0xD778A82044445459ll)
return 1;
return 0;
}
return 1;
}
int len;
FILE *f;
uint64_t filelen;
uint64_t signature;
char *ws = (char *) s;
wchar_t ext[5] = { 0, 0, 0, 0, 0 };
len = wcslen(s);
if ((len < 4) || (s[0] == L'.'))
return 0;
memcpy(ext, ws + ((len - 4) << 1), 8);
if (wcscasecmp(ext, L".HDX") == 0) {
if (check_signature) {
f = plat_fopen((wchar_t *)s, L"rb");
if (!f)
return 0;
fseeko64(f, 0, SEEK_END);
filelen = ftello64(f);
fseeko64(f, 0, SEEK_SET);
if (filelen < 44)
return 0;
fread(&signature, 1, 8, f);
fclose(f);
if (signature == 0xD778A82044445459ll)
return 1;
else
return 0;
} else
return 1;
} else
return 0;
}
int hdd_image_load(int id)
static int
prepare_new_hard_disk(uint8_t id, uint64_t full_size)
{
uint32_t sector_size = 512;
uint32_t zero = 0;
uint64_t signature = 0xD778A82044445459ll;
uint64_t full_size = 0;
uint64_t spt = 0, hpc = 0, tracks = 0;
int c;
uint64_t i = 0, s = 0, t = 0;
wchar_t *fn = hdd[id].fn;
int is_hdx[2] = { 0, 0 };
uint64_t target_size = (full_size + hdd_images[id].base) - ftello64(hdd_images[id].file);
memset(empty_sector, 0, sizeof(empty_sector));
uint32_t size;
uint32_t t, i;
hdd_images[id].base = 0;
t = (uint32_t) (target_size >> 20); /* Amount of 1 MB blocks. */
size = (uint32_t) (target_size & 0xfffff); /* 1 MB mask. */
if (hdd_images[id].loaded) {
if (hdd_images[id].file) {
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
}
hdd_images[id].loaded = 0;
empty_sector_1mb = (char *) malloc(1048576);
memset(empty_sector_1mb, 0, 1048576);
/* Temporarily switch off suppression of seen messages so that the
progress gets displayed. */
pclog_toggle_suppr();
pclog("Writing image sectors: [");
/* First, write all the 1 MB blocks. */
if (t > 0) {
for (i = 0; i < t; i++) {
fwrite(empty_sector_1mb, 1, 1045876, hdd_images[id].file);
pclog("#");
}
}
is_hdx[0] = image_is_hdx(fn, 0);
is_hdx[1] = image_is_hdx(fn, 1);
/* Then, write the remainder. */
fwrite(empty_sector_1mb, 1, size, hdd_images[id].file);
pclog("#]\n");
/* Switch the suppression of seen messages back on. */
pclog_toggle_suppr();
/* Try to open existing hard disk image */
if (fn[0] == '.') {
hdd_image_log("File name starts with .\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
free(empty_sector_1mb);
hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1;
hdd_images[id].loaded = 1;
return 1;
}
void
hdd_image_init(void)
{
int i;
for (i = 0; i < HDD_NUM; i++)
memset(&hdd_images[i], 0, sizeof(hdd_image_t));
}
int
hdd_image_load(int id)
{
uint32_t sector_size = 512;
uint32_t zero = 0;
uint64_t signature = 0xD778A82044445459ll;
uint64_t full_size = 0;
uint64_t spt = 0, hpc = 0, tracks = 0;
int c;
uint64_t s = 0;
wchar_t *fn = hdd[id].fn;
int is_hdx[2] = { 0, 0 };
memset(empty_sector, 0, sizeof(empty_sector));
hdd_images[id].base = 0;
if (hdd_images[id].loaded) {
if (hdd_images[id].file) {
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
}
hdd_images[id].file = plat_fopen(fn, L"rb+");
if (hdd_images[id].file == NULL) {
/* Failed to open existing hard disk image */
if (errno == ENOENT) {
/* Failed because it does not exist,
so try to create new file */
if (hdd[id].wp) {
hdd_image_log("A write-protected image must exist\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
hdd_images[id].loaded = 0;
}
hdd_images[id].file = plat_fopen(fn, L"wb+");
if (hdd_images[id].file == NULL) {
hdd_image_log("Unable to open image\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
} else {
if (image_is_hdi(fn)) {
full_size = hdd[id].spt * hdd[id].hpc * hdd[id].tracks * 512;
hdd_images[id].base = 0x1000;
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file);
fwrite(&full_size, 1, 4, hdd_images[id].file);
fwrite(&sector_size, 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file);
for (c = 0; c < 0x3f8; c++)
fwrite(&zero, 1, 4, hdd_images[id].file);
hdd_images[id].type = 1;
} else if (is_hdx[0]) {
full_size = hdd[id].spt * hdd[id].hpc * hdd[id].tracks * 512;
hdd_images[id].base = 0x28;
fwrite(&signature, 1, 8, hdd_images[id].file);
fwrite(&full_size, 1, 8, hdd_images[id].file);
fwrite(&sector_size, 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
hdd_images[id].type = 2;
}
else
hdd_images[id].type = 0;
hdd_images[id].last_sector = 0;
}
is_hdx[0] = image_is_hdx(fn, 0);
is_hdx[1] = image_is_hdx(fn, 1);
s = full_size = hdd[id].spt * hdd[id].hpc * hdd[id].tracks * 512;
goto prepare_new_hard_disk;
} else {
/* Failed for another reason */
hdd_image_log("Failed for another reason\n");
/* Try to open existing hard disk image */
if (fn[0] == '.') {
hdd_image_log("File name starts with .\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
hdd_images[id].file = plat_fopen(fn, L"rb+");
if (hdd_images[id].file == NULL) {
/* Failed to open existing hard disk image */
if (errno == ENOENT) {
/* Failed because it does not exist,
so try to create new file */
if (hdd[id].wp) {
hdd_image_log("A write-protected image must exist\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
} else {
if (image_is_hdi(fn)) {
fseeko64(hdd_images[id].file, 0x8, SEEK_SET);
fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file);
fseeko64(hdd_images[id].file, 0xC, SEEK_SET);
full_size = 0;
fread(&full_size, 1, 4, hdd_images[id].file);
fseeko64(hdd_images[id].file, 0x10, SEEK_SET);
fread(&sector_size, 1, 4, hdd_images[id].file);
if (sector_size != 512) {
/* Sector size is not 512 */
hdd_image_log("HDI: Sector size is not 512\n");
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
fread(&spt, 1, 4, hdd_images[id].file);
fread(&hpc, 1, 4, hdd_images[id].file);
fread(&tracks, 1, 4, hdd_images[id].file);
if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) {
if ((spt != hdd[id].spt) || (hpc != hdd[id].hpc) || (tracks != hdd[id].tracks)) {
hdd_image_log("HDI: Geometry mismatch\n");
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
}
hdd[id].spt = spt;
hdd[id].hpc = hpc;
hdd[id].tracks = tracks;
hdd_images[id].type = 1;
}
else if (is_hdx[1]) {
hdd_images[id].base = 0x28;
fseeko64(hdd_images[id].file, 8, SEEK_SET);
fread(&full_size, 1, 8, hdd_images[id].file);
fseeko64(hdd_images[id].file, 0x10, SEEK_SET);
fread(&sector_size, 1, 4, hdd_images[id].file);
if (sector_size != 512) {
/* Sector size is not 512 */
hdd_image_log("HDX: Sector size is not 512\n");
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
fread(&spt, 1, 4, hdd_images[id].file);
fread(&hpc, 1, 4, hdd_images[id].file);
fread(&tracks, 1, 4, hdd_images[id].file);
if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) {
if ((spt != hdd[id].spt) || (hpc != hdd[id].hpc) || (tracks != hdd[id].tracks)) {
hdd_image_log("HDX: Geometry mismatch\n");
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
}
hdd[id].spt = spt;
hdd[id].hpc = hpc;
hdd[id].tracks = tracks;
fread(&(hdd[id].at_spt), 1, 4, hdd_images[id].file);
fread(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file);
hdd_images[id].type = 2;
hdd_images[id].file = plat_fopen(fn, L"wb+");
if (hdd_images[id].file == NULL) {
hdd_image_log("Unable to open image\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
} else {
full_size = hdd[id].spt * hdd[id].hpc * hdd[id].tracks * 512;
hdd_images[id].type = 0;
}
}
fseeko64(hdd_images[id].file, 0, SEEK_END);
if (ftello64(hdd_images[id].file) < (full_size + hdd_images[id].base)) {
s = (full_size + hdd_images[id].base) - ftello64(hdd_images[id].file);
prepare_new_hard_disk:
t = s >> 20; /* Amount of 1 MB blocks. */
s &= 0xfffff; /* 1 MB mask. */
empty_sector_1mb = (char *) malloc(1048576);
memset(empty_sector_1mb, 0, 1048576);
/* Temporarily switch off suppression of seen messages so that the
progress gets displayed. */
pclog_toggle_suppr();
pclog("Writing image sectors: [");
/* First, write all the 1 MB blocks. */
if (t > 0) {
for (i = 0; i < t; i++) {
fwrite(empty_sector_1mb, 1, 1045876, hdd_images[id].file);
pclog("#");
if (image_is_hdi(fn)) {
full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
hdd_images[id].base = 0x1000;
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file);
fwrite(&full_size, 1, 4, hdd_images[id].file);
fwrite(&sector_size, 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file);
for (c = 0; c < 0x3f8; c++)
fwrite(&zero, 1, 4, hdd_images[id].file);
hdd_images[id].type = 1;
} else if (is_hdx[0]) {
full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
hdd_images[id].base = 0x28;
fwrite(&signature, 1, 8, hdd_images[id].file);
fwrite(&full_size, 1, 8, hdd_images[id].file);
fwrite(&sector_size, 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
hdd_images[id].type = 2;
}
else
hdd_images[id].type = 0;
hdd_images[id].last_sector = 0;
}
/* Then, write the remainder. */
fwrite(empty_sector_1mb, 1, s, hdd_images[id].file);
pclog("#]\n");
pclog_toggle_suppr();
s = full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
free(empty_sector_1mb);
return prepare_new_hard_disk(id, full_size);
} else {
/* Failed for another reason */
hdd_image_log("Failed for another reason\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1;
hdd_images[id].loaded = 1;
return 1;
}
void hdd_image_seek(uint8_t id, uint32_t sector)
{
off64_t addr = sector;
addr = (uint64_t)sector * 512;
fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET);
}
void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
{
fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET);
fread(buffer, 1, count * 512, hdd_images[id].file);
}
uint32_t hdd_sectors(uint8_t id)
{
fseeko64(hdd_images[id].file, 0, SEEK_END);
return (uint32_t) (ftello64(hdd_images[id].file) >> 9);
}
int hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
{
uint32_t transfer_sectors = count;
uint32_t sectors = hdd_sectors(id);
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET);
fread(buffer, 1, transfer_sectors * 512, hdd_images[id].file);
if (count != transfer_sectors)
return 1;
return 0;
}
void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
{
fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET);
fwrite(buffer, count * 512, 1, hdd_images[id].file);
}
int hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
{
uint32_t transfer_sectors = count;
uint32_t sectors = hdd_sectors(id);
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET);
fwrite(buffer, transfer_sectors * 512, 1, hdd_images[id].file);
if (count != transfer_sectors)
return 1;
return 0;
}
void hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count)
{
int i = 0;
fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET);
for (i = 0; i < count; i++)
fwrite(empty_sector, 512, 1, hdd_images[id].file);
}
int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count)
{
int i = 0;
uint32_t transfer_sectors = count;
uint32_t sectors = hdd_sectors(id);
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET);
for (i = 0; i < transfer_sectors; i++)
fwrite(empty_sector, 1, 512, hdd_images[id].file);
if (count != transfer_sectors)
return 1;
return 0;
}
uint32_t hdd_image_get_last_sector(uint8_t id)
{
return hdd_images[id].last_sector;
}
uint8_t hdd_image_get_type(uint8_t id)
{
return hdd_images[id].type;
}
void hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt)
{
if (hdd_images[id].type == 2)
{
hdd[id].at_hpc = hpc;
hdd[id].at_spt = spt;
fseeko64(hdd_images[id].file, 0x20, SEEK_SET);
fwrite(&(hdd[id].at_spt), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file);
}
}
void hdd_image_unload(uint8_t id, int fn_preserve)
{
if (wcslen(hdd[id].fn) == 0)
return;
if (hdd_images[id].loaded) {
if (hdd_images[id].file != NULL) {
} else {
if (image_is_hdi(fn)) {
fseeko64(hdd_images[id].file, 0x8, SEEK_SET);
fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file);
fseeko64(hdd_images[id].file, 0xC, SEEK_SET);
full_size = 0LL;
fread(&full_size, 1, 4, hdd_images[id].file);
fseeko64(hdd_images[id].file, 0x10, SEEK_SET);
fread(&sector_size, 1, 4, hdd_images[id].file);
if (sector_size != 512) {
/* Sector size is not 512 */
hdd_image_log("HDI: Sector size is not 512\n");
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
hdd_images[id].loaded = 0;
fread(&spt, 1, 4, hdd_images[id].file);
fread(&hpc, 1, 4, hdd_images[id].file);
fread(&tracks, 1, 4, hdd_images[id].file);
hdd[id].spt = spt;
hdd[id].hpc = hpc;
hdd[id].tracks = tracks;
hdd_images[id].type = 1;
} else if (is_hdx[1]) {
hdd_images[id].base = 0x28;
fseeko64(hdd_images[id].file, 8, SEEK_SET);
fread(&full_size, 1, 8, hdd_images[id].file);
fseeko64(hdd_images[id].file, 0x10, SEEK_SET);
fread(&sector_size, 1, 4, hdd_images[id].file);
if (sector_size != 512) {
/* Sector size is not 512 */
hdd_image_log("HDX: Sector size is not 512\n");
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
fread(&spt, 1, 4, hdd_images[id].file);
fread(&hpc, 1, 4, hdd_images[id].file);
fread(&tracks, 1, 4, hdd_images[id].file);
hdd[id].spt = spt;
hdd[id].hpc = hpc;
hdd[id].tracks = tracks;
fread(&(hdd[id].at_spt), 1, 4, hdd_images[id].file);
fread(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file);
hdd_images[id].type = 2;
} else {
full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
hdd_images[id].type = 0;
}
}
hdd_images[id].last_sector = -1;
memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn));
if (fn_preserve)
wcscpy(hdd[id].prev_fn, hdd[id].fn);
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
fseeko64(hdd_images[id].file, 0, SEEK_END);
s = ftello64(hdd_images[id].file);
if (s < (full_size + hdd_images[id].base))
return prepare_new_hard_disk(id, full_size);
else {
hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1;
hdd_images[id].loaded = 1;
return 1;
}
}
void hdd_image_close(uint8_t id)
void
hdd_image_seek(uint8_t id, uint32_t sector)
{
off64_t addr = sector;
addr = (uint64_t)sector * 512;
fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET);
}
void
hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
{
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
fread(buffer, 1, count << 9, hdd_images[id].file);
}
uint32_t
hdd_sectors(uint8_t id)
{
fseeko64(hdd_images[id].file, 0, SEEK_END);
return (uint32_t) ((ftello64(hdd_images[id].file) - hdd_images[id].base) >> 9);
}
int
hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
{
uint32_t transfer_sectors = count;
uint32_t sectors = hdd_sectors(id);
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
fread(buffer, 1, transfer_sectors << 9, hdd_images[id].file);
if (count != transfer_sectors)
return 1;
return 0;
}
void
hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
{
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
fwrite(buffer, count << 9, 1, hdd_images[id].file);
}
int
hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
{
uint32_t transfer_sectors = count;
uint32_t sectors = hdd_sectors(id);
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
fwrite(buffer, transfer_sectors << 9, 1, hdd_images[id].file);
if (count != transfer_sectors)
return 1;
return 0;
}
void
hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count)
{
uint32_t i = 0;
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
for (i = 0; i < count; i++)
fwrite(empty_sector, 512, 1, hdd_images[id].file);
}
int
hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count)
{
uint32_t i = 0;
uint32_t transfer_sectors = count;
uint32_t sectors = hdd_sectors(id);
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
for (i = 0; i < transfer_sectors; i++)
fwrite(empty_sector, 1, 512, hdd_images[id].file);
if (count != transfer_sectors)
return 1;
return 0;
}
uint32_t
hdd_image_get_last_sector(uint8_t id)
{
return hdd_images[id].last_sector;
}
uint8_t
hdd_image_get_type(uint8_t id)
{
return hdd_images[id].type;
}
void
hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt)
{
if (hdd_images[id].type == 2) {
hdd[id].at_hpc = hpc;
hdd[id].at_spt = spt;
fseeko64(hdd_images[id].file, 0x20, SEEK_SET);
fwrite(&(hdd[id].at_spt), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file);
}
}
void
hdd_image_unload(uint8_t id, int fn_preserve)
{
if (wcslen(hdd[id].fn) == 0)
return;
if (hdd_images[id].loaded) {
if (hdd_images[id].file != NULL) {
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
}
hdd_images[id].loaded = 0;
}
hdd_images[id].last_sector = -1;
memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn));
if (fn_preserve)
wcscpy(hdd[id].prev_fn, hdd[id].fn);
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
}
void
hdd_image_close(uint8_t id)
{
hdd_image_log("hdd_image_close(%i)\n", id);
if (!hdd_images[id].loaded)
return;
if (hdd_images[id].file != NULL) {
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
}
memset(&hdd_images[id], 0, sizeof(hdd_image_t));
hdd_images[id].loaded = 0;
}

View File

@@ -9,13 +9,13 @@
* Implementation of the IDE emulation for hard disks and ATAPI
* CD-ROM devices.
*
* Version: @(#)hdd_table.c 1.0.5 2017/11/01
* Version: @(#)hdd_table.c 1.0.5 2018/04/08
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2016,2017 Miran Grca.
* Copyright 2017 Fred N. van Kempen.
* Copyright 2016-2018 Miran Grca.
* Copyright 2017,2018 Fred N. van Kempen.
*/
#include <stdio.h>
#include <stdint.h>
@@ -26,7 +26,7 @@
#include "hdd.h"
uint64_t hdd_table[128][3] = {
unsigned int hdd_table[128][3] = {
{ 306, 4, 17 }, /* 0 - 7 */
{ 615, 2, 17 },
{ 306, 4, 26 },

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
* Implementation of the Iomega ZIP drive with SCSI(-like)
* commands, for both ATAPI and SCSI usage.
*
* Version: @(#)zip.h 1.0.4 2018/03/20
* Version: @(#)zip.h 1.0.5 2018/03/26
*
* Author: Miran Grca, <mgrca8@gmail.com>
*
@@ -19,15 +19,15 @@
#define EMU_ZIP_H
#define ZIP_NUM 4
#define ZIP_NUM 4
#define ZIP_PHASE_IDLE 0
#define ZIP_PHASE_COMMAND 1
#define ZIP_PHASE_COMPLETE 2
#define ZIP_PHASE_DATA_IN 3
#define ZIP_PHASE_DATA_IN_DMA 4
#define ZIP_PHASE_DATA_OUT 5
#define ZIP_PHASE_DATA_OUT_DMA 6
#define ZIP_PHASE_IDLE 0x00
#define ZIP_PHASE_COMMAND 0x01
#define ZIP_PHASE_COMPLETE 0x02
#define ZIP_PHASE_DATA_IN 0x03
#define ZIP_PHASE_DATA_IN_DMA 0x04
#define ZIP_PHASE_DATA_OUT 0x05
#define ZIP_PHASE_DATA_OUT_DMA 0x06
#define ZIP_PHASE_ERROR 0x80
#define BUF_SIZE 32768
@@ -42,134 +42,81 @@
enum {
ZIP_BUS_DISABLED = 0,
ZIP_BUS_ATAPI_PIO_ONLY = 4,
ZIP_BUS_ATAPI_PIO_AND_DMA,
ZIP_BUS_ATAPI = 4,
ZIP_BUS_SCSI,
ZIP_BUS_USB = 8
ZIP_BUS_USB
};
typedef struct {
uint8_t previous_command;
uint8_t previous_command, error,
features, status,
phase, *buffer,
atapi_cdb[16],
current_cdb[16],
sense[256];
int toctimes;
int media_status;
uint16_t request_length, max_transfer_len;
int is_dma;
int toctimes, media_status,
is_dma, requested_blocks,
current_page_len, current_page_pos,
total_length, written_length,
mode_select_phase, do_page_save,
callback, data_pos,
packet_status, unit_attention,
cdb_len_setting, cdb_len,
request_pos, total_read,
block_total, all_blocks_total,
old_len, block_descriptor_len,
init_length;
int requested_blocks; /* This will be set to something other than 1 when block reads are implemented. */
uint32_t sector_pos, sector_len,
packet_len, pos,
seek_pos;
uint64_t current_page_code;
int current_page_len;
int current_page_pos;
int mode_select_phase;
int total_length;
int written_length;
int do_page_save;
uint8_t error;
uint8_t features;
uint16_t request_length;
uint16_t max_transfer_len;
uint8_t status;
uint8_t phase;
uint32_t sector_pos;
uint32_t sector_len;
uint32_t packet_len;
int packet_status;
uint8_t atapi_cdb[16];
uint8_t current_cdb[16];
uint32_t pos;
int callback;
int data_pos;
int cdb_len_setting;
int cdb_len;
int cd_status;
int prev_status;
int unit_attention;
uint8_t sense[256];
int request_pos;
uint8_t *buffer;
int times;
uint32_t seek_pos;
int total_read;
int block_total;
int all_blocks_total;
int old_len;
int block_descriptor_len;
int init_length;
uint64_t current_page_code;
} zip_t;
typedef struct {
int host_drive;
int prev_host_drive;
unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */
uint8_t ide_channel,
bus_mode; /* Bit 0 = PIO suported;
Bit 1 = DMA supportd. */
unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */
uint8_t bus_mode; /* Bit 0 = PIO suported;
Bit 1 = DMA supportd. */
unsigned int scsi_device_id, scsi_device_lun,
is_250;
uint8_t ide_channel;
wchar_t image_path[1024],
prev_image_path[1024];
unsigned int scsi_device_id;
unsigned int scsi_device_lun;
unsigned int is_250;
unsigned int atapi_dma;
int read_only, ui_writeprot;
wchar_t image_path[1024];
wchar_t prev_image_path[1024];
uint32_t medium_size, base;
uint32_t medium_size;
int read_only;
int ui_writeprot;
uint32_t base;
FILE *f;
FILE *f;
} zip_drive_t;
extern zip_t zip[ZIP_NUM];
extern zip_t *zip[ZIP_NUM];
extern zip_drive_t zip_drives[ZIP_NUM];
extern uint8_t atapi_zip_drives[8];
extern uint8_t scsi_zip_drives[16][8];
#define zip_sense_error zip[id].sense[0]
#define zip_sense_key zip[id].sense[2]
#define zip_asc zip[id].sense[12]
#define zip_ascq zip[id].sense[13]
#define zip_drive zip_drives[id].host_drive
#define zip_sense_error zip[id]->sense[0]
#define zip_sense_key zip[id]->sense[2]
#define zip_asc zip[id]->sense[12]
#define zip_ascq zip[id]->sense[13]
#ifdef __cplusplus
extern "C" {
#endif
extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length);
extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length);
extern void (*ide_bus_master_set_irq)(int channel);
extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv);
extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv);
extern void (*ide_bus_master_set_irq)(int channel, void *priv);
extern void *ide_bus_master_priv[2];
extern void ioctl_close(uint8_t id);
extern uint32_t zip_mode_sense_get_channel(uint8_t id, int channel);
@@ -183,8 +130,6 @@ extern void zip_phase_callback(uint8_t id);
extern uint32_t zip_read(uint8_t channel, int length);
extern void zip_write(uint8_t channel, uint32_t val, int length);
extern int zip_lba_to_msf_accurate(int lba);
extern void zip_close(uint8_t id);
extern void zip_disk_reload(uint8_t id);
extern void zip_reset(uint8_t id);
@@ -200,6 +145,8 @@ extern void zip_global_init(void);
extern void zip_hard_reset(void);
extern int zip_load(uint8_t id, wchar_t *fn);
extern void zip_destroy_drives(void);
extern void zip_close(uint8_t id);
#ifdef __cplusplus