abcpun80.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. * abcpun80.c
  3. *
  4. * Emulate a PUN80 network card
  5. */
  6. #include "compiler.h"
  7. #include "common.h"
  8. #include "io.h"
  9. #include "abcio.h"
  10. #define PUN_IOSEL 60
  11. /* ACM channel */
  12. #define PUN_TTY_CHAN 1
  13. #if PUN_TTY_CHAN >= TTY_CHANNELS
  14. # error "PUN_TTY_CHAN out of range"
  15. #endif
  16. #define PUN_DATA TTY_DATA(PUN_TTY_CHAN)
  17. #define PUN_WATERCTL TTY_WATERCTL(PUN_TTY_CHAN)
  18. #define PUN_STATUS TTY_STATUS(PUN_TTY_CHAN)
  19. #define PUN_IRQEN TTY_IRQEN(PUN_TTY_CHAN)
  20. #define PUN_IRQPOL TTY_IRQPOL(PUN_TTY_CHAN)
  21. #define PUN_IRQ TTY_NIRQ(PUN_TTY_CHAN)
  22. #define PUN_IRQ_MASK (TTY_STATUS_TX_HIGH|TTY_STATUS_RX_LOW|\
  23. TTY_STATUS_RX_EMPTY|TTY_STATUS_DTR_IN)
  24. static struct abc_dev pun80_iodev;
  25. /*
  26. * Convert to FT232H-compatible status codes, and advance
  27. * the receive FIFO if applicable.
  28. */
  29. static __hot void
  30. pun80_refresh_input(struct abc_dev *dev, bool advance)
  31. {
  32. static bool data_loaded;
  33. unsigned int status;
  34. uint8_t pun80_status;
  35. status = PUN_STATUS;
  36. if (!data_loaded || advance) {
  37. data_loaded = !(status & TTY_STATUS_RX_EMPTY);
  38. if (data_loaded) {
  39. dev->inp_data_def = dev->inp_data[0] = PUN_DATA;
  40. status = PUN_STATUS;
  41. }
  42. }
  43. PUN_IRQPOL = status;
  44. pun80_status = 0xe6;
  45. pun80_status ^= !!(status & TTY_STATUS_RX_LOW) << 4;
  46. pun80_status ^= !!(status & TTY_STATUS_USB_CONFIG) << 3;
  47. pun80_status ^= !!(status & TTY_STATUS_DTR_IN) << 2;
  48. pun80_status ^= !!(status & TTY_STATUS_TX_HIGH) << 1;
  49. pun80_status ^= data_loaded;
  50. dev->inp_data[1] = pun80_status;
  51. if (abc_selected_dev() == dev)
  52. ABC_INP = dev->inp_data_w;
  53. }
  54. static ABC_CALLBACK(pun80_callback_out)
  55. {
  56. PUN_DATA = data;
  57. CON_DATA = '>';
  58. pun80_refresh_input(dev, false);
  59. }
  60. static ABC_CALLBACK(pun80_callback_inp)
  61. {
  62. CON_DATA = '<';
  63. pun80_refresh_input(dev, true);
  64. }
  65. IRQHANDLER(tty,PUN_TTY_CHAN)
  66. {
  67. CON_DATA = '#';
  68. pun80_refresh_input(&pun80_iodev, false);
  69. }
  70. /* The "flush" command in FT232H (C1#) is not needed with our USB stack */
  71. static struct abc_dev pun80_iodev = {
  72. .callback_mask = (1 << 0)|(1 << 8),
  73. .inp_en = 3,
  74. .inp_data[1] = 0xf6,
  75. .status_first_out_mask = ~0,
  76. .status_first_inp_mask = ~0,
  77. .callback_out[0] = pun80_callback_out,
  78. .callback_inp[0] = pun80_callback_inp
  79. };
  80. void pun80_init(void)
  81. {
  82. mask_irq(PUN_IRQ);
  83. /*
  84. * Set the TX high water mark to 1/4 = 256 bytes free. This allows
  85. * OTIR to be used unconditionally for large transfers after
  86. * polling the TX buffer status only once. The buffer is large
  87. * enough that this should always be true in practice.
  88. *
  89. * The RX low water mark is set to 1/8 = 128 bytes occupied for
  90. * similar reasons. This is added as a non-FT232H status bit 4 if
  91. * 0 (FT232H always has 1 in this bit position.)
  92. */
  93. PUN_WATERCTL = TTY_WATERCTL_TX_LOW(0x3) | TTY_WATERCTL_TX_HIGH(0xc) |
  94. TTY_WATERCTL_RX_LOW(0x1) | TTY_WATERCTL_TX_HIGH(0xc);
  95. /*
  96. * Immediately interrupt on any of:
  97. *
  98. * USB configured
  99. * DTR asserted (host connected)
  100. * TX not past high water mark
  101. * RX not empty
  102. */
  103. PUN_IRQPOL = TTY_STATUS_RX_EMPTY | TTY_STATUS_RX_LOW | TTY_STATUS_TX_HIGH;
  104. PUN_IRQEN = PUN_IRQ_MASK;
  105. unmask_irq(PUN_IRQ);
  106. abc_register(&pun80_iodev, PUN_IOSEL);
  107. }