diff --git a/cdcftdi.cpp b/cdcftdi.cpp index 3a743669..c3b3f2c2 100644 --- a/cdcftdi.cpp +++ b/cdcftdi.cpp @@ -32,7 +32,7 @@ wIdProduct(idProduct) { epInfo[i].maxPktSize = (i) ? 0 : 8; epInfo[i].bmSndToggle = 0; epInfo[i].bmRcvToggle = 0; - epInfo[i].bmNakPower = (i==epDataInIndex) ? USB_NAK_NOWAIT: USB_NAK_MAX_POWER; + epInfo[i].bmNakPower = (i == epDataInIndex) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; } if(pUsb) pUsb->RegisterDeviceClass(this); @@ -54,16 +54,16 @@ uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) { USBTRACE("FTDI Init\r\n"); if(bAddress) { - USBTRACE("FTDI CLASS IN USE??\r\n"); + USBTRACE("FTDI CLASS IN USE??\r\n"); return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; - } + } // Get pointer to pseudo device with address 0 assigned p = addrPool.GetUsbDevicePtr(0); if(!p) { - USBTRACE("FTDI NO ADDRESS??\r\n"); + USBTRACE("FTDI NO ADDRESS??\r\n"); return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; - } + } if(!p->epinfo) { USBTRACE("epinfo\r\n"); return USB_ERROR_EPINFO_IS_NULL; @@ -86,8 +86,7 @@ uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) { if(rcode) { goto FailGetDevDescr; } - if(udd->idVendor != FTDI_VID || udd->idProduct != wIdProduct) - { + if(udd->idVendor != FTDI_VID || udd->idProduct != wIdProduct) { USBTRACE("FTDI Init: Product not supported\r\n"); USBTRACE2("Expected VID:", FTDI_VID); USBTRACE2("Found VID:", udd->idVendor); @@ -108,6 +107,9 @@ uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) { // Extract Max Packet Size from the device descriptor epInfo[0].maxPktSize = udd->bMaxPacketSize0; + // Some devices set endpoint lengths to zero, which is incorrect. + // we should check them, and if zero, set them to 64. + if(epInfo[0].maxPktSize == 0) epInfo[0].maxPktSize = 64; // Assign new address to the device rcode = pUsb->setAddr(0, 0, bAddress); @@ -175,6 +177,12 @@ uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) { if(rcode) goto FailSetConfDescr; + // default latency is 16ms on-chip, reduce it to 1 + rcode = SetLatency(1); + if(rcode) + goto FailOnLatency; + + rcode = pAsync->OnInit(this); if(rcode) @@ -185,6 +193,12 @@ uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) { ready = true; return 0; +FailOnLatency: +#ifdef DEBUG_USB_HOST + USBTRACE("SetLatency: "); + goto Fail; +#endif + FailGetDevDescr: #ifdef DEBUG_USB_HOST NotifyFailGetDevDescr(); @@ -241,6 +255,9 @@ void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t prot epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; epInfo[index].bmSndToggle = 0; epInfo[index].bmRcvToggle = 0; + // Some device vendors set endpoint lengths to zero, which is incorrect. + // Check, and if zero, set to 64. + if(epInfo[index].maxPktSize == 0) epInfo[index].maxPktSize = 64; bNumEP++; @@ -313,6 +330,26 @@ uint8_t FTDI::SetBaudRate(uint32_t baud) { return rv; } +// No docs on if this is 8 or 16 bit, so play it safe, make maximum 255ms + +uint8_t FTDI::SetLatency(uint8_t l) { + uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_LATENCY_TIMER, l, 0, 0, 0, 0, NULL, NULL); + if(rv && rv != hrNAK) { + Release(); + } + return rv; +} + +// No docs on if this is 8 or 16 bit, so play it safe, make maximum 255ms + +uint8_t FTDI::GetLatency(uint8_t *l) { + uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_GET_LATENCY_TIMER, 0, 0, 0, 0, 1, (uint8_t *)l, NULL); + if(rv && rv != hrNAK) { + Release(); + } + return rv; +} + uint8_t FTDI::SetModemControl(uint16_t signal) { uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL); if(rv && rv != hrNAK) { diff --git a/cdcftdi.h b/cdcftdi.h index 4fd08fd3..8890ae7b 100644 --- a/cdcftdi.h +++ b/cdcftdi.h @@ -34,14 +34,16 @@ e-mail : support@circuitsathome.com #define FT232R 0x0600 // Commands -#define FTDI_SIO_RESET 0 /* Reset the port */ -#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ -#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ -#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ -#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */ -#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */ -#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ -#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ +#define FTDI_SIO_RESET 0 /* Reset the port */ +#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ +#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ +#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ +#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */ +#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */ +#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ +#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ +#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ +#define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */ #define FTDI_SIO_RESET_SIO 0 #define FTDI_SIO_RESET_PURGE_RX 1 @@ -64,7 +66,7 @@ e-mail : support@circuitsathome.com #define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 )) #define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 )) -#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 + #define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 #define FTDI_SIO_RTS_CTS_HS (0x1 << 8) #define FTDI_SIO_DTR_DSR_HS (0x2 << 8) #define FTDI_SIO_XON_XOFF_HS (0x4 << 8) @@ -121,8 +123,10 @@ public: uint8_t SetModemControl(uint16_t control); uint8_t SetFlowControl(uint8_t protocol, uint8_t xon = 0x11, uint8_t xoff = 0x13); uint8_t SetData(uint16_t databm); + uint8_t SetLatency(uint8_t l); + uint8_t GetLatency(uint8_t *l); - // Methods for recieving and sending data + // Methods for receiving and sending data uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr); uint8_t SndData(uint16_t nbytes, uint8_t *dataptr); @@ -139,7 +143,7 @@ public: void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep); virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) { - return (vid == FTDI_VID && pid == wIdProduct); + return (vid == FTDI_VID && pid == FTDI_PID); } virtual bool isReady() { return ready;