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.

527 lines
15 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. iso.c
  5. Abstract:
  6. Constructs and handle iso transfers.
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. 1-1-00 : created
  12. --*/
  13. #include "common.h"
  14. #ifdef ALLOC_PRAGMA
  15. #endif
  16. // non paged functions
  17. MP_HW_PHYSICAL_ADDRESS
  18. USBPORT_GetPhysicalAddressFromOffset(
  19. PTRANSFER_SG_LIST SgList,
  20. ULONG Offset,
  21. PULONG Idx
  22. )
  23. /*++
  24. Routine Description:
  25. Arguments:
  26. Return Value:
  27. --*/
  28. {
  29. PTRANSFER_SG_ENTRY32 sg;
  30. ULONG i;
  31. MP_HW_PHYSICAL_ADDRESS p;
  32. ULONG c = SgList->SgCount-1;
  33. for(i=0; i < SgList->SgCount; i++) {
  34. if (Offset >= SgList->SgEntry[i].StartOffset &&
  35. Offset < SgList->SgEntry[i].StartOffset +
  36. SgList->SgEntry[i].Length) {
  37. break;
  38. }
  39. }
  40. // i = idx of sg entry that this packet falls in
  41. sg = &SgList->SgEntry[i];
  42. // the 'offset' of the packet minus the start offset of the
  43. // sg entry is the offset into this sg entry that the packet
  44. // starts
  45. // {.sgN...}{.sgN+1.}{.sgN+2.}{.sgN+3.} sg entries
  46. // b--------------------------->e client buffer
  47. // <p0><p1><p2><p3><p4><p5><p6> urb 'packets'
  48. // x--------x--------x--------x--------x physical pages
  49. // <m0><m1><m2><m3><m4><m5><m6>
  50. *Idx = i;
  51. USBPORT_ASSERT(Offset >= sg->StartOffset);
  52. p = sg->LogicalAddress;
  53. p.Hw32 += (Offset - sg->StartOffset);
  54. return p;
  55. }
  56. VOID
  57. USBPORT_InitializeIsoTransfer(
  58. PDEVICE_OBJECT FdoDeviceObject,
  59. PTRANSFER_URB Urb,
  60. PHCD_TRANSFER_CONTEXT Transfer
  61. )
  62. /*++
  63. Routine Description:
  64. Initialize the iso transfer structure from the
  65. orginal client URB and SG list
  66. {.sgN...}{.sgN...}{..sgN..} sg entries
  67. b--------------------------->e client buffer
  68. <p0><p1><p2><p3><p4><p5><p6> urb 'packets'
  69. x--------x--------x--------x--------x physical pages
  70. <m0><m1><m2><m3><m4><m5><m6>
  71. The sg entries are not that useful to the USB controller
  72. HW since the HW deals in usb packets so we create a structure
  73. that describes the physical addresses assocaited with each
  74. packet.
  75. Arguments:
  76. Return Value:
  77. --*/
  78. {
  79. PDEVICE_EXTENSION devExt;
  80. PMINIPORT_ISO_TRANSFER isoTransfer;
  81. PUSBD_ISO_PACKET_DESCRIPTOR usbdPak;
  82. PMINIPORT_ISO_PACKET mpPak;
  83. PTRANSFER_SG_LIST sgList;
  84. ULONG p, i, cf, j;
  85. ULONG sgIdx_Start, sgIdx_End, offset;
  86. PUCHAR va;
  87. MP_HW_PHYSICAL_ADDRESS b0, b1;
  88. ULONG b1Idx, b0Idx;
  89. BOOLEAN highSpeed;
  90. ASSERT_TRANSFER(Transfer);
  91. highSpeed = TEST_FLAG(Transfer->Flags, USBPORT_TXFLAG_HIGHSPEED);
  92. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  93. ASSERT_FDOEXT(devExt);
  94. isoTransfer = Transfer->IsoTransfer;
  95. sgList = &Transfer->SgList;
  96. LOGENTRY(Transfer->Endpoint,
  97. FdoDeviceObject, LOG_ISO, 'iISO', Urb, Transfer, isoTransfer);
  98. isoTransfer->Sig = SIG_ISOCH;
  99. isoTransfer->PacketCount = Urb->u.Isoch.NumberOfPackets;
  100. isoTransfer->SystemAddress = sgList->MdlSystemAddress;
  101. // note: proper start frame was computed when the transfer
  102. // was queued.
  103. // check the current frame if it is too late to transmit any
  104. // packets set the appropriate errors in the URB
  105. MP_Get32BitFrameNumber(devExt, cf);
  106. LOGENTRY(Transfer->Endpoint,
  107. FdoDeviceObject, LOG_ISO, 'isCf', cf,
  108. Urb->u.Isoch.StartFrame, isoTransfer);
  109. if (highSpeed) {
  110. // for high speed we are dealing with microframes
  111. // (8 packest per frame)
  112. // BUGBUG this needs to be failed
  113. USBPORT_ASSERT((isoTransfer->PacketCount % 8) == 0);
  114. for (i = Urb->u.Isoch.StartFrame;
  115. i < Urb->u.Isoch.StartFrame + Urb->u.Isoch.NumberOfPackets/8;
  116. i++) {
  117. if (i <= cf) {
  118. p = (i - Urb->u.Isoch.StartFrame)*8;
  119. for (j=0; j<8; j++) {
  120. usbdPak = &Urb->u.Isoch.IsoPacket[p+j];
  121. if (usbdPak->Status == USBD_STATUS_NOT_SET) {
  122. usbdPak->Status = USBD_STATUS_ISO_NA_LATE_USBPORT;
  123. LOGENTRY(Transfer->Endpoint,
  124. FdoDeviceObject, LOG_ISO, 'late', cf, i, Transfer);
  125. }
  126. }
  127. }
  128. }
  129. } else {
  130. for (i = Urb->u.Isoch.StartFrame;
  131. i < Urb->u.Isoch.StartFrame + Urb->u.Isoch.NumberOfPackets;
  132. i++) {
  133. if (i <= cf) {
  134. p = i - Urb->u.Isoch.StartFrame;
  135. usbdPak = &Urb->u.Isoch.IsoPacket[p];
  136. if (usbdPak->Status == USBD_STATUS_NOT_SET) {
  137. usbdPak->Status = USBD_STATUS_ISO_NA_LATE_USBPORT;
  138. LOGENTRY(Transfer->Endpoint,
  139. FdoDeviceObject, LOG_ISO, 'late', cf, i, Transfer);
  140. }
  141. }
  142. }
  143. }
  144. // initialize the packets
  145. for (p=0; p< isoTransfer->PacketCount; p++) {
  146. ULONG n;
  147. usbdPak = &Urb->u.Isoch.IsoPacket[p];
  148. mpPak = &isoTransfer->Packets[p];
  149. // first Zero the mp packet
  150. RtlZeroMemory(mpPak, sizeof(*mpPak));
  151. // each packet has an 'offset' from the start
  152. // of the client buffer we need to find the sg
  153. // entry associated with this packet based on
  154. // this 'offset' and get the physical address
  155. // for the satrt of the packet
  156. b0 = USBPORT_GetPhysicalAddressFromOffset(sgList,
  157. usbdPak->Offset,
  158. &b0Idx);
  159. LOGENTRY(NULL, FdoDeviceObject, LOG_ISO, 'ib0=',
  160. usbdPak->Offset, b0Idx, p);
  161. // length is implied by the offset specified in the
  162. // usbd packet, the length is the difference between the
  163. // current packet start offset and the next packet start
  164. // offset.
  165. if (p == isoTransfer->PacketCount - 1) {
  166. n = Transfer->Tp.TransferBufferLength;
  167. } else {
  168. n = Urb->u.Isoch.IsoPacket[p+1].Offset;
  169. }
  170. mpPak->Length = n - usbdPak->Offset;
  171. if (highSpeed) {
  172. mpPak->FrameNumber = Urb->u.Isoch.StartFrame+p/8;
  173. mpPak->MicroFrameNumber = p%8;
  174. } else {
  175. mpPak->FrameNumber = Urb->u.Isoch.StartFrame+p;
  176. }
  177. // get the sg entry associated with the last byte of the packet
  178. b1 = USBPORT_GetPhysicalAddressFromOffset(sgList,
  179. usbdPak->Offset +
  180. mpPak->Length -1,
  181. &b1Idx);
  182. LOGENTRY(NULL, FdoDeviceObject, LOG_ISO, 'ib1=',
  183. usbdPak->Offset, b1Idx, usbdPak->Offset + mpPak->Length);
  184. USBPORT_ASSERT(b1Idx - b0Idx < 2);
  185. if (b0Idx == b1Idx) {
  186. // this packet is contained by a single sg entry
  187. mpPak->BufferPointer0 = b0;
  188. mpPak->BufferPointer0Length = mpPak->Length;
  189. mpPak->BufferPointerCount = 1;
  190. } else {
  191. PTRANSFER_SG_ENTRY32 sg;
  192. // this packet crosses an sg entry...
  193. mpPak->BufferPointer0 = b0;
  194. // since this packet bumps in to the end
  195. // of a page the length is page_size minus
  196. // phys offset
  197. mpPak->BufferPointer0Length = 0x1000;
  198. mpPak->BufferPointer0Length -= (b0.Hw32 & 0xFFF);
  199. // since we crossed an sg entry on this packet
  200. // the start address will be the phys address
  201. // of the sg entry
  202. sg = &sgList->SgEntry[b1Idx];
  203. mpPak->BufferPointer1 = sg->LogicalAddress;
  204. mpPak->BufferPointer1Length = mpPak->Length -
  205. mpPak->BufferPointer0Length;
  206. mpPak->BufferPointerCount = 2;
  207. }
  208. USBPORT_ASSERT(mpPak->BufferPointerCount != 0);
  209. }
  210. }
  211. VOID
  212. USBPORT_ErrorCompleteIsoTransfer(
  213. PDEVICE_OBJECT FdoDeviceObject,
  214. PHCD_ENDPOINT Endpoint,
  215. PHCD_TRANSFER_CONTEXT Transfer
  216. )
  217. /*++
  218. Routine Description:
  219. Arguments:
  220. Return Value:
  221. None.
  222. --*/
  223. {
  224. PDEVICE_EXTENSION devExt;
  225. PTRANSFER_URB urb;
  226. USBD_STATUS usbdStatus;
  227. PMINIPORT_ISO_TRANSFER isoTransfer;
  228. ULONG bytesTransferred, p;
  229. ASSERT_TRANSFER(Transfer);
  230. isoTransfer = Transfer->IsoTransfer;
  231. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  232. ASSERT_FDOEXT(devExt);
  233. ASSERT_ENDPOINT(Endpoint);
  234. usbdStatus = USBD_STATUS_ISOCH_REQUEST_FAILED;
  235. urb = Transfer->Urb;
  236. LOGENTRY(Endpoint, FdoDeviceObject, LOG_ISO, 'cpLi', 0,
  237. Transfer, urb);
  238. ASSERT_TRANSFER_URB(urb);
  239. USBPORT_KdPrint((1, " ISO (USBD_STATUS_ISOCH_REQUEST_FAILED) - packets %d\n",
  240. isoTransfer->PacketCount));
  241. // do some conversion on the isoTransfer data
  242. bytesTransferred = 0;
  243. urb->u.Isoch.ErrorCount = isoTransfer->PacketCount;
  244. for (p=0; p<isoTransfer->PacketCount; p++) {
  245. urb->u.Isoch.IsoPacket[p].Status =
  246. isoTransfer->Packets[p].UsbdStatus;
  247. }
  248. urb->TransferBufferLength = bytesTransferred;
  249. // insert the transfer on to our
  250. // 'done list', this riutine initaites
  251. // a DPC to complete the transfers
  252. #ifdef USBPERF
  253. USBPORT_QueueDoneTransfer(Transfer,
  254. usbdStatus);
  255. #else
  256. USBPORT_QueueDoneTransfer(Transfer,
  257. usbdStatus);
  258. USBPORT_SignalWorker(FdoDeviceObject);
  259. #endif
  260. }
  261. USBD_STATUS
  262. USBPORT_FlushIsoTransfer(
  263. PDEVICE_OBJECT FdoDeviceObject,
  264. PTRANSFER_PARAMETERS TransferParameters,
  265. PMINIPORT_ISO_TRANSFER IsoTransfer
  266. )
  267. /*++
  268. Routine Description:
  269. called to complete a transfer.
  270. ** Must be called in the context of PollEndpoint
  271. Arguments:
  272. Return Value:
  273. None.
  274. --*/
  275. {
  276. PDEVICE_EXTENSION devExt;
  277. PHCD_TRANSFER_CONTEXT transfer;
  278. PTRANSFER_URB urb;
  279. USBD_STATUS usbdStatus = USBD_STATUS_SUCCESS;
  280. ULONG bytesTransferred, p;
  281. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  282. ASSERT_FDOEXT(devExt);
  283. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'cpTi', 0,
  284. TransferParameters->FrameCompleted,
  285. TransferParameters);
  286. TRANSFER_FROM_TPARAMETERS(transfer, TransferParameters);
  287. ASSERT_TRANSFER(transfer);
  288. urb = transfer->Urb;
  289. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'cpUi', 0,
  290. transfer, urb);
  291. ASSERT_TRANSFER_URB(urb);
  292. transfer->MiniportFrameCompleted =
  293. TransferParameters->FrameCompleted;
  294. // do some conversion on the isoTransfer data
  295. bytesTransferred = 0;
  296. urb->u.Isoch.ErrorCount = 0;
  297. for (p=0; p<IsoTransfer->PacketCount; p++) {
  298. bytesTransferred += IsoTransfer->Packets[p].LengthTransferred;
  299. urb->u.Isoch.IsoPacket[p].Status =
  300. IsoTransfer->Packets[p].UsbdStatus;
  301. // note:
  302. // in an effort to create some consistency we handle the buffer
  303. // underrun case here.
  304. // That is:
  305. // if the SHORT_XFER_OK flag is set AND
  306. // the error is USBD_STATUS_DATA_UNDERRUN
  307. // then
  308. // ignore the error
  309. // NOTE: The OHCI controllers report USBD_STATUS_DATA_UNDERRUN
  310. // for short iso packets
  311. if (/*urb->TransferFlags & USBD_SHORT_TRANSFER_OK && */
  312. urb->u.Isoch.IsoPacket[p].Status == USBD_STATUS_DATA_UNDERRUN) {
  313. urb->u.Isoch.IsoPacket[p].Status = USBD_STATUS_SUCCESS;
  314. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'igER',
  315. urb->u.Isoch.IsoPacket[p].Status,
  316. transfer,
  317. urb);
  318. }
  319. if (urb->u.Isoch.IsoPacket[p].Status != USBD_STATUS_SUCCESS) {
  320. urb->u.Isoch.ErrorCount++;
  321. }
  322. if (transfer->Direction == ReadData) {
  323. urb->u.Isoch.IsoPacket[p].Length =
  324. IsoTransfer->Packets[p].LengthTransferred;
  325. }
  326. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'isoP',
  327. urb->u.Isoch.IsoPacket[p].Length,
  328. urb->u.Isoch.IsoPacket[p].Status,
  329. 0);
  330. }
  331. if (urb->u.Isoch.ErrorCount ==
  332. IsoTransfer->PacketCount) {
  333. // all errors set global status in urb
  334. usbdStatus = USBD_STATUS_ISOCH_REQUEST_FAILED;
  335. }
  336. LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'isoD', 0,
  337. bytesTransferred, urb->u.Isoch.ErrorCount);
  338. transfer->MiniportBytesTransferred =
  339. bytesTransferred;
  340. return usbdStatus;
  341. }
  342. VOID
  343. USBPORTSVC_CompleteIsoTransfer(
  344. PDEVICE_DATA DeviceData,
  345. PENDPOINT_DATA EndpointData,
  346. PTRANSFER_PARAMETERS TransferParameters,
  347. PMINIPORT_ISO_TRANSFER IsoTransfer
  348. )
  349. /*++
  350. Routine Description:
  351. called to complete a transfer.
  352. ** Must be called in the context of PollEndpoint
  353. Arguments:
  354. Return Value:
  355. None.
  356. --*/
  357. {
  358. PDEVICE_EXTENSION devExt;
  359. PHCD_TRANSFER_CONTEXT transfer;
  360. PDEVICE_OBJECT fdoDeviceObject;
  361. USBD_STATUS usbdStatus;
  362. ULONG bytesTransferred, p;
  363. DEVEXT_FROM_DEVDATA(devExt, DeviceData);
  364. ASSERT_FDOEXT(devExt);
  365. fdoDeviceObject = devExt->HcFdoDeviceObject;
  366. TRANSFER_FROM_TPARAMETERS(transfer, TransferParameters);
  367. ASSERT_TRANSFER(transfer);
  368. SET_FLAG(transfer->Flags, USBPORT_TXFLAG_MPCOMPLETED);
  369. usbdStatus = USBPORT_FlushIsoTransfer(fdoDeviceObject,
  370. TransferParameters,
  371. IsoTransfer);
  372. // insert the transfer on to our
  373. // 'done list' and signal the worker
  374. // thread
  375. #ifdef USBPERF
  376. USBPORT_QueueDoneTransfer(transfer,
  377. usbdStatus);
  378. #else
  379. USBPORT_QueueDoneTransfer(transfer,
  380. usbdStatus);
  381. USBPORT_SignalWorker(devExt->HcFdoDeviceObject);
  382. #endif
  383. }