| 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 */}
 |