NTSTATUS CyConfigInterruptINepReader( __in PDEVICE_CONTEXT pDevContext, __in WDFUSBPIPE IntUsbPipe ) { NTSTATUS NtStatus; WDF_USB_CONTINUOUS_READER_CONFIG UsbContiReaderConfi; CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "Start CyConfigInterruptINepReader\n"); WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&UsbContiReaderConfi, CyEvtInterruptINepReaderComplete, pDevContext, sizeof(UCHAR)); NtStatus = WdfUsbTargetPipeConfigContinuousReader(IntUsbPipe, &UsbContiReaderConfi); if (!NT_SUCCESS(NtStatus)) { CyTraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "WdfUsbTargetPipeConfigContinuousReader failed %x\n", NtStatus); CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "End CyConfigInterruptINepReader\n"); return NtStatus; } CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "CyConfigInterruptINepReader successfull\n"); CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "End CyConfigInterruptINepReader\n"); return NtStatus; }
NTSTATUS HidFx2ConfigContReaderForInterruptEndPoint( PDEVICE_EXTENSION DeviceContext ) /*++ Routine Description: This routine configures a continuous reader on the interrupt endpoint. It's called from the PrepareHarware event. Arguments: DeviceContext - Pointer to device context structure Return Value: NT status value --*/ { WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig; NTSTATUS status = STATUS_SUCCESS; PAGED_CODE (); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "HidFx2ConfigContReaderForInterruptEndPoint Enter\n"); WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig, HidFx2EvtUsbInterruptPipeReadComplete, DeviceContext, // Context sizeof(UCHAR)); // TransferLength // // Reader requests are not posted to the target automatically. // Driver must explictly call WdfIoTargetStart to kick start the // reader. In this sample, it's done in D0Entry. // By defaut, framework queues two requests to the target // endpoint. Driver can configure up to 10 requests with CONFIG macro. // status = WdfUsbTargetPipeConfigContinuousReader(DeviceContext->InterruptPipe, &contReaderConfig); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "HidFx2ConfigContReaderForInterruptEndPoint failed %x\n", status); return status; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "HidFx2ConfigContReaderForInterruptEndPoint Exit, status:0x%x\n", status); return status; }
NTSTATUS EvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated ) { NTSTATUS status; PDEVICE_CONTEXT devCtx = NULL; WDF_USB_CONTINUOUS_READER_CONFIG interruptConfig; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); // Get device context devCtx = GetDeviceContext(Device); // Configure USB Interface status = ConfigureUsbInterface(Device, devCtx); if(!NT_SUCCESS(status)) return status; // Configure USB Pipe status = ConfigureUsbPipes(devCtx); if(!NT_SUCCESS(status)) return status; // Init Power Management status = InitPowerManagement(Device, devCtx); if(!NT_SUCCESS(status)) return status; /*Set up the interrupt endpoint with a continuous read operation. that way we are guaranteed that no interrupt data is lost.*/ WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&interruptConfig, EvtUsbDeviceInterrupt, // Interrupt Event devCtx, sizeof(BYTE)); status = WdfUsbTargetPipeConfigContinuousReader( devCtx->UsbInterruptPipe, &interruptConfig); if(!NT_SUCCESS(status)) { KdPrint((__DRIVER_NAME "WdfUsbTargetPipeConfigContinuousReader failed with status 0x%08x\n", status)); return status; } return status; }
// This routine configures a continuous reader on the interrupt endpoint. It's called from the PrepareHarware event. // NTSTATUS HidFx2ConfigContReaderForInterruptEndPoint(PDEVICE_EXTENSION pDeviceContext) { WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig; NTSTATUS status = STATUS_SUCCESS; PAGED_CODE (); TraceVerbose(DBG_INIT, "(%!FUNC!) Enter\n"); WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig, HidFx2EvtUsbInterruptPipeReadComplete, pDeviceContext, // Context sizeof(UCHAR)); // TransferLength status = WdfUsbTargetPipeConfigContinuousReader(pDeviceContext->hInterruptPipe, &contReaderConfig); if (!NT_SUCCESS(status)) { TraceErr(DBG_INIT, "(%!FUNC!) failed %!STATUS!\n", status); } TraceVerbose(DBG_INIT, "(%!FUNC!) Exit, status: %!STATUS!\n", status); return status; }
/////////////////////////////////////////////////////////////////////////////// // // BasicUsbEvtDevicePrepareHardware // // This routine is called by the framework when a device of // the type we support is coming online. Our job will be to // create our WDFUSBDEVICE and configure it. // // INPUTS: // // Device - One of our WDFDEVICE objects // // ResourceList - We're a USB device, so not used // // ResourceListTranslated - We're a USB device, so not // used // // OUTPUTS: // // None. // // RETURNS: // // STATUS_SUCCESS, otherwise an error indicating why the driver could not // load. // // IRQL: // // This routine is called at IRQL == PASSIVE_LEVEL. // // NOTES: // // /////////////////////////////////////////////////////////////////////////////// NTSTATUS BasicUsbEvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated ) { NTSTATUS status; PBASICUSB_DEVICE_CONTEXT devContext; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS selectConfigParams; WDFUSBINTERFACE configuredInterface; WDF_USB_PIPE_INFORMATION pipeInfo; UCHAR numPipes; UCHAR pipeIndex; WDFUSBPIPE configuredPipe; WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); #if DBG DbgPrint("BasicUsbEvtDevicePrepareHardware\n"); #endif devContext = BasicUsbGetContextFromDevice(Device); // // First thing to do is create our WDFUSBDEVICE. This is the // special USB I/O target that we'll be using to configure our // device and to send control requests. // // Under very rare cirumstances (i.e. resource rebalance of the // host controller) it's possible to come through here multiple // times. We could handle this by having an // EvtDeviceReleaseHardware and cleaning up the USB device // target, but we'll just leave it around and avoid creating it // multiple times with this check. No race condition as our // Prepare and Release can't run in parallel for the same device // if (devContext->BasicUsbUsbDevice == NULL) { status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &devContext->BasicUsbUsbDevice); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfUsbTargetDeviceCreate failed 0x%0x\n", status); #endif return status; } } // // Now that our WDFUSBDEVICE is created, it's time to select // our configuration and enable our interface. // // // The OSRFX2 device only has a single interface, so we'll // initialize our select configuration parameters structure // using the specially provided macro // WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &selectConfigParams); // // And actually select our configuration. // status = WdfUsbTargetDeviceSelectConfig(devContext->BasicUsbUsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &selectConfigParams); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfUsbTargetDeviceSelectConfig failed 0x%0x\n", status); #endif return status; } // // Our single interface has been configured. Let's grab the // WDFUSBINTERFACE object so that we can get our pipes. // configuredInterface = selectConfigParams.Types.SingleInterface.ConfiguredUsbInterface; // // How many pipes were configure? // numPipes = selectConfigParams.Types.SingleInterface.NumberConfiguredPipes; // // For all the pipes that were configured.... // for(pipeIndex = 0; pipeIndex < numPipes; pipeIndex++) { // // We'll need to find out the type the pipe, which we'll do // by supplying a pipe information structure when calling // WdfUsbInterfaceGetConfiguredPipe // WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); // // Get the configured pipe. // configuredPipe = WdfUsbInterfaceGetConfiguredPipe(configuredInterface, pipeIndex, &pipeInfo); // // For this device, we're looking for three pipes: // // 1) A Bulk IN pipe // 2) A Bulk OUT pipe // 3) An Interrupt IN pipe // // // First, let's see what type of pipe it is... // switch (pipeInfo.PipeType) { case WdfUsbPipeTypeBulk: { // // Bulk pipe. Determine if it's an IN pipe or not. // if (WdfUsbTargetPipeIsInEndpoint(configuredPipe)) { // // Bulk IN pipe. Should only ever get one of these... // ASSERT(devContext->BulkInPipe == NULL); devContext->BulkInPipe = configuredPipe; } else { // // HAS to be an OUT... // ASSERT(WdfUsbTargetPipeIsOutEndpoint(configuredPipe)); // // Bulk OUT pipe. Should only ever get one of these... // ASSERT(devContext->BulkOutPipe == NULL); devContext->BulkOutPipe = configuredPipe; } break; } case WdfUsbPipeTypeInterrupt: { // // We're only expecting an IN interrupt pipe // ASSERT(WdfUsbTargetPipeIsInEndpoint(configuredPipe)); // // And we're only expected one of them // ASSERT(devContext->InterruptInPipe == NULL); devContext->InterruptInPipe = configuredPipe; break; } default: { // // Don't know what it is, don't care what it is... // #if DBG DbgPrint("Unexpected pipe type? 0x%x\n", pipeInfo.PipeType); #endif break; } } } // // We hopefully have found everything we need... // if (devContext->BulkInPipe == NULL || devContext->BulkOutPipe == NULL || devContext->InterruptInPipe == NULL) { #if DBG DbgPrint("Didn't find expected pipes. BIN=0x%p, BOUT=0x%p, IIN=0x%p\n", devContext->BulkInPipe, devContext->BulkOutPipe, devContext->InterruptInPipe); #endif return STATUS_DEVICE_CONFIGURATION_ERROR; } // // By default, KMDF will not allow any non-MaxPacketSize // aligned I/O to be done against IN pipes. This is to avoid // hitting "babble" conditions, which occur when the device // sends more data than what you've asked it for. // // Our device doesn't babble, so we don't need this check on // our IN pipes. // WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(devContext->BulkInPipe); WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(devContext->InterruptInPipe); // // For fun, we're going to hang a continuous reader out on the // interrupt endpoint. By doing so, we'll get called at // BasicUsbInterruptPipeReadComplete every time someone toggles // the switches on the switch pack. // // // Initialize the continuous reader config structure, specifying // our callback, our context, and the size of the transfers. // WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig, BasicUsbInterruptPipeReadComplete, devContext, sizeof(UCHAR)); // // And create the continuous reader. // // Note that the continuous reader is not started by default, so // we'll need to manually start it when we are called at // EvtD0Entry. // status = WdfUsbTargetPipeConfigContinuousReader(devContext->InterruptInPipe, &contReaderConfig); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfUsbTargetPipeConfigContinuousReader failed 0x%0x\n", status); #endif return status; } return STATUS_SUCCESS; }