usbdcdesc.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. //*****************************************************************************
  2. //
  3. // usbcdesc.c - Config descriptor parsing functions.
  4. //
  5. // Copyright (c) 2007-2010 Texas Instruments Incorporated. All rights reserved.
  6. // Software License Agreement
  7. //
  8. // Texas Instruments (TI) is supplying this software for use solely and
  9. // exclusively on TI's microcontroller products. The software is owned by
  10. // TI and/or its suppliers, and is protected under applicable copyright
  11. // laws. You may not combine this software with "viral" open-source
  12. // software in order to form a larger program.
  13. //
  14. // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
  15. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
  16. // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  17. // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
  18. // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
  19. // DAMAGES, FOR ANY REASON WHATSOEVER.
  20. //
  21. // This is part of AM1808 StarterWare USB Library and reused from revision 6288
  22. // of the Stellaris USB Library.
  23. //
  24. //*****************************************************************************
  25. #include "hw_types.h"
  26. #include "debug.h"
  27. #include "usb.h"
  28. #include "usblib.h"
  29. #include "usbdevice.h"
  30. //*****************************************************************************
  31. //
  32. // The functions in this file mirror the descriptor parsing APIs available
  33. // in usblib.h but parse config descriptors defined in terms of a list of
  34. // sections rather than as a single block of descriptor data.
  35. //
  36. //*****************************************************************************
  37. //*****************************************************************************
  38. //
  39. //! \addtogroup device_api
  40. //! @{
  41. //
  42. //*****************************************************************************
  43. //*****************************************************************************
  44. //
  45. //! \internal
  46. //!
  47. //! Walk to the next descriptor after the supplied one within a section-based
  48. //! config descriptor.
  49. //!
  50. //! \param psConfig points to the header structure for the configuration
  51. //! descriptor which contains \e psDesc.
  52. //! \param pulSec points to a variable containing the section within \e
  53. //! psConfig which contains \e psDesc.
  54. //! \param psDesc points to the descriptor that we want to step past.
  55. //!
  56. //! This function walks forward one descriptor within a config descriptor. The
  57. //! value returned is a pointer to the header of the next descriptor after the
  58. //! descriptor supplied in \e psDesc. If the next descriptor is in the next
  59. //! section, \e *pulSec will be incremented accordlingly.
  60. //!
  61. //! \return Returns a pointer to the next descriptor in the config descrptor.
  62. //
  63. //*****************************************************************************
  64. static tDescriptorHeader *
  65. NextConfigDescGet(const tConfigHeader *psConfig, unsigned int *pulSec,
  66. tDescriptorHeader *psDesc)
  67. {
  68. //
  69. // Determine where the next descriptor after the supplied one should be
  70. // assuming it is within the current section.
  71. //
  72. psDesc = NEXT_USB_DESCRIPTOR(psDesc);
  73. //
  74. // Did we run off the end of the section?
  75. //
  76. if((unsigned char *)psDesc >= (psConfig->psSections[*pulSec]->pucData +
  77. psConfig->psSections[*pulSec]->ucSize))
  78. {
  79. //
  80. // Yes - move to the next section.
  81. //
  82. (*pulSec)++;
  83. //
  84. // Are we still within the config descriptor?
  85. //
  86. if(*pulSec < psConfig->ucNumSections)
  87. {
  88. //
  89. // Yes - the new descriptor is at the start of the new section.
  90. //
  91. psDesc =
  92. (tDescriptorHeader *)psConfig->psSections[*pulSec]->pucData;
  93. }
  94. else
  95. {
  96. //
  97. // No - we ran off the end of the descriptor so return NULL.
  98. //
  99. psDesc = (tDescriptorHeader *)0;
  100. }
  101. }
  102. //
  103. // Return the new descriptor pointer.
  104. //
  105. return(psDesc);
  106. }
  107. //*****************************************************************************
  108. //
  109. //! \internal
  110. //!
  111. //! Returns a pointer to the n-th interface descriptor in a config descriptor
  112. //! with the supplied interface number.
  113. //!
  114. //! \param psConfig points to the header structure for the config descriptor
  115. //! that is to be searched.
  116. //! \param ucInterfaceNumber is the interface number of the descriptor that is
  117. //! being queried.
  118. //! \param ulIndex is the zero based index of the descriptor to return.
  119. //! \param pulSection points to storage which will be written with the index
  120. //! of the section containing the returned descriptor.
  121. //!
  122. //! This function returns a pointer to the n-th interface descriptor in the
  123. //! supplied configuration which has the requested interface number. It may be
  124. //! used by a client to retrieve the descriptors for each alternate setting
  125. //! of a given interface within the configuration passed.
  126. //!
  127. //! \return Returns a pointer to the n-th interface descriptor with interface
  128. //! number as specified or NULL of this descriptor does not exist.
  129. //
  130. //*****************************************************************************
  131. static tInterfaceDescriptor *
  132. ConfigAlternateInterfaceGet(const tConfigHeader *psConfig,
  133. unsigned char ucInterfaceNumber,
  134. unsigned int ulIndex,
  135. unsigned int *pulSection)
  136. {
  137. tDescriptorHeader *psDescCheck;
  138. unsigned int ulCount;
  139. unsigned int ulSec;
  140. //
  141. // Set up for our descriptor counting loop.
  142. //
  143. psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pucData;
  144. ulCount = 0;
  145. ulSec = 0;
  146. //
  147. // Keep looking through the supplied data until we reach the end.
  148. //
  149. while(psDescCheck)
  150. {
  151. //
  152. // Does this descriptor match the type passed (if a specific type
  153. // has been specified)?
  154. //
  155. if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) &&
  156. (((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber ==
  157. ucInterfaceNumber))
  158. {
  159. //
  160. // This is an interface descriptor for interface ucInterfaceNumber.
  161. // Determine if this is the n-th one we have found and, if so,
  162. // return its pointer.
  163. //
  164. if(ulCount == ulIndex)
  165. {
  166. //
  167. // Found it - return the pointer and section number.
  168. //
  169. *pulSection = ulSec;
  170. return((tInterfaceDescriptor *)psDescCheck);
  171. }
  172. //
  173. // Increment our count of matching descriptors found and go back
  174. // to look for another since we have not yet reached the n-th
  175. // match.
  176. //
  177. ulCount++;
  178. }
  179. //
  180. // Move on to the next descriptor.
  181. //
  182. psDescCheck = NextConfigDescGet(psConfig, &ulSec, psDescCheck);
  183. }
  184. //
  185. // If we drop out the end of the loop, we did not find the requested
  186. // descriptor so return NULL.
  187. //
  188. return((tInterfaceDescriptor *)0);
  189. }
  190. //*****************************************************************************
  191. //
  192. //! \internal
  193. //!
  194. //! Determines the total length of a config descriptor defined in terms of a
  195. //! collection of concatenated sections.
  196. //!
  197. //! \param psConfig points to the header structure for the configuration
  198. //! descriptor whose size is to be determined.
  199. //!
  200. //! \return Returns the number of bytes in the config descriptor will result
  201. //! from concatenating the required sections.
  202. //
  203. //*****************************************************************************
  204. unsigned int
  205. USBDCDConfigDescGetSize(const tConfigHeader *psConfig)
  206. {
  207. unsigned int ulLoop;
  208. unsigned int ulLen;
  209. ulLen = 0;
  210. //
  211. // Determine the size of the whole descriptor by adding the sizes of
  212. // each section which will be concatenated to produce it.
  213. //
  214. for(ulLoop = 0; ulLoop < psConfig->ucNumSections; ulLoop++)
  215. {
  216. ulLen += psConfig->psSections[ulLoop]->ucSize;
  217. }
  218. return(ulLen);
  219. }
  220. //*****************************************************************************
  221. //
  222. //! \internal
  223. //!
  224. //! Determines the number of individual descriptors of a particular type within
  225. //! a supplied configuration descriptor.
  226. //!
  227. //! \param psConfig points to the header structure for the configuration
  228. //! descriptor that is to be searched.
  229. //! \param ulType identifies the type of descriptor that is to be counted. If
  230. //! the value is \b USB_DESC_ANY, the function returns the total number of
  231. //! descriptors regardless of type.
  232. //!
  233. //! This function can be used to count the number of descriptors of a
  234. //! particular type within a configuration descriptor. The caller can provide
  235. //! a specific type value which the function matches against the second byte
  236. //! of each descriptor or, alternatively, can specify \b USB_DESC_ANY to have
  237. //! the function count all descriptors regardless of their type.
  238. //!
  239. //! The search performed by this function traverses through the list of
  240. //! sections comprising the configuration descriptor. Note that the similar
  241. //! top-level function, USBDescGetNum(), searches through a single, contiguous
  242. //! block of data to perform the same enumeration.
  243. //!
  244. //! \return Returns the number of descriptors found in the supplied block of
  245. //! data.
  246. //
  247. //*****************************************************************************
  248. unsigned int
  249. USBDCDConfigDescGetNum(const tConfigHeader *psConfig, unsigned int ulType)
  250. {
  251. unsigned int ulSection;
  252. unsigned int ulNumDescs;
  253. //
  254. // Initialize our counts.
  255. //
  256. ulNumDescs = 0;
  257. //
  258. // Determine the number of descriptors of the given type in each of the
  259. // sections comprising the config descriptor. Note that this assumes each
  260. // section contains only whole descriptors!
  261. //
  262. for(ulSection = 0; ulSection < (unsigned int)psConfig->ucNumSections;
  263. ulSection++)
  264. {
  265. ulNumDescs += USBDescGetNum(
  266. (tDescriptorHeader *)psConfig->psSections[ulSection]->pucData,
  267. (unsigned int)psConfig->psSections[ulSection]->ucSize,
  268. ulType);
  269. }
  270. return(ulNumDescs);
  271. }
  272. //*****************************************************************************
  273. //
  274. //! \internal
  275. //!
  276. //! Finds the n-th descriptor of a particular type within the supplied
  277. //! configuration descriptor.
  278. //!
  279. //! \param psConfig points to the header structure for the configuration
  280. //! descriptor that is to be searched.
  281. //! \param ulType identifies the type of descriptor that is to be found. If
  282. //! the value is \b USB_DESC_ANY, the function returns a pointer to the n-th
  283. //! descriptor regardless of type.
  284. //! \param ulIndex is the zero based index of the descriptor whose pointer is
  285. //! to be returned. For example, passing value 1 in \e ulIndex returns the
  286. //! second matching descriptor.
  287. //! \param pulSection points to storage which will receive the section index
  288. //! containing the requested descriptor.
  289. //!
  290. //! Return a pointer to the n-th descriptor of a particular type found in the
  291. //! configuration descriptor passed.
  292. //!
  293. //! The search performed by this function traverses through the list of
  294. //! sections comprising the configuration descriptor. Note that the similar
  295. //! top-level function, USBDescGet(), searches through a single, contiguous
  296. //! block of data to perform the same enumeration.
  297. //!
  298. //! \return Returns a pointer to the header of the required descriptor if
  299. //! found or NULL otherwise.
  300. //
  301. //*****************************************************************************
  302. tDescriptorHeader *
  303. USBDCDConfigDescGet(const tConfigHeader *psConfig, unsigned int ulType,
  304. unsigned int ulIndex, unsigned int *pulSection)
  305. {
  306. unsigned int ulSection;
  307. unsigned int ulTotalDescs;
  308. unsigned int ulNumDescs;
  309. //
  310. // Initialize our counts.
  311. //
  312. ulTotalDescs = 0;
  313. //
  314. // Determine the number of descriptors of the given type in each of the
  315. // sections comprising the config descriptor. This allows us to determine
  316. // which section contains the descriptor we are being asked for.
  317. //
  318. for(ulSection = 0; ulSection < (unsigned int)psConfig->ucNumSections;
  319. ulSection++)
  320. {
  321. //
  322. // How many descriptors of the requested type exist in this section?
  323. //
  324. ulNumDescs = USBDescGetNum(
  325. (tDescriptorHeader *)psConfig->psSections[ulSection]->pucData,
  326. (unsigned int)psConfig->psSections[ulSection]->ucSize,
  327. ulType);
  328. //
  329. // Does this section contain the descriptor whose index we are looking
  330. // for?
  331. //
  332. if((ulTotalDescs + ulNumDescs) > ulIndex)
  333. {
  334. //
  335. // We know the requested descriptor exists in the current
  336. // block so write the section number to the caller's storage.
  337. //
  338. *pulSection = ulSection;
  339. //
  340. // Now find the actual descriptor requested and return its pointer.
  341. //
  342. return(USBDescGet(
  343. (tDescriptorHeader *)psConfig->psSections[ulSection]->pucData,
  344. (unsigned int)psConfig->psSections[ulSection]->ucSize,
  345. ulType,
  346. ulIndex - ulTotalDescs));
  347. }
  348. //
  349. // We have not found the required descriptor yet. Update our running
  350. // count of the number of type matches found so far then move on to
  351. // the next section.
  352. //
  353. ulTotalDescs += ulNumDescs;
  354. }
  355. //
  356. // If we drop out of the loop, we can't find the requested descriptor
  357. // so return NULL.
  358. //
  359. return((tDescriptorHeader *)0);
  360. }
  361. //*****************************************************************************
  362. //
  363. //! \internal
  364. //!
  365. //! Determines the number of different alternate configurations for a given
  366. //! interface within a config descriptor.
  367. //!
  368. //! \param psConfig points to the header structure for the configuration
  369. //! descriptor that is to be searched.
  370. //! \param ucInterfaceNumber is the interface number for which the number of
  371. //! alternate configurations is to be counted.
  372. //!
  373. //! This function can be used to count the number of alternate settings for a
  374. //! specific interface within a configuration.
  375. //!
  376. //! The search performed by this function traverses through the list of
  377. //! sections comprising the configuration descriptor. Note that the similar
  378. //! top-level function, USBDescGetNumAlternateInterfaces(), searches through
  379. //! a single, contiguous block of data to perform the same enumeration.
  380. //!
  381. //! \return Returns the number of alternate versions of the specified interface
  382. //! or 0 if the interface number supplied cannot be found in the config
  383. //! descriptor.
  384. //
  385. //*****************************************************************************
  386. unsigned int
  387. USBDCDConfigGetNumAlternateInterfaces(const tConfigHeader *psConfig,
  388. unsigned char ucInterfaceNumber)
  389. {
  390. tDescriptorHeader *psDescCheck;
  391. unsigned int ulCount;
  392. unsigned int ulSec;
  393. //
  394. // Set up for our descriptor counting loop.
  395. //
  396. psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pucData;
  397. ulSec = 0;
  398. ulCount = 0;
  399. //
  400. // Keep looking through the supplied data until we reach the end.
  401. //
  402. while(psDescCheck)
  403. {
  404. //
  405. // Is this an interface descriptor with the required interface number?
  406. //
  407. if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) &&
  408. (((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber ==
  409. ucInterfaceNumber))
  410. {
  411. //
  412. // Yes - increment our count.
  413. //
  414. ulCount++;
  415. }
  416. //
  417. // Move on to the next descriptor.
  418. //
  419. psDescCheck = NextConfigDescGet(psConfig, &ulSec, psDescCheck);
  420. }
  421. //
  422. // Return the descriptor count to the caller.
  423. //
  424. return(ulCount);
  425. }
  426. //*****************************************************************************
  427. //
  428. //! \internal
  429. //!
  430. //! Returns a pointer to the n-th interface descriptor in a configuration
  431. //! descriptor that applies to the supplied alternate setting number.
  432. //!
  433. //! \param psConfig points to the header structure for the configuration
  434. //! descriptor that is to be searched.
  435. //! \param ulIndex is the zero based index of the interface that is to be
  436. //! found. If \e ulAlt is set to a value other than \b USB_DESC_ANY, this will
  437. //! be equivalent to the interface number being searched for.
  438. //! \param ulAlt is the alternate setting number which is to be
  439. //! searched for. If this value is \b USB_DESC_ANY, the alternate setting
  440. //! is ignored and all interface descriptors are considered in the search.
  441. //! \param pulSection points to storage which will receive the index of the
  442. //! config descriptor section which contains the requested interface
  443. //! descriptor.
  444. //!
  445. //! Return a pointer to the n-th interface descriptor found in the supplied
  446. //! configuration descriptor. If \e ulAlt is not \b USB_DESC_ANY, only
  447. //! interface descriptors which are part of the supplied alternate setting are
  448. //! considered in the search otherwise all interface descriptors are
  449. //! considered.
  450. //!
  451. //! Note that, although alternate settings can be applied on an interface-by-
  452. //! interface basis, the number of interfaces offered is fixed for a given
  453. //! config descriptor. Hence, this function will correctly find the unique
  454. //! interface descriptor for that interface's alternate setting number \e
  455. //! ulAlt if \e ulIndex is set to the required interface number and \e ulAlt
  456. //! is set to a valid alternate setting number for that interface.
  457. //!
  458. //! The search performed by this function traverses through the list of
  459. //! sections comprising the configuration descriptor. Note that the similar
  460. //! top-level function, USBDescGetInterface(), searches through a single,
  461. //! contiguous block of data to perform the same enumeration.
  462. //!
  463. //! \return Returns a pointer to the required interface descriptor if
  464. //! found or NULL otherwise.
  465. //
  466. //*****************************************************************************
  467. tInterfaceDescriptor *
  468. USBDCDConfigGetInterface(const tConfigHeader *psConfig, unsigned int ulIndex,
  469. unsigned int ulAlt, unsigned int *pulSection)
  470. {
  471. //
  472. // If we are being told to ignore the alternate configuration, this boils
  473. // down to a very simple query.
  474. //
  475. if(ulAlt == USB_DESC_ANY)
  476. {
  477. //
  478. // Return the ulIndex-th interface descriptor we find in the
  479. // configuration descriptor.
  480. //
  481. return((tInterfaceDescriptor *)USBDCDConfigDescGet(psConfig,
  482. USB_DTYPE_INTERFACE,
  483. ulIndex,
  484. pulSection));
  485. }
  486. else
  487. {
  488. //
  489. // In this case, a specific alternate setting number is required.
  490. // Given that interface numbers are zero based indices, we can
  491. // pass the supplied ulIndex parameter directly as the interface
  492. // number to USBDescGetAlternateInterface to retrieve the requested
  493. // interface descriptor pointer.
  494. //
  495. return(ConfigAlternateInterfaceGet(psConfig, ulIndex, ulAlt,
  496. pulSection));
  497. }
  498. }
  499. //*****************************************************************************
  500. //
  501. //! \internal
  502. //!
  503. //! Return a pointer to the n-th endpoint descriptor in a particular interface
  504. //! within a configuration descriptor.
  505. //!
  506. //! \param psConfig points to the header structure for the configuration
  507. //! descriptor that is to be searched.
  508. //! \param ulInterfaceNumber is the interface number whose endpoint is to be
  509. //! found.
  510. //! \param ulAltCfg is the alternate setting number which is to be searched
  511. //! for. This must be a valid alternate setting number for the requested
  512. //! interface.
  513. //! \param ulIndex is the zero based index of the endpoint that is to be
  514. //! found within the appropriate alternate setting for the interface.
  515. //!
  516. //! Return a pointer to the n-th endpoint descriptor found in the supplied
  517. //! interface descriptor. If the \e ulIndex parameter is invalid (greater
  518. //! than or equal to the bNumEndpoints field of the interface descriptor) or
  519. //! the endpoint cannot be found within \e ulSize bytes of the interface
  520. //! descriptor pointer, the function will return NULL.
  521. //!
  522. //! Note that, although the USB 2.0 specification states that endpoint
  523. //! descriptors must follow the interface descriptor that they relate to, it
  524. //! also states that device specific descriptors should follow any standard
  525. //! descriptor that they relate to. As a result, we cannot assume that each
  526. //! interface descriptor will be followed by nothing but an ordered list of
  527. //! its own endpoints and, hence, the function needs to be provided ulSize to
  528. //! limit the search range.
  529. //!
  530. //! The search performed by this function traverses through the list of
  531. //! sections comprising the configuration descriptor. Note that the similar
  532. //! top-level function, USBDescGetInterfaceEndpoint(), searches through a
  533. //! single, contiguous block of data to perform the same enumeration.
  534. //!
  535. //! \return Returns a pointer to the requested endpoint descriptor if
  536. //! found or NULL otherwise.
  537. //
  538. //*****************************************************************************
  539. tEndpointDescriptor *
  540. USBDCDConfigGetInterfaceEndpoint(const tConfigHeader *psConfig,
  541. unsigned int ulInterfaceNumber,
  542. unsigned int ulAltCfg, unsigned int ulIndex)
  543. {
  544. tInterfaceDescriptor *psInterface;
  545. tDescriptorHeader *psEndpoint;
  546. unsigned int ulSection;
  547. unsigned int ulCount;
  548. //
  549. // Find the requested interface descriptor.
  550. //
  551. psInterface = USBDCDConfigGetInterface(psConfig, ulInterfaceNumber,
  552. ulAltCfg, &ulSection);
  553. //
  554. // Did we find the requested interface?
  555. //
  556. if(psInterface)
  557. {
  558. //
  559. // Is the index passed valid?
  560. //
  561. if(ulIndex >= psInterface->bNumEndpoints)
  562. {
  563. //
  564. // It's out of bounds so return a NULL.
  565. //
  566. return((tEndpointDescriptor *)0);
  567. }
  568. else
  569. {
  570. //
  571. // Endpoint index is valid so find the descriptor. We start from
  572. // the interface descriptor and look for following endpoint
  573. // descriptors.
  574. //
  575. ulCount = 0;
  576. psEndpoint = (tDescriptorHeader *)psInterface;
  577. while(psEndpoint)
  578. {
  579. if(psEndpoint->bDescriptorType == USB_DTYPE_ENDPOINT)
  580. {
  581. //
  582. // We found an endpoint descriptor. Have we reached the
  583. // one we want?
  584. //
  585. if(ulCount == ulIndex)
  586. {
  587. //
  588. // Yes - return the descriptor pointer to the caller.
  589. //
  590. return((tEndpointDescriptor *)psEndpoint);
  591. }
  592. //
  593. // Move on to look for the next endpoint.
  594. //
  595. ulCount++;
  596. }
  597. //
  598. // Move to the next descriptor.
  599. //
  600. psEndpoint = NextConfigDescGet(psConfig, &ulSection,
  601. psEndpoint);
  602. }
  603. }
  604. }
  605. //
  606. // We couldn't find the requested interface or we got to the end of the
  607. // descriptor without finding the requested endpoint.
  608. //
  609. return((tEndpointDescriptor *)0);
  610. }
  611. //*****************************************************************************
  612. //
  613. // Close the Doxygen group.
  614. //! @}
  615. //
  616. //*****************************************************************************