IDE fixes and finished the SiS 5511.

This commit is contained in:
OBattler
2023-10-20 02:57:50 +02:00
parent 5c4429e4ec
commit 88934ab0ca
24 changed files with 844 additions and 480 deletions

View File

@@ -124,8 +124,8 @@ typedef struct ide_board_t {
} ide_board_t;
typedef struct ide_bm_t {
int (*dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv);
void (*set_irq)(int channel, void *priv);
int (*dma)(uint8_t *data, int transfer_length, int out, void *priv);
void (*set_irq)(uint8_t status, void *priv);
void *priv;
} ide_bm_t;
@@ -342,7 +342,7 @@ ide_irq_raise(ide_t *ide)
if (!(ide->fdisk & 2) && ide->selected) {
if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->set_irq)
ide_bm[ide->board]->set_irq(ide->board | 0x40, ide_bm[ide->board]->priv);
ide_bm[ide->board]->set_irq(0x04, ide_bm[ide->board]->priv);
else if (ide_boards[ide->board]->irq != -1)
picint(1 << ide_boards[ide->board]->irq);
}
@@ -363,7 +363,7 @@ ide_irq_lower(ide_t *ide)
if (ide->irqstat && ide->selected) {
if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->set_irq)
ide_bm[ide->board]->set_irq(ide->board, ide_bm[ide->board]->priv);
ide_bm[ide->board]->set_irq(0x00, ide_bm[ide->board]->priv);
else if (ide_boards[ide->board]->irq != -1)
picintc(1 << ide_boards[ide->board]->irq);
}
@@ -382,8 +382,8 @@ ide_irq_update(ide_t *ide)
if (!(ide->fdisk & 2) && ide->irqstat) {
ide_log("IDE %i: IRQ update raise\n", ide->board);
if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->set_irq) {
ide_bm[ide->board]->set_irq(ide->board, ide_bm[ide->board]->priv);
ide_bm[ide->board]->set_irq(ide->board | 0x40, ide_bm[ide->board]->priv);
ide_bm[ide->board]->set_irq(0x00, ide_bm[ide->board]->priv);
ide_bm[ide->board]->set_irq(0x04, ide_bm[ide->board]->priv);
} else if (ide_boards[ide->board]->irq != -1) {
picintc(1 << ide_boards[ide->board]->irq);
picint(1 << ide_boards[ide->board]->irq);
@@ -391,7 +391,7 @@ ide_irq_update(ide_t *ide)
} else if ((ide->fdisk & 2) || !ide->irqstat) {
ide_log("IDE %i: IRQ update lower\n", ide->board);
if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->set_irq)
ide_bm[ide->board]->set_irq(ide->board, ide_bm[ide->board]->priv);
ide_bm[ide->board]->set_irq(0x00, ide_bm[ide->board]->priv);
else if (ide_boards[ide->board]->irq != -1)
picintc(1 << ide_boards[ide->board]->irq);
}
@@ -1022,9 +1022,9 @@ ide_atapi_callback(ide_t *ide)
#endif
out = (ide->sc->packet_status & 0x01);
if (!ide->sc->pad0 && !ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->dma) {
ret = ide_bm[ide->board]->dma(ide->board,
ide->sc->temp_buffer, ide->sc->packet_len,
if (!ide->sc->pad0 && !ide_boards[ide->board]->force_ata3 &&
ide_bm[ide->board] && ide_bm[ide->board]->dma) {
ret = ide_bm[ide->board]->dma(ide->sc->temp_buffer, ide->sc->packet_len,
out, ide_bm[ide->board]->priv);
} else {
/* DMA command without a bus master. */
@@ -2333,8 +2333,7 @@ ide_callback(void *priv)
if (!ide_boards[ide->board]->force_ata3 && ide_bm[ide->board] && ide_bm[ide->board]->dma) {
/* We should not abort - we should simply wait for the host to start DMA. */
ret = ide_bm[ide->board]->dma(ide->board,
ide->sector_buffer, ide->sector_pos * 512,
ret = ide_bm[ide->board]->dma(ide->sector_buffer, ide->sector_pos * 512,
0, ide_bm[ide->board]->priv);
if (ret == 2) {
/* Bus master DMA disabled, simply wait for the host to enable DMA. */
@@ -2431,8 +2430,7 @@ ide_callback(void *priv)
else
ide->sector_pos = 256;
ret = ide_bm[ide->board]->dma(ide->board,
ide->sector_buffer, ide->sector_pos * 512,
ret = ide_bm[ide->board]->dma(ide->sector_buffer, ide->sector_pos * 512,
1, ide_bm[ide->board]->priv);
if (ret == 2) {
@@ -3041,8 +3039,8 @@ ide_xtide_close(void)
void
ide_set_bus_master(int board,
int (*dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv),
void (*set_irq)(int channel, void *priv), void *priv)
int (*dma)(uint8_t *data, int transfer_length, int out, void *priv),
void (*set_irq)(uint8_t status, void *priv), void *priv)
{
if (ide_bm[board] == NULL)
ide_bm[board] = (ide_bm_t *) malloc(sizeof(ide_bm_t));

View File

@@ -74,38 +74,52 @@ cmd640_log(const char *fmt, ...)
#endif
void
cmd640_set_irq(int channel, void *priv)
cmd640_set_irq_0(uint8_t status, void *priv)
{
cmd640_t *dev = (cmd640_t *) priv;
int irq = !!(channel & 0x40);
int irq = !!(status & 0x04);
if (channel & 0x01) {
if (!(dev->regs[0x57] & 0x10) || (channel & 0x40)) {
dev->regs[0x57] &= ~0x10;
dev->regs[0x57] |= (channel >> 2);
}
} else {
if (!(dev->regs[0x50] & 0x04) || (channel & 0x40)) {
dev->regs[0x50] &= ~0x04;
dev->regs[0x50] |= (channel >> 4);
}
}
if (!(dev->regs[0x50] & 0x04) || (status & 0x04))
dev->regs[0x50] = (dev->regs[0x50] & ~0x04) | status;
channel &= 0x01;
if (!(dev->channels & (1 << channel)))
if (!(dev->channels & 1))
return;
if (irq) {
if (dev->irq_mode[channel] == 1)
if (dev->irq_mode[0] == 1)
pci_set_irq(dev->pci_slot, dev->irq_pin, &dev->irq_state);
else
picint(1 << (14 + channel));
picint(1 << 14);
} else {
if (dev->irq_mode[channel] == 1)
if (dev->irq_mode[0] == 1)
pci_clear_irq(dev->pci_slot, dev->irq_pin, &dev->irq_state);
else
picintc(1 << (14 + channel));
picintc(1 << 14);
}
}
void
cmd640_set_irq_1(uint8_t status, void *priv)
{
cmd640_t *dev = (cmd640_t *) priv;
int irq = !!(status & 0x04);
if (!(dev->regs[0x57] & 0x10) || (status & 0x04))
dev->regs[0x57] = (dev->regs[0x57] & ~0x10) | (status << 2);
if (!(dev->channels & 2))
return;
if (irq) {
if (dev->irq_mode[1] == 1)
pci_set_irq(dev->pci_slot, dev->irq_pin, &dev->irq_state);
else
picint(1 << 15);
} else {
if (dev->irq_mode[1] == 1)
pci_clear_irq(dev->pci_slot, dev->irq_pin, &dev->irq_state);
else
picintc(1 << 15);
}
}
@@ -415,10 +429,10 @@ cmd640_reset(void *priv)
}
if (dev->channels & 0x01)
cmd640_set_irq(0x00, priv);
cmd640_set_irq_0(0x00, priv);
if (dev->channels & 0x02)
cmd640_set_irq(0x01, priv);
cmd640_set_irq_1(0x00, priv);
memset(dev->regs, 0x00, sizeof(dev->regs));
@@ -509,10 +523,10 @@ cmd640_init(const device_t *info)
pci_add_card(PCI_ADD_IDE, cmd640_pci_read, cmd640_pci_write, dev, &dev->pci_slot);
if (dev->channels & 0x01)
ide_set_bus_master(0, NULL, cmd640_set_irq, dev);
ide_set_bus_master(0, NULL, cmd640_set_irq_0, dev);
if (dev->channels & 0x02)
ide_set_bus_master(1, NULL, cmd640_set_irq, dev);
ide_set_bus_master(1, NULL, cmd640_set_irq_1, dev);
/* The CMD PCI-0640B IDE controller has no DMA capability,
so set our devices IDE devices to force ATA-3 (no DMA). */

View File

@@ -73,31 +73,41 @@ cmd646_log(const char *fmt, ...)
#endif
static void
cmd646_set_irq(int channel, void *priv)
cmd646_set_irq_0(uint8_t status, void *priv)
{
cmd646_t *dev = (cmd646_t *) priv;
if (channel & 0x01) {
if (!(dev->regs[0x57] & 0x10) || (channel & 0x40)) {
dev->regs[0x57] &= ~0x10;
dev->regs[0x57] |= (channel >> 2);
}
} else {
if (!(dev->regs[0x50] & 0x04) || (channel & 0x40)) {
dev->regs[0x50] &= ~0x04;
dev->regs[0x50] |= (channel >> 4);
}
}
if (!(dev->regs[0x50] & 0x04) || (status & 0x04))
dev->regs[0x50] = (dev->regs[0x50] & ~0x04) | status;
sff_bus_master_set_irq(channel, dev->bm[channel & 0x01]);
sff_bus_master_set_irq(status, dev->bm[0]);
}
static void
cmd646_set_irq_1(uint8_t status, void *priv)
{
cmd646_t *dev = (cmd646_t *) priv;
if (!(dev->regs[0x57] & 0x10) || (status & 0x04))
dev->regs[0x57] = (dev->regs[0x57] & ~0x10) | (status << 2);
sff_bus_master_set_irq(status, dev->bm[1]);
}
static int
cmd646_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv)
cmd646_bus_master_dma_0(uint8_t *data, int transfer_length, int out, void *priv)
{
const cmd646_t *dev = (cmd646_t *) priv;
return sff_bus_master_dma(channel, data, transfer_length, out, dev->bm[channel & 0x01]);
return sff_bus_master_dma(data, transfer_length, out, dev->bm[0]);
}
static int
cmd646_bus_master_dma_1(uint8_t *data, int transfer_length, int out, void *priv)
{
const cmd646_t *dev = (cmd646_t *) priv;
return sff_bus_master_dma(data, transfer_length, out, dev->bm[1]);
}
static void
@@ -105,7 +115,7 @@ cmd646_ide_handlers(cmd646_t *dev)
{
uint16_t main;
uint16_t side;
int irq_mode[2] = { 0, 0 };
int irq_mode[2] = { IRQ_MODE_LEGACY, IRQ_MODE_LEGACY };
sff_set_slot(dev->bm[0], dev->pci_slot);
sff_set_slot(dev->bm[1], dev->pci_slot);
@@ -124,10 +134,9 @@ cmd646_ide_handlers(cmd646_t *dev)
ide_set_side(0, side);
if (dev->regs[0x09] & 0x01)
irq_mode[0] = 1;
irq_mode[0] = IRQ_MODE_PCI_IRQ_PIN;
sff_set_irq_mode(dev->bm[0], 0, irq_mode[0]);
sff_set_irq_mode(dev->bm[0], 1, irq_mode[1]);
sff_set_irq_mode(dev->bm[0], irq_mode[0]);
if (dev->regs[0x04] & 0x01)
ide_pri_enable();
@@ -151,8 +160,7 @@ cmd646_ide_handlers(cmd646_t *dev)
if (dev->regs[0x09] & 0x04)
irq_mode[1] = 1;
sff_set_irq_mode(dev->bm[1], 0, irq_mode[0]);
sff_set_irq_mode(dev->bm[1], 1, irq_mode[1]);
sff_set_irq_mode(dev->bm[1], irq_mode[1]);
if ((dev->regs[0x04] & 0x01) && (dev->regs[0x51] & 0x08))
ide_sec_enable();
@@ -321,8 +329,8 @@ cmd646_reset(void *priv)
mo_reset((scsi_common_t *) mo_drives[i].priv);
}
cmd646_set_irq(0x00, priv);
cmd646_set_irq(0x01, priv);
cmd646_set_irq_0(0x00, priv);
cmd646_set_irq_1(0x00, priv);
memset(dev->regs, 0x00, sizeof(dev->regs));
@@ -401,17 +409,14 @@ cmd646_init(const device_t *info)
if (!dev->single_channel)
dev->bm[1] = device_add_inst(&sff8038i_device, 2);
ide_set_bus_master(0, cmd646_bus_master_dma, cmd646_set_irq, dev);
ide_set_bus_master(0, cmd646_bus_master_dma_0, cmd646_set_irq_0, dev);
if (!dev->single_channel)
ide_set_bus_master(1, cmd646_bus_master_dma, cmd646_set_irq, dev);
ide_set_bus_master(1, cmd646_bus_master_dma_1, cmd646_set_irq_1, dev);
sff_set_irq_mode(dev->bm[0], 0, 0);
sff_set_irq_mode(dev->bm[0], 1, 0);
sff_set_irq_mode(dev->bm[0], IRQ_MODE_LEGACY);
if (!dev->single_channel) {
sff_set_irq_mode(dev->bm[1], 0, 0);
sff_set_irq_mode(dev->bm[1], 1, 0);
}
if (!dev->single_channel)
sff_set_irq_mode(dev->bm[1], IRQ_MODE_LEGACY);
cmd646_reset(dev);

View File

@@ -74,7 +74,7 @@ sff_log(const char *fmt, ...)
void
sff_bus_master_handler(sff8038i_t *dev, int enabled, uint16_t base)
{
if (dev->base != 0x0000) {
if (dev->enabled && (dev->base != 0x0000)) {
io_removehandler(dev->base, 0x08,
sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl,
sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel,
@@ -314,7 +314,7 @@ sff_bus_master_readl(uint16_t port, void *priv)
}
int
sff_bus_master_dma(UNUSED(int channel), uint8_t *data, int transfer_length, int out, void *priv)
sff_bus_master_dma(uint8_t *data, int transfer_length, int out, void *priv)
{
sff8038i_t *dev = (sff8038i_t *) priv;
#ifdef ENABLE_SFF_LOG
@@ -385,64 +385,72 @@ sff_bus_master_dma(UNUSED(int channel), uint8_t *data, int transfer_length, int
}
void
sff_bus_master_set_irq(int channel, void *priv)
sff_bus_master_set_irq(uint8_t status, void *priv)
{
sff8038i_t *dev = (sff8038i_t *) priv;
uint8_t irq = !!(channel & 0x40);
uint8_t irq = !!(status & 0x04);
int irq_shift = 0;
if (!(dev->status & 0x04) || (channel & 0x40)) {
dev->status &= ~0x04;
dev->status |= (channel >> 4);
}
if (!(dev->status & 0x04) || (status & 0x04))
dev->status = (dev->status & ~0x04) | status;
channel &= 0x01;
switch (dev->irq_mode[channel]) {
switch (dev->irq_mode) {
default:
case 0:
case IRQ_MODE_LEGACY:
/* Legacy IRQ mode. */
if (irq)
picint(1 << (14 + channel));
picint(1 << dev->irq_line);
else
picintc(1 << (14 + channel));
picintc(1 << dev->irq_line);
break;
case 1:
case IRQ_MODE_PCI_IRQ_PIN:
/* Native PCI IRQ mode with interrupt pin. */
if (irq)
pci_set_irq(dev->slot, dev->irq_pin, &dev->irq_state);
else
pci_clear_irq(dev->slot, dev->irq_pin, &dev->irq_state);
break;
case 2:
case 5:
case IRQ_MODE_MIRQ_0:
case IRQ_MODE_MIRQ_1:
/* MIRQ 0 or 1. */
case IRQ_MODE_MIRQ_2:
case IRQ_MODE_MIRQ_3:
/* MIRQ 2 or 3. */
if (irq)
pci_set_mirq((dev->irq_mode[channel] & 1), 0, &dev->irq_state);
pci_set_mirq((dev->irq_mode & 3) + irq_shift, 0, &dev->irq_state);
else
pci_clear_mirq((dev->irq_mode[channel] & 1), 0, &dev->irq_state);
pci_clear_mirq((dev->irq_mode & 3) + irq_shift, 0, &dev->irq_state);
break;
case 3:
/* TODO: Redo this as a MIRQ. */
case IRQ_MODE_PCI_IRQ_LINE:
/* Native PCI IRQ mode with specified interrupt line. */
if (irq)
picintlevel(1 << dev->irq_line, &dev->irq_state);
pci_set_dirq(dev->pci_irq_line, &dev->irq_state);
else
picintclevel(1 << dev->irq_line, &dev->irq_state);
pci_clear_dirq(dev->pci_irq_line, &dev->irq_state);
break;
case 4:
case IRQ_MODE_ALI_ALADDIN:
/* ALi Aladdin Native PCI INTAJ mode. */
if (irq)
pci_set_mirq((channel + 2), dev->irq_level[channel], &dev->irq_state);
pci_set_mirq((dev->channel + 2), pci_get_mirq_level(dev->channel + 2), &dev->irq_state);
else
pci_clear_mirq((channel + 2), dev->irq_level[channel], &dev->irq_state);
pci_clear_mirq((dev->channel + 2), pci_get_mirq_level(dev->channel + 2), &dev->irq_state);
break;
case IRQ_MODE_SIS_551X:
/* SiS 551x mode. */
if (irq)
pci_set_mirq(2, 1, &dev->irq_state);
else
pci_clear_mirq(2, 1, &dev->irq_state);
break;
}
}
void
sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base)
sff_bus_master_reset(sff8038i_t *dev)
{
if (dev->enabled) {
io_removehandler(old_base, 0x08,
if (dev->enabled && (dev->base != 0x0000)) {
io_removehandler(dev->base, 0x08,
sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl,
sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel,
dev);
@@ -493,44 +501,54 @@ sff_set_slot(sff8038i_t *dev, int slot)
}
void
sff_set_irq_line(sff8038i_t *dev, int irq_line)
sff_set_irq_line(sff8038i_t *dev, int pci_irq_line)
{
dev->irq_line = irq_line;
dev->pci_irq_line = pci_irq_line;
}
/* TODO: Why does this always set the level to 0, regardless of the parameter?! */
void
sff_set_irq_level(sff8038i_t *dev, UNUSED(int irq_level))
{
dev->irq_level = 0;
}
void
sff_set_irq_level(sff8038i_t *dev, int channel, UNUSED(int irq_level))
sff_set_irq_mode(sff8038i_t *dev, int irq_mode)
{
dev->irq_level[channel] = 0;
}
dev->irq_mode = irq_mode;
void
sff_set_irq_mode(sff8038i_t *dev, int channel, int irq_mode)
{
dev->irq_mode[channel] = irq_mode;
switch (dev->irq_mode[channel]) {
switch (dev->irq_mode) {
default:
case 0:
case IRQ_MODE_LEGACY:
/* Legacy IRQ mode. */
sff_log("[%08X] Setting channel %i to legacy IRQ %i\n", dev, channel, 14 + channel);
sff_log("[%08X] Setting IRQ mode to legacy IRQ %i\n", dev, 14 + channel);
break;
case 1:
case IRQ_MODE_PCI_IRQ_PIN:
/* Native PCI IRQ mode with interrupt pin. */
sff_log("[%08X] Setting channel %i to native PCI INT%c\n", dev, channel, '@' + dev->irq_pin);
sff_log("[%08X] Setting IRQ mode to native PCI INT%c\n", dev, 0x40 + dev->irq_pin);
break;
case 2:
case 5:
case IRQ_MODE_MIRQ_0:
case IRQ_MODE_MIRQ_1:
/* MIRQ 0 or 1. */
sff_log("[%08X] Setting channel %i to PCI MIRQ%i\n", dev, channel, irq_mode & 1);
sff_log("[%08X] Setting IRQ mode to PCI MIRQ%i\n", dev, irq_mode & 1);
break;
case 3:
case IRQ_MODE_MIRQ_2:
case IRQ_MODE_MIRQ_3:
/* MIRQ 0 or 1. */
sff_log("[%08X] Setting IRQ mode to PCI MIRQ%i\n", dev, (irq_mode & 1) + 1);
break;
case IRQ_MODE_PCI_IRQ_LINE:
/* Native PCI IRQ mode with specified interrupt line. */
sff_log("[%08X] Setting channel %i to native PCI IRQ %i\n", dev, channel, dev->irq_line);
sff_log("[%08X] Setting IRQ mode to native PCI IRQ %i\n", dev, dev->pci_irq_line);
break;
case 4:
case IRQ_MODE_ALI_ALADDIN:
/* ALi Aladdin Native PCI INTAJ mode. */
sff_log("[%08X] Setting channel %i to INT%cJ\n", dev, channel, 'A' + channel);
sff_log("[%08X] Setting IRQ mode to INT%cJ\n", dev, 'A' + dev->channel);
break;
case IRQ_MODE_SIS_551X:
/* SiS 551x mode. */
sff_log("[%08X] Setting IRQ mode to PCI MIRQ2\n", dev);
break;
}
}
@@ -566,13 +584,15 @@ sff_init(UNUSED(const device_t *info))
ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev);
dev->slot = 7;
dev->irq_mode[0] = 0; /* Channel 0 goes to IRQ 14. */
dev->irq_mode[1] = 2; /* Channel 1 goes to MIRQ0. */
/* Channel 0 goes to IRQ 14, channel 1 goes to MIRQ0. */
dev->irq_mode = next_id ? IRQ_MODE_MIRQ_0 : IRQ_MODE_LEGACY;
dev->irq_pin = PCI_INTA;
dev->irq_line = 14;
dev->irq_level[0] = dev->irq_level[1] = 0;
dev->irq_line = 14 + next_id;
dev->pci_irq_line = 14;
dev->irq_level = 0;
dev->irq_state = 0;
dev->channel = next_id;
next_id++;
return dev;