genode/os/src/drivers/sd_card/pl180/sd_card.h

143 lines
3.1 KiB
C++

/*
* \brief SD-card protocol
* \author Christian Helmuth
* \date 2011-05-19
*/
/*
* Copyright (C) 2011-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SD_CARD_H_
#define _SD_CARD_H_
#include <block/driver.h>
#include "host_driver.h"
class Sd_card : public Block::Driver
{
private:
Host_driver &_hd;
enum { BLOCK_SIZE = 512 };
public:
Sd_card(Host_driver &host_driver) : _hd(host_driver)
{
unsigned resp;
/* CMD0: go idle state */
_hd.request(0, 0);
/*
* CMD8: send interface condition
*
* XXX only one hard-coded value currently.
*/
_hd.request(8, 0x1aa, &resp);
/*
* ACMD41: card send operating condition
*
* This is an application-specific command and, therefore, consists
* of prefix command CMD55 + CMD41.
*/
_hd.request(55, 0, &resp);
_hd.request(41, 0x4000, &resp);
/* CMD2: all send card identification (CID) */
_hd.request(2, &resp);
/* CMD3: send relative card address (RCA) */
_hd.request(3, &resp);
unsigned short rca = resp >> 16;
/*
* Now, the card is in transfer mode...
*/
/* CMD7: select card */
_hd.request(7, rca << 16, &resp);
}
Host_driver &host_driver() { return _hd; }
/****************************
** Block-driver interface **
****************************/
Genode::size_t block_size() { return BLOCK_SIZE; }
/*
* TODO report (and support) real capacity not just 512M
*/
Genode::size_t block_count() { return 0x20000000 / BLOCK_SIZE; }
void read(Genode::size_t block_number,
Genode::size_t block_count,
char *out_buffer)
{
unsigned resp;
unsigned length = BLOCK_SIZE;
for (Genode::size_t i = 0; i < block_count; ++i) {
/*
* CMD17: read single block
*
* SDSC cards use a byte address as argument while SDHC/SDSC uses a
* block address here.
*/
_hd.read_request(17, (block_number + i) * BLOCK_SIZE,
length, &resp);
_hd.read_data(length, out_buffer + (i * BLOCK_SIZE));
}
}
void write(Genode::size_t block_number,
Genode::size_t block_count,
char const *buffer)
{
unsigned resp;
unsigned length = BLOCK_SIZE;
for (Genode::size_t i = 0; i < block_count; ++i) {
/*
* CMD24: write single block
*
* SDSC cards use a byte address as argument while SDHC/SDSC uses a
* block address here.
*/
_hd.write_request(24, (block_number + i) * BLOCK_SIZE,
length, &resp);
_hd.write_data(length, buffer + (i * BLOCK_SIZE));
}
}
/*
* This driver does not support DMA operation, currently.
*/
void read_dma(Genode::size_t, Genode::size_t, Genode::addr_t) {
throw Io_error(); }
void write_dma(Genode::size_t, Genode::size_t, Genode::addr_t) {
throw Io_error(); }
bool dma_enabled() { return false; }
Genode::Ram_dataspace_capability alloc_dma_buffer(Genode::size_t size)
{
return Genode::env()->ram_session()->alloc(size, false);
}
void sync() {}
};
#endif /* _SD_CARD_H_ */