123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- /*
- * abcio.c
- *
- * Handle ABC-bus I/O operations
- */
- #include "fw.h"
- #include "io.h"
- #include "irq.h"
- #include "abcio.h"
- static struct abc_dev *abc_device[64];
- static struct abc_dev *selected_dev;
- static uint8_t abc_devsel = -1;
- /* Not inlining this makes the code larger...! */
- static inline __attribute__((always_inline))
- void abc_select(struct abc_dev *dev)
- {
- selected_dev = dev;
- if (!dev) {
- ABC_BUSY_MASK = 0x0082; /* Only RST# and CS# */
- ABC_INP = 0;
- } else {
- ABC_BUSY_MASK = dev->callback_mask | 0x0082;
- ABC_INP = dev->inp_data_w;
- }
- }
- IRQHANDLER(abc)
- {
- unsigned int what = ABC_BUSY_STATUS;
- unsigned int callback =
- selected_dev ? (what & selected_dev->callback_mask) : 0;
- struct abc_dev *dev = selected_dev;
- if (what & 0xff) {
- unsigned int addr = ABC_OUT_ADDR;
- unsigned int data = ABC_OUT_DATA;
- switch (addr) {
- case 0:
- dev->out_data[addr] = data;
- if (dev->out_cnt--) {
- *dev->out_buf++ = data;
- dev->inp_data[1] &= dev->status_first_out_mask;
- ABC_INP1_DATA = dev->inp_data[1];
- if (!dev->out_cnt)
- break; /* No callback */
- }
- if (callback & 1)
- dev->callback_out(dev, data);
- break;
- case 2 ... 5:
- dev->out_data[addr] = data;
- if (callback & (1 << addr))
- dev->callback_cmd(dev, data, addr);
- break;
- case 1:
- dev = abc_device[abc_devsel = data & 0x3f];
- abc_select(dev);
- if (dev)
- dev->out_data[addr] = data;
- break;
- case 7:
- /* XXX: broadcast reset to devices? */
- abc_devsel = -1;
- abc_select(NULL);
- break;
- default:
- break;
- }
- }
- if (what & 0x100) {
- if (--dev->inp_cnt) {
- dev->inp_data[1] &= dev->status_first_inp_mask;
- ABC_INP1_DATA = dev->inp_data[1];
- ABC_INP0_DATA = dev->inp_data[0] = *dev->inp_buf++;
- } else {
- ABC_INP0_DATA = dev->inp_data[0] = dev->inp_data_def;
- if (callback & 0x100)
- dev->callback_inp(dev);
- }
- }
- if (what & 0x200) {
- ABC_INP1_DATA = dev->inp_data[1];
- if (callback & 0x200)
- dev->callback_status(dev);
- }
- ABC_BUSY_STATUS = what;
- }
- void abc_setup_out_queue(struct abc_dev *dev, void *buf, size_t len,
- uint8_t status)
- {
- mask_irq(ABC_IRQ);
- dev->out_buf = buf;
- dev->out_cnt = len;
- ABC_INP1_DATA = dev->inp_data[1] = status;
- dev->callback_mask |= (1 << 0);
- unmask_irq(ABC_IRQ);
- }
- void abc_setup_inp_queue(struct abc_dev *dev, const void *buf, size_t len,
- uint8_t status)
- {
- mask_irq(ABC_IRQ);
- dev->inp_buf = buf;
- dev->inp_cnt = len;
- ABC_INP0_DATA = dev->inp_data[0] = *dev->inp_buf++;
- ABC_INP1_DATA = dev->inp_data[1] = status;
- dev->callback_mask |= (1 << 8);
- unmask_irq(ABC_IRQ);
- }
- void abc_set_inp_default(struct abc_dev *dev, uint8_t val)
- {
- mask_irq(ABC_IRQ);
- dev->inp_data_def = val;
- if (!dev->inp_cnt) {
- dev->inp_data[0] = val;
- if (dev == selected_dev)
- ABC_INP0_DATA = val;
- }
- unmask_irq(ABC_IRQ);
- }
- void abc_set_inp_status(struct abc_dev *dev, uint8_t val)
- {
- mask_irq(ABC_IRQ);
- dev->inp_data[1] = val;
- if (dev == selected_dev)
- ABC_INP1_DATA = val;
- unmask_irq(ABC_IRQ);
- }
- void abc_register(struct abc_dev *dev, unsigned int devsel)
- {
- if (devsel > 63)
- return;
- mask_irq(ABC_IRQ);
- abc_device[devsel] = dev;
- if (devsel == abc_devsel)
- abc_select(dev);
- unmask_irq(ABC_IRQ);
- }
- void abc_init(void)
- {
- unsigned int devsel;
- mask_irq(ABC_IRQ);
- devsel = ABC_IOSEL;
- abc_devsel = (devsel & 0x100) ? -1U : devsel & 0x3f;
- abc_select(NULL);
- unmask_irq(ABC_IRQ);
- }
|