/* * abcpun80.c * * Emulate a PUN80 network card */ #include "compiler.h" #include "fw.h" #include "io.h" #include "abcio.h" #define PUN_IOSEL 60 #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_FULL|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 void pun80_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 = ~15 | data_loaded; if (status & TTY_STATUS_DTR_IN) pun80_status |= 8; if (!(status & TTY_STATUS_TX_FULL)) pun80_status |= 2; 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; pun80_refresh_input(dev, false); } static ABC_CALLBACK(pun80_callback_inp) { 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] = 0xf0, .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); /* * Immediately interrupt on: * * USB configured * TX full * RX not empty */ PUN_IRQPOL = TTY_STATUS_RX_EMPTY; PUN_IRQEN = PUN_IRQ_MASK; unmask_irq(PUN_IRQ); abc_register(&pun80_iodev, PUN_IOSEL); }