123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- /*
- * abcpun80.c
- *
- * Emulate a PUN80 network card
- */
- #include "compiler.h"
- #include "common.h"
- #include "io.h"
- #include "abcio.h"
- #include "config.h"
- /* 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 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 = 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,
- .name = "pun80"
- };
- 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);
- pun80_config();
- }
- void pun80_config(void)
- {
- unsigned int devsel = getvar_uint(config_abc_io_pun80_devsel);
- if (!getvar_bool(config_abc_io_pun80_enable))
- devsel = DEVSEL_NONE;
- abc_register(&pun80_iodev, devsel);
- }
|