trs80/core: Enable the pieces we need for TRS80 with labels
authorAlan Cox <alan@linux.intel.com>
Tue, 6 Jan 2015 22:25:18 +0000 (22:25 +0000)
committerAlan Cox <alan@linux.intel.com>
Tue, 6 Jan 2015 22:25:18 +0000 (22:25 +0000)
This is very much a work in progress. Mostly pushing it so that Will can
compare with the blkdev work and the needs of the two models in terms
of functionality and size.

Kernel/include/kdata.h
Kernel/platform-trs80/config.h
Kernel/platform-trs80/devhd.c
Kernel/platform-trs80/devhd.h
Kernel/platform-trs80/devices.c
Kernel/platform-trs80/main.c

index 366cc3c..aea0e77 100644 (file)
@@ -18,6 +18,7 @@ extern uint16_t nready;          /* Number of ready processes */
 
 extern inoptr root;        /* Address of root dir in inode table */
 extern uint16_t root_dev;  /* Device number of root filesystem. */
+extern uint16_t swap_dev;  /* Device number used for swap */
 
 extern struct blkbuf bufpool[NBUFS];
 extern struct p_tab ptab[PTABSIZE];
index bce9377..dc1e73c 100644 (file)
@@ -41,7 +41,7 @@
 #define SWAPBASE    0x0000     /* We swap the lot in one, include the */
 #define SWAPTOP            0x8000      /* vectors so its a round number of sectors */
 
-#define MAX_SWAPS      16      /* Should be plenty */
+#define MAX_SWAPS      64      /* Should be plenty (2MB!) */
 
 #define BOOT_TTY (512 + 1)      /* Set this to default device for stdio, stderr */
                           /* In this case, the default is the first TTY device */
@@ -52,7 +52,7 @@
 /* Device parameters */
 #define NUM_DEV_TTY 3
 #define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
-#define SWAPDEV  (256)   /* Device for swapping (1st hd). */
+#define SWAPDEV  (swap_dev)  /* Device for swapping (dynamic). */
 #define NBUFS    10       /* Number of block buffers */
 #define NMOUNTS         4        /* Number of mounts at a time */
 
index 48a8aaa..4c35e11 100644 (file)
@@ -6,6 +6,7 @@
 #include <kdata.h>
 #include <printf.h>
 #include <devhd.h>
+#include <diskgeom.h>
 
 __sfr __at 0xC0 hd_wpbits;     /* Write protect and IRQ (not used) */
 __sfr __at 0xC1 hd_ctrl;       /* Reset and enable bits */
@@ -28,7 +29,7 @@ __sfr __at 0xCF hd_cmd;
 #define HDCMD_INIT     0x60    /* Ditto */
 #define HDCMD_SEEK     0x70
 
-#define RATE_2MS       0x04    /* 2ms step rate for hd (conservative) */
+#define RATE_4MS       0x08    /* 4ms step rate for hd (conservative) */
 
 #define HDCTRL_SOFTRESET       0x10
 #define HDCTRL_ENABLE          0x08
@@ -39,11 +40,16 @@ __sfr __at 0xCF hd_cmd;
 /* Used by the asm helpers */
 uint8_t hd_page;
 
+/* Swap is scanned for so not constant */
+uint16_t swap_dev;
+
 /* Seek and restore low 4 bits are the step rate, read/write support
    multi-sector mode but not all emulators do .. */
 
 #define MAX_HD 4
 
+struct minipart parts[MAX_HD];
+
 /* Wait for the drive to show ready */
 static uint8_t hd_waitready(void)
 {
@@ -73,21 +79,26 @@ static uint8_t hd_xfer(bool is_read, uint16_t addr)
                hd_xfer_in(addr);
        else
                hd_xfer_out(addr);
-       /* Should be returning READY, and maybe SEEKDONE */
+       /* Should beeturning READY, and maybe SEEKDONE */
        return hd_status;
 }
 
-static int hd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+int hd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
 {
        blkno_t block;
-       uint16_t dptr;
+       staticfast uint16_t dptr;
        uint16_t ct = 0;
-       int tries;
+       staticfast uint8_t tries;
        uint8_t err = 0;
        uint8_t cmd = HDCMD_READ;
        uint8_t head;
        uint8_t sector;
        uint16_t nblock;
+       staticfast uint16_t cyl;
+       uint8_t dev = minor >> 4;
+       staticfast struct minipart *p;
+
+       p = &parts[dev];
 
        if (rawflag == 0) {
                dptr = (uint16_t)udata.u_buf->bf_data;
@@ -105,30 +116,29 @@ static int hd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
        if (!is_read)
                cmd = HDCMD_WRITE;
 
+       /* TRS80 hard disk are 32 sectors/track, 256 byte sectors */
 
-       /* We assume 32 sectors per track for now. From our 512 byte
-          PoV that's 16 */
+       hd_precomp = p->g.precomp;
+       hd_seccnt = 1;
 
-       /* For our test purposes we use a disk with 32 sectors, 4 heads so
-          our blocks map out as   00cccccc ccCCCCCC CCHHSSSS
+       sector = block;
+       sector = ((sector << 1) & 0x1E) | 0x01;
 
-          This matches a real ST506 which is 153 cyls, 4 heads, 32 sector */
+       cyl = block >> 4;
 
-       hd_precomp = 0x20;      /* For now, matches an ST506 */
-       hd_seccnt = 1;
-       block <<= 1;            /* Into 256 byte blocks, limits us to 32MB
-                                  so ought to FIXME */
+       /* Do the maths once and on 16 bit numbers */
+       head = cyl % p->g.head;
+       cyl /= p->g.head;
+       if (minor)
+               cyl += p->cyl[(minor-1)&0x0F];
 
        while (ct < nblock) {
-               /* 32 sectors per track assumed for now */
-               sector = (block & 31) + 1;
-               head = (block >> 5) & 3;
                /* Head next bits, plus drive */
-               hd_sdh = 0x80 | head | (minor << 3);
+               hd_sdh = 0x80 | head | (dev << 3);
                hd_secnum = sector;
                /* cylinder bits */
-               hd_cyllo = (block >> 7) & 0xFF;
-               hd_cylhi = (block >> 15) & 0xFF;
+               hd_cyllo = cyl & 0xFF;
+               hd_cylhi = cyl >> 8;
 
                for (tries = 0; tries < 4; tries++) {
                        /* issue the command */
@@ -145,7 +155,7 @@ static int hd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
                                kprintf("hd%d: err %x\n", minor, err);
 
                        if (tries > 1) {
-                               hd_cmd = HDCMD_RESTORE;
+                               hd_cmd = HDCMD_RESTORE | p->g.seek;
                                if (hd_waitready() & 1)
                                        kprintf("hd%d: restore error %z\n", minor, err);
                        }
@@ -155,7 +165,16 @@ static int hd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
                        goto bad;
                ct++;
                dptr += 256;
-               block ++;
+               sector++;
+               /* Cheaper than divison! */
+               if (sector == 33) {
+                       sector = 1;
+                       head++;
+                       if (head == p->g.head) {
+                               head = 0;
+                               cyl++;
+                       }
+               }
        }
        return 1;
 bad:
@@ -170,17 +189,13 @@ bad2:
 
 int hd_open(uint8_t minor, uint16_t flag)
 {
+       uint8_t dev = minor >> 4;
        flag;
-       if (minor >= MAX_HD) {
+       if (dev > MAX_HD || parts[dev].g.head == 0 ||
+               (minor && parts[dev].cyl[(minor-1)&0x0F] == 0xFFFF)) {
                udata.u_error = ENODEV;
                return -1;
        }
-       hd_sdh = 0xA0 | (minor << 3);
-       hd_cmd = HDCMD_RESTORE | RATE_2MS;
-       if (hd_waitready() & 1) {
-               if ((hd_err & 0x12) == 0x12)
-                       return -ENODEV;
-       }
        return 0;
 }
 
@@ -195,3 +210,93 @@ int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
        flag;
        return hd_transfer(minor, false, rawflag);
 }
+
+/*------------------- below this is thrown after boot ---------------- */
+DISCARDABLE
+
+/*
+ *     Mini part processing. This and mbr and other things all one day
+ *     need to become a bit more unified.
+ */
+static void hd_swapon(struct minipart *p, unsigned int d, unsigned int i)
+{
+       uint16_t cyls;
+       if (i == 14 || p->cyl[i+1] == 0xFFFF)
+               cyls = p->g.cyl;
+       else
+               cyls = p->cyl[i+1];
+       cyls -= p->cyl[i];
+       cyls *= p->g.head;
+       /* This is now the number of sets of 32 sectors (16K) in swap.
+          We need 32K per process: hardwire it here - FIX if you change
+          the mapping model */
+
+       swap_dev = d << 4 + i + 1 + 0x100;
+
+       if (cyls >= MAX_SWAPS)
+               cyls = MAX_SWAPS - 1;
+       for (i = 0; i < cyls; i++) {
+               swapmap_add(i);
+       }
+       kputs("swap-");
+}
+
+void hd_probe(void)
+{
+       unsigned int dev = 0;
+       unsigned int i;
+       uint8_t *d = tmpbuf();
+       /* Second half of second block */
+       struct minipart *p = (struct minipart *)(d + 384);
+       for (dev = 0; dev < 4; dev++) {
+               hd_sdh = 0x80 | (dev << 3);
+               hd_cmd = HDCMD_RESTORE | RATE_4MS;
+               if (hd_waitready() & 1) {
+                       if ((hd_err & 0x12) == 0x12)
+                               continue;
+               }
+               hd_seccnt = 1;
+               hd_sdh = 0x80 | (dev << 3);
+               hd_secnum = 1;
+               hd_cyllo = 0;
+               hd_cylhi = 0;
+               hd_cmd = HDCMD_READ;
+               if (hd_waitdrq() & 1)
+                       continue;
+               if((hd_xfer(1, (uint16_t)d) & 0x41) != 0x40)
+                       continue;
+               kprintf("hd%c: ", dev + 'a');
+               if (p->g.magic != MP_SIG_0) {
+                       p->g.cyl = 1;
+                       p->g.head = 1;
+                       p->g.sec = 32;
+                       p->g.precomp = 0;
+                       p->g.seek = 10;
+                       p->g.secsize = 8;
+                       for (i = 0; i < 15; i++)
+                               p->cyl[i] = 0xFFFFU;
+                       kputs("(unlabelled)\n");
+               } else {
+                       for (i = 0; i < 15; i++) {
+                               if (p->cyl[i] != 0xFFFFU) {
+                                       if (p->type[i] == 0x56) {
+                                               /* Configure swap */
+                                               hd_swapon(p, dev, i);
+                                       }
+                                       kprintf("hd%c%d ", dev + 'a', i + 1);
+                               }
+                       }
+                       kputs("\n");
+               }
+               if (p->g.seek) {
+                       p->g.seek /= 2;
+                       if (p->g.seek == 0)
+                               p->g.seek = 1;
+               }
+               /* Set the step rate */
+               hd_cmd = HDCMD_SEEK | p->g.seek;
+               hd_waitready();
+               memcpy(&parts[dev], p, sizeof(parts[dev]));
+       }
+       brelse((bufptr)d);
+}
index 41200a7..bdebb17 100644 (file)
@@ -10,4 +10,6 @@ int hd_open(uint8_t minor, uint16_t flag);
 int hd_xfer_in(uint16_t addr);
 int hd_xfer_out(uint16_t addr);
 
+void hd_probe(void);
+
 #endif /* __DEVHD_DOT_H__ */
index bc59ba1..7287717 100644 (file)
@@ -34,14 +34,13 @@ bool validdev(uint16_t dev)
         return true;
 }
 
+DISCARDABLE
+
 void device_init(void)
 {
-  int i;
 #ifdef CONFIG_RTC
   /* Time of day clock */
   inittod();
 #endif
-  /* Add 64 swaps (2MB) */
-  for (i = MAX_SWAPS - 1 ; i >= 0; i--)
-    swapmap_add(i);
+  hd_probe();
 }
index 63935c5..ad25b07 100644 (file)
@@ -32,16 +32,6 @@ void platform_interrupt(void)
   timer_interrupt();
 }
 
-void map_init(void)
-{
-}
-
-void pagemap_init(void)
-{
- pagemap_add(0x63);    /* Mode 3, U64K low 32K mapped as low 32K */
- pagemap_add(0x73);    /* Mode 3, U64K high 32K mapped as low 32K */
-}
-
 #ifdef CONFIG_RTC
 
 __sfr __at 0xB0 rtc_secl;
@@ -59,3 +49,15 @@ uint8_t rtc_secs(void)
 }
 
 #endif
+
+DISCARDABLE
+
+void map_init(void)
+{
+}
+
+void pagemap_init(void)
+{
+ pagemap_add(0x63);    /* Mode 3, U64K low 32K mapped as low 32K */
+ pagemap_add(0x73);    /* Mode 3, U64K high 32K mapped as low 32K */
+}