abcio.c 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /*
  2. * abcio.c
  3. *
  4. * Handle ABC-bus I/O operations
  5. */
  6. #include "fw.h"
  7. #include "io.h"
  8. #include "irq.h"
  9. #include "abcio.h"
  10. struct abc_dev *abc_device[64];
  11. static struct abc_dev *selected_dev;
  12. static inline void abc_select(struct abc_dev *dev)
  13. {
  14. selected_dev = dev;
  15. if (!dev) {
  16. ABC_BUSY_MASK = 0x0082; /* Only RST# and CS# */
  17. ABC_INP_ENABLE = 0;
  18. } else {
  19. ABC_BUSY_MASK = dev->callback_mask | 0x0082;
  20. ABC_INP_ENABLE = 3;
  21. }
  22. }
  23. IRQHANDLER(abc)
  24. {
  25. uint16_t what = ABC_BUSY_STATUS;
  26. bool callback = selected_dev && (what & selected_dev->callback_mask);
  27. if (what & 0xff) {
  28. uint8_t addr = ABC_OUT_ADDR;
  29. uint8_t data = ABC_OUT_DATA;
  30. switch (addr) {
  31. case 0:
  32. if (selected_dev->out_cnt) {
  33. *selected_dev->out_buf++ = data;
  34. selected_dev->inp_data[1] &= selected_dev->status_first_out_mask;
  35. ABC_INP1_DATA = selected_dev->inp_data[1];
  36. if (--selected_dev->out_cnt)
  37. callback = false;
  38. }
  39. /* fall through */
  40. case 2 ... 5:
  41. selected_dev->out_data[addr] = data;
  42. if (callback)
  43. selected_dev->callback_out(selected_dev, data, addr);
  44. break;
  45. case 1:
  46. {
  47. struct abc_dev *dev = abc_device[data & 0x3f];
  48. abc_select(dev);
  49. if (dev)
  50. dev->out_data[addr] = data;
  51. break;
  52. }
  53. case 7:
  54. /* XXX: broadcast reset to devices? */
  55. abc_select(NULL);
  56. break;
  57. default:
  58. break;
  59. }
  60. }
  61. if (what & 0x100) {
  62. if (selected_dev->inp_cnt) {
  63. ABC_INP0_DATA = *selected_dev->inp_buf++;
  64. selected_dev->inp_data[1] &= selected_dev->status_first_inp_mask;
  65. ABC_INP1_DATA = selected_dev->inp_data[1];
  66. if (--selected_dev->inp_cnt)
  67. callback = false;
  68. } else {
  69. ABC_INP0_DATA = selected_dev->inp_data[0];
  70. }
  71. if (callback)
  72. selected_dev->callback_inp(selected_dev, 0);
  73. }
  74. if (what & 0x200) {
  75. ABC_INP1_DATA = selected_dev->inp_data[1];
  76. if (callback)
  77. selected_dev->callback_inp(selected_dev, 1);
  78. }
  79. ABC_BUSY_STATUS = what;
  80. }