|
@@ -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;
|
|
|
+}
|