From: Alan Cox Date: Tue, 28 Aug 2018 12:50:11 +0000 (+0100) Subject: propiov2: note a limitation X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=b5b1faca15136cdef9aac38e504eeb1cb5475701;p=FUZIX.git propiov2: note a limitation --- diff --git a/Kernel/dev/propio2.c b/Kernel/dev/propio2.c new file mode 100644 index 00000000..7d24f62a --- /dev/null +++ b/Kernel/dev/propio2.c @@ -0,0 +1,253 @@ +/* + * Wayne Warthen's PropIO 2. + * + * ECB Bus version (although it'll work whatever the bus so long as it's + * I/O mapped at 0xA8). In other words *not* the parportprop + * + * This will not work if you are booting straight into Fuzix without a + * ROM probing it first. The PropIO takes a few seconds (ROMWBW waits 4) + * to respond after power up. As we always boot through ROMWBW on any + * platform currently using this code we don't bother waiting again. + */ + +#include +#include +#include +#include +#include +#include +#include + +__sfr __at 0xA8 tstatus; +__sfr __at 0xA9 tdata; +__sfr __at 0xAA dcmd; +__sfr __at 0xAA dstatus; +__sfr __at 0xAB dio; + +#define TBUSY 0x80 +#define TERR 0x40 +#define TKBD 0x20 +#define TDSP 0x10 + +#define CMD_NOP 0x00 +#define CMD_STAT 0x01 +#define CMD_TYPE 0x02 +#define CMD_CAP 0x03 +#define CMD_CSD 0x04 +#define CMD_RESET 0x10 +#define CMD_INIT 0x20 +#define CMD_READ 0x30 +#define CMD_PREP 0x40 +#define CMD_WRITE 0x50 +#define CMD_VER 0xF0 + +#define DBUSY 0x80 +#define DERR 0x40 +#define DOVER 0x20 +#define DTO 0x10 + +void prop_tty_poll(uint8_t minor) +{ + /* Keyboard data pending but not busy. Busy is ok - we'll pick it up + next poll */ + while((tstatus & (TKBD|TBUSY)) == TKBD) { + uint8_t r = tdata; + tty_inproc(minor, r); + } +} + +void prop_tty_write(uint8_t c) +{ + tdata = c; +} + +ttyready_t prop_tty_writeready(void) +{ + /* Same basic idea - output ready and not busy */ + return ((tstatus & (TDSP|TBUSY)) == TDSP) ? TTY_READY_NOW : TTY_READY_SOON; +} + +/* + * It may be an SD card interface but it doesn't look like one so we + * don't want to use the SD card layer here + */ + +static uint32_t prop_sd_capacity; +static uint32_t prop_sd_error; +static uint8_t prop_sd_status; + +/* An error leaves four bytes waiting in the buffer for us to fetch. We don't + care what they mean right now but just print them. We should care for + read-only FIXME */ +static void prop_error(int st) +{ + /* Recover the error bytes and bitch */ + uint8_t *p = (uint8_t *)&prop_sd_error; + *p++ = dio; + *p++ = dio; + *p++ = dio; + *p = dio; + prop_sd_status = st; + kprintf("propIO sd error: %d %lx\n", st, prop_sd_error); +} + +/* Wait for the Propeller to go idle, or time out + FIXME: delay values - including for slow I/O stuff */ +static int prop_idle(void) +{ + uint16_t n; + /* Delay wants tuning */ + for (n = 0; n < 10000; n++) { + uint8_t s = dstatus; + if (!(s & DBUSY)) + return s; + } + prop_sd_error = 0xFFFFFFFFUL; + return -1; +} + +/* Send a command to the Propeller */ +static int8_t prop_send_cmd(uint8_t cmd) +{ + int st; + /* Ensure we've finished whatever is going on */ + if (prop_idle() < 0) + return -1; + /* Issue our command */ + dcmd = cmd; + /* Wait for it to go idle again. This needs review. I think it's safe + for us to skip the second wait in some cases - notably a write command + where we don't care because the next command will wait for it and + pipeline better FIXME */ + if ((st = prop_idle()) < 0) + return -1; + if (st) + prop_error(st); /* Fetch 4 bytes of error code */ + return st; +} + +/* Send a command and get data back. Various commands return a block of + 1 to 16 bytes of returned information */ +static int8_t prop_send_get(uint8_t cmd, uint8_t *buf, uint8_t l) +{ + uint8_t st; + st = prop_send_cmd(cmd); + if (st != 0) + return st; + while(l--) + *buf++ = dio; + return 0; +} + +/* Query and report the card error status */ +static int prop_stat(void) +{ + uint8_t stat; + if (prop_send_get(CMD_STAT, &stat, 1) < 0) + return -1; + return stat; +} + +/* Reset the controller if present. We ought to check the version here ?? */ +static int8_t prop_sd_reset(void) +{ + return prop_send_cmd(CMD_RESET); +} + +/* Wrapper for when we open an sd interface. Send an init command. get the + capacity and report home. -1 means it broke, 0 means we think there isn't + any media, 1 means all is good */ +int8_t prop_sd_open(void) +{ + uint8_t type; + uint32_t cap; + int8_t r; + /* It lives... */ + r = prop_send_cmd(CMD_INIT); + if (r < 0) + return 0; /* No media probably */ + /* Type and capacity */ + if (prop_send_get(CMD_TYPE, &type, 1) < 0) + return -1; + if (prop_send_get(CMD_CAP, &cap, 4) < 0) + return -1; + return 1; +} + +/* Right now this is a no-op but when we queue write we want to ensure th + write has finished here so we just wait for busy to clear */ +int prop_sd_flush_cache(void) +{ + return prop_idle(); +} + +/* + * Low level read and write logic. This is fairly simple. We set up the LBA + * and we then either issue READ and get 512 bytes of data, or we issue + * PREP, fill the buffer, and WRITE to send it. + * + * (or of course anywhere along the line it errors on us) + * + * The platform needs to provide platform specific common hooks to inir + * or otir 512 bytes from the right bank + */ +uint8_t prop_sd_transfer_sector(void) +{ + uint8_t *p = &blk_op.lba; /* Sadly SDCC sucks at this otherwise */ + uint8_t cmd; + + /* Need to track and handle no media and media changes */ + + /* Reset data pointer */ + if (prop_send_cmd(CMD_NOP) < 0) + return -1; + + dio = *p++; + dio = *p++; + dio = *p++; + dio = *p; + + /* LBA loaded */ + if (blk_op.is_read) + cmd = CMD_READ; + else + cmd = CMD_PREP; + + if (prop_send_cmd(cmd) < 0) + return -1; + + /* Now do the transfer via the platform specific helper */ + if (blk_op.is_read) + platform_prop_sd_read(); + else { + platform_prop_sd_write(); + if (prop_send_cmd(CMD_WRITE) < 0) + return -1; + } + return 0; +} + +/* FIXME: this could move to discard space */ + +uint8_t prop_sd_probe(void) +{ + blkdev_t *blk; + if (prop_sd_reset()) + return 0; + /* Ok we have something. For now do the open here. We need to tweak + this a bit and make blk support removable media */ + if (prop_sd_open() < 0) + return 0; + + blk = blkdev_alloc(); + if (blk == NULL) + return 0 ; + + blk->transfer = prop_sd_transfer_sector; + blk->flush = prop_sd_flush_cache; + blk->drive_lba_count = prop_sd_capacity; + + kputs("PropIO SD: "); + blkdev_scan(blk, SWAPSCAN); + return 1; +}