123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- /*
- * 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[65]; /* 65 == post-RST# = always NULL */
- static struct abc_dev *selected_dev;
- static uint8_t abc_devsel = 64;
- #define EVENT_MASK_ALWAYS 0x0082 /* RST# and CS# */
- static inline __attribute__((always_inline))
- uint16_t event_mask(const struct abc_dev *dev)
- {
- if (!dev)
- return EVENT_MASK_ALWAYS;
- return EVENT_MASK_ALWAYS | dev->callback_mask |
- (dev->out_cnt ? 1 : 0) | (dev->inp_cnt ? 0x100 : 0);
- }
- /* Not inlining this makes the code larger...! */
- static inline __attribute__((always_inline))
- void refresh_dev(struct abc_dev *dev)
- {
- if (dev == selected_dev) {
- ABC_BUSY_MASK = event_mask(dev);
- ABC_INP = dev ? dev->inp_data_w : 0;
- }
- }
- static inline __attribute__((always_inline))
- void abc_select(struct abc_dev *dev)
- {
- selected_dev = dev;
- refresh_dev(dev);
- }
- IRQHANDLER(abc)
- {
- unsigned int what = ABC_BUSY_STATUS;
- struct abc_dev *dev = selected_dev;
- unsigned int callback = dev ? (what & dev->callback_mask) : 0;
- if (what & 0xff) {
- unsigned int addr = ABC_OUT_ADDR;
- unsigned int data = ABC_OUT_DATA;
- switch (addr) {
- case 0:
- if (!dev)
- break;
- 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, don't set out_data[] */
- }
- goto handle_out;
- case 1:
- dev = abc_device[abc_devsel = data & 0x3f];
- abc_select(dev);
- if (!dev)
- break;
- callback = dev->callback_mask & what;
- goto handle_out;
- case 2 ... 5:
- goto handle_out;
- handle_out:
- dev->out_data[addr] = data;
- if (callback & (1 << addr))
- dev->callback_out[addr](dev, data, addr);
- break;
- case 7:
- {
- struct abc_dev **devp;
- uint8_t old_devsel = abc_devsel;
- abc_devsel = DEVSEL_NONE;
- abc_select(NULL);
- devp = &abc_device[0];
- while (devp <= &abc_device[63]) {
- dev = *devp++;
- if (dev && (dev->callback_mask & 0x0080))
- dev->callback_rst(dev, old_devsel, 7);
- }
- dev = NULL;
- break;
- }
- default:
- break;
- }
- }
- if (what & 0x100) {
- if (dev->inp_cnt && --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++;
- /* No callback */
- } else {
- uint8_t old_data = ABC_INP0_DATA;
- ABC_INP0_DATA = dev->inp_data[0] = dev->inp_data_def;
- if (callback & 0x100)
- dev->callback_inp[0](dev, old_data, 0);
- }
- }
- if (what & 0x200) {
- uint8_t old_data = ABC_INP1_DATA;
- ABC_INP1_DATA = dev->inp_data[1];
- if (callback & 0x200)
- dev->callback_inp[1](dev, old_data, 1);
- }
- /* May need to change event_mask here */
- ABC_BUSY = what | (event_mask(dev) << 16);
- }
- void abc_setup_out_queue(struct abc_dev *dev, void *buf, size_t len,
- uint8_t status)
- {
- irqmask_t irqmask = mask_irq(ABC_IRQ);
- dev->out_buf = buf;
- dev->out_cnt = len;
- dev->inp_data[1] = status;
- refresh_dev(dev); /* Update registers as needed */
- restore_irq(irqmask, ABC_IRQ);
- }
- void abc_setup_inp_queue(struct abc_dev *dev, const void *buf, size_t len,
- uint8_t status)
- {
- irqmask_t irqmask = mask_irq(ABC_IRQ);
- dev->inp_buf = buf;
- dev->inp_cnt = len;
- dev->inp_data[0] = *dev->inp_buf++;
- dev->inp_data[1] = status;
- refresh_dev(dev); /* Update registers as needed */
- restore_irq(irqmask, ABC_IRQ);
- }
- void abc_set_inp_default(struct abc_dev *dev, uint8_t val)
- {
- irqmask_t irqmask = 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;
- }
- restore_irq(irqmask, ABC_IRQ);
- }
- void abc_set_inp_status(struct abc_dev *dev, uint8_t val)
- {
- irqmask_t irqmask = mask_irq(ABC_IRQ);
- dev->inp_data[1] = val;
- if (dev == selected_dev)
- ABC_INP1_DATA = val;
- restore_irq(irqmask, ABC_IRQ);
- }
- /*
- * This can be called before or after abc_init()!
- */
- void abc_register(struct abc_dev *dev, unsigned int devsel)
- {
- if (devsel > 63)
- return;
- irqmask_t irqmask = mask_irq(ABC_IRQ);
- if (!dev->inp_cnt)
- dev->inp_data[0] = dev->inp_data_def;
- abc_device[devsel] = dev;
- if (devsel == abc_devsel)
- abc_select(dev);
- restore_irq(irqmask, ABC_IRQ);
- }
- void abc_init(void)
- {
- unsigned int devsel;
- mask_irq(ABC_IRQ);
- devsel = ABC_IOSEL;
- abc_devsel = (devsel & 0x100) ? DEVSEL_NONE : (devsel & 63);
- abc_select(abc_device[abc_devsel]);
- unmask_irq(ABC_IRQ); /* Start ABC bus unconditionally */
- }
|