Browse Source

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.
main
Kurt Eckhardt 7 years ago
parent
commit
704d511c81
5 changed files with 255 additions and 48 deletions
  1. +3
    -0
      USBHost_t36.h
  2. +4
    -0
      ehci.cpp
  3. +13
    -8
      examples/SerialTest/SerialTest.ino
  4. +4
    -0
      keyboard.cpp
  5. +231
    -40
      serial.cpp

+ 3
- 0
USBHost_t36.h View File

volatile uint8_t rxstate;// bitmask: which receive packets are queued volatile uint8_t rxstate;// bitmask: which receive packets are queued
volatile uint8_t txstate; volatile uint8_t txstate;
uint8_t pending_control; 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; uint8_t interface;
bool control_queued; bool control_queued;
enum { CDCACM, FTDI, PL2303, CH341 } sertype; enum { CDCACM, FTDI, PL2303, CH341 } sertype;

+ 4
- 0
ehci.cpp View File

// slowest rate we can poll interrupt endpoints. Each entry uses // slowest rate we can poll interrupt endpoints. Each entry uses
// 12 bytes (4 for a pointer, 8 for bandwidth management). // 12 bytes (4 for a pointer, 8 for bandwidth management).
// Supported values: 8, 16, 32, 64, 128, 256, 512, 1024 // 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 #define PERIODIC_LIST_SIZE 32
#endif


// The EHCI periodic schedule, used for interrupt pipes/endpoints // The EHCI periodic schedule, used for interrupt pipes/endpoints
static uint32_t periodictable[PERIODIC_LIST_SIZE] __attribute__ ((aligned(4096), used)); static uint32_t periodictable[PERIODIC_LIST_SIZE] __attribute__ ((aligned(4096), used));

+ 13
- 8
examples/SerialTest/SerialTest.ino View File

// This example is in the public domain // This example is in the public domain


#include "USBHost_t36.h" #include "USBHost_t36.h"
#define USBBAUD 115200
USBHost myusb; USBHost myusb;
USBHub hub1(myusb); USBHub hub1(myusb);
USBHub hub2(myusb); USBHub hub2(myusb);
// If this is a new Serial device. // If this is a new Serial device.
if (drivers[i] == &userial) { if (drivers[i] == &userial) {
// Lets try first outputting something to our USerial to see if it will go out... // 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 #if 0
userial.println("abcdefghijklmnopqrstuvwxyz"); userial.println("abcdefghijklmnopqrstuvwxyz");
userial.println("ABCDEFGHIJKLMNOPQURSTUVWYZ"); userial.println("ABCDEFGHIJKLMNOPQURSTUVWYZ");
} }
} }


while (Serial.available()) {
if (Serial.available()) {
Serial.println("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()) { while (Serial1.available()) {

+ 4
- 0
keyboard.cpp View File

if (size != 8) { if (size != 8) {
return false; // must be 8 bytes for Keyboard Boot Protocol 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]; uint32_t interval = descriptors[24];
#endif
println("polling interval = ", interval); println("polling interval = ", interval);
datapipe = new_Pipe(dev, 3, endpoint, 1, 8, interval); datapipe = new_Pipe(dev, 3, endpoint, 1, 8, interval);
datapipe->callback_function = callback; datapipe->callback_function = callback;

+ 231
- 40
serial.cpp View File

pending_control = 0x0; // Maybe don't need to do... pending_control = 0x0; // Maybe don't need to do...
return true; 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) { if (dev->idVendor == 0x67B && dev->idProduct == 0x2303) {
// Prolific Technology, Inc. PL2303 Serial Port // Prolific Technology, Inc. PL2303 Serial Port
println("len = ", len); println("len = ", len);
//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 //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 rxep = 0;
uint32_t txep = 0; uint32_t txep = 0;
uint16_t descriptor_index = 9;
uint32_t descriptor_index = 9;
while (count_end_points-- && ((rxep == 0) || txep == 0)) { while (count_end_points-- && ((rxep == 0) || txep == 0)) {
if (descriptors[descriptor_index] != 7) return false; // length 7 if (descriptors[descriptor_index] != 7) return false; // length 7
if (descriptors[descriptor_index+1] != 5) return false; // ep desc if (descriptors[descriptor_index+1] != 5) return false; // ep desc
} else { } else {
txep = descriptors[descriptor_index+2]; txep = descriptors[descriptor_index+2];
} }
}
}
descriptor_index += 7; // setup to look at next one... descriptor_index += 7; // setup to look at next one...
} }
// Try to verify the end points. // Try to verify the end points.
// TODO: free rxpipe // TODO: free rxpipe
return false; return false;
} }

sertype = PL2303; sertype = PL2303;
rxpipe->callback_function = rx_callback; rxpipe->callback_function = rx_callback;
queue_Data_Transfer(rxpipe, rx1, 64, this); queue_Data_Transfer(rxpipe, rx1, 64, this);
txstate = 0; txstate = 0;
txpipe->callback_function = tx_callback; txpipe->callback_function = tx_callback;
baudrate = 115200; 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; control_queued = true;
setup_state = 1; // We are at step one of setup...
pending_control = 0x3f; // Maybe don't need to do...
return true; return true;
} }
#endif #endif
println("control callback (serial) ", pending_control, HEX); println("control callback (serial) ", pending_control, HEX);
control_queued = false; 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; uint32_t baudval = 3000000 / baudrate;
mk_setup(setup, 0x40, 3, baudval, 0, 0); mk_setup(setup, 0x40, 3, baudval, 0, 0);
queue_Control_Transfer(device, &setup, NULL, this); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; 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... // Should probably use data structure, but that may depend on byte ordering...
setupdata[0] = (baudrate) & 0xff; // Setup baud rate 115200 - 0x1C200 setupdata[0] = (baudrate) & 0xff; // Setup baud rate 115200 - 0x1C200
setupdata[1] = (baudrate >> 8) & 0xff; setupdata[1] = (baudrate >> 8) & 0xff;
mk_setup(setup, 0x21, 0x20, 0, 0, 7); mk_setup(setup, 0x21, 0x20, 0, 0, 7);
queue_Control_Transfer(device, &setup, setupdata, this); queue_Control_Transfer(device, &setup, setupdata, this);
control_queued = true; 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 // 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); queue_Control_Transfer(device, &setup, NULL, this);
control_queued = true; control_queued = true;
return; 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;
}
} }
} }


((USBSerial *)(transfer->driver))->tx_data(transfer); ((USBSerial *)(transfer->driver))->tx_data(transfer);
} }



void USBSerial::rx_data(const Transfer_t *transfer) void USBSerial::rx_data(const Transfer_t *transfer)
{ {
uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF); uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF);
uint32_t count; uint32_t count;
uint32_t head = txhead; uint32_t head = txhead;
uint32_t tail = txtail; 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) { if (head == tail) {
println(" *** Empty ***"); println(" *** Empty ***");
return; // nothing to transmit return; // nothing to transmit

Loading…
Cancel
Save