| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 | /* * abcpun80.c * * Emulate a PUN80 network card */#include "compiler.h"#include "common.h"#include "io.h"#include "abcio.h"#define PUN_IOSEL	60/* ACM channel */#define PUN_TTY_CHAN	1#if PUN_TTY_CHAN >= TTY_CHANNELS# error "PUN_TTY_CHAN out of range"#endif#define PUN_DATA	TTY_DATA(PUN_TTY_CHAN)#define PUN_WATERCTL	TTY_WATERCTL(PUN_TTY_CHAN)#define PUN_STATUS	TTY_STATUS(PUN_TTY_CHAN)#define PUN_IRQEN	TTY_IRQEN(PUN_TTY_CHAN)#define PUN_IRQPOL	TTY_IRQPOL(PUN_TTY_CHAN)#define PUN_IRQ		TTY_NIRQ(PUN_TTY_CHAN)#define PUN_IRQ_MASK	(TTY_STATUS_TX_HIGH|TTY_STATUS_RX_LOW|\			 TTY_STATUS_RX_EMPTY|TTY_STATUS_DTR_IN)static struct abc_dev pun80_iodev;/* * Convert to FT232H-compatible status codes, and advance * the receive FIFO if applicable. */static __hot voidpun80_refresh_input(struct abc_dev *dev, bool advance){    static bool data_loaded;    unsigned int status;    uint8_t  pun80_status;    status = PUN_STATUS;    if (!data_loaded || advance) {	data_loaded = !(status & TTY_STATUS_RX_EMPTY);	if (data_loaded) {	    dev->inp_data_def = dev->inp_data[0] = PUN_DATA;	    status = PUN_STATUS;	}    }    PUN_IRQPOL = status;    pun80_status = 0xe6;    pun80_status ^= !!(status & TTY_STATUS_RX_LOW) << 4;    pun80_status ^= !!(status & TTY_STATUS_USB_CONFIG) << 3;    pun80_status ^= !!(status & TTY_STATUS_DTR_IN) << 2;    pun80_status ^= !!(status & TTY_STATUS_TX_HIGH) << 1;    pun80_status ^= data_loaded;    dev->inp_data[1] = pun80_status;    if (abc_selected_dev() == dev)	ABC_INP = dev->inp_data_w;}static ABC_CALLBACK(pun80_callback_out){    PUN_DATA = data;    CON_DATA = '>';    pun80_refresh_input(dev, false);}static ABC_CALLBACK(pun80_callback_inp){    CON_DATA = '<';    pun80_refresh_input(dev, true);}IRQHANDLER(tty,PUN_TTY_CHAN){    CON_DATA = '#';    pun80_refresh_input(&pun80_iodev, false);}/* The "flush" command in FT232H (C1#) is not needed with our USB stack */static struct abc_dev pun80_iodev = {    .callback_mask		= (1 << 0)|(1 << 8),    .inp_en			= 3,    .inp_data[1]                = 0xf6,    .status_first_out_mask	= ~0,    .status_first_inp_mask	= ~0,    .callback_out[0]		= pun80_callback_out,    .callback_inp[0]		= pun80_callback_inp};void pun80_init(void){    mask_irq(PUN_IRQ);    /*     * Set the TX high water mark to 1/4 = 256 bytes free. This allows     * OTIR to be used unconditionally for large transfers after     * polling the TX buffer status only once. The buffer is large     * enough that this should always be true in practice.     *     * The RX low water mark is set to 1/8 = 128 bytes occupied for     * similar reasons. This is added as a non-FT232H status bit 4 if     * 0 (FT232H always has 1 in this bit position.)     */    PUN_WATERCTL = TTY_WATERCTL_TX_LOW(0x3) | TTY_WATERCTL_TX_HIGH(0xc) |	TTY_WATERCTL_RX_LOW(0x1) | TTY_WATERCTL_TX_HIGH(0xc);    /*     * Immediately interrupt on any of:     *     * USB configured     * DTR asserted (host connected)     * TX not past high water mark     * RX not empty     */    PUN_IRQPOL = TTY_STATUS_RX_EMPTY | TTY_STATUS_RX_LOW | TTY_STATUS_TX_HIGH;    PUN_IRQEN  = PUN_IRQ_MASK;    unmask_irq(PUN_IRQ);    abc_register(&pun80_iodev, PUN_IOSEL);}
 |