DragonProbe/src/i2ctinyusb.c

140 lines
3.6 KiB
C

#include "protocfg.h"
#ifdef DBOARD_HAS_I2C
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "tusb.h"
#include "device/usbd_pvt.h"
#include "protos.h"
#include "thread.h"
static uint8_t itf_num;
static void iub_init(void) {
//printf("i2c init\n");
}
static void iub_reset(uint8_t rhport) {
//printf("i2c reset %02x\n", rhport);
itf_num = 0;
}
static uint16_t iub_open(uint8_t rhport, tusb_desc_interface_t const* itf_desc,
uint16_t max_len) {
TU_VERIFY(itf_desc->bInterfaceClass == 0
&& itf_desc->bInterfaceSubClass == 0
&& itf_desc->bInterfaceProtocol == 0, 0);
const uint16_t drv_len = sizeof(tusb_desc_interface_t);
TU_VERIFY(max_len >= drv_len, 0);
itf_num = itf_desc->bInterfaceNumber;
return drv_len;
}
extern char msgbuf[256];
extern volatile bool msgflag;
char msgbuf[256] = {0};
volatile bool msgflag = false;
//, b, c, d, e ,f
#define printf(fmt, a, b, c, d, e) do { \
/*while (msgflag) ;*/\
snprintf(msgbuf, sizeof msgbuf, fmt, a, b, c, d, e);\
msgbuf[sizeof msgbuf - 1] = 0; \
msgflag = true;\
} while (0);\
static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* req) {
if (stage != CONTROL_STAGE_SETUP) return true;
/*printf("ctl req rhport=%02x, stage=%02x, wIndex=%04x, bReq=%02x, wValue=%04x\n",
rhport, stage,
req->wIndex, req->bRequest, req->wValue);*/
if (req->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR) {
switch (req->bRequest) {
case 1: // get func
{
const uint32_t flags = 0xceff0001;
uint8_t rv[4];
rv[0]=flags&0xff;
rv[1]=(flags>>8)&0xff;
rv[2]=(flags>>16)&0xff;
rv[3]=(flags>>24)&0xff;
return tud_control_xfer(rhport, req, rv, sizeof rv);
}
case 2: // set delay
return tud_control_status(rhport, req);
case 3: // get status
{
uint8_t rv = 0; // idle
return tud_control_xfer(rhport, req, &rv, 1);
}
case 4: case 5: case 6: case 7: // I2C_IO
{
if (req->wValue & 1) { // read: we need to return shit
//printf("read!%c%c%c%c%c\n", ' ', ' ', ' ', ' ', ' ');
// so, we'll return some garbage
uint8_t buf[req->wLength];
return tud_control_xfer(rhport, req, buf, req->wLength);
} else {
//printf("write!%c%c%c%c%c\n", ' ', ' ', ' ', ' ', ' ');
// ????
uint8_t buf[req->wLength];
bool rv = tud_control_xfer(rhport, req, buf, req->wLength);
printf("rv %c len %04x buf %02x %02x %02x ...\n",
(rv?'t':'f'), req->wLength, buf[0], buf[1], buf[2]);
return rv;
}
}
}
}
return false; // unk
}
// never actually called
static bool iub_xfer(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
printf("xfer cb! rh=%02x ep=%02x res=%02x len=%08x%c\n",
rhport, ep_addr, result, xferred_bytes, ' ');
return true;
}
// interfacing stuff for TinyUSB API, actually defines the driver
static usbd_class_driver_t const i2ctinyusb_driver = {
#if CFG_TUSB_DEBUG >= 2
.name = "i2c-tiny-usb",
#endif
.init = iub_init,
.reset = iub_reset,
.open = iub_open,
.control_xfer_cb = iub_ctl_req,
.xfer_cb = iub_xfer,
.sof = NULL
};
usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) {
*driver_count = 1;
return &i2ctinyusb_driver;
}
// we need to implement this one, because tinyusb uses hardcoded stuff for
// endpoint 0, which is what the i2c-tiny-usb kernel module uses
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_control_request_t const* req) {
return iub_ctl_req(rhport, ep_addr, req);
}
#endif /* DBOARD_HAS_I2C */