ISAPnP: add card disable/reenable, default device configuration and card/device reset to the API

This commit is contained in:
RichardG867
2021-04-02 23:46:38 -03:00
parent c9e75f6624
commit 340448dfb6

View File

@@ -16,7 +16,6 @@
* Copyright 2016-2018 Miran Grca.
* Copyright 2021 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
@@ -37,7 +36,7 @@
#define CHECK_CURRENT_CARD() if (1) { \
card = dev->first_card; \
while (card) { \
if (card->state == PNP_STATE_CONFIG) \
if (card->enable && (card->state == PNP_STATE_CONFIG)) \
break; \
card = card->next; \
} \
@@ -86,12 +85,13 @@ typedef struct _isapnp_device_ {
uint8_t number;
uint8_t regs[256];
uint8_t mem_upperlimit, irq_types, io_16bit, io_len[8];
const isapnp_device_config_t *defaults;
struct _isapnp_device_ *next;
} isapnp_device_t;
typedef struct _isapnp_card_ {
uint8_t state, csn, id_checksum, serial_read, serial_read_pair, serial_read_pos, *rom;
uint8_t enable, state, csn, id_checksum, serial_read, serial_read_pair, serial_read_pos, *rom;
uint16_t rom_pos, rom_size;
void *priv;
@@ -163,6 +163,59 @@ isapnp_device_config_changed(isapnp_card_t *card, isapnp_device_t *ld)
}
static void
isapnp_reset_ld_config(isapnp_device_t *ld)
{
/* Do nothing if there's no default configuration for this device. */
const isapnp_device_config_t *config = ld->defaults;
if (!config)
return;
/* Populate configuration registers. */
ld->regs[0x30] = !!config->activate;
uint8_t i, reg_base;
uint32_t size;
for (i = 0; i < 4; i++) {
reg_base = 0x40 + (8 * i);
ld->regs[reg_base] = config->mem[i].base >> 16;
ld->regs[reg_base + 1] = config->mem[i].base >> 8;
size = config->mem[i].size;
if (ld->regs[reg_base + 2] & 0x01) /* upper limit */
size += config->mem[i].base;
ld->regs[reg_base + 3] = size >> 16;
ld->regs[reg_base + 4] = size >> 8;
}
for (i = 0; i < 4; i++) {
reg_base = (i == 0) ? 0x76 : (0x80 + (16 * i));
ld->regs[reg_base] = config->mem32[i].base >> 24;
ld->regs[reg_base + 1] = config->mem32[i].base >> 16;
ld->regs[reg_base + 2] = config->mem32[i].base >> 8;
ld->regs[reg_base + 3] = config->mem32[i].base;
size = config->mem32[i].size;
if (ld->regs[reg_base + 4] & 0x01) /* upper limit */
size += config->mem32[i].base;
ld->regs[reg_base + 5] = size >> 24;
ld->regs[reg_base + 6] = size >> 16;
ld->regs[reg_base + 7] = size >> 8;
ld->regs[reg_base + 8] = size;
}
for (i = 0; i < 8; i++) {
reg_base = 0x60 + (2 * i);
ld->regs[reg_base] = config->io[i].base >> 8;
ld->regs[reg_base + 1] = config->io[i].base;
}
for (i = 0; i < 2; i++) {
reg_base = 0x70 + (2 * i);
ld->regs[reg_base] = config->irq[i].irq;
ld->regs[reg_base + 1] = (!!config->irq[i].level << 1) | !!config->irq[i].type;
}
for (i = 0; i < 2; i++) {
reg_base = 0x74 + i;
ld->regs[reg_base] = config->dma[i].dma;
}
}
static void
isapnp_reset_ld_regs(isapnp_device_t *ld)
{
@@ -190,6 +243,9 @@ isapnp_reset_ld_regs(isapnp_device_t *ld)
else if (ld->irq_types & (0x8 << (4 * i)))
ld->regs[0x70 + (2 * i)] = 0x01;
}
/* Reset configuration registers to match the default configuration. */
isapnp_reset_ld_config(ld);
}
@@ -212,7 +268,7 @@ isapnp_read_data(uint16_t addr, void *priv)
case 0x01: /* Serial Isolation */
card = dev->first_card;
while (card) {
if (card->state == PNP_STATE_ISOLATION)
if (card->enable && (card->state == PNP_STATE_ISOLATION))
break;
card = card->next;
}
@@ -349,6 +405,8 @@ isapnp_write_addr(uint16_t addr, uint8_t val, void *priv)
if (!card) /* don't do anything if we have no PnP cards */
return;
dev->reg = val;
if (card->state == PNP_STATE_WAIT_FOR_KEY) { /* checking only the first card should be fine */
/* Check written value against LFSR key. */
if (val == pnp_init_key[dev->key_pos]) {
@@ -356,7 +414,7 @@ isapnp_write_addr(uint16_t addr, uint8_t val, void *priv)
if (!dev->key_pos) {
isapnp_log("ISAPnP: Key unlocked, putting cards to SLEEP\n");
while (card) {
if (card->state == PNP_STATE_WAIT_FOR_KEY)
if (card->enable && (card->state == PNP_STATE_WAIT_FOR_KEY))
card->state = PNP_STATE_SLEEP;
card = card->next;
}
@@ -364,9 +422,6 @@ isapnp_write_addr(uint16_t addr, uint8_t val, void *priv)
} else {
dev->key_pos = 0;
}
} else {
/* Nobody waiting for key, set register address. */
dev->reg = val;
}
}
@@ -483,7 +538,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv)
case 0x30: /* Activate */
CHECK_CURRENT_LD();
isapnp_log("ISAPnP: Activate CSN %02X device %02X\n", dev->current_ld_card->csn, dev->current_ld->number);
isapnp_log("ISAPnP: %sctivate CSN %02X device %02X\n", (val & 0x01) ? "A" : "Dea", dev->current_ld_card->csn, dev->current_ld->number);
dev->current_ld->regs[dev->reg] = val & 0x01;
isapnp_device_config_changed(dev->current_ld_card, dev->current_ld);
@@ -629,6 +684,7 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
isapnp_card_t *card = (isapnp_card_t *) malloc(sizeof(isapnp_card_t));
memset(card, 0, sizeof(isapnp_card_t));
card->enable = 1;
card->rom = rom;
card->rom_size = rom_size;
card->priv = priv;
@@ -839,6 +895,37 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
}
void
isapnp_enable_card(void *priv, uint8_t enable)
{
isapnp_t *dev = (isapnp_t *) device_get_priv(&isapnp_device);
if (!dev)
return;
/* Look for a matching card. */
isapnp_card_t *card = dev->first_card;
while (card) {
if (card == priv) {
/* Enable or disable the card. */
card->enable = !!enable;
/* enable=2 is a cheat code to jump straight into CONFIG state. */
card->state = (enable == 2) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY;
/* Invalidate other references if we're disabling this card. */
if (dev->isolated_card == card)
dev->isolated_card = NULL;
if (dev->current_ld_card == card)
dev->current_ld = dev->current_ld_card = NULL;
break;
}
card = card->next;
}
}
void
isapnp_set_csn(void *priv, uint8_t csn)
{
@@ -850,9 +937,62 @@ isapnp_set_csn(void *priv, uint8_t csn)
}
void
isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config)
{
isapnp_card_t *card = (isapnp_card_t *) priv;
isapnp_device_t *ld = card->first_ld;
/* Look for a logical device with this number. */
while (ld && (ld->number != ldn))
ld = ld->next;
if (!ld) /* none found */
return;
ld->defaults = config;
}
void
isapnp_reset_card(void *priv)
{
isapnp_card_t *card = (isapnp_card_t *) priv;
isapnp_device_t *ld = card->first_ld;
/* Reset all logical devices. */
while (ld) {
/* Reset the logical device's configuration. */
isapnp_reset_ld_config(ld);
isapnp_device_config_changed(card, ld);
ld = ld->next;
}
}
void
isapnp_reset_device(void *priv, uint8_t ldn)
{
isapnp_card_t *card = (isapnp_card_t *) priv;
isapnp_device_t *ld = card->first_ld;
/* Look for a logical device with this number. */
while (ld && (ld->number != ldn))
ld = ld->next;
if (!ld) /* none found */
return;
/* Reset the logical device's configuration. */
isapnp_reset_ld_config(ld);
isapnp_device_config_changed(card, ld);
}
static const device_t isapnp_device = {
"ISA Plug and Play",
DEVICE_ISA,
0,
0,
isapnp_init, isapnp_close, NULL,
{ NULL }, NULL, NULL,