__sfr __at (Z180_IO_BASE + 0x1C) ASCI_ASTC1L; /* ASCI time constant register channel 1 low */
__sfr __at (Z180_IO_BASE + 0x1D) ASCI_ASTC1H; /* ASCI time constant register channel 1 high */
+__sfr __at (Z180_IO_BASE + 0x0A) CSIO_CNTR; /* CSI/O control/status register */
+__sfr __at (Z180_IO_BASE + 0x0B) CSIO_TRDR; /* CSI/O transmit/receive data register */
+
__sfr __at (0xE0) ESCC_CTRL_A; /* ESCC Channel A control register */
__sfr __at (0xE1) ESCC_DATA_A; /* ESCC Channel A data register */
__sfr __at (0xE2) ESCC_CTRL_B; /* ESCC Channel B control register */
--- /dev/null
+/*-----------------------------------------------------------------------*/
+/* Fuzix SD card driver */
+/* 2014-12-28 Will Sowerbutts */
+/* */
+/* Based on UZI-socz80 SD card driver, which was itself based on: */
+/* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2007 */
+/* (from http://www.cl.cam.ac.uk/teaching/1011/P31/lib/diskio.c) */
+/* and http://elm-chan.org/docs/mmc/mmc_e.html */
+/*-----------------------------------------------------------------------*/
+
+/* Minor numbers: See comments in devide.c, exactly the same scheme is used here. */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+#include <devsd.h>
+#include <stdbool.h>
+#include <mbr.h>
+#include "config.h"
+
+#define MAX_SLICES 63
+
+/* keep track of current card type, UZI partition offset */
+static uint8_t sd_drive_present; /* bitmap */
+static uint8_t sd_card_type[SD_DRIVE_COUNT];
+static uint32_t sd_partition_start[SD_DRIVE_COUNT];
+static uint8_t sd_slice_count[SD_DRIVE_COUNT];
+
+/* internal functions */
+static void sd_init_drive(uint8_t drive);
+static int sd_readwrite(uint8_t minor, uint8_t rawflag, bool do_write);
+static int sd_spi_init(uint8_t drive);
+static void sd_spi_release(uint8_t drive);
+static int sd_spi_wait_ready(uint8_t drive);
+static bool sd_spi_transmit_block(uint8_t drive, void *ptr, unsigned int length);
+static bool sd_spi_receive_block(uint8_t drive, void *ptr, unsigned int length);
+static int sd_send_command(uint8_t drive, unsigned char cmd, uint32_t arg);
+static uint32_t sd_get_size_sectors(uint8_t drive);
+static bool sd_read_sector(uint8_t drive, void *ptr, uint32_t lba);
+static bool sd_write_sector(uint8_t drive, void *ptr, uint32_t lba);
+
+int devsd_open(uint8_t minor, uint16_t flags)
+{
+ uint8_t drive;
+ flags; /* not used */
+
+ drive = minor >> 6;
+ minor = minor & 0x3F;
+
+ if(sd_drive_present & (1 << drive) && (minor == 0 || minor < sd_slice_count[drive]))
+ return 0;
+
+ udata.u_error = ENODEV;
+ return -1;
+}
+
+int devsd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag; /* not used */
+ return sd_readwrite(minor, rawflag, false);
+}
+
+int devsd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag; /* not used */
+ return sd_readwrite(minor, rawflag, true);
+}
+
+void devsd_init(void)
+{
+ uint8_t d;
+
+ sd_drive_present = 0;
+ for(d=0; d<SD_DRIVE_COUNT; d++)
+ sd_init_drive(d);
+}
+
+static int sd_readwrite(uint8_t minor, uint8_t rawflag, bool do_write)
+{
+ uint32_t lba;
+ int attempt;
+ void *target;
+ uint8_t drive;
+
+ drive = minor >> 6;
+ minor = minor & 0x3F;
+
+ if(rawflag == 0){
+ target = udata.u_buf->bf_data;
+
+ for(attempt=0; attempt<5; attempt++){
+ lba = udata.u_buf->bf_blk;
+
+ /* minor 0 is the whole drive, without translation */
+ if(minor > 0){
+ lba += sd_partition_start[drive];
+ lba += ((unsigned long)(minor-1) << SLICE_SIZE_LOG2_SECTORS);
+ }
+ if(do_write){
+ if(sd_write_sector(drive, udata.u_buf->bf_data, lba))
+ return 1;
+ }else{
+ if(sd_read_sector(drive, udata.u_buf->bf_data, lba))
+ return 1;
+ }
+ kputs("sd: failed, retrying.\n");
+ }
+ }
+
+ udata.u_error = EIO;
+ return -1;
+}
+
+static void sd_init_drive(uint8_t drive)
+{
+ uint32_t sector_count;
+ unsigned char *sector;
+
+ sd_partition_start[drive] = 0;
+ sd_slice_count[drive] = 0;
+
+ kprintf("sd%c: ", 'a'+drive);
+ sd_card_type[drive] = sd_spi_init(drive);
+
+ if(!(sd_card_type[drive] & (~CT_BLOCK))){
+ kprintf("no card found\n");
+ return;
+ }
+
+ /* read and compute card size */
+ sector_count = sd_get_size_sectors(drive);
+ if(!sector_count){
+ kputs("weird card\n");
+ return;
+ }
+
+ /* read partition table, locate the UZI partition */
+ sector = (unsigned char*)tmpbuf();
+
+ if(!sd_read_sector(drive, sector, 0)){
+ kprintf("failed to read partition table\n");
+ goto failout;
+ }
+
+ /* if we get this far the drive is probably ok */
+ sd_drive_present |= (1 << drive);
+
+ /* look for our partition */
+ parse_partition_table(sector, &sd_partition_start[drive], &sd_slice_count[drive], MAX_SLICES);
+
+failout:
+ brelse((bufptr)sector);
+}
+
+static int sd_spi_init(uint8_t drive)
+{
+ unsigned char n, cmd, card_type, ocr[4];
+ timer_t timer;
+
+ sd_spi_raise_cs(drive);
+
+ sd_spi_clock(drive, false);
+ for (n = 20; n; n--)
+ sd_spi_receive_byte(drive); /* 160 dummy clocks */
+
+ card_type = 0;
+ /* Enter Idle state */
+ if (sd_send_command(drive, CMD0, 0) == 1) {
+ /* initialisation timeout 1 second */
+ timer = set_timer_sec(1);
+ if (sd_send_command(drive, CMD8, (uint32_t)0x1AA) == 1) { /* SDHC */
+ /* Get trailing return value of R7 resp */
+ for (n = 0; n < 4; n++) ocr[n] = sd_spi_receive_byte(drive);
+ /* The card can work at vdd range of 2.7-3.6V */
+ if (ocr[2] == 0x01 && ocr[3] == 0xAA) {
+ /* Wait for leaving idle state (ACMD41 with HCS bit) */
+ while(!timer_expired(timer) && sd_send_command(drive, ACMD41, (uint32_t)1 << 30));
+ /* Check CCS bit in the OCR */
+ if (!timer_expired(timer) && sd_send_command(drive, CMD58, 0) == 0) {
+ for (n = 0; n < 4; n++) ocr[n] = sd_spi_receive_byte(drive);
+ card_type = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */
+ }
+ }
+ } else { /* SDSC or MMC */
+ if (sd_send_command(drive, ACMD41, 0) <= 1) {
+ /* SDv1 */
+ card_type = CT_SD1;
+ cmd = ACMD41;
+ } else {
+ /* MMCv3 */
+ card_type = CT_MMC;
+ cmd = CMD1;
+ }
+ /* Wait for leaving idle state */
+ while(!timer_expired(timer) && sd_send_command(drive, cmd, 0));
+ /* Set R/W block length to 512 */
+ if(timer_expired || sd_send_command(drive, CMD16, 512) != 0)
+ card_type = 0;
+ }
+ }
+ sd_spi_release(drive);
+
+ if (card_type) {
+ sd_spi_clock(drive, true); /* up to 20MHz should be OK */
+ return card_type;
+ }
+
+ return 0; /* failed */
+}
+
+static void sd_spi_release(uint8_t drive)
+{
+ sd_spi_raise_cs(drive);
+ sd_spi_receive_byte(drive);
+}
+
+static int sd_spi_wait_ready(uint8_t drive)
+{
+ unsigned char res;
+ timer_t timer;
+
+ timer = set_timer_ms(100);
+ sd_spi_receive_byte(drive);
+ do{
+ res = sd_spi_receive_byte(drive);
+ if(timer_expired(timer)){
+ kputs("sd_spi_wait_ready: timeout\n");
+ break;
+ }
+ }while ((res != 0xFF));
+
+ return res;
+}
+
+static bool sd_spi_transmit_block(uint8_t drive, void *ptr, unsigned int length)
+{
+ unsigned char reply;
+
+ if(sd_spi_wait_ready(drive) != 0xFF)
+ return false; /* failed */
+
+ sd_spi_transmit_byte(drive, 0xFE);
+ sd_spi_transmit_from_memory(drive, ptr, length);
+ sd_spi_transmit_byte(drive, 0xFF); /* dummy CRC */
+ sd_spi_transmit_byte(drive, 0xFF);
+ reply = sd_spi_receive_byte(drive);
+ if((reply & 0x1f) != 0x05)
+ return false; /* failed */
+ return true; /* hooray! */
+}
+
+static bool sd_spi_receive_block(uint8_t drive, void *ptr, unsigned int length)
+{
+ unsigned int timer;
+ unsigned char b;
+
+ timer = set_timer_ms(250);
+
+ do{
+ b = sd_spi_receive_byte(drive);
+ if(timer_expired(timer)){
+ kputs("sd_spi_receive_block: timeout\n");
+ return false;
+ }
+ }while(b == 0xFF);
+
+ if(b != 0xFE)
+ return false; /* failed */
+
+ return sd_spi_receive_to_memory(drive, ptr, length); /* returns true on success */
+}
+
+static int sd_send_command(uint8_t drive, unsigned char cmd, uint32_t arg)
+{
+ unsigned char n, res, *p;
+
+ if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
+ cmd &= 0x7F;
+ res = sd_send_command(drive, CMD55, 0);
+ if (res > 1)
+ return res;
+ }
+
+ /* Select the card and wait for ready */
+ sd_spi_raise_cs(drive);
+ sd_spi_lower_cs(drive);
+ if (sd_spi_wait_ready(drive) != 0xFF)
+ return 0xFF;
+
+ /* Send command packet */
+ sd_spi_transmit_byte(drive, cmd); /* Start + Command index */
+#if 0
+ sd_spi_transmit_byte(drive, (unsigned char)(arg >> 24)); /* Argument[31..24] */
+ sd_spi_transmit_byte(drive, (unsigned char)(arg >> 16)); /* Argument[23..16] */
+ sd_spi_transmit_byte(drive, (unsigned char)(arg >> 8)); /* Argument[15..8] */
+ sd_spi_transmit_byte(drive, (unsigned char)arg); /* Argument[7..0] */
+#else
+ /* sdcc sadly unable to figure this out for itself yet */
+ p = (unsigned char *)&arg;
+ sd_spi_transmit_byte(drive, p[3]); /* Argument[31..24] */
+ sd_spi_transmit_byte(drive, p[2]); /* Argument[23..16] */
+ sd_spi_transmit_byte(drive, p[1]); /* Argument[15..8] */
+ sd_spi_transmit_byte(drive, p[0]); /* Argument[7..0] */
+#endif
+ /* there's only a few commands (in native mode) that need correct CRCs */
+ n = 0x01; /* Dummy CRC + Stop */
+ if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
+ if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
+ sd_spi_transmit_byte(drive, n);
+
+ /* Receive command response */
+ if (cmd == CMD12)
+ sd_spi_receive_byte(drive); /* Skip a stuff byte when stop reading */
+ n = 10; /* Wait for a valid response in timeout of 10 attempts */
+ do{
+ res = sd_spi_receive_byte(drive);
+ }while ((res & 0x80) && --n);
+
+ return res; /* Return with the response value */
+}
+
+static uint32_t sd_get_size_sectors(uint8_t drive)
+{
+ unsigned char csd[16], n;
+ uint32_t sectors = 0;
+
+ if(sd_send_command(drive, CMD9, 0) == 0 && sd_spi_receive_block(drive, csd, 16)){
+ if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
+ sectors = ((uint32_t)csd[9] + (uint32_t)((unsigned int)csd[8] << 8) + 1) << 10;
+ } else { /* SDC ver 1.XX or MMC*/
+ n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
+ sectors = (csd[8] >> 6) + ((unsigned int)csd[7] << 2) + ((unsigned int)(csd[6] & 3) << 10) + 1;
+ sectors = sectors << (n - 9);
+ }
+ }
+ sd_spi_release(drive);
+ return sectors;
+}
+
+static bool sd_read_sector(uint8_t drive, void *ptr, uint32_t lba)
+{
+ bool r = false;
+
+ if(sd_card_type[drive] != CT_NONE){
+ if(!(sd_card_type[drive] & CT_BLOCK))
+ lba = lba << 9; /* multiply by 512 to get byte address */
+
+ if(sd_send_command(drive, CMD17, lba) == 0)
+ r = sd_spi_receive_block(drive, ptr, 512);
+
+ sd_spi_release(drive);
+ }
+
+ return r;
+}
+
+static bool sd_write_sector(uint8_t drive, void *ptr, uint32_t lba)
+{
+ bool r = false;
+
+ if(sd_card_type[drive] != CT_NONE){
+ if(!(sd_card_type[drive] & CT_BLOCK))
+ lba = lba << 9; /* multiply by 512 to get byte address */
+
+ if(sd_send_command(drive, CMD24, lba) == 0)
+ r = sd_spi_transmit_block(drive, ptr, 512);
+
+ sd_spi_release(drive);
+ }
+
+ return r;
+}
--- /dev/null
+#ifndef __DEVSD_DOT_H__
+#define __DEVSD_DOT_H__
+
+/* SD Configuration (in config.h)
+
+ Define DEVICE_SD if SD hardware is present on your platform.
+
+ Define SD_DRIVE_COUNT to the number of SD cards your hardware
+ supports (range 1--4).
+
+ Provide the platform-specific SPI functions listed below to
+ drive the SPI bus on your hardware, for an example of how to
+ do this see platform-n8vem-mark4/devsdspi.c
+*/
+
+
+/* public interface */
+int devsd_open(uint8_t minor, uint16_t flags);
+int devsd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int devsd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+void devsd_init(void);
+
+/* platform-specific SPI functions */
+void sd_spi_clock(uint8_t drive, bool go_fast);
+void sd_spi_raise_cs(uint8_t drive);
+void sd_spi_lower_cs(uint8_t drive);
+void sd_spi_transmit_byte(uint8_t drive, uint8_t byte);
+uint8_t sd_spi_receive_byte(uint8_t drive);
+bool sd_spi_receive_to_memory(uint8_t drive, uint8_t *ptr, unsigned int length);
+bool sd_spi_transmit_from_memory(uint8_t drive, uint8_t *ptr, unsigned int length);
+
+/* Definitions for MMC/SDC command */
+#define CMD0 (0x40+0) /* GO_IDLE_STATE */
+#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
+#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */
+#define CMD8 (0x40+8) /* SEND_IF_COND */
+#define CMD9 (0x40+9) /* SEND_CSD */
+#define CMD10 (0x40+10) /* SEND_CID */
+#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
+#define ACMD13 (0xC0+13) /* SD_STATUS (SDC) */
+#define CMD16 (0x40+16) /* SET_BLOCKLEN */
+#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
+#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
+#define CMD23 (0x40+23) /* SET_BLOCK_COUNT (MMC) */
+#define ACMD23 (0xC0+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
+#define CMD24 (0x40+24) /* WRITE_BLOCK */
+#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
+#define CMD55 (0x40+55) /* APP_CMD */
+#define CMD58 (0x40+58) /* READ_OCR */
+
+#define CT_NONE 0x00
+#define CT_MMC 0x01
+#define CT_SD1 0x02
+#define CT_SD2 0x04
+#define CT_SDC (CT_SD1|CT_SD2)
+#define CT_BLOCK 0x08
+
+#endif /* __DEVSD_DOT_H__ */
-CSRCS += devices.c main.c devtty.c
-DSRCS = ../dev/devide.c ../dev/mbr.c
+CSRCS += devices.c main.c devtty.c devsdspi.c
+DSRCS = ../dev/devide.c ../dev/devsd.c ../dev/mbr.c
ASRCS = crt0.s z180.s mark4.s commonmem.s
Assumes an N8VEM Mark IV SBC fitted with 512KB RAM, with the RS232 port as
tty1, and the RS422 port as tty2. Does not yet support any ECB peripheral
-boards.
+boards. On-board IDE and SD mass storage interfaces are both supported.
To build, edit ../Makefile to read:
#define IDE_REG_BASE MARK4_IO_BASE
#define IDE_8BIT_ONLY
#define IDE_REG_CS1_FIRST
+
+#define DEVICE_SD
+#define SD_DRIVE_COUNT 1
#include <devsys.h>
#include <devtty.h>
#include <devide.h>
+#include <devsd.h>
struct devsw dev_tab[] = /* The device driver switch table */
{
/* 0: /dev/hd IDE-8 interface */
{ devide_open, no_close, devide_read, devide_write, no_ioctl },
/* 1: /dev/sd SD interface */
- { no_open, no_close, no_rdwr, no_rdwr, no_ioctl },
+ { devsd_open, no_close, devsd_read, devsd_write, no_ioctl },
/* 2: /dev/tty serial ports */
- { tty_open, tty_close, tty_read, tty_write, tty_ioctl },
+ { tty_open, tty_close, tty_read, tty_write, tty_ioctl },
/* 3: /dev/lpr Unused slot (pad to keep system devices at index 4) */
{ no_open, no_close, no_rdwr, no_rdwr, no_ioctl },
/* 4: /dev/mem etc System devices (one offs) */
/* This is a bit uglier than needed but the right hand side is
a constant this way */
if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255)
- return false;
+ return false;
else
return true;
}
void device_init(void)
{
devide_init();
+ devsd_init();
}
--- /dev/null
+/*-----------------------------------------------------------------------*/
+/* N8VEM Mark IV Z180 CSI/O SPI SD driver */
+/* 2014-12-27 Will Sowerbutts */
+/*-----------------------------------------------------------------------*/
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+#include <stdbool.h>
+#include "config.h"
+#include <z180.h>
+
+#define CSIO_CNTR_TE (1<<4) /* transmit enable */
+#define CSIO_CNTR_RE (1<<5) /* receive enable */
+#define CSIO_CNTR_END_FLAG (1<<7) /* operation completed flag */
+
+#define MARK4_SD_CS (1<<2) /* chip select */
+#define MARK4_SD_WRITE_PROTECT (1<<4) /* write protect */
+#define MARK4_SD_CARD_DETECT (1<<5) /* card detect */
+#define MARK4_SD_INT_ENABLE (1<<6) /* interrupt enable */
+#define MARK4_SD_INT_PENDING (1<<7) /* interrupt enable */
+
+__sfr __at (MARK4_IO_BASE + 0x09) MARK4_SD;
+
+/* the CSI/O and SD card send bits in opposite orders, so we need to flip them over */
+static uint8_t reverse_byte[256] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+
+void sd_spi_clock(uint8_t drive, bool go_fast)
+{
+ unsigned char c;
+ drive; /* not used */
+
+ c = CSIO_CNTR & 0xf8; /* clear low three bits, gives fastest rate (clk/20) */
+ if(!go_fast)
+ c = c | 0x03; /* set low two bits, clk/160 (can go down to clk/1280, see data sheet) */
+ CSIO_CNTR = c;
+}
+
+void sd_spi_raise_cs(uint8_t drive)
+{
+ drive; /* not used */
+ /* wait for idle */
+ while(CSIO_CNTR & (CSIO_CNTR_TE | CSIO_CNTR_RE));
+ MARK4_SD = MARK4_SD & (~MARK4_SD_CS);
+}
+
+void sd_spi_lower_cs(uint8_t drive)
+{
+ drive; /* not used */
+ /* wait for idle */
+ while(CSIO_CNTR & (CSIO_CNTR_TE | CSIO_CNTR_RE));
+ MARK4_SD = MARK4_SD | MARK4_SD_CS;
+}
+
+void sd_spi_transmit_byte(uint8_t drive, unsigned char byte)
+{
+ unsigned char c;
+ drive; /* not used */
+
+ /* reverse the bits before we busywait */
+ byte = reverse_byte[byte];
+
+ /* wait for any current transmit operation to complete */
+ do{
+ c = CSIO_CNTR;
+ }while(c & CSIO_CNTR_TE);
+
+ /* write the byte and enable transmitter */
+ CSIO_TRDR = byte;
+ CSIO_CNTR = c | CSIO_CNTR_TE;
+}
+
+uint8_t sd_spi_receive_byte(uint8_t drive)
+{
+ unsigned char c;
+ drive; /* not used */
+
+ /* wait for any current transmit or receive operation to complete */
+ do{
+ c = CSIO_CNTR;
+ }while(c & (CSIO_CNTR_TE | CSIO_CNTR_RE));
+
+ /* enable receive operation */
+ CSIO_CNTR = c | CSIO_CNTR_RE;
+
+ /* wait for receive to complete */
+ while(CSIO_CNTR & CSIO_CNTR_RE);
+
+ /* read byte */
+ return reverse_byte[CSIO_TRDR];
+}
+
+bool sd_spi_receive_to_memory(uint8_t drive, uint8_t *ptr, unsigned int length)
+{
+ unsigned char c;
+ drive; /* not used */
+
+ /* wait for any current transmit or receive operation to complete */
+ do{
+ c = CSIO_CNTR;
+ }while(c & (CSIO_CNTR_TE | CSIO_CNTR_RE));
+
+ while(length){
+ /* enable receive operation */
+ CSIO_CNTR = c | CSIO_CNTR_RE;
+
+ /* wait for receive to complete */
+ do{
+ c = CSIO_CNTR;
+ }while(c & CSIO_CNTR_RE);
+
+ /* read byte */
+ *ptr = reverse_byte[CSIO_TRDR];
+
+ /* next byte */
+ ptr++;
+ length--;
+ }
+
+ return true;
+}
+
+bool sd_spi_transmit_from_memory(uint8_t drive, uint8_t *ptr, int length)
+{
+ unsigned char c, b;
+ drive; /* not used */
+
+ while(length){
+ b = reverse_byte[*ptr];
+
+ /* wait for transmit to complete */
+ do{
+ c = CSIO_CNTR;
+ }while(c & CSIO_CNTR_TE);
+
+ /* write the byte and enable transmitter */
+ CSIO_TRDR = b;
+ CSIO_CNTR = c | CSIO_CNTR_TE;
+
+ /* next byte */
+ ptr++;
+ length--;
+ }
+ return true;
+}
devsys.rel
platform-n8vem-mark4/devtty.rel
platform-n8vem-mark4/devide.rel
+platform-n8vem-mark4/devsd.rel
+platform-n8vem-mark4/devsdspi.rel
platform-n8vem-mark4/mbr.rel
-e