#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; jNumberOfPipes; 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; iNumberOfPipes; 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; iNumberOfPipes; 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