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.

843 lines
24 KiB

  1. /**************************************************************************************************************************
  2. * SEND.C SigmaTel STIR4200 packet send module
  3. **************************************************************************************************************************
  4. * (C) Unpublished Copyright of Sigmatel, Inc. All Rights Reserved.
  5. *
  6. *
  7. * Created: 04/06/2000
  8. * Version 0.9
  9. * Edited: 04/27/2000
  10. * Version 0.92
  11. * Edited: 05/03/2000
  12. * Version 0.93
  13. * Edited: 05/12/2000
  14. * Version 0.94
  15. * Edited: 08/22/2000
  16. * Version 1.02
  17. * Edited: 09/25/2000
  18. * Version 1.10
  19. * Edited: 10/13/2000
  20. * Version 1.11
  21. * Edited: 11/09/2000
  22. * Version 1.12
  23. * Edited: 12/29/2000
  24. * Version 1.13
  25. * Edited: 01/16/2001
  26. * Version 1.14
  27. *
  28. *
  29. **************************************************************************************************************************/
  30. #include <ndis.h>
  31. #include <ntdef.h>
  32. #include <windef.h>
  33. #include "stdarg.h"
  34. #include "stdio.h"
  35. #include "debug.h"
  36. #include "usbdi.h"
  37. #include "usbdlib.h"
  38. #include "ircommon.h"
  39. #include "irusb.h"
  40. #include "irndis.h"
  41. #include "stir4200.h"
  42. /*****************************************************************************
  43. *
  44. * Function: SendPacketPreprocess
  45. *
  46. * Synopsis: Prepares a packet in such a way that the polling thread can later send it
  47. * The only operations are initializing and queuing the context
  48. *
  49. *
  50. * Arguments: pThisDev - pointer to current ir device object
  51. * pPacketToSend - pointer to packet to send
  52. *
  53. * Returns: NDIS_STATUS_PENDING - This is generally what we should
  54. * return. We will call NdisMSendComplete
  55. * when the USB driver completes the
  56. * send.
  57. * NDIS_STATUS_RESOURCES - No descriptor was available.
  58. *
  59. * Unsupported returns:
  60. * NDIS_STATUS_SUCCESS - We should never return this since
  61. * packet has to be sent from the polling thread
  62. *
  63. *
  64. *
  65. *****************************************************************************/
  66. NDIS_STATUS
  67. SendPacketPreprocess(
  68. IN OUT PIR_DEVICE pThisDev,
  69. IN PVOID pPacketToSend
  70. )
  71. {
  72. NDIS_STATUS status = NDIS_STATUS_PENDING ;
  73. PIRUSB_CONTEXT pThisContext;
  74. PLIST_ENTRY pListEntry;
  75. DEBUGMSG(DBG_FUNC, ("+SendPacketPreprocess\n"));
  76. //
  77. // See if there are available send contexts
  78. //
  79. if( pThisDev->SendAvailableCount<=2 )
  80. {
  81. DEBUGMSG(DBG_ERR, (" SendPacketPreprocess not enough contexts\n"));
  82. InterlockedIncrement( &pThisDev->packetsSentRejected );
  83. status = NDIS_STATUS_RESOURCES;
  84. goto done;
  85. }
  86. //
  87. // Dequeue a context
  88. //
  89. pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
  90. if( NULL == pListEntry )
  91. {
  92. //
  93. // This cannot happen
  94. //
  95. IRUSB_ASSERT( 0 );
  96. DEBUGMSG(DBG_ERR, (" SendPacketPreprocess failed to find a free context struct\n"));
  97. InterlockedIncrement( &pThisDev->packetsSentRejected );
  98. status = NDIS_STATUS_RESOURCES;
  99. goto done;
  100. }
  101. InterlockedDecrement( &pThisDev->SendAvailableCount );
  102. pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
  103. pThisContext->pPacket = pPacketToSend;
  104. pThisContext->ContextType = CONTEXT_NDIS_PACKET;
  105. //
  106. // Store the time the packet was handed by the protocol
  107. //
  108. KeQuerySystemTime( &pThisContext->TimeReceived );
  109. //
  110. // Queue so that the polling thread can later handle it
  111. //
  112. ExInterlockedInsertTailList(
  113. &pThisDev->SendBuiltQueue,
  114. &pThisContext->ListEntry,
  115. &pThisDev->SendLock
  116. );
  117. InterlockedIncrement( &pThisDev->SendBuiltCount );
  118. done:
  119. DEBUGMSG(DBG_FUNC, ("-SendPacketPreprocess\n"));
  120. return status;
  121. }
  122. /*****************************************************************************
  123. *
  124. * Function: SendPreprocessedPacketSend
  125. *
  126. * Synopsis: Send a packet to the USB driver and add the sent irp and io context to
  127. * To the pending send queue; this queue is really just needed for possible later error cancellation
  128. *
  129. *
  130. * Arguments: pThisDev - pointer to current ir device object
  131. * pContext - pointer to the context with the packet to send
  132. *
  133. * Returns: NDIS_STATUS_PENDING - This is generally what we should
  134. * return. We will call NdisMSendComplete
  135. * when the USB driver completes the
  136. * send.
  137. * STATUS_UNSUCCESSFUL - The packet was invalid.
  138. *
  139. * NDIS_STATUS_SUCCESS - When blocking send are employed
  140. *
  141. *
  142. *****************************************************************************/
  143. NDIS_STATUS
  144. SendPreprocessedPacketSend(
  145. IN OUT PIR_DEVICE pThisDev,
  146. IN PVOID pContext
  147. )
  148. {
  149. PIRP pIrp;
  150. UINT BytesToWrite;
  151. NDIS_STATUS status;
  152. BOOLEAN fConvertedPacket;
  153. ULONG Counter;
  154. PURB pUrb = NULL;
  155. PDEVICE_OBJECT pUrbTargetDev;
  156. PIO_STACK_LOCATION pNextStack;
  157. PVOID pPacketToSend;
  158. PIRUSB_CONTEXT pThisContext = pContext;
  159. LARGE_INTEGER CurrentTime, TimeDifference;
  160. PNDIS_IRDA_PACKET_INFO pPacketInfo;
  161. DEBUGMSG(DBG_FUNC, ("+SendPreprocessedPacketSend\n"));
  162. IRUSB_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  163. IRUSB_ASSERT( NULL != pThisContext );
  164. //
  165. // Stop if a halt/reset/suspend is going on
  166. //
  167. if( pThisDev->fPendingWriteClearStall || pThisDev->fPendingHalt ||
  168. pThisDev->fPendingReset || pThisDev->fPendingClearTotalStall || !pThisDev->fProcessing )
  169. {
  170. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend abort due to pending reset or halt\n"));
  171. status = NDIS_STATUS_RESET_IN_PROGRESS;
  172. //
  173. // Give the packet back to the protocol
  174. //
  175. NdisMSendComplete(
  176. pThisDev->hNdisAdapter,
  177. pThisContext->pPacket,
  178. status
  179. );
  180. InterlockedIncrement( &pThisDev->packetsSentRejected );
  181. //
  182. // Back to the available queue
  183. //
  184. ExInterlockedInsertTailList(
  185. &pThisDev->SendAvailableQueue,
  186. &pThisContext->ListEntry,
  187. &pThisDev->SendLock
  188. );
  189. InterlockedIncrement( &pThisDev->SendAvailableCount );
  190. goto done;
  191. }
  192. pPacketToSend = pThisContext->pPacket;
  193. IRUSB_ASSERT( NULL != pPacketToSend );
  194. //
  195. // Indicate that we are not receiving
  196. //
  197. InterlockedExchange( (PLONG)&pThisDev->fCurrentlyReceiving, FALSE );
  198. //
  199. // Convert the packet to an ir frame and copy into our buffer
  200. // and send the irp.
  201. //
  202. if( pThisDev->currentSpeed<=MAX_SIR_SPEED )
  203. {
  204. fConvertedPacket = NdisToSirPacket(
  205. pThisDev,
  206. pPacketToSend,
  207. (PUCHAR)pThisDev->pBuffer,
  208. MAX_IRDA_DATA_SIZE,
  209. pThisDev->pStagingBuffer,
  210. &BytesToWrite
  211. );
  212. }
  213. else if( pThisDev->currentSpeed<=MAX_MIR_SPEED )
  214. {
  215. fConvertedPacket = NdisToMirPacket(
  216. pThisDev,
  217. pPacketToSend,
  218. (PUCHAR)pThisDev->pBuffer,
  219. MAX_IRDA_DATA_SIZE,
  220. pThisDev->pStagingBuffer,
  221. &BytesToWrite
  222. );
  223. }
  224. else
  225. {
  226. fConvertedPacket = NdisToFirPacket(
  227. pThisDev,
  228. pPacketToSend,
  229. (PUCHAR)pThisDev->pBuffer,
  230. MAX_IRDA_DATA_SIZE,
  231. pThisDev->pStagingBuffer,
  232. &BytesToWrite
  233. );
  234. }
  235. #if defined(SEND_LOGGING)
  236. if( pThisDev->SendFileHandle )
  237. {
  238. IO_STATUS_BLOCK IoStatusBlock;
  239. ZwWriteFile(
  240. pThisDev->SendFileHandle,
  241. NULL,
  242. NULL,
  243. NULL,
  244. &IoStatusBlock,
  245. pThisDev->pBuffer,
  246. BytesToWrite,
  247. (PLARGE_INTEGER)&pThisDev->SendFilePosition,
  248. NULL
  249. );
  250. pThisDev->SendFilePosition += BytesToWrite;
  251. }
  252. #endif
  253. if( (fConvertedPacket == FALSE) || (BytesToWrite > NDIS_STATUS_INVALID_PACKET) )
  254. {
  255. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() NdisToIrPacket failed. Couldn't convert packet!\n"));
  256. status = NDIS_STATUS_INVALID_LENGTH;
  257. //
  258. // Give the packet back to the protocol
  259. //
  260. NdisMSendComplete(
  261. pThisDev->hNdisAdapter,
  262. pThisContext->pPacket,
  263. status
  264. );
  265. InterlockedIncrement( &pThisDev->packetsSentInvalid );
  266. //
  267. // Back to the available queue
  268. //
  269. ExInterlockedInsertTailList(
  270. &pThisDev->SendAvailableQueue,
  271. &pThisContext->ListEntry,
  272. &pThisDev->SendLock
  273. );
  274. InterlockedIncrement( &pThisDev->SendAvailableCount );
  275. goto done;
  276. }
  277. //
  278. // Save the effective length
  279. //
  280. pThisDev->BufLen = BytesToWrite;
  281. #if !defined(ONLY_ERROR_MESSAGES)
  282. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() NdisToIrPacket success BytesToWrite = dec %d, \n", BytesToWrite));
  283. #endif
  284. //
  285. // Verify the FIFO condition and possibly make sure we don't overflow
  286. //
  287. pThisDev->SendFifoCount += BytesToWrite;
  288. if( pThisDev->SendFifoCount >= (3*STIR4200_FIFO_SIZE/2) )
  289. {
  290. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() Completing, size: %d\n", pThisDev->SendFifoCount));
  291. SendWaitCompletion( pThisDev );
  292. pThisDev->SendFifoCount = BytesToWrite;
  293. }
  294. //
  295. // Enforce turnaround time
  296. //
  297. pPacketInfo = GetPacketInfo( pPacketToSend );
  298. if (pPacketInfo != NULL)
  299. {
  300. #if DBG
  301. //
  302. // See if we get a packet with 0 turnaround time specified
  303. // when we think we need need a turnaround time
  304. //
  305. if( pPacketInfo->MinTurnAroundTime > 0 )
  306. {
  307. pThisDev->NumPacketsSentRequiringTurnaroundTime++;
  308. }
  309. else
  310. {
  311. pThisDev->NumPacketsSentNotRequiringTurnaroundTime++;
  312. }
  313. #endif
  314. //
  315. // Deal with turnaroud time
  316. //
  317. KeQuerySystemTime( &CurrentTime );
  318. TimeDifference = RtlLargeIntegerSubtract( CurrentTime, pThisContext->TimeReceived );
  319. if( (ULONG)(TimeDifference.QuadPart/10) < pPacketInfo->MinTurnAroundTime )
  320. {
  321. ULONG TimeToWait = pPacketInfo->MinTurnAroundTime - (ULONG)(TimeDifference.QuadPart/10);
  322. //
  323. // Potential hack...
  324. //
  325. #if !defined(WORKAROUND_CASIO)
  326. if( TimeToWait > 1000 )
  327. #endif
  328. {
  329. #if !defined(ONLY_ERROR_MESSAGES)
  330. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() Enforcing turnaround time %d\n", TimeToWait));
  331. #endif
  332. NdisMSleep( TimeToWait );
  333. }
  334. }
  335. }
  336. else
  337. {
  338. //
  339. // irda protocol is broken
  340. //
  341. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() pPacketInfo == NULL\n"));
  342. }
  343. //
  344. // MS Security recommendation - allocate a new urb.
  345. //
  346. pThisContext->UrbLen = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  347. pThisContext->pUrb = MyUrbAlloc(pThisContext->UrbLen);
  348. if (pThisContext->pUrb == NULL)
  349. {
  350. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend abort due to urb alloc failure\n"));
  351. goto done;
  352. }
  353. pUrb = pThisContext->pUrb;
  354. //
  355. // Now that we have created the urb, we will send a
  356. // request to the USB device object.
  357. //
  358. pUrbTargetDev = pThisDev->pUsbDevObj;
  359. //
  360. // make an irp sending to usbhub
  361. //
  362. pIrp = IoAllocateIrp( (CCHAR)(pThisDev->pUsbDevObj->StackSize + 1), FALSE );
  363. if( NULL == pIrp )
  364. {
  365. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend failed to alloc IRP\n"));
  366. status = NDIS_STATUS_FAILURE;
  367. //
  368. // Give the packet back to the protocol
  369. //
  370. NdisMSendComplete(
  371. pThisDev->hNdisAdapter,
  372. pThisContext->pPacket,
  373. status
  374. );
  375. InterlockedIncrement( (PLONG)&pThisDev->packetsSentDropped );
  376. //
  377. // Back to the available queue
  378. //
  379. MyUrbFree(pThisContext->pUrb, pThisContext->UrbLen);
  380. pThisContext->pUrb = NULL;
  381. ExInterlockedInsertTailList(
  382. &pThisDev->SendAvailableQueue,
  383. &pThisContext->ListEntry,
  384. &pThisDev->SendLock
  385. );
  386. InterlockedIncrement( &pThisDev->SendAvailableCount );
  387. goto done;
  388. }
  389. pIrp->IoStatus.Status = STATUS_PENDING;
  390. pIrp->IoStatus.Information = 0;
  391. pThisContext->pIrp = pIrp;
  392. //
  393. // Build our URB for USBD
  394. //
  395. pUrb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT)sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  396. pUrb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  397. pUrb->UrbBulkOrInterruptTransfer.PipeHandle = pThisDev->BulkOutPipeHandle;
  398. pUrb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT ;
  399. // short packet is not treated as an error.
  400. pUrb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
  401. pUrb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  402. pUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
  403. pUrb->UrbBulkOrInterruptTransfer.TransferBuffer = pThisDev->pBuffer;
  404. pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength = (int)BytesToWrite;
  405. //
  406. // Call the class driver to perform the operation.
  407. //
  408. pNextStack = IoGetNextIrpStackLocation( pIrp );
  409. IRUSB_ASSERT( pNextStack != NULL );
  410. //
  411. // pass the URB to the USB driver stack
  412. //
  413. pNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  414. pNextStack->Parameters.Others.Argument1 = pUrb;
  415. pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  416. IoSetCompletionRoutine(
  417. pIrp, // irp to use
  418. SendCompletePacketSend, // routine to call when irp is done
  419. DEV_TO_CONTEXT(pThisContext), // context to pass routine
  420. TRUE, // call on success
  421. TRUE, // call on error
  422. TRUE // call on cancel
  423. );
  424. #ifdef SERIALIZE
  425. KeClearEvent( &pThisDev->EventSyncUrb );
  426. #endif
  427. //
  428. // Call IoCallDriver to send the irp to the usb port.
  429. //
  430. ExInterlockedInsertTailList(
  431. &pThisDev->SendPendingQueue,
  432. &pThisContext->ListEntry,
  433. &pThisDev->SendLock
  434. );
  435. InterlockedIncrement( &pThisDev->SendPendingCount );
  436. status = MyIoCallDriver( pThisDev, pUrbTargetDev, pIrp );
  437. //
  438. // The USB driver should always return STATUS_PENDING when
  439. // it receives a write irp
  440. //
  441. IRUSB_ASSERT( status == STATUS_PENDING );
  442. status = MyKeWaitForSingleObject( pThisDev, &pThisDev->EventSyncUrb, 0 );
  443. if( status == STATUS_TIMEOUT )
  444. {
  445. KIRQL OldIrql;
  446. DEBUGMSG( DBG_ERR,(" SendPreprocessedPacketSend() TIMED OUT! return from IoCallDriver USBD %x\n", status));
  447. KeAcquireSpinLock( &pThisDev->SendLock, &OldIrql );
  448. RemoveEntryList( &pThisContext->ListEntry );
  449. KeReleaseSpinLock( &pThisDev->SendLock, OldIrql );
  450. InterlockedDecrement( &pThisDev->SendPendingCount );
  451. // MS Security recommendation - cannot cancel IRP.
  452. }
  453. done:
  454. DEBUGMSG(DBG_FUNC, ("-SendPreprocessedPacketSend\n"));
  455. return status;
  456. }
  457. /*****************************************************************************
  458. *
  459. * Function: SendWaitCompletion
  460. *
  461. * Synopsis: Waits for a send operation to be completed. A send is completed when the
  462. * entire frame has been transmitted ove the IR medium
  463. *
  464. * Arguments: pThisDev - pointer to current ir device object
  465. *
  466. * Returns: NT status code
  467. *
  468. *****************************************************************************/
  469. NTSTATUS
  470. SendWaitCompletion(
  471. IN OUT PIR_DEVICE pThisDev
  472. )
  473. {
  474. NTSTATUS Status;
  475. LARGE_INTEGER CurrentTime, InitialTime;
  476. ULONG FifoCount, OldFifoCount = STIR4200_FIFO_SIZE;
  477. DEBUGMSG(DBG_ERR, (" SendWaitCompletion\n"));
  478. //
  479. // At low speed we simply force to wait
  480. //
  481. if( (pThisDev->currentSpeed <= MAX_MIR_SPEED) || (pThisDev->ChipRevision >= CHIP_REVISION_7) )
  482. {
  483. //
  484. // We force to wait until the end of transmit
  485. //
  486. KeQuerySystemTime( &InitialTime );
  487. while( TRUE )
  488. {
  489. //
  490. // Read the status register and check
  491. //
  492. if( (Status = St4200ReadRegisters( pThisDev, STIR4200_STATUS_REG, 3 )) == STATUS_SUCCESS )
  493. {
  494. //
  495. // bit set means still in transmit mode...
  496. //
  497. if( pThisDev->StIrTranceiver.StatusReg & STIR4200_STAT_FFDIR )
  498. {
  499. KeQuerySystemTime( &CurrentTime );
  500. FifoCount =
  501. ((ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg));
  502. if( ((CurrentTime.QuadPart-InitialTime.QuadPart) > (IRUSB_100ns_PER_ms*STIR4200_SEND_TIMEOUT) ) ||
  503. (FifoCount > OldFifoCount) )
  504. {
  505. //
  506. // The part received something while in transmit mode, so it hosed
  507. //
  508. pThisDev->PreFifoCount = 0;
  509. St4200DoubleResetFifo( pThisDev );
  510. break;
  511. }
  512. OldFifoCount = FifoCount;
  513. }
  514. else
  515. {
  516. pThisDev->PreFifoCount =
  517. ((ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg));
  518. break;
  519. }
  520. }
  521. else break;
  522. }
  523. }
  524. //
  525. // In high speed we try to be smarter
  526. //
  527. else
  528. {
  529. if( (Status = St4200ReadRegisters( pThisDev, STIR4200_STATUS_REG, 3 )) == STATUS_SUCCESS )
  530. {
  531. //
  532. // bit set means still in transmit mode...
  533. //
  534. if( pThisDev->StIrTranceiver.StatusReg & STIR4200_STAT_FFDIR )
  535. {
  536. ULONG Count;
  537. Count = ((ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg));
  538. // MS Security bug #540780 - use NdisMSleep instead of NdisStallExecution
  539. NdisMSleep( (STIR4200_WRITE_DELAY*Count)/MAX_TOTAL_SIZE_WITH_ALL_HEADERS );
  540. pThisDev->PreFifoCount = 0;
  541. }
  542. else
  543. {
  544. pThisDev->PreFifoCount =
  545. ((ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg));
  546. }
  547. }
  548. }
  549. pThisDev->SendFifoCount = 0;
  550. return Status;
  551. }
  552. /*****************************************************************************
  553. *
  554. * Function: SendCheckForOverflow
  555. *
  556. * Synopsis: Makes sure we are not going to overflow the TX FIFO
  557. *
  558. * Arguments: pThisDev - pointer to current ir device object
  559. *
  560. * Returns: NT status code
  561. *
  562. *****************************************************************************/
  563. NTSTATUS
  564. SendCheckForOverflow(
  565. IN OUT PIR_DEVICE pThisDev
  566. )
  567. {
  568. NTSTATUS Status = STATUS_SUCCESS;
  569. //
  570. // Check what we think we have in the FIFO
  571. //
  572. if( pThisDev->SendFifoCount > STIR4200_FIFO_SIZE )
  573. {
  574. //
  575. // Always one initial read
  576. //
  577. if( (Status = St4200ReadRegisters( pThisDev, STIR4200_FIFOCNT_LSB_REG, 2 )) == STATUS_SUCCESS )
  578. {
  579. pThisDev->SendFifoCount =
  580. (ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg);
  581. #if !defined(ONLY_ERROR_MESSAGES)
  582. DEBUGMSG( DBG_ERR,(" SendCheckForOverflow() Count: %d\n", pThisDev->SendFifoCount));
  583. #endif
  584. }
  585. else goto done;
  586. //
  587. // Force reads to get the real count, until condition is satisfied
  588. //
  589. while( pThisDev->SendFifoCount > (3*STIR4200_FIFO_SIZE/4) )
  590. {
  591. if( (Status = St4200ReadRegisters( pThisDev, STIR4200_FIFOCNT_LSB_REG, 2 )) == STATUS_SUCCESS )
  592. {
  593. pThisDev->SendFifoCount =
  594. (ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg);
  595. #if !defined(ONLY_ERROR_MESSAGES)
  596. DEBUGMSG( DBG_ERR,(" SendCheckForOverflow() Count: %d\n", pThisDev->SendFifoCount));
  597. #endif
  598. }
  599. else goto done;
  600. }
  601. }
  602. done:
  603. return Status;
  604. }
  605. /*****************************************************************************
  606. *
  607. * Function: SendCompletePacketSend
  608. *
  609. * Synopsis: Completes USB write operation
  610. *
  611. * Arguments: pUsbDevObj - pointer to the USB device object which
  612. * completed the irp
  613. * pIrp - the irp which was completed by the
  614. * device object
  615. * Context - the context given to IoSetCompletionRoutine
  616. * before calling IoCallDriver on the irp
  617. * The Context is a pointer to the ir device object.
  618. *
  619. * Returns: STATUS_MORE_PROCESSING_REQUIRED - allows the completion routine
  620. * (IofCompleteRequest) to stop working on the irp.
  621. *
  622. *****************************************************************************/
  623. NTSTATUS
  624. SendCompletePacketSend(
  625. IN PDEVICE_OBJECT pUsbDevObj,
  626. IN PIRP pIrp,
  627. IN PVOID Context
  628. )
  629. {
  630. PIR_DEVICE pThisDev;
  631. PVOID pThisContextPacket;
  632. NTSTATUS status;
  633. PIRUSB_CONTEXT pThisContext = (PIRUSB_CONTEXT)Context;
  634. PIRP pContextIrp;
  635. PURB pContextUrb;
  636. ULONG BufLen;
  637. ULONG BytesTransfered;
  638. PLIST_ENTRY pListEntry;
  639. DEBUGMSG(DBG_FUNC, ("+SendCompletePacketSend\n"));
  640. //
  641. // The context given to IoSetCompletionRoutine is an IRUSB_CONTEXT struct
  642. //
  643. IRUSB_ASSERT( NULL != pThisContext ); // we better have a non NULL buffer
  644. pThisDev = pThisContext->pThisDev;
  645. IRUSB_ASSERT( NULL != pThisDev );
  646. pContextIrp = pThisContext->pIrp;
  647. pContextUrb = pThisContext->pUrb;
  648. BufLen = pThisDev->BufLen;
  649. pThisContextPacket = pThisContext->pPacket; //save ptr to packet to access after context freed
  650. //
  651. // Perform various IRP, URB, and buffer 'sanity checks'
  652. //
  653. IRUSB_ASSERT( pContextIrp == pIrp ); // check we're not a bogus IRP
  654. IRUSB_ASSERT( pContextUrb != NULL );
  655. status = pIrp->IoStatus.Status;
  656. //
  657. // we should have failed, succeeded, or cancelled, but NOT be pending
  658. //
  659. IRUSB_ASSERT( STATUS_PENDING != status );
  660. //
  661. // Remove from the pending queue (only if NOT cancelled)
  662. //
  663. if( status != STATUS_CANCELLED )
  664. {
  665. KIRQL OldIrql;
  666. KeAcquireSpinLock( &pThisDev->SendLock, &OldIrql );
  667. RemoveEntryList( &pThisContext->ListEntry );
  668. KeReleaseSpinLock( &pThisDev->SendLock, OldIrql );
  669. InterlockedDecrement( &pThisDev->SendPendingCount );
  670. }
  671. //
  672. // IoCallDriver has been called on this Irp;
  673. // Set the length based on the TransferBufferLength
  674. // value in the URB
  675. //
  676. pIrp->IoStatus.Information = pContextUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  677. BytesTransfered = (ULONG)pIrp->IoStatus.Information; // save for below need-termination test
  678. #if DBG
  679. if( STATUS_SUCCESS == status )
  680. {
  681. IRUSB_ASSERT( pIrp->IoStatus.Information == BufLen );
  682. }
  683. #endif
  684. DEBUGMSG(DBG_OUT, (" SendCompletePacketSend pIrp->IoStatus.Status = 0x%x\n", status));
  685. DEBUGMSG(DBG_OUT, (" SendCompletePacketSend pIrp->IoStatus.Information = 0x%x, dec %d\n", pIrp->IoStatus.Information,pIrp->IoStatus.Information));
  686. //
  687. // Keep statistics.
  688. //
  689. if( status == STATUS_SUCCESS )
  690. {
  691. #if DBG
  692. ULONG total = pThisDev->TotalBytesSent + BytesTransfered;
  693. InterlockedExchange( (PLONG)&pThisDev->TotalBytesSent, (LONG)total );
  694. #endif
  695. InterlockedIncrement( (PLONG)&pThisDev->packetsSent );
  696. DEBUGMSG(DBG_OUT, (" SendCompletePacketSend Sent a packet, packets sent = dec %d\n",pThisDev->packetsSent));
  697. }
  698. else
  699. {
  700. InterlockedIncrement( (PLONG)&pThisDev->NumDataErrors );
  701. InterlockedIncrement( (PLONG)&pThisDev->packetsSentDropped );
  702. DEBUGMSG(DBG_ERR, (" SendCompletePacketSend DROPPED a packet, packets dropped = dec %d\n",pThisDev->packetsSentDropped));
  703. }
  704. //
  705. // Free the IRP.
  706. //
  707. IoFreeIrp( pIrp );
  708. InterlockedIncrement( (PLONG)&pThisDev->NumWrites );
  709. // Free the URB.
  710. MyUrbFree(pThisContext->pUrb, pThisContext->UrbLen);
  711. pThisContext->pUrb = NULL;
  712. //
  713. // Indicate to the protocol the status of the sent packet and return
  714. // ownership of the packet.
  715. //
  716. NdisMSendComplete(
  717. pThisDev->hNdisAdapter,
  718. pThisContextPacket,
  719. status
  720. );
  721. //
  722. // Enqueue the completed packet
  723. //
  724. ExInterlockedInsertTailList(
  725. &pThisDev->SendAvailableQueue,
  726. &pThisContext->ListEntry,
  727. &pThisDev->SendLock
  728. );
  729. InterlockedIncrement( &pThisDev->SendAvailableCount );
  730. IrUsb_DecIoCount( pThisDev ); // we will track count of pending irps
  731. if( ( STATUS_SUCCESS != status ) && ( STATUS_CANCELLED != status ) )
  732. {
  733. if( !pThisDev->fPendingWriteClearStall && !pThisDev->fPendingClearTotalStall &&
  734. !pThisDev->fPendingHalt && !pThisDev->fPendingReset && pThisDev->fProcessing )
  735. {
  736. DEBUGMSG(DBG_ERR, (" SendCompletePacketSend error, will schedule a clear stall via URB_FUNCTION_RESET_PIPE (OUT)\n"));
  737. InterlockedExchange( (PLONG)&pThisDev->fPendingWriteClearStall, TRUE );
  738. ScheduleWorkItem( pThisDev, ResetPipeCallback, pThisDev->BulkOutPipeHandle, 0 );
  739. }
  740. }
  741. #ifdef SERIALIZE
  742. KeSetEvent( &pThisDev->EventSyncUrb, 0, FALSE ); //signal we're done
  743. #endif
  744. DEBUGMSG(DBG_FUNC, ("-SendCompletePacketSend\n"));
  745. return STATUS_MORE_PROCESSING_REQUIRED;
  746. }