devdw: move common bits to the dev/ directory
authorAlan Cox <alan@linux.intel.com>
Mon, 1 Jun 2015 19:46:42 +0000 (20:46 +0100)
committerAlan Cox <alan@linux.intel.com>
Mon, 1 Jun 2015 19:46:42 +0000 (20:46 +0100)
Kernel/dev/devdw.c [new file with mode: 0644]
Kernel/dev/devdw.h [new file with mode: 0644]

diff --git a/Kernel/dev/devdw.c b/Kernel/dev/devdw.c
new file mode 100644 (file)
index 0000000..b4168be
--- /dev/null
@@ -0,0 +1,112 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devdw.h>
+
+#define MAX_DW 4       /* can be 255 */
+
+#define DW_READ                0
+#define DW_WRITE       1
+
+static uint8_t dw_tab[MAX_DW];
+
+/*
+ *     Block device glue for DriveWire
+ *
+ *     DriveWire uses 256 byte sector transfers
+ */
+
+static int dw_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+    blkno_t block;
+    uint16_t dptr;
+    int nblock;
+    int tries;
+    uint8_t err;
+    uint8_t *driveptr = dw_tab + minor;
+    uint8_t cmd[6];
+    uint8_t page;
+    irqflags_t irq;
+
+    if (rawflag == 0) {
+        page = 0;
+        dptr = (uint16_t)udata.u_buf->bf_data;
+        block = udata.u_buf->bf_blk;
+        nblock = 2;
+    } else if (rawflag == 1) {
+        if (((uint16_t)udata.u_offset|udata.u_count) & BLKMASK)
+            goto bad2;
+        page = (uint8_t)udata.u_page;
+        dptr = (uint16_t)udata.u_base;
+        block = udata.u_offset >> 9;
+        nblock = udata.u_count >> 8;
+    } else if (rawflag == 2) {
+        page = (uint8_t)swappage;
+        dptr = (uint16_t)swapbase;
+        nblock = swapcnt >> 8;
+        block = swapblk;
+    } else
+        goto bad2;
+
+//    kprintf("Issue command: drive %d\n", minor);
+    /* maybe mimicking floppy driver more than needed? */
+    cmd[0] = is_read ? DW_READ : DW_WRITE;
+    cmd[1] = block >> 7;       /* 2 sectors per block */
+    cmd[2] = (block << 1) & 0xFF;
+    cmd[3] = dptr >> 8;
+    cmd[4] = dptr & 0xFF;
+    cmd[5] = page;
+    *driveptr = minor; /* pass minor (drive number) through here for now */
+        
+    while (nblock--) {
+        for (tries = 0; tries < 4 ; tries++) {
+            // kprintf("dw_operation block %d left %d\n", block, nblock);
+            irq = di(); /* for now block interrupts for whole operation */
+            err = dw_operation(cmd, driveptr);
+            irqrestore(irq);
+            if (err == 0)
+                break;
+            if (tries > 1)
+                dw_reset(driveptr);
+        }
+        /* FIXME: should we try the other half and then bail out ? */
+        if (tries == 3)
+            goto bad;
+        cmd[3]++;      /* Move on 256 bytes in the buffer */
+        cmd[2]++;      /* Next sector for 2nd block */
+        if (cmd[2] == 0)
+            cmd[1]++;
+    }
+    return 1;
+bad:
+    kprintf("dw%d: error %x\n", minor, err);
+bad2:
+    udata.u_error = EIO;
+    return -1;
+}
+
+/* FIXME: for bit-banger transport (not Becker) we should set up
+   the PIA at some point too */
+
+int dw_open(uint8_t minor, uint16_t flag)
+{
+    used(flag);
+    if(minor >= MAX_DW) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int dw_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    used(flag);
+    return dw_transfer(minor, true, rawflag);
+}
+
+int dw_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    used(flag);
+    return dw_transfer(minor, false, rawflag);
+}
+
diff --git a/Kernel/dev/devdw.h b/Kernel/dev/devdw.h
new file mode 100644 (file)
index 0000000..d7b9358
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __DEVDW_DOT_H__
+#define __DEVDW_DOT_H__
+
+/* public interface */
+int dw_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int dw_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int dw_open(uint8_t minor, uint16_t flag);
+
+/* low level interface */
+uint8_t dw_reset(uint8_t *drive);
+uint8_t dw_operation(uint8_t *cmd, uint8_t *drive);
+
+#endif /* __DEVDW_DOT_H__ */
+