NTSTATUS ReenumerateDevice( _In_ PDEVICE_CONTEXT DevContext ) /*++ Routine Description This routine re-enumerates the USB device. Arguments: pDevContext - One of our device extensions Return Value: NT status value --*/ { NTSTATUS status; WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; WDF_REQUEST_SEND_OPTIONS sendOptions; GUID activity; PAGED_CODE(); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"--> ReenumerateDevice\n"); WDF_REQUEST_SEND_OPTIONS_INIT( &sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT ); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( &sendOptions, DEFAULT_CONTROL_TRANSFER_TIMEOUT ); WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, BmRequestHostToDevice, BmRequestToDevice, USBFX2LK_REENUMERATE, // Request 0, // Value 0); // Index status = WdfUsbTargetDeviceSendControlTransferSynchronously( DevContext->UsbDevice, WDF_NO_HANDLE, // Optional WDFREQUEST &sendOptions, &controlSetupPacket, NULL, // MemoryDescriptor NULL); // BytesTransferred if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ReenumerateDevice: Failed to Reenumerate - 0x%x \n", status); } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"<-- ReenumerateDevice\n"); // // Send event to eventlog // activity = DeviceToActivityId(WdfObjectContextGetObject(DevContext)); EventWriteDeviceReenumerated(DevContext->DeviceName, DevContext->Location, status); return status; }
NTSTATUS OsrFxEvtDeviceAdd( WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. We create and initialize a device object to represent a new instance of the device. All the software resources should be allocated in this callback. Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_OBJECT_ATTRIBUTES attributes; NTSTATUS status; WDFDEVICE device; WDF_DEVICE_PNP_CAPABILITIES pnpCaps; WDF_IO_QUEUE_CONFIG ioQueueConfig; PDEVICE_CONTEXT pDevContext; WDFQUEUE queue; GUID activity; UNREFERENCED_PARAMETER(Driver); PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"--> OsrFxEvtDeviceAdd routine\n"); // // Initialize the pnpPowerCallbacks structure. Callback events for PNP // and Power are specified here. If you don't supply any callbacks, // the Framework will take appropriate default actions based on whether // DeviceInit is initialized to be an FDO, a PDO or a filter device // object. // WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); // // For usb devices, PrepareHardware callback is the to place select the // interface and configure the device. // pnpPowerCallbacks.EvtDevicePrepareHardware = OsrFxEvtDevicePrepareHardware; // // These two callbacks start and stop the wdfusb pipe continuous reader // as we go in and out of the D0-working state. // pnpPowerCallbacks.EvtDeviceD0Entry = OsrFxEvtDeviceD0Entry; pnpPowerCallbacks.EvtDeviceD0Exit = OsrFxEvtDeviceD0Exit; pnpPowerCallbacks.EvtDeviceSelfManagedIoFlush = OsrFxEvtDeviceSelfManagedIoFlush; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); // // Now specify the size of device extension where we track per device // context.DeviceInit is completely initialized. So call the framework // to create the device and attach it to the lower stack. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); status = WdfDeviceCreate(&DeviceInit, &attributes, &device); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreate failed with Status code %!STATUS!\n", status); return status; } // // Setup the activity ID so that we can log events using it. // activity = DeviceToActivityId(device); // // Get the DeviceObject context by using accessor function specified in // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_CONTEXT. // pDevContext = GetDeviceContext(device); // // Get the device's friendly name and location so that we can use it in // error logging. If this fails then it will setup dummy strings. // GetDeviceEventLoggingNames(device); // // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so // that you don't get the popup in usermodewhen you surprise remove the device. // WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); pnpCaps.SurpriseRemovalOK = WdfTrue; WdfDeviceSetPnpCapabilities(device, &pnpCaps); // // Create a parallel default queue and register an event callback to // receive ioctl requests. We will create separate queues for // handling read and write requests. All other requests will be // completed with error status automatically by the framework. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchParallel); ioQueueConfig.EvtIoDeviceControl = OsrFxEvtIoDeviceControl; // // By default, Static Driver Verifier (SDV) displays a warning if it // doesn't find the EvtIoStop callback on a power-managed queue. // The 'assume' below causes SDV to suppress this warning. If the driver // has not explicitly set PowerManaged to WdfFalse, the framework creates // power-managed queues when the device is not a filter driver. Normally // the EvtIoStop is required for power-managed queues, but for this driver // it is not needed b/c the driver doesn't hold on to the requests for // long time or forward them to other drivers. // If the EvtIoStop callback is not implemented, the framework waits for // all driver-owned requests to be done before moving in the Dx/sleep // states or before removing the device, which is the correct behavior // for this type of driver. If the requests were taking an indeterminate // amount of time to complete, or if the driver forwarded the requests // to a lower driver/another stack, the queue should have an // EvtIoStop/EvtIoResume. // __analysis_assume(ioQueueConfig.EvtIoStop != 0); status = WdfIoQueueCreate(device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue);// pointer to default queue __analysis_assume(ioQueueConfig.EvtIoStop == 0); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed %!STATUS!\n", status); goto Error; } // // We will create a separate sequential queue and configure it // to receive read requests. We also need to register a EvtIoStop // handler so that we can acknowledge requests that are pending // at the target driver. // WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoRead = OsrFxEvtIoRead; ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; status = WdfIoQueueCreate( device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue // queue handle ); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed 0x%x\n", status); goto Error; } status = WdfDeviceConfigureRequestDispatching( device, queue, WdfRequestTypeRead); if(!NT_SUCCESS (status)){ assert(NT_SUCCESS(status)); TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); goto Error; } // // We will create another sequential queue and configure it // to receive write requests. // WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoWrite = OsrFxEvtIoWrite; ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; status = WdfIoQueueCreate( device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue // queue handle ); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed 0x%x\n", status); goto Error; } status = WdfDeviceConfigureRequestDispatching( device, queue, WdfRequestTypeWrite); if(!NT_SUCCESS (status)){ assert(NT_SUCCESS(status)); TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); goto Error; } // // Register a manual I/O queue for handling Interrupt Message Read Requests. // This queue will be used for storing Requests that need to wait for an // interrupt to occur before they can be completed. // WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchManual); // // This queue is used for requests that dont directly access the device. The // requests in this queue are serviced only when the device is in a fully // powered state and sends an interrupt. So we can use a non-power managed // queue to park the requests since we dont care whether the device is idle // or fully powered up. // ioQueueConfig.PowerManaged = WdfFalse; status = WdfIoQueueCreate(device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevContext->InterruptMsgQueue ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed 0x%x\n", status); goto Error; } // // Register a device interface so that app can find our device and talk to it. // status = WdfDeviceCreateDeviceInterface(device, (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, NULL); // Reference String if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreateDeviceInterface failed %!STATUS!\n", status); goto Error; } // // Create the lock that we use to serialize calls to ResetDevice(). As an // alternative to using a WDFWAITLOCK to serialize the calls, a sequential // WDFQUEUE can be created and reset IOCTLs would be forwarded to it. // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = device; status = WdfWaitLockCreate(&attributes, &pDevContext->ResetDeviceWaitLock); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfWaitLockCreate failed %!STATUS!\n", status); goto Error; } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- OsrFxEvtDeviceAdd\n"); return status; Error: // // Log fail to add device to the event log // EventWriteFailAddDevice(pDevContext->DeviceName, pDevContext->Location, status); return status; }
NTSTATUS SelectInterfaces( __in WDFDEVICE Device ) /*++ Routine Description: This helper routine selects the configuration, interface and creates a context for every pipe (end point) in that interface. Arguments: Device - Handle to a framework device Return Value: NT status value --*/ { WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; UCHAR index; UCHAR numberConfiguredPipes; PAGED_CODE(); pDeviceContext = GetDeviceContext(Device); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceSelectConfig failed %!STATUS! \n", status); // // Since the Osr USB fx2 device is capable of working at high speed, the only reason // the device would not be working at high speed is if the port doesn't // support it. If the port doesn't support high speed it is a 1.1 port // if ((pDeviceContext->UsbDeviceTraits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) == 0) { GUID activity = DeviceToActivityId(Device); TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, " On a 1.1 USB port on Windows Vista" " this is expected as the OSR USB Fx2 board's Interrupt EndPoint descriptor" " doesn't conform to the USB specification. Windows Vista detects this and" " returns an error. \n" ); EventWriteSelectConfigFailure( &activity, pDeviceContext->DeviceName, pDeviceContext->Location, status ); } return status; } pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; numberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; // // Get pipe handles // for(index=0; index < numberConfiguredPipes; index++) { WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); pipe = WdfUsbInterfaceGetConfiguredPipe( pDeviceContext->UsbInterface, index, //PipeIndex, &pipeInfo ); // // Tell the framework that it's okay to read less than // MaximumPacketSize // WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); if(WdfUsbPipeTypeInterrupt == pipeInfo.PipeType) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "Interrupt Pipe is 0x%p\n", pipe); pDeviceContext->InterruptPipe = pipe; } if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && WdfUsbTargetPipeIsInEndpoint(pipe)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "BulkInput Pipe is 0x%p\n", pipe); pDeviceContext->BulkReadPipe = pipe; } if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && WdfUsbTargetPipeIsOutEndpoint(pipe)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "BulkOutput Pipe is 0x%p\n", pipe); pDeviceContext->BulkWritePipe = pipe; } } // // If we didn't find all the 3 pipes, fail the start. // if(!(pDeviceContext->BulkWritePipe && pDeviceContext->BulkReadPipe && pDeviceContext->InterruptPipe)) { status = STATUS_INVALID_DEVICE_STATE; TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Device is not configured properly %!STATUS!\n", status); return status; } return status; }