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 = STATUS_SUCCESS; PDEVICE_CONTEXT pDeviceContext; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; UCHAR index; UCHAR numberConfiguredPipes; WDFUSBINTERFACE usbInterface; PAGED_CODE(); pDeviceContext = GetDeviceContext(Device); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); usbInterface = WdfUsbTargetDeviceGetInterface(pDeviceContext->UsbDevice, 0); if (NULL == usbInterface) { status = STATUS_UNSUCCESSFUL; TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceGetInterface 0 failed %!STATUS! \n", status); return status; } configParams.Types.SingleInterface.ConfiguredUsbInterface = usbInterface; configParams.Types.SingleInterface.NumberConfiguredPipes = WdfUsbInterfaceGetNumConfiguredPipes(usbInterface); 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; }
/////////////////////////////////////////////////////////////////////////////// // // 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; }
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; }
NTSTATUS ConfigureUsbPipes(PDEVICE_CONTEXT DeviceContext) { NTSTATUS status = STATUS_SUCCESS; BYTE index = 0; WDF_USB_PIPE_INFORMATION pipeConfig; WDFUSBPIPE pipe = NULL; BYTE numEndpoints; // For debug numEndpoints = WdfUsbInterfaceGetNumEndpoints( DeviceContext->UsbInterface, 0 ); KdPrint((__DRIVER_NAME " Found %i EndPoints\n", numEndpoints)); // For debug DeviceContext->UsbInterruptPipe = NULL; DeviceContext->UsbBulkInPipe = NULL; DeviceContext->UsbBulkOutPipe = NULL; WDF_USB_PIPE_INFORMATION_INIT(&pipeConfig); // Init pipe config // // Scan all pipe from USB Interface // do { pipe = WdfUsbInterfaceGetConfiguredPipe(DeviceContext->UsbInterface, index, &pipeConfig); if (NULL == pipe) break; // For debug KdPrint((__DRIVER_NAME " Pipe[%i].PacketSize = %i\n", index, pipeConfig.MaximumPacketSize)); // For debug /*None of our data transfers will have a guarantee that the requested data size is a multiple of the packet size.*/ WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); if(WdfUsbPipeTypeInterrupt == pipeConfig.PipeType) // Interrupt pipe { KdPrint((__DRIVER_NAME " Found Interrupt Pipe at index %i\n", index)); DeviceContext->UsbInterruptPipe = pipe; } else if(WdfUsbPipeTypeBulk == pipeConfig.PipeType) // Bulk pipe { if(TRUE == WdfUsbTargetPipeIsInEndpoint(pipe)) // In EndPoint of Bulk { KdPrint((__DRIVER_NAME " Found In Endpoint Pipe at index %i\n", index)); DeviceContext->UsbBulkInPipe = pipe; } else if(TRUE == WdfUsbTargetPipeIsOutEndpoint(pipe)) { KdPrint((__DRIVER_NAME " Found Out Endpoint Pipe at index %i\n", index)); DeviceContext->UsbBulkOutPipe = pipe; // Out EndPoint of Bulk } } index++; // Encreate index of Pipe } while (NULL != pipe); // Check for all 3 pipe: interrupt, Bulk In, Bulk Out for our device if((NULL == DeviceContext->UsbInterruptPipe) || (NULL == DeviceContext->UsbBulkInPipe) || (NULL == DeviceContext->UsbBulkOutPipe)) { KdPrint((__DRIVER_NAME "Not all expected USB pipes were found.\n")); return STATUS_INVALID_PARAMETER; } return status; }
VOID CyGetActiveAltInterfaceConfig(__in PDEVICE_CONTEXT pDevContext) { WDFUSBPIPE UsbPipe; WDF_USB_PIPE_INFORMATION UsbPipeInfo; UCHAR ucIndex; UCHAR ucNumberConfiguredPipes; ucNumberConfiguredPipes = WdfUsbInterfaceGetNumConfiguredPipes(pDevContext->UsbInterfaceConfig.Types.SingleInterface.ConfiguredUsbInterface); pDevContext->ucActiveNumOfPipe = ucNumberConfiguredPipes; /* Update the number of cofigured pipe */ CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"Number of configured pipe 0x%x\n", pDevContext->ucActiveNumOfPipe); pDevContext->ucActiveInterruptInPipe = 0; // Initialize for(ucIndex=0; ucIndex < ucNumberConfiguredPipes; ucIndex++) { WDF_USB_PIPE_INFORMATION_INIT(&UsbPipeInfo); UsbPipe = WdfUsbInterfaceGetConfiguredPipe( pDevContext->UsbInterfaceConfig.Types.SingleInterface.ConfiguredUsbInterface, ucIndex, &UsbPipeInfo ); WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(UsbPipe); /* disable check for the multiple of maximum packet size for read/write buffer */ pDevContext->WdfUsbPipeArray[ucIndex] = UsbPipe; /* Store pipe handle */ /* display information */ if(WdfUsbPipeTypeInterrupt == UsbPipeInfo.PipeType && (WdfUsbTargetPipeIsInEndpoint(UsbPipe))) { //Update the interrupt IN endpoint information pDevContext->WdfUsbInterruptInPipeArray[pDevContext->ucActiveInterruptInPipe]=UsbPipe; pDevContext->ucActiveInterruptInPipe++; CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Interrupt Pipe is 0x%p\n", UsbPipe); CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Interrupt Pipe\n"); } if(WdfUsbPipeTypeBulk == UsbPipeInfo.PipeType) { CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Bulk Pipe is 0x%p\n", UsbPipe); // && WdfUsbTargetPipeIsInEndpoint(pipe CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Bulk Pipe\n"); } if(WdfUsbPipeTypeIsochronous == UsbPipeInfo.PipeType && WdfUsbTargetPipeIsOutEndpoint(UsbPipe)) { CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Isochronous Pipe is 0x%p\n", UsbPipe); CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "Isochronous Pipe\n"); } CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, " MaximumPacketSize :%x\n", UsbPipeInfo.MaximumPacketSize); CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, " EndpointAddress :%x\n", UsbPipeInfo.EndpointAddress); CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, " Interval :%x\n", UsbPipeInfo.Interval); CyTraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, " SettingIndex :%x\n", UsbPipeInfo.SettingIndex); } }