2343 lines
91 KiB
C++
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
|
|
|