ehci_iso.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. /**************************************************************************//**
  2. * @file ehci_iso.c
  3. * @version V1.10
  4. * @brief USB EHCI isochronous transfer driver.
  5. *
  6. * SPDX-License-Identifier: Apache-2.0
  7. *
  8. * @copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
  9. *****************************************************************************/
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include "NuMicro.h"
  14. #include "usb.h"
  15. #include "hub.h"
  16. /// @cond HIDDEN_SYMBOLS
  17. uint32_t g_flr_cnt; /* frame list rollover counter */
  18. ISO_EP_T *iso_ep_list; /* list of activated isochronous pipes */
  19. extern uint32_t _PFList[FL_SIZE]; /* Periodic frame list */
  20. static const uint16_t sitd_OUT_Smask [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f };
  21. static int ehci_iso_split_xfer(UTR_T *utr, ISO_EP_T *iso_ep);
  22. /*
  23. * Inspect the iTD can be reclaimed or not. If yes, collect the transaction results.
  24. * Return: 1 - reclaimed
  25. * 0 - not completed
  26. */
  27. static int review_itd(iTD_T *itd)
  28. {
  29. UTR_T *utr;
  30. uint32_t frnidx = itd->sched_frnidx;
  31. uint32_t now_frame = (_ehci->UFINDR >> 3) & 0x3FF;
  32. int i, fidx;
  33. // printf("R - %d %d, 0x%x\n", now_frame, frnidx, itd->Transaction[0]);
  34. if (now_frame == frnidx)
  35. {
  36. for (i = 0; i < 8; i++)
  37. {
  38. if (itd->Transaction[i] & ITD_STATUS_ACTIVE)
  39. return 0; /* have any not completed frames */
  40. }
  41. }
  42. else if (now_frame > frnidx)
  43. {
  44. if ((now_frame - frnidx) > EHCI_ISO_RCLM_RANGE)
  45. return 0; /* don't touch it */
  46. }
  47. else
  48. {
  49. if (now_frame + FL_SIZE - frnidx > EHCI_ISO_RCLM_RANGE)
  50. return 0; /* don't touch it */
  51. }
  52. /*
  53. * Reclaim this iTD
  54. */
  55. utr = itd->utr;
  56. fidx = itd->fidx;
  57. for (i = 0; i < 8; i++)
  58. {
  59. if (!(itd->trans_mask & (0x1<<i)))
  60. continue; /* not scheduled micro-frame */
  61. if (ITD_STATUS(itd->Transaction[i]))
  62. {
  63. if (itd->Transaction[i] & ITD_STATUS_ACTIVE)
  64. {
  65. utr->iso_status[fidx] = USBH_ERR_NOT_ACCESS0;
  66. utr->status = USBH_ERR_NOT_ACCESS0;
  67. }
  68. else if (itd->Transaction[i] & ITD_STATUS_BABBLE)
  69. {
  70. utr->iso_status[fidx] = USBH_ERR_BABBLE_DETECTED;
  71. utr->status = USBH_ERR_TRANSFER;
  72. }
  73. else if (itd->Transaction[i] & ITD_STATUS_BUFF_ERR)
  74. {
  75. utr->iso_status[fidx] = USBH_ERR_DATA_BUFF;
  76. utr->status = USBH_ERR_TRANSFER;
  77. }
  78. else
  79. {
  80. utr->iso_status[fidx] = USBH_ERR_TRANSACTION;
  81. utr->status = USBH_ERR_TRANSFER;
  82. }
  83. }
  84. else
  85. {
  86. utr->iso_status[fidx] = 0;
  87. utr->iso_xlen[fidx] = ITD_XFER_LEN(itd->Transaction[i]);
  88. }
  89. fidx++;
  90. }
  91. utr->td_cnt--;
  92. if (utr->td_cnt == 0) /* All iTD of this UTR done */
  93. {
  94. utr->bIsTransferDone = 1;
  95. if (utr->func)
  96. utr->func(utr);
  97. }
  98. return 1; /* to be reclaimed */
  99. }
  100. /*
  101. * Inspect the siTD can be reclaimed or not. If yes, collect the transaction results.
  102. * Return: 1 - reclaimed
  103. * 0 - not completed
  104. */
  105. static int review_sitd(siTD_T *sitd)
  106. {
  107. UTR_T *utr;
  108. uint32_t frnidx = sitd->sched_frnidx;
  109. uint32_t now_frame = (_ehci->UFINDR >> 3) & 0x3FF;
  110. int fidx;
  111. uint32_t TotalBytesToTransfer;
  112. if (now_frame == frnidx)
  113. {
  114. if (SITD_STATUS(sitd->StsCtrl) == SITD_STATUS_ACTIVE)
  115. return 0;
  116. }
  117. else if (now_frame > frnidx)
  118. {
  119. if ((now_frame - frnidx) > EHCI_ISO_RCLM_RANGE)
  120. return 0; /* don't touch it */
  121. }
  122. else
  123. {
  124. if (now_frame + FL_SIZE - frnidx > EHCI_ISO_RCLM_RANGE)
  125. return 0; /* don't touch it */
  126. }
  127. /*
  128. * Reclaim this siTD
  129. */
  130. utr = sitd->utr;
  131. fidx = sitd->fidx;
  132. if (SITD_STATUS(sitd->StsCtrl))
  133. {
  134. if (sitd->StsCtrl & SITD_STATUS_ACTIVE)
  135. {
  136. utr->iso_status[fidx] = USBH_ERR_NOT_ACCESS0;
  137. }
  138. else if (sitd->StsCtrl & SITD_BABBLE_DETECTED)
  139. {
  140. utr->iso_status[fidx] = USBH_ERR_BABBLE_DETECTED;
  141. utr->status = USBH_ERR_TRANSFER;
  142. }
  143. else if (sitd->StsCtrl & SITD_STATUS_BUFF_ERR)
  144. {
  145. utr->iso_status[fidx] = USBH_ERR_DATA_BUFF;
  146. utr->status = USBH_ERR_TRANSFER;
  147. }
  148. else
  149. {
  150. utr->iso_status[fidx] = USBH_ERR_TRANSACTION;
  151. utr->status = USBH_ERR_TRANSFER;
  152. }
  153. }
  154. else
  155. {
  156. TotalBytesToTransfer = (sitd->StsCtrl & SITD_XFER_CNT_Msk) >> SITD_XFER_CNT_Pos;
  157. utr->iso_xlen[fidx] = utr->iso_xlen[fidx] - TotalBytesToTransfer;
  158. utr->iso_status[fidx] = 0;
  159. }
  160. utr->td_cnt--;
  161. if (utr->td_cnt == 0) /* All iTD of this UTR done */
  162. {
  163. utr->bIsTransferDone = 1;
  164. if (utr->func)
  165. utr->func(utr);
  166. }
  167. return 1; /* to be reclaimed */
  168. }
  169. /*
  170. * Some iTD/siTD may be scheduled but not serviced due to time missed.
  171. * This function scan several earlier frames and drop unserviced iTD/siTD if found.
  172. */
  173. void scan_isochronous_list(void)
  174. {
  175. ISO_EP_T *iso_ep = iso_ep_list;
  176. iTD_T *itd, *itd_pre, *p;
  177. siTD_T *sitd, *sitd_pre, *sp;
  178. uint32_t frnidx;
  179. DISABLE_EHCI_IRQ();
  180. while (iso_ep != NULL) /* Search all activated iso endpoints */
  181. {
  182. /*--------------------------------------------------------------------------------*/
  183. /* Scan all iTDs */
  184. /*--------------------------------------------------------------------------------*/
  185. itd = iso_ep->itd_list; /* get the first iTD from iso_ep's iTD list */
  186. itd_pre = NULL;
  187. while (itd != NULL) /* traverse all iTDs of itd list */
  188. {
  189. if (review_itd(itd)) /* inspect and reclaim iTD */
  190. {
  191. /*------------------------------------------------------------------------*/
  192. /* Remove this iTD from period frame list */
  193. /*------------------------------------------------------------------------*/
  194. frnidx = itd->sched_frnidx;
  195. if (_PFList[frnidx] == ITD_HLNK_ITD(itd))
  196. {
  197. /* is the first entry, just change to next */
  198. _PFList[frnidx] = itd->Next_Link;
  199. }
  200. else
  201. {
  202. p = ITD_PTR(_PFList[frnidx]); /* find the preceding iTD */
  203. while ((ITD_PTR(p->Next_Link) != itd) && (p != NULL))
  204. {
  205. p = ITD_PTR(p->Next_Link);
  206. }
  207. if (p == NULL) /* link list out of control! */
  208. {
  209. USB_error("An iTD lost refernece to periodic frame list! 0x%x -> %d\n", (int)itd, frnidx);
  210. }
  211. else /* remove iTD from list */
  212. {
  213. p->Next_Link = itd->Next_Link;
  214. }
  215. }
  216. /*------------------------------------------------------------------------*/
  217. /* Remove this iTD from iso_ep's iTD list */
  218. /*------------------------------------------------------------------------*/
  219. if (itd_pre == NULL)
  220. {
  221. iso_ep->itd_list = itd->next;
  222. }
  223. else
  224. {
  225. itd_pre->next = itd->next;
  226. }
  227. p = itd->next;
  228. free_ehci_iTD(itd);
  229. itd = p;
  230. }
  231. else
  232. {
  233. itd_pre = itd;
  234. itd = itd->next; /* traverse to the next iTD of iTD list */
  235. }
  236. }
  237. /*--------------------------------------------------------------------------------*/
  238. /* Scan all siTDs */
  239. /*--------------------------------------------------------------------------------*/
  240. sitd = iso_ep->sitd_list; /* get the first siTD from iso_ep's siTD list */
  241. sitd_pre = NULL;
  242. while (sitd != NULL) /* traverse all siTDs of sitd list */
  243. {
  244. if (review_sitd(sitd)) /* inspect and reclaim siTD */
  245. {
  246. /*------------------------------------------------------------------------*/
  247. /* Remove this siTD from period frame list */
  248. /*------------------------------------------------------------------------*/
  249. frnidx = sitd->sched_frnidx;
  250. if (_PFList[frnidx] == SITD_HLNK_SITD(sitd))
  251. {
  252. /* is the first entry, just change to next */
  253. _PFList[frnidx] = sitd->Next_Link;
  254. }
  255. else
  256. {
  257. sp = SITD_PTR(_PFList[frnidx]); /* find the preceding siTD */
  258. while ((SITD_PTR(sp->Next_Link) != sitd) && (sp != NULL))
  259. {
  260. sp = SITD_PTR(sp->Next_Link);
  261. }
  262. if (sp == NULL) /* link list out of control! */
  263. {
  264. USB_error("An siTD lost reference to periodic frame list! 0x%x -> %d\n", (int)sitd, frnidx);
  265. }
  266. else /* remove iTD from list */
  267. {
  268. sp->Next_Link = sitd->Next_Link;
  269. }
  270. }
  271. /*------------------------------------------------------------------------*/
  272. /* Remove this siTD from iso_ep's siTD list */
  273. /*------------------------------------------------------------------------*/
  274. if (sitd_pre == NULL)
  275. {
  276. iso_ep->sitd_list = sitd->next;
  277. }
  278. else
  279. {
  280. sitd_pre->next = sitd->next;
  281. }
  282. sp = sitd->next;
  283. free_ehci_siTD(sitd);
  284. sitd = sp;
  285. }
  286. else
  287. {
  288. sitd_pre = sitd;
  289. sitd = sitd->next; /* traverse to the next siTD of siTD list */
  290. }
  291. }
  292. iso_ep = iso_ep->next;
  293. }
  294. ENABLE_EHCI_IRQ();
  295. }
  296. static void write_itd_info(UTR_T *utr, iTD_T *itd)
  297. {
  298. UDEV_T *udev = utr->udev;
  299. EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
  300. uint32_t buff_page_addr;
  301. int i;
  302. buff_page_addr = itd->buff_base & 0xFFFFF000; /* 4K page */
  303. for (i = 0; i < 7; i++)
  304. {
  305. itd->Bptr[i] = buff_page_addr + (0x1000 * i);
  306. }
  307. /* EndPtr R Device Address */
  308. itd->Bptr[0] |= (udev->dev_num) | ((ep->bEndpointAddress & 0xF) << ITD_EP_NUM_Pos);
  309. itd->Bptr[1] |= ep->wMaxPacketSize; /* Maximum Packet Size */
  310. if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN) /* I/O */
  311. itd->Bptr[1] |= ITD_DIR_IN;
  312. else
  313. itd->Bptr[1] |= ITD_DIR_OUT;
  314. itd->Bptr[2] |= (ep->wMaxPacketSize + 1023)/1024; /* Mult */
  315. }
  316. static void write_itd_micro_frame(UTR_T *utr, int fidx, iTD_T *itd, int mf)
  317. {
  318. uint32_t buff_addr;
  319. buff_addr = (uint32_t)(utr->iso_buff[fidx]); /* xfer buffer start address of this frame */
  320. itd->Transaction[mf] = ITD_STATUS_ACTIVE | /* Status */
  321. ((utr->iso_xlen[fidx] & 0xFFF) << ITD_XLEN_Pos) | /* Transaction Length */
  322. ((buff_addr & 0xFFFFF000) - (itd->buff_base & 0xFFFFF000)) | /* PG */
  323. (buff_addr & 0xFFF); /* Transaction offset */
  324. }
  325. static void remove_iso_ep_from_list(ISO_EP_T *iso_ep)
  326. {
  327. ISO_EP_T *p;
  328. if (iso_ep_list == iso_ep)
  329. {
  330. iso_ep_list = iso_ep->next; /* it's the first entry, remove it */
  331. return;
  332. }
  333. p = iso_ep_list; /* find the previous entry of iso_ep */
  334. while (p->next != NULL)
  335. {
  336. if (p->next == iso_ep)
  337. {
  338. break;
  339. }
  340. p = p->next;
  341. }
  342. if (p->next == NULL)
  343. {
  344. return; /* not found */
  345. }
  346. p->next = iso_ep->next; /* remove iso_ep from list */
  347. }
  348. static __inline void add_itd_to_iso_ep(ISO_EP_T *iso_ep, iTD_T *itd)
  349. {
  350. iTD_T *p;
  351. itd->next = NULL;
  352. if (iso_ep->itd_list == NULL)
  353. {
  354. iso_ep->itd_list = itd;
  355. return;
  356. }
  357. /*
  358. * Find the tail entry of iso_ep->itd_list
  359. */
  360. p = iso_ep->itd_list;
  361. while (p->next != NULL)
  362. {
  363. p = p->next;
  364. }
  365. p->next = itd;
  366. }
  367. int ehci_iso_xfer(UTR_T *utr)
  368. {
  369. EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
  370. ISO_EP_T *iso_ep; /* software iso endpoint descriptor */
  371. iTD_T *itd, *itd_next, *itd_list = NULL;
  372. int i, itd_cnt;
  373. int trans_mask; /* bit mask of used xfer in an iTD */
  374. int fidx; /* index to the 8 iso frames of UTR */
  375. int interval; /* frame interval of iTD */
  376. if (ep->hw_pipe != NULL)
  377. {
  378. iso_ep = (ISO_EP_T *)ep->hw_pipe; /* get reference of the isochronous endpoint */
  379. if (utr->bIsoNewSched)
  380. iso_ep->next_frame = (((_ehci->UFINDR + (EHCI_ISO_DELAY * 8)) & HSUSBH_UFINDR_FI_Msk) >> 3) & 0x3FF;
  381. }
  382. else
  383. {
  384. /* first time transfer of this iso endpoint */
  385. iso_ep = usbh_alloc_mem(sizeof(*iso_ep));
  386. if (iso_ep == NULL)
  387. return USBH_ERR_MEMORY_OUT;
  388. memset(iso_ep, 0, sizeof(*iso_ep));
  389. iso_ep->ep = ep;
  390. iso_ep->next_frame = (((_ehci->UFINDR + (EHCI_ISO_DELAY * 8)) & HSUSBH_UFINDR_FI_Msk) >> 3) & 0x3FF;
  391. ep->hw_pipe = iso_ep;
  392. /*
  393. * Add this iso_ep into iso_ep_list
  394. */
  395. DISABLE_EHCI_IRQ();
  396. iso_ep->next = iso_ep_list;
  397. iso_ep_list = iso_ep;
  398. ENABLE_EHCI_IRQ();
  399. }
  400. if (utr->udev->speed == SPEED_FULL)
  401. return ehci_iso_split_xfer(utr, iso_ep);
  402. /*------------------------------------------------------------------------------------*/
  403. /* Allocate iTDs */
  404. /*------------------------------------------------------------------------------------*/
  405. if (ep->bInterval < 2) /* transfer interval is 1 micro-frame */
  406. {
  407. trans_mask = 0xFF;
  408. itd_cnt = 1; /* required 1 iTD for one UTR */
  409. interval = 1; /* iTD frame interval of this endpoint */
  410. }
  411. else if (ep->bInterval < 4) /* transfer interval is 2 micro-frames */
  412. {
  413. trans_mask = 0x55;
  414. itd_cnt = 2; /* required 2 iTDs for one UTR */
  415. interval = 1; /* iTD frame interval of this endpoint */
  416. }
  417. else if (ep->bInterval < 8) /* transfer interval is 4 micro-frames */
  418. {
  419. trans_mask = 0x44;
  420. itd_cnt = 4; /* required 4 iTDs for one UTR */
  421. interval = 1; /* iTD frame interval of this endpoint */
  422. }
  423. else if (ep->bInterval < 16) /* transfer interval is 8 micro-frames */
  424. {
  425. trans_mask = 0x08; /* there's 1 transfer in one iTD */
  426. itd_cnt = 8; /* required 8 iTDs for one UTR */
  427. interval = 1; /* iTD frame interval of this endpoint */
  428. }
  429. else if (ep->bInterval < 32) /* transfer interval is 16 micro-frames */
  430. {
  431. trans_mask = 0x10; /* there's 1 transfer in one iTD */
  432. itd_cnt = 8; /* required 8 iTDs for one UTR */
  433. interval = 2; /* iTD frame interval of this endpoint */
  434. }
  435. else if (ep->bInterval < 64) /* transfer interval is 32 micro-frames */
  436. {
  437. trans_mask = 0x02; /* there's 1 transfer in one iTD */
  438. itd_cnt = 8; /* required 8 iTDs for one UTR */
  439. interval = 4; /* iTD frame interval of this endpoint */
  440. }
  441. else /* transfer interval is 64 micro-frames */
  442. {
  443. trans_mask = 0x04; /* there's 1 transfer in one iTD */
  444. itd_cnt = 8; /* required 8 iTDs for one UTR */
  445. interval = 8; /* iTD frame interval of this endpoint */
  446. }
  447. for (i = 0; i < itd_cnt; i++) /* allocate all iTDs required by UTR */
  448. {
  449. itd = alloc_ehci_iTD();
  450. if (itd == NULL)
  451. goto malloc_failed;
  452. if (itd_list == NULL) /* link all iTDs */
  453. {
  454. itd_list = itd;
  455. }
  456. else
  457. {
  458. itd->next = itd_list;
  459. itd_list = itd;
  460. }
  461. }
  462. utr->td_cnt = itd_cnt;
  463. /*------------------------------------------------------------------------------------*/
  464. /* Fill and link all iTDs */
  465. /*------------------------------------------------------------------------------------*/
  466. utr->iso_sf = iso_ep->next_frame;
  467. fidx = 0; /* index to UTR iso frmes (total IF_PER_UTR) */
  468. for (itd = itd_list; (itd != NULL); )
  469. {
  470. if (fidx >= IF_PER_UTR) /* unlikely */
  471. {
  472. USB_error("EHCI driver ITD bug!?\n");
  473. goto malloc_failed;
  474. }
  475. itd->utr = utr;
  476. itd->fidx = fidx; /* index to UTR's n'th IF_PER_UTR frame */
  477. itd->buff_base = (uint32_t)(utr->iso_buff[fidx]); /* iTD buffer base is buffer of the first UTR iso frame serviced by this iTD */
  478. itd->trans_mask = trans_mask;
  479. write_itd_info(utr, itd);
  480. for (i = 0; i < 8; i++) /* settle xfer into micro-frames */
  481. {
  482. if (!(trans_mask & (0x1<<i)))
  483. {
  484. itd->Transaction[i] = 0; /* not accesed */
  485. continue; /* not scheduled micro-frame */
  486. }
  487. write_itd_micro_frame(utr, fidx, itd, i);
  488. fidx++; /* preceed to next UTR iso frame */
  489. if (fidx == IF_PER_UTR) /* is the last scheduled micro-frame? */
  490. {
  491. /* raise interrupt on completed */
  492. itd->Transaction[i] |= ITD_IOC;
  493. break;
  494. }
  495. }
  496. itd_next = itd->next; /* remember the next itd */
  497. // USB_debug("Link iTD 0x%x, %d\n", (int)itd, iso_ep->next_frame);
  498. /*
  499. * Link iTD to period frame list
  500. */
  501. DISABLE_EHCI_IRQ();
  502. itd->sched_frnidx = iso_ep->next_frame; /* remember it for reclamation scan */
  503. add_itd_to_iso_ep(iso_ep, itd); /* add to software itd list */
  504. itd->Next_Link = _PFList[itd->sched_frnidx]; /* keep the next link */
  505. _PFList[itd->sched_frnidx] = ITD_HLNK_ITD(itd);
  506. iso_ep->next_frame = (iso_ep->next_frame + interval) % FL_SIZE;
  507. ENABLE_EHCI_IRQ();
  508. itd = itd_next;
  509. }
  510. _ehci->UCMDR |= HSUSBH_UCMDR_PSEN_Msk; /* periodic list enable */
  511. return 0;
  512. malloc_failed:
  513. while (itd_list != NULL)
  514. {
  515. itd = itd_list;
  516. itd_list = itd->next;
  517. free_ehci_iTD(itd);
  518. }
  519. return USBH_ERR_MEMORY_OUT;
  520. }
  521. static __inline void add_sitd_to_iso_ep(ISO_EP_T *iso_ep, siTD_T *sitd)
  522. {
  523. siTD_T *p;
  524. sitd->next = NULL;
  525. if (iso_ep->sitd_list == NULL)
  526. {
  527. iso_ep->sitd_list = sitd;
  528. return;
  529. }
  530. /*
  531. * Find the tail entry of iso_ep->itd_list
  532. */
  533. p = iso_ep->sitd_list;
  534. while (p->next != NULL)
  535. {
  536. p = p->next;
  537. }
  538. p->next = sitd;
  539. }
  540. static void write_sitd_info(UTR_T *utr, siTD_T *sitd)
  541. {
  542. UDEV_T *udev = utr->udev;
  543. EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
  544. uint32_t buff_page_addr;
  545. int xlen = utr->iso_xlen[sitd->fidx];
  546. int scnt;
  547. sitd->Chrst = (udev->port_num << SITD_PORT_NUM_Pos) |
  548. (udev->parent->iface->udev->dev_num << SITD_HUB_ADDR_Pos) |
  549. ((ep->bEndpointAddress & 0xF) << SITD_EP_NUM_Pos) |
  550. (udev->dev_num << SITD_DEV_ADDR_Pos);
  551. buff_page_addr = ((uint32_t)utr->iso_buff[sitd->fidx]) & 0xFFFFF000;
  552. sitd->Bptr[0] = (uint32_t)(utr->iso_buff[sitd->fidx]);
  553. sitd->Bptr[1] = buff_page_addr + 0x1000;
  554. scnt = (xlen + 187) / 188;
  555. if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN) /* I/O */
  556. {
  557. sitd->Chrst |= SITD_XFER_IN;
  558. sitd->Sched = (1 << (scnt + 2)) - 1;
  559. sitd->Sched = (sitd->Sched << 10) | 0x1;
  560. //sitd->Sched <<= 1;
  561. }
  562. else
  563. {
  564. sitd->Chrst |= SITD_XFER_OUT;
  565. sitd->Sched = sitd_OUT_Smask[scnt-1];
  566. if (scnt > 1)
  567. {
  568. sitd->Bptr[1] |= (0x1 << 3); /* Transaction position (TP) 01b: Begin */
  569. }
  570. sitd->Bptr[1] |= scnt; /* Transaction count (T-Count) */
  571. }
  572. if (sitd->fidx == IF_PER_UTR)
  573. {
  574. sitd->Sched |= SITD_IOC;
  575. }
  576. sitd->StsCtrl = (xlen << SITD_XFER_CNT_Pos) | SITD_STATUS_ACTIVE;
  577. sitd->BackLink = SITD_LIST_END;
  578. }
  579. static void ehci_sitd_adjust_schedule(siTD_T *sitd)
  580. {
  581. siTD_T *hlink = (siTD_T *)_PFList[sitd->sched_frnidx];
  582. uint32_t uframe_mask = 0x00;
  583. while (hlink && !HLINK_IS_TERMINATED(hlink) && HLINK_IS_SITD(hlink))
  584. {
  585. hlink = SITD_PTR(hlink);
  586. if (hlink != sitd)
  587. {
  588. if ((hlink->Chrst & SITD_XFER_IO_Msk) == SITD_XFER_IN)
  589. {
  590. uframe_mask |= (hlink->Sched & 0xFF); /* mark micro-frames used by IN S-mask */
  591. uframe_mask |= ((hlink->Sched >> 8) & 0xFF); /* mark micro-frames used by IN C-mask */
  592. }
  593. else
  594. {
  595. uframe_mask |= (hlink->Sched & 0xFF); /* mark micro-frames used by OUT S-mask */
  596. }
  597. }
  598. hlink = SITD_PTR(hlink->Next_Link);
  599. }
  600. uframe_mask = uframe_mask | (uframe_mask << 8); /* mark both S-mask and C-mask */
  601. if (uframe_mask)
  602. {
  603. /*
  604. * Shift afterward one micro-frame until no conflicts.
  605. */
  606. while (1)
  607. {
  608. if (sitd->Sched & uframe_mask)
  609. {
  610. sitd->Sched = (sitd->Sched & 0xFFFF0000) | ((sitd->Sched << 1) & 0xFFFF);
  611. }
  612. else
  613. {
  614. break; /* no conflit, done. */
  615. }
  616. }
  617. }
  618. }
  619. static int ehci_iso_split_xfer(UTR_T *utr, ISO_EP_T *iso_ep)
  620. {
  621. EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
  622. siTD_T *sitd, *sitd_next, *sitd_list = NULL;
  623. int i;
  624. int fidx; /* index to the 8 iso frames of UTR */
  625. if (utr->udev->parent == NULL)
  626. {
  627. USB_error("siso xfer - parent lost!\n");
  628. return USBH_ERR_INVALID_PARAM;
  629. }
  630. /*------------------------------------------------------------------------------------*/
  631. /* Allocate siTDs */
  632. /*------------------------------------------------------------------------------------*/
  633. for (i = 0; i < IF_PER_UTR; i++) /* allocate all siTDs required by UTR */
  634. {
  635. sitd = alloc_ehci_siTD();
  636. if (sitd == NULL)
  637. goto malloc_failed;
  638. if (sitd_list == NULL) /* link all siTDs */
  639. {
  640. sitd_list = sitd;
  641. }
  642. else
  643. {
  644. sitd->next = sitd_list;
  645. sitd_list = sitd;
  646. }
  647. }
  648. utr->td_cnt = IF_PER_UTR;
  649. /*------------------------------------------------------------------------------------*/
  650. /* Fill and link all siTDs */
  651. /*------------------------------------------------------------------------------------*/
  652. utr->iso_sf = iso_ep->next_frame;
  653. fidx = 0; /* index to UTR iso frmes (total IF_PER_UTR) */
  654. for (sitd = sitd_list; (sitd != NULL); fidx++)
  655. {
  656. if (fidx >= IF_PER_UTR) /* unlikely */
  657. {
  658. USB_error("EHCI driver siTD bug!?\n");
  659. goto malloc_failed;
  660. }
  661. sitd->utr = utr;
  662. sitd->fidx = fidx; /* index to UTR's n'th IF_PER_UTR frame */
  663. write_sitd_info(utr, sitd);
  664. sitd_next = sitd->next; /* remember the next itd */
  665. // USB_debug("Link iTD 0x%x, %d\n", (int)itd, iso_ep->next_frame);
  666. /*
  667. * Link iTD to period frame list
  668. */
  669. sitd->sched_frnidx = iso_ep->next_frame; /* remember it for reclamation scan */
  670. DISABLE_EHCI_IRQ();
  671. ehci_sitd_adjust_schedule(sitd);
  672. add_sitd_to_iso_ep(iso_ep, sitd); /* add to software itd list */
  673. sitd->Next_Link = _PFList[sitd->sched_frnidx];/* keep the next link */
  674. _PFList[sitd->sched_frnidx] = SITD_HLNK_SITD(sitd);
  675. iso_ep->next_frame = (iso_ep->next_frame + ep->bInterval) % FL_SIZE;
  676. ENABLE_EHCI_IRQ();
  677. sitd = sitd_next;
  678. }
  679. _ehci->UCMDR |= HSUSBH_UCMDR_PSEN_Msk; /* periodic list enable */
  680. return 0;
  681. malloc_failed:
  682. while (sitd_list != NULL)
  683. {
  684. sitd = sitd_list;
  685. sitd_list = sitd->next;
  686. free_ehci_siTD(sitd);
  687. }
  688. return USBH_ERR_MEMORY_OUT;
  689. }
  690. /*
  691. * If it's an isochronous endpoint, quit current transfer via UTR or hardware EP.
  692. */
  693. int ehci_quit_iso_xfer(UTR_T *utr, EP_INFO_T *ep)
  694. {
  695. ISO_EP_T *iso_ep;
  696. iTD_T *itd, *itd_next, *p;
  697. uint32_t frnidx;
  698. uint32_t now_frame;
  699. if (ep == NULL)
  700. {
  701. if (utr == NULL)
  702. return USBH_ERR_NOT_FOUND;
  703. if (utr->ep == NULL)
  704. return USBH_ERR_NOT_FOUND;
  705. ep = utr->ep;
  706. }
  707. if ((ep->bmAttributes & EP_ATTR_TT_MASK) != EP_ATTR_TT_ISO)
  708. return USBH_ERR_NOT_FOUND; /* not isochronous endpoint */
  709. /*------------------------------------------------------------------------------------*/
  710. /* It's an iso endpoint. Remove it as required. */
  711. /*------------------------------------------------------------------------------------*/
  712. iso_ep = iso_ep_list;
  713. while (iso_ep != NULL) /* Search all activated iso endpoints */
  714. {
  715. if (iso_ep->ep == ep)
  716. break;
  717. iso_ep = iso_ep->next;
  718. }
  719. if (iso_ep == NULL)
  720. return 0; /* should have been removed */
  721. itd = iso_ep->itd_list; /* get the first iTD from iso_ep's iTD list */
  722. while (itd != NULL) /* traverse all iTDs of itd list */
  723. {
  724. itd_next = itd->next; /* remember the next iTD */
  725. utr = itd->utr;
  726. /*--------------------------------------------------------------------------------*/
  727. /* Remove this iTD from period frame list */
  728. /*--------------------------------------------------------------------------------*/
  729. frnidx = itd->sched_frnidx;
  730. /*
  731. * Prevent to race with Host Controller. If the iTD to be removed is located in
  732. * current or next frame, wait until HC passed through it.
  733. */
  734. while (1)
  735. {
  736. now_frame = (_ehci->UFINDR >> 3) & 0x3FF;
  737. if ((now_frame == frnidx) || (((now_frame+1)%1024) == frnidx))
  738. continue;
  739. break;
  740. }
  741. if (_PFList[frnidx] == ITD_HLNK_ITD(itd))
  742. {
  743. /* is the first entry, just change to next */
  744. _PFList[frnidx] = itd->Next_Link;
  745. }
  746. else
  747. {
  748. p = ITD_PTR(_PFList[frnidx]); /* find the preceding iTD */
  749. while ((ITD_PTR(p->Next_Link) != itd) && (p != NULL))
  750. {
  751. p = ITD_PTR(p->Next_Link);
  752. }
  753. if (p == NULL) /* link list out of control! */
  754. {
  755. USB_error("ehci_quit_iso_xfer - An iTD lost reference to periodic frame list! 0x%x on %d\n", (int)itd, frnidx);
  756. }
  757. else /* remove iTD from list */
  758. {
  759. p->Next_Link = itd->Next_Link;
  760. }
  761. }
  762. utr->td_cnt--;
  763. if (utr->td_cnt == 0) /* All iTD of this UTR done */
  764. {
  765. utr->bIsTransferDone = 1;
  766. if (utr->func)
  767. utr->func(utr);
  768. utr->status = USBH_ERR_ABORT;
  769. }
  770. free_ehci_iTD(itd);
  771. itd = itd_next;
  772. }
  773. /*
  774. * Remove iso_ep from iso_ep_list
  775. */
  776. remove_iso_ep_from_list(iso_ep);
  777. usbh_free_mem(iso_ep, sizeof(*iso_ep)); /* free this iso_ep */
  778. ep->hw_pipe = NULL;
  779. if (iso_ep_list == NULL)
  780. _ehci->UCMDR &= ~HSUSBH_UCMDR_PSEN_Msk;
  781. return 0;
  782. }
  783. /// @endcond HIDDEN_SYMBOLS
  784. /*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/