tiny.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. * i2c-tiny-usb protocol (Linux drivers/i2c/busses/i2c-tiny-usb.c) on EP0 vendor requests.
  3. *
  4. * bReq 0 ECHO IN 2 B: wValue echoed back
  5. * bReq 1 GET_FUNC IN 4 B: I2C functionality bits, little endian
  6. * bReq 2 SET_DELAY OUT 0 B: wValue = SCL half period in us (kernel default 10 = 100 kHz)
  7. * bReq 3 GET_STATUS IN 1 B: 0 idle, 1 address ACK, 2 address NAK
  8. * bReq 4 I2C_IO (+1 BEGIN: START, +2 END: STOP; neither: repeated START)
  9. * wValue = i2c_msg flags (bit0 = read), wIndex = 7-bit address,
  10. * data stage = message payload (OUT for write, IN for read), any length.
  11. *
  12. * The kernel sends one I2C_IO per i2c_msg followed by GET_STATUS. Address NAK is
  13. * reported via GET_STATUS (-> -ENXIO); data NAK or bus error STALLs the request (-> -EIO).
  14. * While a transaction is open, the CDC side is held off (see tiny_busy()).
  15. */
  16. #include <avr/pgmspace.h>
  17. #include "usb.h"
  18. #include "i2c.h"
  19. #include "tiny.h"
  20. #define CMD_ECHO 0
  21. #define CMD_GET_FUNC 1
  22. #define CMD_SET_DELAY 2
  23. #define CMD_GET_STATUS 3
  24. #define CMD_I2C_IO 4
  25. #define CMD_IO_BEGIN 1
  26. #define CMD_IO_END 2
  27. #define STATUS_IDLE 0
  28. #define STATUS_ACK 1
  29. #define STATUS_NAK 2
  30. #define I2C_M_RD 0x0001
  31. #define I2C_M_TEN 0x0010
  32. /* I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL */
  33. static const uint8_t func[4] PROGMEM = { 0x09, 0x00, 0xFF, 0x0E };
  34. static uint8_t status;
  35. static bool open; /* START sent, no STOP yet */
  36. static uint8_t idle_ticks;
  37. static uint8_t k_delay = 50; /* own SCL setting; kernel default 10 us -> 50 */
  38. bool tiny_busy(void) { return open; }
  39. static void close_bus(void)
  40. {
  41. if (open) i2c_stop();
  42. open = false;
  43. }
  44. void usb_reset_hook(void) { close_bus(); status = STATUS_IDLE; }
  45. void tiny_tick(void) /* ~16 ms: drop a transaction the host abandoned */
  46. {
  47. if (open && ++idle_ticks > 6) close_bus();
  48. }
  49. /*
  50. * SCL half period in us -> i2c.c delay units, never faster than asked. The
  51. * period is 38 + 6 * units cycles (40 at 0), so 0 and 1 us both give the
  52. * 400 kHz maximum, 2 us 235 kHz and the driver's default 10 us 50 kHz.
  53. */
  54. static uint8_t us_to_delay(uint16_t us)
  55. {
  56. if (us <= 1) return 0;
  57. if (us >= 49) return 255;
  58. return (uint8_t)((32 * us - 38 + 5) / 6);
  59. }
  60. static void i2c_io(uint8_t cmd, bool usb_in, uint16_t flags, uint8_t addr, uint16_t len)
  61. {
  62. bool rd = flags & I2C_M_RD;
  63. if (rd != usb_in || (flags & I2C_M_TEN)) { ep0_stall(); return; }
  64. bool repeated = open && !(cmd & CMD_IO_BEGIN);
  65. if (!repeated) i2c_set_delay(k_delay); /* the CDC side has its own speed */
  66. open = true;
  67. uint8_t st = i2c_start((uint8_t)(addr << 1) | rd, repeated);
  68. if (st == I2C_BUS_ERR) goto fail;
  69. status = (st == I2C_OK) ? STATUS_ACK : STATUS_NAK;
  70. bool nak = st != I2C_OK; /* still complete the data stage, the driver checks status */
  71. uint8_t buf[EP0_SIZE];
  72. if (!rd) {
  73. while (len) {
  74. uint8_t n = ep0_rx(buf);
  75. if (n == 0xFF) goto abort;
  76. if (n == 0 || n > len) n = (uint8_t)len; /* ZLP / overrun: stop here */
  77. len -= n;
  78. if (!nak)
  79. for (uint8_t i = 0; i < n; i++)
  80. if (i2c_write(buf[i]) != I2C_OK) goto fail;
  81. }
  82. } else {
  83. while (len) {
  84. uint8_t n = len > EP0_SIZE ? EP0_SIZE : (uint8_t)len;
  85. for (uint8_t i = 0; i < n; i++) {
  86. len--;
  87. buf[i] = nak ? 0xFF : i2c_read(len != 0); /* NACK the final byte */
  88. }
  89. if (!nak && i2c_bus_error()) goto fail;
  90. if (!ep0_tx(buf, n)) goto abort;
  91. }
  92. }
  93. if (nak || (cmd & CMD_IO_END)) close_bus();
  94. if (rd) ep0_status_out(); else ep0_status_in();
  95. return;
  96. fail:
  97. ep0_stall();
  98. abort:
  99. close_bus();
  100. status = STATUS_IDLE;
  101. }
  102. void usb_vendor_request(uint8_t bmRT, uint8_t bReq, uint16_t wV, uint16_t wI, uint16_t wL)
  103. {
  104. idle_ticks = 0;
  105. switch (bReq) {
  106. case CMD_ECHO: ep0_send(&wV, 2, wL, false); break;
  107. case CMD_GET_FUNC: ep0_send(func, sizeof func, wL, true); break;
  108. case CMD_SET_DELAY: k_delay = us_to_delay(wV); ep0_status_in(); break;
  109. case CMD_GET_STATUS: ep0_send(&status, 1, wL, false); break;
  110. case CMD_I2C_IO:
  111. case CMD_I2C_IO | CMD_IO_BEGIN:
  112. case CMD_I2C_IO | CMD_IO_END:
  113. case CMD_I2C_IO | CMD_IO_BEGIN | CMD_IO_END:
  114. i2c_io(bReq, bmRT & 0x80, wV, wI & 0x7F, wL);
  115. break;
  116. default: ep0_stall();
  117. }
  118. }