mmc_disk: add write support
Change-Id: I77cf1612569c43e79917ac5a1493b7ab4a04cb47 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3504 Reviewed-by: Alex von Gluck IV <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
7a160a8629
commit
9a37366b51
@@ -42,10 +42,13 @@ enum SD_COMMANDS {
|
|||||||
SD_SEND_CSD = 9,
|
SD_SEND_CSD = 9,
|
||||||
SD_STOP_TRANSMISSION = 12,
|
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_SINGLE_BLOCK = 17,
|
||||||
SD_READ_MULTIPLE_BLOCKS = 18,
|
SD_READ_MULTIPLE_BLOCKS = 18,
|
||||||
|
|
||||||
|
SD_WRITE_SINGLE_BLOCK = 24,
|
||||||
|
SD_WRITE_MULTIPLE_BLOCKS = 25,
|
||||||
|
|
||||||
// Application specific commands, class 8
|
// Application specific commands, class 8
|
||||||
SD_APP_CMD = 55,
|
SD_APP_CMD = 55,
|
||||||
|
|
||||||
@@ -65,19 +68,32 @@ typedef struct mmc_bus_interface {
|
|||||||
driver_module_info info;
|
driver_module_info info;
|
||||||
|
|
||||||
status_t (*set_clock)(void* controller, uint32_t kilohertz);
|
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,
|
status_t (*execute_command)(void* controller, uint8_t command,
|
||||||
uint32_t argument, uint32_t* result);
|
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;
|
} mmc_bus_interface;
|
||||||
|
|
||||||
|
|
||||||
// Interface between mmc device driver (mmc_disk, sdio drivers, ...) and mmc_bus
|
// 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 {
|
typedef struct mmc_device_interface {
|
||||||
driver_module_info info;
|
driver_module_info info;
|
||||||
status_t (*execute_command)(device_node* node, uint8_t command,
|
status_t (*execute_command)(device_node* node, uint8_t command,
|
||||||
uint32_t argument, uint32_t* result);
|
uint32_t argument, uint32_t* result);
|
||||||
|
// Execute a command with no I/O phase
|
||||||
status_t (*do_io)(device_node* controller, uint16_t rca,
|
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;
|
} mmc_device_interface;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -86,12 +86,12 @@ MMCBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
MMCBus::DoIO(uint16_t rca, IOOperation* operation)
|
MMCBus::DoIO(uint16_t rca, uint8_t command, IOOperation* operation)
|
||||||
{
|
{
|
||||||
status_t status = _ActivateDevice(rca);
|
status_t status = _ActivateDevice(rca);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
return fController->do_io(fCookie, operation);
|
return fController->do_io(fCookie, command, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ public:
|
|||||||
|
|
||||||
status_t ExecuteCommand(uint8_t command,
|
status_t ExecuteCommand(uint8_t command,
|
||||||
uint32_t argument, uint32_t* response);
|
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 AcquireBus() { acquire_sem(fLockSemaphore); }
|
||||||
void ReleaseBus() { release_sem(fLockSemaphore); }
|
void ReleaseBus() { release_sem(fLockSemaphore); }
|
||||||
|
|||||||
@@ -103,7 +103,8 @@ mmc_bus_execute_command(device_node* node, uint8_t command, uint32_t argument,
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
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;
|
driver_module_info* mmc;
|
||||||
void* cookie;
|
void* cookie;
|
||||||
@@ -118,7 +119,7 @@ mmc_bus_do_io(device_node* node, uint16_t rca, IOOperation* operation)
|
|||||||
bus->AcquireBus();
|
bus->AcquireBus();
|
||||||
status_t result = B_OK;
|
status_t result = B_OK;
|
||||||
|
|
||||||
result = bus->DoIO(rca, operation);
|
result = bus->DoIO(rca, command, operation);
|
||||||
|
|
||||||
bus->ReleaseBus();
|
bus->ReleaseBus();
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class SdhciBus {
|
|||||||
status_t InitCheck();
|
status_t InitCheck();
|
||||||
void Reset();
|
void Reset();
|
||||||
void SetClock(int kilohertz);
|
void SetClock(int kilohertz);
|
||||||
status_t DoIO(IOOperation* operation);
|
status_t DoIO(uint8_t command, IOOperation* operation);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool PowerOn();
|
bool PowerOn();
|
||||||
@@ -196,6 +196,8 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
|
|||||||
break;
|
break;
|
||||||
case SD_READ_SINGLE_BLOCK:
|
case SD_READ_SINGLE_BLOCK:
|
||||||
case SD_READ_MULTIPLE_BLOCKS:
|
case SD_READ_MULTIPLE_BLOCKS:
|
||||||
|
case SD_WRITE_SINGLE_BLOCK:
|
||||||
|
case SD_WRITE_MULTIPLE_BLOCKS:
|
||||||
replyType = Command::kR1Type | Command::kDataPresent;
|
replyType = Command::kR1Type | Command::kDataPresent;
|
||||||
break;
|
break;
|
||||||
case SD_APP_CMD:
|
case SD_APP_CMD:
|
||||||
@@ -338,11 +340,9 @@ SdhciBus::SetClock(int kilohertz)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
SdhciBus::DoIO(IOOperation* operation)
|
SdhciBus::DoIO(uint8_t command, IOOperation* operation)
|
||||||
{
|
{
|
||||||
bool isWrite = operation->IsWrite();
|
bool isWrite = operation->IsWrite();
|
||||||
if (isWrite)
|
|
||||||
return B_NOT_SUPPORTED;
|
|
||||||
|
|
||||||
static const uint32 kBlockSize = 512;
|
static const uint32 kBlockSize = 512;
|
||||||
off_t offset = operation->Offset();
|
off_t offset = operation->Offset();
|
||||||
@@ -384,11 +384,16 @@ SdhciBus::DoIO(IOOperation* operation)
|
|||||||
|
|
||||||
fRegisters->block_count = toCopy / kBlockSize;
|
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;
|
| TransferMode::kAutoCmd12Enable | TransferMode::kDmaEnable;
|
||||||
|
|
||||||
uint32_t response;
|
uint32_t response;
|
||||||
result = ExecuteCommand(SD_READ_MULTIPLE_BLOCKS, offset, &response);
|
result = ExecuteCommand(command, offset, &response);
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -780,12 +785,12 @@ execute_command(void* controller, uint8_t command, uint32_t argument,
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
do_io(void* controller, IOOperation* operation)
|
do_io(void* controller, uint8_t command, IOOperation* operation)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
SdhciBus* bus = (SdhciBus*)controller;
|
SdhciBus* bus = (SdhciBus*)controller;
|
||||||
return bus->DoIO(operation);
|
return bus->DoIO(command, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,12 @@ mmc_disk_execute_iorequest(void* data, IOOperation* operation)
|
|||||||
mmc_disk_driver_info* info = (mmc_disk_driver_info*)data;
|
mmc_disk_driver_info* info = (mmc_disk_driver_info*)data;
|
||||||
status_t error;
|
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) {
|
if (error != B_OK) {
|
||||||
info->scheduler->OperationCompleted(operation, error, 0);
|
info->scheduler->OperationCompleted(operation, error, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user