Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: UsbHostMAX3421E_Hello
cdcftdi.cpp
00001 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. 00002 00003 This software may be distributed and modified under the terms of the GNU 00004 General Public License version 2 (GPL2) as published by the Free Software 00005 Foundation and appearing in the file GPL2.TXT included in the packaging of 00006 this file. Please note that GPL2 Section 2[b] requires that all works based 00007 on this software must also be made publicly available under the terms of 00008 the GPL2 ("Copyleft"). 00009 00010 Contact information 00011 ------------------- 00012 00013 Circuits At Home, LTD 00014 Web : http://www.circuitsathome.com 00015 e-mail : support@circuitsathome.com 00016 */ 00017 #include "cdcftdi.h" 00018 00019 const uint8_t FTDI::epDataInIndex = 1; 00020 const uint8_t FTDI::epDataOutIndex = 2; 00021 const uint8_t FTDI::epInterruptInIndex = 3; 00022 00023 FTDI::FTDI(Usb *p, FTDIAsyncOper *pasync, uint16_t idProduct) : 00024 pAsync(pasync), 00025 pUsb(p), 00026 bAddress(0), 00027 bNumEP(1), 00028 wFTDIType(0), 00029 wIdProduct(idProduct) { 00030 for(uint8_t i = 0; i < FTDI_MAX_ENDPOINTS; i++) { 00031 epInfo[i].epAddr = 0; 00032 epInfo[i].maxPktSize = (i) ? 0 : 8; 00033 epInfo[i].bmSndToggle = 0; 00034 epInfo[i].bmRcvToggle = 0; 00035 epInfo[i].bmNakPower = (i == epDataInIndex) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; 00036 } 00037 if(pUsb) 00038 pUsb->RegisterDeviceClass(this); 00039 } 00040 00041 uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) { 00042 const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); 00043 00044 uint8_t buf[constBufSize]; 00045 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); 00046 uint8_t rcode; 00047 UsbDevice *p = NULL; 00048 EpInfo *oldep_ptr = NULL; 00049 00050 uint8_t num_of_conf; // number of configurations 00051 00052 AddressPool &addrPool = pUsb->GetAddressPool(); 00053 00054 USBTRACE("FTDI Init\r\n"); 00055 00056 if(bAddress) { 00057 USBTRACE("FTDI CLASS IN USE??\r\n"); 00058 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; 00059 } 00060 // Get pointer to pseudo device with address 0 assigned 00061 p = addrPool.GetUsbDevicePtr(0); 00062 00063 if(!p) { 00064 USBTRACE("FTDI NO ADDRESS??\r\n"); 00065 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00066 } 00067 if(!p->epinfo) { 00068 USBTRACE("epinfo\r\n"); 00069 return USB_ERROR_EPINFO_IS_NULL; 00070 } 00071 00072 // Save old pointer to EP_RECORD of address 0 00073 oldep_ptr = p->epinfo; 00074 00075 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence 00076 p->epinfo = epInfo; 00077 00078 p->lowspeed = lowspeed; 00079 00080 // Get device descriptor 00081 rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), buf); 00082 00083 // Restore p->epinfo 00084 p->epinfo = oldep_ptr; 00085 00086 if(rcode) { 00087 goto FailGetDevDescr; 00088 } 00089 if(udd->idVendor != FTDI_VID || udd->idProduct != wIdProduct) { 00090 USBTRACE("FTDI Init: Product not supported\r\n"); 00091 USBTRACE2("Expected VID:", FTDI_VID); 00092 USBTRACE2("Found VID:", udd->idVendor); 00093 00094 USBTRACE2("Expected PID:", wIdProduct); 00095 USBTRACE2("Found PID:", udd->idProduct); 00096 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; 00097 } 00098 00099 // Save type of FTDI chip 00100 wFTDIType = udd->bcdDevice; 00101 00102 // Allocate new address according to device class 00103 bAddress = addrPool.AllocAddress(parent, false, port); 00104 00105 if(!bAddress) 00106 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; 00107 00108 // Extract Max Packet Size from the device descriptor 00109 epInfo[0].maxPktSize = udd->bMaxPacketSize0; 00110 // Some devices set endpoint lengths to zero, which is incorrect. 00111 // we should check them, and if zero, set them to 64. 00112 if(epInfo[0].maxPktSize == 0) epInfo[0].maxPktSize = 64; 00113 00114 // Assign new address to the device 00115 rcode = pUsb->setAddr(0, 0, bAddress); 00116 00117 if(rcode) { 00118 p->lowspeed = false; 00119 addrPool.FreeAddress(bAddress); 00120 bAddress = 0; 00121 USBTRACE2("setAddr:", rcode); 00122 return rcode; 00123 } 00124 00125 USBTRACE2("Addr:", bAddress); 00126 00127 p->lowspeed = false; 00128 00129 p = addrPool.GetUsbDevicePtr(bAddress); 00130 00131 if(!p) 00132 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00133 00134 p->lowspeed = lowspeed; 00135 00136 num_of_conf = udd->bNumConfigurations; 00137 00138 // Assign epInfo to epinfo pointer 00139 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); 00140 00141 if(rcode) 00142 goto FailSetDevTblEntry; 00143 00144 USBTRACE2("NC:", num_of_conf); 00145 00146 for(uint8_t i = 0; i < num_of_conf; i++) { 00147 ConfigDescParser < 0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this); 00148 00149 // This interferes with serial output, and should be opt-in for debugging. 00150 //HexDumper<USBReadParser, uint16_t, uint16_t> HexDump; 00151 //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); 00152 //if(rcode) 00153 // goto FailGetConfDescr; 00154 00155 rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); 00156 00157 if(rcode) 00158 goto FailGetConfDescr; 00159 00160 if(bNumEP > 1) 00161 break; 00162 } // for 00163 00164 if(bNumEP < 2) 00165 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; 00166 00167 USBTRACE2("NumEP:", bNumEP); 00168 00169 // Assign epInfo to epinfo pointer 00170 rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); 00171 00172 USBTRACE2("Conf:", bConfNum); 00173 00174 // Set Configuration Value 00175 rcode = pUsb->setConf(bAddress, 0, bConfNum); 00176 00177 if(rcode) 00178 goto FailSetConfDescr; 00179 00180 // default latency is 16ms on-chip, reduce it to 1 00181 rcode = SetLatency(1); 00182 if(rcode) 00183 goto FailOnLatency; 00184 00185 00186 rcode = pAsync->OnInit(this); 00187 00188 if(rcode) 00189 goto FailOnInit; 00190 00191 USBTRACE("FTDI configured\r\n"); 00192 00193 ready = true; 00194 return 0; 00195 00196 FailOnLatency: 00197 #ifdef DEBUG_USB_HOST 00198 USBTRACE("SetLatency: "); 00199 goto Fail; 00200 #endif 00201 00202 FailGetDevDescr: 00203 #ifdef DEBUG_USB_HOST 00204 NotifyFailGetDevDescr(); 00205 goto Fail; 00206 #endif 00207 00208 FailSetDevTblEntry: 00209 #ifdef DEBUG_USB_HOST 00210 NotifyFailSetDevTblEntry(); 00211 goto Fail; 00212 #endif 00213 00214 FailGetConfDescr: 00215 #ifdef DEBUG_USB_HOST 00216 NotifyFailGetConfDescr(); 00217 goto Fail; 00218 #endif 00219 00220 FailSetConfDescr: 00221 #ifdef DEBUG_USB_HOST 00222 NotifyFailSetConfDescr(); 00223 goto Fail; 00224 #endif 00225 00226 FailOnInit: 00227 #ifdef DEBUG_USB_HOST 00228 USBTRACE("OnInit:"); 00229 00230 Fail: 00231 NotifyFail(rcode); 00232 #endif 00233 Release(); 00234 return rcode; 00235 } 00236 00237 void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *pep) { 00238 ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf); 00239 ErrorMessage<uint8_t > (PSTR("Iface Num"), iface); 00240 ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt); 00241 00242 bConfNum = conf; 00243 00244 uint8_t index; 00245 00246 if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) 00247 index = epInterruptInIndex; 00248 else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) 00249 index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; 00250 else 00251 return; 00252 00253 // Fill in the endpoint info structure 00254 epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); 00255 epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; 00256 epInfo[index].bmSndToggle = 0; 00257 epInfo[index].bmRcvToggle = 0; 00258 // Some device vendors set endpoint lengths to zero, which is incorrect. 00259 // Check, and if zero, set to 64. 00260 if(epInfo[index].maxPktSize == 0) epInfo[index].maxPktSize = 64; 00261 00262 bNumEP++; 00263 00264 PrintEndpointDescriptor(pep); 00265 } 00266 00267 uint8_t FTDI::Release() { 00268 pUsb->GetAddressPool().FreeAddress(bAddress); 00269 00270 bAddress = 0; 00271 bNumEP = 1; 00272 qNextPollTime = 0; 00273 bPollEnable = false; 00274 ready = false; 00275 return pAsync->OnRelease(this); 00276 } 00277 00278 uint8_t FTDI::Poll() { 00279 uint8_t rcode = 0; 00280 00281 //if (!bPollEnable) 00282 // return 0; 00283 00284 //if (qNextPollTime <= (uint32_t)millis()) 00285 //{ 00286 // USB_HOST_SERIAL.println(bAddress, HEX); 00287 00288 // qNextPollTime = (uint32_t)millis() + 100; 00289 //} 00290 return rcode; 00291 } 00292 00293 uint8_t FTDI::SetBaudRate(uint32_t baud) { 00294 uint16_t baud_value, baud_index = 0; 00295 uint32_t divisor3; 00296 divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left 00297 00298 if(wFTDIType == FT232AM) { 00299 if((divisor3 & 0x7) == 7) 00300 divisor3++; // round x.7/8 up to x+1 00301 00302 baud_value = divisor3 >> 3; 00303 divisor3 &= 0x7; 00304 00305 if(divisor3 == 1) baud_value |= 0xc000; 00306 else // 0.125 00307 if(divisor3 >= 4) baud_value |= 0x4000; 00308 else // 0.5 00309 if(divisor3 != 0) baud_value |= 0x8000; // 0.25 00310 if(baud_value == 1) baud_value = 0; /* special case for maximum baud rate */ 00311 } else { 00312 static const uint8_t divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3}; 00313 static const uint8_t divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1}; 00314 00315 baud_value = divisor3 >> 3; 00316 baud_value |= divfrac [divisor3 & 0x7] << 14; 00317 baud_index = divindex[divisor3 & 0x7]; 00318 00319 /* Deal with special cases for highest baud rates. */ 00320 if(baud_value == 1) baud_value = 0; 00321 else // 1.0 00322 if(baud_value == 0x4001) baud_value = 1; // 1.5 00323 } 00324 USBTRACE2("baud_value:", baud_value); 00325 USBTRACE2("baud_index:", baud_index); 00326 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL); 00327 if(rv && rv != hrNAK) { 00328 Release(); 00329 } 00330 return rv; 00331 } 00332 00333 // No docs on if this is 8 or 16 bit, so play it safe, make maximum 255ms 00334 00335 uint8_t FTDI::SetLatency(uint8_t l) { 00336 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_LATENCY_TIMER, l, 0, 0, 0, 0, NULL, NULL); 00337 if(rv && rv != hrNAK) { 00338 Release(); 00339 } 00340 return rv; 00341 } 00342 00343 // No docs on if this is 8 or 16 bit, so play it safe, make maximum 255ms 00344 00345 uint8_t FTDI::GetLatency(uint8_t *l) { 00346 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_GET_LATENCY_TIMER, 0, 0, 0, 0, 1, (uint8_t *)l, NULL); 00347 if(rv && rv != hrNAK) { 00348 Release(); 00349 } 00350 return rv; 00351 } 00352 00353 uint8_t FTDI::SetModemControl(uint16_t signal) { 00354 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL); 00355 if(rv && rv != hrNAK) { 00356 Release(); 00357 } 00358 return rv; 00359 } 00360 00361 uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) { 00362 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL); 00363 if(rv && rv != hrNAK) { 00364 Release(); 00365 } 00366 return rv; 00367 } 00368 00369 uint8_t FTDI::SetData(uint16_t databm) { 00370 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL); 00371 if(rv && rv != hrNAK) { 00372 Release(); 00373 } 00374 return rv; 00375 } 00376 00377 uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) { 00378 uint8_t rv = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); 00379 if(rv && rv != hrNAK) { 00380 Release(); 00381 } 00382 return rv; 00383 } 00384 00385 uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) { 00386 uint8_t rv = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); 00387 if(rv && rv != hrNAK) { 00388 Release(); 00389 } 00390 return rv; 00391 } 00392 00393 void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { 00394 Notify(PSTR("Endpoint descriptor:"), 0x80); 00395 Notify(PSTR("\r\nLength:\t\t"), 0x80); 00396 D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80); 00397 Notify(PSTR("\r\nType:\t\t"), 0x80); 00398 D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80); 00399 Notify(PSTR("\r\nAddress:\t"), 0x80); 00400 D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80); 00401 Notify(PSTR("\r\nAttributes:\t"), 0x80); 00402 D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80); 00403 Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); 00404 D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80); 00405 Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); 00406 D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80); 00407 Notify(PSTR("\r\n"), 0x80); 00408 }
Generated on Tue Jul 12 2022 18:12:04 by
 1.7.2