usbhost_devaddr.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /****************************************************************************
  2. * drivers/usbhost/usbhost_devaddr.c
  3. * Manage USB device addresses
  4. *
  5. * Copyright (C) 2013, 2015 Gregory Nutt. All rights reserved.
  6. * Authors: Gregory Nutt <gnutt@nuttx.org>
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. * 3. Neither the name NuttX nor the names of its contributors may be
  19. * used to endorse or promote products derived from this software
  20. * without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  25. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  26. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  27. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  28. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  29. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  30. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  32. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. *
  35. ****************************************************************************/
  36. /****************************************************************************
  37. * Included Files
  38. ****************************************************************************/
  39. #include <nuttx/config.h>
  40. #include <string.h>
  41. #include <errno.h>
  42. #include <debug.h>
  43. #include <nuttx/kmalloc.h>
  44. #include <nuttx/usb/usbhost.h>
  45. #include <nuttx/usb/usbhost_devaddr.h>
  46. /****************************************************************************
  47. * Pre-processor Definitions
  48. ****************************************************************************/
  49. /****************************************************************************
  50. * Private Functions
  51. ****************************************************************************/
  52. /****************************************************************************
  53. * Name: usbhost_takesem and usbhost_givesem
  54. *
  55. * Description:
  56. * This is just a wrapper to handle the annoying behavior of semaphore
  57. * waits that return due to the receipt of a signal.
  58. *
  59. ****************************************************************************/
  60. static void usbhost_takesem(FAR struct usbhost_devaddr_s *devgen)
  61. {
  62. /* Take the semaphore (perhaps waiting) */
  63. while (sem_wait(&devgen->exclsem) != 0)
  64. {
  65. /* The only case that an error should occur here is if the wait was
  66. * awakened by a signal.
  67. */
  68. ASSERT(errno == EINTR);
  69. }
  70. }
  71. #define usbhost_givesem(devgen) sem_post(&devgen->exclsem)
  72. /****************************************************************************
  73. * Name: usbhost_devaddr_allocate
  74. *
  75. * Description:
  76. * Allocate a new unique device address.
  77. *
  78. * Assumptions:
  79. * Caller hold the exclsem
  80. *
  81. ****************************************************************************/
  82. static int usbhost_devaddr_allocate(FAR struct usbhost_devaddr_s *devgen)
  83. {
  84. uint8_t startaddr = devgen->next;
  85. uint8_t devaddr;
  86. int index;
  87. int bitno;
  88. /* Loop until we find a valid device address */
  89. for (; ; )
  90. {
  91. /* Try the next device address */
  92. devaddr = devgen->next;
  93. if (devgen->next >= 0x7f)
  94. {
  95. devgen->next = 1;
  96. }
  97. else
  98. {
  99. devgen->next++;
  100. }
  101. /* Is this address already allocated? */
  102. index = devaddr >> 5;
  103. bitno = devaddr & 0x1f;
  104. if ((devgen->alloctab[index] & (1 << bitno)) == 0)
  105. {
  106. /* No... allocate it now */
  107. devgen->alloctab[index] |= (1 << bitno);
  108. return (int)devaddr;
  109. }
  110. /* This address has already been allocated. The followign logic will
  111. * prevent (unexpected) infinite loops.
  112. */
  113. if (startaddr == devaddr)
  114. {
  115. /* We are back where we started... the are no free device address */
  116. return -ENOMEM;
  117. }
  118. }
  119. }
  120. /****************************************************************************
  121. * Name: usbhost_devaddr_free
  122. *
  123. * Description:
  124. * De-allocate a device address.
  125. *
  126. * Assumptions:
  127. * Caller hold the exclsem
  128. *
  129. ****************************************************************************/
  130. static void usbhost_devaddr_free(FAR struct usbhost_devaddr_s *devgen,
  131. uint8_t devaddr)
  132. {
  133. int index;
  134. int bitno;
  135. /* Free the address by clearing the associated bit in the alloctab[]; */
  136. index = devaddr >> 5;
  137. bitno = devaddr & 0x1f;
  138. DEBUGASSERT((devgen->alloctab[index] |= (1 << bitno)) != 0);
  139. devgen->alloctab[index] &= ~(1 << bitno);
  140. /* Reset the next pointer if the one just released has a lower value */
  141. if (devaddr < devgen->next)
  142. {
  143. devgen->next = devaddr;
  144. }
  145. }
  146. /****************************************************************************
  147. * Name: usbhost_roothubport
  148. *
  149. * Description:
  150. * Find and return a reference the root hub port.
  151. *
  152. ****************************************************************************/
  153. static inline FAR struct usbhost_roothubport_s *
  154. usbhost_roothubport(FAR struct usbhost_hubport_s *hport)
  155. {
  156. #ifdef CONFIG_USBHOST_HUB
  157. /* If this is a root hub port then the parent port pointer will be NULL.
  158. * Otherwise, we need to traverse the parent pointer list until we find the
  159. * root hub port.
  160. */
  161. while (hport->parent != NULL)
  162. {
  163. /* This is not a root hub port. It is a port on a hub. Try the port of
  164. * the parent hub that supports this port.
  165. */
  166. hport = hport->parent;
  167. }
  168. #endif
  169. return (FAR struct usbhost_roothubport_s *)hport;
  170. }
  171. /****************************************************************************
  172. * Name: usbhost_devaddr_gen
  173. *
  174. * Description:
  175. * Find root hub port and return a reference to the device function address
  176. * data set.
  177. *
  178. ****************************************************************************/
  179. static FAR struct usbhost_devaddr_s *
  180. usbhost_devaddr_gen(FAR struct usbhost_hubport_s *hport)
  181. {
  182. FAR struct usbhost_roothubport_s *rhport;
  183. rhport = usbhost_roothubport(hport);
  184. if (rhport != NULL)
  185. {
  186. return &rhport->devgen;
  187. }
  188. return NULL;
  189. }
  190. /****************************************************************************
  191. * Public Functions
  192. ****************************************************************************/
  193. /****************************************************************************
  194. * Name: usbhost_devaddr_initialize
  195. *
  196. * Description:
  197. * Initialize the caller provided struct usbhost_devaddr_s instance in
  198. * preparation for the management of device addresses on behalf of an root
  199. * hub port.
  200. *
  201. * Input Parameters:
  202. * rhport - A reference to a roothubport structure.
  203. *
  204. * Returned Value:
  205. * None
  206. *
  207. ****************************************************************************/
  208. void usbhost_devaddr_initialize(FAR struct usbhost_roothubport_s *rhport)
  209. {
  210. FAR struct usbhost_devaddr_s *devgen;
  211. DEBUGASSERT(rhport);
  212. devgen = &rhport->devgen;
  213. memset(devgen, 0, sizeof(struct usbhost_devaddr_s));
  214. sem_init(&devgen->exclsem, 0, 1);
  215. devgen->next = 1;
  216. }
  217. /****************************************************************************
  218. * Name: usbhost_devaddr_create
  219. *
  220. * Description:
  221. * Create a new unique device address for this hub port.
  222. *
  223. * Input Parameters:
  224. * hport - A reference to a hub port structure to which a device has been
  225. * newly connected and so is in need of a function address.
  226. *
  227. * Returned Value:
  228. * On success, a new device function address in the range 0x01 to 0x7f
  229. * is returned. On failure, a negated errno value is returned.
  230. *
  231. ****************************************************************************/
  232. int usbhost_devaddr_create(FAR struct usbhost_hubport_s *hport)
  233. {
  234. FAR struct usbhost_devaddr_s *devgen;
  235. int devaddr;
  236. /* Get the address generation data from the root hub port */
  237. DEBUGASSERT(hport);
  238. devgen = usbhost_devaddr_gen(hport);
  239. DEBUGASSERT(devgen);
  240. /* Get exclusive access to the root hub port device address data */
  241. usbhost_takesem(devgen);
  242. /* Allocate a device address */
  243. devaddr = usbhost_devaddr_allocate(devgen);
  244. usbhost_givesem(devgen);
  245. if (devaddr < 0)
  246. {
  247. uerr("ERROR: Failed to allocate a device address\n");
  248. }
  249. return devaddr;
  250. }
  251. /****************************************************************************
  252. * Name: usbhost_devaddr_destroy
  253. *
  254. * Description:
  255. * Release a device address previously assigned by usbhost_devaddr_create().
  256. *
  257. * Input Parameters:
  258. * hport - A reference to a hub port structure from which a device has been
  259. * disconnected and so no longer needs the function address.
  260. * devaddr - The address to be released.
  261. *
  262. * Returned Value:
  263. * None
  264. *
  265. ****************************************************************************/
  266. void usbhost_devaddr_destroy(FAR struct usbhost_hubport_s *hport, uint8_t devaddr)
  267. {
  268. FAR struct usbhost_devaddr_s *devgen;
  269. /* Ignore bad device address */
  270. if (devaddr > 0 && devaddr < 0x7f)
  271. {
  272. /* Get the address generation data from the root hub port */
  273. DEBUGASSERT(hport);
  274. devgen = usbhost_devaddr_gen(hport);
  275. DEBUGASSERT(devgen);
  276. /* Get exclusive access to the root hub port device address data */
  277. usbhost_takesem(devgen);
  278. /* Free the device address */
  279. usbhost_devaddr_free(devgen, devaddr);
  280. usbhost_givesem(devgen);
  281. }
  282. }