Floppy and ACSI to begin with, along with the IDE adapters often added.
-CSRCS = devlpr.c devtty.c devfd.c
+CSRCS = devlpr.c devtty.c dma.c devfd.c devacsi.c
CSRCS += devices.c main.c libc.c
ASRCS = p68000.S crt0.S
LSRCS = ../lib/68000exception.c
LOBJS = $(patsubst ../lib/%.c,%.o, $(LSRCS))
-DSRCS = ../dev/mbr.c ../dev/blkdev.c
+DSRCS = ../dev/mbr.c ../dev/blkdev.c ../dev/devide.c ../dev/devide_discard.c
+DSRCS += ../dev/ahdi.c
DOBJS = $(patsubst ../dev/%.c,%.o, $(DSRCS))
COBJS = $(CSRCS:.c=$(BINEXT))
../tty.o ../devsys.o ../usermem.o ../syscall_fs2.o \
../syscall_fs3.o ../syscall_exec32.o \
../usermem_std-68000.o devlpr.o devtty.o libc.o ../vt.o ../malloc.o \
- blkdev.o mbr.o \
+ blkdev.o mbr.o devide.o devide_discard.o devacsi.o dma.o \
../font8x8.o >../fuzix.map
m68k-uclinux-objcopy fuzix.elf -O binary ../fuzix.bin
# And now make a bootable floppy
--- /dev/null
+extern void acsi_init(void);
#define NBUFS 10 /* Number of block buffers */
#define NMOUNTS 4 /* Number of mounts at a time */
+#define CONFIG_IDE
+
#define MAX_BLKDEV 4
/* TODO tty scan rows/cols etc */
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <timer.h>
+#include <devscsi.h>
+#include <blkdev.h>
+#include <dma.h>
+#include <acsi.h>
+
+/*
+ * ACSI Hard disk interface. Based upon EmuTOS
+ *
+ * ACSI is a SASI/SCSI like interface. The drives only speak SASI style
+ * 6 byte commands but we are at least blessed with a DMA interface for
+ * this even if it's a bit of a pain to drive except for block I/O.
+ *
+ * There is a hack (not implemented yet) where full SCSI commands can
+ * be sent to some drive convertors by proceeding the longer commands
+ * with 0x1F.
+ */
+
+
+union acsidma {
+ volatile uint32_t datacontrol;
+ struct {
+ volatile uint16_t data;
+ volatile uint16_t control;
+ } s;
+};
+
+#define ACSIDMA ((union acsidma *) 0xFF8604)
+
+static timer_t acsi_next;
+
+#define ACSI_CMDWAIT TICKSPERSEC/100
+#define ACSI_CMDBYTE TICKSPERSEC/10
+#define ACSI_OP TICKSPERSEC
+
+
+void acsi_select(void)
+{
+ /* We are not allowed to issue the next command too soon */
+ while (!timer_expired(acsi_next))
+ platform_idle();
+
+ /* Claim the DMA */
+ dma_lock();
+}
+
+void acsi_clear(void)
+{
+ /* Hand back the DMAC */
+ ACSIDMA->s.control = DMA_FDC;
+ dma_unlock();
+
+ /* Remember when we can next issue a command */
+ acsi_next = set_timer_duration(ACSI_CMDWAIT);
+}
+
+/* Send byte and *next* control */
+static void dma_send_byte(uint8_t c, uint16_t control)
+{
+ ACSIDMA->datacontrol = ((uint32_t) c) << 16 | control;
+}
+
+static void delay(void)
+{
+ /* Wait 15us : FIXME */
+}
+
+/* Flush FIFO and set control */
+static void hdc_start_dma(uint16_t control)
+{
+ control |= DMA_SCREG;
+ ACSIDMA->s.control = control ^ DMA_WRBIT;
+ delay();
+ ACSIDMA->s.control = control;
+ delay();
+}
+
+/*
+ * The SCSI midlayer wishes to send a command out
+ */
+uint8_t acsi_execute(uint8_t * cmd, uint8_t cmdlen, uint16_t len)
+{
+ uint8_t repeat = 0;
+ uint8_t st;
+ uint8_t control;
+ int i;
+
+ /* FIXME: add ICD hacks */
+
+ if (len && !blk_op.is_read)
+ /* Flush cache */ ;
+
+ /* No banking complexities for us. Some day we may have to address non DMA
+ memory on big machines however FIXME */
+ if (len)
+ set_dma_addr(blk_op.addr);
+ control = DMA_FDC | DMA_HDC;
+ if (!blk_op.is_read)
+ control |= DMA_WRBIT;
+ hdc_start_dma(control);
+ ACSIDMA->s.data = (len + 511) >> 9;
+
+ /* Repeat if neeed to drive through fifo.. ick */
+ if (len & 511) {
+ /* FIXME: add correct logic here */
+ repeat = 1;
+ }
+
+ do {
+ uint8_t *p = cmd;
+
+ /* We are not allowed to issue the next command too soon */
+ while (!timer_expired(acsi_next))
+ platform_idle();
+
+ /* Write the command */
+ ACSIDMA->s.control = control; /* SCSI control */
+ control |= DMA_A0; /* Remaining bytes need this */
+ for (i = 0; i < cmdlen - 1; i++) {
+ dma_send_byte(*p++, control);
+ /* Allow 100ms */
+ if (dma_wait(ACSI_CMDBYTE))
+ return -1;
+ }
+ /* Command final byte */
+ dma_send_byte(*p, control & 0xFF00);
+
+ /* Now wait for command to run - can take a second worst case */
+ st = dma_wait(ACSI_OP);
+ /* Remember when we can issue the next command */
+ acsi_next = set_timer_duration(ACSI_CMDWAIT);
+ if (st)
+ return -1;
+ /* Command issued */
+ ACSIDMA->s.control = control & ~DMA_WRBIT;
+ st = ACSIDMA->s.data & 0xff;
+ if (st)
+ break;
+ control &= ~DMA_A0;
+ } while (repeat--);
+ /* And done */
+ if (len && blk_op.is_read)
+ /* Flush cache */ ;
+ return 0;
+}
+
+uint8_t acsi_transfer(void)
+{
+ uint8_t cmd[11];
+ unsigned short cmdlen;
+ unsigned short count;
+ unsigned short dev;
+ uint8_t blocks = blk_op.nblock;
+
+ if (blk_op.nblock > 255)
+ blocks = 255;
+
+ /* FIXME: lun handling */
+ dev = blk_op.blkdev->driver_data & DRIVE_NR_MASK;
+ /* When we can we issue ACSI commands. When we are out of range we try
+ SCSI. All ACSI devices are small enough only ACSI will hit them */
+ if (blk_op.lba < 0x200000) {
+ cmd[0] = blk_op.is_read ? 0x08 : 0x0A;
+ cmd[1] = (blk_op.lba >> 16) & 0x1f;
+ cmd[2] = blk_op.lba >> 8;
+ cmd[3] = blk_op.lba;
+ cmd[4] = blocks;
+ cmd[5] = 0x00;
+ cmdlen = 6;
+ } else {
+ /* Framed SCSI READ_10/WRITE_10 */
+ cmd[0] = 0x1F; /* SCSI follows, lun bits also go here */
+ cmd[1] = blk_op.is_read ? 0x28 : 0x2A;
+ cmd[2] = 0x00; /* LUN */
+ cmd[3] = blk_op.lba >> 24;
+ cmd[4] = blk_op.lba >> 16;
+ cmd[5] = blk_op.lba >> 8;
+ cmd[6] = blk_op.lba;
+ cmd[7] = 0x00;
+ cmd[8] = 0x00; /* Blocks upper 8. Need to fix blkdev.c before */
+ cmd[9] = blocks; /* we can do > 255 blocks per I/O */
+ cmd[10] = 0x00;
+ cmdlen = 11;
+ }
+
+ acsi_select();
+ /* Should we drop back to single block commands on an error and try to
+ do them all one by one ? */
+ for (count = 0; count < 5; count++) {
+ if (acsi_execute(cmd, cmdlen, blocks << 9) == 0) {
+ acsi_clear();
+ return blocks;
+ }
+ }
+ acsi_clear();
+ kprintf("acsi: device %d failed command %x for block %lx\n", dev, cmd[0], blk_op.lba);
+ return 0;
+}
+
+static unsigned int acsi_probe(uint8_t dev, uint8_t lun)
+{
+ static uint8_t cdb[6]; /* all zeros is TUR */
+ unsigned int st;
+ blkdev_t *blk;
+
+ acsi_select();
+ st = acsi_execute(cdb, 6, 0);
+ acsi_clear();
+
+ if (st)
+ return st;
+
+ /* TODO: do we need to check type and sector size etc on ACSI - prob not */
+
+ /* Add it */
+ blk = blkdev_alloc();
+ blk->transfer = acsi_transfer;
+ //blk->flush = acsi_flush;
+ blk->driver_data = dev; /* FIXME lun */
+ //blk->drive_lba_count = acsi_capcity(dev, lun);
+ blkdev_scan(blk, SWAPSCAN);
+ return st;
+}
+
+void acsi_init(void)
+{
+ unsigned int dev, lun;
+
+ acsi_next = set_timer_duration(0);
+ for (dev = 0; dev < 8; dev++) {
+ for (lun = 0; lun < 8; lun++) {
+ if (acsi_probe(dev, lun) == 0) {
+ } else if (lun == 0)
+ break;
+ }
+ }
+}
static uint8_t step[MAX_FD] = { 3, 3 }; /* 3ms happens to be the value 3 */
static uint8_t deselected = 1;
-static uint8_t locked;
#define FDC_CS (DMA_FDC)
#define FDC_TR (DMA_FDC | DMA_A0)
/* TODO */
}
-/*
- * Report how the DMA did
- */
-static uint16_t get_dma_status(void)
-{
- DMA->control = 0x90;
- return DMA->control;
-}
-
-/*
- * Set the 24bit DMA address for a transfer. The transfer is not
- * cache coherent and must be word aigned
- */
-static void set_dma_addr(uint8_t * ptr)
-{
- uint32_t p = (uint32_t) ptr;
- if (p & 1)
- panic("odd dma");
- DMA->addr_low = p;
- DMA->addr_med = p >> 8;
- DMA->addr_high = p >> 16;
-}
-
/*
* Read an fd register
*/
* Wait for the floppy controller to respond and show up on the MFP
* GPIO.
*/
+
static int fd_wait(void)
{
- timer_t x = set_timer_duration(3 * TICKSPERSEC);
- while (!timer_expired(x)) {
- uint8_t status = *(volatile uint8_t *)0xFFFA01;
- if (!(status & 0x20))
- return 0;
- platform_idle();
- }
- return -1;
+ return dma_wait(3 * TICKSPERSEC);
}
/*
irqflags_t irq;
uint16_t status;
- if (deselected || locked)
+ if (deselected || dma_is_locked())
return;
status = fd_get_reg(FDC_CS);
if (status & FDC_MOTORON)
track >>= 1;
}
- locked = 1;
+ dma_lock();
/* Get into position */
fd_set_side(minor, side);
if (fd_set_track(minor, track)) {
- locked = 0;
+ dma_unlock();
return -1;
}
status = fd_get_reg(FDC_SR);
if (!is_read && (status & FDC_WRI_PRO)) {
- locked = 0;
+ dma_unlock();
udata.u_error = EROFS;
return -1;
}
continue;
}
/* Whoopeee it worked */
- locked = 0;
+ dma_unlock();
if (is_read)
flush_cache_range(udata.u_dptr, 512);
return 0;
}
- locked = 0;
+ dma_unlock();
udata.u_error = EIO;
return -1;
}
fd_set_reg(FDC_CS, FDC_RESTORE | FDC_HBIT | step[unit]);
if (fd_wait() == 0) {
if (fd_get_reg(FDC_CS) & FDC_TRACK0) {
- locked = 0;
+ dma_unlock();
/* The Falcon might have HD but we'll deal with that in the far future! */
kprintf("fd%d: double density.\n", unit);
present[unit] = 1;
void fd_probe(void)
{
/* Do we need to deal with waiting for motor off here ? */
- locked = 1;
+ dma_lock();
fd_probe_drive(0);
fd_probe_drive(1);
- locked = 0;
+ dma_unlock();
}
#include <devlpr.h>
#include <tty.h>
#include <vt.h>
+#include <machine.h>
+#include <devide.h>
+#include <acsi.h>
struct devsw dev_tab[] = /* The device driver switch table */
{
bool validdev(uint16_t dev)
{
- /* 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) - 1)
- return false;
- else
- return true;
+ /* 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) - 1)
+ return false;
+ else
+ return true;
}
void device_init(void)
{
- fd_probe();
+ fd_probe();
+ if (features & FEATURE_IDE)
+ devide_init();
+ acsi_init();
}
+/* Very simple routines because we have a flat memory space and MMIO */
+
+void devide_read_data(void)
+{
+ uint16_t ct = 256;
+ uint16_t *p = (uint16_t *)blk_op.addr;
+ while(ct--)
+ *p++ = *ide_data16;
+}
+
+void devide_write_data(void)
+{
+ uint16_t ct = 256;
+ uint16_t *p = (uint16_t *)blk_op.addr;
+ while(ct--)
+ *ide_data16 = *p++;
+}
\ No newline at end of file
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <dma.h>
+
+static uint8_t locked;
+
+/*
+ * Set the 24bit DMA address for a transfer. The transfer is not
+ * cache coherent and must be word aigned
+ */
+void set_dma_addr(uint8_t *ptr)
+{
+ uint32_t p = (uint32_t) ptr;
+ if (p & 1)
+ panic("odd dma");
+ DMA->addr_low = p;
+ DMA->addr_med = p >> 8;
+ DMA->addr_high = p >> 16;
+}
+
+/*
+ * Report how the DMA did
+ */
+uint16_t get_dma_status(void)
+{
+ DMA->control = 0x90;
+ return DMA->control;
+}
+
+/*
+ * Wait for a DMA devices to complete by watching a GPIO
+ */
+int dma_wait(uint16_t wait)
+{
+ timer_t x = set_timer_duration(wait);
+ while (!timer_expired(x)) {
+ uint8_t status = *(volatile uint8_t *)0xFFFA01;
+ if (!(status & 0x20))
+ return 0;
+ platform_idle();
+ }
+ return -1;
+}
+
+void dma_lock(void)
+{
+ locked = 1;
+}
+
+void dma_unlock(void)
+{
+ locked = 0;
+}
+
+uint8_t dma_is_locked(void)
+{
+ return locked;
+}
#define DMA_SCNOT0 0x0002
#define DMA_DATREQ 0x0004
+extern void dma_lock(void);
+extern void dma_unlock(void);
+extern uint8_t dma_is_locked(void);
+
+extern void set_dma_addr(uint8_t *ptr);
+extern uint16_t get_dma_status(void);
+extern int dma_wait(uint16_t wait);
+
#endif
--- /dev/null
+.mri 1
+
+;
+; The boot loader fits in sector 0/0/1.
+;
+start:
+ bra.s boot ; requred first 2 bytes
+ ascii "Loader"
+ word 0
+ word 0 ; DWord for the serial
+ word 2 ; BPB not used (512 bytes/sec)
+ byte 2 ; 2 sec/cluster
+ word $100 ; 1 sector reserved (intel format)
+ byte 1 ; 1 extra FAT
+ word $100 ; entries in root directory
+ word $400B ; sectors on disk (intel format)
+ byte $0 ; more BPB crap we don't need
+ word $0
+ byte $9 ; 9 spt
+ word $100 ; claim single sided
+ word $200 ; hidden sectors
+
+ word $0 ; execflag
+ word $0 ; load mode
+ word $0 ; logical sector
+ word $0 ; setcnt
+ word $0 ; ldaaddr
+ word $0 ; fatbuf
+
+ word $0 ; fname
+ word $0
+ word $0
+ word $0
+ word $0
+ byte $0
+
+ word $0
+
+;
+; We are located somewhere at random. We need to relocate ourself out
+; of the way. For simplicity we locate ourselves up at 192K out of the
+; way of the image we load above us. We always have at least 512K so
+; that is fine.
+;
+; The screen may be at $10000-$1FFFF.
+;
+; We are only guaranteed that rwabs _floprd and getbpb exist there is
+; nothing else definitely in the ROM
+;
+boot:
+ lea.l run(pc),a0
+ move.l #$30000,a1
+ move.l a1,a2
+ move.w #128,d0
+copy:
+ move.l (a0)+,(a1)+
+ dbra d0,copy
+ jmp (a2)
+
+run:
+ lea.l $30000,sp
+load:
+ clr.w -(sp) ; Drive A: (FIXME - should work off boot)
+ move.w #1,-(sp) ; From sector 1
+ move.w #$256,-(sp) ; 256 sectors
+ move.l #$40000,-(sp) ; read address
+ move.w #2,-(sp) ; read, ignore media change
+ move.w #4,-(sp) ; rwabs
+ trap #13
+
+ ; Now run our code
+ ; All interrupts off while we eat TOS alive
+ or.w #$0700,sr
+
+ ; Skip the vectors and first 512 bytes of TOS variables in case
+ ; they are useful
+ move.w #$600,a0
+ move.l #$40000,a1
+ ; Relocate 128K
+ move.w #$7FFF,d0
+install:
+ move.l (a1)+,(a0)+
+ dbra d0,install
+
+ jmp $600
+
+ ; Never returns
+
+
+;
+; And the checksum goes at $1FE (entire sector summed in motorola
+; word format should be $1234
+;
--- /dev/null
+
+extern uint16_t features;
+
+/* One of these is set for machine type */
+#define FEATURE_FALCON 0x8000 /* Falcon */
+/* 68030 16MHz, 68881/2, 56001DSP, VIDEL video, blitter, DMA audio, crossbar,
+ 2.5" IDE, 1.4MB FDC, SCSI, 2xRS232, enhanced joysticks, RS422 */
+#define FEATURE_TT 0x4000 /* Atari TT */
+/* 68030 32MHz, new graphics, extra MFP, VME, VGA, SCSI, no blitter, 1.44MB FDC,
+fast RAM that isn't DMA capable, 3xRS232, RS422 */
+#define FEATURE_STE 0x2000 /* Atari STe */
+/* 68000 8MHz, blitter, PCM audio, extra joystick features, more colours */
+#define FEATURE_MSTE 0x1000 /* Mega STe */
+/* 68000 + 68881/2FPU, VME, 3xRS232, RS422, 1.44MB FDC, 3 button mouse 8/16MHz
+ extra joystick features, ACSI/SCSI, blitter, more colours */
+#define FEATURE_ST 0x0000 /* ST STF STFM Mega ST */
+/* 68000 8MHz, 720K floppy (360 on earliest), blitter on some MegaST */
+/* FIXME: can we tell MegaST by the RTC ? */
+
+/* TODO: Stacy and STBook */
+
+#define MACHINE_TYPE (features & 0xFF00)
+
+/* Device features */
+#define FEATURE_IDE 0x0080 /* IDE controller - inbuilt or add in */
+#define FEATURE_VME 0x0040 /* Has VME bus */
+#define FEATURE_RTC 0x0020 /* Add in RTC */
+#define FEATURE_BLITTER 0x0010 /* Has a Blitter */
+#define FEATURE_TTRTC 0x0008 /* TT style MC146818A */
+
+/* Various other things could be tested for but they are basically machine
+ tied anyway. One exceptio we need to tidy up somewhere is 1.44MB floppy */
+
+/* TODO: FPU detect */
\ No newline at end of file
#include <kdata.h>
#include <printf.h>
#include <devtty.h>
+#include <machine.h>
+
+uint8_t need_resched;
+uint16_t features;
void platform_idle(void)
{
}
-uint8_t need_resched;
-
uint8_t platform_param(char *p)
{
return 0;
{
}
+struct probe_bits {
+ const char *name;
+ uint16_t bits;
+ uint32_t addr;
+};
+
+struct probe_bits probes[] = {
+ { "falcon ", FEATURE_FALCON, 0xFF8007 },
+ { "tt ", FEATURE_TT, 0xFF8260 },
+ { "ste", FEATURE_STE, 0xFF8093 },
+
+ { "vme ", FEATURE_VME, 0xFF8E01 },
+ { "rtc ", FEATURE_RTC, 0xFFFC21 },
+ { "tt-rtc ", FEATURE_TTRTC, 0xFF8961 },
+ { "blitter ", FEATURE_BLITTER, 0xFF8A00 },
+ { "ide ", FEATURE_IDE, 0xF00009 },
+ { NULL, 0, 0 }
+};
+
void map_init(void)
{
+ struct probe_bits *p = probes;
+ /* Useful spot for hardware set up and reporting */
+
+ kputs("Features: ");
+ while(p->name) {
+ if (probe_memory((uint8_t *)p->addr) == 0) {
+ features |= p->bits;
+ kputs(p->name);
+ }
+ p++;
+ }
+ if ((features & (FEATURE_VME|FEATURE_TT)) == FEATURE_VME) {
+ features |= FEATURE_MSTE;
+ kputs("mste");
+ }
+ kputchar('\n');
}
u_block uarea_block[PTABSIZE];
uint16_t cputype;
uint32_t screenbase;
-
void pagemap_init(void)
{
extern uint8_t _end;
--- /dev/null
+/*
+ * Normal Atari Falcon, STBook and add in card IDE
+ *
+ * Beware - if there is no IDE present it will bus error
+ * Beware #2 - don't probe it using F00000 or you might be fooled by
+ * an Adspeed interface and put the machine into 16Mhz mode instead. Probe
+ * one of the others.
+ */
+
+#define IDE_IS_MMIO
+
+#define IDE_REG_DATA 0xF00001 /* 16bit at 0000/0001 */
+#define IDE_REG_ERROR 0xF00005
+#define IDE_REG_FEATURES 0xF00009
+#define IDE_REG_SEC_COUNT 0xF00009
+#define IDE_REG_LBA_0 0xF0000D
+#define IDE_REG_LBA_1 0xF00011
+#define IDE_REG_LBA_2 0xF00015
+#define IDE_REG_LBA_3 0xF00019
+#define IDE_REG_DEVHEAD 0xF00019
+#define IDE_REG_COMMAND 0xF0001D
+#define IDE_REG_STATUS 0xF0001D
+
+#define IDE_REG_CONTROL 0xF00039
+#define IDE_REG_ALTSTATUS 0xF00039
+
+/* Only one controller */
+#define ide_select(dev)
+#define ide_deselect()
+
+#define ide_data16 ((volatile uint16_t *)0xF00000)