Compare commits

...

3 commits

Author SHA1 Message Date
Daniele Lacamera
a62c3a954b Added drivers for SDIO on stm32 2019-10-26 15:48:59 +02:00
Daniele Lacamera
113e100708 Added root block for filesystem authentication 2019-10-26 15:48:15 +02:00
Daniele Lacamera
68f86aa4f7 draft: mcu SPI-flash support 2019-10-22 23:30:44 +02:00
15 changed files with 1405 additions and 36 deletions

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
*.o
*.bin
test/test
test/test.bin
tags

View file

@ -2,4 +2,5 @@ test/test:
make -C test
clean:
rm -f src/*.o
make -C test clean

11
src/spi_drv.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef SPI_DRV_H_INCLUDED
#define SPI_DRV_H_INCLUDED
#include <stdint.h>
void spi_init(int polarity, int phase);
void spi_write(const char byte);
uint8_t spi_read(void);
void spi_cs_on(void);
void spi_cs_off(void);
#endif

98
src/spi_drv_stm32f4.c Normal file
View file

@ -0,0 +1,98 @@
#include <stdint.h>
#include "spi_drv.h"
#include "system.h"
void spi_cs_off(void)
{
GPIOE_BSRR |= (1 << SPI_FLASH_PIN);
DMB();
while(!(GPIOE_ODR & (1 << SPI_FLASH_PIN)))
;
}
void spi_cs_on(void)
{
volatile int i;
GPIOE_BSRR |= (1 << (SPI_FLASH_PIN + 16));
DMB();
while(GPIOE_ODR & (1 << SPI_FLASH_PIN))
;
}
static void spi_flash_pin_setup(void)
{
uint32_t reg;
AHB1_CLOCK_ER |= GPIOE_AHB1_CLOCK_ER;
reg = GPIOE_MODE & ~ (0x03 << (SPI_FLASH_PIN * 2));
GPIOE_MODE = reg | (1 << (SPI_FLASH_PIN * 2));
reg = GPIOE_PUPD & (0x03 << (SPI_FLASH_PIN * 2));
GPIOE_PUPD = reg | (0x01 << (SPI_FLASH_PIN * 2));
reg = GPIOE_OSPD & ~(0x03 << (SPI_FLASH_PIN * 2));
GPIOE_OSPD |= (0x03 << (SPI_FLASH_PIN * 2));
}
static void spi1_pins_setup(void)
{
uint32_t reg;
AHB1_CLOCK_ER |= GPIOB_AHB1_CLOCK_ER;
/* Set mode = AF */
reg = GPIOB_MODE & ~ (0x03 << (SPI1_CLOCK_PIN * 2));
GPIOB_MODE = reg | (2 << (SPI1_CLOCK_PIN * 2));
reg = GPIOB_MODE & ~ (0x03 << (SPI1_MOSI_PIN * 2));
GPIOB_MODE = reg | (2 << (SPI1_MOSI_PIN * 2));
reg = GPIOB_MODE & ~ (0x03 << (SPI1_MISO_PIN * 2));
GPIOB_MODE = reg | (2 << (SPI1_MISO_PIN * 2));
/* Alternate function: use low pins (5,6,7) */
reg = GPIOB_AFL & ~(0xf << ((SPI1_CLOCK_PIN) * 4));
GPIOB_AFL = reg | (SPI1_PIN_AF << ((SPI1_CLOCK_PIN) * 4));
reg = GPIOB_AFL & ~(0xf << ((SPI1_MOSI_PIN) * 4));
GPIOB_AFL = reg | (SPI1_PIN_AF << ((SPI1_MOSI_PIN) * 4));
reg = GPIOB_AFL & ~(0xf << ((SPI1_MISO_PIN) * 4));
GPIOB_AFL = reg | (SPI1_PIN_AF << ((SPI1_MISO_PIN) * 4));
}
static void spi1_reset(void)
{
APB2_CLOCK_RST |= SPI1_APB2_CLOCK_ER_VAL;
APB2_CLOCK_RST &= ~SPI1_APB2_CLOCK_ER_VAL;
}
uint8_t spi_read(void)
{
volatile uint32_t reg;
do {
reg = SPI1_SR;
} while(!(reg & SPI_SR_RX_NOTEMPTY));
return (uint8_t)SPI1_DR;
}
void spi_write(const char byte)
{
int i;
volatile uint32_t reg;
do {
reg = SPI1_SR;
} while ((reg & SPI_SR_TX_EMPTY) == 0);
SPI1_DR = byte;
do {
reg = SPI1_SR;
} while ((reg & SPI_SR_TX_EMPTY) == 0);
}
void spi_init(int polarity, int phase)
{
spi1_pins_setup();
spi_flash_pin_setup();
APB2_CLOCK_ER |= SPI1_APB2_CLOCK_ER_VAL;
spi1_reset();
SPI1_CR1 = SPI_CR1_MASTER | (5 << 3) | (polarity << 1) | (phase << 0);
SPI1_CR2 |= SPI_CR2_SSOE;
SPI1_CR1 |= SPI_CR1_SPI_EN;
}

247
src/spi_flash.c Normal file
View file

@ -0,0 +1,247 @@
#include "system.h"
#include "spi_drv.h"
#define SPI_FLASH_SECTOR_SIZE (4096)
#define SPI_FLASH_PAGE_SIZE (256)
#define MDID 0x90
#define RDSR 0x05
#define WRSR 0x01
# define ST_BUSY (1 << 0)
# define ST_WEL (1 << 1)
# define ST_BP0 (1 << 2)
# define ST_BP1 (1 << 3)
# define ST_BP2 (1 << 4)
# define ST_BP3 (1 << 5)
# define ST_AAI (1 << 6)
# define ST_BRO (1 << 7)
#define WREN 0x06
#define WRDI 0x04
#define SECTOR_ERASE 0x20
#define BYTE_READ 0x03
#define BYTE_WRITE 0x02
#define AUTOINC 0xAD
#define EWSR 0x50
#define EBSY 0x70
#define DBSY 0x80
static enum write_mode {
WB_WRITEPAGE = 0x00,
SST_AAI = 0x01
} chip_write_mode = WB_WRITEPAGE;
static void write_address(uint32_t address)
{
spi_write((address & 0xFF00) >> 8);
spi_read();
spi_write((address & 0xFF0000) >> 16);
spi_read();
spi_write((address & 0xFF000000) >> 24);
spi_read();
}
static uint8_t read_status(void)
{
uint8_t status;
int i;
spi_cs_on();
spi_write(RDSR);
spi_read();
spi_write(0xFF);
status = spi_read();
spi_cs_off();
return status;
}
static void spi_cmd(uint8_t cmd)
{
spi_cs_on();
spi_write(cmd);
spi_read();
spi_cs_off();
}
static inline void flash_aai_enable(void)
{
spi_cmd(EBSY);
}
static inline void flash_aai_disable(void)
{
spi_cmd(DBSY);
}
static void flash_write_enable(void)
{
uint8_t status;
do {
spi_cmd(WREN);
status = read_status();
} while ((status & ST_WEL) == 0);
}
static void flash_write_disable(void)
{
uint8_t status;
spi_cmd(WRDI);
}
static void wait_busy(void)
{
uint8_t status;
do {
status = read_status();
} while(status & ST_BUSY);
}
static int spi_flash_write_page(uint32_t address, const void *data, int len)
{
const uint8_t *buf = data;
int j = 0;
while (len > 0) {
wait_busy();
flash_write_enable();
spi_cs_on();
spi_write(BYTE_WRITE);
spi_read();
write_address(address);
do {
spi_write(buf[j++]);
address++;
spi_read();
len--;
} while ((address % SPI_FLASH_PAGE_SIZE) != 0);
spi_cs_off();
}
wait_busy();
return j;
}
static int spi_flash_write_aai(uint32_t address, const void *data, int len)
{
const uint8_t *buf = data;
int j = 0;
int cont = 0;
wait_busy();
if (len < 1)
return -1;
while (len > 0) {
if ((address & 0x01) || (len < 2)) {
flash_write_enable();
spi_cs_on();
spi_write(BYTE_WRITE);
spi_read();
write_address(address);
spi_write(buf[j++]);
spi_read();
spi_cs_off();
len--;
address++;
} else {
if (!cont) {
flash_aai_enable();
flash_write_enable();
}
spi_cs_on();
spi_write(AUTOINC);
spi_read();
if (!cont) {
/* First AAI transaction, send address. */
write_address(address);
cont = 1;
}
spi_write(buf[j++]);
spi_read();
spi_write(buf[j++]);
spi_read();
spi_cs_off();
len -= 2;
address += 2;
read_status();
}
}
if (cont) {
flash_write_disable();
flash_aai_disable();
}
wait_busy();
return j;
}
/* --- */
uint16_t spi_flash_probe(void)
{
uint8_t manuf, product, b0;
int i;
wait_busy();
spi_cs_on();
spi_write(MDID);
b0 = spi_read();
write_address(0);
spi_write(0xFF);
manuf = spi_read();
spi_write(0xFF);
product = spi_read();
spi_cs_off();
if (manuf == 0xBF)
chip_write_mode = SST_AAI;
if (manuf == 0xEF)
chip_write_mode = WB_WRITEPAGE;
#ifndef READONLY
spi_cmd(EWSR);
spi_cs_on();
spi_write(WRSR);
spi_read();
spi_write(0x00);
spi_read();
spi_cs_off();
#endif
return (uint16_t)(manuf << 8 | product);
}
void spi_flash_sector_erase(uint32_t address)
{
uint8_t status;
address &= (~(SPI_FLASH_SECTOR_SIZE - 1));
wait_busy();
flash_write_enable();
spi_cs_on();
spi_write(SECTOR_ERASE);
spi_read();
write_address(address);
spi_cs_off();
wait_busy();
}
int spi_flash_read(uint32_t address, void *data, int len)
{
uint8_t *buf = data;
int i = 0;
wait_busy();
spi_cs_on();
spi_write(BYTE_READ);
spi_read();
write_address(address);
while (len > 0) {
spi_write(0xFF);
buf[i++] = spi_read();
len--;
}
spi_cs_off();
return i;
}
int spi_flash_write(uint32_t address, const void *data, int len)
{
if (chip_write_mode == SST_AAI)
return spi_flash_write_aai(address, data, len);
if (chip_write_mode == WB_WRITEPAGE)
return spi_flash_write_page(address, data, len);
return -1;
}

9
src/spi_flash.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef SPI_FLASH_DRI_H
#define SPI_FLASH_DRI_H
#include <stdint.h>
uint16_t spi_flash_probe(void);
void spi_flash_sector_erase(uint32_t address);
int spi_flash_read(uint32_t address, void *data, int len);
int spi_flash_write(uint32_t address, const void *data, int len);
#endif

View file

@ -18,9 +18,10 @@
#define MAX_INLINE_SIZE ((MAX_BLOCKS_0 - 1) * 4) /* Max data size for self-contained block */
#define INLINE_PAYLOAD(x) ((uint8_t *)(&x->blk[1])) /* Macro to access INLINE paylaod */
#ifdef CRYPTO
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/sha256.h>
#ifdef CRYPTO
#define CRYPTO_BLOCK_SIZE 16
uint8_t crypto_tmp[CRYPTO_BLOCK_SIZE];
@ -28,12 +29,14 @@ uint8_t crypto_iv[CRYPTO_BLOCK_SIZE];
#include <wolfssl/wolfcrypt/chacha.h>
#include <wolfssl/wolfcrypt/pwdbased.h>
#include <wolfssl/wolfcrypt/sha256.h>
static ChaCha chacha;
#define CRYPTO_KEY_SIZE 32
#endif
#define HASH_LEN 32
#define MAGIC 0x5AFED15C
static uint8_t cache[BLOCK_SIZE];
static uint8_t inline_buffer_copy[MAX_INLINE_SIZE];
@ -51,11 +54,19 @@ struct __attribute__((packed)) inode {
char filename[MAX_FILENAME];
};
struct __attribute__((packed)) root_block {
uint32_t magic;
uint32_t blk[((BLOCK_SIZE - MAX_FILENAME) / 4) - 3];
uint32_t fs_size; /* unused */
uint32_t nextfile;
uint8_t uuid[UUID_LEN];
uint8_t hash[HASH_LEN];
};
/* One-sector cache, single entry point for read/write
* on blocks
*/
static uint32_t cached_block = NO_BLOCK;
void *blockdev = NULL;
@ -87,7 +98,7 @@ static void cache_commit(void)
}
}
#endif
block_write(blockdev, cache, cached_block, 0, BLOCK_SIZE);
block_write(blockdev, cache, cached_block);
cached_block = NO_BLOCK;
}
@ -97,7 +108,7 @@ static void cache_load(uint32_t blk)
return;
if (cached_block != NO_BLOCK)
cache_commit();
if (block_read(blockdev, cache, blk, 0, BLOCK_SIZE) == BLOCK_SIZE) {
if (block_read(blockdev, cache, blk) == BLOCK_SIZE) {
cached_block = blk;
#ifdef CRYPTO
if (!is_block_empty()) {
@ -140,6 +151,13 @@ static uint32_t get_free_block(uint32_t *fs_tail)
uint32_t cur_inode_0 = 0;
int i;
cache_load(0);
if (ci->nextfile == NO_BLOCK) {
if (fs_tail)
*fs_tail = 0;
return 1;
}
cur_inode_0 = ci->nextfile;
cache_load(cur_inode_0);
while (1) {
for (i = 0; i < MAX_BLOCKS_0; i++)
{
@ -187,6 +205,7 @@ static uint32_t new_inode(void)
cache_load(fs_tail);
ci->nextfile = new_block;
cache_load(new_block);
memset(cache, 0xFF, BLOCK_SIZE);
ci->nextfile = NO_BLOCK;
return new_block;
}
@ -291,6 +310,42 @@ static void file_grow(uint32_t node0, uint32_t newsize)
ci->size = newsize;
}
/* Public interface */
int usecfs_format(const uint8_t *uuid)
{
struct root_block *rb = (struct root_block *)cache;
wc_Sha256 sha;
cache_load(0);
memset(cache, 0xFF, BLOCK_SIZE);
rb->magic = MAGIC;
rb->blk[0] = 0;
memcpy(rb->uuid, uuid, UUID_LEN);
wc_InitSha256(&sha);
wc_Sha256Update(&sha, uuid, UUID_LEN);
wc_Sha256Final(&sha, rb->hash);
cache_commit();
return 0;
}
int usecfs_mount(uint8_t *uuid)
{
struct root_block *rb = (struct root_block *)cache;
wc_Sha256 sha;
uint8_t hash[HASH_LEN];
cache_load(0);
if (rb->magic != MAGIC)
return -1;
wc_InitSha256(&sha);
wc_Sha256Update(&sha, rb->uuid, UUID_LEN);
wc_Sha256Final(&sha, hash);
if (memcmp(hash, rb->hash, HASH_LEN) != 0)
return -1;
if (uuid)
memcpy(uuid, rb->uuid, UUID_LEN);
return 0;
}
int usecfs_read(int fd, void *data, uint32_t len)
{
int r = 0;
@ -505,7 +560,7 @@ int usecfs_truncate(int fd, uint32_t newsize)
cache_load(new_idx_block);
if (idx_block != new_idx_block)
ci->extra = NO_BLOCK;
if (idx_off <= MAX_BLOCKS_0) {
if (idx_block <= MAX_BLOCKS_0) {
idx_off = new_idx_block;
for (i = idx_off; i < MAX_BLOCKS_N; i++)
ce->blk[i] = NO_BLOCK;
@ -551,6 +606,7 @@ int usecfs_close(int fd)
cache_commit();
OpenFiles[fd].blk = NO_BLOCK;
}
return 0;
}
#ifdef CRYPTO
@ -562,7 +618,7 @@ const uint8_t password_salt[SALT_LEN] = {
};
#endif
int usecfs_init(const char *password)
int usecfs_init(const char *password, int format, uint8_t *uuid)
{
blockdev = block_open(BLOCKDEV_OPEN_ARGS);
if (!blockdev)
@ -576,5 +632,11 @@ int usecfs_init(const char *password)
wc_Chacha_SetKey(&chacha, chacha_key, CRYPTO_KEY_SIZE);
}
#endif
return 0;
if (format) {
if (!uuid)
return -1;
else
return usecfs_format(uuid);
} else
return usecfs_mount(uuid);
}

View file

@ -2,9 +2,12 @@
#define INC_USECFS
#define MAX_FILENAME 256
#define MAX_OPEN_FILES 16
#define UUID_LEN 64
#include <stdint.h>
int usecfs_init(const char *password);
int usecfs_init(const char *password, int format, uint8_t *uuid);
int usecfs_format(const uint8_t *uuid);
int usecfs_mount(uint8_t *uuid);
int usecfs_open(const char *name);
int usecfs_creat(const char *name);
int usecfs_read(int fd, void *data, uint32_t len);

View file

@ -6,8 +6,8 @@
#endif
void *block_open(void *args);
int block_read(void *dev, void *_buf, uint32_t lba, int offset, int count);
int block_write(void *dev, const void *_buf, uint32_t lba, int offset, int count);
int block_read(void *dev, void *_buf, uint32_t lba);
int block_write(void *dev, const void *_buf, uint32_t lba);
void block_close(void *dev);
#endif

803
src/usecfs_dev_sdio.c Normal file
View file

@ -0,0 +1,803 @@
/*
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
*
* This software 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 the software. If not, see <http://www.gnu.org/licenses/>.
*
* Original Author: Chuck M. (see https://github.com/ChuckM/stm32f4-sdio-driver/)
* Re-adapted by: Daniele Lacamera
*
* Permission to release under the terms of GPLv2 are granted by the
* copyright holders.
*
*/
/*
* SDIO Bus Driver layer. This code sends commands and drives
* the SDIO peripheral on the STM32F4xx, there is a layer above
* this, the SD Card driver, which uses this driver to talk to
* SD Cards. The SPI driver can also talk to SD Cards, hence the
* split at this layer.
*
* Note that the simple implementation for the SDIO driver runs
* in a 'polled' mode. This is easier to explain and debug and
* sufficient for the first few projects. A more sophisticated
* version with DMA and interrupts will follow.
*
*
*
*/
#include <stdint.h>
#include "usecfs_dev_sdio.h"
#include "system.h"
#if (!defined(BLOCK_SIZE)) || (BLOCK_SIZE != 512)
# error BLOCK_SIZE undefined or invalid
#endif
#ifndef NULL
#define NULL (void *)(0x00000000)
#endif
/*
* Helper defines to pull out various bit fields of the CSD for
* the size calculation.
*/
#define SDIO_CSD_VERSION(x) stm32_sdio_bit_slice(x->csd, 128, 127, 126)
#define SDIO_CSD1_CSIZE_MULT(x) stm32_sdio_bit_slice(x->csd, 128, 49, 47)
#define SDIO_CSD1_RBLKLEN(x) stm32_sdio_bit_slice(x->csd, 128, 83, 80)
#define SDIO_CSD1_CSIZE(x) stm32_sdio_bit_slice(x->csd, 128, 73, 62)
#define SDIO_CSD2_CSIZE(x) stm32_sdio_bit_slice(x->csd, 128, 69, 48)
/*
* Conveniently swaps the bytes in a long around
* used by the SCR code.
*/
#define byte_swap(val) \
asm("rev %[swap], %[swap]" : [swap] "=r" (val) : "0" (val));
static const uint32_t sdio_pins[5] = { 8, 9, 10, 11, 12}; /* GPIOC */
static const uint32_t sdio_cmd_pin = 2; /* GPIOD */
static const uint32_t sdio_detect_pin = 8; /* GPIOA */
static const uint32_t sdio_af = 12;
static struct dev_sd SD;
/*
* sdio_bus
*
* Set the bus width and the clock speed for the
* SDIO bus.
*
* Returns 0 on success
* -1 illegal bit specification
* -2 illegal clock specification
*/
int
stm32_sdio_bus(struct dev_sd *sd, int bits, enum SDIO_CLOCK_DIV freq) {
int clkreg = 0;
switch (bits) {
case 1:
clkreg |= SDIO_CLKCR_WIDBUS_1;
break;
case 4:
clkreg |= SDIO_CLKCR_WIDBUS_4;
break;
default:
return -1;
}
switch (freq) {
case SDIO_24MHZ:
break;
case SDIO_16MHZ:
clkreg |= 1;
break;
case SDIO_12MHZ:
clkreg |= 2;
break;
case SDIO_8MHZ:
clkreg |= 8;
break;
case SDIO_4MHZ:
clkreg |= 10;
break;
case SDIO_1MHZ:
clkreg |= 46;
break;
case SDIO_400KHZ:
clkreg |= 118;
break;
default:
return -2;
}
clkreg |= SDIO_CLKCR_CLKEN;
SDIO_CLKCR = clkreg;
return 0;
}
/*
* Reset the state of the SDIO bus and peripheral. This code tries
* to reset the bus *AND* the card if one is plugged in. The bus
* can be reset by software but the card is reset by powering it down.
*
* The SDIO_POWER_STATE tells the code which state to leave the bus in,
* powered up or powered down.
*
* If the state is POWER_ON, then the bus is reset to 400Khz, 1 bit wide
* which is what he spec requires. Once the type and capabilities of the
* card have been determined, it can be upgraded.
*/
void
stm32_sdio_reset(struct dev_sd *sd, enum SDIO_POWER_STATE state) {
/* Step 1 power off the interface */
SDIO_POWER = SDIO_POWER_PWRCTRL_PWROFF;
/* reset the SDIO peripheral interface */
APB2_CLOCK_RST |= SDIO_APB2_CLOCK_ER_VAL;
APB2_CLOCK_RST &= ~SDIO_APB2_CLOCK_ER_VAL;
if (state == SDIO_POWER_ON) {
SDIO_POWER = SDIO_POWER_PWRCTRL_PWRON;
stm32_sdio_bus(sd, 1, SDIO_400KHZ); // required by the spec
}
}
/*
* The error message catalog.
*/
static const char *__sdio_error_msgs[] = {
"Success",
"Command Timeout", // -1
"Command CRC Failure", // -2
"Soft Timeout (No Response)", // -3
"Data CRC Failure", // -4
"RX FIFO Overrun", // -5
"TX FIFO Underrun", // -6
"Unsupported Card" // -7
};
#define SDIO_ESUCCESS 0
#define SDIO_ECTIMEOUT -1
#define SDIO_ECCRCFAIL -2
#define SDIO_ENORESP -3
#define SDIO_EDCRCFAIL -4
#define SDIO_ERXOVERR -5
#define SDIO_ETXUNDER -6
#define SDIO_EBADCARD -7
#define SDIO_EUNKNOWN -8
/*
* Return a text string description of the error code.
*/
const char *
stm32_sdio_errmsg(int err) {
return (err <= SDIO_EUNKNOWN) ? (const char *) "Unknown Error" :
__sdio_error_msgs[0-err];
}
/*
* stm32_sdio_bit_slice - helper function
*
* A number of the things the SDIO returns are in bit
* fields. This code is designed to slice out a range
* of bits and return them as a value (up to 32 bits
* worth).
*/
uint32_t
stm32_sdio_bit_slice(uint32_t a[], int bits, int msb, int lsb) {
uint32_t t;
int i;
if (((msb >= bits) || (msb < 0)) ||
(lsb > msb) ||
((lsb < 0) || (lsb >= bits))) {
return 0;
}
t = 0;
for (i = msb; i > lsb; i--) {
t |= (a[((bits-1) - i)/32] >> (i % 32)) & 0x1;
t <<= 1;
}
t |= (a[((bits-1) - lsb)/32] >> (lsb % 32)) & 0x1;
return t;
}
/*
* A convienence define. These are the flags we care about when
* sending a command. During command processing SDIO_STA_CMDACT
* will be set.
*/
#define COMMAND_FLAGS (SDIO_STA_CMDSENT |\
SDIO_STA_CCRCFAIL |\
SDIO_STA_CMDREND |\
SDIO_STA_CTIMEOUT)
/*
* Send a command over the SDIO bus.
* Passed a command (8 bit value) and an argument (32 bit value)
* This command figures out if the command will return a short (32 bit)
* or long (64 bit) response. It is up to the calling program to pull
* data from the long response commands.
* Passed:
* cmd - Command to execute
* arg - Argument to pass to the command
* buf - pointer to a long aligned buffer if data
* len - expected length of buffer (in bytes)
*/
int
stm32_sdio_command(struct dev_sd *sd, uint32_t cmd, uint32_t arg)
{
uint32_t tmp_val;
int error = 0;
tmp_val = SDIO_CMD & ~0x7ff; // Read pre-existing state
tmp_val |= (cmd & SDIO_CMD_CMDINDEX_MSK); // Put the Command in
tmp_val |= SDIO_CMD_CPSMEN; // We'll be running CPSM
switch(cmd) {
case 0:
tmp_val |= SDIO_CMD_WAITRESP_NO_0;
break;
case 2:
case 9:
tmp_val |= SDIO_CMD_WAITRESP_LONG;
break;
default:
tmp_val |= SDIO_CMD_WAITRESP_SHORT; // the common case
break;
}
/* If a data transaction is in progress, wait for it to finish */
while ((cmd != 12) & (SDIO_STA & (SDIO_STA_RXACT | SDIO_STA_TXACT)));;
/*
* EXECUTE:
* o Reset all status bits
* o Put ARG into SDIO ARG
* o reset the error indicator
* o Enable all interrupts.
* o Do the command
*/
SDIO_ICR = 0x7ff; // Reset everything that isn't bolted down.
SDIO_ARG = arg;
SDIO_CMD = tmp_val;
/*
* In a polled mode we should be able to just read the status bits
* directly.
*/
tmp_val = 0;
do {
tmp_val |= (SDIO_STA & 0x7ff);
} while ((SDIO_STA & SDIO_STA_CMDACT) || (! tmp_val));;
SDIO_ICR = tmp_val;
/*
* Compute the error here. Which can be one of
* -- Success (either CMDSENT or CMDREND depending on response)
* -- Timeout (based on CTIMEOUT)
* -- No Response (based on no response in the time alloted)
* -- CRC Error (based on CCRCFAIL)
*/
if (! tmp_val) {
error = SDIO_ENORESP;
} else if (tmp_val & SDIO_STA_CCRCFAIL) {
error = SDIO_ECCRCFAIL;
} else if (tmp_val & (SDIO_STA_CMDREND | SDIO_STA_CMDSENT)) {
error = SDIO_ESUCCESS;
} else if (tmp_val & SDIO_STA_CTIMEOUT) {
error = SDIO_ECTIMEOUT;
} else {
error = SDIO_EUNKNOWN;
}
return error;
}
/* our static data buffer we use for data movement commands */
/*
* Helper function - sdio_select
*
* This function "selects" a card using CMD7, note that if
* you select card 0 that deselects the card (RCA is not allowed
* to be 0)
*/
static int
sdio_select(struct dev_sd *sd, int rca) {
int err;
err = stm32_sdio_command(sd, 7, rca << 16);
if ((rca == 0) && (err == SDIO_ECTIMEOUT)) {
return 0; // "cheat" a timeout selecting 0 is a successful deselect
}
return err;
}
/*
* Helper function - sdio_scr
*
* Unlike the CID and CSD functions this function transfers data
* so it needs to use the DPSM.
*
* Note that data over the wire is byte swapped so we swap it back
* to "fix" it.
*
* Note when this return 0 the first two longs in the data_buf are
* the SCR register.
*/
static uint32_t data_buf[129];
static int
sdio_scr(struct dev_sd *sd, SDIO_CARD c) {
int err;
uint32_t tmp_reg;
int ndx;
int data_len;
/* Select the card */
err = sdio_select(sd, c->rca);
if (! err) {
/* Set the Block Size */
err = stm32_sdio_command(sd, 16, 8);
if (! err) {
/* APPCMD (our RCA) */
err = stm32_sdio_command(sd, 55, c->rca << 16);
if (! err) {
SDIO_ICR = 0xFFFFFFFF; /* Clear all status flags */
SDIO_DTIMER = 0xffffffff;
SDIO_DLEN = 8;
SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 |
SDIO_DCTRL_DTDIR |
SDIO_DCTRL_DTEN;
/* ACMD51 - Send SCR */
err = stm32_sdio_command(sd, 51, 0);
if (! err) {
data_len = 0;
do {
tmp_reg = SDIO_STA;
if (tmp_reg & SDIO_STA_RXDAVL) {
data_buf[data_len++] = SDIO_FIFO;
}
} while (tmp_reg & SDIO_STA_RXACT);
if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
if (tmp_reg & SDIO_STA_DCRCFAIL) {
err = SDIO_EDCRCFAIL;
} else if (tmp_reg & SDIO_STA_RXOVERR) {
err = SDIO_ERXOVERR;
} else {
err = SDIO_EUNKNOWN; // unknown error
}
}
if (! err) {
for (ndx = 0; ndx < 2; ndx++) {
byte_swap(data_buf[ndx]);
c->scr[ndx] = data_buf[ndx];
}
}
}
}
}
}
(void) sdio_select(sd, 0);
return err;
}
/*
* Read a Block from our Card
*
* NB: There is a possibly useless test in this code, during the read
* phase it allows that the SDIO card might try to send more than BLOCK_SIZE
* bytes (128 32 bit longs) and allows it to do so, constantly over
* writing the last long in the just-in-case-over-long-by-1 data buffer.
* To compromise the system you would need a borked or custom crafted
* sdio card which did that.
*/
int block_read(void *dev, void *_buf, uint32_t lba)
{
int err;
uint32_t tmp_reg;
uint32_t addr = lba;
uint8_t *t;
int ndx, bdx = 0;
struct dev_sd *sd = &SD;
uint32_t *buf = _buf;
uint32_t buf_len = 0;
if (! SDIO_CARD_CCS(sd->card)) {
addr = lba * BLOCK_SIZE; // non HC cards use byte address
}
err = sdio_select(sd, sd->card->rca);
if (! err) {
err = stm32_sdio_command(sd, 16, BLOCK_SIZE);
if (!err) {
SDIO_DTIMER = 0xffffffff;
SDIO_DLEN = BLOCK_SIZE;
SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_9 |
SDIO_DCTRL_DTDIR |
SDIO_DCTRL_DTEN;
err = stm32_sdio_command(sd, 17, addr);
if (! err) {
buf_len = 0;
do {
tmp_reg = SDIO_STA;
if (tmp_reg & SDIO_STA_RXDAVL) {
buf[buf_len] = SDIO_FIFO;
if (buf_len < 128) {
++buf_len;
}
}
} while (tmp_reg & SDIO_STA_RXACT);
if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
if (tmp_reg & SDIO_STA_DCRCFAIL) {
err = SDIO_EDCRCFAIL;
} else if (tmp_reg & SDIO_STA_RXOVERR) {
err = SDIO_ERXOVERR;
} else {
err = SDIO_EUNKNOWN; // Unknown Error!
}
} else {
err = BLOCK_SIZE;
}
}
}
}
// deselect the card
(void) sdio_select(sd, 0);
return err;
}
/*
* Write a Block from our Card
*/
int block_write(void *dev, void *_buf, uint32_t lba)
{
int err;
uint32_t tmp_reg;
uint32_t addr = lba;
uint8_t *t;
int ndx;
struct dev_sd *sd = &SD;
SDIO_CARD c;
uint32_t *buf = _buf;
uint32_t buf_len = 0;
c = SD.card;
if (! SDIO_CARD_CCS(c)) {
addr = lba * BLOCK_SIZE; // non HC cards use byte address
}
err = sdio_select(sd, c->rca);
if (! err) {
/* Set Block Size to BLOCK_SIZE */
err = stm32_sdio_command(sd, 16, BLOCK_SIZE);
if (!err) {
SDIO_DTIMER = 0xffffffff;
SDIO_DLEN = BLOCK_SIZE;
SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_9 |
SDIO_DCTRL_DTEN;
err = stm32_sdio_command(sd, 24, addr);
if (! err) {
do {
tmp_reg = SDIO_STA;
if (tmp_reg & SDIO_STA_TXFIFOHE) {
SDIO_FIFO = buf[buf_len];
if (buf_len < 128) {
++buf_len;
}
}
} while (tmp_reg & SDIO_STA_TXACT);
if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
if (tmp_reg & SDIO_STA_DCRCFAIL) {
err = SDIO_EDCRCFAIL;
} else if (tmp_reg & SDIO_STA_TXUNDERR) {
err = SDIO_ETXUNDER;
} else {
err = SDIO_EUNKNOWN; // Unknown Error!
}
}
}
}
}
// deselect the card
(void) sdio_select(sd, 0);
if (err == 0)
return BLOCK_SIZE;
return err;
}
/*
* sdio-status - Get Card Status page
*
* This function fetches the SD Card Status page and
* copies it into the CARD structure.
*/
/*
int
sdio_status(SDIO_CARD c) {
uint32_t tmp_reg;
int ndx;
int err;
err = sdio_select(c->rca);
if (! err) {
err = stm32_sdio_command(16, 64);
if (! err) {
err = stm32_sdio_command(55, c->rca << 16);
if (! err) {
SDIO_DTIMER = 0xffffffff;
SDIO_DLEN = 64;
SDIO_DCTRL = SDIO_DCTRL_DBLOCKSIZE_6 |
SDIO_DCTRL_DTDIR |
SDIO_DCTRL_DTEN; */
/* ACMD13 - Send Status Reg */ /*
err = stm32_sdio_command(13, 0);
if (! err) {
data_len = 0;
do {
tmp_reg = SDIO_STA;
if (tmp_reg & SDIO_STA_RXDAVL) {
data_buf[data_len] = SDIO_FIFO;
if (data_len < 128) {
++data_len;
}
}
} while (tmp_reg & SDIO_STA_RXACT);
if ((tmp_reg & SDIO_STA_DBCKEND) == 0) {
if (tmp_reg & SDIO_STA_DCRCFAIL) {
err = SDIO_EDCRCFAIL;
} else if (tmp_reg & SDIO_STA_RXOVERR) {
err = SDIO_ERXOVERR;
} else {
err = SDIO_EUNKNOWN; // Unknown Error!
}
} else {
for (ndx = 0; ndx < 16; ndx++) {
byte_swap(data_buf[ndx]);
c->status[ndx] = data_buf[ndx];
}
}
(void) sdio_select(0);
}
}
}
}
return err;
}
*/
static struct SDIO_CARD_DATA sdio_card_data;
#define MAX_RETRIES 5
/*
* stm32_sdio_open - Prepare to use SDIO card
*
* This function resets the SDIO bus and identifies the
* card (if any) that is plugged in. If there is no card
* present, or an error in figuring out what the card is
* (for example its an old MMC card) the function returns
* NULL. If it fails and you have logging enabled you can
* look at the last few commands sent.
*/
SDIO_CARD
stm32_sdio_open(struct dev_sd *sd) {
int err;
int i;
uint8_t *t;
uint32_t tmp_reg;
SDIO_CARD res = &sdio_card_data;
// basically bset(0, sdio_card_data)
t = (uint8_t *) &sdio_card_data;
for (i = 0; i < (int) sizeof(sdio_card_data); i++) {
*t++ = 0;
}
stm32_sdio_reset(sd, SDIO_POWER_ON);
err = stm32_sdio_command(sd, 0, 0);
if (!err) {
err = stm32_sdio_command(sd, 8, 0x1aa);
if (!err) {
// Woot! We support CMD8 so we're a v2 card at least */
tmp_reg = SDIO_RESP1;
sdio_card_data.props = 1;
i = 0;
err = stm32_sdio_command(sd, 5, 0);
if (! err) {
// It is an SDIO card which is unsupported!
err = SDIO_EBADCARD;
return NULL;
}
do {
err = stm32_sdio_command(sd, 55, 0); // broadcast ACMD
if (err) {
break; // try again
}
// Testing Card Busy, Voltage match, and capacity
err = stm32_sdio_command(sd, 41, 0xc0100000);
if (err != -2) { // Expect CCRCFAIL here
break; // try again
}
tmp_reg = SDIO_RESP1; // what did the card send?
if ((tmp_reg & 0x80000000) == 0) {
continue; // still powering up
}
res->ocr = tmp_reg; // Ok OCR is valid
break;
} while (++i < MAX_RETRIES);
if (res->ocr) {
err = stm32_sdio_command(sd, 2, 0);
if (! err) {
res->cid[0] = SDIO_RESP1;
res->cid[1] = SDIO_RESP2;
res->cid[2] = SDIO_RESP3;
res->cid[3] = SDIO_RESP4;
err = stm32_sdio_command(sd, 3, 0); // get the RCA
if (! err) {
tmp_reg = SDIO_RESP1;
res->rca = (tmp_reg >> 16) & 0xffff;
if (! res->rca) {
/*
* If the card says '0' tell it to pick
* we assume this will work because the
* previous send RCA worked and the card
* should be in the ident state if it is
* functioning correctly.
*/
(void) stm32_sdio_command(sd, 3, 0); // try again
tmp_reg = SDIO_RESP1;
res->rca = (tmp_reg >> 16) & 0xffff;
}
err = stm32_sdio_command(sd, 9, res->rca << 16);
if (! err) {
res->csd[0] = SDIO_RESP1;
res->csd[1] = SDIO_RESP2;
res->csd[2] = SDIO_RESP3;
res->csd[3] = SDIO_RESP4;
err = sdio_scr(sd, res); // Capture the SCR
if (! err) {
/* All SD Cards support 4 bit bus and 24Mhz */
err = sdio_select(sd, res->rca);
if (! err) {
err = stm32_sdio_command(sd, 55, res->rca << 16);
if (! err) {
err = stm32_sdio_command(sd, 6, 2);
if (! err) {
//XXX stm32_sdio_bus(4, SDIO_24MHZ);
//Seems we have speed issues for now...
stm32_sdio_bus(sd, 4, SDIO_12MHZ);
(void) sdio_select(sd, 0);
}
}
}
}
}
}
}
}
}
}
/* Compute the size of the card based on fields in the CSD
* block. There are two kinds, V1 or V2.
* In the V1 Case :
* Size = 1<<BLOCK_LEN * 1<<(MULT+2) * (C_SIZE+1) bytes.
* In the V2 Case :
* Size = (C_SIZE + 1) * BLOCK_SIZEK bytes.
* But for our structure we want the size in BLOCK_SIZE byte "blocks"
* since that is the addressing unit we're going to export so
* we compute the size / BLOCK_SIZE as the "size" for the structure.
*/
if (! err) {
res->size = 0;
switch (SDIO_CSD_VERSION(res)) {
case 0:
tmp_reg = ((1 << (SDIO_CSD1_CSIZE_MULT(res) + 2)) *
( 1 << SDIO_CSD1_RBLKLEN(res))) >> 9;
res->size = tmp_reg * (SDIO_CSD1_CSIZE(res) + 1);
break;
case 1:
res->size = (SDIO_CSD2_CSIZE(res)+1) << 10;
break;
default:
res->size = 0; // Bug if its not CSD V1 or V2
}
}
return (err == 0) ? res : NULL;
}
static int stm32_sdio_card_detect(void)
{
uint8_t block[BLOCK_SIZE];
SDIO_CARD sdcard;
if (SD.card != NULL)
return 0;
sdcard = stm32_sdio_open(&SD);
if (sdcard != NULL) {
SD.card = sdcard;
return 0;
}
return -1;
}
/*
* Set up the GPIO pins and peripheral clocks for the SDIO
* system. The code should probably take an option card detect
* pin, at the moment it uses the one used by the Embest board.
*/
static void sdio_hw_init(void)
{
int i;
uint32_t reg;
/* Enable clocks for SDIO and DMA2 */
APB2_CLOCK_ER |= SDIO_APB2_CLOCK_ER_VAL;
/* Enable clocks for GPIOA, GPIOC, GPIOD */
AHB1_CLOCK_ER |= GPIOA_AHB1_CLOCK_ER |
GPIOC_AHB1_CLOCK_ER | GPIOD_AHB1_CLOCK_ER;
for (i = 0 ; i < 5; i++) {
/* mode = AF */
reg = GPIOC_MODE & ~ (0x03 << (sdio_pins[i] * 2));
GPIOC_MODE = reg | (2 << (sdio_pins[i] * 2));
#if 0
/* Set 100MHz ospeed + pullup */
GPIOC_OSPEED |= (0x03 << (sdio_pins[i] * 2));
GPIOC_OTYPE &= ~(0x01 << (sdio_pins[i]));
reg = GPIOC_PUPD & (~(0x03 << (sdio_pins[i] & 2)));
GPIOC_PUPD = reg | (1 << (sdio_pins[i] * 2));
#endif
/* Alternate function: use high pins (8..12) */
reg = GPIOC_AFH & ~(0xf << ((sdio_pins[i] - 8) * 4));
GPIOC_AFH = reg | (sdio_af << ((sdio_pins[i] - 8) * 4));
}
/* cmd pin */
reg = GPIOD_MODE & ~ (0x03 << (sdio_cmd_pin * 2));
GPIOD_MODE = reg | (2 << (sdio_cmd_pin * 2));
#if 0
/* Set 100MHz ospeed + pullup */
GPIOD_OSPEED |= (0x03 << (sdio_cmd_pin * 2));
GPIOD_OTYPE &= ~(0x01 << (sdio_cmd_pin));
reg = GPIOD_PUPD & (~(0x03 << (sdio_cmd_pin & 2)));
GPIOD_PUPD = reg | (1 << (sdio_cmd_pin * 2));
#endif
/* Alternate function: use low pin */
reg = GPIOD_AFL & ~(0xf << ((sdio_cmd_pin) * 4));
GPIOD_AFL = reg | (sdio_af << ((sdio_cmd_pin) * 4));
/* card detect pin configured as input */
GPIOA_MODE &= ~ (0x03 << (sdio_detect_pin * 2));
reg = GPIOA_PUPD & (~(0x03 << (sdio_detect_pin & 2)));
GPIOA_PUPD = reg | (1 << (sdio_detect_pin * 2));
}
void *block_open(void)
{
int ret;
/* Initialize sdio RCC and pins */
sdio_hw_init();
do {
ret = stm32_sdio_card_detect();
} while (ret < 0);
return &SD;
}

54
src/usecfs_dev_sdio.h Normal file
View file

@ -0,0 +1,54 @@
/* this define lets the init code know that you are using a GPIO as a card
* detect pin */
#define SDIO_HAS_CARD_DETECT
enum SDIO_CLOCK_DIV {
SDIO_24MHZ = 0,
SDIO_16MHZ,
SDIO_12MHZ,
SDIO_8MHZ,
SDIO_4MHZ,
SDIO_1MHZ,
SDIO_400KHZ
};
enum SDIO_POWER_STATE {
SDIO_POWER_ON,
SDIO_POWER_OFF
};
#define SDIO_CARD_CCS(c) (((c)->ocr & 0x40000000) != 0)
#define SDIO_CARD_UHS2(c) (((c)->ocr & 0x40000000) != 0)
#define SDIO_CARD_LVOK(c) (((c)->ocr & 0x01000000) != 0)
typedef struct SDIO_CARD_DATA {
uint32_t props;
uint32_t ocr;
uint32_t cid[4];
uint32_t csd[4];
uint32_t scr[2];
uint32_t status[16];
uint32_t size;
uint16_t rca;
} * SDIO_CARD;
struct dev_sd {
struct device *dev;
uint32_t base;
uint32_t *rcc_rst_reg;
uint32_t rcc_rst;
SDIO_CARD card;
};
/* API for sd_bus clock setting */
enum SD_CLOCK_DIV {
CLOCK_24MHZ = 0,
CLOCK_16MHZ,
CLOCK_12MHZ,
CLOCK_8MHZ,
CLOCK_4MHZ,
CLOCK_1MHZ,
CLOCK_400KHZ
};
//int stm32_sd_bus(int bits, enum SD_CLOCK_DIV freq);

36
src/usecfs_dev_spi.c Normal file
View file

@ -0,0 +1,36 @@
#include <stdint.h>
#include "usecfs_dev.h"
#include "spi_flash.h"
static uint32_t part_base = 0xFFFFFFFF;
static uint32_t part_size = 0;
void *block_open(void *args_ptr)
{
uint32_t *args = (uint32_t *)args_ptr;
part_base = args[0];
part_size = args[1];
return &part_base;
}
int block_read(void *dev, void *_buf, uint32_t lba)
{
if (part_size == 0)
return -1;
return spi_flash_read(part_base + (lba * BLOCK_SIZE), _buf, BLOCK_SIZE);
}
int block_write(void *dev, const void *_buf, uint32_t lba)
{
if (part_size == 0)
return -1;
spi_flash_sector_erase(part_base + lba * BLOCK_SIZE);
return spi_flash_write(part_base + lba * BLOCK_SIZE, _buf, BLOCK_SIZE);
}
void block_close(void *dev)
{
(void)dev;
part_base = 0xFFFFFFFF;
part_size = 0;
}

View file

@ -12,28 +12,34 @@ void *block_open(void *args)
char *file = (char *)args;
int i;
uint8_t ff = 0xFF;
fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0660);
fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0660);
if (fd >= 0) {
for (i = 0; i < FS_SIZE; i++)
write(fd, &ff, 1);
} else {
fd = open(file, O_RDWR);
}
if (fd < 0)
return NULL;
for (i = 0; i < FS_SIZE; i++)
write(fd, &ff, 1);
lseek(fd, 0, SEEK_SET);
return &fd;
}
int block_read(void *dev, void *_buf, uint32_t lba, int offset, int count)
int block_read(void *dev, void *_buf, uint32_t lba)
{
(void)dev;
lseek(fd, lba * BLOCK_SIZE + offset, SEEK_SET);
read(fd, _buf, count);
lseek(fd, lba * BLOCK_SIZE, SEEK_SET);
return read(fd, _buf, BLOCK_SIZE);
}
int block_write(void *dev, const void *_buf, uint32_t lba, int offset, int count)
int block_write(void *dev, const void *_buf, uint32_t lba)
{
(void)dev;
lseek(fd, lba * BLOCK_SIZE + offset, SEEK_SET);
write(fd, _buf, count);
lseek(fd, lba * BLOCK_SIZE, SEEK_SET);
return write(fd, _buf, BLOCK_SIZE);
}
void block_close(void *dev)
{
(void)dev;

View file

@ -6,4 +6,4 @@ test: main.o ../src/usecfs.o ../src/usecfs_dev_test.o
gcc -o $@ $^ -lwolfssl
clean:
rm main.o ../src/usecfs.o ../src/usecfs_dev_test.o test
@rm -f test main.o ../src/*.o

View file

@ -1,64 +1,102 @@
#include "usecfs.h"
#include <stdio.h>
const uint8_t test_uuid[UUID_LEN] = {
0xb3, 0x6b, 0x82, 0x05, 0xb6, 0xcd, 0x28, 0xaa, 0xc7, 0x81, 0x2e, 0x2d,
0xfd, 0xdd, 0x5e, 0x70, 0x3f, 0xbf, 0x09, 0x03, 0x1b, 0x5f, 0xbe, 0xc6,
0x09, 0x62, 0xa8, 0x23, 0xe9, 0x99, 0x5e, 0xcb, 0xb4, 0xab, 0x28, 0xdc,
0x14, 0xca, 0x35, 0xb4, 0x7d, 0xfe, 0x26, 0x81, 0x33, 0xd0, 0x4b, 0xc2,
0x49, 0x53, 0x05, 0xc3, 0xe7, 0xbd, 0x9a, 0x50, 0xb8, 0x01, 0x30, 0x0b,
0x62, 0x58, 0xad, 0xbf
};
int main(void)
{
int fd;
int buf[40] = { };
int uuid[UUID_LEN];
if (usecfs_init("sEcret") < 0)
if (usecfs_init("sEcret", 0, NULL) < 0)
{
printf("error.\n");
return 1;
printf("Filesystem is not formatted. Formatting.\n");
if (usecfs_init("sEcret", 1, test_uuid) != 0) {
printf("Format failed.\n");
return 1;
}
}
printf("Creating file 'file1' \n");
fd = usecfs_creat("file1");
if (fd < 0) {
printf("error: creat.\n");
return 1;
printf("could not create file (this is OK unless open fails)\n");
fd = usecfs_open("file1");
if (fd < 0) {
printf("error: open\n");
return 1;
}
}
if (usecfs_write(fd, "test string file 1 content", 26) < 0) {
printf("Writing to file 'file1' \n");
if (usecfs_write(fd, "test string file 1 content\n", 27) < 0) {
printf("error: write.\n");
return 1;
}
usecfs_close(fd);
printf("Re-opening\n");
fd = usecfs_open("file1");
if (fd < 0) {
printf("error: open\n");
return 1;
}
if (usecfs_read(fd, buf, 26) != 26) {
printf("Reading file...\n");
if (usecfs_read(fd, buf, 27) != 27) {
printf("error: read.\n");
return 1;
}
printf("%s", buf);
if (usecfs_write(fd, "test string2", 12) < 0) {
printf("content of file 'file1': ");
printf("%s\n", buf);
printf("appending 'test string2'\n");
if (usecfs_write(fd, "test string2\n", 13) < 0) {
printf("error: write.\n");
return 1;
}
printf("seek to 0\n");
if (usecfs_seek(fd, 0, 0) != 0) {
printf("error: seek.\n");
return 1;
}
if (usecfs_read(fd, buf, 36) != 36) {
printf("Reading...\n");
if (usecfs_read(fd, buf, 40) < 0) {
printf("error: read.\n");
return 1;
}
printf("%s", buf);
usecfs_close(fd);
printf("Creating file 'file2' \n");
fd = usecfs_creat("file2");
if (fd < 0) {
printf("error: creat2.\n");
return 1;
printf("could not create file (this is OK unless open fails)\n");
fd = usecfs_open("file2");
if (fd < 0) {
printf("error: open\n");
return 1;
}
}
usecfs_close(fd);
printf("Creating file 'file3' \n");
fd = usecfs_creat("file3");
if (fd < 0) {
printf("error: creat2.\n");
return 1;
if (fd < 0) {
printf("could not create file (this is OK unless open fails)\n");
fd = usecfs_open("file3");
if (fd < 0) {
printf("error: open\n");
return 1;
}
}
}
usecfs_close(fd);