windows-nt/Source/XPSP1/NT/drivers/smartcrd/gempc430/usbdev.cpp
2020-09-26 16:20:57 +08:00

2343 lines
91 KiB
C++

#ifdef USBREADER_PROJECT
#ifndef USBDEVICE_PROJECT
#define USBDEVICE_PROJECT
#endif
#endif
#ifdef USBDEVICE_PROJECT
#pragma message("COMPILING USB DEVICE...")
#include "usbdev.h"
// GUID should be defined outside of any block!
#include "guid.h"
#include "thread.h"
#include "usbreader.h" //TO BE REMOVED
VOID onSendDeviceSetPowerComplete(PDEVICE_OBJECT junk, UCHAR fcn, POWER_STATE state, PPOWER_CONTEXT context, PIO_STATUS_BLOCK pstatus)
{// SendDeviceSetPowerComplete
context->status = pstatus->Status;
KeSetEvent(context->powerEvent, EVENT_INCREMENT, FALSE);
}// SendDeviceSetPowerComplete
#pragma PAGEDCODE
CUSBDevice::CUSBDevice()
{
m_Status = STATUS_INSUFFICIENT_RESOURCES;
INCLUDE_PNP_FUNCTIONS_NAMES();
INCLUDE_POWER_FUNCTIONS_NAMES();
m_Type = USB_DEVICE;
m_Flags |= DEVICE_SURPRISE_REMOVAL_OK;
m_MaximumTransferSize = GUR_MAX_TRANSFER_SIZE;
CommandBufferLength = DEFAULT_COMMAND_BUFFER_SIZE;
ResponseBufferLength = DEFAULT_RESPONSE_BUFFER_SIZE;
InterruptBufferLength = DEFAULT_INTERRUPT_BUFFER_SIZE;
// Register handlers processed by this device...
activatePnPHandler(IRP_MN_START_DEVICE);
activatePnPHandler(IRP_MN_QUERY_REMOVE_DEVICE);
activatePnPHandler(IRP_MN_REMOVE_DEVICE);
activatePnPHandler(IRP_MN_SURPRISE_REMOVAL);
activatePnPHandler(IRP_MN_CANCEL_REMOVE_DEVICE);
activatePnPHandler(IRP_MN_QUERY_STOP_DEVICE);
activatePnPHandler(IRP_MN_CANCEL_STOP_DEVICE);
activatePnPHandler(IRP_MN_STOP_DEVICE);
activatePnPHandler(IRP_MN_QUERY_CAPABILITIES);
// Register Power handlers processed by driver...
activatePowerHandler(IRP_MN_SET_POWER);
activatePowerHandler(IRP_MN_QUERY_POWER);
TRACE(" *** New USB device %8.8lX was created ***\n",this);
m_Status = STATUS_SUCCESS;
}
#pragma PAGEDCODE
CUSBDevice::~CUSBDevice()
{
waitForIdle();
TRACE(" USB device %8.8lX was destroyed ***\n",this);
}
// Function redirects all PnP requests
// This is main entry point for the system (after c wrapper).
// It handles locking device for a PnP requests and redirecting
// it to specific PnP handlers.
// In case of IRP_MN_REMOVE_DEVICE it leaves device locked till
// remove message recieved.
#pragma PAGEDCODE
NTSTATUS CUSBDevice::pnpRequest(IN PIRP Irp)
{
NTSTATUS status;
if (!NT_SUCCESS(acquireRemoveLock()))
{
TRACE("Failed to lock USB device...\n");
return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
}
PIO_STACK_LOCATION stack = irp->getCurrentStackLocation(Irp);
ASSERT(stack->MajorFunction == IRP_MJ_PNP);
ULONG fcn = stack->MinorFunction;
if (fcn >= arraysize(PnPfcntab))
{ // some function we don't know about
TRACE("Unknown PnP function at USB device...\n");
status = PnP_Default(Irp);
releaseRemoveLock();
return status;
}
#ifdef DEBUG
TRACE("PnP request (%s) \n", PnPfcnname[fcn]);
#endif
// Call real function to handle the request
status = PnPHandler(fcn,Irp);
// If we've got PnP request to remove->
// Keep device locked to prevent futher connections.
// Device will be unlocked and removed by driver later...
if (fcn != IRP_MN_REMOVE_DEVICE) releaseRemoveLock();
if(!NT_SUCCESS(status))
{
if(status != STATUS_NOT_SUPPORTED)
{
TRACE("\n******** PnP handler reported ERROR -> %x\n", status);
}
}
return status;
}
#pragma PAGEDCODE
// Main redirector of all PnP handlers...
NTSTATUS CUSBDevice::PnPHandler(LONG HandlerID,IN PIRP Irp)
{
// If Handler is not registered...
if (HandlerID >= arraysize(PnPfcntab)) return PnP_Default(Irp);
if(!PnPfcntab[HandlerID]) return PnP_Default(Irp);
// Call registered PnP Handler...
switch(HandlerID)
{
case IRP_MN_START_DEVICE: return PnP_HandleStartDevice(Irp);
break;
case IRP_MN_QUERY_REMOVE_DEVICE: return PnP_HandleQueryRemove(Irp);
break;
case IRP_MN_REMOVE_DEVICE: return PnP_HandleRemoveDevice(Irp);
break;
case IRP_MN_CANCEL_REMOVE_DEVICE: return PnP_HandleCancelRemove(Irp);
break;
case IRP_MN_STOP_DEVICE: return PnP_HandleStopDevice(Irp);
break;
case IRP_MN_QUERY_STOP_DEVICE: return PnP_HandleQueryStop(Irp);
break;
case IRP_MN_CANCEL_STOP_DEVICE: return PnP_HandleCancelStop(Irp);
break;
case IRP_MN_QUERY_DEVICE_RELATIONS: return PnP_HandleQueryRelations(Irp);
break;
case IRP_MN_QUERY_INTERFACE: return PnP_HandleQueryInterface(Irp);
break;
case IRP_MN_QUERY_CAPABILITIES: return PnP_HandleQueryCapabilities(Irp);
break;
case IRP_MN_QUERY_RESOURCES: return PnP_HandleQueryResources(Irp);
break;
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
return PnP_HandleQueryResRequirements(Irp);
break;
case IRP_MN_QUERY_DEVICE_TEXT: return PnP_HandleQueryText(Irp);
break;
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
return PnP_HandleFilterResRequirements(Irp);
break;
case 0x0E: return PnP_Default(Irp);
break;
case IRP_MN_READ_CONFIG: return PnP_HandleReadConfig(Irp);
break;
case IRP_MN_WRITE_CONFIG: return PnP_HandleWriteConfig(Irp);
break;
case IRP_MN_EJECT: return PnP_HandleEject(Irp);
break;
case IRP_MN_SET_LOCK: return PnP_HandleSetLock(Irp);
break;
case IRP_MN_QUERY_ID: return PnP_HandleQueryID(Irp);
break;
case IRP_MN_QUERY_PNP_DEVICE_STATE: return PnP_HandleQueryPnPState(Irp);
break;
case IRP_MN_QUERY_BUS_INFORMATION: return PnP_HandleQueryBusInfo(Irp);
break;
case IRP_MN_DEVICE_USAGE_NOTIFICATION: return PnP_HandleUsageNotification(Irp);
break;
case IRP_MN_SURPRISE_REMOVAL: return PnP_HandleSurprizeRemoval(Irp);
break;
}
return PnP_Default(Irp);
}
#pragma PAGEDCODE
// Asks object to remove device
// Object itself will be removed at wrapper function
NTSTATUS CUSBDevice::PnP_HandleRemoveDevice(IN PIRP Irp)
{
// Set device removal state
m_RemoveLock.removing = TRUE;
// Do any processing required for *us* to remove the device. This
// would include completing any outstanding requests, etc.
PnP_StopDevice();
// Do not remove actually our device here!
// It will be done automatically by PnP handler at basic class.
// Let lower-level drivers handle this request. Ignore whatever
// result eventuates.
Irp->IoStatus.Status = STATUS_SUCCESS;
NTSTATUS status = PnP_Default(Irp);
// lower-level completed IoStatus already
return status;
}
#pragma PAGEDCODE
NTSTATUS CUSBDevice::PnP_HandleStartDevice(IN PIRP Irp)
{
waitForIdleAndBlock();
// First let all lower-level drivers handle this request. In this particular
// sample, the only lower-level driver should be the physical device created
// by the bus driver, but there could theoretically be any number of intervening
// bus filter devices. Those drivers may need to do some setup at this point
// in time before they'll be ready to handle non-PnP IRP's.
Irp->IoStatus.Status = STATUS_SUCCESS;
NTSTATUS status = forwardAndWait(Irp);
if (!NT_SUCCESS(status))
{
TRACE(" ******* BUS DRIVER FAILED START REQUEST! %8.8lX ******",status);
CLogger* logger = kernel->getLogger();
if(logger) logger->logEvent(GRCLASS_BUS_DRIVER_FAILED_REQUEST,getSystemObject());
return completeDeviceRequest(Irp, status, Irp->IoStatus.Information);
}
status = PnP_StartDevice();
setIdle();
return completeDeviceRequest(Irp, status, Irp->IoStatus.Information);
}
#pragma PAGEDCODE
NTSTATUS CUSBDevice::PnP_HandleStopDevice(IN PIRP Irp)
{
PnP_StopDevice();
m_Started = FALSE;
// Let lower-level drivers handle this request. Ignore whatever
// result eventuates.
Irp->IoStatus.Status = STATUS_SUCCESS;
NTSTATUS status = PnP_Default(Irp);
return status;
}
#pragma PAGEDCODE
NTSTATUS CUSBDevice::PnP_StartDevice()
{ // StartDevice
NTSTATUS status = STATUS_SUCCESS;
if(m_Started)
{
TRACE("##### Current device was already started!\n");
ASSERT(!m_Started);
return STATUS_DEVICE_BUSY;
}
__try
{
// Do all required processing to start USB device.
// It will include getting Device and configuration descriptors
// and selecting specific interface.
// For now our device support only interface.
// So, it will be activated at activateInterface().
m_DeviceDescriptor = getDeviceDescriptor();
if(!m_DeviceDescriptor)
{
status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
TRACE("\nDeviceDescriptor %8.8lX\n",m_DeviceDescriptor);
m_Configuration = getConfigurationDescriptor();
if(!m_Configuration)
{
status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
TRACE("Configuration %8.8lX\n",m_Configuration);
m_Interface = activateInterface(m_Configuration);
if(!m_Interface)
{
status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
TRACE("Selected interface %8.8lX\n\n",m_Interface);
// Allocate Xfer buffers
if(m_CommandPipe)
{
TRACE("Allocating command buffer (length 0x%x)...\n",CommandBufferLength);
m_CommandBuffer = memory->allocate(NonPagedPool, CommandBufferLength);
if(!m_CommandBuffer)
{
status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
}
if(m_ResponsePipe)
{
TRACE("Allocating response buffer (length 0x%x)...\n", ResponseBufferLength);
m_ResponseBuffer = memory->allocate(NonPagedPool, ResponseBufferLength);
if(!m_ResponseBuffer)
{
status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
}
if(m_InterruptPipe)
{
TRACE("Allocating interrupt buffer (length 0x%x)...\n", InterruptBufferLength);
m_InterruptBuffer = memory->allocate(NonPagedPool, InterruptBufferLength);
if(!m_InterruptBuffer)
{
status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
}
}
__finally
{
// Check memory allocations!
if(!NT_SUCCESS(status))
{
if(m_DeviceDescriptor) memory->free(m_DeviceDescriptor);
if(m_Configuration) memory->free(m_Configuration);
if(m_Interface) memory->free(m_Interface);
if(m_CommandBuffer) memory->free(m_CommandBuffer);
if(m_ResponseBuffer) memory->free(m_ResponseBuffer);
if(m_InterruptBuffer) memory->free(m_InterruptBuffer);
m_DeviceDescriptor = NULL;
m_Configuration = NULL;
m_Interface = NULL;
m_CommandBuffer = NULL;
m_ResponseBuffer = NULL;
m_InterruptBuffer = NULL;
}
else
{
// Give chance inhereted devices to initialize...
onDeviceStart();
TRACE("USB device started successfully...\n\n");
// Device has been completely initialized and is ready to run.
m_Started = TRUE;
}
}
return status;
}
#pragma PAGEDCODE
// This function used for both Stop and Remove PnP events
// It will undo everything what was done at StartDevice
VOID CUSBDevice::PnP_StopDevice()
{ // StopDevice
if (!m_Started) return; // device not started, so nothing to do
TRACE("*** Stop USB Device %8.8lX requested... ***\n", this);
onDeviceStop();
// If any pipes are still open, call USBD with URB_FUNCTION_ABORT_PIPE
// This call will also close the pipes; if any user close calls get through,
// they will be noops
abortPipes();
//We basically just tell USB this device is now 'unconfigured'
if(!isSurprizeRemoved()) disactivateInterface();
// Free resources allocated at startup
m_ControlPipe = NULL;
m_InterruptPipe = NULL;
m_ResponsePipe = NULL;
m_CommandPipe = NULL;
if(m_DeviceDescriptor) memory->free(m_DeviceDescriptor);
if(m_Configuration) memory->free(m_Configuration);
if(m_Interface) memory->free(m_Interface);
if(m_CommandBuffer) memory->free(m_CommandBuffer);
if(m_ResponseBuffer) memory->free(m_ResponseBuffer);
if(m_InterruptBuffer) memory->free(m_InterruptBuffer);
TRACE("*** Device resources released ***\n");
setIdle();
m_Started = FALSE;
}
#pragma PAGEDCODE
NTSTATUS CUSBDevice::PnP_HandleQueryRemove(IN PIRP Irp)
{
TRACE("******** QUERY REMOVAL ********\n");
// Win98 doesn't check for open handles before allowing a remove to proceed,
// and it may deadlock in IoReleaseRemoveLockAndWait if handles are still
// open.
if (isWin98() && m_DeviceObject->ReferenceCount)
{
TRACE("Failing removal query due to open handles\n");
return completeDeviceRequest(Irp, STATUS_DEVICE_BUSY, 0);
}
Irp->IoStatus.Status = STATUS_SUCCESS;
NTSTATUS status = forwardAndWait(Irp);
return completeDeviceRequest(Irp, Irp->IoStatus.Status,0);
}
NTSTATUS CUSBDevice::PnP_HandleCancelRemove(IN PIRP Irp)
{
NTSTATUS status;
status = forwardAndWait(Irp);
ASSERT(NT_SUCCESS(status));
Irp->IoStatus.Status = STATUS_SUCCESS;
return completeDeviceRequest(Irp, Irp->IoStatus.Status,0);
}
NTSTATUS CUSBDevice::PnP_HandleQueryStop(IN PIRP Irp)
{
TRACE("******** QUERY STOP ********\n");
if(isDeviceLocked())
{
Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
return completeDeviceRequest(Irp, Irp->IoStatus.Status,0);
}
Irp->IoStatus.Status = STATUS_SUCCESS;
NTSTATUS status = forwardAndWait(Irp);
return completeDeviceRequest(Irp, Irp->IoStatus.Status,0);
}
NTSTATUS CUSBDevice::PnP_HandleCancelStop(IN PIRP Irp)
{
TRACE("******** CANCEL STOP ********\n");
Irp->IoStatus.Status = STATUS_SUCCESS;
NTSTATUS status = forwardAndWait(Irp);
return completeDeviceRequest(Irp, Irp->IoStatus.Status,0);
}
NTSTATUS CUSBDevice::PnP_HandleQueryRelations(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleQueryInterface(IN PIRP Irp)
{
return PnP_Default(Irp);
}
#pragma PAGEDCODE
NTSTATUS CUSBDevice::PnP_HandleQueryCapabilities(PIRP Irp)
{
if(!Irp) return STATUS_INVALID_PARAMETER;
PIO_STACK_LOCATION stack = irp->getCurrentStackLocation(Irp);
PDEVICE_CAPABILITIES pdc = stack->Parameters.DeviceCapabilities.Capabilities;
// Check to be sure we know how to handle this version of the capabilities structure
if (pdc->Version < 1) return PnP_Default(Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
NTSTATUS status = forwardAndWait(Irp);
if (NT_SUCCESS(status))
{ // IRP succeeded
stack = irp->getCurrentStackLocation(Irp);
pdc = stack->Parameters.DeviceCapabilities.Capabilities;
if(!pdc) return STATUS_INVALID_PARAMETER;
//if (m_Flags & DEVICE_SURPRISE_REMOVAL_OK)
/*{ // Smartcard readers do not support it!
//if(!isWin98()) pdc->SurpriseRemovalOK = TRUE;
}*/
pdc->SurpriseRemovalOK = FALSE;
m_DeviceCapabilities = *pdc; // save capabilities for whoever needs to see them
TRACE(" Device allows surprize removal - %s\n",(m_DeviceCapabilities.SurpriseRemovalOK?"YES":"NO"));
} // IRP succeeded
return completeDeviceRequest(Irp, status,Irp->IoStatus.Information);
}// HandleQueryCapabilities
NTSTATUS CUSBDevice::PnP_HandleQueryResources(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleQueryResRequirements(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleQueryText(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleFilterResRequirements(IN PIRP Irp)
{
TRACE("Default action for filtering resource requirements...");
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleReadConfig(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleWriteConfig(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleEject(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleSetLock(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleQueryID(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleQueryPnPState(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleQueryBusInfo(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleUsageNotification(IN PIRP Irp)
{
return PnP_Default(Irp);
}
NTSTATUS CUSBDevice::PnP_HandleSurprizeRemoval(IN PIRP Irp)
{
TRACE("******** SURPRIZE REMOVAL ********\n");
return PnP_Default(Irp);
}
// Functions allocate and initialize USB request block.
// It can be used for read/write request on specific Pipe.
// Allocated URB should be free later upon completing of the request.
PURB CUSBDevice::buildBusTransferRequest(CIoPacket* Irp,UCHAR Command)
{
USHORT Size;
ULONG BufferLength;
PURB Urb = NULL;
PVOID pBuffer;
ULONG TransferFlags;
IN USBD_PIPE_HANDLE Pipe = NULL;
ULONG TransferLength;
if(!Irp) return NULL;
if(Command == COMMAND_REQUEST)
{
BufferLength = CommandBufferLength;
pBuffer = m_CommandBuffer;
TransferFlags = USBD_SHORT_TRANSFER_OK;
Pipe = m_CommandPipe;
TransferLength = Irp->getWriteLength();
if(!Pipe || !TransferLength)
{
TRACE("##### Requested Pipe or TransferLength == 0 for the requested command %d ...\n", Command);
return NULL;
}
TRACE("Command transfer requested...\n");
}
else
if(Command == RESPONSE_REQUEST)
{
BufferLength = ResponseBufferLength;
pBuffer = m_ResponseBuffer;
TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
Pipe = m_ResponsePipe;
TransferLength = BufferLength;
if(!Pipe || !TransferLength)
{
TRACE("##### Requested Pipe or TransferLength == 0 for the requested command %d ...\n", Command);
return NULL;
}
TRACE("Response transfer requested with number of expected bytes %x\n",Irp->getReadLength());
}
else
if(Command == INTERRUPT_REQUEST)
{
BufferLength = InterruptBufferLength;
pBuffer = m_InterruptBuffer;
TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
Pipe = m_InterruptPipe;
TransferLength = BufferLength;
if(!Pipe || !TransferLength)
{
TRACE("##### Requested Pipe or TransferLength == 0 for the requested command %d ...\n", Command);
return NULL;
}
TRACE("Interrupt transfer requested...\n");
}
else
{
TRACE("Incorrect command was requested %d", Command);
return NULL;
}
Size = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
Urb = (PURB) memory->allocate(NonPagedPool, Size);
if (Urb)
{
memory->zero(Urb, Size);
memory->zero(pBuffer, BufferLength);
if(Command == COMMAND_REQUEST)
{
memory->copy(pBuffer,Irp->getBuffer(), TransferLength);
((PUCHAR)pBuffer)[TransferLength] = 0x00;
//TRACE("Command ");
//TRACE_BUFFER(pBuffer,TransferLength);
}
UsbBuildInterruptOrBulkTransferRequest(Urb,(USHORT) Size,
Pipe,
pBuffer,
NULL,
TransferLength,
TransferFlags,
NULL);
}
else
{
TRACE("##### ERROR: failed to allocate URB request...\n");
}
return Urb;
}
VOID CUSBDevice::finishBusTransferRequest(CIoPacket* Irp,UCHAR Command)
{
ULONG BufferLength;
PVOID pBuffer;
ULONG_PTR info;
if(!Irp)
{
TRACE(" **** Invalid parameter -> Irp\n");
return;
}
if(!(info = Irp->getInformation()))
{
TRACE(" **** There is no reported information\n");
return;
}
if(Command == COMMAND_REQUEST)
{
BufferLength = CommandBufferLength;
pBuffer = m_CommandBuffer;
TRACE(" Command transfer finished with length %d\n",info);
}
else
if(Command == RESPONSE_REQUEST)
{
ULONG Length = Irp->getReadLength();
BufferLength = (ULONG)(info>ResponseBufferLength?ResponseBufferLength:info);
BufferLength = BufferLength>Length?Length:BufferLength;
pBuffer = m_ResponseBuffer;
TRACE("Bus Driver replied with length %d\n",info);
memory->copy(Irp->getBuffer(),pBuffer, BufferLength);
if(BufferLength!=info)
{
TRACE("##### Response Buffer short! Buffer length %x Reply length %x \n",ResponseBufferLength,info);
}
//TRACE("Response ");
//TRACE_BUFFER(pBuffer,BufferLength);
}
else
if(Command == INTERRUPT_REQUEST)
{
ULONG Length = Irp->getReadLength();
BufferLength = (ULONG)(info>InterruptBufferLength?InterruptBufferLength:info);
BufferLength = BufferLength>Length?Length:BufferLength;
pBuffer = m_InterruptBuffer;
TRACE("Bus Driver replied with length %d\n",info);
memory->copy(Irp->getBuffer(),pBuffer, BufferLength);
if(BufferLength!=info)
{
TRACE("##### Interrupt Buffer short! Buffer length %x Reply length %x \n",InterruptBufferLength,info);
}
TRACE("Interrupt ");
TRACE_BUFFER(pBuffer,BufferLength);
}
else
{
TRACE("Incorrect command was requested %d", Command);
return;
}
}
// This function generates an internal IRP from this driver to the PDO
// to obtain information on the Physical Device Object's capabilities.
// We are most interested in learning which system power states
// are to be mapped to which device power states for honoring IRP_MJ_SET_POWER Irps.
#pragma PAGEDCODE
NTSTATUS CUSBDevice::QueryBusCapabilities(PDEVICE_CAPABILITIES Capabilities)
{
NTSTATUS status;
CIoPacket* IoPacket;
PAGED_CODE();
TRACE("Quering USB bus capabilities...\n");
// Build an IRP for us to generate an internal query request to the PDO
IoPacket = new (NonPagedPool) CIoPacket(m_pLowerDeviceObject->StackSize);
if(!ALLOCATED_OK(IoPacket))
{
DISPOSE_OBJECT(IoPacket);
return STATUS_INSUFFICIENT_RESOURCES;
}
IoPacket->setTimeout(getCommandTimeout());
IoPacket->buildStack(getSystemObject(),IRP_MJ_PNP, IRP_MN_QUERY_CAPABILITIES, 0,Capabilities);
status = sendRequestToDeviceAndWait(IoPacket);
DISPOSE_OBJECT(IoPacket);
return status;
}
#pragma PAGEDCODE
// Function gets device descriptor from the USB bus driver
PUSB_DEVICE_DESCRIPTOR CUSBDevice::getDeviceDescriptor()
{
PUSB_DEVICE_DESCRIPTOR Descriptor = NULL;
PURB Urb;
ULONG Size;
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
CIoPacket* IoPacket = NULL;
TRACE("Getting USB device descriptor...\n");
__try
{
Urb = (PURB)memory->allocate(NonPagedPool,sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if(!Urb) __leave;
IoPacket = new (NonPagedPool) CIoPacket(m_pLowerDeviceObject->StackSize);
if(!ALLOCATED_OK(IoPacket)) __leave;
IoPacket->setTimeout(getCommandTimeout());
Size = sizeof(USB_DEVICE_DESCRIPTOR);
Descriptor = (PUSB_DEVICE_DESCRIPTOR)memory->allocate(NonPagedPool,Size);
if(!Descriptor) __leave;
UsbBuildGetDescriptorRequest(Urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE,
0,
0,
Descriptor,
NULL,
Size,
NULL);
IoPacket->buildStack(getSystemObject(),IRP_MJ_INTERNAL_DEVICE_CONTROL, 0, IOCTL_INTERNAL_USB_SUBMIT_URB,Urb);
Status = sendRequestToDeviceAndWait(IoPacket);
if (NT_SUCCESS(Status))
{
TRACE("Device Descriptor = %x, len %x\n",
Descriptor,
Urb->UrbControlDescriptorRequest.TransferBufferLength);
TRACE("\nGemplus USB SmartCard Device Descriptor:\n");
TRACE("-------------------------\n");
TRACE("bLength 0x%x\n", Descriptor->bLength);
TRACE("bDescriptorType 0x%x\n", Descriptor->bDescriptorType);
TRACE("bcdUSB 0x%x\n", Descriptor->bcdUSB);
TRACE("bDeviceClass 0x%x\n", Descriptor->bDeviceClass);
TRACE("bDeviceSubClass 0x%x\n", Descriptor->bDeviceSubClass);
TRACE("bDeviceProtocol 0x%x\n", Descriptor->bDeviceProtocol);
TRACE("bMaxPacketSize0 0x%x\n", Descriptor->bMaxPacketSize0);
TRACE("idVendor 0x%x\n", Descriptor->idVendor);
TRACE("idProduct 0x%x\n", Descriptor->idProduct);
TRACE("bcdDevice 0x%x\n", Descriptor->bcdDevice);
TRACE("iManufacturer 0x%x\n", Descriptor->iManufacturer);
TRACE("iProduct 0x%x\n", Descriptor->iProduct);
TRACE("iSerialNumber 0x%x\n", Descriptor->iSerialNumber);
TRACE("bNumConfigurations 0x%x\n", Descriptor->bNumConfigurations);
TRACE("-------------------------\n");
}
else
{
TRACE("#### ERROR: Failed to get device descriptor...\n");
CLogger* logger = kernel->getLogger();
if(logger) logger->logEvent(GRCLASS_BUS_DRIVER_FAILED_REQUEST,getSystemObject());
}
__leave;;
}
__finally
{
if(Urb) memory->free(Urb);
DISPOSE_OBJECT(IoPacket);
if (!NT_SUCCESS(Status))
{
if(Descriptor) memory->free(Descriptor);
Descriptor = NULL;
}
else
{
if(Descriptor) TRACE("*** Succeed to get device descriptor ***\n");
}
}
return Descriptor;
}
// Function gets confuguration descriptor
PUSB_CONFIGURATION_DESCRIPTOR CUSBDevice::getConfigurationDescriptor()
{
PUSB_CONFIGURATION_DESCRIPTOR Descriptor = NULL;
PURB Urb;
ULONG Size;
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
CIoPacket* IoPacket = NULL;
TRACE("Getting USB configuration descriptor...\n");
__try
{
Urb = (PURB)memory->allocate(NonPagedPool,sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if(!Urb) __leave;
Size = sizeof(USB_CONFIGURATION_DESCRIPTOR);
while(TRUE)
{
IoPacket = new (NonPagedPool) CIoPacket(m_pLowerDeviceObject->StackSize);
if(!ALLOCATED_OK(IoPacket)) __leave;
IoPacket->setTimeout(getCommandTimeout());
Descriptor = (PUSB_CONFIGURATION_DESCRIPTOR)memory->allocate(NonPagedPool,Size);
if(!Descriptor) __leave;
UsbBuildGetDescriptorRequest(Urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
Descriptor,
NULL,
Size,
NULL);
IoPacket->buildStack(getSystemObject(),IRP_MJ_INTERNAL_DEVICE_CONTROL, 0, IOCTL_INTERNAL_USB_SUBMIT_URB,Urb);
Status = sendRequestToDeviceAndWait(IoPacket);
if (Urb->UrbControlDescriptorRequest.TransferBufferLength>0 &&
Descriptor->wTotalLength > Size)
{
// If bus driver truncated his descriptor-> resend command with
// bus return value
Size = Descriptor->wTotalLength;
TRACE("Descriptor length retrieved - 0x%x! Getting USB device configuration... ***\n",Size);
IoPacket->dispose();
IoPacket = NULL;
memory->free(Descriptor);
Descriptor = NULL;
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else break;
}
if(NT_SUCCESS(Status))
{
TRACE("\nUSB device Configuration Descriptor = %x, len %x\n",Descriptor,
Urb->UrbControlDescriptorRequest.TransferBufferLength);
TRACE("---------\n");
TRACE("bLength 0x%x\n", Descriptor->bLength);
TRACE("bDescriptorType 0x%x\n", Descriptor->bDescriptorType);
TRACE("wTotalLength 0x%x\n", Descriptor->wTotalLength);
TRACE("bNumInterfaces 0x%x\n", Descriptor->bNumInterfaces);
TRACE("bConfigurationValue 0x%x\n", Descriptor->bConfigurationValue);
TRACE("iConfiguration 0x%x\n", Descriptor->iConfiguration);
TRACE("bmAttributes 0x%x\n", Descriptor->bmAttributes);
TRACE("MaxPower 0x%x\n", Descriptor->MaxPower);
TRACE("---------\n");
}
else
{
TRACE("*** Failed to get configuration descriptor ***\n");
CLogger* logger = kernel->getLogger();
if(logger) logger->logEvent(GRCLASS_BUS_DRIVER_FAILED_REQUEST,getSystemObject());
}
__leave;
}
__finally
{
if(Urb) memory->free(Urb);
DISPOSE_OBJECT(IoPacket);
if (!NT_SUCCESS(Status))
{
if(Descriptor) memory->free(Descriptor);
Descriptor = NULL;
}
else
{
if(Descriptor) TRACE("*** Succeed to get configuration descriptor ***\n");
}
}
return Descriptor;
}
#pragma PAGEDCODE
// Function gets confuguration descriptor
PUSBD_INTERFACE_INFORMATION CUSBDevice::activateInterface(PUSB_CONFIGURATION_DESCRIPTOR Configuration)
{
PURB Urb = NULL;
USHORT Size;
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
USHORT j;
PUSBD_INTERFACE_LIST_ENTRY InterfaceList;
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor = NULL;
PUSBD_INTERFACE_INFORMATION Interface = NULL;
PUSBD_INTERFACE_INFORMATION UsbInterface = NULL;
ULONG NumberOfInterfaces;
CIoPacket* IoPacket = NULL;
TRACE("Activating USB device configuration %8.8lX, setting device interface...\n",Configuration);
if(!Configuration) return NULL;
// get this from the config descriptor
NumberOfInterfaces = Configuration->bNumInterfaces;
// We only support one interface!
TRACE("\nNumber of interfaces at the configuration - %d \n",NumberOfInterfaces);
// USBD_ParseConfigurationDescriptorEx searches a given configuration
// descriptor and returns a pointer to an interface that matches the
// given search criteria.
// We only support one interface on this device
if(NumberOfInterfaces==1)
{
InterfaceDescriptor =
USBD_ParseConfigurationDescriptorEx(
Configuration,
Configuration,
0, // intreface number, don't care
-1, // alt setting, don't care
-1, // class, don't care
-1, // subclass, don't care
-1);// protocol, don't care
}
else
{
if(NumberOfInterfaces>1)
{
TRACE("Trying next to get interface descriptor for KEYBOARD READER...\n");
InterfaceDescriptor =
USBD_ParseConfigurationDescriptorEx(
Configuration,
Configuration,
1, // intreface number 1 for keyboard reader
-1, // alt setting, don't care
-1, // class, don't care
-1, // subclass, don't care
-1);// protocol, don't care
}
}
if (!InterfaceDescriptor)
{
TRACE("##### ERROR: Failed to get interface description...\n");
return NULL;
}
InterfaceList = (PUSBD_INTERFACE_LIST_ENTRY)memory->allocate(NonPagedPool,sizeof(USBD_INTERFACE_LIST_ENTRY) * (NumberOfInterfaces+1));
if(!InterfaceList)
{
TRACE("Failed to alloacte memory for the interfacelist...\n");
return NULL;
}
// We support only one interface after current!
InterfaceList->InterfaceDescriptor = InterfaceDescriptor;
InterfaceList++;
InterfaceList->InterfaceDescriptor = NULL;
InterfaceList--;
__try
{
//For now our device support only one interface.
Urb = USBD_CreateConfigurationRequestEx(Configuration, InterfaceList);
if(!Urb) __leave;
Interface = &Urb->UrbSelectConfiguration.Interface;
TRACE("Pipe MaximumTransferSize set to 0x%x\n",m_MaximumTransferSize);
for (ULONG i=0; i< Interface->NumberOfPipes; i++)
{
// perform any pipe initialization here
Interface->Pipes[i].MaximumTransferSize = m_MaximumTransferSize;
Interface->Pipes[i].PipeFlags = 0;
}
TRACE("Building select configuration request...\n");
Size = sizeof(struct _URB_SELECT_CONFIGURATION);
UsbBuildSelectConfigurationRequest(Urb,Size, Configuration);
IoPacket = new (NonPagedPool) CIoPacket(m_pLowerDeviceObject->StackSize);
if(!ALLOCATED_OK(IoPacket)) __leave;
IoPacket->setTimeout(getCommandTimeout());
IoPacket->buildStack(getSystemObject(),IRP_MJ_INTERNAL_DEVICE_CONTROL, 0, IOCTL_INTERNAL_USB_SUBMIT_URB,Urb);
Status = sendRequestToDeviceAndWait(IoPacket);
if (!NT_SUCCESS(Status))
{
TRACE("##### ERROR: Failed to Select configuration, ret 0x%x...\n",Status);
CLogger* logger = kernel->getLogger();
if(logger) logger->logEvent(GRCLASS_BUS_DRIVER_FAILED_REQUEST,getSystemObject());
__leave;
}
// Save the configuration handle for this device
// Well... It is not really nice to initialize it here, but...
m_ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
TRACE("Device Configuration handle 0x%x\n",m_ConfigurationHandle);
UsbInterface = (PUSBD_INTERFACE_INFORMATION)memory->allocate(NonPagedPool,Interface->Length);
if (!UsbInterface)
{
TRACE(("##### ERROR: Failed to allocate memory for the UsbInterface\n"));
__leave;
}
// save a copy of the interface information returned
memory->copy(UsbInterface, Interface, Interface->Length);
TRACE("\nGemplus USB device interface:\n");
// Dump the interface to the debugger
TRACE("---------\n");
TRACE("NumberOfPipes 0x%x\n", UsbInterface->NumberOfPipes);
TRACE("Length 0x%x\n", UsbInterface->Length);
TRACE("Alt Setting 0x%x\n", UsbInterface->AlternateSetting);
TRACE("Interface Number 0x%x\n", UsbInterface->InterfaceNumber);
TRACE("Class, subclass, protocol 0x%x 0x%x 0x%x\n",
UsbInterface->Class,
UsbInterface->SubClass,
UsbInterface->Protocol);
TRACE("---------\n");
// Dump the pipe info
for (j=0; j<Interface->NumberOfPipes; j++)
{
PUSBD_PIPE_INFORMATION pipeInformation;
pipeInformation = &UsbInterface->Pipes[j];
TRACE("\nGemplus USB device pipe[%d] ",j);
if(pipeInformation->PipeType==UsbdPipeTypeBulk)
{
if(pipeInformation->EndpointAddress&0x80)
{
TRACE(("(Bulk Response Pipe):\n"));
m_ResponsePipe = pipeInformation->PipeHandle;
TRACE("m_ResponsePipe 0x%x\n", m_ResponsePipe);
}
else
{
TRACE("(Bulk Command pipe):\n");
m_CommandPipe = pipeInformation->PipeHandle;
TRACE("m_CommandPipe 0x%x\n", m_CommandPipe);
}
}
else
{
if(pipeInformation->PipeType==UsbdPipeTypeInterrupt)
{
if(pipeInformation->EndpointAddress&0x80)
{
TRACE(("(Interrupt Response Pipe):\n"));
m_InterruptPipe = pipeInformation->PipeHandle;
TRACE("m_InterruptPipe 0x%x\n", m_InterruptPipe);
}
else
{
TRACE(("(Unexpected Interrupt OUT pipe):\n"));
TRACE("Unexpected pipe 0x%x\n", pipeInformation);
}
}
else
{
TRACE("Unexpected pipe type 0x%x\n", pipeInformation);
}
}
TRACE("---------\n");
TRACE("PipeType 0x%x\n", pipeInformation->PipeType);
TRACE("EndpointAddress 0x%x\n", pipeInformation->EndpointAddress);
TRACE("MaxPacketSize 0x%x\n", pipeInformation->MaximumPacketSize);
TRACE("Interval 0x%x\n", pipeInformation->Interval);
TRACE("Handle 0x%x\n", pipeInformation->PipeHandle);
TRACE("MaximumTransferSize 0x%x\n", pipeInformation->MaximumTransferSize);
}
TRACE("---------\n");
__leave;
}
__finally
{
if(Urb) memory->free(Urb);
if(InterfaceList) memory->free(InterfaceList);
DISPOSE_OBJECT(IoPacket);
if (!NT_SUCCESS(Status))
{
if(UsbInterface) memory->free(UsbInterface);
UsbInterface = NULL;
}
else
{
if(UsbInterface) TRACE("*** Succeed to set UsbInterface ***\n");
}
}
return UsbInterface;
}
#pragma PAGEDCODE
// Function gets confuguration descriptor
NTSTATUS CUSBDevice::disactivateInterface()
{
PURB Urb = NULL;
USHORT Size;
NTSTATUS Status = STATUS_SUCCESS;
CIoPacket* IoPacket;
TRACE("Disactivating USB device interface...\n");
Size = sizeof(struct _URB_SELECT_CONFIGURATION);
Urb = (PURB)memory->allocate(NonPagedPool,Size);
if(!Urb)
{
TRACE("##### ERROR: Failed to create disable configuration request...\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
//UsbBuildSelectConfigurationRequest(Urb,Size, NULL);
(Urb)->UrbHeader.Function = URB_FUNCTION_SELECT_CONFIGURATION;
(Urb)->UrbHeader.Length = Size;
(Urb)->UrbSelectConfiguration.ConfigurationDescriptor = NULL;
__try
{
IoPacket = new (NonPagedPool) CIoPacket(m_pLowerDeviceObject->StackSize);
if(!ALLOCATED_OK(IoPacket)) __leave;
IoPacket->setTimeout(getCommandTimeout());
IoPacket->buildStack(getSystemObject(),IRP_MJ_INTERNAL_DEVICE_CONTROL, 0, IOCTL_INTERNAL_USB_SUBMIT_URB,Urb);
Status = sendRequestToDeviceAndWait(IoPacket);
if (!NT_SUCCESS(Status))
{
TRACE("##### ERROR: Failed to disable device interface..., ret %x...\n",Status);
}
__leave;
}
__finally
{
if(Urb) memory->free(Urb);
DISPOSE_OBJECT(IoPacket);
if (!NT_SUCCESS(Status))
{
TRACE("*** Failed to disactivateInterface() %8.8lX ***\n",Status);
}
else
{
TRACE("*** Succeed to disactivateInterface() ***\n");
}
}
return Status;
}
#pragma PAGEDCODE
// Function resets specified pipe
NTSTATUS CUSBDevice::resetPipe(IN USBD_PIPE_HANDLE Pipe)
{
PURB Urb = NULL;
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
CIoPacket* IoPacket;
TRACE("Resetting USB device pipe %8.8lX...\n",Pipe);
Urb = (PURB)memory->allocate(NonPagedPool,sizeof(struct _URB_PIPE_REQUEST));
if (!Urb)
{
TRACE("#### ERROR: Failed to allocate Urb at Pipe reset...\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Urb->UrbHeader.Length = sizeof (struct _URB_PIPE_REQUEST);
Urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
Urb->UrbPipeRequest.PipeHandle = Pipe;
__try
{
IoPacket = new (NonPagedPool) CIoPacket(m_pLowerDeviceObject->StackSize);
if(!ALLOCATED_OK(IoPacket)) __leave;
IoPacket->setTimeout(getCommandTimeout());
IoPacket->buildStack(getSystemObject(),IRP_MJ_INTERNAL_DEVICE_CONTROL, 0, IOCTL_INTERNAL_USB_SUBMIT_URB,Urb);
Status = sendRequestToDeviceAndWait(IoPacket);
if (!NT_SUCCESS(Status))
{
TRACE("##### ERROR: Failed to reset Pipe, ret %x...\n",Status);
}
__leave;
}
__finally
{
if(Urb) memory->free(Urb);
DISPOSE_OBJECT(IoPacket);
if (!NT_SUCCESS(Status))
{
TRACE("*** Failed to resetPipe() %8.8lX ***\n",Status);
}
else
{
TRACE("*** Succeed to resetPipe() ***\n");
}
}
return Status;
}
#pragma PAGEDCODE
// Function resets specified pipe
NTSTATUS CUSBDevice::resetDevice()
{
PURB Urb = NULL;
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
CIoPacket* IoPacket;
TRACE("Resetting USB device...\n");
Urb = (PURB)memory->allocate(NonPagedPool,sizeof(struct _URB_PIPE_REQUEST));
if (!Urb)
{
TRACE("#### ERROR: Failed to allocate Urb at Device reset...\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
__try
{
IoPacket = new (NonPagedPool) CIoPacket(m_pLowerDeviceObject->StackSize);
if(!ALLOCATED_OK(IoPacket)) __leave;
IoPacket->setTimeout(getCommandTimeout());
IoPacket->buildStack(getSystemObject(),IRP_MJ_INTERNAL_DEVICE_CONTROL, 0, IOCTL_INTERNAL_USB_RESET_PORT,Urb);
Status = sendRequestToDeviceAndWait(IoPacket);
if (!NT_SUCCESS(Status))
{
TRACE("##### ERROR: Failed to reset Device, ret %x...\n",Status);
}
__leave;
}
__finally
{
if(Urb) memory->free(Urb);
DISPOSE_OBJECT(IoPacket);
if (!NT_SUCCESS(Status))
{
TRACE("*** Failed to resetPipe() %8.8lX ***\n",Status);
}
else
{
TRACE("*** Succeed to resetPipe() ***\n");
}
}
return Status;
}
// Called as part of sudden device removal handling.
// Cancels any pending transfers for all open pipes.
// If any pipes are still open, call USBD with URB_FUNCTION_ABORT_PIPE
// Also marks the pipe 'closed' in our saved configuration info.
NTSTATUS CUSBDevice::abortPipes()
{
PURB Urb = NULL;
NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
PUSBD_PIPE_INFORMATION Pipe;
CIoPacket* IoPacket;
TRACE("Aborting all USB device pipes...\n");
Urb = (PURB)memory->allocate(NonPagedPool,sizeof(struct _URB_PIPE_REQUEST));
if (!Urb)
{
TRACE("#### ERROR: Failed to allocate Urb at Pipe reset...\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
for (USHORT i=0; i<m_Interface->NumberOfPipes; i++)
{
IoPacket = new (NonPagedPool) CIoPacket(m_pLowerDeviceObject->StackSize);
if(!ALLOCATED_OK(IoPacket)) break;
IoPacket->setTimeout(getCommandTimeout());
Pipe = &m_Interface->Pipes[i]; // PUSBD_PIPE_INFORMATION PipeInfo;
if ( Pipe->PipeFlags )
{ // we set this if open, clear if closed
Urb->UrbHeader.Length = sizeof (struct _URB_PIPE_REQUEST);
Urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
Urb->UrbPipeRequest.PipeHandle = Pipe->PipeHandle;
IoPacket->buildStack(getSystemObject(),IRP_MJ_INTERNAL_DEVICE_CONTROL, 0, IOCTL_INTERNAL_USB_SUBMIT_URB,Urb);
Status = sendRequestToDeviceAndWait(IoPacket);
if (!NT_SUCCESS(Status))
{
TRACE("##### ERROR: Failed to abort Pipe %d\n",i);
}
Pipe->PipeFlags = FALSE; // mark the pipe 'closed'
}
DISPOSE_OBJECT(IoPacket);
}
if(Urb) memory->free(Urb);
TRACE("**** Interface' pipes closed ****\n");
return STATUS_SUCCESS;;
}
NTSTATUS CUSBDevice::resetAllPipes()
{
PURB Urb = NULL;
NTSTATUS Status;
PUSBD_PIPE_INFORMATION Pipe;
CIoPacket* IoPacket;
TRACE("Resetting all USB device pipes...\n");
Urb = (PURB)memory->allocate(NonPagedPool,sizeof(struct _URB_PIPE_REQUEST));
if (!Urb)
{
TRACE("#### ERROR: Failed to allocate Urb at Pipe reset...\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
for (USHORT i=0; i<m_Interface->NumberOfPipes; i++)
{
IoPacket = new (NonPagedPool) CIoPacket(m_pLowerDeviceObject->StackSize);
if(!ALLOCATED_OK(IoPacket)) break;
IoPacket->setTimeout(getCommandTimeout());
Pipe = &m_Interface->Pipes[i]; // PUSBD_PIPE_INFORMATION PipeInfo;
if ( Pipe->PipeFlags )
{ // we set this if open, clear if closed
Urb->UrbHeader.Length = sizeof (struct _URB_PIPE_REQUEST);
Urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
Urb->UrbPipeRequest.PipeHandle = Pipe->PipeHandle;
IoPacket->buildStack(getSystemObject(),IRP_MJ_INTERNAL_DEVICE_CONTROL, 0, IOCTL_INTERNAL_USB_SUBMIT_URB,Urb);
Status = sendRequestToDeviceAndWait(IoPacket);
if (!NT_SUCCESS(Status))
{
TRACE("##### ERROR: Failed to abort Pipe %d\n",i);
}
Pipe->PipeFlags = FALSE; // mark the pipe 'closed'
}
DISPOSE_OBJECT(IoPacket);
}
if(Urb) memory->free(Urb);
TRACE(("**** Interface pipes were resetted ****\n"));
return STATUS_SUCCESS;;
}
// Overwrite base class virtual functions
//Handle IRP_MJ_DEVICE_CONTROL request
NTSTATUS CUSBDevice::deviceControl(IN PIRP Irp)
{
if (!NT_SUCCESS(acquireRemoveLock())) return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
PIO_STACK_LOCATION stack = irp->getCurrentStackLocation(Irp);
ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
//ULONG outlength = stack->Parameters.DeviceIoControl.OutputBufferLength;
NTSTATUS status = STATUS_SUCCESS;
ULONG info = 0;
TRACE("IRP_MJ_DEVICE_CONTROL\n");
//switch (code)
{ // process control operation
//default:
TRACE("INVALID_DEVICE_REQUEST\n");
status = STATUS_INVALID_DEVICE_REQUEST;
}
releaseRemoveLock();
return completeDeviceRequest(Irp, status, info);
}
NTSTATUS CUSBDevice::read(IN PIRP Irp)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG info = 0;
CIoPacket* IoPacket;
if (!NT_SUCCESS(acquireRemoveLock())) return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
TRACE("---- Read request ----\n");
if(!m_ResponsePipe)
{
TRACE("#### ERROR: Response Pipe is not ready yet!...\n");
releaseRemoveLock();
return completeDeviceRequest(Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
}
if(!NT_SUCCESS(status = waitForIdleAndBlock()))
{
releaseRemoveLock();
return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
}
if(Response_ErrorNum)
{
NTSTATUS res_status = resetPipe(m_ResponsePipe);
if(NT_SUCCESS(res_status)) Response_ErrorNum = 0;
}
IoPacket = new (NonPagedPool) CIoPacket(Irp);
if(!ALLOCATED_OK(IoPacket))
{
DISPOSE_OBJECT(IoPacket);
setIdle();
releaseRemoveLock();
return completeDeviceRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
}
status = readSynchronously(IoPacket,m_ResponsePipe);
TRACE("---- Read completed ----\n");
status = completeDeviceRequest(IoPacket->getIrpHandle(), status, IoPacket->getInformation());
DISPOSE_OBJECT(IoPacket);
setIdle();
releaseRemoveLock();
return status;
}
NTSTATUS CUSBDevice::write(IN PIRP Irp)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG info = 0;
CIoPacket* IoPacket;
if(!Irp) return STATUS_INVALID_PARAMETER;
if (!NT_SUCCESS(acquireRemoveLock())) return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
TRACE("---- Write request ----\n");
if(!m_CommandPipe)
{
TRACE("#### ERROR: Command Pipe is not ready yet!...\n");
releaseRemoveLock();
return completeDeviceRequest(Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
}
if(!NT_SUCCESS(status = waitForIdleAndBlock()))
{
releaseRemoveLock();
return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
}
if(Command_ErrorNum)
{
NTSTATUS res_status = resetPipe(m_CommandPipe);
if(NT_SUCCESS(res_status)) Command_ErrorNum = 0;
}
IoPacket = new (NonPagedPool) CIoPacket(Irp);
if(!ALLOCATED_OK(IoPacket))
{
DISPOSE_OBJECT(IoPacket);
releaseRemoveLock();
return completeDeviceRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
}
status = writeSynchronously(IoPacket,m_CommandPipe);
releaseRemoveLock();
TRACE("---- Write completed ----\n");
status = completeDeviceRequest(IoPacket->getIrpHandle(), status, IoPacket->getInformation());
DISPOSE_OBJECT(IoPacket);
setIdle();
releaseRemoveLock();
return status;
}
NTSTATUS CUSBDevice::sendRequestToDevice(CIoPacket* IoPacket,PIO_COMPLETION_ROUTINE Routine)
{
if(!IoPacket) return STATUS_INVALID_PARAMETER;
IoPacket->copyStackToNext();
if(Routine) IoPacket->setCompletion(Routine);
else IoPacket->setDefaultCompletionFunction();
return system->callDriver(getLowerDriver(),IoPacket->getIrpHandle());
};
// Send request to low level driver and wait for reply
// Current IRP will not be completed, so we can process it and
// complete later.
// See also description of send() function.
NTSTATUS CUSBDevice::sendRequestToDeviceAndWait(CIoPacket* IoPacket)
{ // Send request to low level and wait for a reply
NTSTATUS status;
TRACE("sendAndWait...\n");
if(!IoPacket) return STATUS_INVALID_PARAMETER;
IoPacket->setStackDefaults();
status = system->callDriver(getLowerDriver(),IoPacket->getIrpHandle());
if(status == STATUS_PENDING)
{
TRACE("Waiting for the bus driver to complete...\n");
ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
status = IoPacket->waitForCompletion();
TRACE("Request completed with status %x\n",status);
}
return status;
};
NTSTATUS CUSBDevice::send(CIoPacket* packet)
{
NTSTATUS status;
if(!packet) return STATUS_INVALID_PARAMETER;
__try
{
if(packet->getMajorIOCtl()==IRP_MJ_READ)
{
if(!m_ResponsePipe)
{
TRACE("#### ERROR: Response Pipe is not ready yet!...\n");
status = STATUS_INVALID_DEVICE_REQUEST;
__leave;
}
status = readSynchronously(packet,m_ResponsePipe);
}
else
{
if(!m_CommandPipe)
{
TRACE("#### ERROR: Command Pipe is not ready yet!...\n");
status = STATUS_INVALID_DEVICE_REQUEST;
__leave;
}
status = writeSynchronously(packet,m_CommandPipe);
}
__leave;
}
__finally
{
}
return status;
};
NTSTATUS CUSBDevice::sendAndWait(CIoPacket* packet)
{
NTSTATUS status = STATUS_SUCCESS;
if(!packet) return STATUS_INVALID_PARAMETER;
__try
{
if(packet->getMajorIOCtl()==IRP_MJ_READ)
{
TRACE("---- Packet Read request ----\n");
if(!m_ResponsePipe)
{
TRACE("#### ERROR: Response Pipe is not ready yet!...\n");
status = STATUS_INVALID_DEVICE_REQUEST;
__leave;
}
status = readSynchronously(packet,m_ResponsePipe);
TRACE("---- Packet Read completed ----\n");
}
else
{
TRACE("---- Packet Write request ----\n");
if(!m_CommandPipe)
{
TRACE("#### ERROR: Command Pipe is not ready yet!...\n");
status = STATUS_INVALID_DEVICE_REQUEST;
__leave;
}
status = writeSynchronously(packet,m_CommandPipe);
TRACE("---- Packet Write completed ----\n");
if(!NT_SUCCESS(status))
{
TRACE("writeSynchronously reported error %x\n", status);
}
}
__leave;
}
__finally
{
}
return status;
};
NTSTATUS CUSBDevice::readSynchronously(CIoPacket* Irp,IN USBD_PIPE_HANDLE Pipe)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB Urb = NULL;
NTSTATUS Status;
if(!Irp) return STATUS_INVALID_PARAMETER;
if(Pipe != m_ResponsePipe && Pipe != m_InterruptPipe)
{
TRACE("##### ERROR: Invalid device Pipe requested!...\n");
return STATUS_INVALID_DEVICE_REQUEST;
}
Urb = buildBusTransferRequest(Irp,RESPONSE_REQUEST);
if (!Urb)
{
TRACE("#### ERROR: Failed to allocate Urb at Pipe read...\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Irp->buildStack(getSystemObject(),IRP_MJ_INTERNAL_DEVICE_CONTROL, 0, IOCTL_INTERNAL_USB_SUBMIT_URB,Urb);
Status = sendRequestToDeviceAndWait(Irp);
if (!NT_SUCCESS(Status))
{
TRACE("##### ERROR: Bus driver reported error 0x%x\n",Status);
Response_ErrorNum++;
Irp->setInformation(0);
}
else
{
Irp->setInformation(Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
finishBusTransferRequest(Irp,RESPONSE_REQUEST);
}
USBD_STATUS urb_status = URB_STATUS(Urb);
TRACE("URB reports status %8.8lX\n",urb_status);
memory->free(Urb);
return Status;
}
NTSTATUS CUSBDevice::writeSynchronously(CIoPacket* Irp,IN USBD_PIPE_HANDLE Pipe)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB Urb = NULL;
NTSTATUS Status;
if(!Irp) return STATUS_INVALID_PARAMETER;
if(Pipe != m_CommandPipe)
{
TRACE("##### ERROR: Invalid device Pipe requested!...\n");
return STATUS_INVALID_DEVICE_REQUEST;
}
Urb = buildBusTransferRequest(Irp,COMMAND_REQUEST);
if (!Urb)
{
TRACE("#### ERROR: Failed to allocate Urb at Pipe read...\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Irp->buildStack(getSystemObject(),IRP_MJ_INTERNAL_DEVICE_CONTROL, 0, IOCTL_INTERNAL_USB_SUBMIT_URB,Urb);
Status = sendRequestToDeviceAndWait(Irp);
if (!NT_SUCCESS(Status))
{
TRACE("##### ERROR: Bus driver reported error %8.8lX\n",Status);
Command_ErrorNum++;
}
else
{
finishBusTransferRequest(Irp,COMMAND_REQUEST);
}
USBD_STATUS urb_status = URB_STATUS(Urb);
TRACE(" URB reports status %8.8lX\n",urb_status);
Irp->setInformation(0);
memory->free(Urb);
return Status;
}
NTSTATUS CUSBDevice::writeAndWait(PUCHAR pRequest,ULONG RequestLength,PUCHAR pReply,ULONG* pReplyLength)
{
NTSTATUS status;
CIoPacket* IoPacket;
if(!pRequest || !RequestLength || !pReply || !pReplyLength) return STATUS_INVALID_PARAMETER;
if(Response_ErrorNum || Command_ErrorNum)
{
TRACE("======= RESETTING ERROR CONDITIONS! =========\n");
NTSTATUS res_status = resetDevice();
if(NT_SUCCESS(res_status))
{
Command_ErrorNum = 0;
Response_ErrorNum = 0;
}
else
{
*pReplyLength = 0;
TRACE("======= FAILED TO RESET DEVICE! =========\n");
return STATUS_INVALID_DEVICE_STATE;
}
/*
NTSTATUS res_status = resetPipe(m_ResponsePipe);
if(NT_SUCCESS(res_status)) Response_ErrorNum = 0;
else
{
*pReplyLength = 0;
TRACE("======= FAILED TO RESET RESPONSE PIPE! =========\n");
resetDevice();
//return STATUS_INVALID_DEVICE_STATE;
}
res_status = resetPipe(m_CommandPipe);
if(NT_SUCCESS(res_status)) Command_ErrorNum = 0;
else
{
*pReplyLength = 0;
TRACE("======= FAILED TO RESET COMMAND PIPE! =========\n");
//return STATUS_INVALID_DEVICE_STATE;
res_status = resetDevice();
if(NT_SUCCESS(res_status)) Command_ErrorNum = 0;
else
{
*pReplyLength = 0;
TRACE("======= FAILED TO RESET DEVICE! =========\n");
return STATUS_INVALID_DEVICE_STATE;
}
}
*/
}
IoPacket = new (NonPagedPool) CIoPacket(getLowerDriver()->StackSize);
if(!ALLOCATED_OK(IoPacket))
{
DISPOSE_OBJECT(IoPacket);
return STATUS_INSUFFICIENT_RESOURCES;
}
IoPacket->setTimeout(getCommandTimeout());
TRACE("IoPacket with device %x\n",getSystemObject());
IoPacket->buildStack(getSystemObject(),IRP_MJ_WRITE);
IoPacket->setWriteLength(RequestLength);
IoPacket->copyBuffer(pRequest,RequestLength);
TRACE(" USB sendAndWait()...\n");
status = sendAndWait(IoPacket);
TRACE(" USB writeAndWait finished: %x\n",status);
if(!NT_SUCCESS(status))
{
*pReplyLength = 0;
IoPacket->dispose();
return status;
}
// Ignore bus driver reply...
DISPOSE_OBJECT(IoPacket);
TRACE(" **** Current WTR %d\n",get_WTR_Delay());
DELAY(get_WTR_Delay());
IoPacket = new (NonPagedPool) CIoPacket(getLowerDriver()->StackSize);
if(!ALLOCATED_OK(IoPacket))
{
DISPOSE_OBJECT(IoPacket);
return STATUS_INSUFFICIENT_RESOURCES;
}
IoPacket->setTimeout(getCommandTimeout());
IoPacket->buildStack(getSystemObject(),IRP_MJ_READ);
IoPacket->setReadLength(RequestLength);
IoPacket->copyBuffer(pRequest,RequestLength);
TRACE(" USB sendAndWait()...\n");
status = sendAndWait(IoPacket);
TRACE(" USB sendAndWait finished: %x\n",status);
if(!NT_SUCCESS(status))
{
*pReplyLength = 0;
IoPacket->dispose();
return status;
}
*pReplyLength = (ULONG)IoPacket->getInformation();
IoPacket->getSystemReply(pReply,*pReplyLength);
//TRACE_BUFFER(pReply,*pReplyLength);
DISPOSE_OBJECT(IoPacket);
return status;
};
NTSTATUS CUSBDevice::readAndWait(PUCHAR pRequest,ULONG RequestLength,PUCHAR pReply,ULONG* pReplyLength)
{
CIoPacket* IoPacket;
if(!pRequest || !RequestLength || !pReply || !pReplyLength) return STATUS_INVALID_PARAMETER;
if(Response_ErrorNum || Command_ErrorNum)
{
TRACE("======= RESETTING ERROR CONDITIONS! =========\n");
NTSTATUS res_status = resetDevice();
if(NT_SUCCESS(res_status))
{
Command_ErrorNum = 0;
Response_ErrorNum = 0;
}
else
{
*pReplyLength = 0;
TRACE("======= FAILED TO RESET DEVICE! =========\n");
return STATUS_INVALID_DEVICE_STATE;
}
/*TRACE("======= RESETTING ERROR CONDITIONS AT PIPES! =========\n");
NTSTATUS res_status = resetPipe(m_ResponsePipe);
if(NT_SUCCESS(res_status)) Response_ErrorNum = 0;
else
{
*pReplyLength = 0;
TRACE("======= FAILED TO RESET RESPONSE PIPE! =========\n");
return STATUS_INVALID_DEVICE_STATE;
}
res_status = resetPipe(m_CommandPipe);
if(NT_SUCCESS(res_status)) Command_ErrorNum = 0;
else
{
*pReplyLength = 0;
TRACE("======= FAILED TO RESET COMMAND PIPE! =========\n");
return STATUS_INVALID_DEVICE_STATE;
}
*/
}
IoPacket = new (NonPagedPool) CIoPacket(getLowerDriver()->StackSize);
if(!ALLOCATED_OK(IoPacket))
{
DISPOSE_OBJECT(IoPacket);
return STATUS_INSUFFICIENT_RESOURCES;
}
IoPacket->setTimeout(getCommandTimeout());
IoPacket->buildStack(getSystemObject(),IRP_MJ_READ);
IoPacket->setReadLength(RequestLength);
IoPacket->copyBuffer(pRequest,RequestLength);
TRACE("WDM sendAndWait()...\n");
NTSTATUS status = sendAndWait(IoPacket);
TRACE("WDM sendAndWait finished: %x\n",status);
if(!NT_SUCCESS(status))
{
*pReplyLength = 0;
IoPacket->dispose();
return status;
}
*pReplyLength = (ULONG)IoPacket->getInformation();
IoPacket->getSystemReply(pReply,*pReplyLength);
//TRACE_BUFFER(pReply,*pReplyLength);
DISPOSE_OBJECT(IoPacket);
return status;
};
// Handle IRP_MJ_POWER request
// This routine uses the IRP's minor function code to dispatch a handler
// function (such as HandleSetPower for IRP_MN_SET_POWER). It calls DefaultPowerHandler
// for any function we don't specifically need to handle.
NTSTATUS CUSBDevice::powerRequest(IN PIRP Irp)
{
if(!Irp) return STATUS_INVALID_PARAMETER;
if (!NT_SUCCESS(acquireRemoveLock()))
{
power->startNextPowerIrp(Irp); // must be done while we own the IRP
return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
}
PIO_STACK_LOCATION stack = irp->getCurrentStackLocation(Irp);
ASSERT(stack->MajorFunction == IRP_MJ_POWER);
ULONG fcn = stack->MinorFunction;
NTSTATUS status;
if (fcn >= arraysize(Powerfcntab))
{ // unknown function
status = power_Default(Irp);
releaseRemoveLock();
return status;
}
#ifdef DEBUG
if (fcn == IRP_MN_SET_POWER || fcn == IRP_MN_QUERY_POWER)
{
ULONG context = stack->Parameters.Power.SystemContext;
POWER_STATE_TYPE type = stack->Parameters.Power.Type;
TRACE("\n(%s)\nSystemContext %X, ", Powerfcnname[fcn], context);
if (type==SystemPowerState)
{
TRACE("SYSTEM POWER STATE = %s\n", Powersysstate[stack->Parameters.Power.State.SystemState]);
}
else
{
TRACE("DEVICE POWER STATE = %s\n", Powerdevstate[stack->Parameters.Power.State.DeviceState]);
}
}
else
TRACE("Request (%s)\n", Powerfcnname[fcn]);
#endif // DEBUG
status = callPowerHandler(fcn,Irp);
releaseRemoveLock();
return status;
}
VOID CUSBDevice::activatePowerHandler(LONG HandlerID)
{
if (HandlerID >= arraysize(Powerfcntab)) return;
Powerfcntab[HandlerID] = TRUE;
}
VOID CUSBDevice::disActivatePowerHandler(LONG HandlerID)
{
if (HandlerID >= arraysize(Powerfcntab)) return;
Powerfcntab[HandlerID] = FALSE;
}
NTSTATUS CUSBDevice::callPowerHandler(LONG HandlerID,IN PIRP Irp)
{
if(!Powerfcntab[HandlerID]) // If Handler is not registered...
return power_Default(Irp);
// Call registered Power Handler...
// This is virtual function...
switch(HandlerID)
{
case IRP_MN_WAIT_WAKE: return power_HandleWaitWake(Irp);
break;
case IRP_MN_POWER_SEQUENCE: return power_HandleSequencePower(Irp);
break;
case IRP_MN_SET_POWER: return power_HandleSetPower(Irp);
break;
case IRP_MN_QUERY_POWER: return power_HandleQueryPower(Irp);
break;
}
return power_Default(Irp);
}
#pragma PAGEDCODE
NTSTATUS CUSBDevice::power_HandleSetPower(IN PIRP Irp)
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status = STATUS_SUCCESS;
BOOLEAN fGoingToD0 = FALSE;
POWER_STATE sysPowerState, desiredDevicePowerState;
if(!Irp) return STATUS_INVALID_PARAMETER;
irpStack = irp->getCurrentStackLocation (Irp);
switch (irpStack->Parameters.Power.Type)
{
case SystemPowerState:
// Get input system power state
sysPowerState.SystemState = irpStack->Parameters.Power.State.SystemState;
#ifdef DEBUG
TRACE("Set Power with type SystemPowerState = %s\n",Powersysstate[sysPowerState.SystemState]);
#endif
// If system is in working state always set our device to D0
// regardless of the wait state or system-to-device state power map
if ( sysPowerState.SystemState == PowerSystemWorking)
{
desiredDevicePowerState.DeviceState = PowerDeviceD0;
TRACE("PowerSystemWorking, device will be set to D0, state map is not used\n");
}
else
{
// set to corresponding system state if IRP_MN_WAIT_WAKE pending
if (isEnabledForWakeup())
{ // got a WAIT_WAKE IRP pending?
// Find the device power state equivalent to the given system state.
// We get this info from the DEVICE_CAPABILITIES struct in our device
// extension (initialized in BulkUsb_PnPAddDevice() )
desiredDevicePowerState.DeviceState = m_DeviceCapabilities.DeviceState[sysPowerState.SystemState];
TRACE("IRP_MN_WAIT_WAKE pending, will use state map\n");
}
else
{
// if no wait pending and the system's not in working state, just turn off
desiredDevicePowerState.DeviceState = PowerDeviceD3;
TRACE("Not EnabledForWakeup and the system's not in the working state,\n settting PowerDeviceD3(off)\n");
}
}
// We've determined the desired device state; are we already in this state?
#ifdef DEBUG
TRACE("Set Power, desiredDevicePowerState = %s\n",
Powerdevstate[desiredDevicePowerState.DeviceState]);
#endif
if (desiredDevicePowerState.DeviceState != m_CurrentDevicePowerState)
{
acquireRemoveLock();// Callback will release the lock
// No, request that we be put into this state
// by requesting a new Power Irp from the Pnp manager
registerPowerIrp(Irp);
IoMarkIrpPending(Irp);
status = power->requestPowerIrp(getSystemObject(),
IRP_MN_SET_POWER,
desiredDevicePowerState,
// completion routine will pass the Irp down to the PDO
(PREQUEST_POWER_COMPLETE)onPowerRequestCompletion,
this, NULL);
}
else
{ // Yes, just pass it on to PDO (Physical Device Object)
irp->copyCurrentStackLocationToNext(Irp);
power->startNextPowerIrp(Irp);
status = power->callPowerDriver(getLowerDriver(),Irp);
}
break;
case DevicePowerState:
#ifdef DEBUG
TRACE("Set DevicePowerState %s\n",
Powerdevstate[irpStack->Parameters.Power.State.DeviceState]);
#endif
// For requests to D1, D2, or D3 ( sleep or off states ),
// sets deviceExtension->CurrentDevicePowerState to DeviceState immediately.
// This enables any code checking state to consider us as sleeping or off
// already, as this will imminently become our state.
// For requests to DeviceState D0 ( fully on ), sets fGoingToD0 flag TRUE
// to flag that we must set a completion routine and update
// deviceExtension->CurrentDevicePowerState there.
// In the case of powering up to fully on, we really want to make sure
// the process is completed before updating our CurrentDevicePowerState,
// so no IO will be attempted or accepted before we're really ready.
fGoingToD0 = setDevicePowerState(irpStack->Parameters.Power.State.DeviceState); // returns TRUE for D0
if (fGoingToD0)
{
acquireRemoveLock();// Callback will release the lock
TRACE("Set PowerIrp Completion Routine, fGoingToD0 =%d\n", fGoingToD0);
irp->copyCurrentStackLocationToNext(Irp);
irp->setCompletionRoutine(Irp,
onPowerIrpComplete,
// Always pass FDO to completion routine as its Context;
// This is because the DriverObject passed by the system to the routine
// is the Physical Device Object ( PDO ) not the Functional Device Object ( FDO )
this,
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
// Completion routine will set our state and start next power Irp
}
else
{
// D3 device state
//Device reduces power, so do specific for device processing...
onSystemPowerDown();
// Report our state to power manager
desiredDevicePowerState.DeviceState = PowerDeviceD3;
power->declarePowerState(getSystemObject(),DevicePowerState,desiredDevicePowerState);
irp->copyCurrentStackLocationToNext(Irp);
power->startNextPowerIrp(Irp);
}
status = power->callPowerDriver(getLowerDriver(),Irp);
break;
} /* case irpStack->Parameters.Power.Type */
return status;
}
#pragma PAGEDCODE
VOID CUSBDevice::onSystemPowerDown()
{
return;
}
#pragma PAGEDCODE
VOID CUSBDevice::onSystemPowerUp()
{
return;
}
#pragma PAGEDCODE
BOOLEAN CUSBDevice::setDevicePowerState(IN DEVICE_POWER_STATE DeviceState)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
BOOLEAN fRes = FALSE;
switch (DeviceState)
{
case PowerDeviceD3:
// Device will be going OFF,
// TODO: add any needed device-dependent code to save state here.
// ( We have nothing to do in this sample )
TRACE("SetDevicePowerState() PowerDeviceD3 (OFF)\n");
setCurrentDevicePowerState(DeviceState);
break;
case PowerDeviceD1:
case PowerDeviceD2:
// power states D1,D2 translate to USB suspend
#ifdef DEBUG
TRACE("SetDevicePowerState() %s\n",Powerdevstate[DeviceState]);
#endif
setCurrentDevicePowerState(DeviceState);
break;
case PowerDeviceD0:
TRACE("Set Device Power State to PowerDeviceD0(ON)\n");
// We'll need to finish the rest in the completion routine;
// signal caller we're going to D0 and will need to set a completion routine
fRes = TRUE;
// Caller will pass on to PDO ( Physical Device object )
break;
default:
TRACE(" Bogus DeviceState = %x\n", DeviceState);
}
return fRes;
}
/*++
Routine Description:
This is the completion routine set in a call to PoRequestPowerIrp()
that was made in ProcessPowerIrp() in response to receiving
an IRP_MN_SET_POWER of type 'SystemPowerState' when the device was
not in a compatible device power state. In this case, a pointer to
the IRP_MN_SET_POWER Irp is saved into the FDO device extension
(deviceExtension->PowerIrp), and then a call must be
made to PoRequestPowerIrp() to put the device into a proper power state,
and this routine is set as the completion routine.
We decrement our pending io count and pass the saved IRP_MN_SET_POWER Irp
on to the next driver
Arguments:
DeviceObject - Pointer to the device object for the class device.
Note that we must get our own device object from the Context
Context - Driver defined context, in this case our own functional device object ( FDO )
Return Value:
The function value is the final status from the operation.
--*/
#pragma LOCKEDCODE
NTSTATUS onPowerRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
PIRP Irp;
NTSTATUS status;
if(!Context) return STATUS_INVALID_PARAMETER;
CUSBReader* device = (CUSBReader*) Context;
// Get the Irp we saved for later processing
// when we decided to request the Power Irp that this routine
// is the completion routine for.
Irp = device->getPowerIrp();
// We will return the status set by the PDO for the power request we're completing
status = IoStatus->Status;
DBG_PRINT("Enter onPowerRequestCompletion()\n");
// we must pass down to the next driver in the stack
IoCopyCurrentIrpStackLocationToNext(Irp);
// Calling PoStartNextPowerIrp() indicates that the driver is finished
// with the previous power IRP, if any, and is ready to handle the next power IRP.
// It must be called for every power IRP.Although power IRPs are completed only once,
// typically by the lowest-level driver for a device, PoStartNextPowerIrp must be called
// for every stack location. Drivers must call PoStartNextPowerIrp while the current IRP
// stack location points to the current driver. Therefore, this routine must be called
// before IoCompleteRequest, IoSkipCurrentStackLocation, and PoCallDriver.
PoStartNextPowerIrp(Irp);
// PoCallDriver is used to pass any power IRPs to the PDO instead of IoCallDriver.
// When passing a power IRP down to a lower-level driver, the caller should use
// IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext to copy the IRP to
// the next stack location, then call PoCallDriver. Use IoCopyCurrentIrpStackLocationToNext
// if processing the IRP requires setting a completion routine, or IoSkipCurrentStackLocation
// if no completion routine is needed.
PoCallDriver(device->getLowerDriver(),Irp);
device->unregisterPowerIrp();
device->releaseRemoveLock();
DBG_PRINT("Exit onPowerRequestCompletion()\n");
return status;
}
/*++
Routine Description:
This routine is called when An IRP_MN_SET_POWER of type 'DevicePowerState'
has been received by BulkUsb_ProcessPowerIrp(), and that routine has determined
1) the request is for full powerup ( to PowerDeviceD0 ), and
2) We are not already in that state
A call is then made to PoRequestPowerIrp() with this routine set as the completion routine.
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.
--*/
#pragma LOCKEDCODE
NTSTATUS onPowerIrpComplete(
IN PDEVICE_OBJECT NullDeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack;
POWER_STATE desiredDevicePowerState;
DBG_PRINT("Enter onPowerIrpComplete()\n");
if(!Context) return STATUS_INVALID_PARAMETER;
CUSBReader* device = (CUSBReader*) Context;
// If the lower driver returned PENDING, mark our stack location as pending also.
if (Irp->PendingReturned) IoMarkIrpPending(Irp);
irpStack = IoGetCurrentIrpStackLocation (Irp);
// We can assert that we're a device powerup-to D0 request,
// because that was the only type of request we set a completion routine
// for in the first place
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);
// Now that we know we've let the lower drivers do what was needed to power up,
// we can set our device extension flags accordingly
device->setCurrentDevicePowerState(PowerDeviceD0);
// Do device specific stuff...
device->onSystemPowerUp();
Irp->IoStatus.Status = status;
device->releaseRemoveLock();
desiredDevicePowerState.DeviceState = PowerDeviceD0;
PoSetPowerState(device->getSystemObject(),DevicePowerState,desiredDevicePowerState);
PoStartNextPowerIrp(Irp);
DBG_PRINT("Exit onPowerIrpComplete() for the state D0\n");
return status;
}
#pragma PAGEDCODE
NTSTATUS CUSBDevice::power_HandleWaitWake(IN PIRP Irp)
{
return power_Default(Irp);
}
NTSTATUS CUSBDevice::power_HandleSequencePower(IN PIRP Irp)
{
return power_Default(Irp);
}
NTSTATUS CUSBDevice::power_HandleQueryPower(IN PIRP Irp)
{
TRACE("******** QUERY POWER ********\n");
if(isDeviceLocked())
{
TRACE("******** FAILED TO CHANGE POWER (DEVICE BUSY) ********\n");
Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
power->startNextPowerIrp(Irp); // must be done while we own the IRP
return completeDeviceRequest(Irp, STATUS_DEVICE_BUSY, 0);
}
Irp->IoStatus.Status = STATUS_SUCCESS;
return power_Default(Irp);
}
NTSTATUS CUSBDevice::createDeviceObjectByName(PDEVICE_OBJECT* ppFdo)
{
NTSTATUS status;
// Construct device name...
CUString* index = new (PagedPool) CUString(getDeviceNumber(),10);
CUString* base = new (PagedPool) CUString(NT_OBJECT_NAME);
if(!ALLOCATED_OK(index) || !ALLOCATED_OK(base))
{
DISPOSE_OBJECT(index);
DISPOSE_OBJECT(base);
return STATUS_INSUFFICIENT_RESOURCES;
}
USHORT size = (USHORT)(index->getLength() + base->getLength() + sizeof(WCHAR));
// Allocate string with required length
m_DeviceObjectName = new (NonPagedPool) CUString(size);
if(!ALLOCATED_OK(m_DeviceObjectName))
{
DISPOSE_OBJECT(index);
DISPOSE_OBJECT(base);
DISPOSE_OBJECT(m_DeviceObjectName);
return STATUS_INSUFFICIENT_RESOURCES;
}
m_DeviceObjectName->append(&base->m_String);
m_DeviceObjectName->append(&index->m_String);
TRACE("Driver registers DeviceObjectName as %ws\n", m_DeviceObjectName->m_String.Buffer);
delete index;
delete base;
status = system->createDevice(m_DriverObject,sizeof(CWDMDevice*),&m_DeviceObjectName->m_String,
FILE_DEVICE_UNKNOWN,0,FALSE,ppFdo);
if(!NT_SUCCESS(status))
{
TRACE("#### Failed to create physical device! Status %x\n",status);
delete m_DeviceObjectName;
}
return status;
}
#endif // USBDEVICE_PROJECT