mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-11-16 20:44:05 +02:00
529 lines
16 KiB
COBOL
529 lines
16 KiB
COBOL
#pypp 0
|
|
// Iris: micro-kernel for a capability-based operating system.
|
|
// source/sd+mmc.ccp: sd+mmc driver.
|
|
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "devices.hh"
|
|
#define ARCH
|
|
#include "arch.hh"
|
|
|
|
class Mmc:
|
|
public:
|
|
enum Response_type:
|
|
NONE = MSC_CMDAT_RESPONSE_NONE
|
|
RD_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_READ
|
|
WR_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE
|
|
R1 = MSC_CMDAT_RESPONSE_R1
|
|
R1B = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_BUSY
|
|
R2 = MSC_CMDAT_RESPONSE_R2
|
|
R3 = MSC_CMDAT_RESPONSE_R3
|
|
R4 = MSC_CMDAT_RESPONSE_R4
|
|
R5 = MSC_CMDAT_RESPONSE_R5
|
|
R6 = MSC_CMDAT_RESPONSE_R6
|
|
R7 = MSC_CMDAT_RESPONSE_R7
|
|
static unsigned const POWER_PORT = 3
|
|
static unsigned const POWER_PIN = 2
|
|
struct CID:
|
|
unsigned mid
|
|
char oid[2]
|
|
char pnm[5]
|
|
unsigned prv
|
|
unsigned psn
|
|
unsigned year
|
|
unsigned month
|
|
struct CSD:
|
|
unsigned c_size
|
|
unsigned c_size_mult
|
|
unsigned read_bl_len, write_bl_len
|
|
bool copy
|
|
bool perm_write_protect
|
|
bool tmp_write_protect
|
|
bool send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response = NULL)
|
|
void check_sd ()
|
|
void check_sdmem ()
|
|
void check_mmc ()
|
|
public:
|
|
void reset ()
|
|
void detect ()
|
|
void release ()
|
|
void interrupt ()
|
|
CID const &get_cid ():
|
|
return cid
|
|
unsigned get_num_blocks ():
|
|
return num_blocks
|
|
unsigned get_read_block_size ():
|
|
return read_block_size
|
|
unsigned get_block_bits ():
|
|
return hc ? 9 : csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len
|
|
void fill_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
|
|
void write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset)
|
|
void wait_write ()
|
|
private:
|
|
unsigned rca
|
|
bool have_sdmem, have_io
|
|
bool hc
|
|
CID cid
|
|
CSD csd
|
|
unsigned num_blocks, read_block_size
|
|
Iris::Page buffer_page
|
|
static unsigned const buffer = 0x15000
|
|
|
|
bool Mmc::send (unsigned cmd, unsigned arg, Response_type response_type, unsigned *response):
|
|
MSC_CMD = cmd
|
|
MSC_ARG = arg
|
|
MSC_CMDAT = response_type
|
|
MSC_IMASK = ~MSC_IMASK_END_CMD_RES
|
|
Iris::register_interrupt (IRQ_MSC)
|
|
msc_start_op ()
|
|
Iris::wait_for_interrupt (IRQ_MSC)
|
|
MSC_IMASK = ~0
|
|
//kdebug ("cmd: ")
|
|
//kdebug_num (cmd)
|
|
unsigned stat = MSC_STAT
|
|
//kdebug (", stat: ")
|
|
//kdebug_num (stat)
|
|
//kdebug ("\n")
|
|
if stat & MSC_STAT_CRC_RES_ERR:
|
|
Iris::panic (0, "crc error in mmc response")
|
|
return false
|
|
if stat & MSC_STAT_TIME_OUT_RES:
|
|
kdebug ("time out waiting for mmc response\n")
|
|
MSC_IREG = MSC_IREG_END_CMD_RES
|
|
return false
|
|
if response_type == R2:
|
|
unsigned d = MSC_RES
|
|
if d >> 8 != 0x3f:
|
|
Iris::panic (d, "invalid r2 response")
|
|
if cmd == 3:
|
|
// Read out result.
|
|
cid.mid = d & 0xff
|
|
d = MSC_RES
|
|
cid.oid[0] = d >> 8
|
|
cid.oid[1] = d & 0xff
|
|
d = MSC_RES
|
|
cid.pnm[0] = d >> 8
|
|
cid.pnm[1] = d & 0xff
|
|
d = MSC_RES
|
|
cid.pnm[2] = d >> 8
|
|
cid.pnm[3] = d & 0xff
|
|
d = MSC_RES
|
|
cid.pnm[4] = d >> 8
|
|
cid.prv = d & 0xff
|
|
d = MSC_RES
|
|
cid.psn = d << 16
|
|
d = MSC_RES
|
|
cid.psn |= d
|
|
d = MSC_RES
|
|
cid.year = 2000 + (d >> 4 & 0xff)
|
|
cid.month = d & 0xf
|
|
else:
|
|
// Header (8) 1.0 1.0
|
|
// Read out csd.
|
|
// Ignore csd_structure. 2 (+ 6) 1.0 2.0 ***
|
|
d = MSC_RES
|
|
// Ignore taac and nsac. 8 + 8 2.0 4.0 ***
|
|
d = MSC_RES
|
|
// Ignore tran_speed, ccc. 8 + 8/12 2.0 6.0 ***
|
|
d = MSC_RES
|
|
// Ignore rest of ccc. 4/12 0.4 6.4
|
|
// 4 0.4 7.0
|
|
csd.read_bl_len = (d >> 8) & 0xf
|
|
// Ignore read_bl_partial, write_blk_misalign, read_blk_misalign, dsr_imp. 1 + 1 + 1 + 1 (+ 2) 0.6 7.6
|
|
// 2/12 0.2 8.0 ***
|
|
csd.c_size = (d & 0x0003) << 10
|
|
d = MSC_RES
|
|
// 10/12 1.2 9.2
|
|
csd.c_size |= d >> 6
|
|
// Ignore vdd_r_cur_min, vdd_r_cur_max. 3 + 3 0.6 10.0 ***
|
|
d = MSC_RES
|
|
// Ignore vdd_w_cur_min, vdd_w_cur_max. 3 + 3 0.6 10.6
|
|
// 3 0.3 11.1
|
|
csd.c_size_mult = (d >> 7) & 0x7
|
|
// Ignore erase_blk_enable, sector_size. 1 + 6/7 0.7 12.0 ***
|
|
d = MSC_RES
|
|
// Ignore rest of sector_size, wp_grp_size, wp_grp_enable, r2w_factor. 1/7 + 7 + 1 (+ 2) + 3 1.6 13.6
|
|
// 2/4 0.4 14.0 ***
|
|
csd.write_bl_len = (d << 2) & 0xc
|
|
d = MSC_RES
|
|
// 2/4 0.2 14.2
|
|
csd.write_bl_len |= (d >> 14) & 0x3
|
|
// Ignore write_bl_partial, file_format_grp. 1 (+ 5) + 1 0.7 15.1
|
|
// 1 0.1 15.2
|
|
csd.copy = d & 0x40
|
|
// 1 0.1 15.3
|
|
csd.perm_write_protect = d & 0x20
|
|
// 1 0.1 15.4
|
|
csd.tmp_write_protect = d & 0x10
|
|
// Ignore file_format. 2 (+ 2) 0.4 16.0 ***
|
|
read_block_size = hc ? 512 : 1 << csd.read_bl_len
|
|
num_blocks = (csd.c_size + 1) << (csd.c_size_mult + 2)
|
|
if hc:
|
|
if csd.read_bl_len < 9:
|
|
num_blocks >>= 9 - csd.read_bl_len
|
|
else:
|
|
num_blocks <<= csd.read_bl_len - 9
|
|
else if response_type != NONE:
|
|
unsigned r = MSC_RES
|
|
if response_type == R3:
|
|
if r >> 8 != 0x3f:
|
|
Iris::panic (r, "r3 response was not 3f")
|
|
else if r >> 8 != cmd:
|
|
kdebug ("stat: ")
|
|
kdebug_num (MSC_STAT)
|
|
kdebug ("; response: ")
|
|
kdebug_num (r)
|
|
kdebug ("; cmd: ")
|
|
kdebug_num (cmd)
|
|
Iris::panic (r, "response doesn't match command")
|
|
r <<= 24
|
|
r |= MSC_RES << 8
|
|
r |= MSC_RES & 0xff
|
|
if response:
|
|
*response = r
|
|
else:
|
|
//kdebug ("extra response fifo read: ")
|
|
//for unsigned i = 0; i < 9; ++i:
|
|
//kdebug (" ")
|
|
//kdebug_num (MSC_RES, 4)
|
|
//kdebug ("\n")
|
|
MSC_IREG = MSC_IREG_END_CMD_RES
|
|
return true
|
|
|
|
void Mmc::reset ():
|
|
// Create a buffer to use for data transfer.
|
|
buffer_page = Iris::my_memory.create_page ()
|
|
Iris::my_memory.map (buffer_page, buffer)
|
|
// Reset all state, by faking a release event.
|
|
release ()
|
|
// Enable 25 MHz clock to msc.
|
|
CPM_MSCCDR = 13
|
|
cpm_start_msc ()
|
|
// Enable msc pins.
|
|
gpio_as_msc ()
|
|
// Disable power to card.
|
|
gpio_as_gpio (POWER_PORT, 1 << POWER_PIN)
|
|
gpio_as_output (POWER_PORT, 1 << POWER_PIN)
|
|
gpio_disable_pull (POWER_PORT, 1 << POWER_PIN)
|
|
gpio_set (POWER_PORT, 1 << POWER_PIN)
|
|
|
|
// Stop the clock.
|
|
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP
|
|
while MSC_STAT & MSC_STAT_CLK_EN:
|
|
//kdebug (",")
|
|
Iris::sleep (1)
|
|
|
|
// Reset controller and inserted devices.
|
|
MSC_STRPCL = MSC_STRPCL_RESET
|
|
while MSC_STAT & MSC_STAT_IS_RESETTING:
|
|
//kdebug (":")
|
|
Iris::sleep (1)
|
|
|
|
// Initialize registers.
|
|
MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_1
|
|
MSC_RESTO = 64
|
|
MSC_RDTO = ~0
|
|
MSC_BLKLEN = 0x200
|
|
MSC_NOB = 0
|
|
MSC_IREG = ~0
|
|
MSC_IMASK = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_RXFIFO_RD_REQ)
|
|
MSC_ARG = 0
|
|
|
|
// Start the clock.
|
|
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START
|
|
// Set cards, if any, to idle.
|
|
send (0, 0, NONE)
|
|
|
|
// Reset SDIO device, if any. Don't do this, because it breaks for some reason.
|
|
//send (52, 0x88000c08, R5)
|
|
|
|
void Mmc::check_mmc ():
|
|
//kdebug ("checking mmc\n")
|
|
// 1. SEND CMD1 (SEND_OP_CMD) TO VALIDATE VOLTAGE (THE GENERAL OCR VALUE IS 0X00FF88000).
|
|
// 2. IF THE RESPONSE IS CORRECT, THEN CONTINUE, ELSE GOTO 9.
|
|
// 3. IF THE INITIALIZATION HAS FINISHED, GO TO 5. (THE RESPONSE IS THE OCR REGISTER AND IT INCLUDES A STATUS INFORMATION BIT (BIT [31]). THIS STATUS BIT IS SET IF THE CARD POWER UP PROCEDURE HAS BEEN FINISHED. AS LONG AS THE CARD IS BUSY, THE CORRESPONDING BIT[31] IS SET TO LOW.)
|
|
// 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3.
|
|
// 5. Send CMD2 (ALL_SEND_CID) to get the card CID.
|
|
// 6. If the response timeout occurs, goto 9.
|
|
// 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA.
|
|
|
|
void Mmc::check_sdmem ():
|
|
kdebug ("checking sdmem\n")
|
|
// 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55.
|
|
// 3. If the response is correct (CMD55 has response), then continue, else go to check MMC.
|
|
unsigned code
|
|
hc = false
|
|
if send (8, 0x1aa, R7, &code) && (code & 0xff) == 0xaa:
|
|
kdebug ("hc\n")
|
|
hc = true
|
|
if !send (55, 0, R1, &code):
|
|
check_mmc ()
|
|
return
|
|
// 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000).
|
|
if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
|
|
check_mmc ()
|
|
return
|
|
// 5. If the initialization has finished, go to 7. (The response is the OCR register and it includes a status information bit (bit [31]). This status bit is set if the card power up procedure has been finished. As long as the card is busy, the corresponding bit[31] is set to LOW.)
|
|
// 6. Send CMD55 and ACMD41 to validate voltage, and then go to 5.
|
|
unsigned retries = 100
|
|
while !(code & (1 << 31)) && --retries:
|
|
if !send (55, 0, R1, &code):
|
|
return
|
|
if !send (41, hc ? 0x40800000 : 0x00800000, R3, &code):
|
|
return
|
|
Iris::sleep (1)
|
|
if !(code & (1 << 31)):
|
|
Iris::panic (code, "card fails to finish setting up")
|
|
// 7. Send CMD2 (ALL_SEND_CID) to get the card CID.
|
|
if !send (2, 0, R2):
|
|
Iris::panic (0, "card failed to send CID")
|
|
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response.
|
|
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
|
|
rca = 0
|
|
while !rca:
|
|
if !send (3, 0, R6, &rca):
|
|
Iris::panic (0, "card failed to provide rca")
|
|
rca &= 0xffff0000
|
|
kdebug ("received rca ")
|
|
kdebug_num (rca >> 16, 4)
|
|
kdebug ("\n")
|
|
have_sdmem = true
|
|
|
|
void Mmc::check_sd ():
|
|
//kdebug ("checking sdio\n")
|
|
if !send (0, 0, NONE):
|
|
Iris::panic (0, "unable to reset cards?")
|
|
// 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage.
|
|
// 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM.
|
|
unsigned code
|
|
if !send (5, 1 << 20, R4, &code) || !(code & (7 << 28)):
|
|
check_sdmem ()
|
|
return
|
|
// 4. If C-bit in the response is ready (the initialization has finished), go to 6.
|
|
// 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4.
|
|
while !(code & (1 << 31)):
|
|
if !send (5, 1 << 20, R4, &code):
|
|
Iris::panic (0, "invalid response to cmd 5")
|
|
// 6. If memory-present-bit in the response is true, then it is a combo card (SDIO + Memory), else it is only a SDIO card.
|
|
// 7. If it is a combo card, go to check SDMEM to initialize the memory part.
|
|
have_io = true
|
|
if code & (1 << 27):
|
|
check_sdmem ()
|
|
return
|
|
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned from the response.
|
|
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
|
|
rca = 0
|
|
while rca == 0:
|
|
if !send (3, 0, R6, &rca):
|
|
Iris::panic (0, "unable to set rca")
|
|
rca &= 0xffff0000
|
|
check_mmc ()
|
|
|
|
void Mmc::detect ():
|
|
kdebug ("mmc detect\n")
|
|
gpio_clear (POWER_PORT, 1 << POWER_PIN)
|
|
check_sd ()
|
|
check_mmc ()
|
|
if have_sdmem:
|
|
if !send (9, rca, R2):
|
|
Iris::panic (0, "unable to request csd")
|
|
if !send (7, rca, R1B):
|
|
Iris::panic (0, "unable to select sdmem")
|
|
kdebug ("found device; size = ")
|
|
kdebug_num (num_blocks)
|
|
kdebug (" * ")
|
|
kdebug_num (read_block_size)
|
|
kdebug (" = ")
|
|
kdebug_num (num_blocks * read_block_size)
|
|
kdebug ("\n")
|
|
|
|
void Mmc::release ():
|
|
kdebug ("mmc release\n")
|
|
gpio_set (POWER_PORT, 1 << POWER_PIN)
|
|
have_sdmem = false
|
|
have_io = false
|
|
read_block_size = 0
|
|
num_blocks = 0
|
|
|
|
void Mmc::interrupt ():
|
|
kdebug ("mmc interrupt\n")
|
|
|
|
void Mmc::fill_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
|
|
if address.h:
|
|
Iris::panic (0, "page too high: not supported")
|
|
return
|
|
//kdebug ("smc get page ")
|
|
//kdebug_num (address.l)
|
|
//kdebug ("+")
|
|
//kdebug_num (size)
|
|
//kdebug ("@")
|
|
//kdebug_num (offset)
|
|
//kdebug ("\n")
|
|
unsigned blockmask = ~((1 << 9) - 1)
|
|
unsigned p = address.l & blockmask
|
|
size &= blockmask
|
|
offset &= ~PAGE_MASK
|
|
if size + offset > PAGE_SIZE:
|
|
size = PAGE_SIZE - offset
|
|
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
|
page.share (buffer_page)
|
|
buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
|
MSC_NOB = 1
|
|
MSC_BLKLEN = 1 << 9
|
|
for unsigned a = 0; a < size; a += 1 << 9:
|
|
//kdebug_num (a)
|
|
//kdebug ("/")
|
|
//kdebug_num (size)
|
|
//kdebug (" ==> ")
|
|
if !send (17, p + a, RD_DATA):
|
|
Iris::panic (0, "unable to request data")
|
|
MSC_IMASK = ~MSC_IMASK_RXFIFO_RD_REQ
|
|
for unsigned aa = 0; aa < 1 << 9; aa += 4:
|
|
while MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY:
|
|
Iris::register_interrupt (IRQ_MSC)
|
|
Iris::wait_for_interrupt (IRQ_MSC)
|
|
*(unsigned *)(buffer + a + aa + offset) = MSC_RXFIFO
|
|
//unsigned d = *(unsigned *)(buffer + a + aa + offset)
|
|
//if (aa & 0x3f) == 0:
|
|
//kdebug ("\n")
|
|
//for unsigned i = 0; i < 4; ++i:
|
|
//kdebug (" ")
|
|
//kdebug_num (d >> (8 * i), 2)
|
|
//kdebug ("\n")
|
|
MSC_IMASK = ~0
|
|
MSC_IREG = MSC_IREG_DATA_TRAN_DONE
|
|
//kdebug ("done filling page\n")
|
|
|
|
void Mmc::write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset):
|
|
if address.h:
|
|
Iris::panic (1, "page too high: not supported")
|
|
return
|
|
unsigned blockmask = ~((1 << 9) - 1)
|
|
unsigned p = address.l & blockmask
|
|
size &= blockmask
|
|
offset &= ~PAGE_MASK
|
|
if size + offset > PAGE_SIZE:
|
|
size = PAGE_SIZE - offset
|
|
page.share (buffer_page)
|
|
buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
|
MSC_NOB = 1
|
|
MSC_BLKLEN = 1 << 9
|
|
for unsigned a = 0; a < size; a += 1 << 9:
|
|
//kdebug_num (a)
|
|
//kdebug ("/")
|
|
//kdebug_num (size)
|
|
//kdebug ("\n")
|
|
if !send (24, p + a, WR_DATA):
|
|
Iris::panic (0, "unable to send data")
|
|
MSC_IMASK = ~MSC_IMASK_TXFIFO_WR_REQ
|
|
for unsigned aa = 0; aa < 1 << 9; aa += 4:
|
|
while MSC_STAT & MSC_STAT_DATA_FIFO_FULL:
|
|
Iris::register_interrupt (IRQ_MSC)
|
|
Iris::wait_for_interrupt (IRQ_MSC)
|
|
MSC_TXFIFO = *(unsigned *)(buffer + a + aa + offset)
|
|
MSC_IMASK = ~0
|
|
MSC_IREG = MSC_IREG_DATA_TRAN_DONE
|
|
//kdebug ("done writing page\n")
|
|
|
|
void Mmc::wait_write ():
|
|
MSC_IMASK = ~MSC_IMASK_PRG_DONE
|
|
while !MSC_STAT & MSC_STAT_PRG_DONE:
|
|
Iris::register_interrupt (IRQ_MSC)
|
|
Iris::wait_for_interrupt (IRQ_MSC)
|
|
MSC_IREG = MSC_IREG_PRG_DONE
|
|
|
|
static Mmc mmc
|
|
|
|
enum types:
|
|
DETECT
|
|
REQUEST
|
|
|
|
Iris::Num start ():
|
|
map_msc ()
|
|
map_gpio ()
|
|
map_cpm ()
|
|
|
|
mmc.reset ()
|
|
|
|
Iris::Event detect = Iris::my_parent.get_capability <Iris::Event> ()
|
|
Iris::Cap cap = Iris::my_receiver.create_capability (DETECT)
|
|
detect.set_cb (cap.copy ())
|
|
cap.invoke (~0)
|
|
Iris::free_cap (cap)
|
|
|
|
// Get a message from the queue. This is either the "there is no card" message, or the message we just sent.
|
|
Iris::wait ()
|
|
if Iris::recv.data[0].l != ~0:
|
|
// If it was "there is no card", the message we sent is still in the queue.
|
|
Iris::wait ()
|
|
else:
|
|
// Otherwise, there is a card.
|
|
mmc.detect ()
|
|
|
|
cap = Iris::my_receiver.create_capability (REQUEST)
|
|
Iris::my_parent.provide_capability <Iris::WString> (cap.copy ())
|
|
Iris::free_cap (cap)
|
|
|
|
Iris::my_parent.init_done ()
|
|
|
|
while true:
|
|
Iris::wait ()
|
|
switch Iris::recv.protected_data.l:
|
|
case DETECT:
|
|
if Iris::recv.data[0].l:
|
|
mmc.detect ()
|
|
else:
|
|
mmc.release ()
|
|
break
|
|
case IRQ_MSC:
|
|
mmc.interrupt ()
|
|
break
|
|
case REQUEST:
|
|
//kdebug ("sd+mmc request ")
|
|
//kdebug_num (Iris::recv.data[0].l)
|
|
//kdebug ("\n")
|
|
switch Iris::recv.data[0].l:
|
|
case Iris::Block::GET_SIZE:
|
|
unsigned long long size = mmc.get_num_blocks () * mmc.get_read_block_size ()
|
|
Iris::recv.reply.invoke (size)
|
|
break
|
|
case Iris::Block::GET_ALIGN_BITS:
|
|
Iris::recv.reply.invoke (9)
|
|
break
|
|
case Iris::Block::GET_BLOCK:
|
|
Iris::Cap reply = Iris::get_reply ()
|
|
Iris::Page page = Iris::get_arg ()
|
|
mmc.fill_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
|
|
reply.invoke ()
|
|
Iris::free_cap (page)
|
|
Iris::free_cap (reply)
|
|
break
|
|
case Iris::WBlock::SET_BLOCK:
|
|
Iris::Cap reply = Iris::get_reply ()
|
|
Iris::Page page = Iris::get_arg ()
|
|
mmc.write_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff)
|
|
reply.invoke ()
|
|
Iris::free_cap (page)
|
|
Iris::free_cap (reply)
|
|
mmc.wait_write ()
|
|
break
|
|
case Iris::WString::TRUNCATE:
|
|
// Fall through: don't support resizing.
|
|
default:
|
|
Iris::panic (0, "unexpected event for sd+mmc")
|
|
break
|
|
default:
|
|
Iris::panic (0, "unexpected request source for sd+mmc")
|