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.
 
 
 
 
 
 

3584 lines
113 KiB

/*++
Copyright (c) 1997-1998 Microsoft Corporation
Module Name:
USBPRINT.c
Abstract:
Device driver for USB printers
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) 1996 Microsoft Corporation. All Rights Reserved.
Revision History:
5-4-96 : created
--*/
#define DRIVER
//Windows includes
#include "wdm.h"
#include "ntddpar.h"
#include "initguid.h"
#include "wdmguid.h"
NTSTATUS
USBPRINT_SystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, USBPRINT_SystemControl)
#endif
#include "stdarg.h"
#include "stdio.h"
//USB includes
#include <usb.h>
#include <usbdrivr.h>
#include "usbdlib.h"
//My includes
#include "usbprint.h"
#include "deviceid.h"
//
// Global pointer to Driver Object
//
PDRIVER_OBJECT USBPRINT_DriverObject;
int iGMessageLevel;
PFREE_PORTS pGPortList;
HANDLE GLogHandle;
NTSTATUS QueryDeviceRelations(PDEVICE_OBJECT DeviceObject,PIRP Irp,DEVICE_RELATION_TYPE,BOOL *pbComplete);
NTSTATUS GetPortNumber(HANDLE hInterfaceKey,ULONG *ulPortNumber);
NTSTATUS ProduceQueriedID(PDEVICE_EXTENSION deviceExtension,PIO_STACK_LOCATION irpStack,PIRP Irp,PDEVICE_OBJECT DeviceObject);
int iGetMessageLevel();
NTSTATUS USBPRINT_ProcessChildPowerIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp);
NTSTATUS USBPRINT_ProcessFdoPowerIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp);
NTSTATUS InitFreePorts( PFREE_PORTS * pHead );
NTSTATUS bAddPortInUseItem(PFREE_PORTS * pFreePorts,ULONG iPortNumber );
NTSTATUS LoadPortsUsed(GUID *pPrinterGuid,PFREE_PORTS * pPortList,WCHAR *wcBaseName);
void ClearFreePorts(PFREE_PORTS * pHead);
NTSTATUS LoadPortsUsed(GUID *pPrinterGuid,PFREE_PORTS * pPortList,WCHAR *wcBaseName);
void vClaimPortNumber(ULONG ulPortNumber,HANDLE hInterfaceKey,PFREE_PORTS * pPortsUsed);
NTSTATUS GetNewPortNumber(PFREE_PORTS * pFreePorts, ULONG *pulPortNumber);
BOOL bDeleteIfRecyclable(HANDLE hInterfaceKey);
NTSTATUS SetValueToZero(HANDLE hRegKey,PUNICODE_STRING ValueName);
USBPRINT_GetDeviceID(PDEVICE_OBJECT ParentDeviceObject);
void WritePortDescription(PDEVICE_EXTENSION deviceExtension);
void vOpenLogFile(IN HANDLE *pHandle);
void vWriteToLogFile(IN HANDLE *pHandle,IN CHAR *pszString);
void vCloseLogFile(IN HANDLE *pHandle);
NTSYSAPI
NTSTATUS
NTAPI
ZwDeleteValueKey(
IN HANDLE KeyHandle,
IN PUNICODE_STRING ValueName
);
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
/*++
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path
to driver-specific key in the registry
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
USBPRINT_DriverObject = DriverObject;
//
// Create dispatch points for device control, create, close.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = USBPRINT_Create;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBPRINT_Close;
DriverObject->DriverUnload = USBPRINT_Unload;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBPRINT_ProcessIOCTL;
DriverObject->MajorFunction[IRP_MJ_WRITE] = USBPRINT_Write;
DriverObject->MajorFunction[IRP_MJ_READ] = USBPRINT_Read;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = USBPRINT_SystemControl;
DriverObject->MajorFunction[IRP_MJ_PNP] = USBPRINT_Dispatch;
DriverObject->MajorFunction[IRP_MJ_POWER] = USBPRINT_ProcessPowerIrp;
DriverObject->DriverExtension->AddDevice = USBPRINT_PnPAddDevice;
iGMessageLevel=iGetMessageLevel();
USBPRINT_KdPrint2 (("USBPRINT.SYS: entering (USBPRINT) DriverEntry\n"));
USBPRINT_KdPrint2 (("USBPRINT.SYS: MessageLevel=%d\n",iGMessageLevel));
USBPRINT_KdPrint2 (("USBPRINT.SYS: About to load ports\n"));
pGPortList = NULL;
ntStatus=InitFreePorts(&pGPortList);
if(NT_SUCCESS(ntStatus) && pGPortList!=NULL)
{
ntStatus=LoadPortsUsed((GUID *)&USBPRINT_GUID,&pGPortList,USB_BASE_NAME);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: DriverInit: Unable to load used ports; error=%u\n", ntStatus));
}
}
else
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: exiting (USBPRINT) DriverEntry (%x)\n", ntStatus));
if(NT_SUCCESS(ntStatus))
{
ntStatus=STATUS_INSUFFICIENT_RESOURCES;
}
}
USBPRINT_KdPrint2 (("USBPRINT.SYS: exiting (USBPRINT) DriverEntry (%x)\n", ntStatus));
if ( !NT_SUCCESS(ntStatus))
ClearFreePorts(&pGPortList);
return ntStatus;
}
/*********************************************
* Message Levels:
* 0 == None, except critical, about to crash the machine failures
* 1 == Error messages only
* 2 == Informative messages
* 3 == Verbose informative messages
******************************************************/
int iGetMessageLevel()
{
OBJECT_ATTRIBUTES rObjectAttribs;
HANDLE hRegHandle;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
ULONG ulSizeUsed;
PKEY_VALUE_PARTIAL_INFORMATION pValueStruct;
NTSTATUS ntStatus;
int iReturn;
RtlInitUnicodeString(&KeyName,L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\USBPRINT");
RtlInitUnicodeString(&ValueName,L"DriverMessageLevel");
InitializeObjectAttributes(&rObjectAttribs,&KeyName,OBJ_CASE_INSENSITIVE,NULL,NULL);
ntStatus=ZwOpenKey(&hRegHandle,KEY_QUERY_VALUE,&rObjectAttribs);
if(NT_SUCCESS(ntStatus))
{
ulSizeUsed=sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG); //this is a byte to much. Oh well
pValueStruct=ExAllocatePoolWithTag(NonPagedPool,ulSizeUsed, USBP_TAG);
if(pValueStruct==NULL)
{
USBPRINT_KdPrint0(("'USBPRINT.SYS: iGetMessageLevel; Unable to allocate memory\n"));
ZwClose(hRegHandle);
return 1;
}
ntStatus=ZwQueryValueKey(hRegHandle,&ValueName,KeyValuePartialInformation,pValueStruct,ulSizeUsed,&ulSizeUsed);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint3(("Failed to Query value Key\n"));
iReturn=1;
}
else
{
iReturn=(int)*((ULONG *)(pValueStruct->Data));
}
ExFreePool(pValueStruct);
ZwClose(hRegHandle);
}
else
{
iReturn=1;
}
return iReturn;
} /*end iGetMessageLevel*/
NTSTATUS
USBPRINT_PoRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
PIRP irp;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT deviceObject = Context;
NTSTATUS ntStatus;
deviceExtension = deviceObject->DeviceExtension;
irp = deviceExtension->PowerIrp;
USBPRINT_KdPrint2(("USBPRINT_PoRequestCompletion\n"));
PoStartNextPowerIrp(irp);
IoCopyCurrentIrpStackLocationToNext(irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
irp);
USBPRINT_DecrementIoCount(deviceObject);
return ntStatus;
}
NTSTATUS
USBPRINT_PowerIrp_Complete(
IN PDEVICE_OBJECT NullDeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
USBPRINT_KdPrint2(("USBPRINT.SYS: enter USBPRINT_PowerIrp_Complete\n"));
deviceObject = (PDEVICE_OBJECT) Context;
deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
ASSERT(irpStack->MinorFunction == IRP_MN_SET_POWER);
ASSERT(irpStack->Parameters.Power.Type==DevicePowerState);
ASSERT(irpStack->Parameters.Power.State.DeviceState==PowerDeviceD0);
deviceExtension->CurrentDevicePowerState = PowerDeviceD0;
deviceExtension->bD0IrpPending=FALSE;
// if (deviceExtension->Interface)
// ExFreePool(deviceExtension->Interface);
// ntStatus=USBPRINT_ConfigureDevice(deviceObject);
// ntStatus = USBPRINT_BuildPipeList(deviceObject);
// if(!NT_SUCCESS(ntStatus))
// USBPRINT_KdPrint1(("USBPRINT.SYS : Unable to reconfigure device after wakeup. Error %x\n",ntStatus));
Irp->IoStatus.Status = ntStatus;
USBPRINT_DecrementIoCount(deviceObject);
return ntStatus;
}
NTSTATUS
USBPRINT_SetDevicePowerState(
IN PDEVICE_OBJECT DeviceObject,
IN DEVICE_POWER_STATE DeviceState,
IN PBOOLEAN HookIt
)
/*++
Routine Description:
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
DeviceState - Device specific power state to set the device in to.
Return Value:
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
switch (DeviceState) {
case PowerDeviceD3:
//
// device will be going OFF, save any state now.
//
USBPRINT_KdPrint2(("USBPRINT.SYS: PowerDeviceD3 (OFF)*******************************/*dd\n"));
deviceExtension->CurrentDevicePowerState = DeviceState;
break;
case PowerDeviceD1:
case PowerDeviceD2:
//
// power states D1,D2 translate to USB suspend
USBPRINT_KdPrint2(("USBPRINT.SYS: PowerDeviceD1/D2 (SUSPEND)*******************************/*dd\n"));
deviceExtension->CurrentDevicePowerState = DeviceState;
break;
case PowerDeviceD0:
USBPRINT_KdPrint2(("USBPRINT.SYS: PowerDeviceD0 (ON)*******************************/*dd\n"));
//
// finish the rest in the completion routine
//
*HookIt = TRUE;
// pass on to PDO
break;
default:
USBPRINT_KdPrint1(("USBPRINT.SYS: Bogus DeviceState = %x\n", DeviceState));
}
return ntStatus;
}
NTSTATUS
USBPRINT_DeferIrpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
PKEVENT event = Context;
KeSetEvent(event,1,FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
USBPRINT_QueryCapabilities(
IN PDEVICE_OBJECT PdoDeviceObject,
IN PDEVICE_CAPABILITIES DeviceCapabilities
)
/*++
Routine Description:
This routine reads or write config space.
Arguments:
DeviceObject - Physical DeviceObject for this USB controller.
Return Value:
None.
--*/
{
PIO_STACK_LOCATION nextStack;
PIRP irp;
NTSTATUS ntStatus;
KEVENT event;
PAGED_CODE();
irp = IoAllocateIrp(PdoDeviceObject->StackSize, FALSE);
if (!irp) {
return STATUS_INSUFFICIENT_RESOURCES;
}
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
nextStack->MajorFunction= IRP_MJ_PNP;
nextStack->MinorFunction= IRP_MN_QUERY_CAPABILITIES;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoSetCompletionRoutine(irp,
USBPRINT_DeferIrpCompletion,
&event,
TRUE,
TRUE,
TRUE);
//this is different from the latest version of busdd.doc
nextStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
ntStatus = IoCallDriver(PdoDeviceObject,
irp);
USBPRINT_KdPrint3(("USBPRINT.SYS: ntStatus from IoCallDriver to PCI = 0x%x\n", ntStatus));
if (ntStatus == STATUS_PENDING) {
// wait for irp to complete
KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
}
#if DBG
if (!NT_SUCCESS(ntStatus)) {
// failed? this is probably a bug
USBPRINT_KdPrint1(("USBPRINT.SYS: QueryCapabilities failed, why?\n"));
}
#endif
IoFreeIrp(irp);
return STATUS_SUCCESS;
}
NTSTATUS
USBPRINT_ProcessPowerIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION deviceExtension;
BOOLEAN hookIt = FALSE;
NTSTATUS ntStatus;
USBPRINT_KdPrint2(("USBPRINT.SYS: /*****************************************************************IRP_MJ_POWER\n"));
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
if(deviceExtension->IsChildDevice)
ntStatus=USBPRINT_ProcessChildPowerIrp(DeviceObject,Irp);
else
ntStatus=USBPRINT_ProcessFdoPowerIrp(DeviceObject,Irp);
USBPRINT_KdPrint3(("USBPRINT.SYS: /*****************************************************************Leaving power IRP_MJ_POWER\n"));
return ntStatus;
} /*end function USBPRINT_ProcessPowerIrp*/
NTSTATUS
USBPRINT_ProcessChildPowerIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION irpStack;
NTSTATUS ntStatus;
PCHILD_DEVICE_EXTENSION pDeviceExtension;
USBPRINT_KdPrint2(("USBPRINT.SYS: IRP_MJ_POWER for child PDO\n"));
pDeviceExtension=(PCHILD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
irpStack=IoGetCurrentIrpStackLocation(Irp);
switch(irpStack->MinorFunction)
{
case IRP_MN_SET_POWER:
USBPRINT_KdPrint3(("USBPRINT.SYS: IRP_MJ_POWER, IRP_MN_SET_POWER\n"));
ntStatus=STATUS_SUCCESS;
break;
case IRP_MN_QUERY_POWER:
USBPRINT_KdPrint3(("USBPRINT.SYS: IRP_MJ_POWER, IRP_MN_QUERY_POWER\n"));
ntStatus=STATUS_SUCCESS;
break;
default:
ntStatus = Irp->IoStatus.Status;
} /*end switch irpStack->MinorFunction*/
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status=ntStatus;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return ntStatus;
} /*end function USBPRINT_ProcessChildPowerIrp*/
NTSTATUS
USBPRINT_ProcessFdoPowerIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the Power IRPs sent to the PDO for this device.
Arguments:
DeviceObject - pointer to a hcd device object (FDO)
Irp - pointer to an I/O Request Packet
Return Value:
NT status code
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
BOOLEAN hookIt = FALSE;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
if(deviceExtension->IsChildDevice)
{
USBPRINT_KdPrint1(("USBPRINT.SYS Is child device inside fdo function. Error!*/\n"));
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
USBPRINT_IncrementIoCount(DeviceObject);
switch(irpStack->MinorFunction)
{
case IRP_MN_SET_POWER:
{
switch(irpStack->Parameters.Power.Type)
{
case SystemPowerState:
//
// find the device power state equivalent to the given system state
//
{
POWER_STATE powerState;
USBPRINT_KdPrint3(("USBPRINT.SYS: Set Power, SystemPowerState (%d)\n",
irpStack->Parameters.Power.State.SystemState));
powerState.DeviceState = deviceExtension->DeviceCapabilities.DeviceState[irpStack->Parameters.Power.State.SystemState];
//
// are we already in this state?
//
if(powerState.DeviceState != deviceExtension->CurrentDevicePowerState)
{
// No,
// request that we be put into this state
//Don't touch the Irp any more after this. It could complete at any time
deviceExtension->PowerIrp = Irp;
IoMarkIrpPending(Irp);
ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
IRP_MN_SET_POWER,
powerState,
USBPRINT_PoRequestCompletion,
DeviceObject,
NULL);
hookIt = TRUE;
}
else
{
// Yes,
// just pass it on
PoStartNextPowerIrp(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
}
}
break;
case DevicePowerState:
ntStatus = USBPRINT_SetDevicePowerState(DeviceObject,
irpStack->Parameters.Power.State.DeviceState,
&hookIt);
PoStartNextPowerIrp(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
if(hookIt)
{
USBPRINT_KdPrint2(("USBPRINT.SYS: Set PowerIrp Completion Routine\n"));
IoSetCompletionRoutine(Irp,USBPRINT_PowerIrp_Complete,DeviceObject,TRUE,TRUE,TRUE);
}
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,Irp);
break;
} /* switch irpStack->Parameters.Power.Type */
}
break; /* IRP_MN_SET_POWER */
default:
USBPRINT_KdPrint1(("USBPRINT.SYS: UNKNOWN POWER MESSAGE (%x)\n", irpStack->MinorFunction));
//
// All unahndled PnP messages are passed on to the PDO
//
PoStartNextPowerIrp(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
} /* irpStack->MinorFunction */
if( !hookIt )
USBPRINT_DecrementIoCount(DeviceObject);
return ntStatus;
} /*end function ProcessFdoPowerIrp*/
NTSTATUS
USBPRINT_Dispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
--*/
{
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT stackDeviceObject;
BOOL bHandled=FALSE;
//Irp->IoStatus.Status = STATUS_SUCCESS;
//Irp->IoStatus.Information = 0;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
//
// Get a pointer to the device extension
//
deviceExtension = DeviceObject->DeviceExtension;
stackDeviceObject = deviceExtension->TopOfStackDeviceObject;
#ifdef MYDEBUG
DbgPrint("USBPRINT_Dispatch entry for pnp event %d\n", irpStack->MinorFunction);
ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
#endif
USBPRINT_IncrementIoCount(DeviceObject);
switch (irpStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
{
if(deviceExtension->IsChildDevice==FALSE)
{
KEVENT event;
USBPRINT_KdPrint2 (("USBPRINT.SYS: IRP_MN_START_DEVICE\n"));
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,USBPRINT_DeferIrpCompletion,&event,TRUE,TRUE,TRUE);
ntStatus = IoCallDriver(stackDeviceObject,Irp);
if (ntStatus == STATUS_PENDING)
{
KeWaitForSingleObject(&event,Suspended,KernelMode,FALSE,NULL);
ntStatus = Irp->IoStatus.Status;
}
if ( NT_SUCCESS(ntStatus) ) {
//
// You start the device after everyone below you have started it
//
Irp->IoStatus.Status = ntStatus = USBPRINT_StartDevice(DeviceObject);
}
} /*end if not child*/
else
{
ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
}
bHandled = TRUE;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
USBPRINT_DecrementIoCount(DeviceObject);
} //end case IRP_MN_START_DEVICE
break;
case IRP_MN_STOP_DEVICE:
if(deviceExtension->IsChildDevice)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
ntStatus=STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
else
{
USBPRINT_KdPrint2 (("USBPRINT.SYS: IRP_MN_STOP_DEVICE\n"));
//
// You stop the device first and then let everyone below you deal with it
//
ntStatus = USBPRINT_StopDevice(DeviceObject);
ASSERT(NT_SUCCESS(ntStatus));
//
// We want to stop the device anyway ..
//
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(Irp);
ntStatus = IoCallDriver(stackDeviceObject,Irp);
}
bHandled = TRUE;
USBPRINT_DecrementIoCount(DeviceObject);
break;
case IRP_MN_SURPRISE_REMOVAL:
if(deviceExtension->IsChildDevice)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
ntStatus=STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
else
{
USBPRINT_KdPrint2(("USBPRINT.SYS: Surprise Remove"));
ntStatus = USBPRINT_StopDevice(DeviceObject);
ASSERT(NT_SUCCESS(ntStatus));
Irp->IoStatus.Status=STATUS_SUCCESS;
deviceExtension->AcceptingRequests=FALSE;
IoSkipCurrentIrpStackLocation(Irp);
ntStatus = IoCallDriver(stackDeviceObject,Irp);
} /*end else NOT child device*/
bHandled = TRUE;
USBPRINT_DecrementIoCount(DeviceObject);
break;
case IRP_MN_REMOVE_DEVICE:
if(deviceExtension->IsChildDevice==FALSE)
{
USBPRINT_KdPrint2 (("USBPRINT.SYS: IRP_MN_REMOVE_DEVICE\n"));
// match the inc at the begining of the dispatch routine
USBPRINT_DecrementIoCount(DeviceObject);
ntStatus = USBPRINT_StopDevice(DeviceObject);
ASSERT(NT_SUCCESS(ntStatus));
Irp->IoStatus.Status=STATUS_SUCCESS;
//
// ounce this flag is set no irps will be pased
// down the stack to lower drivers
//
deviceExtension->AcceptingRequests = FALSE;
if(deviceExtension->bChildDeviceHere)
{
deviceExtension->bChildDeviceHere=FALSE;
IoDeleteDevice(deviceExtension->ChildDevice);
USBPRINT_KdPrint3(("USBPRINT.SYS: Deleted child device\n"));
}
if (NT_SUCCESS(ntStatus))
{
LONG pendingIoCount;
USBPRINT_KdPrint3(("USBPRINT.SYS: About to copy current IrpStackLocation\n"));
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus = IoCallDriver(stackDeviceObject,Irp);
// Irp->IoStatus.Information = 0;
//
// final decrement will trigger the remove
//
pendingIoCount = USBPRINT_DecrementIoCount(DeviceObject);
{
NTSTATUS status;
// wait for any io request pending in our driver to
// complete for finishing the remove
status = KeWaitForSingleObject(&deviceExtension->RemoveEvent,Suspended,KernelMode,FALSE,NULL);
// TRAP();
} /*end of non-controled code block*/
//
// Delete the link and FDO we created
//
USBPRINT_RemoveDevice(DeviceObject);
USBPRINT_KdPrint3 (("USBPRINT.SYS: Detaching from %08X\n",deviceExtension->TopOfStackDeviceObject));
IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
USBPRINT_KdPrint3 (("USBPRINT.SYS: Deleting %08X\n",DeviceObject));
IoDeleteDevice (DeviceObject);
} /*end if NT_SUCCESS(ntStatus)*/
} /*end if IsChildDevice==FALSE*/
else
{
USBPRINT_DecrementIoCount(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
ntStatus=STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
bHandled = TRUE;
break; //case IRP_MN_REMOVE_DEVICE
case IRP_MN_QUERY_CAPABILITIES:
{
if(deviceExtension->IsChildDevice==FALSE) //if it's the parent, pass down the irp, and set SurpriseRemovalOK on the way back up
{
KEVENT event;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,USBPRINT_DeferIrpCompletion,&event,TRUE,TRUE,TRUE);
ntStatus = IoCallDriver(stackDeviceObject,Irp);
if (ntStatus == STATUS_PENDING)
{
KeWaitForSingleObject(&event,Suspended,KernelMode,FALSE,NULL);
ntStatus = Irp->IoStatus.Status;
}
if ( NT_SUCCESS(ntStatus) )
irpStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
// get device wake for selective suspend
deviceExtension->DeviceWake = irpStack->Parameters.DeviceCapabilities.Capabilities->DeviceWake;
}
else
{
irpStack->Parameters.DeviceCapabilities.Capabilities->RawDeviceOK = TRUE;
irpStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
Irp->IoStatus.Status = STATUS_SUCCESS;
ntStatus=STATUS_SUCCESS;
}
IoCompleteRequest(Irp, IO_NO_INCREMENT);
bHandled = TRUE;
USBPRINT_DecrementIoCount(DeviceObject);
}
break;
case IRP_MN_QUERY_DEVICE_TEXT:
USBPRINT_KdPrint2 (("USBPRINT.SYS: IRP_MN_QUERY_DEVICE_TEXT\n"));
if(deviceExtension->IsChildDevice==TRUE)
{
PCHILD_DEVICE_EXTENSION pChildDeviceExtension=(PCHILD_DEVICE_EXTENSION)deviceExtension;
PDEVICE_EXTENSION pParentExtension=pChildDeviceExtension->ParentDeviceObject->DeviceExtension;
USBPRINT_KdPrint2(("USBPRINT.SYS: Is child PDO, will complete locally\n"));
switch(irpStack->Parameters.QueryDeviceText.DeviceTextType)
{
case DeviceTextDescription:
{
ANSI_STRING AnsiTextString;
UNICODE_STRING UnicodeDeviceText;
RtlInitAnsiString(&AnsiTextString,pParentExtension->DeviceIdString);
ntStatus=RtlAnsiStringToUnicodeString(&UnicodeDeviceText,&AnsiTextString,TRUE);
USBPRINT_KdPrint2(("USBPRINT.SYS: QUERY_DEVICE_TEXT, DeviceID=%s\n",pParentExtension->DeviceIdString));
if(NT_SUCCESS(ntStatus))
Irp->IoStatus.Information=(ULONG_PTR)UnicodeDeviceText.Buffer;
}
break;
default:
ntStatus=Irp->IoStatus.Status;
}
bHandled=TRUE;
USBPRINT_DecrementIoCount(DeviceObject);
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
break;
case IRP_MN_QUERY_BUS_INFORMATION:
if(deviceExtension->IsChildDevice==TRUE)
{
PPNP_BUS_INFORMATION pBusInfo = ExAllocatePool( PagedPool, sizeof(PNP_BUS_INFORMATION) );
USBPRINT_KdPrint2(("USBPRINT.SYS: IRP_MN_QUERY_BUS_INFORMATION\n"));
if( pBusInfo )
{
pBusInfo->BusTypeGuid = GUID_BUS_TYPE_USBPRINT;
pBusInfo->LegacyBusType = PNPBus;
pBusInfo->BusNumber = 0;
ntStatus = STATUS_SUCCESS;
Irp->IoStatus.Information = (ULONG_PTR)pBusInfo;
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
bHandled = TRUE;
USBPRINT_DecrementIoCount(DeviceObject);
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
break;
case IRP_MN_QUERY_ID:
{
USBPRINT_KdPrint2 (("USBPRINT.SYS: IRP_MN_QUERY_ID\n"));
if(deviceExtension->IsChildDevice==TRUE)
{
USBPRINT_KdPrint2(("USBPRINT.SYS: Is child PDO, will complete locally\n"));
ntStatus=ProduceQueriedID(deviceExtension,irpStack,Irp,DeviceObject);
bHandled = TRUE;
USBPRINT_DecrementIoCount(DeviceObject);
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
} /*end if child PDO*/
} /*end case QUERY_ID*/
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
USBPRINT_KdPrint2 (("USBPRINT.SYS: IRP_MN_QUERY_DEVICE_RELATIONS\n"));
ntStatus=QueryDeviceRelations(DeviceObject,Irp,irpStack->Parameters.QueryDeviceRelations.Type,&bHandled);
if ( bHandled )
USBPRINT_DecrementIoCount(DeviceObject);
break;
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
if(deviceExtension->IsChildDevice)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
ntStatus=STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
else
{
ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(Irp);
ntStatus = IoCallDriver(stackDeviceObject,Irp);
}
USBPRINT_DecrementIoCount(DeviceObject);
bHandled = TRUE;
break;
} /* end IRP_MN swich inside IRP_MJ_PNP case */
if(!bHandled)
{
if(deviceExtension->IsChildDevice==TRUE)
{
USBPRINT_KdPrint3(("USBPRINT.SYS: unsupported child pnp IRP\n"));
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
} /*end if child device*/
else
{
IoSkipCurrentIrpStackLocation(Irp);
ntStatus = IoCallDriver(stackDeviceObject,Irp);
}
USBPRINT_DecrementIoCount(DeviceObject);
} /*end if !bHandled*/
#ifdef MYDEBUG
DbgPrint("Returning %d\n", ntStatus);
#endif
return ntStatus;
} /*end function USBPRINT_Dispatch*/
NTSTATUS
USBPRINT_SystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus;
PDEVICE_OBJECT stackDeviceObject;
PAGED_CODE();
//
// Get a pointer to the device extension
//
deviceExtension = DeviceObject->DeviceExtension;
stackDeviceObject = deviceExtension->TopOfStackDeviceObject;
USBPRINT_IncrementIoCount(DeviceObject);
if(deviceExtension->IsChildDevice==TRUE)
{
USBPRINT_KdPrint3(("USBPRINT.SYS: unsupported child SystemControl IRP\n"));
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
} /*end if child device*/
else
{
IoSkipCurrentIrpStackLocation(Irp);
ntStatus = IoCallDriver(stackDeviceObject,Irp);
}
USBPRINT_DecrementIoCount(DeviceObject);
return ntStatus;
}
NTSTATUS QueryDeviceRelations(PDEVICE_OBJECT DeviceObject,PIRP Irp,DEVICE_RELATION_TYPE RelationType,BOOL *pbComplete)
{
PIO_STACK_LOCATION irpSp;
NTSTATUS ntStatus;
PDEVICE_EXTENSION pExtension;
PDEVICE_RELATIONS pRelations;
*pbComplete=FALSE;
pExtension=(PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
ntStatus=Irp->IoStatus.Status;
irpSp=IoGetCurrentIrpStackLocation(Irp);
if(!pExtension->IsChildDevice)
{
USBPRINT_KdPrint2 (("USBPRINT.SYS: Parent QueryDeviceRelations\n"));
if(RelationType==BusRelations)
{
*pbComplete=TRUE;
pRelations=(PDEVICE_RELATIONS)ExAllocatePoolWithTag(NonPagedPool,sizeof(DEVICE_RELATIONS), USBP_TAG);
if(pRelations!=NULL)
{
//Some drivers check for pre-existing children and preserve them. This would happen if there is a filter driver above us, but we're not REALLY a bus driver
pRelations->Objects[0]=pExtension->ChildDevice;
pRelations->Count = 1;
ObReferenceObject(pExtension->ChildDevice);
Irp->IoStatus.Information=(ULONG_PTR)pRelations;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus = IoCallDriver(pExtension->TopOfStackDeviceObject,Irp);
} /*end !NULL*/
else
{
ntStatus=STATUS_NO_MEMORY;
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
//Port info will be written to the registry in the IRP_MN_QUERY_ID case. It can't be used before then anyway
} /*end if BusRelations*/
} else {
USBPRINT_KdPrint2 (("USBPRINT.SYS: Child QueryDeviceRelations\n"));
if(RelationType==TargetDeviceRelation)
{
*pbComplete=TRUE;
pRelations=(PDEVICE_RELATIONS)ExAllocatePoolWithTag(NonPagedPool,sizeof(DEVICE_RELATIONS), USBP_TAG);
if(pRelations!=NULL)
{
pRelations->Count = 1;
pRelations->Objects[0]=DeviceObject;
ObReferenceObject(DeviceObject);
Irp->IoStatus.Information=(ULONG_PTR)pRelations;
ntStatus = STATUS_SUCCESS;
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
} /*end !NULL*/
else
{
ntStatus=STATUS_NO_MEMORY;
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
//Port info will be written to the registry in the IRP_MN_QUERY_ID case. It can't be used before then anyway
} /*end if BusRelations*/
}
return ntStatus;
}
VOID
USBPRINT_Unload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Free all the allocated resources, etc.
Arguments:
DriverObject - pointer to a driver object
Return Value:
--*/
{
USBPRINT_KdPrint2 (("USBPRINT.SYS: enter USBPRINT_Unload\n"));
if(pGPortList!=NULL)
{
ClearFreePorts(&pGPortList);
}
// if(pPortsUsed!=NULL)
// ExFreePool(pPortsUsed);
//
// Free any global resources allocated
// in DriverEntry
//
USBPRINT_KdPrint2 (("USBPRINT.SYS: exit USBPRINT_Unload\n"));
}
NTSTATUS
USBPRINT_StartDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Initializes a given instance of the device on the USB.
All we do here is get the device descriptor and store it
Arguments:
DeviceObject - pointer to the device object for this instance of a printer
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus;
UNICODE_STRING KeyName;
PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
PURB urb=NULL;
ULONG siz;
ULONG dwVidPid;
PDEVICE_OBJECT NewDevice;
LARGE_INTEGER timeOut;
PCHILD_DEVICE_EXTENSION pChildExtension;
USBPRINT_KdPrint2 (("USBPRINT.SYS: enter USBPRINT_StartDevice\n"));
deviceExtension = DeviceObject->DeviceExtension;
ntStatus = USBPRINT_ConfigureDevice(DeviceObject);
if(NT_SUCCESS(ntStatus))
{
urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USBP_TAG);
}
else
{
USBPRINT_KdPrint1(("USBPRINT.SYS: USBPRINT_ConfigureDevice Failed\n"));
urb=NULL;
}
if (urb)
{
siz = sizeof(USB_DEVICE_DESCRIPTOR);
deviceDescriptor = ExAllocatePoolWithTag(NonPagedPool,siz, USBP_TAG);
if (deviceDescriptor)
{
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE,
0,
0,
deviceDescriptor,
NULL,
siz,
NULL);
timeOut.QuadPart = FAILURE_TIMEOUT;
ntStatus = USBPRINT_CallUSBD(DeviceObject, urb, &timeOut);
if (NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint3 (("USBPRINT.SYS: Device Descriptor = %x, len %x\n",
deviceDescriptor,
urb->UrbControlDescriptorRequest.TransferBufferLength));
USBPRINT_KdPrint3 (("USBPRINT.SYS: USBPRINT Device Descriptor:\n"));
USBPRINT_KdPrint3 (("USBPRINT.SYS: -------------------------\n"));
USBPRINT_KdPrint3 (("USBPRINT.SYS: bLength %d\n", deviceDescriptor->bLength));
USBPRINT_KdPrint3 (("USBPRINT.SYS: bDescriptorType 0x%x\n", deviceDescriptor->bDescriptorType));
USBPRINT_KdPrint3 (("USBPRINT.SYS: bcdUSB 0x%x\n", deviceDescriptor->bcdUSB));
USBPRINT_KdPrint3 (("USBPRINT.SYS: bDeviceClass 0x%x\n", deviceDescriptor->bDeviceClass));
USBPRINT_KdPrint3 (("USBPRINT.SYS: bDeviceSubClass 0x%x\n", deviceDescriptor->bDeviceSubClass));
USBPRINT_KdPrint3 (("USBPRINT.SYS: bDeviceProtocol 0x%x\n", deviceDescriptor->bDeviceProtocol));
USBPRINT_KdPrint3 (("USBPRINT.SYS: bMaxPacketSize0 0x%x\n", deviceDescriptor->bMaxPacketSize0));
USBPRINT_KdPrint3 (("USBPRINT.SYS: idVendor 0x%x\n", deviceDescriptor->idVendor));
USBPRINT_KdPrint3 (("USBPRINT.SYS: idProduct 0x%x\n", deviceDescriptor->idProduct));
USBPRINT_KdPrint3 (("USBPRINT.SYS: bcdDevice 0x%x\n", deviceDescriptor->bcdDevice));
USBPRINT_KdPrint3 (("USBPRINT.SYS: iManufacturer 0x%x\n", deviceDescriptor->iManufacturer));
USBPRINT_KdPrint3 (("USBPRINT.SYS: iProduct 0x%x\n", deviceDescriptor->iProduct));
USBPRINT_KdPrint3 (("USBPRINT.SYS: iSerialNumber 0x%x\n", deviceDescriptor->iSerialNumber));
USBPRINT_KdPrint3 (("USBPRINT.SYS: bNumConfigurations 0x%x\n", deviceDescriptor->bNumConfigurations));
dwVidPid=deviceDescriptor->idVendor;
dwVidPid<<=16;
dwVidPid+=deviceDescriptor->idProduct;
USBPRINT_KdPrint3 (("USBPRINT.SYS: Math OK\n"));
}
else
{
USBPRINT_KdPrint1(("USBPRINT.SYS: Get Device Descriptor failed\n"));
ntStatus=STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
USBPRINT_KdPrint1(("USBPRINT.SYS: Insufficient resources to allocate device descriptor in StartDevice\n"));
}
if (NT_SUCCESS(ntStatus))
{
deviceExtension->DeviceDescriptor = deviceDescriptor;
} else if (deviceDescriptor)
{
ExFreePool(deviceDescriptor);
}
ExFreePool(urb);
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
USBPRINT_KdPrint1(("USBPRINT.SYS: Insufficient resources to allocate urb in StartDevice\n"));
}
if(deviceExtension->bChildDeviceHere==FALSE)
{
if(NT_SUCCESS(ntStatus))
{
ntStatus=IoCreateDevice(USBPRINT_DriverObject,
sizeof(CHILD_DEVICE_EXTENSION),
NULL,
FILE_DEVICE_PARALLEL_PORT,
FILE_AUTOGENERATED_DEVICE_NAME,
TRUE,
&NewDevice);
}
if(NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint3(("USBPRINT.SYS: IoCreateDevice succeeded for child device\n"));
NewDevice->Flags|=DO_POWER_PAGABLE;
pChildExtension=NewDevice->DeviceExtension;
pChildExtension->ParentDeviceObject=DeviceObject;
deviceExtension->ChildDevice=NewDevice;
deviceExtension->bChildDeviceHere=TRUE;
pChildExtension->IsChildDevice=TRUE;
pChildExtension->ulInstanceNumber=deviceExtension->ulInstanceNumber;
}
else
{
USBPRINT_KdPrint1(("USBPRINT.SYS: IoCreateDevice failed for child device\n"));
}
} /*end if we need to make a child device*/
if(NT_SUCCESS(ntStatus))
{
USBPRINT_GetDeviceID(DeviceObject);
WritePortDescription(deviceExtension);
ntStatus=IoSetDeviceInterfaceState(&(deviceExtension->DeviceLinkName),TRUE);
}
if (NT_SUCCESS(ntStatus))
{
ntStatus = USBPRINT_BuildPipeList(DeviceObject);
if(!deviceExtension->IsChildDevice)
{
USBPRINT_FdoSubmitIdleRequestIrp(deviceExtension);
}
}
USBPRINT_KdPrint2 (("USBPRINT.SYS: exit USBPRINT_StartDevice (%x)\n", ntStatus));
return ntStatus;
}
void WritePortDescription(PDEVICE_EXTENSION deviceExtension)
{
UNICODE_STRING ValueName;
ANSI_STRING AnsiTextString;
UNICODE_STRING Description;
UNICODE_STRING BaseName,BaseValueName;
RtlInitUnicodeString(&ValueName,L"Port Description");
RtlInitAnsiString(&AnsiTextString,deviceExtension->DeviceIdString);
RtlAnsiStringToUnicodeString(&Description,&AnsiTextString,TRUE);
ZwSetValueKey(deviceExtension->hInterfaceKey,&ValueName,0,REG_SZ,Description.Buffer,Description.Length+2);
RtlFreeUnicodeString(&Description);
RtlInitUnicodeString(&BaseName,L"USB");
RtlInitUnicodeString(&BaseValueName,L"Base Name");
ZwSetValueKey(deviceExtension->hInterfaceKey,&BaseValueName,0,REG_SZ,BaseName.Buffer,BaseName.Length+2);
}
NTSTATUS
USBPRINT_RemoveDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Stops a given instance of printer
Arguments:
DeviceObject - pointer to the device object for this instance of the (parent) printer object
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
USBPRINT_KdPrint2 (("USBPRINT.SYS: enter USBPRINT_RemoveDevice\n"));
deviceExtension = DeviceObject->DeviceExtension;
ZwClose(deviceExtension->hInterfaceKey);
USBPRINT_KdPrint2(("USBPRINT.SYS: Closeing interface key in RemoveDevice\n"));
ntStatus=IoSetDeviceInterfaceState(&(deviceExtension->DeviceLinkName),FALSE);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: ioSetDeviceInterface to false failed\n"));
}
RtlFreeUnicodeString(&(deviceExtension->DeviceLinkName));
//
// Free device descriptor structure
//
if (deviceExtension->DeviceDescriptor) {
ExFreePool(deviceExtension->DeviceDescriptor);
}
//
// Free up any interface structures
//
if (deviceExtension->Interface) {
ExFreePool(deviceExtension->Interface);
}
USBPRINT_KdPrint2 (("USBPRINT.SYS: exit USBPRINT_RemoveDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBPRINT_StopDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Stops a given instance of a printer on the USB, this is only
stuff we need to do if the device is still present.
Arguments:
DeviceObject - pointer to the device object for this printer
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb;
ULONG siz;
LARGE_INTEGER timeOut;
timeOut.QuadPart = FAILURE_TIMEOUT;
USBPRINT_KdPrint3 (("USBPRINT.SYS: enter USBPRINT_StopDevice\n"));
deviceExtension = DeviceObject->DeviceExtension;
//
// Send the select configuration urb with a NULL pointer for the configuration
// handle, this closes the configuration and puts the device in the 'unconfigured'
// state.
//
siz = sizeof(struct _URB_SELECT_CONFIGURATION);
urb = ExAllocatePoolWithTag(NonPagedPool,siz, USBP_TAG);
if (urb) {
NTSTATUS status;
UsbBuildSelectConfigurationRequest(urb,
(USHORT) siz,
NULL);
status = USBPRINT_CallUSBD(DeviceObject, urb, &timeOut);
USBPRINT_KdPrint3 (("USBPRINT.SYS: Device Configuration Closed status = %x usb status = %x.\n",
status, urb->UrbHeader.Status));
ExFreePool(urb);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
USBPRINT_KdPrint2 (("USBPRINT.SYS: exit USBPRINT_StopDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBPRINT_PnPAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
This routine is called to create a new instance of the device
Arguments:
DriverObject - pointer to the driver object for this instance of USBPRINT
PhysicalDeviceObject - pointer to a device object created by the bus
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION deviceExtension;
USBD_VERSION_INFORMATION versionInformation;
ULONG ulPortNumber;
GUID * pPrinterGuid;
static ULONG instance = 0;
//UNICODE_STRING deviceLinkUnicodeString;
HANDLE hInterfaceKey;
USBPRINT_KdPrint2 (("USBPRINT.SYS: enter USBPRINT_PnPAddDevice\n"));
//
// create our funtional device object (FDO)
//
ntStatus =
USBPRINT_CreateDeviceObject(DriverObject, &deviceObject);
if (NT_SUCCESS(ntStatus)) {
deviceExtension = deviceObject->DeviceExtension;
//
// we support direct io for read/write
//
deviceObject->Flags |= DO_DIRECT_IO;
deviceObject->Flags |= DO_POWER_PAGABLE;
//** initialize our device extension
//
// remember the Physical device Object
//
deviceExtension->PhysicalDeviceObject=PhysicalDeviceObject;
// init selective suspend stuff
deviceExtension->PendingIdleIrp = NULL;
deviceExtension->IdleCallbackInfo = NULL;
deviceExtension->OpenCnt=0;
deviceExtension->bD0IrpPending=FALSE;
KeInitializeSpinLock(&(deviceExtension->WakeSpinLock));
//
// Attach to the PDO
//
deviceExtension->TopOfStackDeviceObject=IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
if(deviceExtension->TopOfStackDeviceObject==NULL)
{
USBPRINT_KdPrint1(("USBPRINT.SYS: IoAttachDeviceToDeviceStack failed\n"));
}
else
{
USBPRINT_KdPrint3(("USBPRINT.SYS: IoAttachDeviceToDeviceStack worked\n"));
}
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
USBPRINT_KdPrint3(("'USBPRINT.SYS: Before ioRegisterDeviceInterface\n"));
pPrinterGuid=(GUID *)&USBPRINT_GUID;
ntStatus=IoRegisterDeviceInterface(PhysicalDeviceObject,pPrinterGuid,NULL,&(deviceExtension->DeviceLinkName));
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1(("'USBPRINT.SYS: ioRegisterDeviceInterface failed\n"));
goto AddDeviceFailure;
}
ntStatus=IoOpenDeviceInterfaceRegistryKey(&(deviceExtension->DeviceLinkName),KEY_ALL_ACCESS,&hInterfaceKey);
USBPRINT_KdPrint2(("USBPRINT.SYS: Opened Device Interface reg key in AddDevice\n"));
// moved to RemoveDevice RtlFreeUnicodeString(&deviceLinkUnicodeString);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1(("USBPRINT.SYS: IoOpenDeviceInterfaceRegistryKey failed\n"));
goto AddDeviceFailure;
}
USBPRINT_KdPrint3(("USBPRINT.SYS: IoOpenDeviceInterfaceRegistryKey succeeded\n"));
deviceExtension->hInterfaceKey=hInterfaceKey;
ntStatus=GetPortNumber(hInterfaceKey,&ulPortNumber);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1(("USBPRINT.SYS: GetPortNumber failed\n"));
goto AddDeviceFailure;
}
deviceExtension->ulInstanceNumber=ulPortNumber;
USBPRINT_KdPrint2(("USBPRINT.SYS: Allocated port # %u\n",ulPortNumber));
/* ntStatus=IoSetDeviceInterfaceState(&(deviceExtension->DeviceLinkName),TRUE);
if(NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint3(("USBPRINT.SYS: IoSetDeviceInterfaceState worked\n"));
}
else
{
USBPRINT_KdPrint1(("USBPRINT.SYS: IoSetDeviceInterfaceState did not work\n"));
goto AddDeviceFailure;
}
*/
USBPRINT_QueryCapabilities(PhysicalDeviceObject,
&deviceExtension->DeviceCapabilities);
//
// display the device caps
//
#if DBG
{
ULONG i;
USBPRINT_KdPrint3(("USBPRINT.SYS: >>>>>> DeviceCaps\n"));
USBPRINT_KdPrint3(("USBPRINT.SYS: SystemWake = (%d)\n",
deviceExtension->DeviceCapabilities.SystemWake));
USBPRINT_KdPrint3(("USBPRINT.SYS: DeviceWake = (D%d)\n",
deviceExtension->DeviceCapabilities.DeviceWake-1));
for (i=PowerSystemUnspecified; i< PowerSystemMaximum; i++) {
USBPRINT_KdPrint3(("USBPRINT.SYS: Device State Map: sysstate %d = devstate 0x%x\n", i,
deviceExtension->DeviceCapabilities.DeviceState[i]));
}
USBPRINT_KdPrint3(("USBPRINT.SYS: '<<<<<<<<DeviceCaps\n"));
}
#endif
//
// transition to zero signals the event
//
USBPRINT_IncrementIoCount(deviceObject);
}
USBD_GetUSBDIVersion(&versionInformation);
AddDeviceFailure:
USBPRINT_KdPrint2 (("USBPRINT.SYS: exit USBPRINT_PnPAddDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBPRINT_CreateDeviceObject(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT *DeviceObject
)
/*++
Routine Description:
Creates a Functional DeviceObject
Arguments:
DriverObject - pointer to the driver object for device
DeviceObject - pointer to DeviceObject pointer to return
created device object.
Instance - instnace of the device create.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
ULONG instance;
USBPRINT_KdPrint2 (("USBPRINT.SYS: enter USBPRINT_CreateDeviceObject\n"));
//
// This driver supports up to 9 instances
//
ntStatus = IoCreateDevice (DriverObject,
sizeof (DEVICE_EXTENSION),
NULL,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
DeviceObject);
//
// Initialize our device extension
//
deviceExtension = (PDEVICE_EXTENSION) ((*DeviceObject)->DeviceExtension);
deviceExtension->IsChildDevice=FALSE;
deviceExtension->ResetWorkItemPending=0; //init to "no workitem pending"
deviceExtension->bChildDeviceHere=FALSE;
deviceExtension->DeviceDescriptor = NULL;
deviceExtension->Interface = NULL;
deviceExtension->ConfigurationHandle = NULL;
deviceExtension->AcceptingRequests = TRUE;
deviceExtension->PendingIoCount = 0;
deviceExtension->DeviceCapabilities.Size = sizeof(DEVICE_CAPABILITIES);
deviceExtension->DeviceCapabilities.Version = DEVICE_CAPABILITY_VERSION;
deviceExtension->DeviceCapabilities.Address = (ULONG) -1;
deviceExtension->DeviceCapabilities.UINumber= (ULONG) -1;
deviceExtension->DeviceCapabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0;
deviceExtension->DeviceCapabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
deviceExtension->DeviceCapabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
deviceExtension->DeviceCapabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
deviceExtension->DeviceCapabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
deviceExtension->DeviceCapabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
KeInitializeEvent(&deviceExtension->RemoveEvent, NotificationEvent, FALSE);
USBPRINT_KdPrint2 (("USBPRINT.SYS: exit USBPRINT_CreateDeviceObject (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBPRINT_CallUSBD(
IN PDEVICE_OBJECT DeviceObject,
IN PURB Urb,
IN PLARGE_INTEGER pTimeout
)
/*++
Routine Description:
Passes a URB to the USBD class driver
Arguments:
DeviceObject - pointer to the device object for this printer
Urb - pointer to Urb request block
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus, status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
PIRP irp;
KEVENT event;
PIO_STACK_LOCATION nextStack;
USBPRINT_KdPrint2 (("USBPRINT.SYS: enter USBPRINT_CallUSBD\n"));
deviceExtension = DeviceObject->DeviceExtension;
//
// issue a synchronous request
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
if ( (irp = IoAllocateIrp(deviceExtension->TopOfStackDeviceObject->StackSize,
FALSE)) == NULL )
return STATUS_INSUFFICIENT_RESOURCES;
//
// Call the class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
//
// pass the URB to the USB driver stack
//
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
nextStack->Parameters.Others.Argument1 = Urb;
IoSetCompletionRoutine(irp,
USBPRINT_DeferIrpCompletion,
&event,
TRUE,
TRUE,
TRUE);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
irp);
if ( ntStatus == STATUS_PENDING )
{
status = KeWaitForSingleObject(&event,Suspended,KernelMode,FALSE,pTimeout);
//
// If the request timed out cancel the request
// and wait for it to complete
//
if ( status == STATUS_TIMEOUT ) {
#ifdef MYDEBUG
DbgPrint("Call_USBD: Cancelling IRP %X because of timeout\n", irp);
#endif
IoCancelIrp(irp);
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
}
ntStatus = irp->IoStatus.Status;
}
IoFreeIrp(irp);
USBPRINT_KdPrint2 (("USBPRINT.SYS: exit USBPRINT_CallUSBD (%x)\n", ntStatus));
USBPRINT_KdPrint3 (("USBPRINT.SYS: About to return from CallUSBD, status=%x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBPRINT_ConfigureDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Initializes a given instance of the device on the USB and selects the configuration.
Arguments:
DeviceObject - pointer to the device object for this printer devcice.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus;
PURB urb;
ULONG siz;
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
LARGE_INTEGER timeOut;
int tries=0;
timeOut.QuadPart = FAILURE_TIMEOUT;
USBPRINT_KdPrint2 (("USBPRINT.SYS: enter USBPRINT_ConfigureDevice\n"));
deviceExtension = DeviceObject->DeviceExtension;
//
// first configure the device
//
urb = ExAllocatePoolWithTag(NonPagedPool,sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), USBP_TAG);
if (urb)
{
siz = sizeof(USB_CONFIGURATION_DESCRIPTOR)+256;
get_config_descriptor_retry:
configurationDescriptor = ExAllocatePoolWithTag(NonPagedPool,siz, USBP_TAG);
if (configurationDescriptor)
{
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
configurationDescriptor,
NULL,
siz,
NULL);
ntStatus = USBPRINT_CallUSBD(DeviceObject, urb, &timeOut);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: Get Configuration descriptor failed\n"));
}
else
{
//
// if we got some data see if it was enough.
//
// NOTE: we may get an error in URB because of buffer overrun
if (urb->UrbControlDescriptorRequest.TransferBufferLength>0 &&configurationDescriptor->wTotalLength > siz)
{
#define MAX_MEM_FOR_DESCRIPTOR 1024 * 25
if((siz>MAX_MEM_FOR_DESCRIPTOR)||((tries++)==10))
{
USBPRINT_KdPrint3 (("USBPRINT.SYS: ConfigureDevice, this device appears to be lying to us about descriptor size\n"));
ExFreePool(configurationDescriptor);
configurationDescriptor = NULL;
ntStatus=STATUS_DEVICE_CONFIGURATION_ERROR;
}
else
{
siz = configurationDescriptor->wTotalLength;
ExFreePool(configurationDescriptor);
configurationDescriptor = NULL;
goto get_config_descriptor_retry;
}
} //end if not big enough
} //end else we got some sort of descriptor
USBPRINT_KdPrint3 (("USBPRINT.SYS: Configuration Descriptor = %x, len %x\n",
configurationDescriptor,
urb->UrbControlDescriptorRequest.TransferBufferLength));
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
USBPRINT_KdPrint1(("USBPRINT.SYS: Insufficient resources to allocate configuration descriptor in ConfigureDevice\n"));
}
ExFreePool(urb);
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (configurationDescriptor)
{
USBPRINT_KdPrint2(("USBPRINT.SYS: ConfigureDevice, We have a configuration descriptor!\n"));
//
// We have the configuration descriptor for the configuration
// we want.
//
// Now we issue the select configuration command to get
// the pipes associated with this configuration.
//
if(NT_SUCCESS(ntStatus))
{
ntStatus = USBPRINT_SelectInterface(DeviceObject,configurationDescriptor);
}
ExFreePool(configurationDescriptor);
}
else
{
USBPRINT_KdPrint1(("USBPRINT.SYS: ConfigureDevice, No Configuration descriptor.\n"));
}
USBPRINT_KdPrint2 (("USBPRINT.SYS: exit USBPRINT_ConfigureDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS USBPRINT_SelectInterface(IN PDEVICE_OBJECT DeviceObject,IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
/*++
Routine Description:
Initializes a printer with multiple interfaces
Arguments:
DeviceObject - pointer to the device object for this printer
ConfigurationDescriptor - pointer to the USB configuration
descriptor containing the interface and endpoint
descriptors.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus;
PURB urb = NULL;
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = NULL;
PUSBD_INTERFACE_INFORMATION Interface = NULL;
USBD_INTERFACE_LIST_ENTRY InterfaceList[2];
LARGE_INTEGER timeOut;
timeOut.QuadPart = FAILURE_TIMEOUT;
USBPRINT_KdPrint2 (("USBPRINT.SYS: enter USBPRINT_SelectInterface\n"));
deviceExtension = DeviceObject->DeviceExtension;
//starting at offset 0, search for an alternate interface with protocol code 2; Ignore InterfaceNumber, AlternateSetting, InterfaceClass, InterfaceSubClass
interfaceDescriptor=USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor,ConfigurationDescriptor,-1,-1,-1,-1,2);
if(!interfaceDescriptor)
{
USBPRINT_KdPrint3 (("USBPRINT.SYS: First ParseConfigurationDescriptorEx failed\n"));
interfaceDescriptor=USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor,ConfigurationDescriptor,-1,-1,-1,-1,1);
if(!interfaceDescriptor)
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: second ParseConfigurationDescriptorEx failed\n"));
ntStatus=STATUS_DEVICE_CONFIGURATION_ERROR;
}
else
{
USBPRINT_KdPrint3 (("USBPRINT.SYS: second ParseConfigurationDescriptorEx success\n"));
deviceExtension->bReadSupported=FALSE;
} /*end second ParseConfigDescriptor worked*/
}
else
{
deviceExtension->bReadSupported=TRUE;
USBPRINT_KdPrint3 (("USBPRINT.SYS: First ParseConfigurationDescriptorEx success\n"));
}
if(interfaceDescriptor)
{
InterfaceList[0].InterfaceDescriptor=interfaceDescriptor;
InterfaceList[1].InterfaceDescriptor=NULL;
urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor,InterfaceList);
if (urb)
{
Interface = InterfaceList[0].Interface;
ntStatus = USBPRINT_CallUSBD(DeviceObject, urb, &timeOut);
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
USBPRINT_KdPrint1 (("USBPRINT.SYS: CreateConfigurationRequest failed\n"));
}
} //end found good interface
else
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: failed to locate apropriate interface\n"));
} //end no interface
if (NT_SUCCESS(ntStatus))
{
//
// Save the configuration handle for this device
//
USBPRINT_KdPrint3 (("USBPRINT.SYS: SelectInterface, Inside good config case\n"));
deviceExtension->ConfigurationHandle = urb->UrbSelectConfiguration.ConfigurationHandle;
deviceExtension->Interface = ExAllocatePoolWithTag(NonPagedPool,Interface->Length, USBP_TAG);
if (deviceExtension->Interface)
{
ULONG j;
//
// save a copy of the interface information returned
//
RtlCopyMemory(deviceExtension->Interface, Interface, Interface->Length);
//
// Dump the interface to the debugger
//
USBPRINT_KdPrint3 (("USBPRINT.SYS: ---------\n"));
USBPRINT_KdPrint3 (("USBPRINT.SYS: NumberOfPipes 0x%x\n", deviceExtension->Interface->NumberOfPipes));
USBPRINT_KdPrint3 (("USBPRINT.SYS: Length 0x%x\n", deviceExtension->Interface->Length));
USBPRINT_KdPrint3 (("USBPRINT.SYS: Alt Setting 0x%x\n", deviceExtension->Interface->AlternateSetting));
USBPRINT_KdPrint3 (("USBPRINT.SYS: Interface Number 0x%x\n", deviceExtension->Interface->InterfaceNumber));
USBPRINT_KdPrint3 (("USBPRINT.SYS: Class, subclass, protocol 0x%x 0x%x 0x%x\n",
deviceExtension->Interface->Class,
deviceExtension->Interface->SubClass,
deviceExtension->Interface->Protocol));
// Dump the pipe info
for (j=0; j<Interface->NumberOfPipes; j++)
{
PUSBD_PIPE_INFORMATION pipeInformation;
pipeInformation = &deviceExtension->Interface->Pipes[j];
USBPRINT_KdPrint3 (("USBPRINT.SYS: ---------\n"));
USBPRINT_KdPrint3 (("USBPRINT.SYS: PipeType 0x%x\n", pipeInformation->PipeType));
USBPRINT_KdPrint3 (("USBPRINT.SYS: EndpointAddress 0x%x\n", pipeInformation->EndpointAddress));
USBPRINT_KdPrint3 (("USBPRINT.SYS: MaxPacketSize 0x%x\n", pipeInformation->MaximumPacketSize));
USBPRINT_KdPrint3 (("USBPRINT.SYS: Interval 0x%x\n", pipeInformation->Interval));
USBPRINT_KdPrint3 (("USBPRINT.SYS: Handle 0x%x\n", pipeInformation->PipeHandle));
USBPRINT_KdPrint3 (("USBPRINT.SYS: MaximumTransferSize 0x%x\n", pipeInformation->MaximumTransferSize));
}
USBPRINT_KdPrint3 (("USBPRINT.SYS: ---------\n"));
} /*end if interface Alloc OK*/
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
USBPRINT_KdPrint1 (("USBPRINT.SYS: Alloc failed in SelectInterface\n"));
}
}
if (urb)
{
ExFreePool(urb);
}
USBPRINT_KdPrint2 (("USBPRINT.SYS: exit USBPRINT_SelectInterface (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USBPRINT_BuildPipeList(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Arguments:
DeviceObject - pointer to the device object for this printer
devcice.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
ULONG i;
WCHAR Name[] = L"\\PIPE00";
PUSBD_INTERFACE_INFORMATION InterfaceDescriptor;
BOOL bFoundWritePipe=FALSE,bFoundReadPipe=FALSE,bNeedReadPipe=FALSE;
deviceExtension = DeviceObject->DeviceExtension;
InterfaceDescriptor = deviceExtension->Interface;
USBPRINT_KdPrint2 (("USBPRINT.SYS: enter USBPRINT_BuildPipeList\n"));
deviceExtension = DeviceObject->DeviceExtension;
if(InterfaceDescriptor->Protocol==2)
bNeedReadPipe=TRUE;
else
bNeedReadPipe=FALSE;
for (i=0; i<InterfaceDescriptor->NumberOfPipes; i++) {
USBPRINT_KdPrint3 (("USBPRINT.SYS: about to look at endpoint with address 0x%x)\n",InterfaceDescriptor->Pipes[i].EndpointAddress));
if(((InterfaceDescriptor->Pipes[i].EndpointAddress)&0x80)==0) //if bit 7 is 0, it's an OUT endpoint
{
if(bFoundWritePipe==TRUE)
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: Warning!! Multiple OUT pipes detected on printer. Defaulting to first pipe\n"));
} /*end if we've already found a write pipe*/
else
{
USBPRINT_KdPrint3 (("USBPRINT.SYS: Found write pipe\n"));
deviceExtension->pWritePipe=&(InterfaceDescriptor->Pipes[i]);
bFoundWritePipe=TRUE;
} /*else we haven't seen an OUT endpont before*/
} /*end if it's an OUT endpoint*/
else
{
if(!bNeedReadPipe)
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: Warning!! unexpected IN pipe (not specified in protocol field)\n"));
} /*end if we don't need a read pipe, but we found one*/
else if(bFoundReadPipe)
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: Warning!! Multiple IN pipes detected on printer. Defaulting to first pipe\n"));
} /*end if we've already found a read pipe*/
else
{
USBPRINT_KdPrint3 (("USBPRINT.SYS: Found read pipe\n"));
deviceExtension->pReadPipe=&(InterfaceDescriptor->Pipes[i]);
bFoundReadPipe=TRUE;
} /*end else we're supposed to have an IN pipe, and this is the first one we've seen*/
} /*end else it's an IN endpoint*/
} /*end for*/
if((bNeedReadPipe==TRUE)&&(bFoundReadPipe==FALSE))
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: Warning!! IN pipe was specified in protocol field, but was not found\n"));
} /*end if we needed a read pipe, and didn't find one*/
deviceExtension->bReadPipeExists=bFoundReadPipe;
return STATUS_SUCCESS;
} /*end function BuildPipeList*/
NTSTATUS
USBPRINT_ResetPipe(
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_PIPE_INFORMATION Pipe,
IN BOOLEAN IsoClearStall
)
/*++
Routine Description:
Reset a given USB pipe.
NOTES:
This will reset the host to Data0 and should also reset the device
to Data0 for Bulk and Interrupt pipes.
For Iso pipes this will set the virgin state of pipe so that ASAP
transfers begin with the current bus frame instead of the next frame
after the last transfer occurred.
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus;
PURB urb;
LARGE_INTEGER timeOut;
timeOut.QuadPart = FAILURE_TIMEOUT;
USBPRINT_KdPrint2 (("USBPRINT.SYS: Entering Reset Pipe; pipe # %x\n", Pipe));
urb = ExAllocatePoolWithTag(NonPagedPool,sizeof(struct _URB_PIPE_REQUEST), USBP_TAG);
if (urb) {
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
urb->UrbPipeRequest.PipeHandle =
Pipe->PipeHandle;
ntStatus = USBPRINT_CallUSBD(DeviceObject, urb, &timeOut);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1(("USBPRINT.SYS: CallUSBD failed in ResetPipe\n"));
}
else
{
USBPRINT_KdPrint3(("USBPRINT.SYS: CallUSBD Succeeded in ResetPipe\n"));
}
ExFreePool(urb);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
//
// Memphis RESET_PIPE will send a Clear-Feature Endpoint Stall to
// reset the data toggle of non-Iso pipes as part of a RESET_PIPE
// request. It does not do this for Iso pipes as Iso pipes do not use
// the data toggle (all Iso packets are Data0). However, we also use
// the Clear-Feature Endpoint Stall request in our device firmware to
// reset data buffer points inside the device so we explicitly send
// this request to the device for Iso pipes if desired.
//
if (NT_SUCCESS(ntStatus) && IsoClearStall &&
(Pipe->PipeType == UsbdPipeTypeIsochronous)) {
urb = ExAllocatePoolWithTag(NonPagedPool,sizeof(struct _URB_CONTROL_FEATURE_REQUEST), USBP_TAG);
if (urb) {
UsbBuildFeatureRequest(urb,
URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT,
USB_FEATURE_ENDPOINT_STALL,
Pipe->EndpointAddress,
NULL);
ntStatus = USBPRINT_CallUSBD(DeviceObject, urb, &timeOut);
ExFreePool(urb);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
return ntStatus;
}
LONG
USBPRINT_DecrementIoCount(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION deviceExtension;
LONG ioCount=0;
deviceExtension = DeviceObject->DeviceExtension;
if(!(deviceExtension->IsChildDevice))
{
ioCount = InterlockedDecrement(&deviceExtension->PendingIoCount);
#ifdef MYDEBUG
DbgPrint("USBPRINT_DecrementIoCount -- IoCount %d\n", deviceExtension->PendingIoCount);
#endif
USBPRINT_KdPrint3 (("USBPRINT.SYS: Pending io count = %x\n", ioCount));
if (ioCount==0) {
KeSetEvent(&deviceExtension->RemoveEvent,
1,
FALSE);
}
} /*end if ! child device*/
return ioCount;
}
VOID
USBPRINT_IncrementIoCount(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION deviceExtension;
deviceExtension = DeviceObject->DeviceExtension;
if(!(deviceExtension->IsChildDevice))
{
InterlockedIncrement(&deviceExtension->PendingIoCount);
#ifdef MYDEBUG
DbgPrint("USBPRINT_IncrementIoCount -- IoCount %d\n", deviceExtension->PendingIoCount);
#endif
//
// Everytime iocount goes to 0 we set this event
// so we must cleat it when we have a new io
//
KeClearEvent(&deviceExtension->RemoveEvent);
}
}
NTSTATUS
USBPRINT_ReconfigureDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Initializes a given instance of the device on the USB and selects the
configuration.
Arguments:
DeviceObject - pointer to the device object for this printer
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
PUSBD_INTERFACE_INFORMATION InterfaceDescriptor;
USBPRINT_KdPrint2 (("USBPRINT.SYS: enter USBPRINT_ReconfigureDevice\n"));
deviceExtension = DeviceObject->DeviceExtension;
if (NT_SUCCESS(ntStatus)) {
ntStatus = USBPRINT_ConfigureDevice(DeviceObject);
}
//
// new InterfaceDescriptor structure is now set up
//
InterfaceDescriptor = deviceExtension->Interface;
//
// set up the pipe handles again
//
return ntStatus;
}
NTSTATUS LoadPortsUsed(GUID *pPrinterGuid,PFREE_PORTS * pPortList,WCHAR *wcBaseName)
{
NTSTATUS ReturnStatus=STATUS_SUCCESS,Result=STATUS_SUCCESS;
PWSTR pDeviceList;
PWSTR pWalk;
UNICODE_STRING wNumberValueName,wBaseValueName,wLinkName;
ULONG ulPortNum;
ULONG ulBaseNameSizeIn,ulBaseNameSizeOut,ulPortNumSizeIn,ulPortNumSizeOut;
PKEY_VALUE_PARTIAL_INFORMATION pBaseValueStruct,pNumberValueStruct;
HANDLE hInterfaceKey;
BOOL bFoundUsbPort;
Result=IoGetDeviceInterfaces(pPrinterGuid,NULL,DEVICE_INTERFACE_INCLUDE_NONACTIVE,&pDeviceList);
if(Result==STATUS_SUCCESS)
{
RtlInitUnicodeString(&wNumberValueName,PORT_NUM_VALUE_NAME);
RtlInitUnicodeString(&wBaseValueName,PORT_BASE_NAME);
pWalk=pDeviceList;
ulBaseNameSizeIn=sizeof(KEY_VALUE_PARTIAL_INFORMATION)+((wcslen(wcBaseName)+1)*sizeof(WCHAR)); //this is a byte to much. Oh well
ulPortNumSizeIn=sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG);
pBaseValueStruct=ExAllocatePoolWithTag(NonPagedPool,ulBaseNameSizeIn, USBP_TAG);
pNumberValueStruct=ExAllocatePoolWithTag(NonPagedPool,ulPortNumSizeIn, USBP_TAG);
if((pBaseValueStruct!=NULL)&&(pNumberValueStruct!=NULL))
{
while( *pWalk!=0 && NT_SUCCESS(ReturnStatus) )
{
RtlInitUnicodeString(&wLinkName,pWalk);
Result=IoOpenDeviceInterfaceRegistryKey(&wLinkName,KEY_ALL_ACCESS,&hInterfaceKey);
if(NT_SUCCESS(Result))
{
//The following is: If there is not a value, or there is a value that matches what we expect, then set bFoundUsbPort to true
bFoundUsbPort=TRUE;
Result=ZwQueryValueKey(hInterfaceKey,&wBaseValueName,KeyValuePartialInformation,pBaseValueStruct,ulBaseNameSizeIn,&ulBaseNameSizeOut);
if(NT_SUCCESS(Result))
{
if(wcscmp(wcBaseName,(WCHAR *)(pBaseValueStruct->Data))!=0)
bFoundUsbPort=FALSE;
}//end if Query OK
else if(STATUS_OBJECT_NAME_NOT_FOUND!=Result)
{
bFoundUsbPort=FALSE;
}
if(bFoundUsbPort)
{
Result=ZwQueryValueKey(hInterfaceKey,&wNumberValueName,KeyValuePartialInformation,pNumberValueStruct,ulPortNumSizeIn,&ulPortNumSizeOut);
if(NT_SUCCESS(Result))
{
ulPortNum=*((ULONG *)(pNumberValueStruct->Data));
if(!bDeleteIfRecyclable(hInterfaceKey))
{
USBPRINT_KdPrint2(("USBPRINT.SYS: Adding port number\n"));
ReturnStatus=bAddPortInUseItem(pPortList,ulPortNum);
if(!NT_SUCCESS(ReturnStatus))
{
USBPRINT_KdPrint1(("USBPRINT.SYS: Unable to add port %u to port list\n",ulPortNum));
USBPRINT_KdPrint1(("USBPRINT.SYS: Failing out of LoadPortsUsed due to ntstatus failure %d\n",ReturnStatus));
} //end if AddPortInUse failed
} //end if port not deleted
else
{
// ReturnStatus=STATUS_INVALID_PARAMETER;
USBPRINT_KdPrint1(("USBPRINT.SYS: Invalid port number %u\n",ulPortNum));
}
} //end if Query Port Number OK
//no else. If there's no port number, we ignore this interface
} //End if bFoundUSbPort
ZwClose(hInterfaceKey);
} //end if OpenReg ok
pWalk=pWalk+wcslen(pWalk)+1;
} //end while
} //end ExAllocatePool OK
else
{
USBPRINT_KdPrint1(("USBPRINT.SYS: Unable to allocate memory"));
ReturnStatus=STATUS_INSUFFICIENT_RESOURCES;
} /*end else ExAllocatePool failed*/
if(pBaseValueStruct!=NULL)
ExFreePool(pBaseValueStruct);
if(pNumberValueStruct!=NULL)
ExFreePool(pNumberValueStruct);
ExFreePool(pDeviceList);
} /*end if IoGetDeviceInterfaces success*/
else
{
USBPRINT_KdPrint1(("USBPRINT.SYS: IoGetDeviceInterfaces failed"));
ReturnStatus=Result; //do some error translation here?
}
return ReturnStatus;
} /*end function LoadPortsUsed*/
NTSTATUS GetPortNumber(HANDLE hInterfaceKey,
ULONG *ulReturnNumber)
{
ULONG ulPortNumber,ulSizeUsed;
NTSTATUS ntStatus=STATUS_SUCCESS;
UNICODE_STRING uncValueName;
PKEY_VALUE_PARTIAL_INFORMATION pValueStruct;
ulSizeUsed=sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG); //this is a byte to much. Oh well
pValueStruct=ExAllocatePoolWithTag(PagedPool,ulSizeUsed, USBP_TAG);
if(pValueStruct==NULL)
return STATUS_INSUFFICIENT_RESOURCES;
RtlInitUnicodeString(&uncValueName,PORT_NUM_VALUE_NAME);
ntStatus=ZwQueryValueKey(hInterfaceKey,&uncValueName,KeyValuePartialInformation,(PVOID)pValueStruct,ulSizeUsed,&ulSizeUsed);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint2(("USBPRINT.SYS: GetPortNumber; ZwQueryValueKey failed\n"));
switch(ntStatus)
{
case STATUS_BUFFER_OVERFLOW:
USBPRINT_KdPrint2(("USBPRINT.SYS: GetPortNumber zwQueryValueKey returned STATUS_BUFFER_OVERFLOW\n"));
break;
case STATUS_INVALID_PARAMETER:
USBPRINT_KdPrint2(("USBPRINT.SYS: GetPortNumber zwQueryValueKey returned STATUS_INVALID_PARAMETER\n"));
break;
case STATUS_OBJECT_NAME_NOT_FOUND:
USBPRINT_KdPrint2(("USBPRINT.SYS: GetPortNumber zwQueryValueKey returned STATUS_OBJECT_NAME_NOT_FOUND\n"));
break;
default:
USBPRINT_KdPrint2(("USBPRINT.SYS: GetPortNumber zwQueryValueKey returned unkown error\n"));
}
ntStatus=GetNewPortNumber(&pGPortList,&ulPortNumber);
}
else
{
ulPortNumber=*((ULONG *)&(pValueStruct->Data));
if(ulPortNumber==0) //zero is a placeholder for "not there" which we use because win9x is missing the zwDeleteValueKey api
ntStatus=GetNewPortNumber(&pGPortList,&ulPortNumber);
else
vClaimPortNumber(ulPortNumber,hInterfaceKey,&pGPortList);
}
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1(("USBPRINT.SYS: GetPortNumber; failed to allocate new port number\n"));
}
else
{
*ulReturnNumber=ulPortNumber;
USBPRINT_KdPrint3(("USBPRINT.SYS: GetPortNumber; Inside \"write back to reg\" case, ulPortNumber==%d\n",ulPortNumber));
USBPRINT_KdPrint3(("USBPRINT.SYS: GetPortNumber; Before ntstatys=success\n"));
ntStatus=STATUS_SUCCESS;
USBPRINT_KdPrint3(("USBPRINT.SYS: GetPortNumber; Before ZwSetValueKey\n"));
ntStatus=ZwSetValueKey(hInterfaceKey,&uncValueName,0,REG_DWORD,&ulPortNumber,sizeof(ulPortNumber));
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1(("USBPRINT.SYS: GetPortNumber; Unable to set value key\n"));
}
else
{
*ulReturnNumber=ulPortNumber;
}
}
ExFreePool(pValueStruct);
return ntStatus;
} /*end function GetPortNumber*/
USBPRINT_GetDeviceID(PDEVICE_OBJECT ParentDeviceObject)
{
UCHAR *p1284Id;
NTSTATUS ntStatus;
int iReturnSize;
PDEVICE_EXTENSION pParentExtension;
pParentExtension=ParentDeviceObject->DeviceExtension;
USBPRINT_KdPrint1 (("USBPRINT.SYS: GetDeviceID enter\n")); /*dd*/
p1284Id=ExAllocatePoolWithTag(NonPagedPool,MAX_ID_SIZE, USBP_TAG);
if(p1284Id==NULL)
{
pParentExtension->bBadDeviceID=TRUE;
USBPRINT_KdPrint1 (("USBPRINT.SYS: Memory Allocation failed in GetDeviceID\n"));
sprintf(pParentExtension->DeviceIdString,BOGUS_PNP_ID);
}
else
{
iReturnSize=USBPRINT_Get1284Id(ParentDeviceObject,p1284Id,MAX_ID_SIZE-ID_OVERHEAD); //
if(iReturnSize==-1)
{
pParentExtension->bBadDeviceID=TRUE;
USBPRINT_KdPrint1 (("USBPRINT.SYS: Get1284Id Failed\n"));
sprintf(pParentExtension->DeviceIdString,BOGUS_PNP_ID);
} /*end if Get1284 failed*/
else
{
USBPRINT_KdPrint3 (("USBPRINT.SYS: Get1284Id Succeeded\n"));
USBPRINT_KdPrint2 (("USBPRINT.SYS: 1284 ID == %s\n",(p1284Id+2)));
ntStatus=ParPnpGetId(p1284Id+2,BusQueryDeviceID,pParentExtension->DeviceIdString);
USBPRINT_KdPrint3 (("USBPRINT.SYS: After call to ParPnpGetId"));
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: ParPnpGetId failed, error== 0x%0X\n",ntStatus));
sprintf(pParentExtension->DeviceIdString,BOGUS_PNP_ID);
pParentExtension->bBadDeviceID=TRUE;
}
else
{
USBPRINT_KdPrint3 (("USBPRINT.SYS: After ParPnpGetID\n"));
USBPRINT_KdPrint2 (("USBPRINT.SYS: DeviceIdString=%s\n",pParentExtension->DeviceIdString));
}
} /*end if the request didn't fail*/
ExFreePool(p1284Id);
}
USBPRINT_KdPrint2 (("USBPRINT.SYS: GetDeviceID exit\n"));
} /*end function USBPRINT_GetDeviceID*/
NTSTATUS ProduceQueriedID(PDEVICE_EXTENSION deviceExtension,PIO_STACK_LOCATION irpStack,PIRP Irp,PDEVICE_OBJECT DeviceObject)
{
PDEVICE_EXTENSION pParentExtension;
NTSTATUS ntStatus=STATUS_SUCCESS;
WCHAR wTempString1[30];
PWSTR pWalk;
HANDLE hChildRegKey;
UCHAR *pRawString,*pTempString;
UNICODE_STRING UnicodeDeviceId;
UNICODE_STRING uncPortValueName;
ANSI_STRING AnsiIdString;
PCHILD_DEVICE_EXTENSION pChildExtension;
int iReturnSize;
int iFirstLen,iSecondLen, iTotalLen;
pChildExtension=(PCHILD_DEVICE_EXTENSION)deviceExtension;
pParentExtension=pChildExtension->ParentDeviceObject->DeviceExtension;
USBPRINT_KdPrint1(("USBPRINT.SYS: head of ProduceQueriedID\n")); /*dd*/
pRawString=ExAllocatePool(NonPagedPool,MAX_ID_SIZE);
pTempString=ExAllocatePool(NonPagedPool,MAX_ID_SIZE);
if((pTempString==NULL)||(pRawString==NULL))
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: BusQueryDeviceIDs; No memory. Failing\n"));
ntStatus=STATUS_NO_MEMORY;
iReturnSize=-1;
}
else
{
if(pParentExtension->DeviceIdString[0]!=0)
{
switch(irpStack->Parameters.QueryId.IdType)
{
case BusQueryDeviceID:
USBPRINT_KdPrint1 (("USBPRINT.SYS: Received BusQueryDeviceID message\n"));
sprintf(pRawString,"USBPRINT\\%s",pParentExtension->DeviceIdString); //this sprintf safe.. DeviceIDString guaranteed to be 15 less than RawString
FixupDeviceId((PUCHAR)pRawString);
RtlInitAnsiString(&AnsiIdString,pRawString);
if(!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeDeviceId,&AnsiIdString,TRUE))) //Make a unicode string out of this
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: RtlAnsiStringToUnicodeString failed\n"));
ntStatus=STATUS_NO_MEMORY;
iReturnSize=-1;
Irp->IoStatus.Information=0;
break;
}
ntStatus=STATUS_SUCCESS;
Irp->IoStatus.Information=(ULONG_PTR)UnicodeDeviceId.Buffer;
USBPRINT_KdPrint1(("USBPRINT.SYS: returing DeviceID\n")); /*dd*/
break;
case BusQueryInstanceID:
USBPRINT_KdPrint2 (("USBPRINT.SYS: Received BusQueryInstanceID message\n"));
USBPRINT_KdPrint2 (("USBPRINT.SYS: returning instance %u\n",pChildExtension->ulInstanceNumber));
sprintf(pRawString,"USB%03u",pChildExtension->ulInstanceNumber);
USBPRINT_KdPrint2 (("USBPRINT.SYS: RawString=%s\n",pRawString));
RtlInitAnsiString(&AnsiIdString,pRawString);
if(!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeDeviceId,&AnsiIdString,TRUE))) //Make a unicode string out of this
{
ntStatus=STATUS_NO_MEMORY;
iReturnSize=-1;
Irp->IoStatus.Information=0;
break;
}
ntStatus=STATUS_SUCCESS;
Irp->IoStatus.Information=(ULONG_PTR)UnicodeDeviceId.Buffer;
break;
case BusQueryHardwareIDs:
USBPRINT_KdPrint2 (("USBPRINT.SYS: Received BusQueryHardwareIDs message\n"));
#ifndef WIN9XBUILD
USBPRINT_KdPrint2 (("USBPRINT.SYS: inside IF NT\n"));
ntStatus=IoOpenDeviceRegistryKey(DeviceObject,PLUGPLAY_REGKEY_DEVICE,KEY_ALL_ACCESS,&hChildRegKey);
#else
USBPRINT_KdPrint2 (("USBPRINT.SYS: inside not NT\n"));
ntStatus=IoOpenDeviceRegistryKey(pParentExtension->PhysicalDeviceObject,PLUGPLAY_REGKEY_DEVICE,KEY_ALL_ACCESS,&hChildRegKey);
#endif
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: BusQueryHardwareIDs; IoOpenDeviceRegistryKey failed\n"));
break;
}
swprintf(wTempString1,L"USB%03u",pChildExtension->ulInstanceNumber);
RtlInitUnicodeString(&uncPortValueName,L"PortName");
ntStatus=ZwSetValueKey(hChildRegKey,&uncPortValueName,0,REG_SZ,wTempString1,(wcslen(wTempString1)+1)*sizeof(WCHAR));
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: BusQueryHardwareIDs; ZwSetValueKey failed\n"));
}
else
{
USBPRINT_KdPrint3 (("USBPRINT.SYS: BusQueryHardwareIDs; ZwSetValueKey worked, wcslen(wTempString1)==%u\n",wcslen(wTempString1)));
ntStatus=STATUS_SUCCESS;
}
ZwClose(hChildRegKey);
if(pParentExtension->DeviceIdString[0]==0)
{
ntStatus=STATUS_NOT_FOUND;
USBPRINT_KdPrint2 (("USBPRINT.SYS: BusQueryCompatibleIDs; DeviceIdString is null. Can't continue\n"));
break;
}
ntStatus=ParPnpGetId(pParentExtension->DeviceIdString,irpStack->Parameters.QueryId.IdType,pRawString);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1 (("USBPRINT.SYS: BusQueryDeviceIDs; ParPnpGetID failed\n"));
break;
}
if((strlen(pRawString)+ID_OVERHEAD)*2>MAX_ID_SIZE)
{
ntStatus=STATUS_NO_MEMORY;
USBPRINT_KdPrint1 (("USBPRINT.SYS: BusQueryDeviceIDs; ID's to long. Failing\n"));
iReturnSize=-1;
break;
}
sprintf(pTempString,"USBPRINT\\%s",pRawString);
iFirstLen=strlen(pTempString);
*(pTempString+iFirstLen)=' '; //make the old null be a space so that RtlInitAnsiString will step past it
*(pTempString+iFirstLen+1)='\0'; //add an extra null at the end of the string
strcat(pTempString,pRawString);
iTotalLen=strlen(pTempString);
#ifdef USBPRINT_LIE_ABOUT_LPT
*(pTempString+iTotalLen)=' ';
*(pTempString+iTotalLen+1)='\0';
iSecondLen=iTotalLen;
strcat(pTempString,"LPTENUM\\");
strcat(pTempString,pRawString);
iTotalLen=strlen(pTempString);
#endif
*(pTempString+iTotalLen)=' ';
*(pTempString+iTotalLen+1)='\0';
FixupDeviceId((PUCHAR)pTempString);
RtlInitAnsiString(&AnsiIdString,pTempString); //make a counted ansi string
if(!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeDeviceId,&AnsiIdString,TRUE))) //Make a unicode string out of this
{
ntStatus=STATUS_NO_MEMORY;
iReturnSize=-1;
Irp->IoStatus.Information=0;
break;
}
pWalk = UnicodeDeviceId.Buffer+iFirstLen; //Set a pointer to the beginning of the string
*pWalk=L'\0'; //set the space to be a unicode null
#ifdef USBPRINT_LIE_ABOUT_LPT
pWalk = UnicodeDeviceId.Buffer+iSecondLen; //Set a pointer to the beginning of the string
*pWalk=L'\0'; //set the space to be a unicode null
#endif
pWalk = UnicodeDeviceId.Buffer+iTotalLen; //set a pointer to the space at the end of the total string
*pWalk=L'\0'; //set the space to be a unicode null, so that we now have a double unicode null.
Irp->IoStatus.Information = (ULONG_PTR)UnicodeDeviceId.Buffer;
break;
case BusQueryCompatibleIDs:
USBPRINT_KdPrint2 (("USBPRINT.SYS: Received BusQueryCompatibleIDs message\n"));
Irp->IoStatus.Information = (ULONG_PTR) NULL; //(ULONG_PTR)UnicodeDeviceId.Buffer;
break;
default:
{
USBPRINT_KdPrint2 (("USBPRINT.SYS: Received unkown BusQuery message\n"));
ntStatus = Irp->IoStatus.Status;
}
} /*end switch ID type*/
} /*end no 1284 ID*/
else
{
ntStatus=STATUS_NOT_FOUND;
}
}
if(pTempString!=NULL)
ExFreePool(pTempString);
if(pRawString!=NULL)
ExFreePool(pRawString);
return ntStatus;
} /*End function QueryID*/
//
// Function: bAddPortInUseItem
//
// Description : iPortNumber is removed from the free ports list structure.
//
// Parameters: IN\OUT pFreePorts - is the beginning of the list and on return will contain the beginning of the list.
// pFreePorts may change during the call.
// IN iPortNumber - the port number that is in use.
//
// Returns: NTSTATUS value - STATUS_NO_MEMORY
// - STATUS_SUCCESS
//
NTSTATUS bAddPortInUseItem(PFREE_PORTS * pFreePorts,ULONG iPortNumber )
{
NTSTATUS ntstatus = STATUS_SUCCESS;
PFREE_PORTS pBefore = *pFreePorts;
PFREE_PORTS pHead = *pFreePorts;
PFREE_PORTS pNewBlock = NULL;
USBPRINT_KdPrint2 ((" USBPRINT.SYS: Head of bAddPortInUseItem\n"));
//
// Traverse the FREE_PORT structure to remove the port number from the list.
// Note - This function will not be needed to be called by anyone else other than LoadPortsUsed
// as the GetNewPortNumber will do this functionality automatically.
//
while( *pFreePorts )
{
if( iPortNumber >= (*pFreePorts)->iBottomOfRange && iPortNumber <= (*pFreePorts)->iTopOfRange )
{
// We're where we want to be - so decide what to do...
if( iPortNumber == (*pFreePorts)->iBottomOfRange )
{
if( (++((*pFreePorts)->iBottomOfRange)) > (*pFreePorts)->iTopOfRange )
{
// Case of the Port Number being the first and only element in the first block.
if( *pFreePorts == pHead )
{
pHead = (*pFreePorts)->pNextBlock;
}
else // Case of the Port Number being the first element in another block.
{
pBefore->pNextBlock = (*pFreePorts)->pNextBlock;
}
ExFreePool( *pFreePorts );
}
}
else
{
if( iPortNumber == (*pFreePorts)->iTopOfRange )
{ // Deletion case handled in the above case, so just need to decrement.
((*pFreePorts)->iTopOfRange)--;
}
else // Otherwise we're in the middle of the block and we need to split it.
{
pNewBlock = ExAllocatePoolWithTag( NonPagedPool, sizeof(FREE_PORTS), USBP_TAG);
if( !pNewBlock )
{
ntstatus = STATUS_NO_MEMORY;
goto Cleanup;
}
pNewBlock->iTopOfRange = (*pFreePorts)->iTopOfRange;
(*pFreePorts)->iTopOfRange = iPortNumber - 1;
pNewBlock->iBottomOfRange = iPortNumber + 1;
pNewBlock->pNextBlock = (*pFreePorts)->pNextBlock;
(*pFreePorts)->pNextBlock = pNewBlock;
}
}
break;
}
else
{
if( iPortNumber < (*pFreePorts)->iBottomOfRange )
{ // The port number has already been used - not in the free list.
USBPRINT_KdPrint2 ((" USBPRINT.SYS: Port number %n is allocated already from free list.\n", iPortNumber));
break;
}
pBefore = *pFreePorts;
*pFreePorts = (*pFreePorts)->pNextBlock;
}
}
if( NULL == *pFreePorts )
{
ntstatus = STATUS_INVALID_PARAMETER;
// Assert this as we could never allocate a port number that is not in the initial ranges 1-999
// - but if we assert here, we have run off the end of the port allocation numbers.
ASSERT( *pFreePorts );
}
Cleanup:
*pFreePorts = pHead;
return ntstatus;
} /*end function bAddPortInUseItem*/
void vClaimPortNumber(ULONG ulPortNumber,HANDLE hInterfaceKey,PFREE_PORTS * pPortsUsed)
{
UNICODE_STRING wRecycle;
WCHAR *pName;
pName=L"RECYCLABLE";
RtlInitUnicodeString(&wRecycle,pName);
#if WIN95_BUILD==1
SetValueToZero(hInterfaceKey,&wRecycle);
#else
ZwDeleteValueKey(hInterfaceKey,&wRecycle);
#endif
// Do we need to fail out gracefully from the below?
// The func doesn't have a return, but we could fail a mem alloc inside the below call!!
// bAddPortInUseItem(pPortsUsed,ulPortNumber);
} /*end function vClaimPortNumber*/
NTSTATUS GetNewPortNumber(PFREE_PORTS * pFreePorts, ULONG *pulPortNumber)
{
NTSTATUS ntstatus = STATUS_SUCCESS;
PFREE_PORTS pTemp = *pFreePorts;
USBPRINT_KdPrint2 (("USBPRINT.SYS: Head of GetNewPortNumber\n"));
if( NULL == *pFreePorts )
{
// If the pFreePorts list is empty - try to reconstruct it.
ntstatus=InitFreePorts(pFreePorts);
if(NT_SUCCESS(ntstatus))
ntstatus=LoadPortsUsed((GUID *)&USBPRINT_GUID,pFreePorts,USB_BASE_NAME);
if( NULL == *pFreePorts && NT_SUCCESS(ntstatus))
{
ntstatus=STATUS_INVALID_PORT_HANDLE;
}
if(!NT_SUCCESS(ntstatus))
{
*pulPortNumber = 0;
goto Cleanup;
}
}
*pulPortNumber = (*pFreePorts)->iBottomOfRange;
if( (++((*pFreePorts)->iBottomOfRange)) > (*pFreePorts)->iTopOfRange )
{
// Case of the Port Number being the first and only element in the first block.
*pFreePorts = (*pFreePorts)->pNextBlock;
ExFreePool( pTemp );
}
Cleanup:
return ntstatus;
} /*end function GetNewPortNumber*/
BOOL bDeleteIfRecyclable(HANDLE hRegKey)
{
BOOL bReturn=FALSE;
UNICODE_STRING wcValueName;
NTSTATUS ntStatus;
USBPRINT_KdPrint2 (("USBPRINT.SYS: Head of bDeleteifRecyclable\n"));
RtlInitUnicodeString(&wcValueName,L"recyclable");
#if WIN95_BUILD==1
ntStatus=SetValueToZero(hRegKey,&wcValueName);
#else
ntStatus=ZwDeleteValueKey(hRegKey,&wcValueName);
#endif
if(NT_SUCCESS(ntStatus))
{
RtlInitUnicodeString(&wcValueName,L"Port Number");
#if WIN95_BUILD==1
ntStatus=SetValueToZero(hRegKey,&wcValueName);
#else
ntStatus=ZwDeleteValueKey(hRegKey,&wcValueName);
#endif
if(NT_SUCCESS(ntStatus))
bReturn=TRUE;
} // end function bDeleteIfRecyclable
if(bReturn)
{
USBPRINT_KdPrint3 (("USBPRINT.SYS: bDeleteIfRecyclable, returning TRUE\n"));
}
else
{
USBPRINT_KdPrint3 (("USBPRINT.SYS: bDeleteIfRecyclable, returning FALSE\n"));
}
return bReturn;
} //End function bDeleteIfRecycable
//
// Initialises the free ports structure list.
// pHead must be NULL or a valid pointer to a FREE_PORTS structure.
//
NTSTATUS InitFreePorts( PFREE_PORTS * pHead )
{
PFREE_PORTS pNext = *pHead;
NTSTATUS ntstatus = STATUS_SUCCESS;
while(pNext)
{
pNext = (*pHead)->pNextBlock;
ExFreePool(*pHead);
*pHead = pNext;
}
//
// Any old list will be cleared from memory and pHead will be NULL
//
*pHead = ExAllocatePoolWithTag(NonPagedPool, sizeof(FREE_PORTS), USBP_TAG);
if( *pHead )
{
(*pHead)->iBottomOfRange = MIN_PORT_NUMBER;
(*pHead)->iTopOfRange = MAX_PORT_NUMBER;
(*pHead)->pNextBlock = NULL;
}
else
ntstatus = STATUS_NO_MEMORY;
return ntstatus;
}
void ClearFreePorts( PFREE_PORTS * pHead )
{
PFREE_PORTS pTemp = *pHead;
while( *pHead )
{
*pHead = (*pHead)->pNextBlock;
ExFreePool( pTemp );
pTemp = *pHead;
}
}
/********************************************************
* SetValueToZero. Sets and interger reg key to zero.
* Returns failure if reg key does not exist, or if
* The key already is set to zero. Mimics ZwDeleteValueKey
* (which is not currently avaiable on Milinium) by
* useing the value 0 to mean deleted
**************************************************************/
NTSTATUS SetValueToZero(HANDLE hRegKey,PUNICODE_STRING ValueName)
{
PKEY_VALUE_PARTIAL_INFORMATION pValueStruct;
NTSTATUS ReturnCode;
ULONG dwZero=0;
ULONG ulSizeUsed;
NTSTATUS ntStatus;
int iValue;
ulSizeUsed=sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(ULONG); //this is a byte to much. Oh well
pValueStruct=ExAllocatePool(NonPagedPool,ulSizeUsed);
if(pValueStruct==NULL)
{
USBPRINT_KdPrint1(("USBPRINT.SYS: SetValueToZero; Unable to allocate memory\n"));
return STATUS_NO_MEMORY;
}
ntStatus=ZwQueryValueKey(hRegKey,ValueName,KeyValuePartialInformation,pValueStruct,ulSizeUsed,&ulSizeUsed);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint3(("Failed to Query value Key\n"));
ExFreePool(pValueStruct);
return STATUS_OBJECT_NAME_NOT_FOUND;
}
iValue=(int)*((ULONG *)(pValueStruct->Data));
ExFreePool(pValueStruct);
if(iValue==0)
return STATUS_OBJECT_NAME_NOT_FOUND;
//if we make it to here, the value exists, and is nonzero
ReturnCode=ZwSetValueKey(hRegKey,ValueName,0,REG_DWORD,&dwZero,sizeof(dwZero));
return ReturnCode;
} /*end function SetValueToZero*/
VOID
USBPRINT_FdoIdleNotificationCallback(IN PDEVICE_EXTENSION DevExt)
/*++
Routine Description:
Called when it is time to idle out USB printer
--*/
{
POWER_STATE powerState;
NTSTATUS ntStatus;
USBPRINT_KdPrint1(("USB Printer (%08X) going idle\n", DevExt));
if(!DevExt->AcceptingRequests || DevExt->OpenCnt)
{
// Don't idle this printer if the printer is not accepting requests
USBPRINT_KdPrint1(("USB Printer (%08X) not accepting requests, abort idle\n", DevExt));
return;
}
powerState.DeviceState = DevExt->DeviceWake;
// request new device power state, wait wake Irp will be posted on request
PoRequestPowerIrp(DevExt->PhysicalDeviceObject,
IRP_MN_SET_POWER,
powerState,
NULL,
NULL,
NULL);
} // USBPRINT_FdoIdleNotificationCallback
NTSTATUS
USBPRINT_FdoIdleNotificationRequestComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PDEVICE_EXTENSION DevExt
)
/*++
Routine Description:
Completion routine for the Idle request IRP for the USB printer device
--*/
{
NTSTATUS ntStatus;
PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
//
// DeviceObject is NULL because we sent the irp
//
UNREFERENCED_PARAMETER(DeviceObject);
USBPRINT_KdPrint1(("Idle notification IRP for USB Printer (%08X) completed (%08X)\n",
DevExt, Irp->IoStatus.Status));
// save completion status in device extension
idleCallbackInfo = DevExt->IdleCallbackInfo;
DevExt->IdleCallbackInfo = NULL;
DevExt->PendingIdleIrp = NULL;
// free up callback info
if(idleCallbackInfo)
{
ExFreePool(idleCallbackInfo);
}
ntStatus = Irp->IoStatus.Status;
return ntStatus;
} // USBPRINT_FdoIdleNotificationRequestComplete
NTSTATUS
USBPRINT_FdoSubmitIdleRequestIrp(IN PDEVICE_EXTENSION DevExt)
/*++
Routine Description:
Called when all handles to the USB printer are closed. This function allocates
an idle request IOCTL IRP and passes it to the parent's PDO.
--*/
{
PIRP irp = NULL;
NTSTATUS ntStatus = STATUS_SUCCESS;
PUSB_IDLE_CALLBACK_INFO idleCallbackInfo = NULL;
USBPRINT_KdPrint1(("USBPRINT_FdoSubmitIdleRequestIrp (%08X)\n", DevExt));
// if we have an Irp pending, don't bother to send another
if(DevExt->PendingIdleIrp || DevExt->CurrentDevicePowerState == DevExt->DeviceWake)
return ntStatus;
idleCallbackInfo = ExAllocatePoolWithTag(NonPagedPool,
sizeof(struct _USB_IDLE_CALLBACK_INFO), USBP_TAG);
if (idleCallbackInfo)
{
idleCallbackInfo->IdleCallback = USBPRINT_FdoIdleNotificationCallback;
idleCallbackInfo->IdleContext = (PVOID)DevExt;
DevExt->IdleCallbackInfo = idleCallbackInfo;
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION,
DevExt->PhysicalDeviceObject,
idleCallbackInfo,
sizeof(struct _USB_IDLE_CALLBACK_INFO),
NULL,
0,
TRUE, /* INTERNAL */
NULL,
NULL);
if (irp == NULL)
{
ExFreePool(idleCallbackInfo);
return STATUS_INSUFFICIENT_RESOURCES;
}
IoSetCompletionRoutine(irp,
USBPRINT_FdoIdleNotificationRequestComplete,
DevExt,
TRUE,
TRUE,
TRUE);
ntStatus = IoCallDriver(DevExt->PhysicalDeviceObject, irp);
if(ntStatus == STATUS_PENDING)
{
// Successfully posted an Idle IRP.
DevExt->PendingIdleIrp = irp;
}
}
return ntStatus;
} // USBPRINT_FdoSubmitIdleRequestIrp
VOID
USBPRINT_FdoRequestWake(IN PDEVICE_EXTENSION DevExt)
/*++
Routine Description:
Called when we want to wake up the device after an idle request
--*/
{
POWER_STATE powerState;
KIRQL OldIrql;
BOOL bExit=FALSE;
USBPRINT_KdPrint1(("USBPRINT: USB Printer (%08X) waking up\n", DevExt));
KeAcquireSpinLock(&(DevExt->WakeSpinLock),&OldIrql);
if(!DevExt->AcceptingRequests || DevExt->CurrentDevicePowerState == PowerDeviceD0 || DevExt->bD0IrpPending)
{
// Don't wake this printer if it's not accepting requests or we're already at power state D0
if(!DevExt->AcceptingRequests)
USBPRINT_KdPrint1(("USBPRINT: USB Printer (%08X) not accepting requests, abort wake\n", DevExt));
if(DevExt->CurrentDevicePowerState == PowerDeviceD0)
USBPRINT_KdPrint1(("USBPRINT: USB Printer (%08X) already at D0, abort wake\n", DevExt));
if(DevExt->bD0IrpPending == TRUE)
USBPRINT_KdPrint1(("USBPRINT: USB Printer (%08X) already has D0 irp pending, abort wake\n", DevExt));
bExit=TRUE;
}
else
DevExt->bD0IrpPending=TRUE;
KeReleaseSpinLock(&(DevExt->WakeSpinLock),OldIrql);
if(bExit)
return;
powerState.DeviceState = PowerDeviceD0;
// request new device power state, wake up the device
PoRequestPowerIrp(DevExt->PhysicalDeviceObject,
IRP_MN_SET_POWER,
powerState,
NULL,
NULL,
NULL);
} // USBPRINT_FdoRequestWake
void vOpenLogFile(HANDLE *pHandle)
{
NTSTATUS ntStatus;
OBJECT_ATTRIBUTES FileAttributes;
IO_STATUS_BLOCK StatusBlock;
UNICODE_STRING PathName;
RtlInitUnicodeString(&PathName,L"\\??\\C:\\USBPRINT.LOG");
InitializeObjectAttributes(&FileAttributes,&PathName,0,NULL,NULL);
ntStatus=ZwCreateFile(pHandle,
GENERIC_WRITE,
&FileAttributes,
&StatusBlock,
0,
0,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_NON_DIRECTORY_FILE|FILE_WRITE_THROUGH|FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1(("USBPRINT: Unable to open C:\\USBPRINT.LOG"));
}
else
{
USBPRINT_KdPrint1(("USBPRINT: Opened logfile C:\\USBPRINT.LOG")); /*dd*/
}
}
void vWriteToLogFile(HANDLE *pHandle,IN CHAR *pszString)
{
HANDLE hFileHandle;
ULONG BufferSize;
NTSTATUS ntStatus;
IO_STATUS_BLOCK StatusBlock;
LARGE_INTEGER WriteOffset;
WriteOffset.LowPart=FILE_WRITE_TO_END_OF_FILE;
WriteOffset.HighPart=-1;
BufferSize=strlen(pszString);
ntStatus=ZwWriteFile(*pHandle,
NULL,
NULL,
NULL,
&StatusBlock,
pszString,
BufferSize,
&WriteOffset,
NULL);
if(!NT_SUCCESS(ntStatus))
{
USBPRINT_KdPrint1(("USBPRINT: Unable to write to log file C:\\USBPRINT.LOG"));
}
else
{
USBPRINT_KdPrint1(("USBPRINT: write to log file C:\\USBPRINT.LOG")); /*dd*/
}
} /*end function vWriteToLog*/
void vCloseLogFile(IN HANDLE *pHandle)
{
ZwClose(*pHandle);
} /*end function vCloseLogFile*/