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.
 
 
 
 
 
 

706 lines
19 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
ocrw.c
Abstract:
read/write io code for printing
Environment:
kernel mode only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
Revision History:
5-4-96 : created
--*/
#define DRIVER
#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"
#include <usb.h>
#include <usbdrivr.h>
#include "usbdlib.h"
#include "usbprint.h"
//******************************************************************************
//
// USBPRINT_CompletionStop()
//
// IO Completion Routine which just stops further completion of the Irp
//
//******************************************************************************
NTSTATUS
USBPRINT_CompletionStop (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
return STATUS_MORE_PROCESSING_REQUIRED;
}
PURB
USBPRINT_BuildAsyncRequest(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PUSBD_PIPE_INFORMATION PipeHandle,
IN BOOLEAN Read
)
/*++
Routine Description:
Arguments:
DeviceObject - pointer to the device extension for this instance of the
printer
Irp -
PipeHandle -
Return Value:
initialized async urb.
--*/
{
ULONG siz;
ULONG length;
PURB urb = NULL;
USBPRINT_KdPrint3 (("USBPRINT.SYS: handle = 0x%x\n", PipeHandle));
if ( Irp->MdlAddress == NULL )
return NULL;
length = MmGetMdlByteCount(Irp->MdlAddress);
USBPRINT_KdPrint3 (("USBPRINT.SYS: length = 0x%x\n", length));
siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
urb = ExAllocatePoolWithTag(NonPagedPool, siz, USBP_TAG);
USBPRINT_KdPrint3 (("USBPRINT.SYS: siz = 0x%x urb 0x%x\n", siz, urb));
if (urb) {
RtlZeroMemory(urb, siz);
urb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT) siz;
urb->UrbBulkOrInterruptTransfer.Hdr.Function =
URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
urb->UrbBulkOrInterruptTransfer.PipeHandle =
PipeHandle->PipeHandle;
urb->UrbBulkOrInterruptTransfer.TransferFlags =
Read ? USBD_TRANSFER_DIRECTION_IN : 0;
// short packet is not treated as an error.
urb->UrbBulkOrInterruptTransfer.TransferFlags |=
USBD_SHORT_TRANSFER_OK;
//
// no linkage for now
//
urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
urb->UrbBulkOrInterruptTransfer.TransferBufferMDL =
Irp->MdlAddress;
urb->UrbBulkOrInterruptTransfer.TransferBufferLength =
length;
USBPRINT_KdPrint3 (("USBPRINT.SYS: Init async urb Length = 0x%x buf = 0x%x, mdlBuff=0x%x\n",
urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
urb->UrbBulkOrInterruptTransfer.TransferBuffer,
urb->UrbBulkOrInterruptTransfer.TransferBufferMDL));
}
USBPRINT_KdPrint3 (("USBPRINT.SYS: exit USBPRINT_BuildAsyncRequest\n"));
return urb;
}
NTSTATUS
USBPRINT_AsyncReadWrite_Complete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
Arguments:
DeviceObject - Pointer to the device object for the USBPRINT device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb;
PUSBPRINT_RW_CONTEXT context = Context;
PDEVICE_OBJECT deviceObject;
PDEVICE_EXTENSION deviceExtension;
PUSBPRINT_WORKITEM_CONTEXT pResetWorkItemObj;
LONG ResetPending;
//Always mark irp pending in dispatch routine now
// if (Irp->PendingReturned) {
// IoMarkIrpPending(Irp);
// }
urb = context->Urb;
deviceObject = context->DeviceObject;
deviceExtension=deviceObject->DeviceExtension;
USBPRINT_KdPrint2 (("USBPRINT.SYS: Async Completion: Length %d, Status 0x%08X\n",
urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
urb->UrbHeader.Status));
//ASSERT(urb->UrbHeader.Status==0);
ntStatus=urb->UrbHeader.Status;
//
// set the length based on the TransferBufferLength
// value in the URB
//
Irp->IoStatus.Information =
urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
if((!NT_SUCCESS(ntStatus))&&(ntStatus!=STATUS_CANCELLED)&&(ntStatus!=STATUS_DEVICE_NOT_CONNECTED)&&(ntStatus!=STATUS_DELETE_PENDING))
{ //We've got an error, and it's not "not connected" or "cancelled", we need to reset the connection
ResetPending=InterlockedCompareExchange(&deviceExtension->ResetWorkItemPending,
1,
0); //Check to see if ResetWorkItem is 0, if so, set it to 1, and start a Reset
if(!ResetPending)
{
pResetWorkItemObj=ExAllocatePoolWithTag(NonPagedPool,sizeof(USBPRINT_WORKITEM_CONTEXT),USBP_TAG);
if(pResetWorkItemObj)
{
pResetWorkItemObj->ioWorkItem=IoAllocateWorkItem(DeviceObject);
if(pResetWorkItemObj==NULL)
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: Unable to allocate IoAllocateWorkItem in ReadWrite_Complete\n"));
ExFreePool(pResetWorkItemObj);
pResetWorkItemObj=NULL;
}
} //if ALloc RestWorkItem OK
else
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: Unable to allocate WorkItemObj in ReadWrite_Complete\n"));
}
if(pResetWorkItemObj)
{
pResetWorkItemObj->irp=Irp;
pResetWorkItemObj->deviceObject=DeviceObject;
if(context->IsWrite)
pResetWorkItemObj->pPipeInfo=deviceExtension->pWritePipe;
else
pResetWorkItemObj->pPipeInfo=deviceExtension->pReadPipe;
USBPRINT_IncrementIoCount(deviceObject);
IoQueueWorkItem(pResetWorkItemObj->ioWorkItem,
USBPRINT_ResetWorkItem,
DelayedWorkQueue,
pResetWorkItemObj);
ntStatus=STATUS_MORE_PROCESSING_REQUIRED;
//Leave the IRP pending until the reset is complete. This way we won't get flooded with irp's we're not
//prepaired to deal with. The Reset WorkItem completes the IRP when it's done.
} //end if the allocs went OK
} //end if ! Reset Pending
} //end if we need to reset
USBPRINT_DecrementIoCount(deviceObject); //still +1 on the IO count after this, leaving one for the workitem to decrement
ExFreePool(context);
ExFreePool(urb);
return ntStatus;
}
NTSTATUS USBPRINT_ResetWorkItem(IN PDEVICE_OBJECT deviceObject, IN PVOID Context)
{
PUSBPRINT_WORKITEM_CONTEXT pResetWorkItemObj;
PDEVICE_EXTENSION DeviceExtension;
NTSTATUS ntStatus;
ULONG portStatus;
PDEVICE_OBJECT devObj;
USBPRINT_KdPrint2(("USBPRINT.SYS: Entering USBPRINT_ResetWorkItem\n"));
pResetWorkItemObj=(PUSBPRINT_WORKITEM_CONTEXT)Context;
DeviceExtension=pResetWorkItemObj->deviceObject->DeviceExtension;
ntStatus=USBPRINT_ResetPipe(pResetWorkItemObj->deviceObject,pResetWorkItemObj->pPipeInfo,FALSE);
IoCompleteRequest(pResetWorkItemObj->irp,IO_NO_INCREMENT);
IoFreeWorkItem(pResetWorkItemObj->ioWorkItem);
// save off work item device object before freeing work item
devObj = pResetWorkItemObj->deviceObject;
ExFreePool(pResetWorkItemObj);
InterlockedExchange(&(DeviceExtension->ResetWorkItemPending),0);
USBPRINT_DecrementIoCount(devObj);
return ntStatus;
}
NTSTATUS
USBPRINT_Read(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
DeviceObject - pointer to the device object for this instance of a printer.
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
PFILE_OBJECT fileObject;
PIO_STACK_LOCATION irpStack, nextStack;
PDEVICE_EXTENSION deviceExtension;
PURB urb;
PUSBPRINT_RW_CONTEXT context = NULL;
USBPRINT_KdPrint3 (("USBPRINT.SYS: /*dd enter USBPRINT_Read\n\n\n\n\n\n"));
USBPRINT_KdPrint3 (("USBPRINT.SYS: /*dd **************************************************************************\n"));
USBPRINT_IncrementIoCount(DeviceObject);
deviceExtension = DeviceObject->DeviceExtension;
if (deviceExtension->IsChildDevice == TRUE)
{
ntStatus = STATUS_NOT_SUPPORTED;
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
USBPRINT_DecrementIoCount(DeviceObject);
return ntStatus;
}
if (deviceExtension->AcceptingRequests == FALSE)
{
ntStatus = STATUS_DELETE_PENDING;
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
USBPRINT_DecrementIoCount(DeviceObject);
return ntStatus;
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
fileObject = irpStack->FileObject;
pipeHandle = deviceExtension->pReadPipe;
if (!pipeHandle) {
ntStatus = STATUS_INVALID_HANDLE;
goto USBPRINT_Read_Reject;
}
//
// submit the Read request to USB
//
switch (pipeHandle->PipeType) {
case UsbdPipeTypeInterrupt:
case UsbdPipeTypeBulk:
urb = USBPRINT_BuildAsyncRequest(DeviceObject,
Irp,
pipeHandle,
TRUE);
if (urb) {
context = ExAllocatePoolWithTag(NonPagedPool, sizeof(USBPRINT_RW_CONTEXT), USBP_TAG);
if ( !context )
ExFreePool(urb);
}
if (urb && context) {
context->Urb = urb;
context->DeviceObject = DeviceObject;
context->IsWrite=FALSE;
nextStack = IoGetNextIrpStackLocation(Irp);
ASSERT(nextStack != NULL);
ASSERT(DeviceObject->StackSize>1);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(Irp,
USBPRINT_AsyncReadWrite_Complete,
context,
TRUE,
TRUE,
TRUE);
USBPRINT_KdPrint3 (("USBPRINT.SYS: IRP = 0x%x current = 0x%x next = 0x%x\n",
Irp, irpStack, nextStack));
// start perf timer here if needed
IoMarkIrpPending(Irp);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
ntStatus=STATUS_PENDING;
goto USBPRINT_Read_Done;
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
break;
default:
ntStatus = STATUS_INVALID_PARAMETER;
TRAP();
}
USBPRINT_Read_Reject:
USBPRINT_DecrementIoCount(DeviceObject);
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
USBPRINT_Read_Done:
return ntStatus;
}
NTSTATUS
USBPRINT_Write(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This function services WRITE requests for this device (probably from the user mode USB port monitor)
Arguments:
DeviceObject - pointer to the device object for this printer
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
PFILE_OBJECT fileObject;
PIO_STACK_LOCATION irpStack, nextStack;
PDEVICE_EXTENSION deviceExtension;
PURB urb;
PUSBPRINT_RW_CONTEXT context = NULL;
USBPRINT_KdPrint2 (("USBPRINT.SYS: enter USBPRINT_Write (foo)\n"));
USBPRINT_IncrementIoCount(DeviceObject);
deviceExtension = DeviceObject->DeviceExtension;
if (deviceExtension->IsChildDevice == TRUE)
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: failure because bChildDevice=TRUE\n"));
ntStatus = STATUS_NOT_SUPPORTED;
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
USBPRINT_DecrementIoCount(DeviceObject);
IoCompleteRequest (Irp,IO_NO_INCREMENT);
return ntStatus;
}
if (deviceExtension->AcceptingRequests == FALSE)
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: failure because AcceptingRequests=FALSE\n"));
ntStatus = STATUS_DELETE_PENDING;
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
USBPRINT_DecrementIoCount(DeviceObject);
IoCompleteRequest (Irp,IO_NO_INCREMENT);
return ntStatus;
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
fileObject = irpStack->FileObject;
// MmProbeAndLockPages(Irp->MdlAddress,
// KernelMode,
// IoReadAccess);
pipeHandle = deviceExtension->pWritePipe;
if (!pipeHandle)
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: failure because pipe is bad\n"));
ntStatus = STATUS_INVALID_HANDLE;
goto USBPRINT_Write_Reject;
}
//
// submit the write request to USB
//
switch (pipeHandle->PipeType)
{
case UsbdPipeTypeInterrupt:
case UsbdPipeTypeBulk:
urb = USBPRINT_BuildAsyncRequest(DeviceObject,
Irp,
pipeHandle,
FALSE);
if (urb)
{
context = ExAllocatePoolWithTag(NonPagedPool, sizeof(USBPRINT_RW_CONTEXT), USBP_TAG);
if(!context)
ExFreePool(urb);
}
if (urb && context)
{
context->Urb = urb;
context->DeviceObject = DeviceObject;
context->IsWrite=TRUE;
nextStack = IoGetNextIrpStackLocation(Irp);
ASSERT(nextStack != NULL);
ASSERT(DeviceObject->StackSize>1);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(Irp,
USBPRINT_AsyncReadWrite_Complete,
context,
TRUE,
TRUE,
TRUE);
USBPRINT_KdPrint3 (("USBPRINT.SYS: IRP = 0x%x current = 0x%x next = 0x%x\n",Irp, irpStack, nextStack));
IoMarkIrpPending(Irp);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,Irp);
ntStatus=STATUS_PENDING;
goto USBPRINT_Write_Done;
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
break;
default:
ntStatus = STATUS_INVALID_PARAMETER;
TRAP();
}
USBPRINT_Write_Reject:
USBPRINT_DecrementIoCount(DeviceObject);
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
USBPRINT_Write_Done:
USBPRINT_KdPrint3 (("USBPRINT.SYS: Write Done, status= 0x%08X\n",ntStatus));
return ntStatus;
}
NTSTATUS
USBPRINT_Close(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
DeviceObject - pointer to the device object for this printer
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus;
PFILE_OBJECT fileObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
USBPRINT_KdPrint2 (("USBPRINT.SYS: entering USBPRINT_Close\n"));
USBPRINT_IncrementIoCount(DeviceObject);
deviceExtension = DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation (Irp);
fileObject = irpStack->FileObject;
if (fileObject->FsContext)
{
// closing pipe handle
pipeHandle = fileObject->FsContext;
USBPRINT_KdPrint3 (("USBPRINT.SYS: closing pipe %x\n", pipeHandle));
}
deviceExtension->OpenCnt--;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
USBPRINT_DecrementIoCount(DeviceObject);
if(!deviceExtension->IsChildDevice)
{
USBPRINT_FdoSubmitIdleRequestIrp(deviceExtension);
}
return ntStatus;
}
NTSTATUS
USBPRINT_Create(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
/*++
Routine Description:
//
// Entry point for CreateFile calls
// user mode apps open device interfaces via
// SetupDiEnumDeviceInterfaces
Arguments:
DeviceObject - pointer to the device object for this printer.
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_OBJECT fileObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
USBPRINT_KdPrint2 (("USBPRINT.SYS: entering USBPRINT_Create\n"));
USBPRINT_IncrementIoCount(DeviceObject);
deviceExtension = DeviceObject->DeviceExtension;
if (deviceExtension->IsChildDevice==TRUE) {
ntStatus = STATUS_NOT_SUPPORTED;
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
USBPRINT_DecrementIoCount(DeviceObject);
return ntStatus;
}
if (deviceExtension->AcceptingRequests == FALSE) {
ntStatus = STATUS_DELETE_PENDING;
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
USBPRINT_DecrementIoCount(DeviceObject);
return ntStatus;
}
USBPRINT_FdoRequestWake(deviceExtension);
irpStack = IoGetCurrentIrpStackLocation (Irp);
fileObject = irpStack->FileObject;
// fscontext is null for device
fileObject->FsContext = NULL;
deviceExtension->OpenCnt++;
ntStatus = STATUS_SUCCESS;
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
USBPRINT_DecrementIoCount(DeviceObject);
USBPRINT_KdPrint2 (("USBPRINT.SYS: exit USBPRINT_Create %x\n", ntStatus));
return ntStatus;
}