diff --git a/headers/private/drivers/mmc.h b/headers/private/drivers/mmc.h index 815d97488c..6449b75de3 100644 --- a/headers/private/drivers/mmc.h +++ b/headers/private/drivers/mmc.h @@ -42,10 +42,13 @@ enum SD_COMMANDS { SD_SEND_CSD = 9, SD_STOP_TRANSMISSION = 12, - // Block oriented read commands, class 2 + // Block oriented read and write commands, class 2 SD_READ_SINGLE_BLOCK = 17, SD_READ_MULTIPLE_BLOCKS = 18, + SD_WRITE_SINGLE_BLOCK = 24, + SD_WRITE_MULTIPLE_BLOCKS = 25, + // Application specific commands, class 8 SD_APP_CMD = 55, @@ -65,19 +68,32 @@ typedef struct mmc_bus_interface { driver_module_info info; status_t (*set_clock)(void* controller, uint32_t kilohertz); + // Configure the bus clock. The bus is initialized with a slow clock + // that allows device enumeration in all cases, but after enumeration + // the mmc_bus knows how fast each card can go, and configures the bus + // accordingly. status_t (*execute_command)(void* controller, uint8_t command, uint32_t argument, uint32_t* result); - status_t (*do_io)(void* controller, IOOperation* operation); + // Execute a command with no I/O phase + status_t (*do_io)(void* controller, uint8_t command, + IOOperation* operation); + // Execute a command that involves a data transfer. } mmc_bus_interface; // Interface between mmc device driver (mmc_disk, sdio drivers, ...) and mmc_bus +// This interface is rather generic as it allows implementation of drivers for +// different type of cards, which will use different commands. The bus +// provides a generic interface for all of them, and is not specific to any +// type of card. 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); + // Execute a command with no I/O phase status_t (*do_io)(device_node* controller, uint16_t rca, - IOOperation* operation); + uint8_t command, IOOperation* operation); + // Execute a command that involves a data transfer. } 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 096e8f5b4a..15693363c4 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp @@ -86,12 +86,12 @@ MMCBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) status_t -MMCBus::DoIO(uint16_t rca, IOOperation* operation) +MMCBus::DoIO(uint16_t rca, uint8_t command, IOOperation* operation) { status_t status = _ActivateDevice(rca); if (status != B_OK) return status; - return fController->do_io(fCookie, operation); + return fController->do_io(fCookie, command, operation); } 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 bf39bdc93c..fa8c3f3830 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.h @@ -43,7 +43,8 @@ public: status_t ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response); - status_t DoIO(uint16_t rca, IOOperation* operation); + status_t DoIO(uint16_t rca, uint8_t command, + IOOperation* operation); void AcquireBus() { acquire_sem(fLockSemaphore); } void ReleaseBus() { release_sem(fLockSemaphore); } 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 6c713e83c3..d3186d771f 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_module.cpp @@ -103,7 +103,8 @@ mmc_bus_execute_command(device_node* node, uint8_t command, uint32_t argument, static status_t -mmc_bus_do_io(device_node* node, uint16_t rca, IOOperation* operation) +mmc_bus_do_io(device_node* node, uint16_t rca, uint8_t command, + IOOperation* operation) { driver_module_info* mmc; void* cookie; @@ -118,7 +119,7 @@ mmc_bus_do_io(device_node* node, uint16_t rca, IOOperation* operation) bus->AcquireBus(); status_t result = B_OK; - result = bus->DoIO(rca, operation); + result = bus->DoIO(rca, command, operation); bus->ReleaseBus(); return result; diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp index 82bdfe616f..b66c5178f4 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp +++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp @@ -52,7 +52,7 @@ class SdhciBus { status_t InitCheck(); void Reset(); void SetClock(int kilohertz); - status_t DoIO(IOOperation* operation); + status_t DoIO(uint8_t command, IOOperation* operation); private: bool PowerOn(); @@ -196,6 +196,8 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) break; case SD_READ_SINGLE_BLOCK: case SD_READ_MULTIPLE_BLOCKS: + case SD_WRITE_SINGLE_BLOCK: + case SD_WRITE_MULTIPLE_BLOCKS: replyType = Command::kR1Type | Command::kDataPresent; break; case SD_APP_CMD: @@ -338,11 +340,9 @@ SdhciBus::SetClock(int kilohertz) status_t -SdhciBus::DoIO(IOOperation* operation) +SdhciBus::DoIO(uint8_t command, IOOperation* operation) { bool isWrite = operation->IsWrite(); - if (isWrite) - return B_NOT_SUPPORTED; static const uint32 kBlockSize = 512; off_t offset = operation->Offset(); @@ -384,11 +384,16 @@ SdhciBus::DoIO(IOOperation* operation) fRegisters->block_count = toCopy / kBlockSize; - fRegisters->transfer_mode = TransferMode::kSingle | TransferMode::kRead + uint16 direction; + if (isWrite) + direction = TransferMode::kWrite; + else + direction = TransferMode::kRead; + fRegisters->transfer_mode = TransferMode::kMulti | direction | TransferMode::kAutoCmd12Enable | TransferMode::kDmaEnable; uint32_t response; - result = ExecuteCommand(SD_READ_MULTIPLE_BLOCKS, offset, &response); + result = ExecuteCommand(command, offset, &response); if (result != B_OK) break; @@ -780,12 +785,12 @@ execute_command(void* controller, uint8_t command, uint32_t argument, static status_t -do_io(void* controller, IOOperation* operation) +do_io(void* controller, uint8_t command, IOOperation* operation) { CALLED(); SdhciBus* bus = (SdhciBus*)controller; - return bus->DoIO(operation); + return bus->DoIO(command, operation); } 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 6a7b54836d..c465ef28a8 100644 --- a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp @@ -110,7 +110,12 @@ mmc_disk_execute_iorequest(void* data, IOOperation* operation) mmc_disk_driver_info* info = (mmc_disk_driver_info*)data; status_t error; - error = info->mmc->do_io(info->parent, info->rca, operation); + uint8_t command; + if (operation->IsWrite()) + command = SD_WRITE_MULTIPLE_BLOCKS; + else + command = SD_READ_MULTIPLE_BLOCKS; + error = info->mmc->do_io(info->parent, info->rca, command, operation); if (error != B_OK) { info->scheduler->OperationCompleted(operation, error, 0);