diff --git a/headers/private/drivers/mmc.h b/headers/private/drivers/mmc.h index af105f1e0f..43f3910486 100644 --- a/headers/private/drivers/mmc.h +++ b/headers/private/drivers/mmc.h @@ -25,6 +25,37 @@ enum { }; +// Commands for SD cards defined in SD Specifications Part 1: +// Physical Layer Simplified Specification Version 8.00 +// They are in the common .h file for the mmc stack because the SDHCI driver +// currently needs to map them to the corresponding expected response types. +enum SD_COMMANDS { + // Basic commands, class 0 + SD_GO_IDLE_STATE = 0, + SD_ALL_SEND_CID = 2, + SD_SEND_RELATIVE_ADDR = 3, + SD_SELECT_DESELECT_CARD = 7, + SD_SEND_IF_COND = 8, + SD_SEND_CSD = 9, + SD_STOP_TRANSMISSION = 12, + + // Block oriented read commands, class 2 + SD_READ_SINGLE_BLOCK = 17, + SD_READ_MULTIPLE_BLOCKS = 18, + + // Application specific commands, class 8 + SD_APP_CMD = 55, + + // I/O mode commands, class 9 + SD_IO_ABORT = 52, +}; + + +enum SDHCI_APPLICATION_COMMANDS { + SD_SEND_OP_COND = 41, +}; + + // Interface between mmc_bus and underlying implementation (sdhci_pci or any // other thing that can execute mmc commands) typedef struct mmc_bus_interface { @@ -33,15 +64,18 @@ typedef struct mmc_bus_interface { status_t (*set_clock)(void* controller, uint32_t kilohertz); status_t (*execute_command)(void* controller, uint8_t command, uint32_t argument, uint32_t* result); + status_t (*read_naive)(void* controller, off_t pos, + void* buffer, size_t* _length); } mmc_bus_interface; // Interface between mmc device driver (mmc_disk, sdio drivers, ...) and mmc_bus typedef struct mmc_device_interface { driver_module_info info; - status_t (*execute_command)(device_node* node, uint8_t command, uint32_t argument, uint32_t* result); + status_t (*read_naive)(device_node* controller, uint16_t rca, off_t pos, + void* buffer, size_t* _length); } mmc_device_interface; diff --git a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp index 339d156bff..de625f0e1e 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp @@ -18,7 +18,8 @@ MMCBus::MMCBus(device_node* node) fController(NULL), fCookie(NULL), fStatus(B_OK), - fWorkerThread(0) + fWorkerThread(-1), + fActiveDevice(0) { CALLED(); @@ -34,8 +35,9 @@ MMCBus::MMCBus(device_node* node) return; } - fSemaphore = create_sem(0, "MMC bus scan"); - fWorkerThread = spawn_kernel_thread(WorkerThread, "SD bus controller", + fScanSemaphore = create_sem(0, "MMC bus scan"); + fLockSemaphore = create_sem(1, "MMC bus lock"); + fWorkerThread = spawn_kernel_thread(_WorkerThread, "SD bus controller", B_NORMAL_PRIORITY, this); resume_thread(fWorkerThread); } @@ -52,6 +54,9 @@ MMCBus::~MMCBus() if (fWorkerThread != 0) wait_for_thread(fWorkerThread, &result); // TODO power off cards, stop clock, etc if needed. + + delete_sem(fLockSemaphore); + delete_sem(fScanSemaphore); } @@ -66,41 +71,90 @@ void MMCBus::Rescan() { // Just wake up the thread for a scan - release_sem(fSemaphore); + release_sem(fScanSemaphore); } status_t MMCBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) { + status_t status = _ActivateDevice(0); + if (status != B_OK) + return status; return fController->execute_command(fCookie, command, argument, response); } status_t -MMCBus::WorkerThread(void* cookie) +MMCBus::Read(uint16_t rca, off_t position, void* buffer, size_t* length) +{ + status_t status = _ActivateDevice(rca); + if (status != B_OK) + return status; + return fController->read_naive(fCookie, position, buffer, length); +} + + +status_t +MMCBus::_ActivateDevice(uint16_t rca) +{ + // Do nothing if the device is already activated + if (fActiveDevice == rca) + return B_OK; + + uint32_t response; + status_t result; + result = fController->execute_command(fCookie, SD_SELECT_DESELECT_CARD, + ((uint32)rca) << 16, &response); + + if (result == B_OK) + fActiveDevice = rca; + + return result; +} + + +status_t +MMCBus::_WorkerThread(void* cookie) { MMCBus* bus = (MMCBus*)cookie; uint32_t response; + acquire_sem(bus->fLockSemaphore); + // We assume the bus defaults to 400kHz clock and has already powered on // cards. - + // Reset all cards on the bus - bus->ExecuteCommand(0, 0, NULL); + bus->ExecuteCommand(SD_GO_IDLE_STATE, 0, NULL); while (bus->fStatus != B_SHUTTING_DOWN) { + release_sem(bus->fLockSemaphore); // wait for bus to signal a card is inserted - acquire_sem(bus->fSemaphore); + // Most of the time the thread will be waiting here, with + // fLockSemaphore released + acquire_sem(bus->fScanSemaphore); + acquire_sem(bus->fLockSemaphore); + TRACE("Scanning the bus\n"); // Probe the voltage range + enum { + // Table 4-40 in physical layer specification v8.00 + // All other values are currently reserved + HOST_27_36V = 1, //Host supplied voltage 2.7-3.6V + }; + + // An arbitrary value, we just need to check that the response + // containts the same. + static const uint8 kVoltageCheckPattern = 0xAA; + // FIXME MMC cards will not reply to this! They expect CMD1 instead // SD v1 cards will also not reply, but we can proceed to ACMD41 // If ACMD41 also does not work, it may be an SDIO card, too - uint32_t probe = (1 << 8) | 0xAA; + uint32_t probe = (HOST_27_36V << 8) | kVoltageCheckPattern; uint32_t hcs = 1 << 30; - if (bus->ExecuteCommand(8, probe, &response) != B_OK) { + if (bus->ExecuteCommand(SD_SEND_IF_COND, probe, &response) != B_OK) { TRACE("Card does not implement CMD8, may be a V1 SD card\n"); // Do not check for SDHC support in this case hcs = 0; @@ -114,7 +168,7 @@ MMCBus::WorkerThread(void* cookie) uint32_t ocr; do { uint32_t cardStatus; - while (bus->ExecuteCommand(55, 0, &cardStatus) + while (bus->ExecuteCommand(SD_APP_CMD, 0, &cardStatus) == B_BUSY) { ERROR("Card locked after CMD8...\n"); snooze(1000000); @@ -124,7 +178,7 @@ MMCBus::WorkerThread(void* cookie) if ((cardStatus & (1 << 5)) == 0) ERROR("Card did not enter ACMD mode\n"); - bus->ExecuteCommand(41, hcs | 0xFF8000, &ocr); + bus->ExecuteCommand(SD_SEND_OP_COND, hcs | 0xFF8000, &ocr); if ((ocr & (1 << 31)) == 0) { TRACE("Card is busy\n"); @@ -146,11 +200,17 @@ MMCBus::WorkerThread(void* cookie) // TODO send CMD11 to switch to low voltage mode if card supports it? - // iterate CMD2/CMD3 to assign an RCA to all cards and publish devices - // for each of them + // We use CMD2 (ALL_SEND_CID) and CMD3 (SEND_RELATIVE_ADDR) to assign + // an RCA to all cards. Initially all cards have an RCA of 0 and will + // all receive CMD2. But only ne of them will reply (they do collision + // detection while sending the CID in reply). We assign a new RCA to + // that first card, and repeat the process with the remaining ones + // until no one answers to CMD2. Then we know all cards have an RCA + // (and a matching published device on our side). uint32_t cid[4]; - while (bus->ExecuteCommand(2, 0, cid) == B_OK) { - bus->ExecuteCommand(3, 0, &response); + + while (bus->ExecuteCommand(SD_ALL_SEND_CID, 0, cid) == B_OK) { + bus->ExecuteCommand(SD_SEND_RELATIVE_ADDR, 0, &response); TRACE("RCA: %x Status: %x\n", response >> 16, response & 0xFFFF); @@ -175,7 +235,7 @@ MMCBus::WorkerThread(void* cookie) uint8_t month = cid[0] & 0xF; uint16_t year = 2000 + ((cid[0] >> 4) & 0xFF); uint16_t rca = response >> 16; - + device_attr attrs[] = { { B_DEVICE_BUS, B_STRING_TYPE, {string: "mmc" }}, { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "mmc device" }}, @@ -200,6 +260,8 @@ MMCBus::WorkerThread(void* cookie) // to detect added/removed cards? } + release_sem(bus->fLockSemaphore); + TRACE("poller thread terminating"); return B_OK; } diff --git a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h index cccae48e67..9692ef9489 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h @@ -41,10 +41,16 @@ public: status_t InitCheck(); void Rescan(); -private: status_t ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response); - static status_t WorkerThread(void*); + status_t Read(uint16_t rca, off_t position, void* buffer, + size_t* length); + + void AcquireBus() { acquire_sem(fLockSemaphore); } + void ReleaseBus() { release_sem(fLockSemaphore); } +private: + status_t _ActivateDevice(uint16_t rca); + static status_t _WorkerThread(void*); private: @@ -53,7 +59,9 @@ private: void* fCookie; status_t fStatus; thread_id fWorkerThread; - sem_id fSemaphore; + sem_id fScanSemaphore; + sem_id fLockSemaphore; + uint16 fActiveDevice; }; diff --git a/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp b/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp index 5104f874ad..c0ce6e5c36 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp @@ -82,20 +82,43 @@ static status_t mmc_bus_execute_command(device_node* node, uint8_t command, uint32_t argument, uint32_t* result) { - // FIXME store these in the bus cookie or something instead of - // getting/putting the parents each time. - mmc_bus_interface* sdhci; + // FIXME store the parent cookie in the bus cookie or something instead of + // getting/putting the parent each time. + driver_module_info* mmc; void* cookie; TRACE("In mmc_bus_execute_command\n"); device_node* parent = gDeviceManager->get_parent_node(node); - device_node* grandparent = gDeviceManager->get_parent_node(parent); - gDeviceManager->get_driver(grandparent, (driver_module_info**)&sdhci, - &cookie); - gDeviceManager->put_node(grandparent); + gDeviceManager->get_driver(parent, &mmc, &cookie); gDeviceManager->put_node(parent); - return sdhci->execute_command(cookie, command, argument, result); + MMCBus* bus = (MMCBus*)cookie; + + bus->AcquireBus(); + status_t error = bus->ExecuteCommand(command, argument, result); + bus->ReleaseBus(); + return error; +} + + +static status_t +mmc_bus_read_naive(device_node* node, uint16_t rca, off_t pos, void* buffer, + size_t* _length) +{ + // FIXME store the parent cookie in the bus cookie or something instead of + // getting/putting the parent each time. + driver_module_info* mmc; + void* cookie; + + device_node* parent = gDeviceManager->get_parent_node(node); + gDeviceManager->get_driver(parent, &mmc, &cookie); + gDeviceManager->put_node(parent); + + MMCBus* bus = (MMCBus*)cookie; + bus->AcquireBus(); + status_t result = bus->Read(rca, pos, buffer, _length); + bus->ReleaseBus(); + return result; } @@ -148,7 +171,8 @@ mmc_device_interface mmc_bus_controller_module = { NULL, NULL }, - mmc_bus_execute_command + mmc_bus_execute_command, + mmc_bus_read_naive }; diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp index fdefcdbcc8..3700c8c255 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp +++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp @@ -49,7 +49,8 @@ class SdhciBus { status_t InitCheck(); void Reset(); void SetClock(int kilohertz); - + status_t ReadNaive(off_t pos, void* buffer, size_t* _length); + private: bool PowerOn(); void RecoverError(); @@ -89,7 +90,7 @@ SdhciBus::SdhciBus(struct registers* registers, uint8_t irq) } fSemaphore = create_sem(0, "SDHCI interrupts"); - + fStatus = install_io_interrupt_handler(fIrq, sdhci_generic_interrupt, this, 0); @@ -113,23 +114,25 @@ SdhciBus::SdhciBus(struct registers* registers, uint8_t irq) return; } - // FIXME do we need all these? Wouldn't card insertion/removal and command - // completion be enough? EnableInterrupts(SDHCI_INT_CMD_CMP - | SDHCI_INT_TRANS_CMP | SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM - | SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_INDEX - | SDHCI_INT_BUS_POWER | SDHCI_INT_END_BIT); + | SDHCI_INT_BUF_READ_READY | SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM); - fRegisters->interrupt_status_enable |= SDHCI_INT_ERROR; + // We want to see the error bits in the status register, but not have an + // interrupt trigger on them (we get a "command complete" interrupt on + // errors already) + fRegisters->interrupt_status_enable |= SDHCI_INT_ERROR + | SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_INDEX + | SDHCI_INT_BUS_POWER | SDHCI_INT_END_BIT; } SdhciBus::~SdhciBus() { + EnableInterrupts(0); + if (fSemaphore != 0) delete_sem(fSemaphore); - EnableInterrupts(0); if (fIrq != 0) remove_io_interrupt_handler(fIrq, sdhci_generic_interrupt, this); @@ -146,45 +149,83 @@ SdhciBus::EnableInterrupts(uint32_t mask) } +// #pragma mark - +/* +PartA2, SD Host Controller Simplified Specification, Version 4.20 +ยง3.7.1.1 The sequence to issue an SD Command +*/ status_t SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) { TRACE("ExecuteCommand(%d, %x)\n", command, argument); + + // Check if it's possible to send a command right now. + // It is not possible to send a command as long as the command line is busy. + // The spec says we should wait, but we can't do that on kernel side, since + // it leaves no chance for the upper layers to handle the problem. So we + // just say we're busy and the caller can retry later. + // Note that this should normally never happen: the command line is busy + // only during command execution, and we don't leave this function with ac + // command running. if (fRegisters->present_state.CommandInhibit()) { ERROR("Execution aborted, command inhibit\n"); return B_BUSY; } - fRegisters->argument = argument; - uint32_t replyType; switch(command) { - case 0: + case SD_GO_IDLE_STATE: replyType = Command::kNoReplyType; break; - case 55: - replyType = Command::kR1Type; - break; - case 2: - case 9: + case SD_ALL_SEND_CID: + case SD_SEND_CSD: replyType = Command::kR2Type; break; + case SD_SEND_RELATIVE_ADDR: + replyType = Command::kR6Type; + break; + case SD_SELECT_DESELECT_CARD: + replyType = Command::kR1bType; + break; + case SD_SEND_IF_COND: + replyType = Command::kR7Type; + break; + case SD_READ_SINGLE_BLOCK: + case SD_READ_MULTIPLE_BLOCKS: + replyType = Command::kR1Type | Command::kDataPresent; + break; + case SD_APP_CMD: + replyType = Command::kR1Type; + break; case 41: // ACMD replyType = Command::kR3Type; break; - case 3: - replyType = Command::kR6Type; - break; - case 8: - replyType = Command::kR7Type; - break; default: ERROR("Unknown command\n"); return B_BAD_DATA; } + // Check if DATA line is available (if needed) + if ((replyType & Command::k32BitResponseCheckBusy) != 0 + && command != SD_STOP_TRANSMISSION && command != SD_IO_ABORT) { + if (fRegisters->present_state.DataInhibit()) { + ERROR("Execution aborted, data inhibit\n"); + return B_BUSY; + } + } + + //FIXME : Assign only at this point, if needed : + // -32 bit block count/SDMA system address + // -block size + // -16-bit block count + // -transfer mode + + fRegisters->argument = argument; fRegisters->command.SendCommand(command, replyType); + + // Wait for command response to be available (either "command complete" or + // "buffer read ready" interrupt will happen, depending on the command) acquire_sem(fSemaphore); if (fCommandResult & SDHCI_INT_ERROR) { @@ -220,12 +261,13 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) response[2] = fRegisters->response[2]; response[3] = fRegisters->response[3]; break; + default: // No response break; } - ERROR("Command execution complete\n"); + ERROR("Command execution %d complete\n", command); return B_OK; } @@ -285,6 +327,62 @@ SdhciBus::SetClock(int kilohertz) } +status_t +SdhciBus::ReadNaive(off_t pos, void* buffer, size_t* _length) +{ + // TODO read multiple blocks at once (don't ignore _length) + fRegisters->block_size = 512; + fRegisters->block_count = 1; + fRegisters->transfer_mode = TransferMode::kSingle | TransferMode::kRead + | TransferMode::kAutoCmdDisabled | TransferMode::kNoDmaOrNoData; + + uint32_t response; + status_t result; + result = ExecuteCommand(SD_READ_SINGLE_BLOCK, pos, &response); + + if (result != B_OK) + return result; + + TRACE("Command response: %02x\n", response); + + if (fCommandResult & SDHCI_INT_BUF_READ_READY == 0) { + TRACE("No data!\n"); + return B_ERROR; + } + + // We don't know how to read more than 512 bytes (CMD18 would be needed) + if (*_length > 512) + *_length = 512; + + // read block data from Buffer Data Port register + // TODO use DMA instead + size_t to_read = *_length / sizeof(uint32_t); + size_t to_drop = 512 / sizeof(uint32_t) - to_read; + uint32_t* dest = (uint32_t*)buffer; + while(to_read > 0) { + *dest = fRegisters->buffer_data_port; + TRACE("read : 0x%x", *dest); + dest++; + to_read--; + } + + // We cannot read less than one sector, so we have to drop the extra data. + // This will be fixed when we use DMA and the IO scheduler (since it makes + // sure to only ask for complete sectors). + // Currently the IO scheduler does not support bounce buffers for non-DMA + // transfers. + while(to_drop > 0) { + (void*)fRegisters->buffer_data_port; + to_drop--; + } + + // wait for command complete interrupt + acquire_sem(fSemaphore); + + return B_OK; +} + + bool SdhciBus::PowerOn() { @@ -428,17 +526,29 @@ SdhciBus::RecoverError() int32 SdhciBus::HandleInterrupt() { + CALLED(); + +#if 0 + // We could use the slot register to quickly see for which slot the + // interrupt is. But since we have an interrupt handler call for each slot + // anyway, it's just as simple to let each of them scan its own interrupt + // status register. + if ( !(fRegisters->slot_interrupt_status & (1 << fSlot)) ) { + TRACE("interrupt not for me.\n"); + return B_UNHANDLED_INTERRUPT; + } +#endif + uint32_t intmask = fRegisters->interrupt_status; + // Shortcut: exit early if there is no interrupt or if the register is + // clearly invalid. if ((intmask == 0) || (intmask == 0xffffffff)) { return B_UNHANDLED_INTERRUPT; } TRACE("interrupt function called %x\n", intmask); - // FIXME use the global "slot interrupt" register to quickly decide if an - // interrupt is targetted to this slot - // handling card presence interrupt if (intmask & (SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM)) { uint32_t card_present = ((intmask & SDHCI_INT_CARD_INS) != 0); @@ -455,37 +565,43 @@ SdhciBus::HandleInterrupt() fRegisters->interrupt_status |= (intmask & (SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM)); TRACE("Card presence interrupt handled\n"); - - return B_HANDLED_INTERRUPT; } // handling command interrupt if (intmask & SDHCI_INT_CMD_MASK) { fCommandResult = intmask; - // Save the status before clearing so the thhread can handle it + // Save the status before clearing so the thread can handle it fRegisters->interrupt_status |= (intmask & SDHCI_INT_CMD_MASK); + // Notify the thread release_sem_etc(fSemaphore, 1, B_DO_NOT_RESCHEDULE); - TRACE("Command interrupt handled\n"); + TRACE("Command complete interrupt handled\n"); + } - return B_HANDLED_INTERRUPT; + // handling data transfer interrupt + if (intmask & SDHCI_INT_BUF_READ_READY) { + TRACE("buffer read ready interrupt raised"); + fRegisters->interrupt_status |= (intmask & SDHCI_INT_BUF_READ_READY); + + release_sem_etc(fSemaphore, 1, B_DO_NOT_RESCHEDULE); } // handling bus power interrupt if (intmask & SDHCI_INT_BUS_POWER) { fRegisters->interrupt_status |= SDHCI_INT_BUS_POWER; TRACE("card is consuming too much power\n"); - - return B_HANDLED_INTERRUPT; } + // Check that all interrupts have been cleared (we check all the ones we + // enabled, so that should always be the case) intmask = fRegisters->slot_interrupt_status; if (intmask != 0) { ERROR("Remaining interrupts at end of handler: %x\n", intmask); } - return B_UNHANDLED_INTERRUPT; + return B_HANDLED_INTERRUPT; } +// #pragma mark - static void @@ -639,6 +755,17 @@ execute_command(void* controller, uint8_t command, uint32_t argument, } +//Very naive read protocol : non DMA, 32 bits at a time (size of Buffer Data Port) +static status_t +read_naive(void* controller, off_t pos, void* buffer, size_t* _length) +{ + CALLED(); + + SdhciBus* bus = (SdhciBus*)controller; + return bus->ReadNaive(pos, buffer, _length); +} + + module_dependency module_dependencies[] = { { MMC_BUS_MODULE_NAME, (module_info**)&gMMCBusController}, { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, @@ -666,6 +793,7 @@ static mmc_bus_interface gSDHCIPCIDeviceModule = { set_clock, execute_command, + read_naive }; diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.h b/src/add-ons/kernel/busses/mmc/sdhci_pci.h index ad2fc36c4c..00dbc7a0fb 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci_pci.h +++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.h @@ -19,6 +19,36 @@ #define SDHCI_BUS_TYPE_NAME "bus/sdhci/v1" +class TransferMode { + public: + uint16_t Bits() { return fBits; } + + // TODO response interrupt + // TODO response check + + static const uint8_t kR1 = 0 << 6; + static const uint8_t kR5 = 1 << 6; + + static const uint8_t kMulti = 1 << 5; + static const uint8_t kSingle = 0 << 5; + + static const uint8_t kRead = 1 << 4; + static const uint8_t kWrite = 0 << 4; + + static const uint8_t kAutoCmdDisabled = 0 << 2; + static const uint8_t kAutoCmd12Enable = 1 << 2; + static const uint8_t kAutoCmd23Enable = 2 << 2; + static const uint8_t kAutoCmdAutoSelect = + kAutoCmd23Enable | kAutoCmd12Enable; + + // TODO block count enable + + static const uint8_t kDmaEnable = 1; + static const uint8_t kNoDmaOrNoData = 0; + + private: + volatile uint16_t fBits; +} __attribute__((packed)); class Command { public: @@ -35,14 +65,17 @@ class Command { static const uint8_t kSubCommand = 0x4; static const uint8_t kReplySizeMask = 0x3; static const uint8_t k32BitResponse = 0x2; - static const uint8_t k128BitResponse = 0x1; + static const uint8_t k128BitResponse = 0x1; + static const uint8_t k32BitResponseCheckBusy = 0x3; // For simplicity pre-define the standard response types from the SD // card specification static const uint8_t kNoReplyType = 0; static const uint8_t kR1Type = kCheckIndex | kCRCEnable | k32BitResponse; - static const uint8_t kR2Type = kCRCEnable | k128BitResponse; + static const uint8_t kR1bType = (kCheckIndex | kCRCEnable + | k32BitResponseCheckBusy) & (~ kDataPresent); + static const uint8_t kR2Type = kCRCEnable | k128BitResponse; static const uint8_t kR3Type = k32BitResponse; static const uint8_t kR6Type = kCheckIndex | k32BitResponse; static const uint8_t kR7Type = kDataPresent | kCheckIndex | kCRCEnable @@ -62,6 +95,7 @@ class PresentState { bool IsCardInserted() { return fBits & (1 << 16); } bool CommandInhibit() { return fBits & (1 << 0); } + bool DataInhibit() { return fBits & (1 << 1); } private: volatile uint32_t fBits; @@ -134,24 +168,25 @@ class SoftwareReset { } __attribute__((packed)); -/* Interrupt registers */ -#define SDHCI_INT_CMD_CMP 0x00000001 // command complete enable -#define SDHCI_INT_TRANS_CMP 0x00000002 // transfer complete enable -#define SDHCI_INT_CARD_INS 0x00000040 // card insertion enable -#define SDHCI_INT_CARD_REM 0x00000080 // card removal enable -#define SDHCI_INT_ERROR 0x00008000 // error -#define SDHCI_INT_TIMEOUT 0x00010000 // Timeout error -#define SDHCI_INT_CRC 0x00020000 // CRC error -#define SDHCI_INT_END_BIT 0x00040000 // end bit error -#define SDHCI_INT_INDEX 0x00080000 // index error -#define SDHCI_INT_BUS_POWER 0x00800000 // power fail +// #pragma mark Interrupt registers +#define SDHCI_INT_CMD_CMP 0x00000001 // command complete enable +#define SDHCI_INT_TRANS_CMP 0x00000002 // transfer complete enable +#define SDHCI_INT_BUF_READ_READY 0x00000020 // buffer read ready enable +#define SDHCI_INT_CARD_INS 0x00000040 // card insertion enable +#define SDHCI_INT_CARD_REM 0x00000080 // card removal enable +#define SDHCI_INT_ERROR 0x00008000 // error +#define SDHCI_INT_TIMEOUT 0x00010000 // Timeout error +#define SDHCI_INT_CRC 0x00020000 // CRC error +#define SDHCI_INT_END_BIT 0x00040000 // end bit error +#define SDHCI_INT_INDEX 0x00080000 // index error +#define SDHCI_INT_BUS_POWER 0x00800000 // power fail #define SDHCI_INT_CMD_ERROR_MASK (SDHCI_INT_TIMEOUT | \ SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX) #define SDHCI_INT_CMD_MASK (SDHCI_INT_CMD_CMP | SDHCI_INT_CMD_ERROR_MASK) - +// #pragma mark - class Capabilities { public: @@ -175,7 +210,7 @@ class HostControllerVersion { const uint8_t vendorVersion; } __attribute__((packed)); - +// #pragma mark - struct registers { // SD command generation volatile uint32_t system_address; diff --git a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp index 8742668c8f..486a84bd32 100644 --- a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp @@ -1,5 +1,6 @@ /* * Copyright 2018-2020 Haiku, Inc. All rights reserved. + * Copyright 2020, Viveris Technologies. * Distributed under the terms of the MIT License. * * Authors: @@ -200,7 +201,7 @@ mmc_block_open(void* _info, const char* path, int openMode, void** _cookie) CALLED(); mmc_disk_driver_info* info = (mmc_disk_driver_info*)_info; - // TODO allocate cookie + // allocate cookie mmc_disk_handle* handle = new(std::nothrow) mmc_disk_handle; *_cookie = handle; if (handle == NULL) { @@ -233,13 +234,13 @@ mmc_block_free(void* cookie) } -static status_t -mmc_block_read(void* cookie, off_t position, void* buffer, size_t* length) +static status_t +mmc_block_read(void* cookie, off_t pos, void* buffer, size_t* _length) { CALLED(); mmc_disk_handle* handle = (mmc_disk_handle*)cookie; - - return B_NOT_SUPPORTED; + TRACE("Ready to execute %p\n", handle->info->mmc->read_naive); + return handle->info->mmc->read_naive(handle->info->parent, handle->info->rca, pos, buffer, _length); } @@ -269,7 +270,7 @@ mmc_block_get_geometry(mmc_disk_handle* handle, device_geometry* geometry) { struct mmc_disk_csd csd; TRACE("Ready to execute %p\n", handle->info->mmc->execute_command); - handle->info->mmc->execute_command(handle->info->parent, 9, + handle->info->mmc->execute_command(handle->info->parent, SD_SEND_CSD, handle->info->rca << 16, (uint32_t*)&csd); TRACE("CSD: %lx %lx\n", csd.bits[0], csd.bits[1]);