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.

617 lines
16 KiB

  1. /* ++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. write.c
  5. Abstract:
  6. Write functions
  7. Environment:
  8. kernel mode only
  9. Revision History:
  10. 07-14-99 : created
  11. Authors:
  12. Jeff Midkiff (jeffmi)
  13. -- */
  14. #include <wdm.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <usbdi.h>
  18. #include <usbdlib.h>
  19. #include <ntddser.h>
  20. #include "wceusbsh.h"
  21. NTSTATUS
  22. WriteComplete(
  23. IN PDEVICE_OBJECT PDevObj,
  24. IN PIRP PIrp,
  25. IN PUSB_PACKET PPacket
  26. );
  27. VOID
  28. WriteTimeout(
  29. IN PKDPC PDpc,
  30. IN PVOID DeferredContext,
  31. IN PVOID SystemContext1,
  32. IN PVOID SystemContext2
  33. );
  34. #if DBG
  35. VOID
  36. DbgDumpReadWriteData(
  37. IN PDEVICE_OBJECT PDevObj,
  38. IN PIRP PIrp,
  39. IN BOOLEAN Read
  40. );
  41. #else
  42. #define DbgDumpReadWriteData( _devobj, _irp, _read )
  43. #endif
  44. NTSTATUS
  45. Write(
  46. IN PDEVICE_OBJECT PDevObj,
  47. PIRP PIrp
  48. )
  49. /*++
  50. Routine Description:
  51. Process the IRPs sent to this device for writing.
  52. IRP_MJ_WRITE
  53. Arguments:
  54. PDevObj - Pointer to the device object for the device written to
  55. PIrp - Pointer to the write IRP.
  56. Return Value:
  57. NTSTATUS
  58. Notes:
  59. The AN2720 is a low-quality FIFO device and will NAK all packets when it's
  60. FIFO gets full. We can't get real device status, like serial port registers.
  61. If we submit a USBDI 'GetEndpointStatus', then all we get back is a stall bit.
  62. PROBLEM: what to do when it's FIFO get's full, i.e., how to handle flow control?
  63. If the peer/client on the other side of the FIFO is not reading packets out of the FIFO,
  64. then AN2720 NAKS every packet thereafter, until the FIFO gets drained (or, at least 1 packet
  65. removed).
  66. Here's what we currently do: on every _USB_PACKET we submit, set a timeout.
  67. When the timer expires we check if our R/W completion routine has already cancelled that
  68. packet's timer. If our completion did cancel the timer, then we are done.
  69. If not, then we timed out on this packet. We do not reset the endpoint on a timeout
  70. since the FIFO's contents will be lost. We simply complete the Irp to
  71. user with STATUS_TIMEOUT. User should then go into whatever retry logic they require.
  72. --*/
  73. {
  74. PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)PDevObj->DeviceExtension;
  75. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  76. KIRQL irql;
  77. LARGE_INTEGER timeOut = {0,0};
  78. ULONG ulTransferLength;
  79. NTSTATUS status = STATUS_UNSUCCESSFUL;
  80. BOOLEAN bCompleteIrp = FALSE;
  81. PERF_ENTRY( PERF_Write );
  82. DbgDump(DBG_WRITE|DBG_TRACE, (">Write(%p, %p, %x)\n", PDevObj, PIrp, Read));
  83. PIrp->IoStatus.Information = 0L;
  84. //
  85. // Make sure the device is accepting request
  86. //
  87. if ( !CanAcceptIoRequests( PDevObj, TRUE, TRUE) ||
  88. !NT_SUCCESS(AcquireRemoveLock(&pDevExt->RemoveLock, PIrp)) )
  89. {
  90. status = PIrp->IoStatus.Status = STATUS_DELETE_PENDING;
  91. DbgDump(DBG_ERR, ("Write ERROR: 0x%x\n", status));
  92. PIrp->IoStatus.Status = status;
  93. IoCompleteRequest(PIrp, IO_NO_INCREMENT);
  94. return status;
  95. }
  96. //
  97. // Check write length.
  98. // Allow zero length writes for apps to send a NULL packet
  99. // to signal end of transaction.
  100. //
  101. ulTransferLength = pIrpSp->Parameters.Write.Length;
  102. if ( ulTransferLength > pDevExt->MaximumTransferSize ) {
  103. DbgDump(DBG_ERR, ("Write Buffer too large: %d\n", ulTransferLength ));
  104. status = PIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  105. bCompleteIrp = TRUE;
  106. goto WriteExit;
  107. }
  108. DbgDump(DBG_WRITE_LENGTH, ("User Write request length: %d\n", ulTransferLength ));
  109. //
  110. // calculate Serial TimeOut values
  111. //
  112. ASSERT_SERIAL_PORT(pDevExt->SerialPort);
  113. CalculateTimeout( &timeOut,
  114. pIrpSp->Parameters.Write.Length,
  115. pDevExt->SerialPort.Timeouts.WriteTotalTimeoutMultiplier,
  116. pDevExt->SerialPort.Timeouts.WriteTotalTimeoutConstant );
  117. DbgDump(DBG_TIME, ("CalculateWriteTimeOut = %d msec\n", timeOut.QuadPart ));
  118. status = STATUS_SUCCESS;
  119. //
  120. // check if this Irp should be cancelled.
  121. // Note that we don't queue write Irps.
  122. //
  123. IoAcquireCancelSpinLock(&irql);
  124. if (PIrp->Cancel) {
  125. TEST_TRAP();
  126. IoReleaseCancelSpinLock(irql);
  127. status = PIrp->IoStatus.Status = STATUS_CANCELLED;
  128. // since we don't set a completion routine we complete it here
  129. bCompleteIrp = TRUE;
  130. } else {
  131. //
  132. // prepare to submit the IRP to the USB stack.
  133. //
  134. IoSetCancelRoutine(PIrp, NULL);
  135. IoReleaseCancelSpinLock(irql);
  136. KeAcquireSpinLock( &pDevExt->ControlLock, &irql);
  137. IRP_INIT_REFERENCE(PIrp);
  138. // set current number of chars in the Tx buffer
  139. InterlockedExchange( &pDevExt->SerialPort.CharsInWriteBuf, ulTransferLength );
  140. KeClearEvent( &pDevExt->PendingDataOutEvent );
  141. //
  142. // bump ttl request count
  143. //
  144. pDevExt->TtlWriteRequests++;
  145. KeReleaseSpinLock( &pDevExt->ControlLock, irql);
  146. status = UsbReadWritePacket( pDevExt,
  147. PIrp,
  148. WriteComplete,
  149. timeOut,
  150. WriteTimeout,
  151. FALSE );
  152. }
  153. WriteExit:
  154. if (bCompleteIrp)
  155. {
  156. ReleaseRemoveLock(&pDevExt->RemoveLock, PIrp);
  157. IoCompleteRequest (PIrp, IO_SERIAL_INCREMENT );
  158. }
  159. DbgDump(DBG_WRITE|DBG_TRACE, ("<Write 0x%x\n", status));
  160. PERF_EXIT( PERF_Write );
  161. return status;
  162. }
  163. NTSTATUS
  164. WriteComplete(
  165. IN PDEVICE_OBJECT PDevObj,
  166. IN PIRP PIrp,
  167. IN PUSB_PACKET PPacket
  168. )
  169. /*++
  170. Routine Description:
  171. This is the completion routine for Write requests.
  172. It assumes you have the serial port context.
  173. Arguments:
  174. PDevObj - Pointer to device object
  175. PIrp - Irp we are completing
  176. PPacket - USB Packet which will be freed
  177. Return Value:
  178. NTSTATUS -- propogate Irp's status.
  179. Notes:
  180. This routine runs at DPC_LEVEL.
  181. --*/
  182. {
  183. PDEVICE_EXTENSION pDevExt = PPacket->DeviceExtension;
  184. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
  185. PURB pUrb = &PPacket->Urb;
  186. NTSTATUS irpStatus, workStatus;
  187. USBD_STATUS urbStatus;
  188. KIRQL irql;
  189. LONG curCount;
  190. PERF_ENTRY( PERF_WriteComplete );
  191. UNREFERENCED_PARAMETER( PDevObj );
  192. DbgDump(DBG_WRITE, (">WriteComplete(%p, %p, %p)\n", PDevObj, PIrp, PPacket));
  193. // Note: we don't hold the control lock so this could
  194. // disappear on us.
  195. ASSERT_SERIAL_PORT(pDevExt->SerialPort);
  196. //
  197. // First off, cancel the Packet Timer
  198. //
  199. if ( PPacket->Timeout.QuadPart != 0 ) {
  200. if (KeCancelTimer( &PPacket->TimerObj ) ) {
  201. //
  202. // the packet's timer was successfully removed from the system
  203. //
  204. } else {
  205. //
  206. // the timer could be spinning on the control lock,
  207. // so tell it we took the Irp.
  208. //
  209. PPacket->Status = STATUS_ALERTED;
  210. }
  211. }
  212. //
  213. // Now we can process the Irp.
  214. // If the lower driver returned PENDING,
  215. // then mark our stack location as pending.
  216. //
  217. if ( PIrp->PendingReturned ) {
  218. DbgDump(DBG_WRITE, ("Resetting Irp STATUS_PENDING\n"));
  219. IoMarkIrpPending(PIrp);
  220. }
  221. //
  222. // This is the R/W operation's return status.
  223. // irpStatus is the Irp's completion status
  224. // ubrStatus is a more USBD specific Urb operation completion status
  225. //
  226. irpStatus = PIrp->IoStatus.Status;
  227. DbgDump(DBG_WRITE, ("Irp->IoStatus.Status 0x%x\n", irpStatus));
  228. urbStatus = pUrb->UrbHeader.Status;
  229. DbgDump(DBG_WRITE, ("Urb->UrbHeader.Status 0x%x\n", urbStatus ));
  230. // get the Irp type Read or Write
  231. ASSERT( IRP_MJ_WRITE == pIrpStack->MajorFunction );
  232. switch (irpStatus) {
  233. case STATUS_SUCCESS: {
  234. // ASSERT( USBD_STATUS_SUCCESS == urbStatus );
  235. //
  236. // indicate the number of Tx bytes transferred, as indicated in the Urb
  237. //
  238. PIrp->IoStatus.Information = pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  239. //
  240. // indicate that our Tx buffer is empty, although the data may
  241. // actually still reside on the AN2720 chip.
  242. // There is no way for us to know.
  243. //
  244. InterlockedExchange( &pDevExt->SerialPort.CharsInWriteBuf, 0 );
  245. //
  246. // clear pipe error count
  247. //
  248. InterlockedExchange( &pDevExt->WriteDeviceErrors, 0);
  249. //
  250. // incr ttl byte counter
  251. //
  252. pDevExt->TtlWriteBytes += (ULONG)PIrp->IoStatus.Information;
  253. DbgDump( DBG_WRITE_LENGTH , ("USB Write indication: %d\n", PIrp->IoStatus.Information) );
  254. DbgDumpReadWriteData( PDevObj, PIrp, FALSE);
  255. }
  256. break;
  257. case STATUS_CANCELLED: {
  258. DbgDump(DBG_WRN|DBG_WRITE|DBG_IRP, ("Write: STATUS_CANCELLED\n"));
  259. //
  260. // If it was cancelled, it may have timed out.
  261. // We can tell by looking at the packet attached to it.
  262. //
  263. if ( STATUS_TIMEOUT == PPacket->Status ) {
  264. //
  265. // more than likely the FIFO was stalled (i.e., the other side did not
  266. // read fom the endpoint). Inform user we timed out the R/W request
  267. //
  268. ASSERT( USBD_STATUS_CANCELED == urbStatus);
  269. irpStatus = PIrp->IoStatus.Status = STATUS_TIMEOUT;
  270. DbgDump(DBG_WRN|DBG_WRITE|DBG_IRP, ("Write: STATUS_TIMEOUT\n"));
  271. }
  272. }
  273. break;
  274. case STATUS_DEVICE_DATA_ERROR: {
  275. //
  276. // generic device error set by USBD.
  277. //
  278. DbgDump(DBG_ERR, ("WritePipe STATUS_DEVICE_DATA_ERROR: 0x%x\n", urbStatus));
  279. //
  280. // bump pipe error count
  281. //
  282. InterlockedIncrement( &pDevExt->WriteDeviceErrors);
  283. //
  284. // is the endpoint is stalled?
  285. //
  286. if ( USBD_HALTED(pUrb->UrbHeader.Status) ) {
  287. //
  288. // queue a reset request
  289. //
  290. workStatus = QueueWorkItem( pDevExt->DeviceObject,
  291. UsbResetOrAbortPipeWorkItem,
  292. (PVOID)((LONG_PTR)urbStatus),
  293. WORK_ITEM_RESET_WRITE_PIPE
  294. );
  295. }
  296. }
  297. break;
  298. case STATUS_INVALID_PARAMETER:
  299. //
  300. // This means that our (TransferBufferSize > PipeInfo->MaxTransferSize)
  301. // we need to either break up requests or reject the Irp from the start.
  302. //
  303. DbgDump(DBG_WRN, ("STATUS_INVALID_PARAMETER\n"));
  304. ASSERT(USBD_STATUS_INVALID_PARAMETER == urbStatus);
  305. //
  306. // pass the Irp through for completion
  307. //
  308. break;
  309. default:
  310. DbgDump(DBG_WRN, ("WRITE: Unhandled Irp status: 0x%x\n", irpStatus));
  311. break;
  312. }
  313. //
  314. // Remove the packet from the pending List
  315. //
  316. KeAcquireSpinLock( &pDevExt->ControlLock, &irql );
  317. RemoveEntryList( &PPacket->ListEntry );
  318. curCount = InterlockedDecrement( &pDevExt->PendingWriteCount );
  319. //
  320. // Put the packet back in packet pool.
  321. //
  322. PPacket->Irp = NULL;
  323. ExFreeToNPagedLookasideList( &pDevExt->PacketPool, // Lookaside,
  324. PPacket // Entry
  325. );
  326. ReleaseRemoveLock(&pDevExt->RemoveLock, PIrp);
  327. //
  328. // Complete the IRP
  329. //
  330. TryToCompleteCurrentIrp(
  331. pDevExt,
  332. irpStatus, // ReturnStatus
  333. &PIrp, // Irp
  334. NULL, // Queue
  335. NULL, // IntervalTimer
  336. NULL, // TotalTimer
  337. NULL, // StartNextIrpRoutine
  338. NULL, // GetNextIrpRoutine
  339. IRP_REF_RX_BUFFER, // ReferenceType
  340. FALSE, // CompleteRequest
  341. irql );
  342. //
  343. // Perform any post I/O processing.
  344. //
  345. ASSERT(curCount >= 0);
  346. if ( 0 == curCount ) {
  347. //
  348. // do Tx post processing here...
  349. //
  350. KeAcquireSpinLock( &pDevExt->ControlLock , &irql);
  351. pDevExt->SerialPort.HistoryMask |= SERIAL_EV_TXEMPTY;
  352. KeReleaseSpinLock( &pDevExt->ControlLock, irql);
  353. ProcessSerialWaits( pDevExt );
  354. KeSetEvent( &pDevExt->PendingDataOutEvent, IO_SERIAL_INCREMENT, FALSE);
  355. }
  356. DbgDump(DBG_WRITE, ("<WriteComplete 0x%x\n", irpStatus));
  357. PERF_EXIT( PERF_WriteComplete );
  358. return irpStatus;
  359. }
  360. VOID
  361. WriteTimeout(
  362. IN PKDPC PDpc,
  363. IN PVOID DeferredContext,
  364. IN PVOID SystemContext1,
  365. IN PVOID SystemContext2
  366. )
  367. /*++
  368. Routine Description:
  369. This is the Write Timeout DPC routine that is called when a
  370. Timer expires on a packet submitted to USBD.
  371. Runs at DPC_LEVEL.
  372. Arguments:
  373. PDpc - Unused
  374. DeferredContext - pointer to the Packet
  375. SystemContext1 - Unused
  376. SystemContext2 - Unused
  377. Return Value:
  378. VOID
  379. --*/
  380. {
  381. PUSB_PACKET pPacket = (PUSB_PACKET)DeferredContext;
  382. PDEVICE_EXTENSION pDevExt = pPacket->DeviceExtension;
  383. PDEVICE_OBJECT pDevObj = pDevExt->DeviceObject;
  384. NTSTATUS status = STATUS_TIMEOUT;
  385. KIRQL irql;
  386. PERF_ENTRY( PERF_WriteTimeout );
  387. UNREFERENCED_PARAMETER(PDpc);
  388. UNREFERENCED_PARAMETER(SystemContext1);
  389. UNREFERENCED_PARAMETER(SystemContext2);
  390. DbgDump(DBG_WRITE|DBG_TIME, (">WriteTimeout\n"));
  391. if (pPacket && pDevExt && pDevObj) {
  392. //
  393. // sync with completion routine putting packet back on list
  394. //
  395. KeAcquireSpinLock( &pDevExt->ControlLock, &irql );
  396. if ( !pPacket || !pPacket->Irp ||
  397. (STATUS_ALERTED == pPacket->Status) ) {
  398. status = STATUS_ALERTED;
  399. KeReleaseSpinLock( &pDevExt->ControlLock, irql );
  400. DbgDump(DBG_WRITE, ("WriteTimeout: Irp completed\n" ));
  401. PERF_EXIT( PERF_WriteTimeout );
  402. return;
  403. } else {
  404. //
  405. // mark the packet as timed out, so we can propogate this to user
  406. // from completion routine
  407. //
  408. pPacket->Status = STATUS_TIMEOUT;
  409. KeReleaseSpinLock( &pDevExt->ControlLock, irql );
  410. //
  411. // Cancel the Irp.
  412. //
  413. if ( !IoCancelIrp(pPacket->Irp) ) {
  414. //
  415. // The Irp is not in a cancelable state.
  416. //
  417. DbgDump(DBG_WRITE|DBG_TIME, ("Warning: couldn't cancel Irp: %p,\n", pPacket->Irp));
  418. }
  419. }
  420. } else {
  421. status = STATUS_INVALID_PARAMETER;
  422. DbgDump(DBG_ERR, ("WriteTimeout: 0x%x\n", status ));
  423. TEST_TRAP();
  424. }
  425. DbgDump(DBG_WRITE|DBG_TIME, ("<WriteTimeout 0x%x\n", status));
  426. PERF_EXIT( PERF_WriteTimeout );
  427. return;
  428. }
  429. #if DBG
  430. VOID
  431. DbgDumpReadWriteData(
  432. IN PDEVICE_OBJECT PDevObj,
  433. IN PIRP PIrp,
  434. IN BOOLEAN Read
  435. )
  436. {
  437. PIO_STACK_LOCATION pIrpSp;
  438. ASSERT(PDevObj);
  439. ASSERT(PIrp);
  440. pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  441. if ( (Read && (DebugLevel & DBG_DUMP_READS)) ||
  442. (!Read && (DebugLevel & DBG_DUMP_WRITES)) ) {
  443. ULONG i;
  444. ULONG count=0;
  445. NTSTATUS status;
  446. status = PIrp->IoStatus.Status;
  447. if (STATUS_SUCCESS == status) {
  448. count = (ULONG)PIrp->IoStatus.Information;
  449. }
  450. KdPrint( ("WCEUSBSH: %s: for DevObj(%p) Irp(0x%x) Length(0x%x) status(0x%x)\n",
  451. Read ? "ReadData" : "WriteData", PDevObj, PIrp, count, status ));
  452. for (i = 0; i < count; i++) {
  453. KdPrint(("%02x ", *(((PUCHAR)PIrp->AssociatedIrp.SystemBuffer) + i) & 0xFF));
  454. }
  455. KdPrint(("\n"));
  456. }
  457. return;
  458. }
  459. #endif
  460. // EOF