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.

840 lines
23 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. pUrb = pThisDev->pUrb;
  193. NdisZeroMemory( pUrb, pThisDev->UrbLen );
  194. pPacketToSend = pThisContext->pPacket;
  195. IRUSB_ASSERT( NULL != pPacketToSend );
  196. //
  197. // Indicate that we are not receiving
  198. //
  199. InterlockedExchange( (PLONG)&pThisDev->fCurrentlyReceiving, FALSE );
  200. //
  201. // Convert the packet to an ir frame and copy into our buffer
  202. // and send the irp.
  203. //
  204. if( pThisDev->currentSpeed<=MAX_SIR_SPEED )
  205. {
  206. fConvertedPacket = NdisToSirPacket(
  207. pThisDev,
  208. pPacketToSend,
  209. (PUCHAR)pThisDev->pBuffer,
  210. MAX_IRDA_DATA_SIZE,
  211. pThisDev->pStagingBuffer,
  212. &BytesToWrite
  213. );
  214. }
  215. else if( pThisDev->currentSpeed<=MAX_MIR_SPEED )
  216. {
  217. fConvertedPacket = NdisToMirPacket(
  218. pThisDev,
  219. pPacketToSend,
  220. (PUCHAR)pThisDev->pBuffer,
  221. MAX_IRDA_DATA_SIZE,
  222. pThisDev->pStagingBuffer,
  223. &BytesToWrite
  224. );
  225. }
  226. else
  227. {
  228. fConvertedPacket = NdisToFirPacket(
  229. pThisDev,
  230. pPacketToSend,
  231. (PUCHAR)pThisDev->pBuffer,
  232. MAX_IRDA_DATA_SIZE,
  233. pThisDev->pStagingBuffer,
  234. &BytesToWrite
  235. );
  236. }
  237. #if defined(SEND_LOGGING)
  238. if( pThisDev->SendFileHandle )
  239. {
  240. IO_STATUS_BLOCK IoStatusBlock;
  241. ZwWriteFile(
  242. pThisDev->SendFileHandle,
  243. NULL,
  244. NULL,
  245. NULL,
  246. &IoStatusBlock,
  247. pThisDev->Buffer,
  248. BytesToWrite,
  249. (PLARGE_INTEGER)&pThisDev->SendFilePosition,
  250. NULL
  251. );
  252. pThisDev->SendFilePosition += BytesToWrite;
  253. }
  254. #endif
  255. if( (fConvertedPacket == FALSE) || (BytesToWrite > NDIS_STATUS_INVALID_PACKET) )
  256. {
  257. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() NdisToIrPacket failed. Couldn't convert packet!\n"));
  258. status = NDIS_STATUS_INVALID_LENGTH;
  259. //
  260. // Give the packet back to the protocol
  261. //
  262. NdisMSendComplete(
  263. pThisDev->hNdisAdapter,
  264. pThisContext->pPacket,
  265. status
  266. );
  267. InterlockedIncrement( &pThisDev->packetsSentInvalid );
  268. //
  269. // Back to the available queue
  270. //
  271. ExInterlockedInsertTailList(
  272. &pThisDev->SendAvailableQueue,
  273. &pThisContext->ListEntry,
  274. &pThisDev->SendLock
  275. );
  276. InterlockedIncrement( &pThisDev->SendAvailableCount );
  277. goto done;
  278. }
  279. //
  280. // Save the effective length
  281. //
  282. pThisDev->BufLen = BytesToWrite;
  283. #if !defined(ONLY_ERROR_MESSAGES)
  284. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() NdisToIrPacket success BytesToWrite = dec %d, \n", BytesToWrite));
  285. #endif
  286. //
  287. // Verify the FIFO condition and possibly make sure we don't overflow
  288. //
  289. pThisDev->SendFifoCount += BytesToWrite;
  290. if( pThisDev->SendFifoCount >= (3*STIR4200_FIFO_SIZE/2) )
  291. {
  292. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() Completing, size: %d\n", pThisDev->SendFifoCount));
  293. SendWaitCompletion( pThisDev );
  294. pThisDev->SendFifoCount = BytesToWrite;
  295. }
  296. #if defined( WORKAROUND_STUCK_AFTER_GEAR_DOWN )
  297. if( pThisDev->GearedDown )
  298. {
  299. #define SIZE_FAKE_SEND 5
  300. UCHAR pData[SIZE_FAKE_SEND]={0x55,0xaa,SIZE_FAKE_SEND-4,0x00,0xff};
  301. St4200FakeSend(
  302. pThisDev,
  303. pData,
  304. SIZE_FAKE_SEND
  305. );
  306. St4200FakeSend(
  307. pThisDev,
  308. pData,
  309. SIZE_FAKE_SEND
  310. );
  311. pThisDev->GearedDown = FALSE;
  312. }
  313. #endif
  314. //
  315. // Enforce turnaround time
  316. //
  317. pPacketInfo = GetPacketInfo( pPacketToSend );
  318. if (pPacketInfo != NULL)
  319. {
  320. #if DBG
  321. //
  322. // See if we get a packet with 0 turnaround time specified
  323. // when we think we need need a turnaround time
  324. //
  325. if( pPacketInfo->MinTurnAroundTime > 0 )
  326. {
  327. pThisDev->NumPacketsSentRequiringTurnaroundTime++;
  328. }
  329. else
  330. {
  331. pThisDev->NumPacketsSentNotRequiringTurnaroundTime++;
  332. }
  333. #endif
  334. //
  335. // Deal with turnaroud time
  336. //
  337. KeQuerySystemTime( &CurrentTime );
  338. TimeDifference = RtlLargeIntegerSubtract( CurrentTime, pThisContext->TimeReceived );
  339. if( (ULONG)(TimeDifference.QuadPart/10) < pPacketInfo->MinTurnAroundTime )
  340. {
  341. ULONG TimeToWait = pPacketInfo->MinTurnAroundTime - (ULONG)(TimeDifference.QuadPart/10);
  342. //
  343. // Potential hack...
  344. //
  345. if( TimeToWait > 1000 )
  346. {
  347. #if !defined(ONLY_ERROR_MESSAGES)
  348. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() Enforcing turnaround time %d\n", TimeToWait));
  349. #endif
  350. NdisMSleep( TimeToWait );
  351. }
  352. }
  353. }
  354. else
  355. {
  356. //
  357. // irda protocol is broken
  358. //
  359. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend() pPacketInfo == NULL\n"));
  360. }
  361. //
  362. // Now that we have created the urb, we will send a
  363. // request to the USB device object.
  364. //
  365. pUrbTargetDev = pThisDev->pUsbDevObj;
  366. //
  367. // make an irp sending to usbhub
  368. //
  369. pIrp = IoAllocateIrp( (CCHAR)(pThisDev->pUsbDevObj->StackSize + 1), FALSE );
  370. if( NULL == pIrp )
  371. {
  372. DEBUGMSG(DBG_ERR, (" SendPreprocessedPacketSend failed to alloc IRP\n"));
  373. status = NDIS_STATUS_FAILURE;
  374. //
  375. // Give the packet back to the protocol
  376. //
  377. NdisMSendComplete(
  378. pThisDev->hNdisAdapter,
  379. pThisContext->pPacket,
  380. status
  381. );
  382. InterlockedIncrement( (PLONG)&pThisDev->packetsSentDropped );
  383. //
  384. // Back to the available queue
  385. //
  386. ExInterlockedInsertTailList(
  387. &pThisDev->SendAvailableQueue,
  388. &pThisContext->ListEntry,
  389. &pThisDev->SendLock
  390. );
  391. InterlockedIncrement( &pThisDev->SendAvailableCount );
  392. goto done;
  393. }
  394. pIrp->IoStatus.Status = STATUS_PENDING;
  395. pIrp->IoStatus.Information = 0;
  396. pThisContext->pIrp = pIrp;
  397. //
  398. // Build our URB for USBD
  399. //
  400. pUrb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT)sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  401. pUrb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  402. pUrb->UrbBulkOrInterruptTransfer.PipeHandle = pThisDev->BulkOutPipeHandle;
  403. pUrb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT ;
  404. // short packet is not treated as an error.
  405. pUrb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
  406. pUrb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  407. pUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
  408. pUrb->UrbBulkOrInterruptTransfer.TransferBuffer = pThisDev->pBuffer;
  409. pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength = (int)BytesToWrite;
  410. //
  411. // Call the class driver to perform the operation.
  412. //
  413. pNextStack = IoGetNextIrpStackLocation( pIrp );
  414. IRUSB_ASSERT( pNextStack != NULL );
  415. //
  416. // pass the URB to the USB driver stack
  417. //
  418. pNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  419. pNextStack->Parameters.Others.Argument1 = pUrb;
  420. pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  421. IoSetCompletionRoutine(
  422. pIrp, // irp to use
  423. SendCompletePacketSend, // routine to call when irp is done
  424. DEV_TO_CONTEXT(pThisContext), // context to pass routine
  425. TRUE, // call on success
  426. TRUE, // call on error
  427. TRUE // call on cancel
  428. );
  429. #ifdef SERIALIZE
  430. KeClearEvent( &pThisDev->EventSyncUrb );
  431. #endif
  432. //
  433. // Call IoCallDriver to send the irp to the usb port.
  434. //
  435. ExInterlockedInsertTailList(
  436. &pThisDev->SendPendingQueue,
  437. &pThisContext->ListEntry,
  438. &pThisDev->SendLock
  439. );
  440. InterlockedIncrement( &pThisDev->SendPendingCount );
  441. status = MyIoCallDriver( pThisDev, pUrbTargetDev, pIrp );
  442. //
  443. // The USB driver should always return STATUS_PENDING when
  444. // it receives a write irp
  445. //
  446. IRUSB_ASSERT( status == STATUS_PENDING );
  447. status = MyKeWaitForSingleObject( pThisDev, &pThisDev->EventSyncUrb, NULL, 0 );
  448. if( status == STATUS_TIMEOUT )
  449. {
  450. KIRQL OldIrql;
  451. DEBUGMSG( DBG_ERR,(" SendPreprocessedPacketSend() TIMED OUT! return from IoCallDriver USBD %x\n", status));
  452. KeAcquireSpinLock( &pThisDev->SendLock, &OldIrql );
  453. RemoveEntryList( &pThisContext->ListEntry );
  454. KeReleaseSpinLock( &pThisDev->SendLock, OldIrql );
  455. InterlockedDecrement( &pThisDev->SendPendingCount );
  456. IrUsb_CancelIo( pThisDev, pIrp, &pThisDev->EventSyncUrb );
  457. }
  458. done:
  459. DEBUGMSG(DBG_FUNC, ("-SendPreprocessedPacketSend\n"));
  460. return status;
  461. }
  462. /*****************************************************************************
  463. *
  464. * Function: SendWaitCompletion
  465. *
  466. * Synopsis: Waits for a send operation to be completed. A send is completed when the
  467. * entire frame has been transmitted ove the IR medium
  468. *
  469. * Arguments: pThisDev - pointer to current ir device object
  470. *
  471. * Returns: NT status code
  472. *
  473. *****************************************************************************/
  474. NTSTATUS
  475. SendWaitCompletion(
  476. IN OUT PIR_DEVICE pThisDev
  477. )
  478. {
  479. NTSTATUS Status;
  480. LARGE_INTEGER CurrentTime, InitialTime;
  481. ULONG FifoCount, OldFifoCount = STIR4200_FIFO_SIZE;
  482. //
  483. // At low speed we simply force to wait
  484. //
  485. if( (pThisDev->currentSpeed <= MAX_MIR_SPEED) || (pThisDev->ChipRevision >= CHIP_REVISION_7) )
  486. {
  487. //
  488. // We force to wait until the end of transmit
  489. //
  490. KeQuerySystemTime( &InitialTime );
  491. while( TRUE )
  492. {
  493. //
  494. // Read the status register and check
  495. //
  496. if( (Status = St4200ReadRegisters( pThisDev, STIR4200_STATUS_REG, 3 )) == STATUS_SUCCESS )
  497. {
  498. //
  499. // bit set means still in transmit mode...
  500. //
  501. if( pThisDev->StIrTranceiver.StatusReg & STIR4200_STAT_FFDIR )
  502. {
  503. KeQuerySystemTime( &CurrentTime );
  504. FifoCount =
  505. ((ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg));
  506. if( ((CurrentTime.QuadPart-InitialTime.QuadPart) > (IRUSB_100ns_PER_ms*STIR4200_SEND_TIMEOUT) ) ||
  507. (FifoCount > OldFifoCount) )
  508. {
  509. pThisDev->PreFifoCount = 0;
  510. St4200DoubleResetFifo( pThisDev );
  511. break;
  512. }
  513. OldFifoCount = FifoCount;
  514. }
  515. else
  516. {
  517. pThisDev->PreFifoCount =
  518. ((ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg));
  519. break;
  520. }
  521. }
  522. else break;
  523. }
  524. }
  525. //
  526. // In high speed we try to be smarter
  527. //
  528. else
  529. {
  530. if( (Status = St4200ReadRegisters( pThisDev, STIR4200_STATUS_REG, 3 )) == STATUS_SUCCESS )
  531. {
  532. //
  533. // bit set means still in transmit mode...
  534. //
  535. if( pThisDev->StIrTranceiver.StatusReg & STIR4200_STAT_FFDIR )
  536. {
  537. ULONG Count;
  538. Count = ((ULONG)MAKEUSHORT(pThisDev->StIrTranceiver.FifoCntLsbReg, pThisDev->StIrTranceiver.FifoCntMsbReg));
  539. NdisStallExecution( (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 > (3*STIR4200_FIFO_SIZE/4) )
  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 = pThisDev->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. status = pIrp->IoStatus.Status;
  655. //
  656. // we should have failed, succeeded, or cancelled, but NOT be pending
  657. //
  658. IRUSB_ASSERT( STATUS_PENDING != status );
  659. //
  660. // Remove from the pending queue (only if NOT cancelled)
  661. //
  662. if( status != STATUS_CANCELLED )
  663. {
  664. KIRQL OldIrql;
  665. KeAcquireSpinLock( &pThisDev->SendLock, &OldIrql );
  666. RemoveEntryList( &pThisContext->ListEntry );
  667. KeReleaseSpinLock( &pThisDev->SendLock, OldIrql );
  668. InterlockedDecrement( &pThisDev->SendPendingCount );
  669. }
  670. //
  671. // IoCallDriver has been called on this Irp;
  672. // Set the length based on the TransferBufferLength
  673. // value in the URB
  674. //
  675. pIrp->IoStatus.Information = pContextUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  676. BytesTransfered = (ULONG)pIrp->IoStatus.Information; // save for below need-termination test
  677. #if DBG
  678. if( STATUS_SUCCESS == status )
  679. {
  680. IRUSB_ASSERT( pIrp->IoStatus.Information == BufLen );
  681. }
  682. #endif
  683. DEBUGMSG(DBG_OUT, (" SendCompletePacketSend pIrp->IoStatus.Status = 0x%x\n", status));
  684. DEBUGMSG(DBG_OUT, (" SendCompletePacketSend pIrp->IoStatus.Information = 0x%x, dec %d\n", pIrp->IoStatus.Information,pIrp->IoStatus.Information));
  685. //
  686. // Keep statistics.
  687. //
  688. if( status == STATUS_SUCCESS )
  689. {
  690. #if DBG
  691. ULONG total = pThisDev->TotalBytesSent + BytesTransfered;
  692. InterlockedExchange( (PLONG)&pThisDev->TotalBytesSent, (LONG)total );
  693. #endif
  694. InterlockedIncrement( (PLONG)&pThisDev->packetsSent );
  695. DEBUGMSG(DBG_OUT, (" SendCompletePacketSend Sent a packet, packets sent = dec %d\n",pThisDev->packetsSent));
  696. }
  697. else
  698. {
  699. InterlockedIncrement( (PLONG)&pThisDev->NumDataErrors );
  700. InterlockedIncrement( (PLONG)&pThisDev->packetsSentDropped );
  701. DEBUGMSG(DBG_ERR, (" SendCompletePacketSend DROPPED a packet, packets dropped = dec %d\n",pThisDev->packetsSentDropped));
  702. }
  703. //
  704. // Free the IRP because we alloced it ourselves,
  705. //
  706. IoFreeIrp( pIrp );
  707. InterlockedIncrement( (PLONG)&pThisDev->NumWrites );
  708. //
  709. // Indicate to the protocol the status of the sent packet and return
  710. // ownership of the packet.
  711. //
  712. NdisMSendComplete(
  713. pThisDev->hNdisAdapter,
  714. pThisContextPacket,
  715. status
  716. );
  717. //
  718. // Enqueue the completed packet
  719. //
  720. ExInterlockedInsertTailList(
  721. &pThisDev->SendAvailableQueue,
  722. &pThisContext->ListEntry,
  723. &pThisDev->SendLock
  724. );
  725. InterlockedIncrement( &pThisDev->SendAvailableCount );
  726. IrUsb_DecIoCount( pThisDev ); // we will track count of pending irps
  727. if( ( STATUS_SUCCESS != status ) && ( STATUS_CANCELLED != status ) )
  728. {
  729. if( !pThisDev->fPendingWriteClearStall && !pThisDev->fPendingClearTotalStall &&
  730. !pThisDev->fPendingHalt && !pThisDev->fPendingReset && pThisDev->fProcessing )
  731. {
  732. DEBUGMSG(DBG_ERR, (" SendCompletePacketSend error, will schedule a clear stall via URB_FUNCTION_RESET_PIPE (OUT)\n"));
  733. InterlockedExchange( (PLONG)&pThisDev->fPendingWriteClearStall, TRUE );
  734. ScheduleWorkItem( pThisDev, ResetPipeCallback, pThisDev->BulkOutPipeHandle, 0 );
  735. }
  736. }
  737. #ifdef SERIALIZE
  738. KeSetEvent( &pThisDev->EventSyncUrb, 0, FALSE ); //signal we're done
  739. #endif
  740. DEBUGMSG(DBG_FUNC, ("-SendCompletePacketSend\n"));
  741. return STATUS_MORE_PROCESSING_REQUIRED;
  742. }