Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

689 lines
20 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. iso.c
  5. Abstract:
  6. miniport transfer code for iso
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  11. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  12. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  13. PURPOSE.
  14. Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
  15. Revision History:
  16. 3-1-00 : created, jdunn
  17. --*/
  18. #include "common.h"
  19. //implements the following miniport functions:
  20. USB_MINIPORT_STATUS
  21. OHCI_OpenIsoEndpoint(
  22. PDEVICE_DATA DeviceData,
  23. PENDPOINT_PARAMETERS EndpointParameters,
  24. PENDPOINT_DATA EndpointData
  25. )
  26. /*++
  27. Routine Description:
  28. Arguments:
  29. Return Value:
  30. --*/
  31. {
  32. PUCHAR buffer;
  33. HW_32BIT_PHYSICAL_ADDRESS phys, edPhys;
  34. PHCD_ENDPOINT_DESCRIPTOR ed;
  35. ULONG i, available, tdCount;
  36. LOGENTRY(DeviceData, G, '_opS', 0, 0, 0);
  37. buffer = EndpointParameters->CommonBufferVa;
  38. phys = EndpointParameters->CommonBufferPhys;
  39. available = EndpointParameters->CommonBufferBytes;
  40. #if DBG
  41. {
  42. ULONG offset;
  43. offset = BYTE_OFFSET(buffer);
  44. // OHCI requires 16 byte alignemnt
  45. OHCI_ASSERT(DeviceData, (offset % 16) == 0);
  46. }
  47. #endif
  48. // use control list
  49. EndpointData->StaticEd =
  50. &DeviceData->StaticEDList[ED_ISOCHRONOUS];
  51. // make the Ed
  52. ed = (PHCD_ENDPOINT_DESCRIPTOR) buffer;
  53. edPhys = phys;
  54. phys += sizeof(HCD_ENDPOINT_DESCRIPTOR);
  55. buffer += sizeof(HCD_ENDPOINT_DESCRIPTOR);
  56. available -= sizeof(HCD_ENDPOINT_DESCRIPTOR);
  57. EndpointData->TdList = (PHCD_TD_LIST) buffer;
  58. tdCount = available/sizeof(HCD_TRANSFER_DESCRIPTOR);
  59. LOGENTRY(DeviceData, G, '_tdC', tdCount, TDS_PER_ISO_ENDPOINT, 0);
  60. OHCI_ASSERT(DeviceData, tdCount >= TDS_PER_ISO_ENDPOINT);
  61. EndpointData->TdCount = tdCount;
  62. for (i=0; i<tdCount; i++) {
  63. OHCI_InitializeTD(DeviceData,
  64. EndpointData,
  65. &EndpointData->TdList->Td[i],
  66. phys);
  67. phys += sizeof(HCD_TRANSFER_DESCRIPTOR);
  68. }
  69. EndpointData->HcdEd =
  70. OHCI_InitializeED(DeviceData,
  71. EndpointData,
  72. ed,
  73. &EndpointData->TdList->Td[0],
  74. edPhys);
  75. // iso endpoints do not halt
  76. ed->EdFlags = EDFLAG_NOHALT;
  77. OHCI_InsertEndpointInSchedule(DeviceData,
  78. EndpointData);
  79. return USBMP_STATUS_SUCCESS;
  80. }
  81. ULONG
  82. OHCI_IsoTransferLookAhead(
  83. PDEVICE_DATA DeviceData,
  84. PENDPOINT_DATA EndpointData,
  85. PTRANSFER_PARAMETERS TransferParameters,
  86. PTRANSFER_CONTEXT TransferContext,
  87. PMINIPORT_ISO_TRANSFER IsoTransfer
  88. )
  89. /*++
  90. Routine Description:
  91. Calculates how many TDs we will need for this transfer
  92. Arguments:
  93. Return Value:
  94. --*/
  95. {
  96. PHCD_TRANSFER_DESCRIPTOR td, lastTd;
  97. ULONG currentPacket;
  98. PMINIPORT_ISO_TRANSFER tmpIsoTransfer;
  99. ULONG need = 1, n;
  100. LOGENTRY(DeviceData, G, '_lk1', EndpointData, TransferParameters,
  101. EndpointData->HcdEd);
  102. OHCI_ASSERT(DeviceData, IsoTransfer->PacketCount > 0);
  103. // sometimes you just need memory
  104. n = sizeof(MINIPORT_ISO_TRANSFER) + sizeof(MINIPORT_ISO_PACKET) *
  105. (IsoTransfer->PacketCount-1);
  106. tmpIsoTransfer = ExAllocatePool(NonPagedPool, n);
  107. if (tmpIsoTransfer == NULL) {
  108. // this will cause us to return busy
  109. return 99999;
  110. }
  111. RtlCopyMemory(tmpIsoTransfer, IsoTransfer, n);
  112. td = OHCI_ALLOC_TD(DeviceData, EndpointData);
  113. currentPacket = 0;
  114. // we need at least one TD to do the caculations
  115. if (td == USB_BAD_PTR) {
  116. // this will cause us to return busy
  117. return 99999;
  118. }
  119. do {
  120. INITIALIZE_TD_FOR_TRANSFER(td, TransferContext);
  121. //TransferContext->PendingTds++;
  122. //EndpointData->PendingTds++;
  123. currentPacket =
  124. OHCI_MapIsoTransferToTd(DeviceData,
  125. tmpIsoTransfer,
  126. currentPacket,
  127. td);
  128. // alloc another iso TD
  129. lastTd = td;
  130. // reuse the same td since this is not a real transfer
  131. //td = OHCI_ALLOC_TD(DeviceData, EndpointData);
  132. need++;
  133. SET_NEXT_TD(lastTd, td);
  134. } while (currentPacket < tmpIsoTransfer->PacketCount);
  135. // free the TD we borrowed
  136. OHCI_FREE_TD(DeviceData, EndpointData, td);
  137. ExFreePool(tmpIsoTransfer);
  138. return need;
  139. }
  140. USB_MINIPORT_STATUS
  141. OHCI_IsoTransfer(
  142. PDEVICE_DATA DeviceData,
  143. PENDPOINT_DATA EndpointData,
  144. PTRANSFER_PARAMETERS TransferParameters,
  145. PTRANSFER_CONTEXT TransferContext,
  146. PMINIPORT_ISO_TRANSFER IsoTransfer
  147. )
  148. /*++
  149. Routine Description:
  150. Arguments:
  151. Return Value:
  152. --*/
  153. {
  154. PHCD_TRANSFER_DESCRIPTOR td, lastTd;
  155. ULONG currentPacket;
  156. ULONG tdsNeeded;
  157. EndpointData->PendingTransfers++;
  158. // we have enough tds, program the transfer
  159. LOGENTRY(DeviceData, G, '_nby', EndpointData, TransferParameters,
  160. EndpointData->HcdEd);
  161. TransferContext->IsoTransfer = IsoTransfer;
  162. // lookahead calculation
  163. // see if we can handle this transfer
  164. //
  165. tdsNeeded = OHCI_IsoTransferLookAhead(DeviceData,
  166. EndpointData,
  167. TransferParameters,
  168. TransferContext,
  169. IsoTransfer);
  170. if ((EndpointData->TdCount - EndpointData->PendingTds) <
  171. tdsNeeded) {
  172. return USBMP_STATUS_BUSY;
  173. }
  174. //
  175. // grab the dummy TD from the tail of the queue
  176. //
  177. td = EndpointData->HcdTailP;
  178. OHCI_ASSERT(DeviceData, td->Flags & TD_FLAG_BUSY);
  179. currentPacket = 0;
  180. LOGENTRY(DeviceData, G, '_iso', EndpointData, TransferContext,
  181. td);
  182. do {
  183. INITIALIZE_TD_FOR_TRANSFER(td, TransferContext);
  184. TransferContext->PendingTds++;
  185. EndpointData->PendingTds++;
  186. currentPacket =
  187. OHCI_MapIsoTransferToTd(DeviceData,
  188. IsoTransfer,
  189. currentPacket,
  190. td);
  191. // alloc another iso TD
  192. lastTd = td;
  193. td = OHCI_ALLOC_TD(DeviceData, EndpointData);
  194. OHCI_ASSERT(DeviceData, td != USB_BAD_PTR);
  195. SET_NEXT_TD(lastTd, td);
  196. } while (currentPacket < IsoTransfer->PacketCount);
  197. // td should be the new dummy,
  198. // now put a new dummy TD on the tail of the EP queue
  199. //
  200. SET_NEXT_TD_NULL(td);
  201. //
  202. // Set new TailP in ED
  203. // note: This is the last TD in the list and the place holder.
  204. //
  205. TransferContext->NextXferTd =
  206. EndpointData->HcdTailP = td;
  207. //if (TransferParameters->TransferBufferLength > 128) {
  208. // TEST_TRAP();
  209. //}
  210. // put the request on the hardware queue
  211. LOGENTRY(DeviceData, G,
  212. '_Til', TransferContext->PendingTds ,
  213. td->PhysicalAddress, EndpointData->HcdEd->HwED.HeadP);
  214. EndpointData->HcdEd->HwED.TailP = td->PhysicalAddress;
  215. LOGENTRY(DeviceData, G, '_igo', EndpointData->HcdHeadP,
  216. TransferContext->TcFlags, 0);
  217. //if (TransferParameters->TransferBufferLength > 128) {
  218. // TEST_TRAP();
  219. //}
  220. return USBMP_STATUS_SUCCESS;
  221. }
  222. ULONG
  223. OHCI_MapIsoTransferToTd(
  224. PDEVICE_DATA DeviceData,
  225. PMINIPORT_ISO_TRANSFER IsoTransfer,
  226. ULONG CurrentPacket,
  227. PHCD_TRANSFER_DESCRIPTOR Td
  228. )
  229. /*++
  230. Routine Description:
  231. Arguments:
  232. Returns:
  233. LengthMapped
  234. --*/
  235. {
  236. HW_32BIT_PHYSICAL_ADDRESS logicalStart, logicalEnd;
  237. HW_32BIT_PHYSICAL_ADDRESS startPage, endPage;
  238. PMINIPORT_ISO_PACKET iPacket;
  239. ULONG packetsThisTd;
  240. ULONG lengthThisTd, offset;
  241. USHORT startFrame;
  242. packetsThisTd = 0;
  243. lengthThisTd = 0;
  244. logicalStart = 0;
  245. LOGENTRY(DeviceData, G, '_mpI', CurrentPacket,
  246. IsoTransfer->PacketCount, 0);
  247. OHCI_ASSERT(DeviceData, CurrentPacket < IsoTransfer->PacketCount);
  248. Td->FrameIndex = CurrentPacket;
  249. while (CurrentPacket < IsoTransfer->PacketCount) {
  250. LOGENTRY(DeviceData, G, '_mpC', CurrentPacket,
  251. IsoTransfer->PacketCount, 0);
  252. iPacket = &IsoTransfer->Packets[CurrentPacket];
  253. OHCI_ASSERT(DeviceData, iPacket->BufferPointerCount < 3);
  254. OHCI_ASSERT(DeviceData, iPacket->BufferPointerCount != 0);
  255. // cases are:
  256. // case 1 - packet has pagebreak
  257. // case 1a we have already filled in part of the current TD
  258. // <bail, next pass will be 1b>
  259. //
  260. // case 1b we have not used the current TD yet
  261. // <add packet to TD and bail>
  262. //
  263. // case 2 - packet has no pagebreak and will fit
  264. // case 2a current packet is on different page than previous
  265. // packet
  266. // <add packet and bail>
  267. //
  268. // case 2b current packet is on same page as previous packet
  269. // <add packet and try to add another>
  270. //
  271. // case 2c TD has not been used yet
  272. // <add packet and try to add another>
  273. //
  274. // case 3 - packet will not fit
  275. // <bail>
  276. // does the packet have a page break?
  277. if (iPacket->BufferPointerCount > 1) {
  278. // yes,
  279. // case 1
  280. if (packetsThisTd != 0) {
  281. // case 1a
  282. // we have packets in this TD bail,
  283. // leave it for next time
  284. LOGENTRY(DeviceData, G, '_c1a', 0, 0, lengthThisTd);
  285. break;
  286. }
  287. // case 1b give the packet its own TD
  288. // convert to a 16-bit frame number
  289. startFrame = (USHORT) iPacket->FrameNumber;
  290. LOGENTRY(DeviceData, G, '_c1b', iPacket, CurrentPacket, startFrame);
  291. logicalStart = iPacket->BufferPointer0.Hw32 & ~OHCI_PAGE_SIZE_MASK;
  292. offset = iPacket->BufferPointer0.Hw32 & OHCI_PAGE_SIZE_MASK;
  293. logicalEnd = iPacket->BufferPointer1.Hw32 +
  294. iPacket->BufferPointer1Length;
  295. lengthThisTd = iPacket->Length;
  296. packetsThisTd++;
  297. CurrentPacket++;
  298. Td->HwTD.Packet[0].Offset = (USHORT) offset;
  299. Td->HwTD.Packet[0].Ones = 0xFFFF;
  300. break;
  301. }
  302. // will this packet fit in the current Td?
  303. if (packetsThisTd < 8 &&
  304. (lengthThisTd+iPacket->Length < OHCI_PAGE_SIZE * 2)) {
  305. LOGENTRY(DeviceData, G, '_fit', iPacket, CurrentPacket, 0);
  306. OHCI_ASSERT(DeviceData, iPacket->BufferPointerCount == 1);
  307. OHCI_ASSERT(DeviceData, iPacket->Length ==
  308. iPacket->BufferPointer0Length);
  309. // yes
  310. // case 2
  311. if (logicalStart == 0) {
  312. // first packet, set logical start & end
  313. // case 2c and frame number
  314. LOGENTRY(DeviceData, G, '_c2c', iPacket, CurrentPacket, 0);
  315. startFrame = (USHORT) iPacket->FrameNumber;
  316. offset = iPacket->BufferPointer0.Hw32 & OHCI_PAGE_SIZE_MASK;
  317. logicalStart = iPacket->BufferPointer0.Hw32 & ~OHCI_PAGE_SIZE_MASK;
  318. logicalEnd = iPacket->BufferPointer0.Hw32 +
  319. iPacket->BufferPointer0Length;
  320. lengthThisTd += iPacket->Length;
  321. Td->HwTD.Packet[0].Offset = (USHORT) offset;
  322. Td->HwTD.Packet[0].Ones = 0xFFFF;
  323. packetsThisTd++;
  324. CurrentPacket++;
  325. } else {
  326. // not first packet
  327. LOGENTRY(DeviceData, G, '_adp', iPacket, CurrentPacket,
  328. packetsThisTd);
  329. logicalEnd = iPacket->BufferPointer0.Hw32 +
  330. iPacket->Length;
  331. OHCI_ASSERT(DeviceData, lengthThisTd < OHCI_PAGE_SIZE * 2);
  332. Td->HwTD.Packet[packetsThisTd].Offset
  333. = (USHORT) (lengthThisTd + offset);
  334. Td->HwTD.Packet[packetsThisTd].Ones = 0xFFFF;
  335. lengthThisTd += iPacket->Length;
  336. packetsThisTd++;
  337. startPage = logicalStart & ~OHCI_PAGE_SIZE_MASK;
  338. endPage = logicalEnd & ~OHCI_PAGE_SIZE_MASK;
  339. CurrentPacket++;
  340. // did we cross a page?
  341. if (startPage != endPage) {
  342. // yes, bail now
  343. LOGENTRY(DeviceData, G, '_c2a', Td, CurrentPacket, 0);
  344. break;
  345. }
  346. LOGENTRY(DeviceData, G, '_c2b', Td, CurrentPacket, 0);
  347. // no, keep going
  348. }
  349. } else {
  350. // won't fit
  351. // bail and leave it for next time
  352. LOGENTRY(DeviceData, G, '_ca3', Td, CurrentPacket, 0);
  353. break;
  354. }
  355. }
  356. Td->HwTD.CBP = logicalStart;
  357. Td->HwTD.BE = logicalEnd-1;
  358. Td->TransferCount = lengthThisTd;
  359. Td->HwTD.Iso.StartingFrame = startFrame;
  360. Td->HwTD.Iso.FrameCount = packetsThisTd-1;
  361. Td->HwTD.Iso.Isochronous = 1;
  362. Td->HwTD.Iso.IntDelay = HcTDIntDelay_0ms;
  363. LOGENTRY(DeviceData, G, '_iso', Td, 0, CurrentPacket);
  364. return CurrentPacket;
  365. }
  366. VOID
  367. OHCI_ProcessDoneIsoTd(
  368. PDEVICE_DATA DeviceData,
  369. PHCD_TRANSFER_DESCRIPTOR Td,
  370. BOOLEAN CompleteTransfer
  371. )
  372. /*++
  373. Routine Description:
  374. process a completed Iso TD
  375. Parameters
  376. --*/
  377. {
  378. PTRANSFER_CONTEXT transferContext;
  379. PENDPOINT_DATA endpointData;
  380. USBD_STATUS usbdStatus;
  381. PMINIPORT_ISO_TRANSFER isoTransfer;
  382. ULONG frames, n, i;
  383. transferContext = TRANSFER_CONTEXT_PTR(Td->TransferContext);
  384. isoTransfer = transferContext->IsoTransfer;
  385. transferContext->PendingTds--;
  386. endpointData = transferContext->EndpointData;
  387. endpointData->PendingTds--;
  388. LOGENTRY(DeviceData, G, '_Did', transferContext,
  389. 0,
  390. Td);
  391. // walk the PSWs and fill in the IsoTransfer structure
  392. frames = Td->HwTD.Iso.FrameCount+1;
  393. n = Td->FrameIndex;
  394. for (i = 0; i<frames; i++) {
  395. PMINIPORT_ISO_PACKET mpPak;
  396. PHC_OFFSET_PSW psw;
  397. mpPak = &isoTransfer->Packets[n+i];
  398. psw = &Td->HwTD.Packet[i];
  399. mpPak->LengthTransferred = 0;
  400. if (IN_TRANSFER(transferContext->TransferParameters)) {
  401. // in transfer
  402. // if we got an error the length may still be
  403. // valid, so we return it
  404. if (psw->ConditionCode != HcCC_NotAccessed) {
  405. mpPak->LengthTransferred = psw->Size;
  406. }
  407. LOGENTRY(DeviceData, G, '_isI',
  408. i,
  409. mpPak->LengthTransferred,
  410. psw->ConditionCode);
  411. } else {
  412. // out transfer
  413. // assume all data was sent if no error is indicated
  414. if (psw->ConditionCode == HcCC_NoError) {
  415. mpPak->LengthTransferred = mpPak->Length;
  416. }
  417. LOGENTRY(DeviceData, G, '_isO',
  418. i,
  419. mpPak->LengthTransferred,
  420. psw->ConditionCode);
  421. }
  422. if (psw->ConditionCode == HcCC_NoError) {
  423. mpPak->UsbdStatus = USBD_STATUS_SUCCESS;
  424. } else {
  425. mpPak->UsbdStatus = psw->ConditionCode;
  426. mpPak->UsbdStatus |= 0xC0000000;
  427. }
  428. }
  429. // mark the TD free
  430. OHCI_FREE_TD(DeviceData, endpointData, Td);
  431. if (transferContext->PendingTds == 0 && CompleteTransfer) {
  432. // all TDs for this transfer are done
  433. // clear the HAVE_TRANSFER flag to indicate
  434. // we can take another
  435. endpointData->PendingTransfers--;
  436. transferContext->TransferParameters->FrameCompleted =
  437. OHCI_Get32BitFrameNumber(DeviceData);
  438. LOGENTRY(DeviceData, G, '_cpi',
  439. transferContext,
  440. 0,
  441. 0);
  442. USBPORT_COMPLETE_ISO_TRANSFER(DeviceData,
  443. endpointData,
  444. transferContext->TransferParameters,
  445. transferContext->IsoTransfer);
  446. }
  447. }
  448. VOID
  449. OHCI_PollIsoEndpoint(
  450. PDEVICE_DATA DeviceData,
  451. PENDPOINT_DATA EndpointData
  452. )
  453. /*++
  454. Routine Description:
  455. Called when the endpoint 'needs attention'
  456. The goal here is to determine which TDs, if any,
  457. have completed and complete any associated transfers
  458. Arguments:
  459. Return Value:
  460. --*/
  461. {
  462. PHCD_TRANSFER_DESCRIPTOR td, currentTd;
  463. PHCD_ENDPOINT_DESCRIPTOR ed;
  464. ULONG i;
  465. PTRANSFER_CONTEXT transfer;
  466. HW_32BIT_PHYSICAL_ADDRESS headP;
  467. ed = EndpointData->HcdEd;
  468. LOGENTRY(DeviceData, G, '_pli', ed, 0, 0);
  469. // note it is important the the compiler generate a
  470. // dword move when reading the queuehead HeadP register
  471. // since this location is also accessed by the host
  472. // hardware
  473. headP = ed->HwED.HeadP;
  474. // get the 'currentTD'
  475. currentTd = (PHCD_TRANSFER_DESCRIPTOR)
  476. USBPORT_PHYSICAL_TO_VIRTUAL(headP & ~HcEDHeadP_FLAGS,
  477. DeviceData,
  478. EndpointData);
  479. LOGENTRY(DeviceData, G, '_cTD', currentTd,
  480. headP & ~HcEDHeadP_FLAGS,
  481. TRANSFER_CONTEXT_PTR(currentTd->TransferContext));
  482. // iso endpoints shpuld not halt
  483. OHCI_ASSERT(DeviceData, (ed->HwED.HeadP & HcEDHeadP_HALT) == 0)
  484. // Walk the swHeadP to the current TD (hw headp)
  485. // mark all TDs we find as completed
  486. //
  487. // NOTE: this step may be skipped if the
  488. // done queue is reliable
  489. td = EndpointData->HcdHeadP;
  490. while (td != currentTd) {
  491. LOGENTRY(DeviceData, G, '_mDN', td, 0, 0);
  492. SET_FLAG(td->Flags, TD_FLAG_DONE);
  493. td = TRANSFER_DESCRIPTOR_PTR(td->NextHcdTD);
  494. }
  495. // set the sw headp to the new current head
  496. EndpointData->HcdHeadP = currentTd;
  497. // now flush all completed TDs
  498. for (i=0; i<EndpointData->TdCount; i++) {
  499. td = &EndpointData->TdList->Td[i];
  500. if ((td->Flags & (TD_FLAG_XFER | TD_FLAG_DONE)) ==
  501. (TD_FLAG_XFER | TD_FLAG_DONE)) {
  502. OHCI_ProcessDoneIsoTd(DeviceData,
  503. td,
  504. TRUE);
  505. }
  506. }
  507. }