ISAPnP: add card disable/reenable, default device configuration and card/device reset to the API
This commit is contained in:
@@ -16,7 +16,6 @@
|
|||||||
* Copyright 2016-2018 Miran Grca.
|
* Copyright 2016-2018 Miran Grca.
|
||||||
* Copyright 2021 RichardG.
|
* Copyright 2021 RichardG.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -37,7 +36,7 @@
|
|||||||
#define CHECK_CURRENT_CARD() if (1) { \
|
#define CHECK_CURRENT_CARD() if (1) { \
|
||||||
card = dev->first_card; \
|
card = dev->first_card; \
|
||||||
while (card) { \
|
while (card) { \
|
||||||
if (card->state == PNP_STATE_CONFIG) \
|
if (card->enable && (card->state == PNP_STATE_CONFIG)) \
|
||||||
break; \
|
break; \
|
||||||
card = card->next; \
|
card = card->next; \
|
||||||
} \
|
} \
|
||||||
@@ -86,12 +85,13 @@ typedef struct _isapnp_device_ {
|
|||||||
uint8_t number;
|
uint8_t number;
|
||||||
uint8_t regs[256];
|
uint8_t regs[256];
|
||||||
uint8_t mem_upperlimit, irq_types, io_16bit, io_len[8];
|
uint8_t mem_upperlimit, irq_types, io_16bit, io_len[8];
|
||||||
|
const isapnp_device_config_t *defaults;
|
||||||
|
|
||||||
struct _isapnp_device_ *next;
|
struct _isapnp_device_ *next;
|
||||||
} isapnp_device_t;
|
} isapnp_device_t;
|
||||||
|
|
||||||
typedef struct _isapnp_card_ {
|
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;
|
uint16_t rom_pos, rom_size;
|
||||||
void *priv;
|
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
|
static void
|
||||||
isapnp_reset_ld_regs(isapnp_device_t *ld)
|
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)))
|
else if (ld->irq_types & (0x8 << (4 * i)))
|
||||||
ld->regs[0x70 + (2 * i)] = 0x01;
|
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 */
|
case 0x01: /* Serial Isolation */
|
||||||
card = dev->first_card;
|
card = dev->first_card;
|
||||||
while (card) {
|
while (card) {
|
||||||
if (card->state == PNP_STATE_ISOLATION)
|
if (card->enable && (card->state == PNP_STATE_ISOLATION))
|
||||||
break;
|
break;
|
||||||
card = card->next;
|
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 */
|
if (!card) /* don't do anything if we have no PnP cards */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
dev->reg = val;
|
||||||
|
|
||||||
if (card->state == PNP_STATE_WAIT_FOR_KEY) { /* checking only the first card should be fine */
|
if (card->state == PNP_STATE_WAIT_FOR_KEY) { /* checking only the first card should be fine */
|
||||||
/* Check written value against LFSR key. */
|
/* Check written value against LFSR key. */
|
||||||
if (val == pnp_init_key[dev->key_pos]) {
|
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) {
|
if (!dev->key_pos) {
|
||||||
isapnp_log("ISAPnP: Key unlocked, putting cards to SLEEP\n");
|
isapnp_log("ISAPnP: Key unlocked, putting cards to SLEEP\n");
|
||||||
while (card) {
|
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->state = PNP_STATE_SLEEP;
|
||||||
card = card->next;
|
card = card->next;
|
||||||
}
|
}
|
||||||
@@ -364,9 +422,6 @@ isapnp_write_addr(uint16_t addr, uint8_t val, void *priv)
|
|||||||
} else {
|
} else {
|
||||||
dev->key_pos = 0;
|
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 */
|
case 0x30: /* Activate */
|
||||||
CHECK_CURRENT_LD();
|
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;
|
dev->current_ld->regs[dev->reg] = val & 0x01;
|
||||||
isapnp_device_config_changed(dev->current_ld_card, dev->current_ld);
|
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));
|
isapnp_card_t *card = (isapnp_card_t *) malloc(sizeof(isapnp_card_t));
|
||||||
memset(card, 0, sizeof(isapnp_card_t));
|
memset(card, 0, sizeof(isapnp_card_t));
|
||||||
|
|
||||||
|
card->enable = 1;
|
||||||
card->rom = rom;
|
card->rom = rom;
|
||||||
card->rom_size = rom_size;
|
card->rom_size = rom_size;
|
||||||
card->priv = priv;
|
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
|
void
|
||||||
isapnp_set_csn(void *priv, uint8_t csn)
|
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 = {
|
static const device_t isapnp_device = {
|
||||||
"ISA Plug and Play",
|
"ISA Plug and Play",
|
||||||
DEVICE_ISA,
|
0,
|
||||||
0,
|
0,
|
||||||
isapnp_init, isapnp_close, NULL,
|
isapnp_init, isapnp_close, NULL,
|
||||||
{ NULL }, NULL, NULL,
|
{ NULL }, NULL, NULL,
|
||||||
|
|||||||
Reference in New Issue
Block a user