18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Copyright (C) 2007-2008 The Android Open Source Project
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This software is licensed under the terms of the GNU General Public
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** License version 2, as published by the Free Software Foundation, and
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** may be copied, distributed, and modified under those terms.
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This program is distributed in the hope that it will be useful,
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** but WITHOUT ANY WARRANTY; without even the implied warranty of
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** GNU General Public License for more details.
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project*/
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu_file.h"
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "goldfish_device.h"
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "mmc.h"
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "sd.h"
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "block.h"
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectenum {
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* status register */
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_INT_STATUS          = 0x00,
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* set this to enable IRQ */
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_INT_ENABLE          = 0x04,
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* set this to specify buffer address */
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_SET_BUFFER          = 0x08,
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* MMC command number */
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_CMD                 = 0x0C,
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* MMC argument */
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_ARG                 = 0x10,
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* MMC response (or R2 bits 0 - 31) */
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_RESP_0              = 0x14,
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* MMC R2 response bits 32 - 63 */
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_RESP_1              = 0x18,
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* MMC R2 response bits 64 - 95 */
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_RESP_2              = 0x1C,
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* MMC R2 response bits 96 - 127 */
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_RESP_3              = 0x20,
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_BLOCK_LENGTH        = 0x24,
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_BLOCK_COUNT         = 0x28,
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* MMC state flags */
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_STATE               = 0x2C,
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* MMC_INT_STATUS bits */
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_STAT_END_OF_CMD     = 1U << 0,
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_STAT_END_OF_DATA    = 1U << 1,
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_STAT_STATE_CHANGE   = 1U << 2,
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* MMC_STATE bits */
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_STATE_INSERTED     = 1U << 0,
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    MMC_STATE_READ_ONLY     = 1U << 1,
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct goldfish_mmc_state {
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct goldfish_device dev;
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BlockDriverState *bs;
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    // pointer to our buffer
665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t buffer_address;
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    // offsets for read and write operations
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t read_offset, write_offset;
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    // buffer status flags
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t int_status;
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    // irq enable mask for int_status
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t int_enable;
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    // MMC command argument
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t arg;
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t resp[4];
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t block_length;
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t block_count;
808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int is_SDHC;
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t* buf;
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define  GOLDFISH_MMC_SAVE_VERSION  2
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  QFIELD_STRUCT  struct goldfish_mmc_state
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectQFIELD_BEGIN(goldfish_mmc_fields)
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QFIELD_INT32(buffer_address),
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(read_offset),
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(write_offset),
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(int_status),
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(int_enable),
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(arg),
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(resp[0]),
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(resp[1]),
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(resp[2]),
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(resp[3]),
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(block_length),
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(block_count),
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QFIELD_INT32(is_SDHC),
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectQFIELD_END
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void  goldfish_mmc_save(QEMUFile*  f, void*  opaque)
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct goldfish_mmc_state*  s = opaque;
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_struct(f, goldfish_mmc_fields, s);
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int  goldfish_mmc_load(QEMUFile*  f, void*  opaque, int  version_id)
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct goldfish_mmc_state*  s = opaque;
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (version_id != GOLDFISH_MMC_SAVE_VERSION)
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -1;
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return qemu_get_struct(f, goldfish_mmc_fields, s);
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct mmc_opcode {
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char* name;
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int cmd;
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} mmc_opcodes[] = {
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_GO_IDLE_STATE",         0  },
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SEND_OP_COND",          1  },
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_ALL_SEND_CID",          2  },
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SET_RELATIVE_ADDR",     3  },
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SET_DSR",               4  },
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SWITCH",                6  },
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SELECT_CARD",           7  },
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SEND_EXT_CSD",          8  },
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SEND_CSD",              9  },
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SEND_CID",             10  },
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_READ_DAT_UNTIL_STOP",  11  },
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_STOP_TRANSMISSION",    12  },
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SEND_STATUS",          13  },
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_GO_INACTIVE_STATE",    15  },
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SET_BLOCKLEN",         16  },
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_READ_SINGLE_BLOCK",    17  },
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_READ_MULTIPLE_BLOCK",  18  },
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_WRITE_DAT_UNTIL_STOP", 20  },
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SET_BLOCK_COUNT",      23  },
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_WRITE_BLOCK",          24  },
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_WRITE_MULTIPLE_BLOCK", 25  },
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_PROGRAM_CID",          26  },
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_PROGRAM_CSD",          27  },
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SET_WRITE_PROT",       28  },
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_CLR_WRITE_PROT",       29  },
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_SEND_WRITE_PROT",      30  },
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_ERASE_GROUP_START",    35  },
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_ERASE_GROUP_END",      36  },
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_ERASE",                38  },
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_FAST_IO",              39  },
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_GO_IRQ_STATE",         40  },
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_LOCK_UNLOCK",          42  },
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_APP_CMD",              55  },
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "MMC_GEN_CMD",              56  },
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "SD_APP_OP_COND",           41  },
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "SD_APP_SEND_SCR",          51  },
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    { "UNKNOWN",                  -1  }
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if 0
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic const char* get_command_name(int command)
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct mmc_opcode* opcode = mmc_opcodes;
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (opcode->cmd != command && opcode->cmd != -1) opcode++;
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return opcode->name;
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int  goldfish_mmc_bdrv_read(struct goldfish_mmc_state *s,
1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   int64_t                    sector_number,
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   target_phys_addr_t         dst_address,
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   int                        num_sectors)
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int  ret;
1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (num_sectors > 0) {
1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = bdrv_read(s->bs, sector_number, s->buf, 1);
1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret < 0)
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return ret;
1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        cpu_physical_memory_write(dst_address, s->buf, 512);
1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        dst_address   += 512;
1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        num_sectors   -= 1;
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sector_number += 1;
1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int  goldfish_mmc_bdrv_write(struct goldfish_mmc_state *s,
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                    int64_t                    sector_number,
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                    target_phys_addr_t         dst_address,
1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                    int                        num_sectors)
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int  ret;
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (num_sectors > 0) {
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        cpu_physical_memory_read(dst_address, s->buf, 512);
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = bdrv_write(s->bs, sector_number, s->buf, 1);
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret < 0)
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return ret;
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        dst_address   += 512;
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        num_sectors   -= 1;
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sector_number += 1;
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void goldfish_mmc_do_command(struct goldfish_mmc_state *s, uint32_t cmd, uint32_t arg)
2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int result;
2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int new_status = MMC_STAT_END_OF_CMD;
2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int opcode = cmd & 63;
2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22192568958dd42bf35667cc6451b5edd7f7d1f73a1David 'Digit' Turner// fprintf(stderr, "goldfish_mmc_do_command opcode: %s (0x%04X), arg: %d\n", get_command_name(opcode), cmd, arg);
22292568958dd42bf35667cc6451b5edd7f7d1f73a1David 'Digit' Turner
2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->resp[0] = 0;
2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->resp[1] = 0;
2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->resp[2] = 0;
2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->resp[3] = 0;
2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define SET_R1_CURRENT_STATE(s)    ((s << 9) & 0x00001E00) /* sx, b (4 bits) */
2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (opcode) {
2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_SEND_CSD: {
2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            int64_t sector_count = 0;
2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            uint64_t capacity;
2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            uint8_t exponent;
2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            uint32_t m;
2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            bdrv_get_geometry(s->bs, (uint64_t*)&sector_count);
2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            capacity = sector_count * 512;
2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (capacity > 2147483648U) {
2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // if storages is > 2 gig, then emulate SDHC card
2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->is_SDHC = 1;
2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // CSD bits borrowed from a real SDHC card, with capacity bits zeroed out
2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[3] = 0x400E0032;
2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[2] = 0x5B590000;
2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[1] = 0x00007F80;
2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[0] = 0x0A4040DF;
2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // stuff in the real capacity
2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // m = UNSTUFF_BITS(resp, 48, 22);
2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                m = (uint32_t)(capacity / (512*1024)) - 1;
2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // m must fit into 22 bits
2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (m & 0xFFC00000) {
254d9b6cb97a8a9e93f1bbe5351874b03f7faa81783David 'Digit' Turner                    fprintf(stderr, "SD card too big (%lld bytes).  Maximum SDHC card size is 128 gigabytes.\n", (long long)capacity);
2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    abort();
2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                }
2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // low 16 bits go in high end of resp[1]
2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[1] |= ((m & 0x0000FFFF) << 16);
2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // high 6 bits go in low end of resp[2]
2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[2] |= (m >> 16);
2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            } else {
2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // emulate standard SD card
2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->is_SDHC = 0;
2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // CSD bits borrowed from a real SD card, with capacity bits zeroed out
2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[3] = 0x00260032;
2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[2] = 0x5F5A8000;
2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[1] = 0x3EF84FFF;
2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[0] = 0x928040CB;
2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // stuff in the real capacity
2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // e = UNSTUFF_BITS(resp, 47, 3);
2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // m = UNSTUFF_BITS(resp, 62, 12);
2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // csd->capacity = (1 + m) << (e + 2);
2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // need to reverse the formula and calculate e and m
2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                exponent = 0;
2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                capacity = sector_count * 512;
2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (capacity > 2147483648U) {
280d9b6cb97a8a9e93f1bbe5351874b03f7faa81783David 'Digit' Turner                    fprintf(stderr, "SD card too big (%lld bytes).  Maximum SD card size is 2 gigabytes.\n", (long long)capacity);
2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    abort();
2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                }
2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                capacity >>= 10; // convert to Kbytes
2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                while (capacity > 4096) {
2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    // (capacity - 1) must fit into 12 bits
2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    exponent++;
2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    capacity >>= 1;
2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                }
2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                capacity -= 1;
2908b657e5deaa03b989b0b36791fcf2aa6b2882656David 'Digit' Turner                if (exponent < 2) {
2918b657e5deaa03b989b0b36791fcf2aa6b2882656David 'Digit' Turner                    cpu_abort(cpu_single_env, "SDCard too small, must be at least 9MB\n");
2928b657e5deaa03b989b0b36791fcf2aa6b2882656David 'Digit' Turner                }
2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                exponent -= 2;
2948b657e5deaa03b989b0b36791fcf2aa6b2882656David 'Digit' Turner                if (exponent > 7) {
2958b657e5deaa03b989b0b36791fcf2aa6b2882656David 'Digit' Turner                    cpu_abort(cpu_single_env, "SDCard too large.\n");
2968b657e5deaa03b989b0b36791fcf2aa6b2882656David 'Digit' Turner                }
2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[2] |= (((uint32_t)capacity >> 2) & 0x3FF);  // high 10 bits to bottom of resp[2]
2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[1] |= (((uint32_t)capacity & 3) << 30);    // low 2 bits to top of resp[1]
3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->resp[1] |= (exponent << (47 - 32));
3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_SEND_EXT_CSD:
3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = arg;
3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_APP_CMD:
3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA | R1_APP_CMD; //2336
3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case SD_APP_OP_COND:
3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = 0x80FF8000;
3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case SD_APP_SEND_SCR:
3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        {
3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if 1 /* this code is actually endian-safe */
3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            const uint8_t  scr[8] = "\x02\x25\x00\x00\x00\x00\x00\x00";
3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else /* this original code wasn't */
3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            uint32_t scr[2];
3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            scr[0] = 0x00002502;
3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            scr[1] = 0x00000000;
3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            cpu_physical_memory_write(s->buffer_address, (uint8_t*)scr, 8);
3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA | R1_APP_CMD; //2336
3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            new_status |= MMC_STAT_END_OF_DATA;
3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_SET_RELATIVE_ADDR:
3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = -518519520;
3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_ALL_SEND_CID:
3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[3] = 55788627;
3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[2] = 1429221959;
3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[1] = -2147479692;
3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = -436179883;
3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_SELECT_CARD:
3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = SET_R1_CURRENT_STATE(3) | R1_READY_FOR_DATA; // 1792
3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project         case MMC_SWITCH:
3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (arg == 0x00FFFFF1 || arg == 0x80FFFFF1) {
3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                uint8_t  buff0[64];
3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                memset(buff0, 0, sizeof buff0);
3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                buff0[13] = 2;
3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                cpu_physical_memory_write(s->buffer_address, buff0, sizeof buff0);
3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                new_status |= MMC_STAT_END_OF_DATA;
3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA | R1_APP_CMD; //2336
3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project         case MMC_SET_BLOCKLEN:
3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->block_length = arg;
3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304
3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_READ_SINGLE_BLOCK:
3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->block_count = 1;
3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            // fall through
3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_READ_MULTIPLE_BLOCK: {
3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (s->is_SDHC) {
3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // arg is block offset
3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            } else {
3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // arg is byte offset
3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (arg & 511) fprintf(stderr, "offset %d is not multiple of 512 when reading\n", arg);
3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                arg /= s->block_length;
3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            result = goldfish_mmc_bdrv_read(s, arg, s->buffer_address, s->block_count);
3758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            new_status |= MMC_STAT_END_OF_DATA;
3768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304
3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_WRITE_BLOCK:
3818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->block_count = 1;
3828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            // fall through
3838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_WRITE_MULTIPLE_BLOCK: {
3848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (s->is_SDHC) {
3858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // arg is block offset
3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            } else {
3878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                // arg is byte offset
3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (arg & 511) fprintf(stderr, "offset %d is not multiple of 512 when writing\n", arg);
3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                arg /= s->block_length;
3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            // arg is byte offset
3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            result = goldfish_mmc_bdrv_write(s, arg, s->buffer_address, s->block_count);
3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project//            bdrv_flush(s->bs);
3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            new_status |= MMC_STAT_END_OF_DATA;
3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304
3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_STOP_TRANSMISSION:
4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = SET_R1_CURRENT_STATE(5) | R1_READY_FOR_DATA; // 2816
4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_SEND_STATUS:
4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304
4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     }
4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->int_status |= new_status;
4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ((s->int_status & s->int_enable)) {
4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t goldfish_mmc_read(void *opaque, target_phys_addr_t offset)
4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
41792568958dd42bf35667cc6451b5edd7f7d1f73a1David 'Digit' Turner    uint32_t ret;
4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct goldfish_mmc_state *s = opaque;
4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch(offset) {
4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_INT_STATUS:
4228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            // return current buffer status flags
4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return s->int_status & s->int_enable;
4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_RESP_0:
4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return s->resp[0];
4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_RESP_1:
4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return s->resp[1];
4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_RESP_2:
4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return s->resp[2];
4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_RESP_3:
4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return s->resp[3];
4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_STATE: {
43392568958dd42bf35667cc6451b5edd7f7d1f73a1David 'Digit' Turner            ret = MMC_STATE_INSERTED;
43492568958dd42bf35667cc6451b5edd7f7d1f73a1David 'Digit' Turner            if (bdrv_is_read_only(s->bs)) {
43592568958dd42bf35667cc6451b5edd7f7d1f73a1David 'Digit' Turner                ret |= MMC_STATE_READ_ONLY;
4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return ret;
4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        default:
4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            cpu_abort(cpu_single_env, "goldfish_mmc_read: Bad offset %x\n", offset);
4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 0;
4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void goldfish_mmc_write(void *opaque, target_phys_addr_t offset, uint32_t val)
4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct goldfish_mmc_state *s = opaque;
4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int status, old_status;
4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch(offset) {
4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_INT_STATUS:
4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            status = s->int_status;
4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            old_status = status;
4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            status &= ~val;
4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->int_status = status;
4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if(status != old_status) {
4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                goldfish_device_set_irq(&s->dev, 0, status);
4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_INT_ENABLE:
4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* enable buffer interrupts */
4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->int_enable = val;
4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->int_status = 0;
4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_SET_BUFFER:
4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* save pointer to buffer 1 */
4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            s->buffer_address = val;
4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_CMD:
4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goldfish_mmc_do_command(s, val, s->arg);
4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_ARG:
4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->arg = val;
4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_BLOCK_LENGTH:
4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->block_length = val + 1;
4808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case MMC_BLOCK_COUNT:
4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->block_count = val + 1;
4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        default:
4868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            cpu_abort (cpu_single_env, "goldfish_mmc_write: Bad offset %x\n", offset);
4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUReadMemoryFunc *goldfish_mmc_readfn[] = {
4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   goldfish_mmc_read,
4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   goldfish_mmc_read,
4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   goldfish_mmc_read
4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUWriteMemoryFunc *goldfish_mmc_writefn[] = {
4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   goldfish_mmc_write,
4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   goldfish_mmc_write,
4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   goldfish_mmc_write
5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
50292568958dd42bf35667cc6451b5edd7f7d1f73a1David 'Digit' Turnervoid goldfish_mmc_init(uint32_t base, int id, BlockDriverState* bs)
5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct goldfish_mmc_state *s;
5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s = (struct goldfish_mmc_state *)qemu_mallocz(sizeof(*s));
5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.name = "goldfish_mmc";
5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.id = id;
5098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.base = base;
5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.size = 0x1000;
5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dev.irq_count = 1;
51292568958dd42bf35667cc6451b5edd7f7d1f73a1David 'Digit' Turner    s->bs = bs;
5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->buf = qemu_memalign(512,512);
5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    goldfish_device_add(&s->dev, goldfish_mmc_readfn, goldfish_mmc_writefn, s);
5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
51792568958dd42bf35667cc6451b5edd7f7d1f73a1David 'Digit' Turner    register_savevm( "goldfish_mmc", 0, GOLDFISH_MMC_SAVE_VERSION,
5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                     goldfish_mmc_save, goldfish_mmc_load, s);
5198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
521