diff options
Diffstat (limited to 'hw/ide/microdrive.c')
-rw-r--r-- | hw/ide/microdrive.c | 170 |
1 files changed, 123 insertions, 47 deletions
diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 92c1df0..cdf0eb9 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -30,15 +30,22 @@ #include <hw/ide/internal.h> +#define TYPE_MICRODRIVE "microdrive" +#define MICRODRIVE(obj) OBJECT_CHECK(MicroDriveState, (obj), TYPE_MICRODRIVE) + /***********************************************************/ /* CF-ATA Microdrive */ #define METADATA_SIZE 0x20 /* DSCM-1XXXX Microdrive hard disk with CF+ II / PCMCIA interface. */ -typedef struct { + +typedef struct MicroDriveState { + /*< private >*/ + PCMCIACardState parent_obj; + /*< public >*/ + IDEBus bus; - PCMCIACardState card; uint32_t attr_base; uint32_t io_base; @@ -81,10 +88,13 @@ enum md_ctrl { static inline void md_interrupt_update(MicroDriveState *s) { - if (!s->card.slot) + PCMCIACardState *card = PCMCIA_CARD(s); + + if (card->slot == NULL) { return; + } - qemu_set_irq(s->card.slot->irq, + qemu_set_irq(card->slot->irq, !(s->stat & STAT_INT) && /* Inverted */ !(s->ctrl & (CTRL_IEN | CTRL_SRST)) && !(s->opt & OPT_SRESET)); @@ -101,8 +111,10 @@ static void md_set_irq(void *opaque, int irq, int level) md_interrupt_update(s); } -static void md_reset(MicroDriveState *s) +static void md_reset(DeviceState *dev) { + MicroDriveState *s = MICRODRIVE(dev); + s->opt = OPT_MODE_MMAP; s->stat = 0; s->pins = 0; @@ -111,14 +123,17 @@ static void md_reset(MicroDriveState *s) ide_bus_reset(&s->bus); } -static uint8_t md_attr_read(void *opaque, uint32_t at) +static uint8_t md_attr_read(PCMCIACardState *card, uint32_t at) { - MicroDriveState *s = opaque; + MicroDriveState *s = MICRODRIVE(card); + PCMCIACardClass *pcc = PCMCIA_CARD_GET_CLASS(card); + if (at < s->attr_base) { - if (at < s->card.cis_len) - return s->card.cis[at]; - else + if (at < pcc->cis_len) { + return pcc->cis[at]; + } else { return 0x00; + } } at -= s->attr_base; @@ -144,16 +159,18 @@ static uint8_t md_attr_read(void *opaque, uint32_t at) return 0; } -static void md_attr_write(void *opaque, uint32_t at, uint8_t value) +static void md_attr_write(PCMCIACardState *card, uint32_t at, uint8_t value) { - MicroDriveState *s = opaque; + MicroDriveState *s = MICRODRIVE(card); + at -= s->attr_base; switch (at) { case 0x00: /* Configuration Option Register */ s->opt = value & 0xcf; - if (value & OPT_SRESET) - md_reset(s); + if (value & OPT_SRESET) { + device_reset(DEVICE(s)); + } md_interrupt_update(s); break; case 0x02: /* Card Configuration Status Register */ @@ -175,9 +192,9 @@ static void md_attr_write(void *opaque, uint32_t at, uint8_t value) } } -static uint16_t md_common_read(void *opaque, uint32_t at) +static uint16_t md_common_read(PCMCIACardState *card, uint32_t at) { - MicroDriveState *s = opaque; + MicroDriveState *s = MICRODRIVE(card); IDEState *ifs; uint16_t ret; at -= s->io_base; @@ -237,9 +254,9 @@ static uint16_t md_common_read(void *opaque, uint32_t at) return 0; } -static void md_common_write(void *opaque, uint32_t at, uint16_t value) +static void md_common_write(PCMCIACardState *card, uint32_t at, uint16_t value) { - MicroDriveState *s = opaque; + MicroDriveState *s = MICRODRIVE(card); at -= s->io_base; switch (s->opt & OPT_MODE) { @@ -285,8 +302,9 @@ static void md_common_write(void *opaque, uint32_t at, uint16_t value) break; case 0xe: /* Device Control */ s->ctrl = value; - if (value & CTRL_SRST) - md_reset(s); + if (value & CTRL_SRST) { + device_reset(DEVICE(s)); + } md_interrupt_update(s); break; default: @@ -501,49 +519,107 @@ static const uint8_t dscm1xxxx_cis[0x14a] = { [0x146] = CISTPL_END, /* Tuple End */ }; -static int dscm1xxxx_attach(void *opaque) +#define TYPE_DSCM1XXXX "dscm1xxxx" + +static int dscm1xxxx_attach(PCMCIACardState *card) { - MicroDriveState *md = opaque; - md->card.attr_read = md_attr_read; - md->card.attr_write = md_attr_write; - md->card.common_read = md_common_read; - md->card.common_write = md_common_write; - md->card.io_read = md_common_read; - md->card.io_write = md_common_write; - - md->attr_base = md->card.cis[0x74] | (md->card.cis[0x76] << 8); + MicroDriveState *md = MICRODRIVE(card); + PCMCIACardClass *pcc = PCMCIA_CARD_GET_CLASS(card); + + md->attr_base = pcc->cis[0x74] | (pcc->cis[0x76] << 8); md->io_base = 0x0; - md_reset(md); + device_reset(DEVICE(md)); md_interrupt_update(md); - md->card.slot->card_string = "DSCM-1xxxx Hitachi Microdrive"; + card->slot->card_string = "DSCM-1xxxx Hitachi Microdrive"; return 0; } -static int dscm1xxxx_detach(void *opaque) +static int dscm1xxxx_detach(PCMCIACardState *card) { - MicroDriveState *md = opaque; - md_reset(md); + MicroDriveState *md = MICRODRIVE(card); + + device_reset(DEVICE(md)); return 0; } -PCMCIACardState *dscm1xxxx_init(DriveInfo *bdrv) +PCMCIACardState *dscm1xxxx_init(DriveInfo *dinfo) { - MicroDriveState *md = (MicroDriveState *) g_malloc0(sizeof(MicroDriveState)); - md->card.state = md; - md->card.attach = dscm1xxxx_attach; - md->card.detach = dscm1xxxx_detach; - md->card.cis = dscm1xxxx_cis; - md->card.cis_len = sizeof(dscm1xxxx_cis); - - ide_init2_with_non_qdev_drives(&md->bus, bdrv, NULL, - qemu_allocate_irqs(md_set_irq, md, 1)[0]); + MicroDriveState *md = MICRODRIVE(object_new(TYPE_DSCM1XXXX)); + PCMCIACardState *card = PCMCIA_CARD(md); + + if (dinfo != NULL) { + ide_create_drive(&md->bus, 0, dinfo); + } md->bus.ifs[0].drive_kind = IDE_CFATA; md->bus.ifs[0].mdata_size = METADATA_SIZE; md->bus.ifs[0].mdata_storage = (uint8_t *) g_malloc0(METADATA_SIZE); - vmstate_register(NULL, -1, &vmstate_microdrive, md); + return card; +} + +static void dscm1xxxx_class_init(ObjectClass *oc, void *data) +{ + PCMCIACardClass *pcc = PCMCIA_CARD_CLASS(oc); + + pcc->cis = dscm1xxxx_cis; + pcc->cis_len = sizeof(dscm1xxxx_cis); + + pcc->attach = dscm1xxxx_attach; + pcc->detach = dscm1xxxx_detach; +} + +static const TypeInfo dscm1xxxx_type_info = { + .name = TYPE_DSCM1XXXX, + .parent = TYPE_MICRODRIVE, + .class_init = dscm1xxxx_class_init, +}; + +static void microdrive_realize(DeviceState *dev, Error **errp) +{ + MicroDriveState *md = MICRODRIVE(dev); + + ide_init2(&md->bus, qemu_allocate_irqs(md_set_irq, md, 1)[0]); +} + +static void microdrive_init(Object *obj) +{ + MicroDriveState *md = MICRODRIVE(obj); + + ide_bus_new(&md->bus, sizeof(md->bus), DEVICE(obj), 0, 1); +} - return &md->card; +static void microdrive_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PCMCIACardClass *pcc = PCMCIA_CARD_CLASS(oc); + + pcc->attr_read = md_attr_read; + pcc->attr_write = md_attr_write; + pcc->common_read = md_common_read; + pcc->common_write = md_common_write; + pcc->io_read = md_common_read; + pcc->io_write = md_common_write; + + dc->realize = microdrive_realize; + dc->reset = md_reset; + dc->vmsd = &vmstate_microdrive; } + +static const TypeInfo microdrive_type_info = { + .name = TYPE_MICRODRIVE, + .parent = TYPE_PCMCIA_CARD, + .instance_size = sizeof(MicroDriveState), + .instance_init = microdrive_init, + .abstract = true, + .class_init = microdrive_class_init, +}; + +static void microdrive_register_types(void) +{ + type_register_static(µdrive_type_info); + type_register_static(&dscm1xxxx_type_info); +} + +type_init(microdrive_register_types) |