mpsse, mcuhost usb protocol decoding

This commit is contained in:
Triss 2021-08-29 03:01:33 +02:00
parent c5a4a6b3e5
commit 210f74dbc5
2 changed files with 158 additions and 5 deletions

View File

@ -156,6 +156,7 @@ static void ftdi_task(int itfnum) {
enum ftdi_mode mode = ftdi_if_get_mode(itf);
struct ftfifo_fns fifocb = fifocbs[(mode == 0) ? 0 : __builtin_ctz(mode)];
uint32_t avail;
uint8_t cmdbyte;
switch (mode) {
case ftmode_uart : case ftmode_fifo : case ftmode_cpufifo:
case ftmode_asyncbb: case ftmode_syncbb:
@ -173,8 +174,159 @@ static void ftdi_task(int itfnum) {
if (avail) tud_vendor_n_write(itfnum, itf->readbuf, avail);
} while (avail == sizeof itf->readbuf);
break;
case ftmode_mpsse: break; // BIG TODO
case ftmode_mcuhost: break; // BIG TODO
case ftmode_mpsse:
avail = 0;
switch ((cmdbyte = vnd_read_byte(itf, itfnum))) {
case ftmpsse_set_dirval_lo: // low byte of output gpio, not to low level
itf->writebuf[0] = vnd_read_byte(itf, itfnum); // val
itf->writebuf[1] = vnd_read_byte(itf, itfnum); // dir
ftdi_if_mpsse_set_dirval_lo(itf, itf->writebuf[1], itf->writebuf[0]);
break;
case ftmpsse_set_dirval_hi:
itf->writebuf[0] = vnd_read_byte(itf, itfnum); // val
itf->writebuf[1] = vnd_read_byte(itf, itfnum); // dir
ftdi_if_mpsse_set_dirval_hi(itf, itf->writebuf[1], itf->writebuf[0]);
break;
case ftmpsse_read_lo:
itf->readbuf[0] = ftdi_if_mpsse_read_lo(itf);
avail = 1;
break;
case ftmpsse_read_hi:
itf->readbuf[0] = ftdi_if_mpsse_read_hi(itf);
avail = 1;
break;
case ftmpsse_loopback_on : ftdi_if_mpsse_loopback(itf, true ); break;
case ftmpsse_loopback_off: ftdi_if_mpsse_loopback(itf, false); break;
case ftmpsse_set_clkdiv:
avail = vnd_read_byte(itf, itfnum);
avail |= (uint32_t)vnd_read_byte(itf, itfnum) << 8;
ftdi_if_mpsse_set_clkdiv(itf, (uint16_t)avail);
avail = 0;
break;
case ftmpsse_flush: ftdi_if_mpsse_flush(itf); break;
case ftmpsse_wait_io_hi: ftdi_if_mpsse_wait_io(itf, true ); break;
case ftmpsse_wait_io_lo: ftdi_if_mpsse_wait_io(itf, false); break;
case ftmpsse_div5_disable: ftdi_if_mpsse_div5(itf, false); break;
case ftmpsse_div5_enable : ftdi_if_mpsse_div5(itf, true ); break;
case ftmpsse_data_3ph_en : ftdi_if_mpsse_data_3ph(itf, true ); break;
case ftmpsse_data_3ph_dis: ftdi_if_mpsse_data_3ph(itf, false); break;
case ftmpsse_clockonly_bits: ftdi_if_mpsse_clockonly(itf, vnd_read_byte(itf, itfnum)); break;
case ftmpsse_clockonly_bytes:
avail = vnd_read_byte(itf, itfnum);
avail |= (uint32_t)vnd_read_byte(itf, itfnum) << 8;
ftdi_if_mpsse_clockonly(itf, avail);
avail = 0;
break;
case ftmpsse_clock_wait_io_hi: ftdi_if_mpsse_clock_wait_io(itf, true ); break;
case ftmpsse_clock_wait_io_lo: ftdi_if_mpsse_clock_wait_io(itf, false); break;
case ftmpsse_clock_adapclk_enable : ftdi_if_mpsse_adaptive(itf, true ); break;
case ftmpsse_clock_adapclk_disable: ftdi_if_mpsse_adaptive(itf, false); break;
case ftmpsse_clock_bits_wait_io_hi:
avail = vnd_read_byte(itf, itfnum);
avail |= (uint32_t)vnd_read_byte(itf, itfnum) << 8;
ftdi_if_mpsse_clockonly_wait_io(itf, true, avail);
avail = 0;
break;
case ftmpsse_clock_bits_wait_io_lo:
avail = vnd_read_byte(itf, itfnum);
avail |= (uint32_t)vnd_read_byte(itf, itfnum) << 8;
ftdi_if_mpsse_clockonly_wait_io(itf, false, avail);
avail = 0;
break;
case ftmpsse_hi_is_tristate:
avail = vnd_read_byte(itf, itfnum);
avail |= (uint32_t)vnd_read_byte(itf, itfnum) << 8;
ftdi_if_mpsse_hi_is_tristate(itf, avail);
avail = 0;
break;
default:
if (!(cmdbyte & ftmpsse_specialcmd)) {
if (cmdbyte & ftmpsse_tmswrite) {
if (cmdbyte & ftmpsse_bitmode) {
itf->writebuf[0] = vnd_read_byte(itf, itfnum); // number of bits
itf->writebuf[1] = vnd_read_byte(itf, itfnum); // data bits to output
itf->readbuf[0] = ftdi_if_mpsse_tms_xfer(itf, cmdbyte, itf->writebuf[0], itf->writebuf[1]);
if (cmdbyte & tdoread) avail = 1;
break;
}
// else: fallthru to error code
} else {
if (cmdbyte & bitmode) {
itf->writebuf[0] = vnd_read_byte(itf, itfnum); // number of bits
if (cmdbyte & ftmpsse_tdiwrite)
itf->writebuf[1] = vnd_read_byte(itf, itfnum); // data bits to output
itf->readbuf[0] = ftdi_if_mpsse_xfer_bits(itf, cmdbyte, itf->writebuf[0], itf->writebuf[1]);
if (cmdbyte & tdoread) avail = 1;
break;
} else {
avail = vnd_read_byte(itf, itfnum);
avail |= (uint32_t)vnd_read_byte(itf, itfnum) << 8;
for (size_t i = 0; i < avail; i += 64) {
uint32_t thisbatch = avail - i;
if (thisbatch > 64) thisbatch = 64;
for (size_t j = 0; j < thisbatch; ++j)
itf->writebuf[j] = vnd_read_byte(itf, itfnum);
ftdi_if_mpsse_xfer_bytes(itf, cmdbyte, thisbatch, itf->readbuf, itf->writebuf);
tud_vendor_n_write(itfnum, itf->readbuf, thisbatch);
}
avail = 0;
break;
}
}
}
itf->readbuf[0] = 0xfa;
itf->readbuf[1] = cmdbyte;
avail = 2;
break;
}
if (avail) tud_vendor_n_write(itfnum, itf->readbuf, avail);
break;
case ftmode_mcuhost:
avail = 0;
switch ((cmdbyte = vnd_read_byte(itf, itfnum))) {
case ftmcu_flush: ftdi_if_mcu_flush(itf); break;
case ftmcu_wait_io_hi: ftdi_if_mcu_wait_io(itf, true ); break;
case ftmcu_wait_io_lo: ftdi_if_mcu_wait_io(itf, false); break;
case ftmcu_read8:
itf->readbuf[0] = ftdi_if_mcu_read8(itf, vnd_read_byte(itf, itfnum));
avail = 1;
break;
case ftmcu_read16:
avail = (uint32_t)vnd_read_byte(itf, itfnum) << 8;
avail |= vnd_read_byte(itf, itfnum);
itf->readbuf[0] = ftdi_if_mcu_read16(itf, (uint16_t)avail);
avail = 1;
break;
case ftmcu_write8:
itf->writebuf[0] = vnd_read_byte(itf, itfnum);
itf->writebuf[1] = vnd_read_byte(itf, itfnum);
ftdi_if_mcu_write8(itf, itf->writebuf[0], itf->writebuf[1]);
break;
case ftmcu_write16:
avail = (uint32_t)vnd_read_byte(itf, itfnum) << 8;
avail |= vnd_read_byte(itf, itfnum);
itf->writebuf[0] = vnd_read_byte(itf, itfnum);
ftdi_if_mcu_write8(itf, addr, itf->writebuf[0]);
break;
default: // send error response when command doesn't exist
itf->readbuf[0] = 0xfa;
itf->readbuf[1] = cmdbyte;
avail = 2;
break;
}
if (avail) tuf_vendor_n_write(itfnum, itf->readbuf, avail);
break;
default: // drop incoming data so that the pipes don't get clogged. can't do much else
avail = tud_vendor_n_available(itfnum);
if (avail) tud_vendor_n_read(itfnum, itf->writebuf, avail);

View File

@ -154,7 +154,9 @@ enum ftdi_mpsse_cflg {
ftmpsse_lsbfirst = 1<<3, // if 0, msb first
ftmpsse_tdiwrite = 1<<4, // 1 == do perform output
ftmpsse_tdoread = 1<<5, // 1 == do perform input
ftmpsse_tmswrite = 1<<6 // 1 == do perform output?
ftmpsse_tmswrite = 1<<6, // 1 == do perform output?
ftmpsse_specialcmd = 1<<7 // see below enum if set
};
// bitmode: 1 length byte, max=7 (#bits = length+1) for separate bits
// bytemode: 2 length bytes == number of bytes that follow
@ -314,8 +316,7 @@ void ftdi_if_mpsse_set_dirval_lo(struct ftdi_interface* itf, uint8_t dir, uint8_
void ftdi_if_mpsse_set_dirval_hi(struct ftdi_interface* itf, uint8_t dir, uint8_t val);
uint8_t ftdi_if_mpsse_read_lo(struct ftdi_interface* itf);
uint8_t ftdi_if_mpsse_read_hi(struct ftdi_interface* itf);
void ftdi_if_mpsse_loopback_on(struct ftdi_interface* itf);
void ftdi_if_mpsse_loopback_off(struct ftdi_interface* itf);
void ftdi_if_mpsse_loopback(struct ftdi_interface* itf, bool enable);
void ftdi_if_mpsse_set_clkdiv(struct ftdi_interface* itf, uint16_t div);
uint8_t ftdi_if_mpsse_xfer_bits(struct ftdi_interface* itf, int flags, size_t nbits, uint8_t value);