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
cdcacm.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 "cdcacm.h" 00018 00019 const uint8_t ACM::epDataInIndex = 1; 00020 const uint8_t ACM::epDataOutIndex = 2; 00021 const uint8_t ACM::epInterruptInIndex = 3; 00022 00023 ACM::ACM(Usb *p, CDCAsyncOper *pasync) : 00024 pUsb(p), 00025 pAsync(pasync), 00026 bAddress(0), 00027 bControlIface(0), 00028 bDataIface(0), 00029 bNumEP(1), 00030 qNextPollTime(0), 00031 bPollEnable(false), 00032 ready(false) { 00033 _enhanced_status = enhanced_features(); // Set up features 00034 for(uint8_t i = 0; i < ACM_MAX_ENDPOINTS; i++) { 00035 epInfo[i].epAddr = 0; 00036 epInfo[i].maxPktSize = (i) ? 0 : 8; 00037 epInfo[i].bmSndToggle = 0; 00038 epInfo[i].bmRcvToggle = 0; 00039 epInfo[i].bmNakPower = (i == epDataInIndex) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; 00040 00041 } 00042 if(pUsb) 00043 pUsb->RegisterDeviceClass(this); 00044 } 00045 00046 uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) { 00047 00048 const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); 00049 00050 uint8_t buf[constBufSize]; 00051 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); 00052 00053 uint8_t rcode; 00054 UsbDevice *p = NULL; 00055 EpInfo *oldep_ptr = NULL; 00056 uint8_t num_of_conf; // number of configurations 00057 00058 AddressPool &addrPool = pUsb->GetAddressPool(); 00059 00060 USBTRACE("ACM Init\r\n"); 00061 00062 if(bAddress) 00063 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; 00064 00065 // Get pointer to pseudo device with address 0 assigned 00066 p = addrPool.GetUsbDevicePtr(0); 00067 00068 if(!p) 00069 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00070 00071 if(!p->epinfo) { 00072 USBTRACE("epinfo\r\n"); 00073 return USB_ERROR_EPINFO_IS_NULL; 00074 } 00075 00076 // Save old pointer to EP_RECORD of address 0 00077 oldep_ptr = p->epinfo; 00078 00079 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence 00080 p->epinfo = epInfo; 00081 00082 p->lowspeed = lowspeed; 00083 00084 // Get device descriptor 00085 rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); 00086 00087 // Restore p->epinfo 00088 p->epinfo = oldep_ptr; 00089 00090 if(rcode) 00091 goto FailGetDevDescr; 00092 00093 // Allocate new address according to device class 00094 bAddress = addrPool.AllocAddress(parent, false, port); 00095 00096 if(!bAddress) 00097 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; 00098 00099 // Extract Max Packet Size from the device descriptor 00100 epInfo[0].maxPktSize = udd->bMaxPacketSize0; 00101 00102 // Assign new address to the device 00103 rcode = pUsb->setAddr(0, 0, bAddress); 00104 00105 if(rcode) { 00106 p->lowspeed = false; 00107 addrPool.FreeAddress(bAddress); 00108 bAddress = 0; 00109 USBTRACE2("setAddr:", rcode); 00110 return rcode; 00111 } 00112 00113 USBTRACE2("Addr:", bAddress); 00114 00115 p->lowspeed = false; 00116 00117 p = addrPool.GetUsbDevicePtr(bAddress); 00118 00119 if(!p) 00120 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00121 00122 p->lowspeed = lowspeed; 00123 00124 num_of_conf = udd->bNumConfigurations; 00125 00126 // Assign epInfo to epinfo pointer 00127 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); 00128 00129 if(rcode) 00130 goto FailSetDevTblEntry; 00131 00132 USBTRACE2("NC:", num_of_conf); 00133 00134 for(uint8_t i = 0; i < num_of_conf; i++) { 00135 ConfigDescParser< USB_CLASS_COM_AND_CDC_CTRL, 00136 CDC_SUBCLASS_ACM, 00137 CDC_PROTOCOL_ITU_T_V_250, 00138 CP_MASK_COMPARE_CLASS | 00139 CP_MASK_COMPARE_SUBCLASS | 00140 CP_MASK_COMPARE_PROTOCOL > CdcControlParser(this); 00141 00142 ConfigDescParser<USB_CLASS_CDC_DATA, 0, 0, 00143 CP_MASK_COMPARE_CLASS> CdcDataParser(this); 00144 00145 rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcControlParser); 00146 00147 if(rcode) 00148 goto FailGetConfDescr; 00149 00150 rcode = pUsb->getConfDescr(bAddress, 0, i, &CdcDataParser); 00151 00152 if(rcode) 00153 goto FailGetConfDescr; 00154 00155 if(bNumEP > 1) 00156 break; 00157 } // for 00158 00159 if(bNumEP < 4) 00160 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; 00161 00162 // Assign epInfo to epinfo pointer 00163 rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); 00164 00165 USBTRACE2("Conf:", bConfNum); 00166 00167 // Set Configuration Value 00168 rcode = pUsb->setConf(bAddress, 0, bConfNum); 00169 00170 if(rcode) 00171 goto FailSetConfDescr; 00172 00173 // Set up features status 00174 _enhanced_status = enhanced_features(); 00175 half_duplex(false); 00176 autoflowRTS(false); 00177 autoflowDSR(false); 00178 autoflowXON(false); 00179 wide(false); // Always false, because this is only available in custom mode. 00180 rcode = pAsync->OnInit(this); 00181 00182 if(rcode) 00183 goto FailOnInit; 00184 00185 USBTRACE("ACM configured\r\n"); 00186 00187 ready = true; 00188 00189 //bPollEnable = true; 00190 00191 //USBTRACE("Poll enabled\r\n"); 00192 return 0; 00193 00194 FailGetDevDescr: 00195 #ifdef DEBUG_USB_HOST 00196 NotifyFailGetDevDescr(); 00197 goto Fail; 00198 #endif 00199 00200 FailSetDevTblEntry: 00201 #ifdef DEBUG_USB_HOST 00202 NotifyFailSetDevTblEntry(); 00203 goto Fail; 00204 #endif 00205 00206 FailGetConfDescr: 00207 #ifdef DEBUG_USB_HOST 00208 NotifyFailGetConfDescr(); 00209 goto Fail; 00210 #endif 00211 00212 FailSetConfDescr: 00213 #ifdef DEBUG_USB_HOST 00214 NotifyFailSetConfDescr(); 00215 goto Fail; 00216 #endif 00217 00218 FailOnInit: 00219 #ifdef DEBUG_USB_HOST 00220 USBTRACE("OnInit:"); 00221 #endif 00222 00223 #ifdef DEBUG_USB_HOST 00224 Fail: 00225 NotifyFail(rcode); 00226 #endif 00227 Release(); 00228 return rcode; 00229 } 00230 00231 void ACM::EndpointXtract(uint8_t conf, uint8_t iface __attribute__((unused)), uint8_t alt __attribute__((unused)), uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *pep) { 00232 //ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf); 00233 //ErrorMessage<uint8_t > (PSTR("Iface Num"), iface); 00234 //ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt); 00235 00236 bConfNum = conf; 00237 00238 uint8_t index; 00239 00240 if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) 00241 index = epInterruptInIndex; 00242 else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) 00243 index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; 00244 else 00245 return; 00246 00247 // Fill in the endpoint info structure 00248 epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); 00249 epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; 00250 epInfo[index].bmSndToggle = 0; 00251 epInfo[index].bmRcvToggle = 0; 00252 00253 bNumEP++; 00254 00255 PrintEndpointDescriptor(pep); 00256 } 00257 00258 uint8_t ACM::Release() { 00259 ready = false; 00260 pUsb->GetAddressPool().FreeAddress(bAddress); 00261 00262 bControlIface = 0; 00263 bDataIface = 0; 00264 bNumEP = 1; 00265 00266 bAddress = 0; 00267 qNextPollTime = 0; 00268 bPollEnable = false; 00269 return 0; 00270 } 00271 00272 uint8_t ACM::Poll() { 00273 //uint8_t rcode = 0; 00274 //if(!bPollEnable) 00275 // return 0; 00276 //return rcode; 00277 return 0; 00278 } 00279 00280 uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) { 00281 uint8_t rv = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); 00282 if(rv && rv != hrNAK) { 00283 Release(); 00284 } 00285 return rv; 00286 } 00287 00288 uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) { 00289 uint8_t rv = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); 00290 if(rv && rv != hrNAK) { 00291 Release(); 00292 } 00293 return rv; 00294 } 00295 00296 uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) { 00297 uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL)); 00298 if(rv && rv != hrNAK) { 00299 Release(); 00300 } 00301 return rv; 00302 } 00303 00304 uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) { 00305 uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL)); 00306 if(rv && rv != hrNAK) { 00307 Release(); 00308 } 00309 return rv; 00310 } 00311 00312 uint8_t ACM::ClearCommFeature(uint16_t fid) { 00313 uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL)); 00314 if(rv && rv != hrNAK) { 00315 Release(); 00316 } 00317 return rv; 00318 } 00319 00320 uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) { 00321 uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL)); 00322 if(rv && rv != hrNAK) { 00323 Release(); 00324 } 00325 return rv; 00326 } 00327 00328 uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) { 00329 uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof (LINE_CODING), sizeof (LINE_CODING), (uint8_t*)dataptr, NULL)); 00330 if(rv && rv != hrNAK) { 00331 Release(); 00332 } 00333 return rv; 00334 } 00335 00336 uint8_t ACM::SetControlLineState(uint8_t state) { 00337 uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL)); 00338 if(rv && rv != hrNAK) { 00339 Release(); 00340 } 00341 return rv; 00342 } 00343 00344 uint8_t ACM::SendBreak(uint16_t duration) { 00345 uint8_t rv = ( pUsb->ctrlReq(bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL)); 00346 if(rv && rv != hrNAK) { 00347 Release(); 00348 } 00349 return rv; 00350 } 00351 00352 void ACM::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { 00353 Notify(PSTR("Endpoint descriptor:"), 0x80); 00354 Notify(PSTR("\r\nLength:\t\t"), 0x80); 00355 D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80); 00356 Notify(PSTR("\r\nType:\t\t"), 0x80); 00357 D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80); 00358 Notify(PSTR("\r\nAddress:\t"), 0x80); 00359 D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80); 00360 Notify(PSTR("\r\nAttributes:\t"), 0x80); 00361 D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80); 00362 Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); 00363 D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80); 00364 Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); 00365 D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80); 00366 Notify(PSTR("\r\n"), 0x80); 00367 }
Generated on Tue Jul 12 2022 18:12:04 by
1.7.2