initial ftdi stuff

This commit is contained in:
Triss 2021-08-23 18:26:35 +02:00
parent a1561ee35a
commit 45cce4dfff
5 changed files with 302 additions and 2 deletions

View File

@ -20,7 +20,7 @@
#else
#define CFG_TUD_CDC 2
#endif
#define CFG_TUD_VENDOR 1
#define CFG_TUD_VENDOR 2
/* don't access storage for RAM-only builds */
#if !PICO_NO_FLASH

192
src/m_ftdi/_ftdi.c Normal file
View File

@ -0,0 +1,192 @@
// vim: set et:
#include <tusb.h>
#include "mode.h"
#include "thread.h"
#include "usbstdio.h"
#include "vnd_cfg.h"
#include "m_ftdi/bsp-feature.h"
#include "ftdi.h"
#ifdef DBOARD_HAS_FTDI
static cothread_t ftdithread;
static uint8_t ftdistack[THREAD_STACK_SIZE];
static void ftdi_thread_fn(void) {
ftdi_init();
thread_yield();
while (1) {
ftdi_task();
thread_yield();
}
}
#endif
static void enter_cb(void) {
#ifdef USE_USBCDC_FOR_STDIO
stdio_usb_set_itf_num(CDC_N_STDIO);
#endif
vnd_cfg_set_itf_num(VND_N_CFG);
#ifdef DBOARD_HAS_FTDI
ftdithread = co_derive(ftdistack, sizeof ftdistack, ftdi_thread_fn);
thread_enter(ftdithread);
#endif
}
static void leave_cb(void) {
#ifdef DBOARD_HAS_FTDI
ftdi_deinit();
#endif
}
static void task_cb(void) {
#ifdef DBOARD_HAS_FTDI
ftdi_task();
#endif
}
static void handle_cmd_cb(uint8_t cmd) {
switch (cmd) {
default:
vnd_cfg_write_strf(cfg_resp_illcmd, "unknown mode5 command %02x", cmd);
break;
}
}
enum {
STRID_LANGID = 0,
STRID_MANUFACTURER,
STRID_PRODUCT,
STRID_SERIAL,
STRID_CONFIG,
STRID_IF_VND_CFG,
STRID_IF_VND_FTDI_IFA,
STRID_IF_VND_FTDI_IFB,
STRID_IF_CDC_STDIO,
};
enum {
ITF_NUM_VND_FTDI_IFA,
ITF_NUM_VND_FTDI_IFB,
#if CFG_TUD_VENDOR > 0
ITF_NUM_VND_CFG,
#endif
#ifdef USE_USBCDC_FOR_STDIO
ITF_NUM_CDC_STDIO_COM,
ITF_NUM_CDC_STDIO_DATA,
#endif
ITF_NUM__TOTAL
};
enum {
CONFIG_TOTAL_LEN
= TUD_CONFIG_DESC_LEN
+ TUD_VENDOR_DESC_LEN
+ TUD_VENDOR_DESC_LEN
#if CFG_TUD_VENDOR > 0
+ TUD_VENDOR_DESC_LEN
#endif
#ifdef USE_USBCDC_FOR_STDIO
+ TUD_CDC_DESC_LEN
#endif
};
#define EPNUM_VND_FTDI_IFA_OUT 0x02
#define EPNUM_VND_FTDI_IFA_IN 0x81
#define EPNUM_VND_FTDI_IFB_OUT 0x04
#define EPNUM_VND_FTDI_IFB_IN 0x83
#define EPNUM_VND_CFG_OUT 0x05
#define EPNUM_VND_CFG_IN 0x85
#define EPNUM_CDC_STDIO_OUT 0x06
#define EPNUM_CDC_STDIO_IN 0x86
#define EPNUM_CDC_STDIO_NOTIF 0x87
// clang-format off
static const uint8_t desc_configuration[] = {
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM__TOTAL, STRID_CONFIG, CONFIG_TOTAL_LEN,
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
TUD_VENDOR_DESCRIPTOR_EX(ITF_NUM_VND_FTDI_IFA, STRID_IF_VND_FTDI_IFA,
EPNUM_VND_FTDI_IFA_OUT, EPNUM_VND_FTDI_IFA_IN, CFG_TUD_VENDOR_RX_BUFSIZE, 255, 255),
TUD_VENDOR_DESCRIPTOR_EX(ITF_NUM_VND_FTDI_IFB, STRID_IF_VND_FTDI_IFB,
EPNUM_VND_FTDI_IFB_OUT, EPNUM_VND_FTDI_IFB_IN, CFG_TUD_VENDOR_RX_BUFSIZE, 255, 255),
#if CFG_TUD_VENDOR > 0
TUD_VENDOR_DESCRIPTOR_EX(ITF_NUM_VND_CFG, STRID_IF_VND_CFG, EPNUM_VND_CFG_OUT,
EPNUM_VND_CFG_IN, CFG_TUD_VENDOR_RX_BUFSIZE, VND_CFG_SUBCLASS, VND_CFG_PROTOCOL),
#endif
#ifdef USE_USBCDC_FOR_STDIO
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_STDIO_COM, STRID_IF_CDC_STDIO, EPNUM_CDC_STDIO_NOTIF,
CFG_TUD_CDC_RX_BUFSIZE, EPNUM_CDC_STDIO_OUT, EPNUM_CDC_STDIO_IN, CFG_TUD_CDC_RX_BUFSIZE),
#endif
};
static const char* string_desc_arr[] = {
NULL,
[STRID_CONFIG] = "Configuration descriptor",
// max string length check: |||||||||||||||||||||||||||||||
[STRID_IF_VND_CFG ] = "Device cfg/ctl interface",
[STRID_IF_VND_FTDI_IFA] = "FT2232C interface A",
[STRID_IF_VND_FTDI_IFB] = "FT2232C interface B",
#ifdef USE_USBCDC_FOR_STDIO
[STRID_IF_CDC_STDIO] = "stdio CDC interface (debug)",
#endif
};
// clang-format on
static const tusb_desc_device_t desc_device = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0110, // TODO: 0x0200 ? is an eeprom option
.bDeviceClass = 0x00,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0x0403, // ?
.idProduct = 0x6010, // ?
.bcdDevice = 0x0500, // required!
.iManufacturer = STRID_MANUFACTURER,
.iProduct = STRID_PRODUCT,
.iSerialNumber = STRID_SERIAL,
.bNumConfigurations = 0x01
};
static const uint8_t* my_descriptor_device_cb(void) {
return (const uint8_t*)&desc_device;
}
extern struct mode m_05_ftdi;
// clang-format off
struct mode m_05_ftdi = {
.name = "FTDI FT2232C (single-channel) emulation mode",
.version = 0x0010,
.n_string_desc = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]),
.usb_desc = desc_configuration,
.string_desc = string_desc_arr,
.enter = enter_cb,
.leave = leave_cb,
.task = task_cb,
.handle_cmd = handle_cmd_cb,
#ifdef DBOARD_HAS_FTDI
.tud_descriptor_device_cb = my_descriptor_device_cb,
#endif
#ifdef DBOARD_HAS_FTDI
.tud_vendor_control_xfer_cb = ftdi_control_xfer_cb,
#endif
};
// clang-format on

90
src/m_ftdi/ftdi.c Normal file
View File

@ -0,0 +1,90 @@
#include "tusb_config.h"
#include <tusb.h>
// for handling USB bulk commands
void ftdi_init(void) {
}
void ftdi_deinit(void) {
}
void ftdi_task(void) {
}
bool ftdi_control_xfer_cb(uint8_t rhport, uint8_t stage,
tusb_control_request_t const* req) {
// return true: don't stall
// return false: stall
// not a vendor request -> not meant for this code
if (req->bmRequestType_bit.type != TUSB_REQ_TYPE_VENDOR) return true;
// index = interface number (A/B)
// out/in bRequest wValue wIndex data wLength
// RESET: out 0 0 index
// TCIFLUSH: out 0 2 index
// TCOFLUSH: out 0 1 index
// SETMODEMCTRL:out 1 (mask:8<<8 | data:8) // bit0=dtr bit1=rts
// SETFLOWCTRL: out 2 xon?1:0 (flowctrl | index) // flowctrl: 0=disable, 1=ctsrts, 2=dtrdsr 4=xonxoff FROM VALUE, not set/reset!
// SETBAUDRATE: out 3 brate index // 48 MHz clocks, /16?
// SETLINEPROP: out 4 (break:1<<14 | stop:2<<11 | parity:3<<8 | bits:8) ; break: off/on, stop=1/15/2, parity=none/odd/even/mark/space; bits=7/8
// POLLMODEMSTAT:in 5 0 index &modemstat len=2 // first byte: bit0..3=0 bit4=cts bit5=dts bit6=ri bit7=rlsd ; second byte: bit0=dr bit1=oe bit2=pe bit3=fe bit4=bi bit5=thre bit6=temt bit7=fifoerr
// SETEVENTCHAR:out 6 (endis:1<<8 | char)
// SETERRORCHAR:out 7 (endir:1<<8 | char)
// <there is no bReqest 8>
// SETLATENCY: out 9 latency(1..255)
// GETLATENCY: in 0xa 0 index &latency len=1
// SETBITBANG: out 0xb dirmask:8<<8 | mode:8 // mode: MPSSE mode: 0=serial/fifo, 1=bitbang, 2=mpsse, 4=syncbb, (8=mcu 16=opto)
// READPINS: in 0xc 0 index &pins len=1
// READEEPROM: in 0x90 0 eepaddr &val 2 // eepaddr in 16-bit units(?)
// WRITEEEPROM: out 0x91 value eepaddr
// ERASEEEPROM: out 0x92 0 0
// eeprom layout:
// max size is 128 words (256 bytes), little-endian
// 00: type, driver, .. stuff (chanA byte, chanB byte)
// 01: VID
// 02: PID
// 03: bcdDevice
// 04: byte08: flags: bit7=1 bit6=1=selfpowered bit5=1=remotewakeup ; byte09=max power, 2mA units
// 05: bit0=epin isochr, bit1=epout isochr, bit2=suspend pulldn, bit3=serialno use, bit4=usbver change, bit5..7=0
// 06: USB version
// 07: byte0E=manufstr.off-0x80, byte0F=manufstr.len (in bytes, but 16-bit ascii)
// 08: ^ but product
// 09: ^ but serial
// 0a: chip type (66 etc)
// TODO: checksum
// ftdi_write_data(), ftdi_read_data(): bulk xfer
// input/tristate: 200K pullup
// SI/WU: let's ignore this
// UART mode: standard stuff
// FIFO mode: RDF#=0: enable output. RD# rising when RXF#=0: fetch next byte
// TXF#=0: enable input. WR falling when TXF#=0: write byte
// bitbang mode: ^ similar, no RDF#/TXF#, RD#/WR# (now WR# jenai WR) pos depends on UART mode std (UART vs FIFO)
// sync bitbang: doesn't use RD#/WR#, clocked by baudrate control
// MPSSE: lots of magic. TCK/SK, TDI/DO, TDO/DI, TMS/CS, GPIOL0..3, GPIOH0..3(7?)
// bulk xfer formats:
// * UART: ok I guess
// * FIFO: same
// * bitbang, sync bitbang: ???? (just data or also clock stuff?? ?)
// * MPSSE: see separate PDF
switch (stage) {
case CONTROL_STAGE_SETUP:
// tud_control_status(rhport, req); : acknowledge
// tud_control_xfer(rhport, req, bufaddr, size); : ack + there's a data phase with stuff to do
// write: send bufaddr value. read: data stage will have bufaddr filled out
return false; // stall if not recognised
case CONTROL_STAGE_DATA:
// TODO: stuff?
// 'bufaddr' from setup stage is now filled in for reads
return true;
default: return true; // ignore
}
}

18
src/m_ftdi/ftdi.h Normal file
View File

@ -0,0 +1,18 @@
// vim: set et:
#ifndef FTDI_H_
#define FTDI_H_
#include "tusb_config.h"
#include <tusb.h>
// for handling USB bulk commands
void ftdi_init(void);
void ftdi_deinit(void);
void ftdi_task(void);
bool ftdi_control_xfer_cb(uint8_t rhport, uint8_t ep_addr,
tusb_control_request_t const* req);
#endif

View File

@ -39,7 +39,7 @@ struct mode {
void (*tud_cdc_line_coding_cb)(uint8_t itf, cdc_line_coding_t const* line_coding);
#endif
//#if CFG_TUD_VENDOR > 0
bool (*tud_vendor_control_xfer_cb)(uint8_t rhport, uint8_t ep_addr,
bool (*tud_vendor_control_xfer_cb)(uint8_t rhport, uint8_t stage,
tusb_control_request_t const* req);
//#endif