CSRCS = devtty.c ttydw.c mbr.c
-CSRCS += devices.c main.c libc.c
+CSRCS += devices.c main.c libc.c devsdc.c
DSRCS = ../dev/devdw.c ../dev/blkdev.c ../dev/devide.c
DSRCS += ../dev/devide_discard.c
ASRCS = coco3.s crt0.s ../platform-dragon-nx32/ide.s
-ASRCS += tricks.s commonmem.s usermem_gime.s drivewire.s
+ASRCS += tricks.s commonmem.s usermem_gime.s drivewire.s sdc.s
COBJS = $(CSRCS:.c=$(BINEXT))
AOBJS = $(ASRCS:.s=$(BINEXT))
coco3.o ../start.o ../version.o ../lowlevel-6809.o \
tricks.o main.o ../timer.o ../kdata.o devices.o \
drivewire.o devdw.o ttydw.o blkdev.o mbr.o devide.o devide_discard.o \
- ../platform-dragon-nx32/ide.o \
+ ../platform-dragon-nx32/ide.o devsdc.o sdc.o \
../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
../syscall_proc.o ../syscall_other.o ../mm.o ../bank16k.o ../swap.o \
../tty.o ../devsys.o ../usermem.o ../syscall_fs2.o ../syscall_exec16.o \
--- /dev/null
+/*
+
+ CoCoSDC driver
+ (c)2015 Brett M. Gordon GPL2
+
+ * Needs work on extended SDC API stuff.
+ * init / mounting stuff really needs to set/update blkdev structure for size
+ * need to get rawmode=1 and 2 working.
+
+*/
+
+#include <kernel.h>
+#include <kdata.h>
+#include <blkdev.h>
+#include <mbr.h>
+#include <devsdc.h>
+#include <printf.h>
+
+
+#define SDC_REG_BASE 0xff40
+#define SDC_REG_CTL (SDC_REG_BASE+0x00 )
+#define SDC_REG_DATA (SDC_REG_BASE+0x02 )
+#define SDC_REG_FCTL (SDC_REG_BASE+0x03 )
+#define SDC_REG_CMD (SDC_REG_BASE+0x08 )
+#define SDC_REG_STAT (SDC_REG_BASE+0x08 )
+#define SDC_REG_PARAM1 (SDC_REG_BASE+0x09 )
+#define SDC_REG_PARAM2 (SDC_REG_BASE+0x0a )
+#define SDC_REG_PARAM3 (SDC_REG_BASE+0x0b )
+
+#define SDC_BUSY 0x01
+#define SDC_READY 0x02
+#define SDC_FAIL 0x80
+
+
+
+#define sdc_reg_ctl *((volatile uint8_t *)SDC_REG_CTL)
+#define sdc_reg_data *((volatile uint8_t *)SDC_REG_DATA)
+#define sdc_reg_fctl *((volatile uint8_t *)SDC_REG_FCTL)
+#define sdc_reg_cmd *((volatile uint8_t *)SDC_REG_CMD)
+#define sdc_reg_stat *((volatile uint8_t *)SDC_REG_STAT)
+#define sdc_reg_param1 *((volatile uint8_t *)SDC_REG_PARAM1)
+#define sdc_reg_param2 *((volatile uint8_t *)SDC_REG_PARAM2)
+#define sdc_reg_param3 *((volatile uint8_t *)SDC_REG_PARAM3)
+
+
+/* a "simple" internal function pointer to which transfer
+ routine to use.
+*/
+typedef void (*sdc_transfer_function_t)( void *addr);
+
+
+
+/* blkdev method: flush drive */
+int devsdc_flush( void )
+{
+ return 0;
+}
+
+
+/* blkdev method: transfer sectors */
+uint8_t devsdc_transfer(void)
+{
+ uint8_t ret=0; /* our return value, preset to failure */
+ uint8_t *ptr; /* points to 32 bit lba in blk op */
+ int i; /* iterator */
+ uint8_t t; /* temporarory sdc status holder */
+ uint8_t cmd; /* holds SDC command value */
+ sdc_transfer_function_t fptr; /* holds which xfer routine we want */
+
+ /* test for raw mode */
+ blk_op.
+
+
+ /* turn on uber-secret SDC LBA mode*/
+ sdc_reg_ctl = 0x43;
+
+ /* we get 256 bytes per lba in SDC so convert */
+ blk_op.lba*=2;
+
+ /* setup cmd pointer and command value from blk_op */
+ if( blk_op.is_read ){
+ cmd = 0x80;
+ fptr = devsdc_read;
+ }
+ else{
+ cmd = 0xa0;
+ fptr = devsdc_write;
+ }
+
+ /* or in our drive value */
+ cmd |= blk_op.blkdev->driver_data;
+
+ /* get/send two sectors (512 bytes) of data */
+ for( i=0; i<2; i++){
+ /* load up registers */
+ ptr=((uint8_t *)(&blk_op.lba))+1;
+ sdc_reg_param1 = ptr[0];
+ sdc_reg_param2 = ptr[1];
+ sdc_reg_param3 = ptr[2];
+ sdc_reg_cmd= cmd;
+ asm("\texg x,x\n"); /* delay 16us minimum */
+ asm("\texg x,x\n");
+ /* wait till SDC is ready */
+ do{
+ t=sdc_reg_stat;
+ if( t & SDC_FAIL ) goto fail;
+ } while( ! (t & SDC_READY) );
+ /* do our low-level xfer function */
+ fptr( blk_op.addr );
+ /* and wait will ready again, and test for failure */
+ do{
+ t=sdc_reg_stat;
+ if( t & SDC_FAIL ) goto fail;
+ }while ( t & SDC_BUSY );
+ /* increment our blk_op values for next 256 bytes sector */
+ blk_op.lba++;
+ blk_op.addr+=256;
+ }
+ /* Huzzah! success! */
+ ret=1;
+ /* Boo! failure */
+ fail: sdc_reg_ctl = 0x00;
+ return ret;
+}
+
+
+/* Returns true if SDC hardware seems to exist */
+bool devsdc_exist()
+{
+ uint8_t t;
+ sdc_reg_data=0x64;
+ t=sdc_reg_fctl;
+ sdc_reg_data=0x00;
+ if( (sdc_reg_fctl ^ t) == 0x60 ) return -1;
+ else return 0;
+}
+
+
+/* Call this to initialize SDC/blkdev interface */
+void devsdc_init()
+{
+ blkdev_t *blk;
+
+ if( devsdc_exist() ){
+ /* register first drive */
+ blk=blkdev_alloc();
+ blk->driver_data = 0 ;
+ blk->transfer = devsdc_transfer;
+ blk->flush = devsdc_flush;
+ blk->drive_lba_count=-1;
+ /* register second drive */
+ blk=blkdev_alloc();
+ blk->driver_data = 1 ;
+ blk->transfer = devsdc_transfer;
+ blk->flush = devsdc_flush;
+ blk->drive_lba_count=-1;
+ kprintf("SDC: ok.\n");
+ }
+
+}
+
--- /dev/null
+;;;
+;;; The CoCoSDC Driver
+;;; Big thanks for Darren Atkinson for good documentation
+;;; and help with autodetection in the init method
+;;;
+;;;
+
+;;; imported
+ .globl blk_op ; blk operation arguments
+
+;;; exported
+ .globl _devsdc_write
+ .globl _devsdc_read
+
+;;; dev
+
+*********************************************************************
+*** Hardware Addressing
+*********************************************************************
+CTRLATCH equ $FF40 ; controller latch (write)
+CMDREG equ $FF48 ; command register (write)
+STATREG equ $FF48 ; status register (read)
+PREG1 equ $FF49 ; param register 1
+PREG2 equ $FF4A ; param register 2
+PREG3 equ $FF4B ; param register 3
+DATREGA equ PREG2 ; first data register
+DATREGB equ PREG3 ; second data register
+
+
+
+ section .common
+
+
+
+;;; Write 256 bytes from SDC
+_devsdc_write
+ pshs y,u
+ ldy #PREG2 ; set Y to point at data reg a
+ ldd #64*256+4 ; A = chunk count (64), B = bytes per chunk (4)
+wrChnk ldu ,x ; get 2 data bytes from source
+ stu ,y ; send data to controller
+ ldu 2,x ; two more bytes..
+ stu ,y ; ..for this chunk
+ abx ; increment X by chunk size (4)
+ deca ; decrement loop counter
+ bne wrChnk ; loop until all chunks written
+ puls y,u,pc ; return
+
+;;; Reads 256 bytes from SDC
+_devsdc_read
+ pshs y,u
+ ldy #PREG2 ; set Y to point to data reg a
+ ldd #32*256+8 ; A = chunk count (32), B = bytes per chunk (8)
+rdChnk ldu ,y ; read 1st pair of bytes for the chunk
+ stu ,x ; store to buffer
+ ldu ,y ; bytes 3 and 4 of..
+ stu 2,x ; ..the chunk
+ ldu ,y ; bytes 5 and 6 of..
+ stu 4,x ; ..the chunk
+ ldu ,y ; bytes 7 and 8 of..
+ stu 6,x ; ..the chunk
+ abx ; increment X by chunk size (8)
+ deca ; decrement loop counter
+ bne rdChnk ; loop if more chunks to read
+ puls y,u,pc ; return
+
+
+
+
+
+
+