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.

331 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 "cdcacm.h"
  15. const uint8_t ACM::epDataInIndex = 1;
  16. const uint8_t ACM::epDataOutIndex = 2;
  17. const uint8_t ACM::epInterruptInIndex = 3;
  18. ACM::ACM(USB *p, CDCAsyncOper *pasync) :
  19. pUsb(p),
  20. pAsync(pasync),
  21. bAddress(0),
  22. bControlIface(0),
  23. bDataIface(0),
  24. bNumEP(1),
  25. qNextPollTime(0),
  26. bPollEnable(false),
  27. ready(false) {
  28. _enhanced_status = enhanced_features(); // Set up features
  29. for(uint8_t i = 0; i < ACM_MAX_ENDPOINTS; i++) {
  30. epInfo[i].epAddr = 0;
  31. epInfo[i].maxPktSize = (i) ? 0 : 8;
  32. epInfo[i].epAttribs = 0;
  33. epInfo[i].bmNakPower = (i == epDataInIndex) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
  34. }
  35. if(pUsb)
  36. pUsb->RegisterDeviceClass(this);
  37. }
  38. uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) {
  39. const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
  40. uint8_t buf[constBufSize];
  41. USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
  42. uint8_t rcode;
  43. UsbDevice *p = NULL;
  44. EpInfo *oldep_ptr = NULL;
  45. uint8_t num_of_conf; // number of configurations
  46. AddressPool &addrPool = pUsb->GetAddressPool();
  47. USBTRACE("ACM Init\r\n");
  48. if(bAddress)
  49. return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
  50. // Get pointer to pseudo device with address 0 assigned
  51. p = addrPool.GetUsbDevicePtr(0);
  52. if(!p)
  53. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  54. if(!p->epinfo) {
  55. USBTRACE("epinfo\r\n");
  56. return USB_ERROR_EPINFO_IS_NULL;
  57. }
  58. // Save old pointer to EP_RECORD of address 0
  59. oldep_ptr = p->epinfo;
  60. // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
  61. p->epinfo = epInfo;
  62. p->lowspeed = lowspeed;
  63. // Get device descriptor
  64. rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
  65. // Restore p->epinfo
  66. p->epinfo = oldep_ptr;
  67. if(rcode)
  68. goto FailGetDevDescr;
  69. // Allocate new address according to device class
  70. bAddress = addrPool.AllocAddress(parent, false, port);
  71. if(!bAddress)
  72. return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
  73. // Extract Max Packet Size from the device descriptor
  74. epInfo[0].maxPktSize = udd->bMaxPacketSize0;
  75. // Assign new address to the device
  76. rcode = pUsb->setAddr(0, 0, bAddress);
  77. if(rcode) {
  78. p->lowspeed = false;
  79. addrPool.FreeAddress(bAddress);
  80. bAddress = 0;
  81. USBTRACE2("setAddr:", rcode);
  82. return rcode;
  83. }
  84. USBTRACE2("Addr:", bAddress);
  85. p->lowspeed = false;
  86. p = addrPool.GetUsbDevicePtr(bAddress);
  87. if(!p)
  88. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  89. p->lowspeed = lowspeed;
  90. num_of_conf = udd->bNumConfigurations;
  91. // Assign epInfo to epinfo pointer
  92. rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
  93. if(rcode)
  94. goto FailSetDevTblEntry;
  95. USBTRACE2("NC:", num_of_conf);
  96. for(uint8_t i = 0; i < num_of_conf; i++) {
  97. ConfigDescParser< USB_CLASS_COM_AND_CDC_CTRL,
  98. CDC_SUBCLASS_ACM,
  99. CDC_PROTOCOL_ITU_T_V_250,
  100. CP_MASK_COMPARE_CLASS |
  101. CP_MASK_COMPARE_SUBCLASS |
  102. CP_MASK_COMPARE_PROTOCOL > CdcControlParser(this);
  103. ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0,
  104. CP_MASK_COMPARE_CLASS> CdcDataParser(this);
  105. rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser);
  106. if(rcode)
  107. goto FailGetConfDescr;
  108. rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser);
  109. if(rcode)
  110. goto FailGetConfDescr;
  111. if(bNumEP > 1)
  112. break;
  113. } // for
  114. if(bNumEP < 4)
  115. return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
  116. // Assign epInfo to epinfo pointer
  117. rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
  118. USBTRACE2("Conf:", bConfNum);
  119. // Set Configuration Value
  120. rcode = pUsb->setConf(bAddress, 0, bConfNum);
  121. if(rcode)
  122. goto FailSetConfDescr;
  123. // Set up features status
  124. _enhanced_status = enhanced_features();
  125. half_duplex(false);
  126. autoflowRTS(false);
  127. autoflowDSR(false);
  128. autoflowXON(false);
  129. wide(false); // Always false, because this is only available in custom mode.
  130. rcode = pAsync->OnInit(this);
  131. if(rcode)
  132. goto FailOnInit;
  133. USBTRACE("ACM configured\r\n");
  134. ready = true;
  135. //bPollEnable = true;
  136. //USBTRACE("Poll enabled\r\n");
  137. return 0;
  138. FailGetDevDescr:
  139. #ifdef DEBUG_USB_HOST
  140. NotifyFailGetDevDescr();
  141. goto Fail;
  142. #endif
  143. FailSetDevTblEntry:
  144. #ifdef DEBUG_USB_HOST
  145. NotifyFailSetDevTblEntry();
  146. goto Fail;
  147. #endif
  148. FailGetConfDescr:
  149. #ifdef DEBUG_USB_HOST
  150. NotifyFailGetConfDescr();
  151. goto Fail;
  152. #endif
  153. FailSetConfDescr:
  154. #ifdef DEBUG_USB_HOST
  155. NotifyFailSetConfDescr();
  156. goto Fail;
  157. #endif
  158. FailOnInit:
  159. #ifdef DEBUG_USB_HOST
  160. USBTRACE("OnInit:");
  161. #endif
  162. #ifdef DEBUG_USB_HOST
  163. Fail:
  164. NotifyFail(rcode);
  165. #endif
  166. Release();
  167. return rcode;
  168. }
  169. void ACM::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
  170. //ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
  171. //ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
  172. //ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
  173. bConfNum = conf;
  174. uint8_t index;
  175. if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
  176. index = epInterruptInIndex;
  177. else
  178. if((pep->bmAttributes & 0x02) == 2)
  179. index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
  180. else
  181. return;
  182. // Fill in the endpoint info structure
  183. epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
  184. epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
  185. epInfo[index].epAttribs = 0;
  186. bNumEP++;
  187. PrintEndpointDescriptor(pep);
  188. }
  189. uint8_t ACM::Release() {
  190. ready = false;
  191. pUsb->GetAddressPool().FreeAddress(bAddress);
  192. bControlIface = 0;
  193. bDataIface = 0;
  194. bNumEP = 1;
  195. bAddress = 0;
  196. qNextPollTime = 0;
  197. bPollEnable = false;
  198. return 0;
  199. }
  200. uint8_t ACM::Poll() {
  201. uint8_t rcode = 0;
  202. if(!bPollEnable)
  203. return 0;
  204. return rcode;
  205. }
  206. uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) {
  207. return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
  208. }
  209. uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) {
  210. return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
  211. }
  212. uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
  213. return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
  214. }
  215. uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) {
  216. return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL));
  217. }
  218. uint8_t ACM::ClearCommFeature(uint16_t fid) {
  219. return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL));
  220. }
  221. uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) {
  222. return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
  223. }
  224. uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) {
  225. return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL));
  226. }
  227. uint8_t ACM::SetControlLineState(uint8_t state) {
  228. return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL));
  229. }
  230. uint8_t ACM::SendBreak(uint16_t duration) {
  231. return ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL));
  232. }
  233. void ACM::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
  234. Notify(PSTR("Endpoint descriptor:"), 0x80);
  235. Notify(PSTR("\r\nLength:\t\t"), 0x80);
  236. D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
  237. Notify(PSTR("\r\nType:\t\t"), 0x80);
  238. D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
  239. Notify(PSTR("\r\nAddress:\t"), 0x80);
  240. D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
  241. Notify(PSTR("\r\nAttributes:\t"), 0x80);
  242. D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
  243. Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
  244. D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
  245. Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
  246. D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
  247. Notify(PSTR("\r\n"), 0x80);
  248. }