aboutsummaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/android_arm.c21
-rw-r--r--hw/goldfish_device.h6
-rw-r--r--hw/goldfish_mmc.c78
3 files changed, 89 insertions, 16 deletions
diff --git a/hw/android_arm.c b/hw/android_arm.c
index 32f6925..4ef4a10 100644
--- a/hw/android_arm.c
+++ b/hw/android_arm.c
@@ -42,7 +42,18 @@ static struct goldfish_device nand_device = {
/* Board init. */
-#define TEST_SWITCH 1
+static void goldfish_sdcard_init(int n, unsigned base)
+{
+ int idx = drive_get_index( IF_IDE, 0, n );
+
+ goldfish_mmc_init(base, n);
+
+ if (idx >= 0) {
+ goldfish_mmc_insert(n, drives_table[idx].bdrv);
+ }
+}
+
+// #define TEST_SWITCH 1
#if TEST_SWITCH
uint32_t switch_test_write(void *opaque, uint32_t state)
{
@@ -113,11 +124,9 @@ static void android_arm_init_(ram_addr_t ram_size,
#ifdef HAS_AUDIO
goldfish_audio_init(0xff004000, 0, audio_input_source);
#endif
- {
- int idx = drive_get_index( IF_IDE, 0, 0 );
- if (idx >= 0)
- goldfish_mmc_init(0xff005000, 0, drives_table[idx].bdrv);
- }
+
+ goldfish_sdcard_init(0, 0xff005000);
+ goldfish_sdcard_init(1, 0xff007000);
goldfish_memlog_init(0xff006000);
diff --git a/hw/goldfish_device.h b/hw/goldfish_device.h
index d04a166..7eb21de 100644
--- a/hw/goldfish_device.h
+++ b/hw/goldfish_device.h
@@ -46,7 +46,11 @@ void goldfish_audio_init(uint32_t base, int id, const char* input_source);
void goldfish_battery_init();
void goldfish_battery_set_prop(int ac, int property, int value);
void goldfish_battery_display(void (* callback)(void *data, const char* string), void *data);
-void goldfish_mmc_init(uint32_t base, int id, BlockDriverState* bs);
+
+void goldfish_mmc_init(uint32_t base, int id);
+void goldfish_mmc_insert(int id, BlockDriverState* bs);
+void goldfish_mmc_remove(int id, BlockDriverState *bs);
+
void *goldfish_switch_add(char *name, uint32_t (*writefn)(void *opaque, uint32_t state), void *writeopaque, int id);
void goldfish_switch_set_state(void *opaque, uint32_t state);
diff --git a/hw/goldfish_mmc.c b/hw/goldfish_mmc.c
index 3824db9..124f865 100644
--- a/hw/goldfish_mmc.c
+++ b/hw/goldfish_mmc.c
@@ -52,6 +52,7 @@ enum {
MMC_STAT_END_OF_CMD = 1U << 0,
MMC_STAT_END_OF_DATA = 1U << 1,
MMC_STAT_STATE_CHANGE = 1U << 2,
+ MMC_STAT_CMD_TIMEOUT = 1U << 3,
/* MMC_STATE bits */
MMC_STATE_INSERTED = 1U << 0,
@@ -82,6 +83,9 @@ struct goldfish_mmc_state {
uint8_t* buf;
};
+#define GOLDFISH_MMC_MAX 2
+static struct goldfish_mmc_state *gDrvState[GOLDFISH_MMC_MAX];
+
#define GOLDFISH_MMC_SAVE_VERSION 2
#define QFIELD_STRUCT struct goldfish_mmc_state
QFIELD_BEGIN(goldfish_mmc_fields)
@@ -218,13 +222,24 @@ static void goldfish_mmc_do_command(struct goldfish_mmc_state *s, uint32_t cmd,
int new_status = MMC_STAT_END_OF_CMD;
int opcode = cmd & 63;
-// fprintf(stderr, "goldfish_mmc_do_command opcode: %s (0x%04X), arg: %d\n", get_command_name(opcode), cmd, arg);
-
+ //fprintf(stderr, "goldfish_mmc_do_command opcode: %s (0x%04X), arg: %d\n", get_command_name(opcode), cmd, arg);
s->resp[0] = 0;
s->resp[1] = 0;
s->resp[2] = 0;
s->resp[3] = 0;
+ if (!s->bs) {
+ /*
+ * No backing store available. Signal a command timeout
+ * to the host. If the command timeout irq enable is set
+ * then also set the status bit - otherwise we're assuming
+ * a legacy driver which doesnt support timeouts.
+ */
+ if (s->int_enable & MMC_STAT_CMD_TIMEOUT)
+ new_status |= MMC_STAT_CMD_TIMEOUT;
+ goto skip;
+ }
+
#define SET_R1_CURRENT_STATE(s) ((s << 9) & 0x00001E00) /* sx, b (4 bits) */
switch (opcode) {
@@ -405,6 +420,7 @@ static void goldfish_mmc_do_command(struct goldfish_mmc_state *s, uint32_t cmd,
break;
}
+ skip:
s->int_status |= new_status;
if ((s->int_status & s->int_enable)) {
@@ -414,7 +430,7 @@ static void goldfish_mmc_do_command(struct goldfish_mmc_state *s, uint32_t cmd,
static uint32_t goldfish_mmc_read(void *opaque, target_phys_addr_t offset)
{
- uint32_t ret;
+ uint32_t ret = 0;
struct goldfish_mmc_state *s = opaque;
switch(offset) {
@@ -430,9 +446,11 @@ static uint32_t goldfish_mmc_read(void *opaque, target_phys_addr_t offset)
case MMC_RESP_3:
return s->resp[3];
case MMC_STATE: {
- ret = MMC_STATE_INSERTED;
- if (bdrv_is_read_only(s->bs)) {
- ret |= MMC_STATE_READ_ONLY;
+ if (s->bs) {
+ ret = MMC_STATE_INSERTED;
+ if (bdrv_is_read_only(s->bs)) {
+ ret |= MMC_STATE_READ_ONLY;
+ }
}
return ret;
}
@@ -499,22 +517,64 @@ static CPUWriteMemoryFunc *goldfish_mmc_writefn[] = {
goldfish_mmc_write
};
-void goldfish_mmc_init(uint32_t base, int id, BlockDriverState* bs)
+void goldfish_mmc_init(uint32_t base, int id)
{
struct goldfish_mmc_state *s;
+ if (id >= GOLDFISH_MMC_MAX) {
+ fprintf(stderr, "mmc controller %d out of range\n", id);
+ return;
+ }
+
s = (struct goldfish_mmc_state *)qemu_mallocz(sizeof(*s));
s->dev.name = "goldfish_mmc";
s->dev.id = id;
s->dev.base = base;
s->dev.size = 0x1000;
s->dev.irq_count = 1;
- s->bs = bs;
+ s->bs = NULL;
s->buf = qemu_memalign(512,512);
+ gDrvState[id] = s;
+
goldfish_device_add(&s->dev, goldfish_mmc_readfn, goldfish_mmc_writefn, s);
- register_savevm( "goldfish_mmc", 0, GOLDFISH_MMC_SAVE_VERSION,
+ register_savevm( (!id ? "goldfish_mmc0" : "goldfish_mmc1"),
+ id, GOLDFISH_MMC_SAVE_VERSION,
goldfish_mmc_save, goldfish_mmc_load, s);
}
+static void goldfish_mmc_setbs(struct goldfish_mmc_state* s, BlockDriverState* bs)
+{
+ s->bs = bs;
+ s->int_status |= MMC_STAT_STATE_CHANGE;
+
+ /*
+ * Legacy - only send state change irq if
+ * the driver has the CMD_TIMEOUT irq enabled.
+ */
+ if (s->int_enable & MMC_STAT_CMD_TIMEOUT)
+ goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+}
+
+void goldfish_mmc_insert(int id, BlockDriverState* bs)
+{
+ if (id >= GOLDFISH_MMC_MAX) {
+ fprintf(stderr, "mmc controller %d out of range\n", id);
+ return;
+ }
+
+ goldfish_mmc_setbs(gDrvState[id], bs);
+}
+
+void goldfish_mmc_remove(int id, BlockDriverState* bs)
+{
+ if (id >= GOLDFISH_MMC_MAX) {
+ fprintf(stderr, "mmc controller %d out of range\n", id);
+ return;
+ }
+
+ goldfish_mmc_setbs(gDrvState[id], NULL);
+}
+
+