IDE DMA: Properly handle partial transfers, fixes ATAPI DMA in Windows 98 SE.

This commit is contained in:
OBattler
2025-03-17 20:58:15 +01:00
parent 8fd299f2d7
commit 556c74c159
6 changed files with 30 additions and 19 deletions

View File

@@ -117,7 +117,7 @@
#define ROM_PATH_MCIDE "roms/hdd/xtide/ide_ps2 R1.1.bin"
typedef struct ide_bm_t {
int (*dma)(uint8_t *data, int transfer_length, int out, void *priv);
int (*dma)(uint8_t *data, int transfer_length, int total_length, int out, void *priv);
void (*set_irq)(uint8_t status, void *priv);
void *priv;
} ide_bm_t;
@@ -1094,7 +1094,7 @@ ide_atapi_callback(ide_t *ide)
if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 &&
(bm != NULL) && bm->dma) {
if (ide->sc->block_len == 0) {
ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, bm->priv);
ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, 0, bm->priv);
/* Underrun. */
if (ret == 1)
@@ -1102,6 +1102,7 @@ ide_atapi_callback(ide_t *ide)
} else {
ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos -
ide->sc->block_len, ide->sc->block_len,
ide->sc->sector_len * ide->sc->block_len,
0, bm->priv);
if (ret == 1) {
@@ -1144,14 +1145,16 @@ ide_atapi_callback(ide_t *ide)
if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 &&
(bm != NULL) && bm->dma) {
if (ide->sc->block_len == 0) {
ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 1, bm->priv);
ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, 1, bm->priv);
/* Underrun. */
if (ret == 1)
ret = 3;
} else {
ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos,
ide->sc->block_len, 1, bm->priv);
ide->sc->block_len,
ide->sc->sector_len * ide->sc->block_len,
1, bm->priv);
if (ret & 1) {
if (ide->write != NULL)
@@ -2392,7 +2395,7 @@ ide_callback(void *priv)
err = UNC_ERR;
} else if (!ide_boards[ide->board]->force_ata3 && bm->dma) {
/* We should not abort - we should simply wait for the host to start DMA. */
ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 0, bm->priv);
ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 0, 0, bm->priv);
if (ret == 2) {
/* Bus master DMA disabled, simply wait for the host to enable DMA. */
ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT;
@@ -2500,7 +2503,7 @@ ide_callback(void *priv)
else
ide->sector_pos = 256;
ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 1, bm->priv);
ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 0, 1, bm->priv);
if (ret == 2) {
/* Bus master DMA disabled, simply wait for the host to enable DMA. */
@@ -3127,7 +3130,7 @@ ide_xtide_close(void)
void
ide_set_bus_master(int board,
int (*dma)(uint8_t *data, int transfer_length, int out, void *priv),
int (*dma)(uint8_t *data, int transfer_length, int total_length, int out, void *priv),
void (*set_irq)(uint8_t status, void *priv), void *priv)
{
ide_bm_t *bm;

View File

@@ -95,19 +95,19 @@ cmd646_set_irq_1(uint8_t status, void *priv)
}
static int
cmd646_bus_master_dma_0(uint8_t *data, int transfer_length, int out, void *priv)
cmd646_bus_master_dma_0(uint8_t *data, int transfer_length, int total_length, int out, void *priv)
{
const cmd646_t *dev = (cmd646_t *) priv;
return sff_bus_master_dma(data, transfer_length, out, dev->bm[0]);
return sff_bus_master_dma(data, transfer_length, total_length, out, dev->bm[0]);
}
static int
cmd646_bus_master_dma_1(uint8_t *data, int transfer_length, int out, void *priv)
cmd646_bus_master_dma_1(uint8_t *data, int transfer_length, int total_length, int out, void *priv)
{
const cmd646_t *dev = (cmd646_t *) priv;
return sff_bus_master_dma(data, transfer_length, out, dev->bm[1]);
return sff_bus_master_dma(data, transfer_length, total_length, out, dev->bm[1]);
}
static void

View File

@@ -316,14 +316,14 @@ sff_bus_master_readl(uint16_t port, void *priv)
}
int
sff_bus_master_dma(uint8_t *data, int transfer_length, int out, void *priv)
sff_bus_master_dma(uint8_t *data, int transfer_length, int total_length, int out, void *priv)
{
sff8038i_t *dev = (sff8038i_t *) priv;
#ifdef ENABLE_SFF_LOG
char *sop;
#endif
int force_end = 0;
int force_end = 0;
int buffer_pos = 0;
#ifdef ENABLE_SFF_LOG
@@ -365,9 +365,15 @@ sff_bus_master_dma(uint8_t *data, int transfer_length, int out, void *priv)
return 1; /* This block has exhausted the data to transfer and it was smaller than the count, break. */
} else {
if (!transfer_length && !dev->eot) {
sff_log("Total transfer length smaller than sum of all blocks, full block\n");
dev->status &= ~2;
return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */
if (total_length) {
sff_log("Total transfer length smaller than sum of all blocks, partial transfer\n");
sff_bus_master_next_addr(dev);
return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */
} else {
sff_log("Total transfer length smaller than sum of all blocks, full block\n");
dev->status &= ~2;
return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */
}
} else if (transfer_length && dev->eot) {
sff_log("Total transfer length greater than sum of all blocks\n");
dev->status |= 2;