fxhci_dev.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  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: fxhci_dev.c
  15. * Date: 2022-02-11 13:33:12
  16. * LastEditTime: 2022-02-18 09:12:46
  17. * Description:  This files is for implementation of XHCI device
  18. *
  19. * Modify History:
  20. * Ver   Who        Date         Changes
  21. * ----- ------     --------    --------------------------------------
  22. * 1.0 Zhugengyu 2022/2/7 init commit
  23. */
  24. #include <string.h>
  25. #include "fsleep.h"
  26. #include "fcache.h"
  27. #include "fdebug.h"
  28. #include "fxhci_private.h"
  29. #define FUSB_DEBUG_TAG "FXHCI_DEV"
  30. #define FUSB_ERROR(format, ...) FT_DEBUG_PRINT_E(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
  31. #define FUSB_WARN(format, ...) FT_DEBUG_PRINT_W(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
  32. #define FUSB_INFO(format, ...) FT_DEBUG_PRINT_I(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
  33. #define FUSB_DEBUG(format, ...) FT_DEBUG_PRINT_D(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
  34. static u32 FXhciGenRounte(FXhci *const xhci, const int hubport, const int hubaddr)
  35. {
  36. FASSERT(xhci);
  37. if (!hubaddr)
  38. return 0;
  39. u32 route_string = FXHCI_SC_GET(ROUTE, xhci->dev[hubaddr].ctx.slot);
  40. int i;
  41. for (i = 0; i < 20; i += 4)
  42. {
  43. if (!(route_string & (0xf << i)))
  44. {
  45. route_string |= (hubport & 0xf) << i;
  46. break;
  47. }
  48. }
  49. return route_string;
  50. }
  51. static int FXhciGetRoothubPort(FXhci *const xhci, const int hubport, const int hubaddr)
  52. {
  53. FASSERT(xhci);
  54. if (!hubaddr)
  55. return hubport;
  56. return FXHCI_SC_GET(RHPORT, xhci->dev[hubaddr].ctx.slot);
  57. }
  58. static int FXhciGetTT(FXhci *const xhci, const FUsbSpeed speed,
  59. const int hubport, const int hubaddr,
  60. int *const tt, int *const tt_port)
  61. {
  62. FASSERT(xhci);
  63. if (!hubaddr)
  64. return 0;
  65. const FXhciSlotCtx *const slot = xhci->dev[hubaddr].ctx.slot;
  66. if ((*tt = FXHCI_SC_GET(TTID, slot)))
  67. {
  68. *tt_port = FXHCI_SC_GET(TTPORT, slot);
  69. }
  70. else if (speed < FUSB_HIGH_SPEED &&
  71. FXHCI_SC_GET(SPEED1, slot) - 1 == FUSB_HIGH_SPEED)
  72. {
  73. *tt = hubaddr;
  74. *tt_port = hubport;
  75. }
  76. return *tt != 0;
  77. }
  78. static void FXhciReapSlots(FXhci *const xhci, int skip_slot)
  79. {
  80. FASSERT(xhci);
  81. int i;
  82. FUsb *instance = xhci->usb;
  83. FUSB_INFO("xHC resource shortage, trying to reap old slots... ");
  84. for (i = 1; i <= xhci->max_slots_en; i++)
  85. {
  86. if (i == skip_slot)
  87. continue; /* don't reap slot we were working on */
  88. if (xhci->dev[i].transfer_rings[1])
  89. continue; /* slot still in use */
  90. if (NULL == xhci->dev[i].ctx.raw)
  91. continue; /* slot already disabled */
  92. const FXhciTransCode cc = FXhciCmdDisableSlot(xhci, i);
  93. if (cc != FXHCI_CC_SUCCESS)
  94. FUSB_INFO("Failed to disable slot %d: %d ", i, cc);
  95. else
  96. FUSB_INFO("Successfully reaped slot %d ", i);
  97. xhci->dcbaa[i] = 0;
  98. FUSB_FREE(instance, xhci->dev[i].ctx.raw);
  99. xhci->dev[i].ctx.raw = NULL;
  100. }
  101. }
  102. static FXhciInputCtx *FXhciMakeInputCtx(FXhci *xhci, const size_t ctxsize)
  103. {
  104. int i;
  105. const size_t size = (1 + FXHCI_NUM_EPS) * ctxsize;
  106. FUsb *instance = xhci->usb;
  107. FXhciInputCtx *const ic = FUSB_ALLOCATE(instance, sizeof(*ic), FUSB_DEFAULT_ALIGN);
  108. void *dma_buffer = FUSB_ALLOCATE(instance, size, 64);
  109. if ((NULL == ic) || (NULL == dma_buffer))
  110. {
  111. FUSB_FREE(instance, ic);
  112. FUSB_FREE(instance, dma_buffer);
  113. return NULL;
  114. }
  115. memset(dma_buffer, 0, size);
  116. ic->drop = dma_buffer + 0;
  117. ic->add = dma_buffer + 4;
  118. dma_buffer += ctxsize;
  119. for (i = 0; i < FXHCI_NUM_EPS; i++, dma_buffer += ctxsize)
  120. ic->dev.ep[i] = dma_buffer;
  121. return ic;
  122. }
  123. /**
  124. * @name: FXhciSetAddress
  125. * @msg: 设备USB设备的地址
  126. * @return {FUsbDev *}, USB设备实例
  127. * @param {FUsbHc} *controller, USB控制器实例
  128. * @param {FUsbSpeed} speed, USB设备的速度类型
  129. * @param {int} hubport, USB设备连接的port号
  130. * @param {int} hubaddr, USB设备连接的hub地址
  131. */
  132. FUsbDev *FXhciSetAddress(FUsbHc *controller, FUsbSpeed speed, int hubport, int hubaddr)
  133. {
  134. FXhci *const xhci = FXHCI_INST_GET(controller);
  135. FASSERT(xhci);
  136. const size_t ctxsize = FXhciGetCtxSize(&xhci->mmio);
  137. FXhciDevInfo *di = NULL;
  138. FUsbDev *dev = NULL;
  139. FUsb *instance = controller->usb;
  140. int i;
  141. FXhciInputCtx *const ic = FXhciMakeInputCtx(xhci, ctxsize);
  142. FXhciTransRing *const tr = FUSB_ALLOCATE(instance, sizeof(*tr), FUSB_DEFAULT_ALIGN);
  143. if (NULL != tr)
  144. {
  145. FASSERT(NULL == tr->ring);
  146. tr->ring = FXHCI_ALIGN(xhci, 16, FXHCI_TRANSFER_RING_SIZE * sizeof(FXhciTrb));
  147. }
  148. if ((NULL == ic) || (NULL == tr) || (NULL == tr->ring))
  149. {
  150. FUSB_INFO("Out of memory ");
  151. goto _free_return;
  152. }
  153. int slot_id;
  154. FXhciTransCode cc = FXhciCmdEnableSlot(xhci, &slot_id);
  155. if (cc == FXHCI_CC_NO_SLOTS_AVAILABLE)
  156. {
  157. FXhciReapSlots(xhci, 0);
  158. cc = FXhciCmdEnableSlot(xhci, &slot_id);
  159. }
  160. if (cc != FXHCI_CC_SUCCESS)
  161. {
  162. FUSB_INFO("Enable slot failed: %d ", cc);
  163. goto _free_return;
  164. }
  165. else
  166. {
  167. FUSB_INFO("Enabled slot %d ", slot_id);
  168. }
  169. di = &xhci->dev[slot_id];
  170. void *dma_buffer = FUSB_ALLOCATE(instance, FXHCI_NUM_EPS * ctxsize, 64);
  171. if (NULL == dma_buffer)
  172. goto _disable_return;
  173. memset(dma_buffer, 0, FXHCI_NUM_EPS * ctxsize);
  174. for (i = 0; i < FXHCI_NUM_EPS; i++, dma_buffer += ctxsize)
  175. di->ctx.ep[i] = dma_buffer;
  176. *ic->add = (1 << 0) /* Slot Context */ | (1 << 1) /* EP0 Context */;
  177. FXHCI_SC_SET(ROUTE, ic->dev.slot, FXhciGenRounte(xhci, hubport, hubaddr));
  178. FXHCI_SC_SET(SPEED1, ic->dev.slot, speed + 1);
  179. FXHCI_SC_SET(CTXENT, ic->dev.slot, 1); /* the endpoint 0 context */
  180. FXHCI_SC_SET(RHPORT, ic->dev.slot, FXhciGetRoothubPort(xhci, hubport, hubaddr));
  181. int tt, tt_port;
  182. if (FXhciGetTT(xhci, speed, hubport, hubaddr, &tt, &tt_port))
  183. {
  184. FUSB_INFO("TT for %d: %d[%d] ", slot_id, tt, tt_port);
  185. FXHCI_SC_SET(MTT, ic->dev.slot, FXHCI_SC_GET(MTT, xhci->dev[tt].ctx.slot));
  186. FXHCI_SC_SET(TTID, ic->dev.slot, tt);
  187. FXHCI_SC_SET(TTPORT, ic->dev.slot, tt_port);
  188. }
  189. di->transfer_rings[1] = tr;
  190. FXhciInitCycleRing(tr, FXHCI_TRANSFER_RING_SIZE);
  191. ic->dev.ep0->tr_dq_low = (uintptr)(tr->ring);
  192. ic->dev.ep0->tr_dq_high = 0;
  193. FXHCI_EC_SET(TYPE, ic->dev.ep0, FXHCI_EP_CONTROL);
  194. FXHCI_EC_SET(AVRTRB, ic->dev.ep0, 8);
  195. FXHCI_EC_SET(MPS, ic->dev.ep0, FUsbSpeedtoDefaultMaxPacketSz(speed));
  196. FXHCI_EC_SET(CERR, ic->dev.ep0, 3);
  197. FXHCI_EC_SET(DCS, ic->dev.ep0, 1);
  198. xhci->dcbaa[slot_id] = (uintptr)(di->ctx.raw);
  199. FCacheDCacheInvalidateRange((uintptr)ic, sizeof(*ic)); /* flush cache of input address */
  200. cc = FXhciCmdAddressDevice(xhci, slot_id, ic);
  201. if (cc == FXHCI_CC_RESOURCE_ERROR)
  202. {
  203. FXhciReapSlots(xhci, slot_id);
  204. cc = FXhciCmdAddressDevice(xhci, slot_id, ic);
  205. }
  206. if (cc != FXHCI_CC_SUCCESS)
  207. {
  208. FUSB_INFO("Address device failed: %d ", cc);
  209. goto _disable_return;
  210. }
  211. else
  212. {
  213. FUSB_INFO("Addressed device %d (USB: %d) ",
  214. slot_id, FXHCI_SC_GET(UADDR, di->ctx.slot));
  215. }
  216. fsleep_millisec(FUSB_SET_ADDRESS_MDELAY);
  217. dev = FUsbInitDevEntry(controller, slot_id);
  218. if (!dev)
  219. goto _disable_return;
  220. dev->address = slot_id;
  221. dev->hub = hubaddr;
  222. dev->port = hubport;
  223. dev->speed = speed;
  224. dev->endpoints[0].dev = dev;
  225. dev->endpoints[0].endpoint = 0;
  226. dev->endpoints[0].toggle = 0;
  227. dev->endpoints[0].direction = FUSB_SETUP;
  228. dev->endpoints[0].type = FUSB_CONTROL_EP;
  229. u8 buf[8];
  230. if (FUsbGetDescriptor(dev, FUsbGenerateReqType(FUSB_REQ_DEVICE_TO_HOST, FUSB_REQ_TYPE_STANDARD, FUSB_REQ_RECP_DEV), FUSB_DESC_TYPE_DEVICE, 0, buf, sizeof(buf)) != sizeof(buf))
  231. {
  232. FUSB_INFO("first FUsbGetDescriptor(FUSB_DESC_TYPE_DEVICE) failed ");
  233. goto _disable_return;
  234. }
  235. dev->endpoints[0].maxpacketsize = FUsbDecodeMaxPacketSz0(speed, buf[7]);
  236. if (dev->endpoints[0].maxpacketsize != FUsbSpeedtoDefaultMaxPacketSz(speed))
  237. {
  238. memset((void *)ic->dev.ep0, 0x00, ctxsize);
  239. *ic->add = (1 << 1); /* EP0 Context */
  240. FXHCI_EC_SET(MPS, ic->dev.ep0, dev->endpoints[0].maxpacketsize);
  241. /* flush cache of input context before send command */
  242. FCacheDCacheInvalidateRange((uintptr)ic, sizeof(*ic));
  243. cc = FXhciCmdEvaluateCtx(xhci, slot_id, ic);
  244. if (cc == FXHCI_CC_RESOURCE_ERROR)
  245. {
  246. FXhciReapSlots(xhci, slot_id);
  247. cc = FXhciCmdEvaluateCtx(xhci, slot_id, ic);
  248. }
  249. if (cc != FXHCI_CC_SUCCESS)
  250. {
  251. FUSB_INFO("Context evaluation failed: %d ", cc);
  252. goto _disable_return;
  253. }
  254. }
  255. goto _free_ic_return;
  256. _disable_return:
  257. FXhciCmdDisableSlot(xhci, slot_id);
  258. xhci->dcbaa[slot_id] = 0;
  259. FUsbDetachDev(controller, slot_id);
  260. dev = NULL;
  261. _free_return:
  262. if (tr)
  263. FUSB_FREE(instance, (void *)tr->ring);
  264. FUSB_FREE(instance, tr);
  265. if (di)
  266. {
  267. FUSB_FREE(instance, di->ctx.raw);
  268. di->ctx.raw = 0;
  269. }
  270. _free_ic_return:
  271. if (ic)
  272. {
  273. FUSB_FREE(instance, ic->raw);
  274. FUSB_FREE(instance, ic);
  275. }
  276. return dev;
  277. }
  278. static int FXhciFinishHubConfig(FUsbDev *const dev, FXhciInputCtx *const ic)
  279. {
  280. int type = FUsbIsSuperSpeed(dev->speed) ? 0x2a : 0x29; /* similar enough */
  281. FUsbHubDescriptor desc;
  282. if (FUsbGetDescriptor(dev, FUsbGenerateReqType(FUSB_REQ_DEVICE_TO_HOST, FUSB_REQ_TYPE_CLASS, FUSB_REQ_RECP_DEV), type, 0, &desc, sizeof(desc)) != sizeof(desc))
  283. {
  284. FUSB_INFO("Failed to fetch hub descriptor ");
  285. return FXHCI_CC_COMMUNICATION_ERROR;
  286. }
  287. FXHCI_SC_SET(HUB, ic->dev.slot, 1);
  288. FXHCI_SC_SET(MTT, ic->dev.slot, 0); /* No support for Multi-TT */
  289. FXHCI_SC_SET(NPORTS, ic->dev.slot, desc.bNbrPorts);
  290. if (dev->speed == FUSB_HIGH_SPEED)
  291. FXHCI_SC_SET(TTT, ic->dev.slot,
  292. (desc.wHubCharacteristics >> 5) & 0x0003);
  293. return 0;
  294. }
  295. static size_t FXhciBoundInterval(const FUsbEndpoint *const ep)
  296. {
  297. if ((ep->dev->speed == FUSB_LOW_SPEED &&
  298. (ep->type == FUSB_ISOCHRONOUS_EP ||
  299. ep->type == FUSB_INTERRUPT_EP)) ||
  300. (ep->dev->speed == FUSB_FULL_SPEED &&
  301. ep->type == FUSB_INTERRUPT_EP))
  302. {
  303. if (ep->interval < 3)
  304. return 3;
  305. else if (ep->interval > 11)
  306. return 11;
  307. else
  308. return ep->interval;
  309. }
  310. else
  311. {
  312. if (ep->interval < 0)
  313. return 0;
  314. else if (ep->interval > 15)
  315. return 15;
  316. else
  317. return ep->interval;
  318. }
  319. }
  320. static int FXhciFinishEpConfig(const FUsbEndpoint *const ep, FXhciInputCtx *const ic)
  321. {
  322. FXhci *const xhci = FXHCI_INST_GET(ep->dev->controller);
  323. FASSERT(xhci);
  324. FUsb *instance = xhci->usb;
  325. const int ep_id = FXhciEpId(ep);
  326. FUSB_INFO("ep_id: %d ", ep_id);
  327. if (ep_id <= 1 || 32 <= ep_id)
  328. return FXHCI_CC_DRIVER_ERROR;
  329. FXhciTransRing *const tr = FUSB_ALLOCATE(instance, sizeof(*tr), FUSB_DEFAULT_ALIGN);
  330. if (NULL != tr)
  331. {
  332. FASSERT(NULL == tr->ring);
  333. tr->ring = FXHCI_ALIGN(xhci, 16, FXHCI_TRANSFER_RING_SIZE * sizeof(FXhciTrb));
  334. }
  335. if ((NULL == tr) || (NULL == tr->ring))
  336. {
  337. FUSB_FREE(instance, tr);
  338. FUSB_ERROR("Out of memory ");
  339. return FXHCI_CC_OUT_OF_MEMORY;
  340. }
  341. xhci->dev[ep->dev->address].transfer_rings[ep_id] = tr;
  342. FXhciInitCycleRing(tr, FXHCI_TRANSFER_RING_SIZE);
  343. *ic->add |= (1 << ep_id);
  344. if ((int)FXHCI_SC_GET(CTXENT, ic->dev.slot) < ep_id)
  345. FXHCI_SC_SET(CTXENT, ic->dev.slot, ep_id);
  346. FXhciEpCtx *const epctx = ic->dev.ep[ep_id];
  347. FUSB_DEBUG("Filling epctx (@%p) ", epctx);
  348. epctx->tr_dq_low = (uintptr)(tr->ring);
  349. epctx->tr_dq_high = 0;
  350. FXHCI_EC_SET(INTVAL, epctx, FXhciBoundInterval(ep));
  351. FXHCI_EC_SET(CERR, epctx, 3);
  352. FXHCI_EC_SET(TYPE, epctx, ep->type | ((ep->direction != FUSB_OUT) << 2));
  353. FXHCI_EC_SET(MPS, epctx, ep->maxpacketsize);
  354. FXHCI_EC_SET(DCS, epctx, 1);
  355. size_t avrtrb;
  356. switch (ep->type)
  357. {
  358. case FUSB_BULK_EP:
  359. case FUSB_ISOCHRONOUS_EP:
  360. avrtrb = 3 * 1024;
  361. break;
  362. case FUSB_INTERRUPT_EP:
  363. avrtrb = 1024;
  364. break;
  365. default:
  366. avrtrb = 8;
  367. break;
  368. }
  369. FXHCI_EC_SET(AVRTRB, epctx, avrtrb);
  370. FXHCI_EC_SET(MXESIT, epctx, FXHCI_EC_GET(MPS, epctx) * FXHCI_EC_GET(MBS, epctx));
  371. return 0;
  372. }
  373. /**
  374. * @name: FXhciFinishDevConfig
  375. * @msg: 完成USB设备配置
  376. * @return {FXhciTransCode} 传输返回码
  377. * @param {FUsbDev} *dev, USB设备实例
  378. */
  379. FXhciTransCode FXhciFinishDevConfig(FUsbDev *const dev)
  380. {
  381. FXhci *const xhci = FXHCI_INST_GET(dev->controller);
  382. FASSERT(xhci);
  383. FUsb *instance = xhci->usb;
  384. int slot_id = dev->address;
  385. FXhciDevInfo *const di = &xhci->dev[slot_id];
  386. int i;
  387. FXhciTransCode ret = FXHCI_CC_ZERO_BYTES;
  388. FXhciInputCtx *const ic = FXhciMakeInputCtx(xhci, FXhciGetCtxSize(&xhci->mmio));
  389. if (!ic)
  390. {
  391. FUSB_INFO("Out of memory ");
  392. return FXHCI_CC_OUT_OF_MEMORY;
  393. }
  394. *ic->add = (1 << 0); /* Slot Context */
  395. ic->dev.slot->f1 = di->ctx.slot->f1;
  396. ic->dev.slot->f2 = di->ctx.slot->f2;
  397. ic->dev.slot->f3 = di->ctx.slot->f3;
  398. /* f4 *must* be 0 in the Input Context... yeah, it's weird, I know. */
  399. FCacheDCacheInvalidateRange((uintptr)ic, sizeof(*ic));
  400. if (dev->descriptor->bDeviceClass == FUSB_HUB_DEVICE)
  401. {
  402. ret = FXhciFinishHubConfig(dev, ic);
  403. if (ret)
  404. goto _free_return;
  405. }
  406. for (i = 1; i < dev->num_endp; ++i)
  407. {
  408. ret = FXhciFinishEpConfig(&dev->endpoints[i], ic);
  409. if (ret)
  410. goto _free_ep_ctx_return;
  411. }
  412. const int config_id = dev->configuration->bConfigurationValue;
  413. FUSB_INFO("config_id: %d ", config_id);
  414. FXhciTransCode cc = FXhciCmdConfigureEp(xhci, slot_id, config_id, ic);
  415. if (cc == FXHCI_CC_RESOURCE_ERROR || cc == FXHCI_CC_BANDWIDTH_ERROR)
  416. {
  417. FXhciReapSlots(xhci, slot_id);
  418. cc = FXhciCmdConfigureEp(xhci, slot_id, config_id, ic);
  419. }
  420. if (cc != FXHCI_CC_SUCCESS)
  421. {
  422. FUSB_INFO("Configure endpoint failed: %d ", cc);
  423. ret = FXHCI_CC_CONTROLLER_ERROR;
  424. goto _free_ep_ctx_return;
  425. }
  426. else
  427. {
  428. FUSB_INFO("Endpoints configured ");
  429. }
  430. goto _free_return;
  431. _free_ep_ctx_return:
  432. for (i = 2; i < 31; ++i)
  433. {
  434. if (di->transfer_rings[i])
  435. {
  436. FUSB_FREE(instance, (void *)di->transfer_rings[i]->ring);
  437. FUSB_FREE(instance, di->transfer_rings[i]);
  438. }
  439. di->transfer_rings[i] = NULL;
  440. }
  441. _free_return:
  442. if (NULL != ic)
  443. {
  444. FUSB_FREE(instance, ic->raw);
  445. FUSB_FREE(instance, ic);
  446. }
  447. return ret;
  448. }
  449. /**
  450. * @name: FXhciDestoryDev
  451. * @msg: 删除指定USB设备实例
  452. * @return {*}
  453. * @param {FUsbHc} *controller, USB控制器实例
  454. * @param {int} slot_id, USB设备所在的slot号
  455. */
  456. void FXhciDestoryDev(FUsbHc *const controller, const int slot_id)
  457. {
  458. FXhci *const xhci = FXHCI_INST_GET(controller);
  459. FASSERT(xhci);
  460. FUsb *instance = xhci->usb;
  461. if (slot_id <= 0 || slot_id > xhci->max_slots_en)
  462. return;
  463. FXhciInputCtx *const ic = FXhciMakeInputCtx(xhci, FXhciGetCtxSize(&xhci->mmio));
  464. if (NULL == ic)
  465. {
  466. FUSB_WARN("Out of memory, leaking resources! ");
  467. return;
  468. }
  469. const int num_eps = controller->devices[slot_id]->num_endp;
  470. *ic->add = 0; /* Leave Slot/EP0 state as it is for now. */
  471. *ic->drop = (1 << num_eps) - 1; /* Drop all endpoints we can. */
  472. *ic->drop &= ~(1 << 1 | 1 << 0); /* Not allowed to drop EP0 or Slot. */
  473. FCacheDCacheInvalidateRange((uintptr)ic, sizeof(*ic));
  474. FXhciTransCode cc = FXhciCmdEvaluateCtx(xhci, slot_id, ic);
  475. if (NULL != ic)
  476. {
  477. FUSB_FREE(instance, ic->raw);
  478. FUSB_FREE(instance, ic);
  479. }
  480. if (cc != FXHCI_CC_SUCCESS)
  481. FUSB_INFO("Failed to quiesce slot %d: %d ", slot_id, cc);
  482. cc = FXhciCmdStopEp(xhci, slot_id, FXHCI_EP0_ID);
  483. if (cc != FXHCI_CC_SUCCESS)
  484. FUSB_INFO("Failed to stop EP0 on slot %d: %d ", slot_id, cc);
  485. int i;
  486. FXhciDevInfo *const di = &xhci->dev[slot_id];
  487. for (i = 1; i < /*num_eps*/FXHCI_NUM_EPS; ++i)
  488. {
  489. if (di->transfer_rings[i])
  490. {
  491. FUSB_FREE(instance, (void *)di->transfer_rings[i]->ring);
  492. FUSB_FREE(instance, (void *)di->transfer_rings[i]);
  493. }
  494. FUSB_FREE(instance, di->interrupt_queues[i]);
  495. }
  496. /* free device context */
  497. if (NULL != di->ctx.raw)
  498. {
  499. FUSB_FREE(instance, di->ctx.raw);
  500. di->ctx.raw = NULL;
  501. }
  502. FUSB_INFO("Stopped slot %d, but not disabling it yet. ", slot_id);
  503. di->transfer_rings[1] = NULL;
  504. return;
  505. }