mirror of
https://github.com/gdsports/USBHost_t36
synced 2024-11-21 08:35:03 -05:00
PL2303 support
This commit should start to allow some Prolific PL2303 devices to work. Tis device has a rather more complex initialization process than some of the other devices. I have tested this some with one device that I used to use to program some older RS232 based boards plus talk to an SSC-32 device. Test case is I am able to talk to SSC-32 and if I type in ver<cr> It does properly return the version number. The data I am seeing is pretty close to what was documented in: https://gist.github.com/tommie/89011c5ac06553d5cdb8 as well as what the Linux driver outputs. I also incorperated Frank's configuration options.
This commit is contained in:
parent
6e1f0c379c
commit
704d511c81
@ -942,6 +942,9 @@ private:
|
||||
volatile uint8_t rxstate;// bitmask: which receive packets are queued
|
||||
volatile uint8_t txstate;
|
||||
uint8_t pending_control;
|
||||
uint8_t setup_state; // PL2303 - has several steps... Could use pending control?
|
||||
uint8_t pl2303_v1; // Which version do we have
|
||||
uint8_t pl2303_v2;
|
||||
uint8_t interface;
|
||||
bool control_queued;
|
||||
enum { CDCACM, FTDI, PL2303, CH341 } sertype;
|
||||
|
4
ehci.cpp
4
ehci.cpp
@ -54,7 +54,11 @@
|
||||
// slowest rate we can poll interrupt endpoints. Each entry uses
|
||||
// 12 bytes (4 for a pointer, 8 for bandwidth management).
|
||||
// Supported values: 8, 16, 32, 64, 128, 256, 512, 1024
|
||||
#if defined(USBHS_PERIODIC_LIST_SIZE)
|
||||
#define PERIODIC_LIST_SIZE (USBHS_PERIODIC_LIST_SIZE)
|
||||
#else
|
||||
#define PERIODIC_LIST_SIZE 32
|
||||
#endif
|
||||
|
||||
// The EHCI periodic schedule, used for interrupt pipes/endpoints
|
||||
static uint32_t periodictable[PERIODIC_LIST_SIZE] __attribute__ ((aligned(4096), used));
|
||||
|
@ -3,7 +3,7 @@
|
||||
// This example is in the public domain
|
||||
|
||||
#include "USBHost_t36.h"
|
||||
|
||||
#define USBBAUD 115200
|
||||
USBHost myusb;
|
||||
USBHub hub1(myusb);
|
||||
USBHub hub2(myusb);
|
||||
@ -60,7 +60,10 @@ void loop()
|
||||
// If this is a new Serial device.
|
||||
if (drivers[i] == &userial) {
|
||||
// Lets try first outputting something to our USerial to see if it will go out...
|
||||
userial.begin(1000000);
|
||||
userial.begin(USBBAUD);
|
||||
|
||||
// delay(5);
|
||||
// userial.println("ver");
|
||||
#if 0
|
||||
userial.println("abcdefghijklmnopqrstuvwxyz");
|
||||
userial.println("ABCDEFGHIJKLMNOPQURSTUVWYZ");
|
||||
@ -79,14 +82,16 @@ void loop()
|
||||
}
|
||||
}
|
||||
|
||||
while (Serial.available()) {
|
||||
if (Serial.available()) {
|
||||
Serial.println("Serial Available");
|
||||
int ch = Serial.read();
|
||||
if (ch == '$') {
|
||||
BioloidTest();
|
||||
while (Serial.read() != -1);
|
||||
while (Serial.available()) {
|
||||
int ch = Serial.read();
|
||||
if (ch == '$') {
|
||||
BioloidTest();
|
||||
while (Serial.read() != -1);
|
||||
}
|
||||
else userial.write(ch);
|
||||
}
|
||||
else userial.write(ch);
|
||||
}
|
||||
|
||||
while (Serial1.available()) {
|
||||
|
@ -128,7 +128,11 @@ bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descripto
|
||||
if (size != 8) {
|
||||
return false; // must be 8 bytes for Keyboard Boot Protocol
|
||||
}
|
||||
#ifdef USBHS_KEYBOARD_INTERVAL
|
||||
uint32_t interval = USBHS_KEYBOARD_INTERVAL;
|
||||
#else
|
||||
uint32_t interval = descriptors[24];
|
||||
#endif
|
||||
println("polling interval = ", interval);
|
||||
datapipe = new_Pipe(dev, 3, endpoint, 1, 8, interval);
|
||||
datapipe->callback_function = callback;
|
||||
|
271
serial.cpp
271
serial.cpp
@ -225,7 +225,8 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
|
||||
pending_control = 0x0; // Maybe don't need to do...
|
||||
return true;
|
||||
}
|
||||
#if 0
|
||||
#if 1
|
||||
// BUGBUG: Note: there are probably more vendor/product pairs.. Maybe should create table of them
|
||||
if (dev->idVendor == 0x67B && dev->idProduct == 0x2303) {
|
||||
// Prolific Technology, Inc. PL2303 Serial Port
|
||||
println("len = ", len);
|
||||
@ -241,7 +242,7 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
|
||||
//09 04 00 00 03 FF 00 00 00 07 05 81 03 0A 00 01 07 05 02 02 40 00 00 07 05 83 02 40 00 00
|
||||
uint32_t rxep = 0;
|
||||
uint32_t txep = 0;
|
||||
uint16_t descriptor_index = 9;
|
||||
uint32_t descriptor_index = 9;
|
||||
while (count_end_points-- && ((rxep == 0) || txep == 0)) {
|
||||
if (descriptors[descriptor_index] != 7) return false; // length 7
|
||||
if (descriptors[descriptor_index+1] != 5) return false; // ep desc
|
||||
@ -254,7 +255,7 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
|
||||
} else {
|
||||
txep = descriptors[descriptor_index+2];
|
||||
}
|
||||
}
|
||||
}
|
||||
descriptor_index += 7; // setup to look at next one...
|
||||
}
|
||||
// Try to verify the end points.
|
||||
@ -269,6 +270,7 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
|
||||
// TODO: free rxpipe
|
||||
return false;
|
||||
}
|
||||
|
||||
sertype = PL2303;
|
||||
rxpipe->callback_function = rx_callback;
|
||||
queue_Data_Transfer(rxpipe, rx1, 64, this);
|
||||
@ -280,10 +282,15 @@ bool USBSerial::claim(Device_t *dev, int type, const uint8_t *descriptors, uint3
|
||||
txstate = 0;
|
||||
txpipe->callback_function = tx_callback;
|
||||
baudrate = 115200;
|
||||
pending_control = 0x0F;
|
||||
mk_setup(setup, 0x40, 0, 0, 0, 0); // reset port
|
||||
queue_Control_Transfer(dev, &setup, NULL, this);
|
||||
|
||||
// Lets see if it will handle the same CDCACM - messages?
|
||||
println("PL2303: readRegister(0x04)");
|
||||
// Need to setup the data the line coding data
|
||||
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
|
||||
queue_Control_Transfer(dev, &setup, setupdata, this);
|
||||
control_queued = true;
|
||||
setup_state = 1; // We are at step one of setup...
|
||||
pending_control = 0x3f; // Maybe don't need to do...
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@ -417,24 +424,52 @@ void USBSerial::control(const Transfer_t *transfer)
|
||||
println("control callback (serial) ", pending_control, HEX);
|
||||
control_queued = false;
|
||||
|
||||
// set data format
|
||||
if (pending_control & 1) {
|
||||
pending_control &= ~1;
|
||||
mk_setup(setup, 0x40, 4, 8, 0, 0); // data format 8N1
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
}
|
||||
// set baud rate
|
||||
if (pending_control & 2) {
|
||||
pending_control &= ~2;
|
||||
if (sertype == FTDI) {
|
||||
// We will split this up by Serial type, maybe different functions?
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// First FTDI
|
||||
if (sertype == FTDI) {
|
||||
if (pending_control & 1) {
|
||||
pending_control &= ~1;
|
||||
// set data format
|
||||
mk_setup(setup, 0x40, 4, 8, 0, 0); // data format 8N1
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
}
|
||||
// set baud rate
|
||||
if (pending_control & 2) {
|
||||
pending_control &= ~2;
|
||||
uint32_t baudval = 3000000 / baudrate;
|
||||
mk_setup(setup, 0x40, 3, baudval, 0, 0);
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
}
|
||||
// configure flow control
|
||||
if (pending_control & 4) {
|
||||
pending_control &= ~4;
|
||||
mk_setup(setup, 0x40, 2, 0, 1, 0);
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
}
|
||||
// set DTR
|
||||
if (pending_control & 8) {
|
||||
pending_control &= ~8;
|
||||
mk_setup(setup, 0x40, 1, 0x0101, 0, 0);
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (sertype == CDCACM) {
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Now CDCACM
|
||||
if (sertype == CDCACM) {
|
||||
if (pending_control & 2) {
|
||||
pending_control &= ~2;
|
||||
// Should probably use data structure, but that may depend on byte ordering...
|
||||
setupdata[0] = (baudrate) & 0xff; // Setup baud rate 115200 - 0x1C200
|
||||
setupdata[1] = (baudrate >> 8) & 0xff;
|
||||
@ -448,34 +483,183 @@ void USBSerial::control(const Transfer_t *transfer)
|
||||
mk_setup(setup, 0x21, 0x20, 0, 0, 7);
|
||||
queue_Control_Transfer(device, &setup, setupdata, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// configure flow control
|
||||
if (pending_control & 4) {
|
||||
pending_control &= ~4;
|
||||
if (sertype == FTDI) {
|
||||
mk_setup(setup, 0x40, 2, 0, 1, 0);
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
} else if (sertype == CDCACM) {
|
||||
println("Control - CDCACM DTR...");
|
||||
// configure flow control
|
||||
if (pending_control & 4) {
|
||||
pending_control &= ~4;
|
||||
println("Control - 0x21,0x22, 0x3");
|
||||
// Need to setup the data the line coding data
|
||||
mk_setup(setup, 0x21, 0x22, 1, interface, 0);
|
||||
mk_setup(setup, 0x21, 0x22, 3, 0, 0);
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
// set DTR
|
||||
if (pending_control & 8) {
|
||||
pending_control &= ~8;
|
||||
mk_setup(setup, 0x40, 1, 0x0101, 0, 0);
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Now PL2303 - Which appears to be a little more complicated
|
||||
if (sertype == PL2303) {
|
||||
if (pending_control & 1) {
|
||||
// Still in larger setup state mode
|
||||
switch (setup_state) {
|
||||
case 1:
|
||||
println("PL2303: writeRegister(0x04, 0x00)");
|
||||
mk_setup(setup, 0x40, 1, 0x0404, 0, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
setup_state = 2;
|
||||
control_queued = true;
|
||||
return;
|
||||
case 2:
|
||||
println("PL2303: readRegister(0x04)");
|
||||
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
|
||||
queue_Control_Transfer(device, &setup, setupdata, this);
|
||||
control_queued = true;
|
||||
setup_state = 3;
|
||||
return;
|
||||
case 3:
|
||||
println("PL2303: v1 = readRegister(0x03)");
|
||||
mk_setup(setup, 0xC0, 0x1, 0x8383, 0, 1);
|
||||
queue_Control_Transfer(device, &setup, setupdata, this);
|
||||
control_queued = true;
|
||||
setup_state = 4;
|
||||
return;
|
||||
case 4:
|
||||
println("PL2303: readRegister(0x04)");
|
||||
// Do we need this value long term or we could just leave in setup data?
|
||||
pl2303_v1 = setupdata[0]; // save the first bye of version
|
||||
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
|
||||
queue_Control_Transfer(device, &setup, setupdata, this);
|
||||
control_queued = true;
|
||||
setup_state = 5;
|
||||
return;
|
||||
case 5:
|
||||
println("PL2303: writeRegister(0x04, 0x01)");
|
||||
mk_setup(setup, 0x40, 1, 0x0404, 1, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
setup_state = 6;
|
||||
control_queued = true;
|
||||
return;
|
||||
case 6:
|
||||
println("PL2303: readRegister(0x04)");
|
||||
mk_setup(setup, 0xC0, 0x1, 0x8484, 0, 1);
|
||||
queue_Control_Transfer(device, &setup, setupdata, this);
|
||||
control_queued = true;
|
||||
setup_state = 7;
|
||||
return;
|
||||
case 7:
|
||||
println("PL2303: v2 = readRegister(0x03)");
|
||||
mk_setup(setup, 0xC0, 0x1, 0x8383, 0, 1);
|
||||
queue_Control_Transfer(device, &setup, setupdata, this);
|
||||
control_queued = true;
|
||||
setup_state = 8;
|
||||
return;
|
||||
case 8:
|
||||
pl2303_v2 = setupdata[0]; // save the first bye of version
|
||||
print(" PL2303 Version ", pl2303_v1, HEX);
|
||||
println(":", pl2303_v2, HEX);
|
||||
println("PL2303: writeRegister(0, 1)");
|
||||
mk_setup(setup, 0x40, 1, 0, 1, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
setup_state = 9;
|
||||
control_queued = true;
|
||||
return;
|
||||
case 9:
|
||||
println("PL2303: writeRegister(1, 0)");
|
||||
mk_setup(setup, 0x40, 1, 1, 0, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
setup_state = 10;
|
||||
control_queued = true;
|
||||
return;
|
||||
case 10:
|
||||
println("PL2303: writeRegister(2, 44)");
|
||||
mk_setup(setup, 0x40, 1, 2, 0x44, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
setup_state = 11;
|
||||
control_queued = true;
|
||||
return;
|
||||
case 11:
|
||||
println("PL2303: writeRegister(8, 0)");
|
||||
mk_setup(setup, 0x40, 1, 8, 0, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
setup_state = 12;
|
||||
control_queued = true;
|
||||
return;
|
||||
case 12:
|
||||
println("PL2303: writeRegister(9, 0)");
|
||||
mk_setup(setup, 0x40, 1, 9, 0, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
setup_state = 13;
|
||||
control_queued = true;
|
||||
return;
|
||||
case 13:
|
||||
println("PL2303: Read current Baud/control");
|
||||
mk_setup(setup, 0xA1, 0x21, 0, 0, 7);
|
||||
queue_Control_Transfer(device, &setup, setupdata, this);
|
||||
control_queued = true;
|
||||
break;
|
||||
}
|
||||
pending_control &= ~1; // We are finally going to leave this list and join the rest
|
||||
if (control_queued) return;
|
||||
}
|
||||
|
||||
// set baud rate
|
||||
if (pending_control & 2) {
|
||||
pending_control &= ~2;
|
||||
// See what the read returned earlier
|
||||
print("PL2303: Returned configuration data: ");
|
||||
print_hexbytes(setupdata, 7);
|
||||
|
||||
// Should probably use data structure, but that may depend on byte ordering...
|
||||
setupdata[0] = (baudrate) & 0xff; // Setup baud rate 115200 - 0x1C200
|
||||
setupdata[1] = (baudrate >> 8) & 0xff;
|
||||
setupdata[2] = (baudrate >> 16) & 0xff;
|
||||
setupdata[3] = (baudrate >> 24) & 0xff;
|
||||
setupdata[4] = 0; // 0 - 1 stop bit, 1 - 1.5 stop bits, 2 - 2 stop bits
|
||||
setupdata[5] = 0; // 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space
|
||||
setupdata[6] = 8; // Data bits (5, 6, 7, 8 or 16)
|
||||
print("PL2303: Set baud/control: ", baudrate, HEX);
|
||||
print(" = ");
|
||||
print_hexbytes(&setupdata, 7);
|
||||
mk_setup(setup, 0x21, 0x20, 0, 0, 7);
|
||||
queue_Control_Transfer(device, &setup, setupdata, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
}
|
||||
if (pending_control & 4) {
|
||||
pending_control &= ~4;
|
||||
println("PL2303: writeRegister(0, 0)");
|
||||
mk_setup(setup, 0x40, 1, 0, 0, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
}
|
||||
if (pending_control & 8) {
|
||||
pending_control &= ~8;
|
||||
println("PL2303: Read current Baud/control");
|
||||
memset(setupdata, 0, sizeof(setupdata)); // clear it to see if we read it...
|
||||
mk_setup(setup, 0xA1, 0x21, 0, 0, 7);
|
||||
queue_Control_Transfer(device, &setup, setupdata, this);
|
||||
control_queued = true;
|
||||
}
|
||||
if (pending_control & 0x10) {
|
||||
pending_control &= ~0x10;
|
||||
print("PL2303: Returned configuration data: ");
|
||||
print_hexbytes(setupdata, 7);
|
||||
|
||||
println("PL2303: 0x21, 0x22, 0x3");
|
||||
mk_setup(setup, 0x21, 0x22, 3, 0, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
return;
|
||||
}
|
||||
if (pending_control & 0x30) {
|
||||
pending_control &= ~0x30;
|
||||
println("PL2303: 0x21, 0x22, 0x3");
|
||||
mk_setup(setup, 0x21, 0x22, 3, 0, 0); //
|
||||
queue_Control_Transfer(device, &setup, NULL, this);
|
||||
control_queued = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -496,6 +680,7 @@ void USBSerial::tx_callback(const Transfer_t *transfer)
|
||||
((USBSerial *)(transfer->driver))->tx_data(transfer);
|
||||
}
|
||||
|
||||
|
||||
void USBSerial::rx_data(const Transfer_t *transfer)
|
||||
{
|
||||
uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF);
|
||||
@ -634,6 +819,12 @@ void USBSerial::timer_event(USBDriverTimer *whichTimer)
|
||||
uint32_t count;
|
||||
uint32_t head = txhead;
|
||||
uint32_t tail = txtail;
|
||||
if (pending_control) {
|
||||
// We are still doing setup postpone for awhile..
|
||||
txtimer.start(1200);
|
||||
println(" Postpone: setup pending_control");
|
||||
return; // no outgoing buffers available, try again later
|
||||
}
|
||||
if (head == tail) {
|
||||
println(" *** Empty ***");
|
||||
return; // nothing to transmit
|
||||
|
Loading…
Reference in New Issue
Block a user