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*)§or_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