Source code of Windows XP (NT5)
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.

1700 lines
65 KiB

  1. /***************************************************************************
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. iso.c
  5. Abstract:
  6. Environment:
  7. kernel mode only
  8. Notes:
  9. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  10. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  11. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  12. PURPOSE.
  13. Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  14. Revision History:
  15. ****************************************************************************/
  16. #define DRIVER
  17. #pragma warning(disable:4214) // bitfield nonstd
  18. #include "wdm.h"
  19. #pragma warning(default:4214)
  20. #include "stdarg.h"
  21. #include "stdio.h"
  22. #pragma warning(disable:4200) //non std struct used
  23. #include "usbdi.h"
  24. #pragma warning(default:4200)
  25. #include "usbdlib.h"
  26. #include "usb.h"
  27. #include "ioctl.h"
  28. #include "isoperf.h"
  29. #include "iso.h"
  30. #define MAX_URBS_PER_PIPE 16
  31. UCHAR ucIsoInterface = 0;
  32. // Memory Leak detection global counters
  33. ULONG gulBytesAllocated = 0;
  34. ULONG gulBytesFreed = 0;
  35. NTSTATUS
  36. ISOPERF_RefreshIsoUrb(
  37. PURB urb,
  38. USHORT packetSize,
  39. USBD_PIPE_HANDLE pipeHandle,
  40. PVOID pvDataBuffer,
  41. ULONG ulDataBufferLen
  42. )
  43. /*++
  44. Routine Description:
  45. Refreshes an Iso Usb Request Block in prep for resubmission to USB stack.
  46. Arguments:
  47. urb - pointer to urb to refresh
  48. packetsize - max packet size for the endpoint for which this urb is intended
  49. pipeHandle - Usbd pipe handle for the Urb
  50. pvDataBuff - pointer to a data buffer that will contain data or will receive data
  51. ulDataBufLen- length of data buffer
  52. Return Value:
  53. NT status code:
  54. STATUS_SUCCESS indicates Urb successfully refreshed
  55. Other status codes indicate error (most likely is a bad parameter passed in, which
  56. would result in STATUS_INVALID_PARAMETER to be returned)
  57. --*/
  58. {
  59. NTSTATUS ntStatus = STATUS_SUCCESS;
  60. ULONG siz = 0;
  61. ULONG i = 0;
  62. ULONG numPackets = 0;
  63. // Calculate the number of packets in this buffer
  64. numPackets = ulDataBufferLen/packetSize;
  65. // Adjust num packets by one if data buffer can accommodate it
  66. if (numPackets*packetSize < ulDataBufferLen) {
  67. numPackets++;
  68. }
  69. //
  70. // Use macro from provided by stack to figure out Urb length for given size of packets. This is
  71. // necessary since Urb for iso transfers depends on the number of packets in the data buffer
  72. // since per-packet information is passed on the usbd interface
  73. //
  74. siz = GET_ISO_URB_SIZE(numPackets);
  75. // Clear out any garbage that may have gotten put in the urb by the last transfer
  76. RtlZeroMemory(urb, siz);
  77. // Now fill in the Urb
  78. urb->UrbIsochronousTransfer.Length = (USHORT) siz;
  79. urb->UrbIsochronousTransfer.Function = URB_FUNCTION_ISOCH_TRANSFER;
  80. urb->UrbIsochronousTransfer.PipeHandle = pipeHandle;
  81. urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN;
  82. urb->UrbIsochronousTransfer.TransferBufferMDL = NULL;
  83. urb->UrbIsochronousTransfer.TransferBuffer = pvDataBuffer;
  84. urb->UrbIsochronousTransfer.TransferBufferLength = numPackets * packetSize;
  85. ASSERT (ulDataBufferLen >= numPackets*packetSize);
  86. // This flag tells the stack to start sending/receiving right away
  87. urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;
  88. urb->UrbIsochronousTransfer.StartFrame = 0;
  89. urb->UrbIsochronousTransfer.NumberOfPackets = numPackets;
  90. urb->UrbIsochronousTransfer.ReservedMBZ = 0;
  91. for (i=0; i< urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
  92. urb->UrbIsochronousTransfer.IsoPacket[i].Offset
  93. = i * packetSize;
  94. }//for
  95. return ntStatus;
  96. }//ISOPERF_RefreshIsoUrb
  97. NTSTATUS
  98. ISOPERF_IsoInCompletion(
  99. IN PDEVICE_OBJECT DeviceObject,
  100. IN PIRP Irp,
  101. IN PVOID Context
  102. )
  103. /*++
  104. Routine Description:
  105. This is the completion routine that is called at the end of an iso Irp/Urb. It is
  106. called when the Usb stack completes the Irp.
  107. NOTE: IoCompletion routine always runs at IRQL DISPATCH_LEVEL.
  108. Arguments:
  109. DeviceObject - pointer to the device object that represents this USB iso test device
  110. DeviceObject is obtained from context due to old, old bug
  111. in initial WDM implemenations
  112. Irp - pointer to the Irp that was completed by the usb stack
  113. Context - caller-supplied context that is passed in for use by this completion routine
  114. Return Value:
  115. NT status code
  116. --*/
  117. {
  118. PIsoTxterContext pIsoContext = Context;
  119. PDEVICE_OBJECT myDeviceObject = pIsoContext->DeviceObject;
  120. PDEVICE_EXTENSION deviceExtension = myDeviceObject->DeviceExtension;
  121. pConfig_Stat_Info pStatInfo = deviceExtension->pConfig_Stat_Information;
  122. PIO_STACK_LOCATION nextStack = NULL;
  123. PURB urb = pIsoContext->urb;
  124. PISOPERF_WORKITEM isoperfWorkItem = NULL;
  125. PDEVICE_EXTENSION MateDeviceExtension = NULL;
  126. ULONG unew,lnew,uold,lold;
  127. char * pcWork = NULL; //a worker pointer
  128. ULONG i = 0;
  129. char tempStr[32];
  130. ISO_ASSERT (pIsoContext != NULL);
  131. ISO_ASSERT (pStatInfo != NULL);
  132. ISO_ASSERT (deviceExtension != NULL);
  133. ISOPERF_KdPrint_MAXDEBUG (("In IsoInCompletionRoutine %x %x %x\n",
  134. DeviceObject, Irp, Context));
  135. // Check the USBD status code and only proceed in resubmission if the Urb was successful
  136. // or if the device extension flag that indicates the device is gone is FALSE
  137. if ( (USBD_SUCCESS(urb->UrbHeader.Status)) && ((deviceExtension->StopTransfers) == FALSE) ) {
  138. ISOPERF_GetUrbTimeStamp (urb, &lold, &uold); //Get the Urb's timestamp
  139. GET_PENTIUM_CLOCK_COUNT(unew,lnew); //Get the time now
  140. pStatInfo->ulUrbDeltaClockCount = lnew-lold; //Compute & store the delta
  141. // Check that data is incrementing from last data pattern received on this pipe
  142. if ((ISOPERF_IsDataGood(pIsoContext))== TRUE) {
  143. // Data was good
  144. pStatInfo->ulSuccessfulIrps++;
  145. pStatInfo->ulBytesTransferredIn += pIsoContext->ulBufferLen;
  146. } else {
  147. // An error occured, so stop the test by setting the flag to stop the test
  148. deviceExtension->bStopIsoTest = TRUE;
  149. deviceExtension->ulCountDownToStop = 0;
  150. // Put this information in the status area for the device so the app can see it when it asks
  151. pStatInfo->erError = DataCompareFailed;
  152. pStatInfo->bStopped = 1;
  153. }//else data was bad
  154. if ( (deviceExtension->bStopIsoTest == TRUE) && (deviceExtension->ulCountDownToStop > 0) ) {
  155. // User has requested a stop to the Iso Test so, decrement the countdown value
  156. (deviceExtension->ulCountDownToStop)--;
  157. }//if user requested a stop
  158. // If device extension says to keep going on this test then continue on
  159. if ((deviceExtension->ulCountDownToStop) > 0) {
  160. // Refresh this Urb before we resubmit it to the stack
  161. ISOPERF_RefreshIsoUrb (pIsoContext->urb,
  162. pIsoContext->PipeInfo->MaximumPacketSize,
  163. pIsoContext->PipeInfo->PipeHandle,
  164. pIsoContext->pvBuffer,
  165. pIsoContext->ulBufferLen
  166. );
  167. // If this iso in device has a mate, then start a thread to have it use this data buffer
  168. if (deviceExtension->MateDeviceObject) {
  169. MateDeviceExtension = deviceExtension->MateDeviceObject->DeviceExtension;
  170. // Check if the mate device is up and running
  171. if ( (MateDeviceExtension->Stopped == FALSE) && (MateDeviceExtension->StopTransfers == FALSE) ) {
  172. //start a Work Item to use this buffer which will only do so when the buffer has arrived
  173. isoperfWorkItem = ISOPERF_ExAllocatePool(NonPagedPool, sizeof(ISOPERF_WORKITEM),&gulBytesAllocated);
  174. isoperfWorkItem->DeviceObject = deviceExtension->MateDeviceObject;
  175. isoperfWorkItem->pvBuffer = pIsoContext->pvBuffer;
  176. isoperfWorkItem->ulBufferLen = pIsoContext->ulBufferLen;
  177. isoperfWorkItem->bFirstUrb = pIsoContext->bFirstUrb;
  178. isoperfWorkItem->InMaxPacket = pIsoContext->PipeInfo->MaximumPacketSize;
  179. isoperfWorkItem->ulNumberOfFrames = urb->UrbIsochronousTransfer.NumberOfPackets;
  180. // Call the OUT pipe transfer routine
  181. ISOPERF_StartIsoOutTest (isoperfWorkItem);
  182. // Since the firstUrb flag is used to tell the outpipe whether it's a virgin or not,
  183. // and since this Urb can be recycled through here again, we have to de-virginize the
  184. // flag so this Urb doesn't always cause the outpipe to think it's dealing with a virgin Urb.
  185. if (pIsoContext->bFirstUrb == TRUE) {
  186. pIsoContext->bFirstUrb = FALSE;
  187. }//if this was the first Urb
  188. }//if mate device is ok
  189. }//if there is a mate device in the system (that this driver runs)
  190. // Get the next lower driver's stack
  191. nextStack = IoGetNextIrpStackLocation(Irp);
  192. ASSERT(nextStack != NULL);
  193. //
  194. // Set up the next lower driver's stack parameters which is where that
  195. // driver will go to get its parameters for this internal IOCTL Irp
  196. //
  197. nextStack->Parameters.Others.Argument1 = urb;
  198. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  199. nextStack->Parameters.DeviceIoControl.IoControlCode =
  200. IOCTL_INTERNAL_USB_SUBMIT_URB;
  201. IoSetCompletionRoutine(Irp,
  202. ISOPERF_IsoInCompletion,
  203. pIsoContext,
  204. TRUE,
  205. TRUE,
  206. FALSE); //INVOKE ON CANCEL
  207. // Time stamp the Urb before we send it down the stack
  208. ISOPERF_TimeStampUrb (urb, &unew, &lnew);
  209. // Call the driver
  210. IoCallDriver (deviceExtension->StackDeviceObject,
  211. Irp);
  212. // Tell the IO Manager that we want to handle this Irp from here on...
  213. return (STATUS_MORE_PROCESSING_REQUIRED);
  214. } else {
  215. ISOPERF_KdPrint (("Stopped Iso test (did not resubmit Irp/Urb due to device extension flag)\n"));
  216. }/* else the tests should be stopped */
  217. }//if Urb status was successful
  218. // Otherwise, the Urb was unsuccessful
  219. else {
  220. pStatInfo->erError = UsbdErrorInCompletion;
  221. pStatInfo->ulUnSuccessfulIrps++;
  222. FIRE_OFF_CATC;
  223. if (!(USBD_SUCCESS(urb->UrbHeader.Status))) {
  224. ISOPERF_KdPrint (("Urb unsuccessful (status: %#x)\n",urb->UrbHeader.Status));
  225. // Dump out the status for the packets
  226. for (i=0; i< urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
  227. ISOPERF_KdPrint (("Packet %d: Status: [%#X]\n",
  228. i,
  229. urb->UrbIsochronousTransfer.IsoPacket[i].Status));
  230. // Put the last known bad packet status code into this space in the stat area
  231. if (!USBD_SUCCESS(urb->UrbIsochronousTransfer.IsoPacket[i].Status)) {
  232. pStatInfo->UsbdPacketStatCode = urb->UrbIsochronousTransfer.IsoPacket[i].Status;
  233. }//if hit a fail code
  234. sprintf (tempStr, "Data: %x", *((PULONG)(urb->UrbIsochronousTransfer.TransferBuffer)));
  235. ISOPERF_KdPrint (("First data in buffer: %s\n",tempStr));
  236. }//for all the packets
  237. }else {
  238. ISOPERF_KdPrint (("Urb successful, but StopTransfers flag is set (%d)\n",deviceExtension->StopTransfers));
  239. }
  240. }//Urb was unsuccessful, so don't repost it and fall thru to cleanup code
  241. // Clean up section. This only executes if:
  242. // --Urb (bus transfer) was unsuccessful (stop the test)
  243. // --Buffer didn't look right (a hiccup was detected, etc.)
  244. // --User requested tests to stop
  245. ISOPERF_KdPrint (("Stopping Iso In Stream and Cleaning Up...U:%x|C:%x|B:%x\n",
  246. urb,
  247. pIsoContext,
  248. pIsoContext->pvBuffer));
  249. // Free up the memory created for this transfer that we are retiring
  250. if (urb) {
  251. // We can't free the Urb itself, since it has some junk before it, so we have to roll back the
  252. // pointer to get to the beginning of the block that we originally allocated, and then try to free it.
  253. pcWork = (char*)urb; //get the urb
  254. urb = (PURB) (pcWork - (2*sizeof(ULONG))); //the original pointer is 2 DWORDs behind the Urb
  255. ISOPERF_KdPrint (("Freeing urb %x\n",urb));
  256. ISOPERF_ExFreePool (urb, &gulBytesFreed); //Free that buffer
  257. }//if
  258. if (pIsoContext) {
  259. // Free the data buffer
  260. if (pIsoContext->pvBuffer) {
  261. ISOPERF_KdPrint (("Freeing databuff %x\n",pIsoContext->pvBuffer));
  262. ISOPERF_ExFreePool (pIsoContext->pvBuffer, &gulBytesFreed);
  263. }
  264. // Free the Iso Context
  265. ISOPERF_KdPrint (("Freeing pIsoContext %x\n",pIsoContext));
  266. ISOPERF_ExFreePool (pIsoContext, &gulBytesFreed);
  267. }//if valid Iso Context
  268. //Decrement the number of outstanding Irps since this one is being retired
  269. (deviceExtension->ulNumberOfOutstandingIrps)--;
  270. // If this is the last Irp we are retiring, then the device should be marked as not busy
  271. if (deviceExtension->ulNumberOfOutstandingIrps == 0) {
  272. deviceExtension->DeviceIsBusy = FALSE;
  273. pStatInfo->bDeviceRunning = FALSE;
  274. }//if not irps left outstanding on this device
  275. //Free the IoStatus block that we allocated for this Irp
  276. if (Irp->UserIosb) {
  277. ISOPERF_KdPrint (("Freeing My IoStatusBlock %x\n",Irp->UserIosb));
  278. ISOPERF_ExFreePool(Irp->UserIosb, &gulBytesFreed);
  279. } else {
  280. //Bad thing...no IoStatus block pointer??
  281. ISOPERF_KdPrint (("ERROR: Irp's IoStatus block is apparently NULL!\n"));
  282. TRAP();
  283. }//else bad iostatus pointer
  284. //Free the Irp here and return STATUS_MORE_PROCESSING_REQUIRED instead of SUCCESS
  285. ISOPERF_KdPrint (("Freeing Irp %x\n",Irp));
  286. IoFreeIrp(Irp);
  287. // Tell the IO Manager that we want to handle this Irp from here on...
  288. ISOPERF_KdPrint (("Returning STATUS_MORE_PROCESSING_REQUIRED from IsoInCompletion\n"));
  289. return (STATUS_MORE_PROCESSING_REQUIRED);
  290. }//ISOPERF_IsoInCompletion
  291. PURB
  292. ISOPERF_BuildIsoRequest(
  293. IN PDEVICE_OBJECT DeviceObject,
  294. IN PUSBD_PIPE_INFORMATION pPipeInfo,
  295. IN BOOLEAN Read,
  296. IN ULONG length,
  297. IN ULONG ulFrameNumber,
  298. IN PVOID pvTransferBuffer,
  299. IN PMDL pMDL
  300. )
  301. /*++
  302. Routine Description:
  303. Allocates and initializes most of a URB. The caller must initialize the FLAGS field
  304. with any further flags they desire after this function is called.
  305. Arguments:
  306. DeviceObject - pointer to the device extension for this instance of the device
  307. pPipeInfo - ptr to pipe descr for which to build the iso request (urb)
  308. Read - if TRUE, it's a read, FALSE it's a write
  309. length - length of the data buffer or MDL, used for packetizing the buffer for iso txfer
  310. ulframeNumber- if non-zero, use this frame number to build in the urb and don't set flags
  311. pvTransferBuffer - Non-NULL: this is the TB ; NULL: an MDL is specified
  312. ulTransferBufferLength - len of buffer specified in pvTransferBuffer
  313. pMDL - if an MDL is being used, this is a ptr to it
  314. Return Value:
  315. Almost initialized iso urb. Caller must fill in the flags after this fn is called.
  316. --*/
  317. {
  318. ULONG siz;
  319. ULONG packetSize,numPackets, i;
  320. PURB urb = NULL;
  321. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  322. char * pcWork = NULL;
  323. ISO_ASSERT(pPipeInfo!=NULL)
  324. packetSize = pPipeInfo->MaximumPacketSize;
  325. numPackets = length/packetSize;
  326. if (numPackets*packetSize < length) {
  327. numPackets++;
  328. }
  329. siz = GET_ISO_URB_SIZE(numPackets);
  330. //Add room for a URB time stamp at the beginning of the Urb by allocating more than
  331. //siz by 4 DWORDs. The pentium clock count macro can then be used by the caller of
  332. //this routine to fill in the clock count stamp. We allocate an extra 2 DWORDs more than
  333. //we need to allow some room for stuff to put at the end of the URB in the future.
  334. pcWork = ISOPERF_ExAllocatePool(NonPagedPool, (siz+(4*sizeof(ULONG))), &gulBytesAllocated);
  335. urb = (PURB) (pcWork + (2*sizeof(ULONG))); //Push pass the clock count area to the urb area
  336. if (urb) {
  337. RtlZeroMemory(urb, siz);
  338. urb->UrbIsochronousTransfer.Length = (USHORT) siz;
  339. urb->UrbIsochronousTransfer.Function = URB_FUNCTION_ISOCH_TRANSFER;
  340. urb->UrbIsochronousTransfer.PipeHandle = pPipeInfo->PipeHandle;
  341. urb->UrbIsochronousTransfer.TransferFlags = Read ? USBD_TRANSFER_DIRECTION_IN : 0;
  342. urb->UrbIsochronousTransfer.TransferBufferMDL = pMDL;
  343. urb->UrbIsochronousTransfer.TransferBuffer = pvTransferBuffer;
  344. urb->UrbIsochronousTransfer.TransferBufferLength = length;
  345. urb->UrbIsochronousTransfer.Function = URB_FUNCTION_ISOCH_TRANSFER;
  346. if (ulFrameNumber==0) {
  347. //No frame number specified, just start asap
  348. urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;
  349. }else{
  350. //use specific starting framenumber & don't set (unset) the asap flag
  351. urb->UrbIsochronousTransfer.StartFrame = ulFrameNumber;
  352. urb->UrbIsochronousTransfer.TransferFlags &= ~USBD_START_ISO_TRANSFER_ASAP;
  353. }//if framenumber was specified
  354. urb->UrbIsochronousTransfer.NumberOfPackets = numPackets;
  355. urb->UrbIsochronousTransfer.ReservedMBZ = 0;
  356. // Fill in the packet size array
  357. for (i=0; i< urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
  358. urb->UrbIsochronousTransfer.IsoPacket[i].Offset
  359. = i * packetSize;
  360. } //for
  361. }//if urb
  362. return urb;
  363. }
  364. PVOID
  365. ISOPERF_GetBuff (
  366. PDEVICE_OBJECT DeviceObject,
  367. ULONG ulPipeNumber,
  368. ULONG ulInterfaceNumber,
  369. ULONG ulNumberOfFrames,
  370. PULONG pulBufferSize
  371. )
  372. /*++
  373. ISOPERF_GetBuff
  374. Routine Description:
  375. Creates a buffer as specified by input params. If the input params specify a buffer
  376. that is too big to be submitted to this pipe, then this request will fail.
  377. Arguments:
  378. DeviceObject - pointer to the device extension for this instance of the device
  379. Return Value:
  380. Returns a pointer to the allocated data buffer
  381. --*/
  382. {
  383. PDEVICE_EXTENSION deviceExtension = NULL;
  384. ULONG ulMaxPacketSize = 0;
  385. ULONG ulBufferSize = 0;
  386. ULONG ulMaxTxferSize = 0;
  387. PVOID pvBuffer = NULL;
  388. deviceExtension = DeviceObject->DeviceExtension;
  389. ulMaxPacketSize = deviceExtension->Interface[ulInterfaceNumber]->Pipes[ulPipeNumber].MaximumPacketSize;
  390. ulMaxTxferSize = deviceExtension->Interface[ulInterfaceNumber]->Pipes[ulPipeNumber].MaximumTransferSize;
  391. ulBufferSize = *pulBufferSize = ulMaxPacketSize * ulNumberOfFrames;
  392. // Check if this buffer is too big to submit on this pipe (per its initial setup)
  393. if (ulBufferSize > ulMaxTxferSize) {
  394. *pulBufferSize = 0;
  395. return (NULL);
  396. } else {
  397. return ( ISOPERF_ExAllocatePool (NonPagedPool, ulBufferSize, &gulBytesAllocated) );
  398. }
  399. }//ISOPERF_GetBuff
  400. ULONG
  401. ISOPERF_StartIsoInTest (
  402. PDEVICE_OBJECT DeviceObject,
  403. PIRP pIrp
  404. )
  405. /*++
  406. ISOPERF_StartIsoInTest
  407. Routine Description:
  408. Starts the Iso In Test
  409. Arguments:
  410. DeviceObject - pointer to the device extension for this instance of the device
  411. pIrp - pointer to the Irp from the Ioctl
  412. Return Value:
  413. --*/
  414. {
  415. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  416. PDEVICE_EXTENSION deviceExtension = NULL;
  417. PURB urb = NULL;
  418. ULONG ulFrameNumber = 0;
  419. ULONG UrbNumber = 0;
  420. ULONG NumberOfFrames = 0;
  421. PUSBD_INTERFACE_INFORMATION pInterfaceInfo = NULL;
  422. PUSBD_PIPE_INFORMATION pUsbdPipeInfo = NULL;
  423. PUSBD_INTERFACE_INFORMATION pMateInterfaceInfo = NULL;
  424. PUSBD_PIPE_INFORMATION pMateUsbdPipeInfo = NULL;
  425. ULONG ulBufferSize = 0;
  426. IsoTxferContext * pIsoContext = NULL;
  427. PVOID pvBuff = NULL;
  428. BOOLEAN bFirstUrb = FALSE;
  429. BOOLEAN bHaveMate = FALSE;
  430. ULONG Upper, Lower;
  431. pConfig_Stat_Info configStatInfo = NULL;
  432. ULONG Max_Urbs_Per_Pipe = 0;
  433. PDEVICE_OBJECT mateDeviceObject = NULL;
  434. PDEVICE_EXTENSION mateDeviceExtension = NULL;
  435. pConfig_Stat_Info mateConfigStatInfo = NULL;
  436. char * pcWork = NULL;
  437. ISOPERF_KdPrint (("Enter ISOPERF_StartIsoInTest (%x) (%x)\n",DeviceObject, pIrp));
  438. deviceExtension = DeviceObject->DeviceExtension;
  439. pInterfaceInfo = deviceExtension->Interface[ucIsoInterface];
  440. ISO_ASSERT (pInterfaceInfo!=NULL)
  441. //make sure this is an IN Iso device
  442. if (deviceExtension->dtTestDeviceType != Iso_In_With_Pattern) {
  443. ISOPERF_KdPrint (("Error: not an Iso IN device! (%d)\n",deviceExtension->dtTestDeviceType));
  444. TRAP();
  445. return (ULONG)STATUS_INVALID_PARAMETER;
  446. }//if it's NOT an ISO IN then bounce it back
  447. // Get the config info for the In Iso Device
  448. configStatInfo = deviceExtension->pConfig_Stat_Information;
  449. ASSERT (configStatInfo != NULL);
  450. // Check out the offset provided to make sure it's not too big
  451. if (configStatInfo->ulFrameOffset >= USBD_ISO_START_FRAME_RANGE) {
  452. ISOPERF_KdPrint (("Error: Detected a FrameOffset Larger than allowed! (%d)\n",configStatInfo->ulFrameOffset));
  453. TRAP();
  454. return (ULONG)STATUS_INVALID_PARAMETER;
  455. }//if bad frame offset
  456. if (configStatInfo) {
  457. Max_Urbs_Per_Pipe = configStatInfo->ulMax_Urbs_Per_Pipe;
  458. NumberOfFrames = configStatInfo->ulNumberOfFrames;
  459. }//if configstatinfo is not null
  460. // Only set up the output device if the config info indicates a desire to do the In->Out test
  461. if (configStatInfo->ulDoInOutTest) {
  462. //If there is an OUT Iso device, and we are trying to do a IN->OUT test, then set that device object up
  463. ntStatus = ISOPERF_FindMateDevice (DeviceObject);
  464. if (ntStatus == STATUS_SUCCESS) {
  465. bHaveMate = TRUE;
  466. mateDeviceObject = deviceExtension->MateDeviceObject;
  467. mateDeviceExtension = mateDeviceObject->DeviceExtension;
  468. pMateInterfaceInfo = mateDeviceExtension->Interface[ucIsoInterface];
  469. mateConfigStatInfo = mateDeviceExtension->pConfig_Stat_Information;
  470. mateConfigStatInfo->ulFrameOffset = configStatInfo->ulFrameOffsetMate;
  471. }//if status success
  472. // Reset the pipe on the mate device if it's also here
  473. // NOTE: we only reset the first pipe on the mate device here
  474. if (bHaveMate == TRUE) {
  475. ASSERT (pMateInterfaceInfo!=NULL);
  476. pMateUsbdPipeInfo = &(pMateInterfaceInfo->Pipes[0]);
  477. ASSERT (pMateUsbdPipeInfo != NULL);
  478. ISOPERF_ResetPipe(deviceExtension->MateDeviceObject,pMateUsbdPipeInfo);
  479. }// if mate
  480. } else {
  481. // Set the mate dev obj to NULL so completion routine knows not to use it
  482. deviceExtension->MateDeviceObject = NULL;
  483. }//if In->Out test is not being requested
  484. // Reset the first pipe on the IN device
  485. pUsbdPipeInfo= &(pInterfaceInfo->Pipes[0]);
  486. ISOPERF_ResetPipe(DeviceObject, pUsbdPipeInfo);
  487. // Untrigger the CATC so if we trigger it later it will go off
  488. RESTART_CATC;
  489. // Get the current frame number
  490. ulFrameNumber = ISOPERF_GetCurrentFrame(DeviceObject);
  491. //Save away the current frame number so the app can peek at it
  492. configStatInfo->ulFrameNumberAtStart = ulFrameNumber;
  493. // See what the user wants to do wrt starting frame number by looking at the config info
  494. if (configStatInfo->ulFrameOffset == 0) {
  495. // This means start ASAP
  496. ulFrameNumber = 0;
  497. }else {
  498. //Add the offset that the User wants to add to this frame number (it better be less than 1024!)
  499. ulFrameNumber += configStatInfo->ulFrameOffset;
  500. } //else
  501. //Save away the starting frame number so the app can peek at it
  502. configStatInfo->ulStartingFrameNumber = ulFrameNumber;
  503. // Set flag to indicate first Urb
  504. bFirstUrb = TRUE;
  505. // Get the pipe info for the first pipe
  506. pUsbdPipeInfo= &(pInterfaceInfo->Pipes[0]);
  507. // Build all the urbs for each pipe (note we send multiple Urbs down the stack)
  508. for (UrbNumber=0;UrbNumber<Max_Urbs_Per_Pipe;UrbNumber++) {
  509. //
  510. // Calculate the buffer size required and get a pointer to the buffer
  511. // Note: this buffer needs to be freed when the StopIsoInTest ioctl is
  512. // received. The completion routine will free the buffer when it
  513. // sees that it is time to stop the iso in test (the pointer is grabbed
  514. // from the irp).
  515. //
  516. pvBuff = ISOPERF_GetBuff (DeviceObject,
  517. 0, // pipe number
  518. 0, // interface number
  519. NumberOfFrames, // Nbr of mS worth of data to post
  520. &ulBufferSize);
  521. ISO_ASSERT (pvBuff!=NULL);
  522. //
  523. // Create the context for this transfer out of the nonpaged pool since it survives
  524. // this routine and is used in the completion routine
  525. //
  526. pIsoContext = ISOPERF_ExAllocatePool (NonPagedPool, sizeof (IsoTxferContext), &gulBytesAllocated);
  527. //build the urb
  528. urb = ISOPERF_BuildIsoRequest(DeviceObject,
  529. pUsbdPipeInfo, //Pipe info struct
  530. TRUE, //READ
  531. ulBufferSize, //Data buffer size
  532. bFirstUrb ? ulFrameNumber : 0, //Frame Nbr
  533. pvBuff, //Data buffer
  534. NULL //no MDL used
  535. );
  536. if (urb) {
  537. // Fill in the iso context
  538. pIsoContext->urb = urb;
  539. pIsoContext->DeviceObject = DeviceObject;
  540. pIsoContext->PipeInfo = pUsbdPipeInfo;
  541. pIsoContext->irp = pIrp;
  542. pIsoContext->pvBuffer = pvBuff;
  543. pIsoContext->ulBufferLen = ulBufferSize;
  544. pIsoContext->PipeNumber = UrbNumber;
  545. pIsoContext->NumPackets = urb->UrbIsochronousTransfer.NumberOfPackets;
  546. pIsoContext->bFirstUrb = bFirstUrb;
  547. ISOPERF_KdPrint_MAXDEBUG (("Urb %d pvBuff %x ulBuffSz %d NumPackts %d pIsoCont %x Urb: %x\n",
  548. UrbNumber,pvBuff,ulBufferSize,pIsoContext->NumPackets,pIsoContext,urb));
  549. // Time stamp the Urb before we send it down the stack
  550. ISOPERF_TimeStampUrb(urb, &Lower, &Upper);
  551. //Create our own Irp for the device and call the usb stack w/ our urb/irp
  552. ntStatus = ISOPERF_CallUSBDEx ( DeviceObject,
  553. urb,
  554. FALSE, //Don't block
  555. ISOPERF_IsoInCompletion, //Completion routine
  556. pIsoContext, //pvContext
  557. FALSE); //don't want timeout
  558. // Set the busy flag if the Urb/Irp succeed
  559. if (NT_SUCCESS(ntStatus)) {
  560. deviceExtension->DeviceIsBusy = TRUE;
  561. //Set to some huge value; ioctl to stop the test will set this to a smaller value
  562. deviceExtension->ulCountDownToStop = 0xFFFF;
  563. deviceExtension->bStopIsoTest = FALSE;
  564. deviceExtension->StopTransfers = FALSE;
  565. configStatInfo->erError = NoError;
  566. configStatInfo->bDeviceRunning = TRUE;
  567. } else {
  568. deviceExtension->DeviceIsBusy = FALSE;
  569. deviceExtension->bStopIsoTest = TRUE;
  570. deviceExtension->StopTransfers = TRUE;
  571. configStatInfo->erError = ErrorInPostingUrb;
  572. configStatInfo->UrbStatusCode = urb->UrbHeader.Status;
  573. if (bFirstUrb) {
  574. //since this is the first Urb, we know for sure the device isn't running
  575. configStatInfo->bDeviceRunning = FALSE;
  576. configStatInfo->bStopped = TRUE;
  577. }//if first Urb
  578. } //else FAILED calling USB stack
  579. }//if urb[UrbNumber] exists
  580. // Reset the flag that indicates it's the first Urb
  581. bFirstUrb = FALSE;
  582. }//for all the urbs per pipe (UrbNumber)
  583. ISOPERF_KdPrint (("Exit ISOPERF_StartIsoInTest (%x)\n",ntStatus));
  584. return ntStatus;
  585. }//StartIsoInTest
  586. NTSTATUS
  587. ISOPERF_ResetPipe(
  588. IN PDEVICE_OBJECT DeviceObject,
  589. IN USBD_PIPE_INFORMATION * pPipeInfo
  590. )
  591. /*++
  592. Routine Description:
  593. Resets the given Pipe by calling a USBD function
  594. Arguments:
  595. DeviceObject - pointer to dev obj for this instance of usb device
  596. pPipeInfo - pointer to usbd pipe info struct
  597. Return Value:
  598. --*/
  599. {
  600. NTSTATUS ntStatus;
  601. PURB urb;
  602. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  603. ISO_ASSERT (pPipeInfo!=NULL)
  604. urb = ISOPERF_ExAllocatePool(NonPagedPool,((sizeof(struct _URB_PIPE_REQUEST))+64), &gulBytesAllocated);
  605. if (urb) {
  606. urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
  607. urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
  608. urb->UrbPipeRequest.PipeHandle = pPipeInfo->PipeHandle;
  609. ntStatus = ISOPERF_CallUSBD ( DeviceObject,
  610. urb);
  611. } else {
  612. ntStatus = STATUS_NO_MEMORY;
  613. }
  614. ISOPERF_KdPrint (("Freeing urb in RESET_PIPE: %x\n",urb));
  615. // Free the urb we created since we blocked on this function
  616. if (urb) {
  617. ISOPERF_ExFreePool (urb, &gulBytesFreed);
  618. }//if urb
  619. return ntStatus;
  620. }
  621. ULONG
  622. ISOPERF_GetCurrentFrame(
  623. IN PDEVICE_OBJECT DeviceObject
  624. )
  625. /*++
  626. ISOPERF_GetCurrentFrame
  627. Arguments:
  628. DeviceExtension - pointer to the device extension for this instance
  629. Return Value:
  630. Current Frame Number
  631. --*/
  632. {
  633. NTSTATUS ntStatus;
  634. PURB urb;
  635. ULONG currentUSBFrame = 0;
  636. ISOPERF_KdPrint_MAXDEBUG (("In ISOPERF_GetCurrentFrame: (%x)\n",DeviceObject));
  637. urb = ISOPERF_ExAllocatePool(NonPagedPool,sizeof(struct _URB_GET_CURRENT_FRAME_NUMBER), &gulBytesAllocated);
  638. if (urb) {
  639. urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_GET_CURRENT_FRAME_NUMBER);
  640. urb->UrbHeader.Function = URB_FUNCTION_GET_CURRENT_FRAME_NUMBER;
  641. ntStatus = ISOPERF_CallUSBD ( DeviceObject,
  642. urb
  643. );
  644. if (NT_SUCCESS(ntStatus) && USBD_SUCCESS(URB_STATUS(urb))) {
  645. currentUSBFrame = urb->UrbGetCurrentFrameNumber.FrameNumber;
  646. // Since a ZERO for the USBFrameNumber indicates an error, and if it really is zero by chance, then just bump it by one
  647. if (currentUSBFrame==0) {
  648. currentUSBFrame++;
  649. }
  650. }
  651. ISOPERF_ExFreePool(urb, &gulBytesFreed);
  652. } else {
  653. ntStatus = STATUS_NO_MEMORY;
  654. }
  655. ISOPERF_KdPrint_MAXDEBUG (("Exit ISOPERF_GetCurrentFrame: (%x)\n",currentUSBFrame));
  656. return currentUSBFrame;
  657. }
  658. NTSTATUS
  659. ISOPERF_StopIsoInTest (
  660. IN PDEVICE_OBJECT DeviceObject,
  661. IN PIRP Irp
  662. )
  663. /*++
  664. Routine Description:
  665. Stops the Iso IN test by setting fields in the device extension so that the completion
  666. routine no longer does checks and resubmits Irps to keep the iso stream running.
  667. This call causes no USB stack calls nor USB bus traffic.
  668. Arguments:
  669. DeviceObject - pointer to the device extension for this instance of the device
  670. Irp - pointer to the Irp created in the Ioctl
  671. Return Value:
  672. Always returns NT status of STATUS_SUCCESS
  673. --*/
  674. {
  675. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  676. ULONG Upper, Lower;
  677. GET_PENTIUM_CLOCK_COUNT(Upper,Lower);
  678. ISOPERF_KdPrint (("Enter StopIsoInTest\n"));
  679. ISOPERF_KdPrint (("Upper:Lower -- %ld : %ld\n",Upper,Lower));
  680. ISO_ASSERT (deviceExtension != NULL);
  681. deviceExtension->bStopIsoTest = TRUE;
  682. deviceExtension->ulCountDownToStop = 100;
  683. ISOPERF_KdPrint (("Stopped: %d\n", deviceExtension->Stopped));
  684. ISOPERF_KdPrint (("StopTransfers: %d\n", deviceExtension->StopTransfers));
  685. ISOPERF_KdPrint (("DeviceIsBusy: %d\n", deviceExtension->DeviceIsBusy));
  686. ISOPERF_KdPrint (("NeedCleanup: %d\n", deviceExtension->NeedCleanup));
  687. ISOPERF_KdPrint (("bStopIsoTest: %d\n", deviceExtension->bStopIsoTest));
  688. ISOPERF_KdPrint (("ulNumberOfOutstandingIrps: %d\n", deviceExtension->ulNumberOfOutstandingIrps));
  689. ISOPERF_KdPrint (("ulCountDownToStop: %d\n", deviceExtension->ulCountDownToStop));
  690. ISOPERF_KdPrint (("Exit StopIsoInTest\n"));
  691. return (STATUS_SUCCESS);
  692. }//ISOPERF_StopIsoInTest
  693. BOOLEAN
  694. ISOPERF_IsDataGood(PIsoTxterContext pIsoContext
  695. )
  696. /*++
  697. Routine Description:
  698. Checks the data in the buffer for an incrementing pattern in every "maxpacketsize" granule
  699. of bytes.
  700. Arguments:
  701. pIsoContext - pointer to the Iso context that contains what this routine needs to process the buffer
  702. Return Value:
  703. TRUE - indicates buffer looks good
  704. FALSE - buffer has an error
  705. --*/
  706. {
  707. PUCHAR pchWork, pchEnd;
  708. UCHAR cCurrentValue, cNextValue;
  709. ULONG ulMaxPacketSize;
  710. pchWork = pIsoContext->pvBuffer;
  711. ulMaxPacketSize = pIsoContext->PipeInfo->MaximumPacketSize;
  712. if (pchWork==NULL) {
  713. ISOPERF_KdPrint (("Bad pchWork in IsDataGood (%x)\n",pchWork));
  714. return (FALSE);
  715. }
  716. if (ulMaxPacketSize >= 1024) {
  717. ISOPERF_KdPrint (("Bad MaxPacketSize in IsDataGood (%x)\n",ulMaxPacketSize));
  718. return (FALSE);
  719. }
  720. pchEnd = pchWork + ((pIsoContext->ulBufferLen) - ulMaxPacketSize);
  721. if (pchEnd > (pchWork + ((pIsoContext->NumPackets)*(ulMaxPacketSize)))) {
  722. ISOPERF_KdPrint (("Buffer Problem in IsDataGood: Base: %x | End: %x | NumPackts: %d | MaxPacktSz: %d\n",
  723. pchWork, pchEnd, pIsoContext->NumPackets, ulMaxPacketSize));
  724. }
  725. ASSERT (pchEnd <= (pchWork + ((pIsoContext->NumPackets)*ulMaxPacketSize)));
  726. cCurrentValue = *pchWork;
  727. while (pchWork < pchEnd) {
  728. // Get the next frame's byte value
  729. cNextValue = *(pchWork + ulMaxPacketSize);
  730. if (cNextValue == (cCurrentValue + 1)) {
  731. //Success, go on to next packet
  732. pchWork+=ulMaxPacketSize;
  733. cCurrentValue = *pchWork;
  734. }else{
  735. // Maybe this is the rollover case, so check for it and don't fail it if it is
  736. if (cNextValue==0) {
  737. if (cCurrentValue==0xFF) {
  738. //Success, go on to next packet
  739. pchWork+=ulMaxPacketSize;
  740. cCurrentValue = *pchWork;
  741. continue;
  742. }
  743. }
  744. ISOPERF_KdPrint (("Fail data compare: pchWork: %x | cNextValue: %x | *pchWork: %x | Base: %x\n",
  745. pchWork, cNextValue, *pchWork, pIsoContext->pvBuffer));
  746. FIRE_OFF_CATC;
  747. RESTART_CATC;
  748. return (FALSE);
  749. }
  750. } //while
  751. return (TRUE);
  752. }//ISOPERF_IsDataGood
  753. NTSTATUS
  754. ISOPERF_GetStats (
  755. IN PDEVICE_OBJECT DeviceObject,
  756. IN PIRP Irp,
  757. IN OUT pConfig_Stat_Info pStatInfoOut,
  758. IN ULONG ulBufferLen
  759. )
  760. /*++
  761. Routine Description:
  762. Copies the existing Iso traffic counter values into buffer supplied by caller. The
  763. values of the counter variables are defined in IOCTL.H in the pIsoStats structure.
  764. Arguments:
  765. DeviceObject - pointer to the device extension for this instance of the device
  766. Irp - pointer to the Irp created in the Ioctl
  767. pIsoStats - pointer to buffer where stats will go
  768. ulBufferLen - len of above output buffer
  769. Return Value:
  770. NT status of STATUS_SUCCESS means copy was successful
  771. NT status of STATUS_INVALID_PARAMETER means a param (usually a pointer) was bad
  772. --*/
  773. {
  774. ULONG Upper, Lower;
  775. pConfig_Stat_Info pStatInfo = NULL;
  776. NTSTATUS ntStatus = STATUS_SUCCESS;
  777. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  778. ISOPERF_KdPrint_MAXDEBUG (("In GetStats (%x) (%x) (%x) (%d)\n",
  779. DeviceObject,Irp,pStatInfoOut,ulBufferLen));
  780. ASSERT (deviceExtension != NULL);
  781. if (deviceExtension) {
  782. pStatInfo = deviceExtension->pConfig_Stat_Information;
  783. }
  784. ASSERT (pStatInfo!= NULL);
  785. GET_PENTIUM_CLOCK_COUNT(Upper,Lower);
  786. if ( (pStatInfoOut) && (ulBufferLen >= sizeof(Config_Stat_Info)) ) {
  787. // Only copy the stat info from the dev ext area if it exists
  788. if (pStatInfo) {
  789. memcpy (pStatInfoOut, pStatInfo, sizeof (Config_Stat_Info));
  790. }/* if dev ext's stat/config info exists */
  791. // Get the global mem alloc/free info
  792. pStatInfoOut->ulBytesAllocated = gulBytesAllocated;
  793. pStatInfoOut->ulBytesFreed = gulBytesFreed;
  794. // Get the current countdown value
  795. pStatInfoOut->ulCountDownToStop= deviceExtension->ulCountDownToStop;
  796. // Get the Pentium counter values
  797. pStatInfoOut->ulUpperClockCount=Upper;
  798. pStatInfoOut->ulLowerClockCount=Lower;
  799. // Get the device type
  800. pStatInfoOut->DeviceType = deviceExtension->dtTestDeviceType;
  801. Irp->IoStatus.Information = sizeof (Config_Stat_Info);
  802. } else {
  803. ntStatus = STATUS_INVALID_PARAMETER;
  804. Irp->IoStatus.Information = 0;
  805. }/* else */
  806. return (ntStatus);
  807. }//ISOPERF_GetStats
  808. NTSTATUS
  809. ISOPERF_SetDriverConfig (
  810. IN PDEVICE_OBJECT DeviceObject,
  811. IN PIRP Irp,
  812. IN OUT pConfig_Stat_Info pConfInfoIn,
  813. IN ULONG ulBufferLen
  814. )
  815. /*++
  816. Routine Description:
  817. Sets the driver's test parameters. These are only checked by this driver when the
  818. Iso tests are started. So, if a user mode app tries to set these after a test has started
  819. they will take effect on the next "start" of the test.
  820. Arguments:
  821. DeviceObject - pointer to the device extension for this instance of the device
  822. Irp - pointer to the Irp created in the Ioctl
  823. pIsoStats - pointer to buffer where config info is located
  824. ulBufferLen - len of above input buffer
  825. Return Value:
  826. NT status of STATUS_SUCCESS means setting of params was successful
  827. NT status of STATUS_INVALID_PARAMETER means a param (usually a pointer) was bad
  828. --*/
  829. {
  830. pConfig_Stat_Info pDriverConfigInfo = NULL;
  831. NTSTATUS ntStatus = STATUS_SUCCESS;
  832. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  833. ASSERT (deviceExtension != NULL);
  834. if (deviceExtension) {
  835. pDriverConfigInfo = deviceExtension->pConfig_Stat_Information;
  836. }else{
  837. ntStatus = STATUS_INVALID_PARAMETER;
  838. }//else bad dev ext
  839. ASSERT (pDriverConfigInfo!= NULL);
  840. if ( (pConfInfoIn) && (ulBufferLen >= sizeof(Config_Stat_Info)) ) {
  841. // Only copy the stat info from the dev ext area if it exists
  842. if (pDriverConfigInfo) {
  843. //Set the config info in the driver's config/stat area
  844. pDriverConfigInfo->ulNumberOfFrames = pConfInfoIn->ulNumberOfFrames;
  845. pDriverConfigInfo->ulMax_Urbs_Per_Pipe = pConfInfoIn->ulMax_Urbs_Per_Pipe;
  846. pDriverConfigInfo->ulDoInOutTest = pConfInfoIn->ulDoInOutTest;
  847. pDriverConfigInfo->ulFrameOffset = pConfInfoIn->ulFrameOffset;
  848. pDriverConfigInfo->ulFrameOffsetMate = pConfInfoIn->ulFrameOffsetMate;
  849. ISOPERF_KdPrint (("Setting Driver Config-Number of Frames: %d | MaxUrbsPerPipe: %d | DoInOut: %d | FrameOffset %d | MateOffset %d\n",
  850. pDriverConfigInfo->ulNumberOfFrames,
  851. pDriverConfigInfo->ulMax_Urbs_Per_Pipe,
  852. pDriverConfigInfo->ulDoInOutTest,
  853. pDriverConfigInfo->ulFrameOffset,
  854. pDriverConfigInfo->ulFrameOffsetMate));
  855. }/* if dev ext's stat/config info exists */
  856. else {
  857. ntStatus = STATUS_INVALID_PARAMETER;
  858. }//else bad dev extension
  859. Irp->IoStatus.Information = 0;
  860. } else {
  861. ntStatus = STATUS_INVALID_PARAMETER;
  862. Irp->IoStatus.Information = 0;
  863. }/* else bad buffer passed in (pointer was bad, or length was not correct) */
  864. return (ntStatus);
  865. }//ISOPERF_SetDriverConfig
  866. NTSTATUS
  867. ISOPERF_FindMateDevice (
  868. PDEVICE_OBJECT DeviceObject
  869. )
  870. /*++
  871. Searches the linked list of device objects looking for the long lost mate device for the
  872. given device object. By practicing safe device mating rituals (ie., checking that the device
  873. object is a known type, etc.) it then puts the mate's device object pointer into the device extension
  874. of the given device object.
  875. If no mate is found, sadly, then this routine puts a NULL in the mate deviceobject field in the dev extension,
  876. and returns a STATUS_NOT_FOUND result code
  877. ++*/
  878. {
  879. NTSTATUS ntStatus = STATUS_SUCCESS;
  880. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  881. PDRIVER_OBJECT driverObject = DeviceObject->DriverObject;
  882. PDEVICE_OBJECT NextDeviceObject = DeviceObject->NextDevice;
  883. PDEVICE_EXTENSION NextDeviceExtension = NULL;
  884. dtDeviceType dtMateTestDeviceTypeA = Unknown_Device_Type;
  885. dtDeviceType dtMateTestDeviceTypeB = Unknown_Device_Type;
  886. ASSERT (DeviceObject != NULL);
  887. ASSERT (deviceExtension!=NULL);
  888. if (NextDeviceObject == NULL) {
  889. ISOPERF_KdPrint(("FindMateDevice: No Next Device\n"));
  890. // NOTE: (old code)
  891. // WDM appears to be loading an entirely separate driver image for the same venid/prodid.
  892. // This makes the approach where we look at the device chain to find the next device in the
  893. // chain not feasible, so as a shortterm fix we'll put the Device Object for a Output Iso device
  894. // in a global variable (which does seem to persist across dd loads) and we'll see if that is a
  895. // mate. kjaff 12/24/96
  896. if (gMyOutputDevice!=NULL) {
  897. ISOPERF_KdPrint(("There is a global device us to check...(%x)\n",gMyOutputDevice));
  898. NextDeviceObject = gMyOutputDevice;
  899. NextDeviceExtension = NextDeviceObject->DeviceExtension;
  900. } else {
  901. ISOPERF_KdPrint (("No global device found either...exiting...\n"));
  902. return STATUS_NOT_FOUND;
  903. }//else no global either
  904. }else{
  905. NextDeviceExtension = NextDeviceObject->DeviceExtension;
  906. ISOPERF_KdPrint(("Found a NextDevice: %x\n",NextDeviceObject));
  907. }//else there is a next device
  908. // The Mate for the device is dependent on the device type
  909. switch (deviceExtension->dtTestDeviceType) {
  910. case Iso_In_With_Pattern:
  911. //This dev can have 2 mate types
  912. ISOPERF_KdPrint (("Looking for a mate for Iso_In_With_Pattern %d\n",deviceExtension->dtTestDeviceType));
  913. dtMateTestDeviceTypeA = Iso_Out_With_Interrupt_Feedback;
  914. dtMateTestDeviceTypeB = Iso_Out_Without_Feedback;
  915. break;
  916. case Iso_Out_With_Interrupt_Feedback:
  917. break;
  918. case Iso_Out_Without_Feedback:
  919. break;
  920. case Unknown_Device_Type:
  921. break;
  922. default:
  923. break;
  924. }//switch on device type
  925. ntStatus = STATUS_NOT_FOUND; //assume we haven't found the mate
  926. while (NextDeviceObject != NULL) {
  927. NextDeviceExtension = NextDeviceObject->DeviceExtension;
  928. // Is this the mate?
  929. if ( (NextDeviceExtension->dtTestDeviceType == dtMateTestDeviceTypeA) ||
  930. (NextDeviceExtension->dtTestDeviceType == dtMateTestDeviceTypeB) ) {
  931. ISOPERF_KdPrint (("Found a mate for Dev %X : %X\n",DeviceObject, NextDeviceObject));
  932. //Found a mate, so fill in this dev object into the given dev obj's ext
  933. deviceExtension->MateDeviceObject = NextDeviceObject;
  934. ntStatus = STATUS_SUCCESS;
  935. break; //drop out of the while
  936. } else {
  937. ISOPERF_KdPrint (("%x is not a mate for Dev %X (type:%d\n",
  938. NextDeviceObject,
  939. DeviceObject,
  940. NextDeviceExtension->dtTestDeviceType));
  941. // Get the next device object
  942. NextDeviceObject = NextDeviceObject->NextDevice;
  943. }//else go on to next device object
  944. }//while next dev obj
  945. ISOPERF_KdPrint (("FindMateDevice exiting...\n"));
  946. return ntStatus;
  947. }//ISOPERF_FindMateDevice
  948. VOID
  949. ISOPERF_StartIsoOutTest (
  950. IN PISOPERF_WORKITEM IsoperfWorkItem
  951. )
  952. /*++
  953. Queues an Irp to the USB stack on the given device object.
  954. Inputs:
  955. IsoperfWorkItem - This routine is designed to be fired offf either directly or via a Work Item. The
  956. work item structure only allows for one parameter to be passed to the work item
  957. routine, hence this single workitem parameter.
  958. Return Value:
  959. None
  960. ++*/
  961. {
  962. PDEVICE_OBJECT deviceObject = NULL;
  963. PDEVICE_EXTENSION deviceExtension = NULL;
  964. PUSBD_INTERFACE_INFORMATION pInterfaceInfo = NULL;
  965. PUSBD_PIPE_INFORMATION pUsbdPipeInfo = NULL;
  966. pConfig_Stat_Info configStatInfo = NULL;
  967. PVOID pvBuff = NULL;
  968. PURB urb = NULL;
  969. ULONG ulBufferSize = 0;
  970. NTSTATUS ntStatus = STATUS_SUCCESS;
  971. IsoTxferContext * pIsoContext = NULL;
  972. ULONG ulFrameNumber = 0;
  973. ULONG NumberOfFrames = 0;
  974. ULONG i = 0;
  975. deviceObject = IsoperfWorkItem->DeviceObject;
  976. pvBuff = IsoperfWorkItem->pvBuffer;
  977. ulBufferSize = IsoperfWorkItem->ulBufferLen;
  978. deviceExtension = deviceObject->DeviceExtension;
  979. pInterfaceInfo = deviceExtension->Interface[ucIsoInterface];
  980. configStatInfo = deviceExtension->pConfig_Stat_Information;
  981. ASSERT (pInterfaceInfo!=NULL);
  982. ASSERT (configStatInfo != NULL);
  983. ASSERT (deviceObject != NULL);
  984. if ( (configStatInfo==NULL) || (pInterfaceInfo==NULL) || (deviceObject==NULL) ) {
  985. ISOPERF_KdPrint (("Bad Parameter Received: configInf: %x | InterfInfo: %x | DevObj: %x\n",
  986. configStatInfo, pInterfaceInfo, deviceObject));
  987. TRAP();
  988. return;
  989. }//if any params are bad
  990. // Check out the offset provided to make sure it's not too big
  991. if (configStatInfo->ulFrameOffset >= USBD_ISO_START_FRAME_RANGE) {
  992. ISOPERF_KdPrint (("ISOOUT: Error-Detected a FrameOffset Larger than allowed! (%d)\n",configStatInfo->ulFrameOffset));
  993. TRAP();
  994. return;
  995. }//if bad frame offset
  996. if (IsoperfWorkItem->bFirstUrb) {
  997. // We have to match the endpoint maxpacket sizes for this to work (we can't assume that this is the
  998. // case since the Out device sometimes seems to have a larger maxpacket than the In device
  999. // DESIGNDESIGN This may be OK if we later on want to do some rate-matching emulation here.
  1000. if ( (deviceExtension->Interface[0]->Pipes[0].MaximumPacketSize) >= IsoperfWorkItem->InMaxPacket ) {
  1001. deviceExtension->Interface[0]->Pipes[0].MaximumPacketSize = IsoperfWorkItem->InMaxPacket;
  1002. } else {
  1003. //if the OUT device's maxpacket is smaller than the IN device's this seems incorrect so do nothing
  1004. return;
  1005. }//else the endpoint sizes seem out of whack
  1006. //#if 0
  1007. // Since this is the first Urb, we need the frame number, so get it
  1008. ulFrameNumber = ISOPERF_GetCurrentFrame(deviceObject);
  1009. ISOPERF_KdPrint (("StartISOOut got Frame Number: %x | Offset: %d\n",ulFrameNumber,configStatInfo->ulFrameOffset));
  1010. if (ulFrameNumber==0) {
  1011. ISOPERF_KdPrint (("Got Bad Frame Number (%x) ...exiting...\n",ulFrameNumber));
  1012. deviceExtension->StopTransfers = TRUE; //set flag so further transfers stop
  1013. return;
  1014. }//if bad frame #
  1015. //Save away the current frame number so the app can peek at it
  1016. configStatInfo->ulFrameNumberAtStart = ulFrameNumber;
  1017. // See what the user wants to do wrt starting frame number by looking at the config info
  1018. if (configStatInfo->ulFrameOffset == 0) {
  1019. // This means start ASAP
  1020. ulFrameNumber = 0;
  1021. }else {
  1022. //Add the offset that the User wants to add to this frame number (it better be less than 1024!)
  1023. ulFrameNumber += configStatInfo->ulFrameOffset;
  1024. } //else
  1025. //Save away the starting frame number so the app can peek at it
  1026. configStatInfo->ulStartingFrameNumber = ulFrameNumber;
  1027. ISOPERF_KdPrint (("StartISOOut using Frame Number: %x\n",ulFrameNumber));
  1028. //#endif
  1029. }//if this is the first Urb
  1030. else
  1031. {
  1032. ISOPERF_KdPrint (("StartISOOut _NOT_ the First URB!\n"));
  1033. }//else not first Urb
  1034. // Get the pipe info for the first pipe
  1035. pUsbdPipeInfo= &(pInterfaceInfo->Pipes[0]);
  1036. ASSERT(pUsbdPipeInfo != NULL);
  1037. if (deviceExtension->StopTransfers != TRUE) {
  1038. //We get the Urbs to submit and the Nbr of frames from the workitem because we want to
  1039. //make sure this is the same as the setting for the In device (this is filled in by InComplRoutine)
  1040. NumberOfFrames = IsoperfWorkItem->ulNumberOfFrames;
  1041. ASSERT (NumberOfFrames > 0);
  1042. //We get our own buffer for now...in the future this will be passed in if we decide to reuse the
  1043. //input device's buffer
  1044. pvBuff = ISOPERF_GetBuff (deviceObject,
  1045. 0,//pipe number
  1046. 0,//interfacenumber
  1047. NumberOfFrames,
  1048. &ulBufferSize
  1049. );
  1050. if (pvBuff==NULL){
  1051. return;
  1052. }else{
  1053. //Copy the input buffer into our output buffer (they should be the same size)
  1054. ASSERT (IsoperfWorkItem->ulBufferLen == ulBufferSize);
  1055. RtlCopyMemory (pvBuff, IsoperfWorkItem->pvBuffer, ulBufferSize);
  1056. }//if pvbuff
  1057. //...to here
  1058. //build the urb
  1059. urb = ISOPERF_BuildIsoRequest(deviceObject,
  1060. pUsbdPipeInfo, //Pipe info struct
  1061. FALSE, //WRITE
  1062. ulBufferSize, //Data buffer size
  1063. IsoperfWorkItem->bFirstUrb ? ulFrameNumber : 0,
  1064. pvBuff, //Data buffer
  1065. NULL //no MDL used
  1066. );
  1067. ISOPERF_KdPrint_MAXDEBUG (("OUT Urb: %x\n",urb));
  1068. pIsoContext = ISOPERF_ExAllocatePool (NonPagedPool, sizeof (IsoTxferContext), &gulBytesAllocated);
  1069. // Fill in the iso context
  1070. pIsoContext->urb = urb;
  1071. pIsoContext->DeviceObject = deviceObject;
  1072. pIsoContext->PipeInfo = pUsbdPipeInfo;
  1073. pIsoContext->pvBuffer = pvBuff; //NOTE: set this to NULL if you're using the IN device's buffer
  1074. pIsoContext->ulBufferLen = ulBufferSize;
  1075. pIsoContext->PipeNumber = 0;
  1076. pIsoContext->NumPackets = urb->UrbIsochronousTransfer.NumberOfPackets;
  1077. pIsoContext->bFirstUrb = IsoperfWorkItem->bFirstUrb;
  1078. //Create our own Irp for the device and call the usb stack w/ our urb/irp
  1079. ntStatus = ISOPERF_CallUSBDEx ( deviceObject,
  1080. urb,
  1081. FALSE, //Don't block
  1082. ISOPERF_IsoOutCompletion,//Completion routine
  1083. pIsoContext, //pvContext
  1084. FALSE); //don't want timeout
  1085. if (NT_SUCCESS(ntStatus)) {
  1086. deviceExtension->DeviceIsBusy = TRUE;
  1087. deviceExtension->bStopIsoTest = FALSE;
  1088. deviceExtension->StopTransfers = FALSE;
  1089. configStatInfo->erError = NoError;
  1090. configStatInfo->bDeviceRunning = 1;
  1091. } else {
  1092. // An error occurred, so stop things and report it thru config/stat info
  1093. deviceExtension->DeviceIsBusy = FALSE;
  1094. deviceExtension->bStopIsoTest = TRUE;
  1095. deviceExtension->StopTransfers = TRUE;
  1096. configStatInfo->erError = ErrorInPostingUrb;
  1097. configStatInfo->bDeviceRunning = 0;
  1098. // If the URB status code got filled in then extract the info returned
  1099. if (!(USBD_SUCCESS(urb->UrbHeader.Status))) {
  1100. ISOPERF_KdPrint (("StartIsoOut -- Urb unsuccessful (status: %#x)\n",urb->UrbHeader.Status));
  1101. configStatInfo->UrbStatusCode = urb->UrbHeader.Status;
  1102. // Dump out the status for the packets
  1103. for (i=0; i< urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
  1104. ISOPERF_KdPrint (("Packet %d: Status: [%#X]\n",
  1105. i,
  1106. urb->UrbIsochronousTransfer.IsoPacket[i].Status));
  1107. // Put the last known bad packet status code into this space in the stat area
  1108. if (!USBD_SUCCESS(urb->UrbIsochronousTransfer.IsoPacket[i].Status)) {
  1109. configStatInfo->UsbdPacketStatCode = urb->UrbIsochronousTransfer.IsoPacket[i].Status;
  1110. }//if hit a fail code
  1111. }//for all the packets
  1112. }// if bad Urb status code
  1113. }//else there was an error
  1114. }else{
  1115. ISOPERF_KdPrint_MAXDEBUG (("IsoOut not submitting Urbs because StopTransfers is asserted!\n"));
  1116. }//else we are being asked to stoptransfers
  1117. //Free the work item junk
  1118. ISOPERF_ExFreePool (IsoperfWorkItem, &gulBytesFreed);
  1119. ISOPERF_KdPrint_MAXDEBUG (("Exit StartIsoOut\n"));
  1120. return;
  1121. }//ISOPERF_StartIsoOutTest
  1122. NTSTATUS
  1123. ISOPERF_IsoOutCompletion(
  1124. IN PDEVICE_OBJECT DeviceObject,
  1125. IN PIRP Irp,
  1126. IN PVOID Context
  1127. )
  1128. /*++
  1129. This is the completion routine for the Iso OUT transfer
  1130. Inputs:
  1131. Device Object - the device object
  1132. Irp - The Irp we posted that is being completed
  1133. Context - pointer to our defined context which has our DeviceObject since it comes back as NULL here
  1134. DeviceObject is obtained from context due to old, old bug
  1135. in initial WDM implemenations
  1136. Return Value:
  1137. ntStatus
  1138. ++*/
  1139. {
  1140. PIsoTxterContext pIsoContext;
  1141. PDEVICE_OBJECT myDeviceObject;
  1142. PDEVICE_EXTENSION deviceExtension;
  1143. PURB urb;
  1144. pConfig_Stat_Info pStatInfo;
  1145. char * pcWork = NULL; //a worker pointer
  1146. ULONG i = 0;
  1147. ISOPERF_KdPrint_MAXDEBUG (("In IsoOUTCompletion\n"));
  1148. TRAP();
  1149. pIsoContext = Context;
  1150. myDeviceObject = pIsoContext->DeviceObject;
  1151. deviceExtension = myDeviceObject->DeviceExtension;
  1152. urb = pIsoContext->urb;
  1153. pStatInfo = deviceExtension->pConfig_Stat_Information;
  1154. // Check the USBD status code and only proceed in resubmission if the Urb was successful
  1155. // or if the device extension flag that indicates the device is gone is FALSE
  1156. if (!(USBD_SUCCESS(urb->UrbHeader.Status))) {
  1157. ISOPERF_KdPrint (("IsoOUT Urb %x unsuccessful (status: %x)\n",urb,(urb->UrbHeader.Status)));
  1158. // Don't let it go on w/ the tests
  1159. deviceExtension->StopTransfers = TRUE;
  1160. // Fill in stat info
  1161. if (pStatInfo) {
  1162. pStatInfo->erError = UsbdErrorInCompletion;
  1163. pStatInfo->bStopped = 1;
  1164. pStatInfo->UrbStatusCode = urb->UrbHeader.Status;
  1165. }//if pStatInfo
  1166. // Dump out the status for the packets
  1167. for (i=0; i< urb->UrbIsochronousTransfer.NumberOfPackets; i++) {
  1168. ISOPERF_KdPrint (("Packet %d: Status: [%#X]\n",
  1169. i,
  1170. urb->UrbIsochronousTransfer.IsoPacket[i].Status));
  1171. // Put the last known bad packet status code into this space in the stat area
  1172. if (!USBD_SUCCESS(urb->UrbIsochronousTransfer.IsoPacket[i].Status)) {
  1173. pStatInfo->UsbdPacketStatCode = urb->UrbIsochronousTransfer.IsoPacket[i].Status;
  1174. }//if hit a fail code
  1175. }//for all the packets
  1176. }//if failure detected
  1177. // Free up the URB memory created for this transfer that we are retiring
  1178. if (urb) {
  1179. // We can't free the Urb itself, since it has some junk before it, so we have to roll back the
  1180. // pointer to get to the beginning of the block that we originally allocated, and then try to free it.
  1181. pcWork = (char*)urb; //get the urb
  1182. urb = (PURB) (pcWork - (2*sizeof(ULONG))); //the original pointer is 2 DWORDs behind the Urb
  1183. ISOPERF_KdPrint_MAXDEBUG (("Freeing Urb: %x\n",urb));
  1184. ISOPERF_ExFreePool (urb, &gulBytesFreed);
  1185. }//if
  1186. if (pIsoContext) {
  1187. // Free the data buffer
  1188. // NOTE: This only can be done if we own this data buffer. If the same data buffer that
  1189. // the IN device is using is being used here, then we don't want to free this buffer.
  1190. // The presence of a pointer to the data buffer will tell us that
  1191. if (pIsoContext->pvBuffer) {
  1192. ISOPERF_KdPrint_MAXDEBUG (("Freeing pvBuffer: %x\n",pIsoContext->pvBuffer));
  1193. ISOPERF_ExFreePool(pIsoContext->pvBuffer, &gulBytesFreed);
  1194. }//if pvbuffer
  1195. // Free the Iso Context
  1196. ISOPERF_KdPrint_MAXDEBUG (("Freeing pIsoContext: %x\n",pIsoContext));
  1197. ISOPERF_ExFreePool (pIsoContext, &gulBytesFreed);
  1198. }//if valid Iso Context
  1199. //Free the IoStatus block
  1200. if (Irp->UserIosb) {
  1201. ISOPERF_KdPrint_MAXDEBUG (("Freeing My IoStatus Block: %x\n",Irp->UserIosb));
  1202. ISOPERF_ExFreePool(Irp->UserIosb, &gulBytesFreed);
  1203. } else {
  1204. //Bad thing...no IoStatus block pointer??
  1205. ISOPERF_KdPrint (("ERROR: Irp's IoStatus block is apparently NULL!\n"));
  1206. TRAP();
  1207. }//else bad iostatus pointer
  1208. // Free the Irp we created
  1209. ISOPERF_KdPrint (("Freeing Irp %x\n",Irp));
  1210. IoFreeIrp(Irp);
  1211. ISOPERF_KdPrint_MAXDEBUG (("Exit IsoOUTCompletion\n"));
  1212. return (STATUS_MORE_PROCESSING_REQUIRED); //Leave the Irp alone, IOS, since we're the top level driver
  1213. }//ISOPERF_IsoOutCompletion
  1214. NTSTATUS
  1215. ISOPERF_TimeStampUrb ( PVOID urb,
  1216. PULONG pulLower,
  1217. PULONG pulUpper
  1218. )
  1219. /*++
  1220. Routine Description:
  1221. Puts a Pentium Clock count time stamp 2 DWORDS before the given pointer (usually a urb,
  1222. hence the name of the function).
  1223. This function can also be used to simply get the Pentium clock count, although there
  1224. is already a Macro to do that.
  1225. Inputs:
  1226. PVOID urb - pointer to a chunk of memory that ususally contains a Urb
  1227. PULONG puLower - pointer to a ULONG that gets the current upper CPU clock count (eax)
  1228. PULONG puUpper - same as lower, but the upper ULONG value (edx)
  1229. Return Value:
  1230. ntStatus indiciating success/fail
  1231. --*/
  1232. {
  1233. char * pcWork;
  1234. ULONG u,l;
  1235. GET_PENTIUM_CLOCK_COUNT (u,l);
  1236. // Time stamp the Urb before we send it down the stack
  1237. pcWork = (char*) (urb);
  1238. //Backup 2 DWORDS
  1239. pcWork -= (2*sizeof(ULONG));
  1240. //First DWORD is the Upper value (edx)
  1241. *((PULONG)pcWork) = u;
  1242. //Goto next DWORD
  1243. pcWork += sizeof(ULONG);
  1244. //Second DWORD is the Lower value (eax)
  1245. *((PULONG)pcWork) = l;
  1246. // Copy the values to the caller's supplied area
  1247. *pulUpper = u;
  1248. *pulLower = l;
  1249. return STATUS_SUCCESS;
  1250. }
  1251. NTSTATUS
  1252. ISOPERF_GetUrbTimeStamp ( PVOID urb,
  1253. PULONG pulLower,
  1254. PULONG pulUpper
  1255. )
  1256. /* ++
  1257. Routine Description:
  1258. Gets the Pentium Clock count time stamp 2 DWORDS before the given pointer (usually a urb,
  1259. hence the name of the function).
  1260. Inputs:
  1261. PVOID urb - pointer to a chunk of memory that ususally contains a Urb
  1262. PULONG puLower - pointer to a ULONG that gets the upper CPU clock count from the timestamp area(eax)
  1263. PULONG puUpper - same as lower, but the upper ULONG value (edx)
  1264. Return Value:
  1265. ntStatus indiciating success/fail
  1266. --*/
  1267. {
  1268. char * pcWork;
  1269. //Get the Urb's pointer
  1270. pcWork = (char *) urb;
  1271. //The first DW before the Urb is the lower DW of the clk cnt...
  1272. pcWork -= (sizeof(ULONG));
  1273. //...when the Urb was posted to the Usb stack
  1274. *pulLower = *((ULONG*)pcWork);
  1275. //NOTE: we don't care about the upper value right now...
  1276. *pulUpper = 0;
  1277. return STATUS_SUCCESS;
  1278. }//ISOPERF_GetUrbTimeStamp