usbhost_skeleton.c 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. /****************************************************************************
  2. * drivers/usbhost/usbhost_skeleton.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <assert.h>
  28. #include <errno.h>
  29. #include <debug.h>
  30. #include <nuttx/irq.h>
  31. #include <nuttx/kmalloc.h>
  32. #include <nuttx/fs/fs.h>
  33. #include <nuttx/arch.h>
  34. #include <nuttx/semaphore.h>
  35. #include <nuttx/wqueue.h>
  36. #include <nuttx/usb/usb.h>
  37. #include <nuttx/usb/usbhost.h>
  38. /****************************************************************************
  39. * Pre-processor Definitions
  40. ****************************************************************************/
  41. /* Configuration ************************************************************/
  42. #ifndef CONFIG_SCHED_WORKQUEUE
  43. # warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
  44. #endif
  45. /* Driver support ***********************************************************/
  46. /* This format is used to construct the /dev/skel[n] device driver path. It
  47. * defined here so that it will be used consistently in all places.
  48. */
  49. #define DEV_FORMAT "/dev/skel%c"
  50. #define DEV_NAMELEN 12
  51. /* Used in usbhost_cfgdesc() */
  52. #define USBHOST_IFFOUND 0x01
  53. #define USBHOST_BINFOUND 0x02
  54. #define USBHOST_BOUTFOUND 0x04
  55. #define USBHOST_ALLFOUND 0x07
  56. #define USBHOST_MAX_CREFS 0x7fff
  57. /****************************************************************************
  58. * Private Types
  59. ****************************************************************************/
  60. /* This structure contains the internal, private state of the USB host class
  61. * driver.
  62. */
  63. struct usbhost_state_s
  64. {
  65. /* This is the externally visible portion of the state */
  66. struct usbhost_class_s usbclass;
  67. /* The remainder of the fields are provide to the class driver */
  68. char devchar; /* Character identifying the /dev/skel[n] device */
  69. volatile bool disconnected; /* TRUE: Device has been disconnected */
  70. uint8_t ifno; /* Interface number */
  71. int16_t crefs; /* Reference count on the driver instance */
  72. sem_t exclsem; /* Used to maintain mutual exclusive access */
  73. struct work_s work; /* For interacting with the worker thread */
  74. FAR uint8_t *tbuffer; /* The allocated transfer buffer */
  75. size_t tbuflen; /* Size of the allocated transfer buffer */
  76. usbhost_ep_t epin; /* IN endpoint */
  77. usbhost_ep_t epout; /* OUT endpoint */
  78. };
  79. /****************************************************************************
  80. * Private Function Prototypes
  81. ****************************************************************************/
  82. /* Semaphores */
  83. static int usbhost_takesem(FAR sem_t *sem);
  84. static void usbhost_forcetake(FAR sem_t *sem);
  85. #define usbhost_givesem(s) nxsem_post(s);
  86. /* Memory allocation services */
  87. static inline FAR struct usbhost_state_s *usbhost_allocclass(void);
  88. static inline void usbhost_freeclass(FAR struct usbhost_state_s *usbclass);
  89. /* Device name management */
  90. static int usbhost_allocdevno(FAR struct usbhost_state_s *priv);
  91. static void usbhost_freedevno(FAR struct usbhost_state_s *priv);
  92. static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv,
  93. FAR char *devname);
  94. /* Worker thread actions */
  95. static void usbhost_destroy(FAR void *arg);
  96. /* Helpers for usbhost_connect() */
  97. static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
  98. FAR const uint8_t *configdesc,
  99. int desclen);
  100. static inline int usbhost_devinit(FAR struct usbhost_state_s *priv);
  101. /* (Little Endian) Data helpers */
  102. static inline uint16_t usbhost_getle16(const uint8_t *val);
  103. static inline void usbhost_putle16(uint8_t *dest, uint16_t val);
  104. static inline uint32_t usbhost_getle32(const uint8_t *val);
  105. static void usbhost_putle32(uint8_t *dest, uint32_t val);
  106. /* Transfer descriptor memory management */
  107. static inline int usbhost_talloc(FAR struct usbhost_state_s *priv);
  108. static inline int usbhost_tfree(FAR struct usbhost_state_s *priv);
  109. /* struct usbhost_registry_s methods */
  110. static struct usbhost_class_s *
  111. usbhost_create(FAR struct usbhost_hubport_s *hport,
  112. FAR const struct usbhost_id_s *id);
  113. /* struct usbhost_class_s methods */
  114. static int usbhost_connect(FAR struct usbhost_class_s *usbclass,
  115. FAR const uint8_t *configdesc, int desclen);
  116. static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass);
  117. /* Driver methods --
  118. * depend upon the type of NuttX driver interface exported
  119. */
  120. /****************************************************************************
  121. * Private Data
  122. ****************************************************************************/
  123. /* This structure provides the registry entry ID information that will be
  124. * used to associate the USB class driver to a connected USB device.
  125. */
  126. static const struct usbhost_id_s g_id =
  127. {
  128. 0, /* base -- Must be one of the USB_CLASS_* definitions in usb.h */
  129. 0, /* subclass -- depends on the device */
  130. 0, /* proto -- depends on the device */
  131. 0, /* vid */
  132. 0 /* pid */
  133. };
  134. /* This is the USB host storage class's registry entry */
  135. static struct usbhost_registry_s g_skeleton =
  136. {
  137. NULL, /* flink */
  138. usbhost_create, /* create */
  139. 1, /* nids */
  140. &g_id /* id[] */
  141. };
  142. /* This is a bitmap that is used to allocate device names /dev/skela-z. */
  143. static uint32_t g_devinuse;
  144. /****************************************************************************
  145. * Private Functions
  146. ****************************************************************************/
  147. /****************************************************************************
  148. * Name: usbhost_takesem
  149. *
  150. * Description:
  151. * This is just a wrapper to handle the annoying behavior of semaphore
  152. * waits that return due to the receipt of a signal.
  153. *
  154. ****************************************************************************/
  155. static int usbhost_takesem(FAR sem_t *sem)
  156. {
  157. return nxsem_wait_uninterruptible(sem);
  158. }
  159. /****************************************************************************
  160. * Name: usbhost_forcetake
  161. *
  162. * Description:
  163. * This is just another wrapper but this one continues even if the thread
  164. * is canceled. This must be done in certain conditions where were must
  165. * continue in order to clean-up resources.
  166. *
  167. ****************************************************************************/
  168. static void usbhost_forcetake(FAR sem_t *sem)
  169. {
  170. int ret;
  171. do
  172. {
  173. ret = nxsem_wait_uninterruptible(sem);
  174. /* The only expected error would -ECANCELED meaning that the
  175. * parent thread has been canceled. We have to continue and
  176. * terminate the poll in this case.
  177. */
  178. DEBUGASSERT(ret == OK || ret == -ECANCELED);
  179. }
  180. while (ret < 0);
  181. }
  182. /****************************************************************************
  183. * Name: usbhost_allocclass
  184. *
  185. * Description:
  186. * This is really part of the logic that implements the create() method
  187. * of struct usbhost_registry_s. This function allocates memory for one
  188. * new class instance.
  189. *
  190. * Input Parameters:
  191. * None
  192. *
  193. * Returned Value:
  194. * On success, this function will return a non-NULL instance of struct
  195. * usbhost_class_s. NULL is returned on failure; this function will
  196. * will fail only if there are insufficient resources to create another
  197. * USB host class instance.
  198. *
  199. ****************************************************************************/
  200. static inline FAR struct usbhost_state_s *usbhost_allocclass(void)
  201. {
  202. FAR struct usbhost_state_s *priv;
  203. DEBUGASSERT(!up_interrupt_context());
  204. priv = (FAR struct usbhost_state_s *)
  205. kmm_malloc(sizeof(struct usbhost_state_s));
  206. uinfo("Allocated: %p\n", priv);
  207. return priv;
  208. }
  209. /****************************************************************************
  210. * Name: usbhost_freeclass
  211. *
  212. * Description:
  213. * Free a class instance previously allocated by usbhost_allocclass().
  214. *
  215. * Input Parameters:
  216. * usbclass - A reference to the class instance to be freed.
  217. *
  218. * Returned Value:
  219. * None
  220. *
  221. ****************************************************************************/
  222. static inline void usbhost_freeclass(FAR struct usbhost_state_s *usbclass)
  223. {
  224. DEBUGASSERT(usbclass != NULL);
  225. /* Free the class instance (perhaps calling sched_kmm_free() in case we are
  226. * executing from an interrupt handler.
  227. */
  228. uinfo("Freeing: %p\n", usbclass);
  229. kmm_free(usbclass);
  230. }
  231. /****************************************************************************
  232. * Name: Device name management
  233. *
  234. * Description:
  235. * Some tiny functions to coordinate management of device names.
  236. *
  237. ****************************************************************************/
  238. static int usbhost_allocdevno(FAR struct usbhost_state_s *priv)
  239. {
  240. irqstate_t flags;
  241. int devno;
  242. flags = enter_critical_section();
  243. for (devno = 0; devno < 26; devno++)
  244. {
  245. uint32_t bitno = 1 << devno;
  246. if ((g_devinuse & bitno) == 0)
  247. {
  248. g_devinuse |= bitno;
  249. priv->devchar = 'a' + devno;
  250. leave_critical_section(flags);
  251. return OK;
  252. }
  253. }
  254. leave_critical_section(flags);
  255. return -EMFILE;
  256. }
  257. static void usbhost_freedevno(FAR struct usbhost_state_s *priv)
  258. {
  259. int devno = 'a' - priv->devchar;
  260. if (devno >= 0 && devno < 26)
  261. {
  262. irqstate_t flags = enter_critical_section();
  263. g_devinuse &= ~(1 << devno);
  264. leave_critical_section(flags);
  265. }
  266. }
  267. static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv,
  268. FAR char *devname)
  269. {
  270. snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->devchar);
  271. }
  272. /****************************************************************************
  273. * Name: usbhost_destroy
  274. *
  275. * Description:
  276. * The USB device has been disconnected and the reference count on the USB
  277. * host class instance has gone to 1.. Time to destroy the USB host class
  278. * instance.
  279. *
  280. * Input Parameters:
  281. * arg - A reference to the class instance to be destroyed.
  282. *
  283. * Returned Value:
  284. * None
  285. *
  286. ****************************************************************************/
  287. static void usbhost_destroy(FAR void *arg)
  288. {
  289. FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
  290. FAR struct usbhost_hubport_s *hport;
  291. FAR struct usbhost_driver_s *drvr;
  292. DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL);
  293. hport = priv->usbclass.hport;
  294. DEBUGASSERT(hport->drvr);
  295. drvr = hport->drvr;
  296. uinfo("crefs: %d\n", priv->crefs);
  297. /* Unregister the driver */
  298. /* Release the device name used by this connection */
  299. usbhost_freedevno(priv);
  300. /* Free the endpoints */
  301. /* Free any transfer buffers */
  302. /* Free the function address assigned to this device */
  303. usbhost_devaddr_destroy(hport, hport->funcaddr);
  304. hport->funcaddr = 0;
  305. /* Destroy the semaphores */
  306. /* Disconnect the USB host device */
  307. DRVR_DISCONNECT(drvr, hport);
  308. /* And free the class instance. Hmmm.. this may execute on the worker
  309. * thread and the work structure is part of what is getting freed. That
  310. * should be okay because once the work contained is removed from the
  311. * queue, it should not longer be accessed by the worker thread.
  312. */
  313. usbhost_freeclass(priv);
  314. }
  315. /****************************************************************************
  316. * Name: usbhost_cfgdesc
  317. *
  318. * Description:
  319. * This function implements the connect() method of struct
  320. * usbhost_class_s. This method is a callback into the class
  321. * implementation. It is used to provide the device's configuration
  322. * descriptor to the class so that the class may initialize properly
  323. *
  324. * Input Parameters:
  325. * priv - The USB host class instance.
  326. * configdesc - A pointer to a uint8_t buffer container the configuration
  327. * descriptor.
  328. * desclen - The length in bytes of the configuration descriptor.
  329. *
  330. * Returned Value:
  331. * On success, zero (OK) is returned. On a failure, a negated errno value
  332. * is returned indicating the nature of the failure
  333. *
  334. * Assumptions:
  335. * This function will *not* be called from an interrupt handler.
  336. *
  337. ****************************************************************************/
  338. static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
  339. FAR const uint8_t *configdesc, int desclen)
  340. {
  341. FAR struct usbhost_hubport_s *hport;
  342. FAR struct usb_cfgdesc_s *cfgdesc;
  343. FAR struct usb_desc_s *desc;
  344. FAR struct usbhost_epdesc_s bindesc;
  345. FAR struct usbhost_epdesc_s boutdesc;
  346. int remaining;
  347. uint8_t found = 0;
  348. int ret;
  349. DEBUGASSERT(priv != NULL && priv->usbclass.hport &&
  350. configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s));
  351. hport = priv->usbclass.hport;
  352. /* Verify that we were passed a configuration descriptor */
  353. cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
  354. if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
  355. {
  356. return -EINVAL;
  357. }
  358. /* Get the total length of the configuration descriptor (little endian).
  359. * It might be a good check to get the number of interfaces here too.
  360. */
  361. remaining = (int)usbhost_getle16(cfgdesc->totallen);
  362. /* Skip to the next entry descriptor */
  363. configdesc += cfgdesc->len;
  364. remaining -= cfgdesc->len;
  365. /* Loop where there are more dscriptors to examine */
  366. while (remaining >= sizeof(struct usb_desc_s))
  367. {
  368. /* What is the next descriptor? */
  369. desc = (FAR struct usb_desc_s *)configdesc;
  370. switch (desc->type)
  371. {
  372. /* Interface descriptor. We really should get the number of endpoints
  373. * from this descriptor too.
  374. */
  375. case USB_DESC_TYPE_INTERFACE:
  376. {
  377. FAR struct usb_ifdesc_s *ifdesc =
  378. (FAR struct usb_ifdesc_s *)configdesc;
  379. uinfo("Interface descriptor\n");
  380. DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);
  381. /* Save the interface number and mark ONLY the interface found */
  382. priv->ifno = ifdesc->ifno;
  383. found = USBHOST_IFFOUND;
  384. }
  385. break;
  386. /* Endpoint descriptor. Here, we expect two bulk endpoints, an IN
  387. * and an OUT.
  388. */
  389. case USB_DESC_TYPE_ENDPOINT:
  390. {
  391. FAR struct usb_epdesc_s *epdesc =
  392. (FAR struct usb_epdesc_s *)configdesc;
  393. uinfo("Endpoint descriptor\n");
  394. DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC);
  395. /* Check for a bulk endpoint. */
  396. if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) ==
  397. USB_EP_ATTR_XFER_BULK)
  398. {
  399. /* Yes.. it is a bulk endpoint. IN or OUT? */
  400. if (USB_ISEPOUT(epdesc->addr))
  401. {
  402. /* It is an OUT bulk endpoint. There should be only one
  403. * bulk OUT endpoint.
  404. */
  405. if ((found & USBHOST_BOUTFOUND) != 0)
  406. {
  407. /* Oops.. more than one endpoint. We don't know
  408. * what to do with this.
  409. */
  410. return -EINVAL;
  411. }
  412. found |= USBHOST_BOUTFOUND;
  413. /* Save the bulk OUT endpoint information */
  414. boutdesc.hport = hport;
  415. boutdesc.addr = epdesc->addr &
  416. USB_EP_ADDR_NUMBER_MASK;
  417. boutdesc.in = false;
  418. boutdesc.xfrtype = USB_EP_ATTR_XFER_BULK;
  419. boutdesc.interval = epdesc->interval;
  420. boutdesc.mxpacketsize =
  421. usbhost_getle16(epdesc->mxpacketsize);
  422. uinfo("Bulk OUT EP addr:%d mxpacketsize:%d\n",
  423. boutdesc.addr, boutdesc.mxpacketsize);
  424. }
  425. else
  426. {
  427. /* It is an IN bulk endpoint. There should be only one
  428. * bulk IN endpoint.
  429. */
  430. if ((found & USBHOST_BINFOUND) != 0)
  431. {
  432. /* Oops.. more than one endpoint. We don't know
  433. * what to do with this.
  434. */
  435. return -EINVAL;
  436. }
  437. found |= USBHOST_BINFOUND;
  438. /* Save the bulk IN endpoint information */
  439. bindesc.hport = hport;
  440. bindesc.addr = epdesc->addr &
  441. USB_EP_ADDR_NUMBER_MASK;
  442. bindesc.in = 1;
  443. bindesc.xfrtype = USB_EP_ATTR_XFER_BULK;
  444. bindesc.interval = epdesc->interval;
  445. bindesc.mxpacketsize =
  446. usbhost_getle16(epdesc->mxpacketsize);
  447. uinfo("Bulk IN EP addr:%d mxpacketsize:%d\n",
  448. bindesc.addr, bindesc.mxpacketsize);
  449. }
  450. }
  451. }
  452. break;
  453. /* Other descriptors are just ignored for now */
  454. default:
  455. break;
  456. }
  457. /* If we found everything we need with this interface, then break out
  458. * of the loop early.
  459. */
  460. if (found == USBHOST_ALLFOUND)
  461. {
  462. break;
  463. }
  464. /* Increment the address of the next descriptor */
  465. configdesc += desc->len;
  466. remaining -= desc->len;
  467. }
  468. /* Sanity checking... did we find all of things that we need? */
  469. if (found != USBHOST_ALLFOUND)
  470. {
  471. uerr("ERROR: Found IF:%s BIN:%s BOUT:%s\n",
  472. (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO",
  473. (found & USBHOST_BINFOUND) != 0 ? "YES" : "NO",
  474. (found & USBHOST_BOUTFOUND) != 0 ? "YES" : "NO");
  475. return -EINVAL;
  476. }
  477. /* We are good... Allocate the endpoints */
  478. ret = DRVR_EPALLOC(hport->drvr, &boutdesc, &priv->epout);
  479. if (ret < 0)
  480. {
  481. uerr("ERROR: Failed to allocate Bulk OUT endpoint\n");
  482. return ret;
  483. }
  484. ret = DRVR_EPALLOC(hport->drvr, &bindesc, &priv->epin);
  485. if (ret < 0)
  486. {
  487. uerr("ERROR: Failed to allocate Bulk IN endpoint\n");
  488. DRVR_EPFREE(hport->drvr, priv->epout);
  489. return ret;
  490. }
  491. uinfo("Endpoints allocated\n");
  492. return OK;
  493. }
  494. /****************************************************************************
  495. * Name: usbhost_devinit
  496. *
  497. * Description:
  498. * The USB device has been successfully connected. This completes the
  499. * initialization operations. It is first called after the
  500. * configuration descriptor has been received.
  501. *
  502. * This function is called from the connect() method. This function always
  503. * executes on the thread of the caller of connect().
  504. *
  505. * Input Parameters:
  506. * priv - A reference to the class instance.
  507. *
  508. * Returned Value:
  509. * None
  510. *
  511. ****************************************************************************/
  512. static inline int usbhost_devinit(FAR struct usbhost_state_s *priv)
  513. {
  514. int ret = OK;
  515. /* Set aside a transfer buffer for exclusive use by the class driver */
  516. /* Increment the reference count. This will prevent usbhost_destroy() from
  517. * being called asynchronously if the device is removed.
  518. */
  519. priv->crefs++;
  520. DEBUGASSERT(priv->crefs == 2);
  521. /* Configure the device */
  522. /* Register the driver */
  523. if (ret >= 0)
  524. {
  525. char devname[DEV_NAMELEN];
  526. uinfo("Register block driver\n");
  527. usbhost_mkdevname(priv, devname);
  528. #if 0 /* Finish me */
  529. ret = register_blockdriver(devname, &g_bops, 0, priv);
  530. #endif
  531. }
  532. /* Check if we successfully initialized. We now have to be concerned
  533. * about asynchronous modification of crefs because the block
  534. * driver has been registered.
  535. */
  536. if (ret >= 0)
  537. {
  538. ret = usbhost_takesem(&priv->exclsem);
  539. if (ret < 0)
  540. {
  541. return ert;
  542. }
  543. DEBUGASSERT(priv->crefs >= 2);
  544. /* Handle a corner case where (1) open() has been called so the
  545. * reference count is > 2, but the device has been disconnected.
  546. * In this case, the class instance needs to persist until close()
  547. * is called.
  548. */
  549. if (priv->crefs <= 2 && priv->disconnected)
  550. {
  551. /* We don't have to give the semaphore because it will be
  552. * destroyed when usb_destroy is called.
  553. */
  554. ret = -ENODEV;
  555. }
  556. else
  557. {
  558. /* Ready for normal operation as a block device driver */
  559. uinfo("Successfully initialized\n");
  560. priv->crefs--;
  561. usbhost_givesem(&priv->exclsem);
  562. }
  563. }
  564. return ret;
  565. }
  566. /****************************************************************************
  567. * Name: usbhost_getle16
  568. *
  569. * Description:
  570. * Get a (possibly unaligned) 16-bit little endian value.
  571. *
  572. * Input Parameters:
  573. * val - A pointer to the first byte of the little endian value.
  574. *
  575. * Returned Value:
  576. * A uint16_t representing the whole 16-bit integer value
  577. *
  578. ****************************************************************************/
  579. static inline uint16_t usbhost_getle16(const uint8_t *val)
  580. {
  581. return (uint16_t)val[1] << 8 | (uint16_t)val[0];
  582. }
  583. /****************************************************************************
  584. * Name: usbhost_putle16
  585. *
  586. * Description:
  587. * Put a (possibly unaligned) 16-bit little endian value.
  588. *
  589. * Input Parameters:
  590. * dest - A pointer to the first byte to save the little endian value.
  591. * val - The 16-bit value to be saved.
  592. *
  593. * Returned Value:
  594. * None
  595. *
  596. ****************************************************************************/
  597. static void usbhost_putle16(uint8_t *dest, uint16_t val)
  598. {
  599. dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
  600. dest[1] = val >> 8;
  601. }
  602. /****************************************************************************
  603. * Name: usbhost_getle32
  604. *
  605. * Description:
  606. * Get a (possibly unaligned) 32-bit little endian value.
  607. *
  608. * Input Parameters:
  609. * dest - A pointer to the first byte to save the big endian value.
  610. * val - The 32-bit value to be saved.
  611. *
  612. * Returned Value:
  613. * None
  614. *
  615. ****************************************************************************/
  616. static inline uint32_t usbhost_getle32(const uint8_t *val)
  617. {
  618. /* Little endian means LS halfword first in byte stream */
  619. return (uint32_t)usbhost_getle16(&val[2]) << 16 |
  620. (uint32_t)usbhost_getle16(val);
  621. }
  622. /****************************************************************************
  623. * Name: usbhost_putle32
  624. *
  625. * Description:
  626. * Put a (possibly unaligned) 32-bit little endian value.
  627. *
  628. * Input Parameters:
  629. * dest - A pointer to the first byte to save the little endian value.
  630. * val - The 32-bit value to be saved.
  631. *
  632. * Returned Value:
  633. * None
  634. *
  635. ****************************************************************************/
  636. static void usbhost_putle32(uint8_t *dest, uint32_t val)
  637. {
  638. /* Little endian means LS halfword first in byte stream */
  639. usbhost_putle16(dest, (uint16_t)(val & 0xffff));
  640. usbhost_putle16(dest + 2, (uint16_t)(val >> 16));
  641. }
  642. /****************************************************************************
  643. * Name: usbhost_talloc
  644. *
  645. * Description:
  646. * Allocate transfer buffer memory.
  647. *
  648. * Input Parameters:
  649. * priv - A reference to the class instance.
  650. *
  651. * Returned Value:
  652. * On success, zero (OK) is returned. On failure, an negated errno value
  653. * is returned to indicate the nature of the failure.
  654. *
  655. ****************************************************************************/
  656. static inline int usbhost_talloc(FAR struct usbhost_state_s *priv)
  657. {
  658. FAR struct usbhost_hubport_s *hport;
  659. DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL &&
  660. priv->tbuffer == NULL);
  661. hport = priv->usbclass.hport;
  662. return DRVR_ALLOC(hport->drvr, &priv->tbuffer, &priv->tbuflen);
  663. }
  664. /****************************************************************************
  665. * Name: usbhost_tfree
  666. *
  667. * Description:
  668. * Free transfer buffer memory.
  669. *
  670. * Input Parameters:
  671. * priv - A reference to the class instance.
  672. *
  673. * Returned Value:
  674. * On success, zero (OK) is returned. On failure, an negated errno value
  675. * is returned to indicate the nature of the failure.
  676. *
  677. ****************************************************************************/
  678. static inline int usbhost_tfree(FAR struct usbhost_state_s *priv)
  679. {
  680. FAR struct usbhost_hubport_s *hport;
  681. int result = OK;
  682. DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL);
  683. if (priv->tbuffer)
  684. {
  685. hport = priv->usbclass.hport;
  686. result = DRVR_FREE(hport->drvr, priv->tbuffer);
  687. priv->tbuffer = NULL;
  688. priv->tbuflen = 0;
  689. }
  690. return result;
  691. }
  692. /****************************************************************************
  693. * struct usbhost_registry_s methods
  694. ****************************************************************************/
  695. /****************************************************************************
  696. * Name: usbhost_create
  697. *
  698. * Description:
  699. * This function implements the create() method of struct
  700. * usbhost_registry_s. The create() method is a callback into the class
  701. * implementation. It is used to (1) create a new instance of the USB
  702. * host class state and to (2) bind a USB host driver "session" to the
  703. * class instance. Use of this create() method will support environments
  704. * where there may be multiple USB ports and multiple USB devices
  705. * simultaneously connected.
  706. *
  707. * Input Parameters:
  708. * hport - The hub hat manages the new class instance.
  709. * id - In the case where the device supports multiple base classes,
  710. * subclasses, or protocols, this specifies which to configure for.
  711. *
  712. * Returned Value:
  713. * On success, this function will return a non-NULL instance of struct
  714. * usbhost_class_s that can be used by the USB host driver to communicate
  715. * with the USB host class. NULL is returned on failure; this function
  716. * will fail only if the hport input parameter is NULL or if there are
  717. * insufficient resources to create another USB host class instance.
  718. *
  719. ****************************************************************************/
  720. static FAR struct usbhost_class_s *
  721. usbhost_create(FAR struct usbhost_hubport_s *hport,
  722. FAR const struct usbhost_id_s *id)
  723. {
  724. FAR struct usbhost_state_s *priv;
  725. /* Allocate a USB host class instance */
  726. priv = usbhost_allocclass();
  727. if (priv)
  728. {
  729. /* Initialize the allocated storage class instance */
  730. memset(priv, 0, sizeof(struct usbhost_state_s));
  731. /* Assign a device number to this class instance */
  732. if (usbhost_allocdevno(priv) == OK)
  733. {
  734. /* Initialize class method function pointers */
  735. priv->usbclass.hport = hport;
  736. priv->usbclass.connect = usbhost_connect;
  737. priv->usbclass.disconnected = usbhost_disconnected;
  738. /* The initial reference count is 1...
  739. * One reference is held by the driver
  740. */
  741. priv->crefs = 1;
  742. /* Initialize semaphores
  743. * (this works okay in the interrupt context)
  744. */
  745. nxsem_init(&priv->exclsem, 0, 1);
  746. /* Return the instance of the USB class driver */
  747. return &priv->usbclass;
  748. }
  749. }
  750. /* An error occurred. Free the allocation and return NULL on all failures */
  751. if (priv)
  752. {
  753. usbhost_freeclass(priv);
  754. }
  755. return NULL;
  756. }
  757. /****************************************************************************
  758. * struct usbhost_class_s methods
  759. ****************************************************************************/
  760. /****************************************************************************
  761. * Name: usbhost_connect
  762. *
  763. * Description:
  764. * This function implements the connect() method of struct
  765. * usbhost_class_s. This method is a callback into the class
  766. * implementation. It is used to provide the device's configuration
  767. * descriptor to the class so that the class may initialize properly
  768. *
  769. * Input Parameters:
  770. * usbclass - The USB host class entry previously obtained from a call to
  771. * create().
  772. * configdesc - A pointer to a uint8_t buffer container the configuration
  773. * descriptor.
  774. * desclen - The length in bytes of the configuration descriptor.
  775. *
  776. * Returned Value:
  777. * On success, zero (OK) is returned. On a failure, a negated errno value
  778. * is returned indicating the nature of the failure
  779. *
  780. * NOTE that the class instance remains valid upon return with a failure.
  781. * It is the responsibility of the higher level enumeration logic to call
  782. * CLASS_DISCONNECTED to free up the class driver resources.
  783. *
  784. * Assumptions:
  785. * - This function will *not* be called from an interrupt handler.
  786. * - If this function returns an error, the USB host controller driver
  787. * must call to DISCONNECTED method to recover from the error
  788. *
  789. ****************************************************************************/
  790. static int usbhost_connect(FAR struct usbhost_class_s *usbclass,
  791. FAR const uint8_t *configdesc, int desclen)
  792. {
  793. FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)usbclass;
  794. int ret;
  795. DEBUGASSERT(priv != NULL &&
  796. configdesc != NULL &&
  797. desclen >= sizeof(struct usb_cfgdesc_s));
  798. /* Parse the configuration descriptor to get the endpoints */
  799. ret = usbhost_cfgdesc(priv, configdesc, desclen);
  800. if (ret < 0)
  801. {
  802. uerr("ERROR: usbhost_cfgdesc() failed: %d\n", ret);
  803. }
  804. else
  805. {
  806. /* Now configure the device and register the NuttX driver */
  807. ret = usbhost_devinit(priv);
  808. if (ret < 0)
  809. {
  810. uerr("ERROR: usbhost_devinit() failed: %d\n", ret);
  811. }
  812. }
  813. return ret;
  814. }
  815. /****************************************************************************
  816. * Name: usbhost_disconnected
  817. *
  818. * Description:
  819. * This function implements the disconnected() method of struct
  820. * usbhost_class_s. This method is a callback into the class
  821. * implementation. It is used to inform the class that the USB device has
  822. * been disconnected.
  823. *
  824. * Input Parameters:
  825. * usbclass - The USB host class entry previously obtained from a call to
  826. * create().
  827. *
  828. * Returned Value:
  829. * On success, zero (OK) is returned. On a failure, a negated errno value
  830. * is returned indicating the nature of the failure
  831. *
  832. * Assumptions:
  833. * This function may be called from an interrupt handler.
  834. *
  835. ****************************************************************************/
  836. static int usbhost_disconnected(struct usbhost_class_s *usbclass)
  837. {
  838. FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)usbclass;
  839. irqstate_t flags;
  840. DEBUGASSERT(priv != NULL);
  841. /* Set an indication to any users of the device that the device is no
  842. * longer available.
  843. */
  844. flags = enter_critical_section();
  845. priv->disconnected = true;
  846. /* Now check the number of references on the class instance. If it is one,
  847. * then we can free the class instance now. Otherwise, we will have to
  848. * wait until the holders of the references free them by closing the
  849. * block driver.
  850. */
  851. uinfo("crefs: %d\n", priv->crefs);
  852. if (priv->crefs == 1)
  853. {
  854. /* Destroy the class instance. If we are executing from an interrupt
  855. * handler, then defer the destruction to the worker thread.
  856. * Otherwise, destroy the instance now.
  857. */
  858. if (up_interrupt_context())
  859. {
  860. /* Destroy the instance on the worker thread. */
  861. uinfo("Queuing destruction: worker %p->%p\n",
  862. priv->work.worker, usbhost_destroy);
  863. DEBUGASSERT(priv->work.worker == NULL);
  864. work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0);
  865. }
  866. else
  867. {
  868. /* Do the work now */
  869. usbhost_destroy(priv);
  870. }
  871. }
  872. leave_critical_section(flags);
  873. return OK;
  874. }
  875. /****************************************************************************
  876. * Public Functions
  877. ****************************************************************************/
  878. /****************************************************************************
  879. * Name: usbhost_skelinit
  880. *
  881. * Description:
  882. * Initialize the USB class driver. This function should be called
  883. * be platform-specific code in order to initialize and register support
  884. * for the USB host class device.
  885. *
  886. * Input Parameters:
  887. * None
  888. *
  889. * Returned Value:
  890. * On success this function will return zero (OK); A negated errno value
  891. * will be returned on failure.
  892. *
  893. ****************************************************************************/
  894. int usbhost_skelinit(void)
  895. {
  896. /* Perform any one-time initialization of the class implementation */
  897. /* Advertise our availability to support (certain) devices */
  898. return usbhost_registerclass(&g_skeleton);
  899. }