瀏覽代碼

fw: ABC-bus I/O handler interrupt routine

H. Peter Anvin 3 年之前
父節點
當前提交
22b175e569
共有 3 個文件被更改,包括 124 次插入16 次删除
  1. 0 16
      fw/abcdma.c
  2. 94 0
      fw/abcio.c
  3. 30 0
      fw/abcio.h

+ 0 - 16
fw/abcdma.c

@@ -1,16 +0,0 @@
-#include "fw.h"
-#include "io.h"
-
-void setup_abc_dma(void *buf, unsigned int len, uint8_t devsel,
-		  bool dir_in, unsigned long status)
-{
-    devsel &= 63;
-
-    volatile uint32_t *portctl    = &ABCMEM_WRPORT(devsel)  + dir_in;
-    volatile uint32_t *portcount  = &ABCMEM_WRCOUNT(devsel) + dir_in;
-    volatile uint32_t *portstatus = &ABCMEMMAP_STATUS(devsel);
-
-    *portctl = ((size_t)buf & 0x01ffffff) | (ABCMEMMAP_WR << dir_in);
-    *portcount = len;
-    *portstatus = status;
-}

+ 94 - 0
fw/abcio.c

@@ -0,0 +1,94 @@
+/*
+ * abcio.c
+ *
+ * Handle ABC-bus I/O operations
+ */
+
+#include "fw.h"
+#include "io.h"
+#include "irq.h"
+#include "abcio.h"
+
+struct abc_dev *abc_device[64];
+static struct abc_dev *selected_dev;
+
+static inline void abc_select(struct abc_dev *dev)
+{
+    selected_dev = dev;
+    if (!dev) {
+	ABC_BUSY_MASK = 0x0082;	/* Only RST# and CS# */
+	ABC_INP_ENABLE = 0;
+    } else {
+	ABC_BUSY_MASK = dev->callback_mask | 0x0082;
+	ABC_INP_ENABLE = 3;
+    }
+}
+
+IRQHANDLER(abc)
+{
+    uint16_t what = ABC_BUSY_STATUS;
+    bool callback = selected_dev && (what & selected_dev->callback_mask);
+
+    if (what & 0xff) {
+	uint8_t addr = ABC_OUT_ADDR;
+	uint8_t data = ABC_OUT_DATA;
+
+	switch (addr) {
+	case 0:
+	    if (selected_dev->out_cnt) {
+		*selected_dev->out_buf++ = data;
+		selected_dev->inp_data[1] &= selected_dev->status_first_out_mask;
+		ABC_INP1_DATA = selected_dev->inp_data[1];
+		if (--selected_dev->out_cnt)
+		    callback = false;
+	    }
+
+	    /* fall through */
+	case 2 ... 5:
+	    selected_dev->out_data[addr] = data;
+	    if (callback)
+		selected_dev->callback_out(selected_dev, data, addr);
+	    break;
+
+	case 1:
+	{
+	    struct abc_dev *dev = abc_device[data & 0x3f];
+	    abc_select(dev);
+
+	    if (dev)
+		dev->out_data[addr] = data;
+	    break;
+	}
+
+	case 7:
+	    /* XXX: broadcast reset to devices? */
+	    abc_select(NULL);
+	    break;
+
+	default:
+	    break;
+	}
+    }
+
+    if (what & 0x100) {
+	if (selected_dev->inp_cnt) {
+	    ABC_INP0_DATA = *selected_dev->inp_buf++;
+	    selected_dev->inp_data[1] &= selected_dev->status_first_inp_mask;
+	    ABC_INP1_DATA = selected_dev->inp_data[1];
+	    if (--selected_dev->inp_cnt)
+		callback = false;
+	} else {
+	    ABC_INP0_DATA = selected_dev->inp_data[0];
+	}
+	if (callback)
+	    selected_dev->callback_inp(selected_dev, 0);
+    }
+
+    if (what & 0x200) {
+	ABC_INP1_DATA = selected_dev->inp_data[1];
+	if (callback)
+	    selected_dev->callback_inp(selected_dev, 1);
+    }
+
+    ABC_BUSY_STATUS = what;
+}

+ 30 - 0
fw/abcio.h

@@ -0,0 +1,30 @@
+#ifndef ABCIO_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct abc_dev {
+    uint8_t *out_buf;
+    size_t out_cnt;
+
+    const uint8_t *inp_buf;
+    size_t inp_cnt;
+
+    uint16_t callback_mask;
+
+    uint8_t status_first_out_mask;
+    uint8_t status_first_inp_mask;
+
+    uint8_t out_data[6];	/* [1] is devsel, all 8 bits */
+    union {
+	uint8_t inp_data[2];
+	uint16_t inp_data_w;
+    };
+
+    void (*callback_out)(struct abc_dev *, uint8_t addr, uint8_t data);
+    void (*callback_inp)(struct abc_dev *, uint8_t addr);
+};
+
+extern struct abc_dev *abc_device[64];
+
+#endif /* ABCIO_H */