fusb_hub.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. * Copyright : (C) 2022 Phytium Information Technology, Inc.
  3. * All Rights Reserved.
  4. *
  5. * This program is OPEN SOURCE software: you can redistribute it and/or modify it
  6. * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
  7. * either version 1.0 of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
  10. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. * See the Phytium Public License for more details.
  12. *
  13. *
  14. * FilePath: fusb_hub.c
  15. * Date: 2022-02-11 13:33:07
  16. * LastEditTime: 2022-02-17 17:48:52
  17. * Description:  This files is for implmentation of USB hub function
  18. * you may refer to chapter 11 Hub specification for details
  19. *
  20. * Modify History:
  21. * Ver   Who        Date         Changes
  22. * ----- ------     --------    --------------------------------------
  23. * 1.0 Zhugengyu 2022/2/7 init commit
  24. */
  25. #include "fkernel.h"
  26. #include "fdebug.h"
  27. #include "fassert.h"
  28. #include "fusb_private.h"
  29. #include "fusb_generic_hub.h"
  30. #define FUSB_DEBUG_TAG "FUSB_HUB"
  31. #define FUSB_ERROR(format, ...) FT_DEBUG_PRINT_E(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
  32. #define FUSB_WARN(format, ...) FT_DEBUG_PRINT_W(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
  33. #define FUSB_INFO(format, ...) FT_DEBUG_PRINT_I(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
  34. #define FUSB_DEBUG(format, ...) FT_DEBUG_PRINT_D(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
  35. /* assume that FUSB_REQ_HOST_TO_DEVICE is overwritten if necessary */
  36. #define DR_PORT FUsbGenerateReqType(FUSB_REQ_HOST_TO_DEVICE, FUSB_REQ_TYPE_CLASS, FUSB_REQ_RECP_OTHER) /* 10100011B */
  37. #define DR_HUB FUsbGenerateReqType(FUSB_REQ_HOST_TO_DEVICE, FUSB_REQ_TYPE_CLASS, FUSB_REQ_RECP_DEV) /* 10100000B */
  38. #define FUSB_HUB_PORT_STATUS 0
  39. #define FUSB_HUB_PORT_CHANGE 1
  40. #define FUSB_HUB_PORT_BUF_LEN 2
  41. /* status (and status change) bits, refer to Table 10-10, Port Status Field in USB spec */
  42. #define FUSB_HUB_STATUS_PORT_CONNECTION BIT(0) /* reflects if device is currently connected to this port */
  43. #define FUSB_HUB_STATUS_PORT_ENABLE BIT(1) /* reflects if this port is enabled */
  44. #define FUSB_HUB_STATUS_PORT_SUSPEND BIT(2) /* reflects if this port is suspend, only for USB2 */
  45. #define FUSB_HUB_STATUS_PORT_OVER_CURRENT BIT(3) /* reports over-current conditions in this port */
  46. #define FUSB_HUB_STATUS_PORT_RESET BIT(4) /* reset signaling asserted */
  47. #define FUSB_HUB_STATUS_BH_PORT_RESET BIT(5) /* warm reset completed */
  48. #define FUSB_HUB_STATUS_PORT_LINK_STATE BIT(6) /* link state changed */
  49. #define FUSB_HUB_STATUS_PORT_PORT_CONFIG_ERROR BIT(7) /* port fails to config */
  50. /* feature selectors (for setting / clearing features), refer to USB spec. Table 10-17. Hub Class Feature Selectors for details */
  51. #define FUSB_HUB_SEL_PORT_RESET 4
  52. #define FUSB_HUB_SEL_PORT_POWER 8
  53. #define FUSB_HUB_SEL_C_PORT_CONNECTION 16
  54. #define FUSB_HUB_SEL_C_PORT_ENABLE 17 /* USB2 only */
  55. #define FUSB_HUB_SEL_C_PORT_SUSPEND 18 /* USB2 only */
  56. #define FUSB_HUB_SEL_C_PORT_OVER_CURRENT 19
  57. #define FUSB_HUB_SEL_C_PORT_RESET 20
  58. #define FUSB_HUB_SEL_C_PORT_LINK_STATE 25
  59. #define FUSB_HUB_SEL_C_PORT_CONFIG_ERROR 26
  60. #define FUSB_HUB_SEL_C_BH_PORT_RESET 27
  61. /* request type (USB 3.0 hubs only) */
  62. #define SET_HUB_DEPTH 12
  63. /**
  64. * @name: FUsbHubIntrEp
  65. * @msg: 获取USB Hub的中断端点
  66. * @return {FUsbEndpoint *} 中断类型的功能端点
  67. * @param {FUsbDev} *dev, Hub实例
  68. */
  69. static FUsbEndpoint *FUsbHubIntrEp(FUsbDev *const dev)
  70. {
  71. FASSERT(dev);
  72. int i;
  73. for (i = 0; i < dev->num_endp; ++i)
  74. {
  75. if (dev->endpoints[i].type == FUSB_INTERRUPT_EP &&
  76. dev->endpoints[i].direction == FUSB_IN)
  77. return &dev->endpoints[i];
  78. }
  79. return NULL;
  80. }
  81. /**
  82. * @name: FUsbHubPortStatusChange
  83. * @msg: Usb Hub的Port状态变化回调函数
  84. * @return {FUsbTransCode} USB请求返回值
  85. * @param {FUsbDev} *dev, Hub实例
  86. * @param {int} port, Port号
  87. */
  88. static FUsbTransCode FUsbHubPortStatusChange(FUsbDev *const dev, const int port)
  89. {
  90. FASSERT(dev);
  91. unsigned short buf[FUSB_HUB_PORT_BUF_LEN]; /* Hub Status and Change Status */
  92. FUsbTransCode ret = FUsbGetStatus(dev, port, DR_PORT, sizeof(buf), buf);
  93. if (ret >= FUSB_CC_ZERO_BYTES)
  94. {
  95. ret = buf[FUSB_HUB_PORT_CHANGE] & FUSB_HUB_STATUS_PORT_CONNECTION;
  96. if (ret)
  97. {
  98. ret = FUsbClearFeature(dev, port, FUSB_HUB_SEL_C_PORT_CONNECTION, DR_PORT);
  99. }
  100. }
  101. return ret;
  102. }
  103. /**
  104. * @name: FUsbHubPortConnected
  105. * @msg: Usb Hub的Port连接回调函数
  106. * @return {FUsbTransCode} USB请求返回值
  107. * @param {FUsbDev} *dev, Hub实例
  108. * @param {int} port, Port号
  109. */
  110. static FUsbTransCode FUsbHubPortConnected(FUsbDev *const dev, const int port)
  111. {
  112. FASSERT(dev);
  113. unsigned short buf[FUSB_HUB_PORT_BUF_LEN]; /* Hub Status and Change Status */
  114. FUsbTransCode ret = FUsbGetStatus(dev, port, DR_PORT, sizeof(buf), buf);
  115. if (ret >= FUSB_CC_ZERO_BYTES)
  116. {
  117. ret = buf[FUSB_HUB_PORT_STATUS] & FUSB_HUB_STATUS_PORT_CONNECTION;
  118. }
  119. return ret;
  120. }
  121. /**
  122. * @name: FUsbHubPortInReset
  123. * @msg: 检查Hub port是否处于Reset状态
  124. * @return {FUsbTransCode} USB请求返回值
  125. * @param {FUsbDev} *dev, Hub实例
  126. * @param {int} port, Port号
  127. */
  128. static FUsbTransCode FUsbHubPortInReset(FUsbDev *const dev, const int port)
  129. {
  130. FASSERT(dev);
  131. unsigned short buf[FUSB_HUB_PORT_BUF_LEN]; /* Hub Status and Change Status */
  132. FUsbTransCode ret = FUsbGetStatus(dev, port, DR_PORT, sizeof(buf), buf);
  133. if (ret >= FUSB_CC_ZERO_BYTES)
  134. ret = buf[FUSB_HUB_PORT_STATUS] & FUSB_HUB_STATUS_PORT_RESET;
  135. return ret;
  136. }
  137. /**
  138. * @name: FUsbHubPortEnabled
  139. * @msg: 检查Hub port是否已使能
  140. * @return {FUsbTransCode} USB请求返回值
  141. * @param {FUsbDev} *dev, Hub实例
  142. * @param {int} port, Port号
  143. */
  144. static FUsbTransCode FUsbHubPortEnabled(FUsbDev *const dev, const int port)
  145. {
  146. FASSERT(dev);
  147. unsigned short buf[FUSB_HUB_PORT_BUF_LEN]; /* Hub Status and Change Status */
  148. FUsbTransCode ret = FUsbGetStatus(dev, port, DR_PORT, sizeof(buf), buf);
  149. if (ret >= FUSB_CC_ZERO_BYTES)
  150. ret = buf[FUSB_HUB_PORT_STATUS] & FUSB_HUB_STATUS_PORT_ENABLE;
  151. return ret;
  152. }
  153. /**
  154. * @name: FUsbHubPortSpeed
  155. * @msg: 获取Hub port的速度类型
  156. * @return {FUsbSpeed} Port的速度类型,支持SuperSpeed和HighSpeed
  157. * @param {FUsbDev} *dev, Hub实例
  158. * @param {int} port, Port号
  159. */
  160. static FUsbSpeed FUsbHubPortSpeed(FUsbDev *const dev, const int port)
  161. {
  162. FASSERT(dev);
  163. unsigned short buf[FUSB_HUB_PORT_BUF_LEN]; /* Hub Status and Change Status */
  164. FUsbTransCode ret = FUsbGetStatus(dev, port, DR_PORT, sizeof(buf), buf);
  165. int speed;
  166. if (ret >= FUSB_CC_ZERO_BYTES && (buf[FUSB_HUB_PORT_STATUS] & FUSB_HUB_STATUS_PORT_ENABLE))
  167. {
  168. /* SuperSpeed hubs can only have SuperSpeed devices. */
  169. if (FUsbIsSuperSpeed(dev->speed))
  170. return dev->speed;
  171. /*[bit] 10 9 (USB 2.0 port status word)
  172. * 0 0 full speed
  173. * 0 1 low speed
  174. * 1 0 high speed
  175. * 1 1 invalid
  176. */
  177. speed = (buf[FUSB_HUB_PORT_STATUS] >> 9) & 0x3;
  178. if (speed != 0x3) /* high-speed device */
  179. return speed;
  180. }
  181. return FUSB_UNKNOWN_SPEED;
  182. }
  183. /**
  184. * @name: FUsbHubEnablePort
  185. * @msg: 使能Hub port
  186. * @return {FUsbTransCode} USB请求返回值
  187. * @param {FUsbDev} *dev, Hub实例
  188. * @param {int} port, port号
  189. */
  190. static FUsbTransCode FUsbHubEnablePort(FUsbDev *const dev, const int port)
  191. {
  192. FASSERT(dev);
  193. return FUsbSetFeature(dev, port, FUSB_HUB_SEL_PORT_POWER, DR_PORT);
  194. }
  195. /**
  196. * @name: FUsbHubStartPortReset
  197. * @msg: 开始Reset Hub port
  198. * @return {FUsbTransCode} USB请求返回值
  199. * @param {FUsbDev} *dev, Hub实例
  200. * @param {int} port, port号
  201. */
  202. static FUsbTransCode FUsbHubStartPortReset(FUsbDev *const dev, const int port)
  203. {
  204. FASSERT(dev);
  205. return FUsbSetFeature(dev, port, FUSB_HUB_SEL_PORT_RESET, DR_PORT);
  206. }
  207. static void FUsbHubSetHubDepth(FUsbDev *const dev)
  208. {
  209. FASSERT(dev);
  210. FUsbDevReq dr =
  211. {
  212. .bmRequestType = FUsbGenerateReqType(FUSB_REQ_HOST_TO_DEVICE,
  213. FUSB_REQ_TYPE_CLASS, FUSB_REQ_RECP_DEV),
  214. .bRequest = SET_HUB_DEPTH,
  215. .wValue = 0,
  216. .wIndex = 0,
  217. .wLength = 0,
  218. };
  219. FUsbDev *parent = dev;
  220. FASSERT(dev->controller);
  221. while (parent->hub > 0)
  222. {
  223. FASSERT(dev->controller->devices[parent->hub]);
  224. parent = dev->controller->devices[parent->hub];
  225. dr.wValue++;
  226. }
  227. FUsbTransCode ret = dev->controller->control(dev, FUSB_OUT, sizeof(dr), &dr, 0, NULL);
  228. if (ret < FUSB_CC_ZERO_BYTES)
  229. {
  230. FUSB_ERROR("Failed SET_HUB_DEPTH(%d) on hub %d: %d ",
  231. dr.wValue, dev->address, ret);
  232. }
  233. return;
  234. }
  235. static const FUsbGenericHubOps FUSB_HUB_OPS =
  236. {
  237. .hub_status_changed = NULL,
  238. .port_status_changed = FUsbHubPortStatusChange,
  239. .port_connected = FUsbHubPortConnected,
  240. .port_in_reset = FUsbHubPortInReset,
  241. .port_enabled = FUsbHubPortEnabled,
  242. .port_speed = FUsbHubPortSpeed,
  243. .enable_port = FUsbHubEnablePort,
  244. .disable_port = NULL,
  245. .start_port_reset = FUsbHubStartPortReset,
  246. .reset_port = FUsbGenericHubResetPort,
  247. };
  248. /* Clear CSC if set and enumerate port if it's connected regardless of change
  249. bits. Some broken hubs don't set CSC if already connected during reset. */
  250. static void FUsbHubPortInit(FUsbDev *const dev, const int port)
  251. {
  252. FASSERT(dev);
  253. unsigned short buf[FUSB_HUB_PORT_BUF_LEN]; /* Hub Status and Change Status */
  254. FUsbTransCode ret = FUsbGetStatus(dev, port, DR_PORT, sizeof(buf), buf);
  255. if (ret < FUSB_CC_ZERO_BYTES)
  256. return;
  257. if (buf[FUSB_HUB_PORT_CHANGE] & FUSB_HUB_STATUS_PORT_CONNECTION)
  258. FUsbClearFeature(dev, port, FUSB_HUB_SEL_C_PORT_CONNECTION, DR_PORT);
  259. if (buf[FUSB_HUB_PORT_STATUS] & FUSB_HUB_STATUS_PORT_CONNECTION)
  260. {
  261. FUSB_INFO("usbhub: Port coldplug at %d ", port);
  262. FUsbGenericHubScanPort(dev, port);
  263. }
  264. return;
  265. }
  266. /**
  267. * @name: FUsbHubHandlePortChange
  268. * @msg: Hub端口状态变化的处理回调函数
  269. * @return {*}
  270. * @param {FUsbDev} *dev
  271. * @param {int} port
  272. */
  273. static FUsbTransCode FUsbHubHandlePortChange(FUsbDev *const dev, const int port)
  274. {
  275. FASSERT(dev);
  276. static const struct
  277. {
  278. unsigned short change_bit;
  279. unsigned short clear_sel;
  280. } change_bits[] =
  281. {
  282. {FUSB_HUB_STATUS_PORT_CONNECTION, FUSB_HUB_SEL_C_PORT_CONNECTION},
  283. {FUSB_HUB_STATUS_PORT_ENABLE, FUSB_HUB_SEL_C_PORT_ENABLE},
  284. {FUSB_HUB_STATUS_PORT_SUSPEND, FUSB_HUB_SEL_C_PORT_SUSPEND},
  285. {FUSB_HUB_STATUS_PORT_OVER_CURRENT, FUSB_HUB_SEL_C_PORT_OVER_CURRENT},
  286. {FUSB_HUB_STATUS_PORT_RESET, FUSB_HUB_SEL_C_PORT_RESET},
  287. {FUSB_HUB_STATUS_BH_PORT_RESET, FUSB_HUB_SEL_C_BH_PORT_RESET},
  288. {FUSB_HUB_STATUS_PORT_LINK_STATE, FUSB_HUB_SEL_C_PORT_LINK_STATE},
  289. {FUSB_HUB_STATUS_PORT_PORT_CONFIG_ERROR, FUSB_HUB_SEL_C_PORT_CONFIG_ERROR},
  290. };
  291. FUsbTransCode ret = 0;
  292. unsigned int i;
  293. unsigned short checked_bits = 0;
  294. unsigned short buf[FUSB_HUB_PORT_BUF_LEN] = {0, 0}; /* Hub Status and Change Status */
  295. ret = FUsbGetStatus(dev, port, DR_PORT, sizeof(buf), buf);
  296. if (ret < FUSB_CC_ZERO_BYTES)
  297. return ret;
  298. /*
  299. * Second word holds the change bits. The interrupt transfer shows
  300. * a logical or of these bits, so we have to clear them all.
  301. */
  302. for (i = 0; i < ARRAY_SIZE(change_bits); ++i)
  303. {
  304. if (buf[FUSB_HUB_PORT_CHANGE] & change_bits[i].change_bit)
  305. {
  306. /* clear feature if specific change bit = 1 */
  307. FUsbClearFeature(dev, port, change_bits[i].clear_sel, DR_PORT);
  308. }
  309. checked_bits |= change_bits[i].change_bit;
  310. }
  311. if (buf[FUSB_HUB_PORT_CHANGE] & ~checked_bits)
  312. FUSB_DEBUG("Spurious change bit at port %d ", port);
  313. /* Now, handle connection changes. */
  314. if (buf[FUSB_HUB_PORT_CHANGE] & FUSB_HUB_STATUS_PORT_CONNECTION)
  315. {
  316. FUSB_DEBUG("Port change at %d ", port);
  317. ret = FUsbGenericHubScanPort(dev, port);
  318. }
  319. return ret;
  320. }
  321. /**
  322. * @name: FUsbHubPoll
  323. * @msg: 轮询Hub的所有端口,检查端口状态变化
  324. * @return {*}
  325. * @param {FUsbDev} *dev, Hub设备实例
  326. */
  327. static void FUsbHubPoll(FUsbDev *const dev)
  328. {
  329. FASSERT(dev);
  330. int port, i;
  331. u8 buf[32] = {0};
  332. const u8 *ibuf;
  333. /* First, gather all change bits from finished interrupt transfers. */
  334. const size_t port_bytes = min(ARRAY_SIZE(buf),
  335. (size_t)DIV_ROUND_UP(FUSB_GEN_HUB_GET(dev)->num_ports + 1, 8));
  336. while (NULL != (ibuf = dev->controller->poll_intr_queue(FUSB_GEN_HUB_GET(dev)->data)))
  337. {
  338. for (i = 0; (size_t)i < port_bytes; ++i)
  339. buf[i] |= ibuf[i];
  340. }
  341. for (port = 1; port <= FUSB_GEN_HUB_GET(dev)->num_ports; ++port)
  342. {
  343. /* ports start at bit1; bit0 is hub status change */
  344. if (buf[port / 8] & (1 << (port % 8)))
  345. {
  346. if (FUsbHubHandlePortChange(dev, port) < 0)
  347. return;
  348. }
  349. }
  350. return;
  351. }
  352. /**
  353. * @name: FUsbHubDestory
  354. * @msg: USB Hub的去初始化函数
  355. * @return {*}
  356. * @param {FUsbDev} *dev, Hub设备实例
  357. */
  358. static void FUsbHubDestory(FUsbDev *const dev)
  359. {
  360. FASSERT(dev);
  361. FUsbEndpoint *const intr_ep = FUsbHubIntrEp(dev);
  362. FASSERT(intr_ep); /* interrupt ep must exists */
  363. dev->controller->destroy_intr_queue(intr_ep, FUSB_GEN_HUB_GET(dev)->data);
  364. FUsbGenericHubDestory(dev);
  365. }
  366. /**
  367. * @name: FUsbHubInit
  368. * @msg: USB Hub的初始化函数,由应用程序注册到FUSB框架中
  369. * @return {*}
  370. * @param {FUsbDev} *dev, Hub设备实例
  371. */
  372. void FUsbHubInit(FUsbDev *dev)
  373. {
  374. FASSERT(dev);
  375. FUsbEndpoint *const intr_ep = FUsbHubIntrEp(dev); /* get the first intrrupt ep found */
  376. if (NULL == intr_ep)
  377. {
  378. FUSB_ERROR("No interrupt-in endpoint found ");
  379. return;
  380. }
  381. FASSERT(dev->controller);
  382. /* Get number of ports from hub descriptor */
  383. int type = FUsbIsSuperSpeed(dev->speed) ? FUSB_DESC_TYPE_SUPER_SPEED_HUB : FUSB_DESC_TYPE_HUB; /* similar enough */
  384. FUsbHubDescriptor desc; /* won't fit the whole thing, we don't care */
  385. if (FUsbGetDescriptor(dev, FUsbGenerateReqType(FUSB_REQ_DEVICE_TO_HOST, FUSB_REQ_TYPE_CLASS, FUSB_REQ_RECP_DEV), type, 0, &desc, sizeof(desc)) != sizeof(desc))
  386. {
  387. FUSB_ERROR("FUsbGetDescriptor(HUB) failed ");
  388. FUsbDetachDev(dev->controller, dev->address);
  389. return;
  390. }
  391. if (FUsbIsSuperSpeed(dev->speed))
  392. {
  393. FUsbHubSetHubDepth(dev);
  394. }
  395. /*
  396. * Register interrupt transfer:
  397. * one bit per port + one bit for the hub,
  398. * 20 transfers in the queue, like our HID driver,
  399. * one transfer per 256ms
  400. */
  401. void *const intrq = dev->controller->create_intr_queue(
  402. intr_ep, intr_ep->maxpacketsize, 20, 256);
  403. if (NULL == intrq)
  404. {
  405. FUsbDetachDev(dev->controller, dev->address);
  406. return;
  407. }
  408. /*
  409. * Limit the number of ports by the max packet size of
  410. * the interrupt endpoint. This shouldn't be necessary
  411. * but prevents a potential overflow in FUsbHubPoll().
  412. */
  413. const unsigned int num_ports =
  414. min((int)desc.bNbrPorts, intr_ep->maxpacketsize * 8 - 1);
  415. if (FUsbGenericHubInit(dev, num_ports, &FUSB_HUB_OPS))
  416. {
  417. dev->controller->destroy_intr_queue(intr_ep, intrq);
  418. FUsbDetachDev(dev->controller, dev->address);
  419. return;
  420. }
  421. unsigned int port;
  422. for (port = 1; port <= num_ports; ++port)
  423. {
  424. FUsbHubPortInit(dev, port);
  425. }
  426. FUSB_GEN_HUB_GET(dev)->data = intrq;
  427. dev->poll = FUsbHubPoll;
  428. dev->destroy = FUsbHubDestory;
  429. return;
  430. }