You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

334 lines
10 KiB

  1. /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
  2. This software may be distributed and modified under the terms of the GNU
  3. General Public License version 2 (GPL2) as published by the Free Software
  4. Foundation and appearing in the file GPL2.TXT included in the packaging of
  5. this file. Please note that GPL2 Section 2[b] requires that all works based
  6. on this software must also be made publicly available under the terms of
  7. the GPL2 ("Copyleft").
  8. Contact information
  9. -------------------
  10. Circuits At Home, LTD
  11. Web : http://www.circuitsathome.com
  12. e-mail : support@circuitsathome.com
  13. */
  14. #include "cdcftdi.h"
  15. const uint8_t FTDI::epDataInIndex = 1;
  16. const uint8_t FTDI::epDataOutIndex = 2;
  17. const uint8_t FTDI::epInterruptInIndex = 3;
  18. FTDI::FTDI(USB *p, FTDIAsyncOper *pasync) :
  19. pAsync(pasync),
  20. pUsb(p),
  21. bAddress(0),
  22. bNumEP(1),
  23. wFTDIType(0) {
  24. for(uint8_t i = 0; i < FTDI_MAX_ENDPOINTS; i++) {
  25. epInfo[i].epAddr = 0;
  26. epInfo[i].maxPktSize = (i) ? 0 : 8;
  27. epInfo[i].epAttribs = 0;
  28. epInfo[i].bmNakPower = (i==epDataInIndex) ? USB_NAK_NOWAIT: USB_NAK_MAX_POWER;
  29. }
  30. if(pUsb)
  31. pUsb->RegisterDeviceClass(this);
  32. }
  33. uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) {
  34. const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
  35. uint8_t buf[constBufSize];
  36. USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
  37. uint8_t rcode;
  38. UsbDevice *p = NULL;
  39. EpInfo *oldep_ptr = NULL;
  40. uint8_t num_of_conf; // number of configurations
  41. AddressPool &addrPool = pUsb->GetAddressPool();
  42. USBTRACE("FTDI Init\r\n");
  43. if(bAddress)
  44. return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
  45. // Get pointer to pseudo device with address 0 assigned
  46. p = addrPool.GetUsbDevicePtr(0);
  47. if(!p)
  48. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  49. if(!p->epinfo) {
  50. USBTRACE("epinfo\r\n");
  51. return USB_ERROR_EPINFO_IS_NULL;
  52. }
  53. // Save old pointer to EP_RECORD of address 0
  54. oldep_ptr = p->epinfo;
  55. // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
  56. p->epinfo = epInfo;
  57. p->lowspeed = lowspeed;
  58. // Get device descriptor
  59. rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), buf);
  60. // Restore p->epinfo
  61. p->epinfo = oldep_ptr;
  62. if(rcode)
  63. goto FailGetDevDescr;
  64. if(udd->idVendor != FTDI_VID || udd->idProduct != FTDI_PID)
  65. return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
  66. // Save type of FTDI chip
  67. wFTDIType = udd->bcdDevice;
  68. // Allocate new address according to device class
  69. bAddress = addrPool.AllocAddress(parent, false, port);
  70. if(!bAddress)
  71. return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
  72. // Extract Max Packet Size from the device descriptor
  73. epInfo[0].maxPktSize = udd->bMaxPacketSize0;
  74. // Assign new address to the device
  75. rcode = pUsb->setAddr(0, 0, bAddress);
  76. if(rcode) {
  77. p->lowspeed = false;
  78. addrPool.FreeAddress(bAddress);
  79. bAddress = 0;
  80. USBTRACE2("setAddr:", rcode);
  81. return rcode;
  82. }
  83. USBTRACE2("Addr:", bAddress);
  84. p->lowspeed = false;
  85. p = addrPool.GetUsbDevicePtr(bAddress);
  86. if(!p)
  87. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  88. p->lowspeed = lowspeed;
  89. num_of_conf = udd->bNumConfigurations;
  90. // Assign epInfo to epinfo pointer
  91. rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
  92. if(rcode)
  93. goto FailSetDevTblEntry;
  94. USBTRACE2("NC:", num_of_conf);
  95. for(uint8_t i = 0; i < num_of_conf; i++) {
  96. HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
  97. ConfigDescParser < 0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL> confDescrParser(this);
  98. rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
  99. if(rcode)
  100. goto FailGetConfDescr;
  101. rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
  102. if(rcode)
  103. goto FailGetConfDescr;
  104. if(bNumEP > 1)
  105. break;
  106. } // for
  107. if(bNumEP < 2)
  108. return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
  109. USBTRACE2("NumEP:", bNumEP);
  110. // Assign epInfo to epinfo pointer
  111. rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
  112. USBTRACE2("Conf:", bConfNum);
  113. // Set Configuration Value
  114. rcode = pUsb->setConf(bAddress, 0, bConfNum);
  115. if(rcode)
  116. goto FailSetConfDescr;
  117. rcode = pAsync->OnInit(this);
  118. if(rcode)
  119. goto FailOnInit;
  120. USBTRACE("FTDI configured\r\n");
  121. bPollEnable = true;
  122. return 0;
  123. FailGetDevDescr:
  124. #ifdef DEBUG_USB_HOST
  125. NotifyFailGetDevDescr();
  126. goto Fail;
  127. #endif
  128. FailSetDevTblEntry:
  129. #ifdef DEBUG_USB_HOST
  130. NotifyFailSetDevTblEntry();
  131. goto Fail;
  132. #endif
  133. FailGetConfDescr:
  134. #ifdef DEBUG_USB_HOST
  135. NotifyFailGetConfDescr();
  136. goto Fail;
  137. #endif
  138. FailSetConfDescr:
  139. #ifdef DEBUG_USB_HOST
  140. NotifyFailSetConfDescr();
  141. goto Fail;
  142. #endif
  143. FailOnInit:
  144. #ifdef DEBUG_USB_HOST
  145. USBTRACE("OnInit:");
  146. Fail:
  147. NotifyFail(rcode);
  148. #endif
  149. Release();
  150. return rcode;
  151. }
  152. void FTDI::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
  153. ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
  154. ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
  155. ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
  156. bConfNum = conf;
  157. uint8_t index;
  158. if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
  159. index = epInterruptInIndex;
  160. else
  161. if((pep->bmAttributes & 0x02) == 2)
  162. index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
  163. else
  164. return;
  165. // Fill in the endpoint info structure
  166. epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
  167. epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
  168. epInfo[index].epAttribs = 0;
  169. bNumEP++;
  170. PrintEndpointDescriptor(pep);
  171. }
  172. uint8_t FTDI::Release() {
  173. pUsb->GetAddressPool().FreeAddress(bAddress);
  174. bAddress = 0;
  175. bNumEP = 1;
  176. qNextPollTime = 0;
  177. bPollEnable = false;
  178. return pAsync->OnRelease(this);
  179. }
  180. uint8_t FTDI::Poll() {
  181. uint8_t rcode = 0;
  182. //if (!bPollEnable)
  183. // return 0;
  184. //if (qNextPollTime <= millis())
  185. //{
  186. // USB_HOST_SERIAL.println(bAddress, HEX);
  187. // qNextPollTime = millis() + 100;
  188. //}
  189. return rcode;
  190. }
  191. uint8_t FTDI::SetBaudRate(uint32_t baud) {
  192. uint16_t baud_value, baud_index = 0;
  193. uint32_t divisor3;
  194. divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
  195. if(wFTDIType == FT232AM) {
  196. if((divisor3 & 0x7) == 7)
  197. divisor3++; // round x.7/8 up to x+1
  198. baud_value = divisor3 >> 3;
  199. divisor3 &= 0x7;
  200. if(divisor3 == 1) baud_value |= 0xc000;
  201. else // 0.125
  202. if(divisor3 >= 4) baud_value |= 0x4000;
  203. else // 0.5
  204. if(divisor3 != 0) baud_value |= 0x8000; // 0.25
  205. if(baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
  206. } else {
  207. static const unsigned char divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3};
  208. static const unsigned char divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1};
  209. baud_value = divisor3 >> 3;
  210. baud_value |= divfrac [divisor3 & 0x7] << 14;
  211. baud_index = divindex[divisor3 & 0x7];
  212. /* Deal with special cases for highest baud rates. */
  213. if(baud_value == 1) baud_value = 0;
  214. else // 1.0
  215. if(baud_value == 0x4001) baud_value = 1; // 1.5
  216. }
  217. USBTRACE2("baud_value:", baud_value);
  218. USBTRACE2("baud_index:", baud_index);
  219. return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL);
  220. }
  221. uint8_t FTDI::SetModemControl(uint16_t signal) {
  222. return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
  223. }
  224. uint8_t FTDI::SetFlowControl(uint8_t protocol, uint8_t xon, uint8_t xoff) {
  225. return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
  226. }
  227. uint8_t FTDI::SetData(uint16_t databm) {
  228. return pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL);
  229. }
  230. uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
  231. return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
  232. }
  233. uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) {
  234. return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
  235. }
  236. void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
  237. Notify(PSTR("Endpoint descriptor:"), 0x80);
  238. Notify(PSTR("\r\nLength:\t\t"), 0x80);
  239. D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
  240. Notify(PSTR("\r\nType:\t\t"), 0x80);
  241. D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
  242. Notify(PSTR("\r\nAddress:\t"), 0x80);
  243. D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
  244. Notify(PSTR("\r\nAttributes:\t"), 0x80);
  245. D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
  246. Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
  247. D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
  248. Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
  249. D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
  250. Notify(PSTR("\r\n"), 0x80);
  251. }