618 lines
15 KiB
C
618 lines
15 KiB
C
|
/* ++
|
|||
|
|
|||
|
Copyright (c) 1999-2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
write.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Write functions
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
kernel mode only
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
07-14-99 : created
|
|||
|
|
|||
|
Authors:
|
|||
|
|
|||
|
Jeff Midkiff (jeffmi)
|
|||
|
|
|||
|
-- */
|
|||
|
|
|||
|
#include <wdm.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <usbdi.h>
|
|||
|
#include <usbdlib.h>
|
|||
|
#include <ntddser.h>
|
|||
|
|
|||
|
#include "wceusbsh.h"
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
WriteComplete(
|
|||
|
IN PDEVICE_OBJECT PDevObj,
|
|||
|
IN PIRP PIrp,
|
|||
|
IN PUSB_PACKET PPacket
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
WriteTimeout(
|
|||
|
IN PKDPC PDpc,
|
|||
|
IN PVOID DeferredContext,
|
|||
|
IN PVOID SystemContext1,
|
|||
|
IN PVOID SystemContext2
|
|||
|
);
|
|||
|
|
|||
|
#if DBG
|
|||
|
VOID
|
|||
|
DbgDumpReadWriteData(
|
|||
|
IN PDEVICE_OBJECT PDevObj,
|
|||
|
IN PIRP PIrp,
|
|||
|
IN BOOLEAN Read
|
|||
|
);
|
|||
|
#else
|
|||
|
#define DbgDumpReadWriteData( _devobj, _irp, _read )
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
Write(
|
|||
|
IN PDEVICE_OBJECT PDevObj,
|
|||
|
PIRP PIrp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Process the IRPs sent to this device for writing.
|
|||
|
IRP_MJ_WRITE
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PDevObj - Pointer to the device object for the device written to
|
|||
|
PIrp - Pointer to the write IRP.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
The AN2720 is a low-quality FIFO device and will NAK all packets when it's
|
|||
|
FIFO gets full. We can't get real device status, like serial port registers.
|
|||
|
If we submit a USBDI 'GetEndpointStatus', then all we get back is a stall bit.
|
|||
|
PROBLEM: what to do when it's FIFO get's full, i.e., how to handle flow control?
|
|||
|
If the peer/client on the other side of the FIFO is not reading packets out of the FIFO,
|
|||
|
then AN2720 NAKS every packet thereafter, until the FIFO gets drained (or, at least 1 packet
|
|||
|
removed).
|
|||
|
|
|||
|
Here's what we currently do: on every _USB_PACKET we submit, set a timeout.
|
|||
|
When the timer expires we check if our R/W completion routine has already cancelled that
|
|||
|
packet's timer. If our completion did cancel the timer, then we are done.
|
|||
|
If not, then we timed out on this packet. We do not reset the endpoint on a timeout
|
|||
|
since the FIFO's contents will be lost. We simply complete the Irp to
|
|||
|
user with STATUS_TIMEOUT. User should then go into whatever retry logic they require.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)PDevObj->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
|
|||
|
|
|||
|
KIRQL irql;
|
|||
|
LARGE_INTEGER timeOut = {0,0};
|
|||
|
ULONG ulTransferLength;
|
|||
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|||
|
BOOLEAN bCompleteIrp = FALSE;
|
|||
|
|
|||
|
PERF_ENTRY( PERF_Write );
|
|||
|
|
|||
|
DbgDump(DBG_WRITE|DBG_TRACE, (">Write(%p, %p, %x)\n", PDevObj, PIrp, Read));
|
|||
|
|
|||
|
PIrp->IoStatus.Information = 0L;
|
|||
|
|
|||
|
//
|
|||
|
// Make sure the device is accepting request
|
|||
|
//
|
|||
|
if ( !CanAcceptIoRequests( PDevObj, TRUE, TRUE) ||
|
|||
|
!NT_SUCCESS(AcquireRemoveLock(&pDevExt->RemoveLock, PIrp)) )
|
|||
|
{
|
|||
|
status = PIrp->IoStatus.Status = STATUS_DELETE_PENDING;
|
|||
|
DbgDump(DBG_ERR, ("Write ERROR: 0x%x\n", status));
|
|||
|
PIrp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest(PIrp, IO_NO_INCREMENT);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check write length.
|
|||
|
// Allow zero length writes for apps to send a NULL packet
|
|||
|
// to signal end of transaction.
|
|||
|
//
|
|||
|
ulTransferLength = pIrpSp->Parameters.Write.Length;
|
|||
|
|
|||
|
if ( ulTransferLength > pDevExt->MaximumTransferSize ) {
|
|||
|
|
|||
|
DbgDump(DBG_ERR, ("Write Buffer too large: %d\n", ulTransferLength ));
|
|||
|
|
|||
|
status = PIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|||
|
|
|||
|
bCompleteIrp = TRUE;
|
|||
|
|
|||
|
goto WriteExit;
|
|||
|
}
|
|||
|
|
|||
|
DbgDump(DBG_WRITE_LENGTH, ("User Write request length: %d\n", ulTransferLength ));
|
|||
|
|
|||
|
//
|
|||
|
// calculate Serial TimeOut values
|
|||
|
//
|
|||
|
ASSERT_SERIAL_PORT(pDevExt->SerialPort);
|
|||
|
|
|||
|
CalculateTimeout( &timeOut,
|
|||
|
pIrpSp->Parameters.Write.Length,
|
|||
|
pDevExt->SerialPort.Timeouts.WriteTotalTimeoutMultiplier,
|
|||
|
pDevExt->SerialPort.Timeouts.WriteTotalTimeoutConstant );
|
|||
|
|
|||
|
DbgDump(DBG_TIME, ("CalculateWriteTimeOut = %d msec\n", timeOut.QuadPart ));
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
//
|
|||
|
// check if this Irp should be cancelled.
|
|||
|
// Note that we don't queue write Irps.
|
|||
|
//
|
|||
|
IoAcquireCancelSpinLock(&irql);
|
|||
|
|
|||
|
if (PIrp->Cancel) {
|
|||
|
|
|||
|
TEST_TRAP();
|
|||
|
IoReleaseCancelSpinLock(irql);
|
|||
|
status = PIrp->IoStatus.Status = STATUS_CANCELLED;
|
|||
|
// since we don't set a completion routine we complete it here
|
|||
|
bCompleteIrp = TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// prepare to submit the IRP to the USB stack.
|
|||
|
//
|
|||
|
IoSetCancelRoutine(PIrp, NULL);
|
|||
|
IoReleaseCancelSpinLock(irql);
|
|||
|
|
|||
|
KeAcquireSpinLock( &pDevExt->ControlLock, &irql);
|
|||
|
|
|||
|
IRP_INIT_REFERENCE(PIrp);
|
|||
|
|
|||
|
// set current number of chars in the Tx buffer
|
|||
|
InterlockedExchange( &pDevExt->SerialPort.CharsInWriteBuf, ulTransferLength );
|
|||
|
|
|||
|
KeClearEvent( &pDevExt->PendingDataOutEvent );
|
|||
|
|
|||
|
//
|
|||
|
// bump ttl request count
|
|||
|
//
|
|||
|
pDevExt->TtlWriteRequests++;
|
|||
|
|
|||
|
KeReleaseSpinLock( &pDevExt->ControlLock, irql);
|
|||
|
|
|||
|
status = UsbReadWritePacket( pDevExt,
|
|||
|
PIrp,
|
|||
|
WriteComplete,
|
|||
|
timeOut,
|
|||
|
WriteTimeout,
|
|||
|
FALSE );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
WriteExit:
|
|||
|
|
|||
|
if (bCompleteIrp)
|
|||
|
{
|
|||
|
ReleaseRemoveLock(&pDevExt->RemoveLock, PIrp);
|
|||
|
|
|||
|
IoCompleteRequest (PIrp, IO_SERIAL_INCREMENT );
|
|||
|
}
|
|||
|
|
|||
|
DbgDump(DBG_WRITE|DBG_TRACE, ("<Write 0x%x\n", status));
|
|||
|
|
|||
|
PERF_EXIT( PERF_Write );
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
WriteComplete(
|
|||
|
IN PDEVICE_OBJECT PDevObj,
|
|||
|
IN PIRP PIrp,
|
|||
|
IN PUSB_PACKET PPacket
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the completion routine for Write requests.
|
|||
|
It assumes you have the serial port context.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PDevObj - Pointer to device object
|
|||
|
PIrp - Irp we are completing
|
|||
|
PPacket - USB Packet which will be freed
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS -- propogate Irp's status.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
This routine runs at DPC_LEVEL.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION pDevExt = PPacket->DeviceExtension;
|
|||
|
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
|
|||
|
PURB pUrb = &PPacket->Urb;
|
|||
|
NTSTATUS irpStatus, workStatus;
|
|||
|
USBD_STATUS urbStatus;
|
|||
|
KIRQL irql;
|
|||
|
LONG curCount;
|
|||
|
|
|||
|
PERF_ENTRY( PERF_WriteComplete );
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( PDevObj );
|
|||
|
|
|||
|
DbgDump(DBG_WRITE, (">WriteComplete(%p, %p, %p)\n", PDevObj, PIrp, PPacket));
|
|||
|
|
|||
|
// Note: we don't hold the control lock so this could
|
|||
|
// disappear on us.
|
|||
|
ASSERT_SERIAL_PORT(pDevExt->SerialPort);
|
|||
|
|
|||
|
//
|
|||
|
// First off, cancel the Packet Timer
|
|||
|
//
|
|||
|
if ( PPacket->Timeout.QuadPart != 0 ) {
|
|||
|
|
|||
|
if (KeCancelTimer( &PPacket->TimerObj ) ) {
|
|||
|
//
|
|||
|
// the packet's timer was successfully removed from the system
|
|||
|
//
|
|||
|
} else {
|
|||
|
//
|
|||
|
// the timer could be spinning on the control lock,
|
|||
|
// so tell it we took the Irp.
|
|||
|
//
|
|||
|
PPacket->Status = STATUS_ALERTED;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now we can process the Irp.
|
|||
|
// If the lower driver returned PENDING,
|
|||
|
// then mark our stack location as pending.
|
|||
|
//
|
|||
|
if ( PIrp->PendingReturned ) {
|
|||
|
DbgDump(DBG_WRITE, ("Resetting Irp STATUS_PENDING\n"));
|
|||
|
IoMarkIrpPending(PIrp);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This is the R/W operation's return status.
|
|||
|
// irpStatus is the Irp's completion status
|
|||
|
// ubrStatus is a more USBD specific Urb operation completion status
|
|||
|
//
|
|||
|
irpStatus = PIrp->IoStatus.Status;
|
|||
|
DbgDump(DBG_WRITE, ("Irp->IoStatus.Status 0x%x\n", irpStatus));
|
|||
|
|
|||
|
urbStatus = pUrb->UrbHeader.Status;
|
|||
|
DbgDump(DBG_WRITE, ("Urb->UrbHeader.Status 0x%x\n", urbStatus ));
|
|||
|
|
|||
|
// get the Irp type Read or Write
|
|||
|
ASSERT( IRP_MJ_WRITE == pIrpStack->MajorFunction );
|
|||
|
|
|||
|
switch (irpStatus) {
|
|||
|
|
|||
|
case STATUS_SUCCESS: {
|
|||
|
// ASSERT( USBD_STATUS_SUCCESS == urbStatus );
|
|||
|
|
|||
|
//
|
|||
|
// indicate the number of Tx bytes transferred, as indicated in the Urb
|
|||
|
//
|
|||
|
PIrp->IoStatus.Information = pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
|
|||
|
|
|||
|
//
|
|||
|
// indicate that our Tx buffer is empty, although the data may
|
|||
|
// actually still reside on the AN2720 chip.
|
|||
|
// There is no way for us to know.
|
|||
|
//
|
|||
|
InterlockedExchange( &pDevExt->SerialPort.CharsInWriteBuf, 0 );
|
|||
|
|
|||
|
//
|
|||
|
// clear pipe error count
|
|||
|
//
|
|||
|
InterlockedExchange( &pDevExt->WriteDeviceErrors, 0);
|
|||
|
|
|||
|
//
|
|||
|
// incr ttl byte counter
|
|||
|
//
|
|||
|
pDevExt->TtlWriteBytes += (ULONG)PIrp->IoStatus.Information;
|
|||
|
|
|||
|
DbgDump( DBG_WRITE_LENGTH , ("USB Write indication: %d\n", PIrp->IoStatus.Information) );
|
|||
|
|
|||
|
DbgDumpReadWriteData( PDevObj, PIrp, FALSE);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case STATUS_CANCELLED: {
|
|||
|
|
|||
|
DbgDump(DBG_WRN|DBG_WRITE|DBG_IRP, ("Write: STATUS_CANCELLED\n"));
|
|||
|
//
|
|||
|
// If it was cancelled, it may have timed out.
|
|||
|
// We can tell by looking at the packet attached to it.
|
|||
|
//
|
|||
|
if ( STATUS_TIMEOUT == PPacket->Status ) {
|
|||
|
//
|
|||
|
// more than likely the FIFO was stalled (i.e., the other side did not
|
|||
|
// read fom the endpoint). Inform user we timed out the R/W request
|
|||
|
//
|
|||
|
ASSERT( USBD_STATUS_CANCELED == urbStatus);
|
|||
|
irpStatus = PIrp->IoStatus.Status = STATUS_TIMEOUT;
|
|||
|
DbgDump(DBG_WRN|DBG_WRITE|DBG_IRP, ("Write: STATUS_TIMEOUT\n"));
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case STATUS_DEVICE_DATA_ERROR: {
|
|||
|
//
|
|||
|
// generic device error set by USBD.
|
|||
|
//
|
|||
|
DbgDump(DBG_ERR, ("WritePipe STATUS_DEVICE_DATA_ERROR: 0x%x\n", urbStatus));
|
|||
|
|
|||
|
//
|
|||
|
// bump pipe error count
|
|||
|
//
|
|||
|
InterlockedIncrement( &pDevExt->WriteDeviceErrors);
|
|||
|
|
|||
|
//
|
|||
|
// is the endpoint is stalled?
|
|||
|
//
|
|||
|
if ( USBD_HALTED(pUrb->UrbHeader.Status) ) {
|
|||
|
//
|
|||
|
// queue a reset request
|
|||
|
//
|
|||
|
workStatus = QueueWorkItem( pDevExt->DeviceObject,
|
|||
|
UsbResetOrAbortPipeWorkItem,
|
|||
|
(PVOID)((LONG_PTR)urbStatus),
|
|||
|
WORK_ITEM_RESET_WRITE_PIPE
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case STATUS_INVALID_PARAMETER:
|
|||
|
//
|
|||
|
// This means that our (TransferBufferSize > PipeInfo->MaxTransferSize)
|
|||
|
// we need to either break up requests or reject the Irp from the start.
|
|||
|
//
|
|||
|
DbgDump(DBG_WRN, ("STATUS_INVALID_PARAMETER\n"));
|
|||
|
ASSERT(USBD_STATUS_INVALID_PARAMETER == urbStatus);
|
|||
|
|
|||
|
//
|
|||
|
// pass the Irp through for completion
|
|||
|
//
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
DbgDump(DBG_WRN, ("WRITE: Unhandled Irp status: 0x%x\n", irpStatus));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove the packet from the pending List
|
|||
|
//
|
|||
|
KeAcquireSpinLock( &pDevExt->ControlLock, &irql );
|
|||
|
|
|||
|
RemoveEntryList( &PPacket->ListEntry );
|
|||
|
|
|||
|
curCount = InterlockedDecrement( &pDevExt->PendingWriteCount );
|
|||
|
|
|||
|
//
|
|||
|
// Put the packet back in packet pool.
|
|||
|
//
|
|||
|
PPacket->Irp = NULL;
|
|||
|
|
|||
|
ExFreeToNPagedLookasideList( &pDevExt->PacketPool, // Lookaside,
|
|||
|
PPacket // Entry
|
|||
|
);
|
|||
|
|
|||
|
ReleaseRemoveLock(&pDevExt->RemoveLock, PIrp);
|
|||
|
|
|||
|
//
|
|||
|
// Complete the IRP
|
|||
|
//
|
|||
|
TryToCompleteCurrentIrp(
|
|||
|
pDevExt,
|
|||
|
irpStatus, // ReturnStatus
|
|||
|
&PIrp, // Irp
|
|||
|
NULL, // Queue
|
|||
|
NULL, // IntervalTimer
|
|||
|
NULL, // TotalTimer
|
|||
|
NULL, // StartNextIrpRoutine
|
|||
|
NULL, // GetNextIrpRoutine
|
|||
|
IRP_REF_RX_BUFFER, // ReferenceType
|
|||
|
FALSE, // CompleteRequest
|
|||
|
irql );
|
|||
|
|
|||
|
//
|
|||
|
// Perform any post I/O processing.
|
|||
|
//
|
|||
|
ASSERT(curCount >= 0);
|
|||
|
|
|||
|
if ( 0 == curCount ) {
|
|||
|
//
|
|||
|
// do Tx post processing here...
|
|||
|
//
|
|||
|
KeAcquireSpinLock( &pDevExt->ControlLock , &irql);
|
|||
|
pDevExt->SerialPort.HistoryMask |= SERIAL_EV_TXEMPTY;
|
|||
|
KeReleaseSpinLock( &pDevExt->ControlLock, irql);
|
|||
|
|
|||
|
ProcessSerialWaits( pDevExt );
|
|||
|
|
|||
|
KeSetEvent( &pDevExt->PendingDataOutEvent, IO_SERIAL_INCREMENT, FALSE);
|
|||
|
}
|
|||
|
|
|||
|
DbgDump(DBG_WRITE, ("<WriteComplete 0x%x\n", irpStatus));
|
|||
|
|
|||
|
PERF_EXIT( PERF_WriteComplete );
|
|||
|
|
|||
|
return irpStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
WriteTimeout(
|
|||
|
IN PKDPC PDpc,
|
|||
|
IN PVOID DeferredContext,
|
|||
|
IN PVOID SystemContext1,
|
|||
|
IN PVOID SystemContext2
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the Write Timeout DPC routine that is called when a
|
|||
|
Timer expires on a packet submitted to USBD.
|
|||
|
Runs at DPC_LEVEL.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PDpc - Unused
|
|||
|
DeferredContext - pointer to the Packet
|
|||
|
SystemContext1 - Unused
|
|||
|
SystemContext2 - Unused
|
|||
|
|
|||
|
Return Value:
|
|||
|
VOID
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PUSB_PACKET pPacket = (PUSB_PACKET)DeferredContext;
|
|||
|
PDEVICE_EXTENSION pDevExt = pPacket->DeviceExtension;
|
|||
|
PDEVICE_OBJECT pDevObj = pDevExt->DeviceObject;
|
|||
|
|
|||
|
NTSTATUS status = STATUS_TIMEOUT;
|
|||
|
KIRQL irql;
|
|||
|
|
|||
|
PERF_ENTRY( PERF_WriteTimeout );
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(PDpc);
|
|||
|
UNREFERENCED_PARAMETER(SystemContext1);
|
|||
|
UNREFERENCED_PARAMETER(SystemContext2);
|
|||
|
|
|||
|
DbgDump(DBG_WRITE|DBG_TIME, (">WriteTimeout\n"));
|
|||
|
|
|||
|
if (pPacket && pDevExt && pDevObj) {
|
|||
|
//
|
|||
|
// sync with completion routine putting packet back on list
|
|||
|
//
|
|||
|
KeAcquireSpinLock( &pDevExt->ControlLock, &irql );
|
|||
|
|
|||
|
if ( !pPacket || !pPacket->Irp ||
|
|||
|
(STATUS_ALERTED == pPacket->Status) ) {
|
|||
|
|
|||
|
status = STATUS_ALERTED;
|
|||
|
|
|||
|
KeReleaseSpinLock( &pDevExt->ControlLock, irql );
|
|||
|
|
|||
|
DbgDump(DBG_WRITE, ("WriteTimeout: Irp completed\n" ));
|
|||
|
PERF_EXIT( PERF_WriteTimeout );
|
|||
|
return;
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// mark the packet as timed out, so we can propogate this to user
|
|||
|
// from completion routine
|
|||
|
//
|
|||
|
pPacket->Status = STATUS_TIMEOUT;
|
|||
|
|
|||
|
KeReleaseSpinLock( &pDevExt->ControlLock, irql );
|
|||
|
|
|||
|
//
|
|||
|
// Cancel the Irp.
|
|||
|
//
|
|||
|
if ( !IoCancelIrp(pPacket->Irp) ) {
|
|||
|
//
|
|||
|
// The Irp is not in a cancelable state.
|
|||
|
//
|
|||
|
DbgDump(DBG_WRITE|DBG_TIME, ("Warning: couldn't cancel Irp: %p,\n", pPacket->Irp));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
DbgDump(DBG_ERR, ("WriteTimeout: 0x%x\n", status ));
|
|||
|
TEST_TRAP();
|
|||
|
}
|
|||
|
|
|||
|
DbgDump(DBG_WRITE|DBG_TIME, ("<WriteTimeout 0x%x\n", status));
|
|||
|
|
|||
|
PERF_EXIT( PERF_WriteTimeout );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#if DBG
|
|||
|
VOID
|
|||
|
DbgDumpReadWriteData(
|
|||
|
IN PDEVICE_OBJECT PDevObj,
|
|||
|
IN PIRP PIrp,
|
|||
|
IN BOOLEAN Read
|
|||
|
)
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION pIrpSp;
|
|||
|
|
|||
|
ASSERT(PDevObj);
|
|||
|
ASSERT(PIrp);
|
|||
|
|
|||
|
pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
|
|||
|
|
|||
|
if ( (Read && (DebugLevel & DBG_DUMP_READS)) ||
|
|||
|
(!Read && (DebugLevel & DBG_DUMP_WRITES)) ) {
|
|||
|
|
|||
|
ULONG i;
|
|||
|
ULONG count=0;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
status = PIrp->IoStatus.Status;
|
|||
|
|
|||
|
if (STATUS_SUCCESS == status) {
|
|||
|
count = (ULONG)PIrp->IoStatus.Information;
|
|||
|
}
|
|||
|
|
|||
|
KdPrint( ("WCEUSBSH: %s: for DevObj(%p) Irp(0x%x) Length(0x%x) status(0x%x)\n",
|
|||
|
Read ? "ReadData" : "WriteData", PDevObj, PIrp, count, status ));
|
|||
|
|
|||
|
for (i = 0; i < count; i++) {
|
|||
|
KdPrint(("%02x ", *(((PUCHAR)PIrp->AssociatedIrp.SystemBuffer) + i) & 0xFF));
|
|||
|
}
|
|||
|
|
|||
|
KdPrint(("\n"));
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
// EOF
|