| 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);}
 |