www.pudn.com > usbfx2lk_v1.1.zip > usbfx2lk_usb.cpp
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright 2005 OSR Open Systems Resources, Inc.
// All Rights Reserved
//
// This sofware is supplied for instructional purposes only.
//
// OSR Open Systems Resources, Inc. (OSR) expressly disclaims any warranty
// for this software. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
// THE IMPLIED WARRANTIES OF MECHANTABILITY OR FITNESS FOR A PARTICULAR
// PURPOSE. THE ENTIRE RISK ARISING FROM THE USE OF THIS SOFTWARE REMAINS
// WITH YOU. OSR's entire liability and your exclusive remedy shall not
// exceed the price paid for this material. In no event shall OSR or its
// suppliers be liable for any damages whatsoever (including, without
// limitation, damages for loss of business profit, business interruption,
// loss of business information, or any other pecuniary loss) arising out
// of the use or inability to use this software, even if OSR has been
// advised of the possibility of such damages. Because some states/
// jurisdictions do not allow the exclusion or limitation of liability for
// consequential or incidental damages, the above limitation may not apply
// to you.
//
// OSR Open Systems Resources, Inc.
// 105 Route 101A Suite 19
// Amherst, NH 03031 (603) 595-6500 FAX: (603) 595-6503
// email bugs to: bugs@osr.com
//
//
// MODULE:
//
// USBFx2LK_PnP.cpp
//
// ABSTRACT:
//
// This file contains the routines that handle Plug and Play processing for the
// OSR USB FX2 Learning Kit Device
//
// AUTHOR(S):
//
// OSR Open Systems Resources, Inc.
//
///////////////////////////////////////////////////////////////////////////////
#include "usbfx2lk.h"
#ifdef WPP_TRACING
//
// Include the necessary tmh file - this is
// just a matter of course if you're using WPP tracing.
//
extern "C" {
#include "usbfx2lk_usb.tmh"
}
#endif
//
// Forward Definitions
//
NTSTATUS SubmitUrb(PUSBFX2LK_EXT DevExt,PURB Urb);
NTSTATUS ConfigureUsbDevice(PUSBFX2LK_EXT DevExt);
NTSTATUS SelectUsbInterfaces(PUSBFX2LK_EXT DevExt,
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor);
VOID DetermineDeviceSpeed(PUSBFX2LK_EXT DevExt);
#ifndef IoForwardIrpSynchronously
NTSTATUS DetermineDeviceSpeedCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
#endif //IoForwardIrpSynchronously
NTSTATUS AsynchronousUrbRequestCompletion(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp, IN PVOID Context);
///////////////////////////////////////////////////////////////////////////////
//
// ReadandSelectUsbDescriptors
//
// This routine is called by OsrStartDevice to Read and Select the USB
// descriptors that will be used to talk to the usb device.
//
//
// INPUTS:
//
// DevExt - Address of the Devices Device Extension.
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary Context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS ReadandSelectUsbDescriptors(PUSBFX2LK_EXT DevExt)
{
PURB urb = NULL;
NTSTATUS status;
PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ReadandSelectUsbDescriptors: Enter\n"));
//
// Allocate a URB.
//
urb = (PURB) ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),'bruO');
if(urb) {
//
// Allocate a USB_DEVICE_DESCRIPTOR to receive the device descriptor from our device.
//
deviceDescriptor = (PUSB_DEVICE_DESCRIPTOR) ExAllocatePoolWithTag(NonPagedPool,
sizeof(USB_DEVICE_DESCRIPTOR), 'dduO');
if(deviceDescriptor) {
//
// Format the Urb for the request to get the USB_DEVICE_DESCRIPTOR
//
UsbBuildGetDescriptorRequest(
urb,
(USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE,
0,
0,
deviceDescriptor,
NULL,
sizeof(USB_DEVICE_DESCRIPTOR),
NULL);
//
// Submit the URB to the Device
//
status = SubmitUrb(DevExt,urb);
//
// If the request is successful, then configure the device
//
if(NT_SUCCESS(status)) {
ASSERT(deviceDescriptor->bNumConfigurations);
//
// Save away the device descriptor
//
DevExt->UsbDeviceDescriptor = deviceDescriptor;
status = ConfigureUsbDevice(DevExt);
} else {
//
// No descriptor info? Clean up.
//
ExFreePool(deviceDescriptor);
}
//
// Free the URB
//
ExFreePool(urb);
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("ReadandSelectUsbDescriptors: Failed to allocate memory for deviceDescriptor\n"));
ExFreePool(urb);
status = STATUS_INSUFFICIENT_RESOURCES;
}
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("ReadandSelectUsbDescriptors: Failed to allocate memory for urb\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ReadandSelectUsbDescriptors: Exit\n"));
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// ConfigureUsbDevice
//
// This routine is called by ReadandSelectUsbDescriptors to read the USB
// configuration descriptor that will be used to talk to the usb device.
//
//
// INPUTS:
//
// DevExt - Address of the Devices Device Extension.
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary Context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS ConfigureUsbDevice(PUSBFX2LK_EXT DevExt)
{
PURB urb = NULL;
ULONG size = sizeof(USB_CONFIGURATION_DESCRIPTOR);
NTSTATUS status;
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ConfigureUsbDevice: Enter\n"));
//
// Allocate memory for a URB.
//
urb = (PURB) ExAllocatePoolWithTag(NonPagedPool,sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),'bruO');
if(urb) {
//
// Allocate memory for the default sized configuration descriptor.
//
configurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) ExAllocatePoolWithTag(NonPagedPool, size,'dcuO');
if(configurationDescriptor) {
//
// Format the URB for the request.
//
UsbBuildGetDescriptorRequest(
urb,
(USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
configurationDescriptor,
NULL,
sizeof(USB_CONFIGURATION_DESCRIPTOR),
NULL);
//
// Submit the request to the USB Device.
//
status = SubmitUrb(DevExt,urb);
//
// If the request is not successful, go and cleanup from the error.
//
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("ConfigureUsbDevice: UsbBuildGetDescriptorRequest failed\n"));
goto ConfigureDevice_Exit;
}
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("ConfigureUsbDevice: Failed to allocate mem for config Descriptor\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
goto ConfigureDevice_Exit;
}
//
// Okay, the request was successful. Look at the returned length in the configuration
// descriptor and use it to allocate a configuration descriptor that is big enough
// to receive the full configuration from the device.
//
size = configurationDescriptor->wTotalLength;
//
// Free the existing configuration descriptor.
//
ExFreePool(configurationDescriptor);
//
// Allocate the correct sized descriptor.
//
configurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) ExAllocatePoolWithTag(NonPagedPool, size,'dcuO');
if(configurationDescriptor) {
//
// Format the urb to get the full configuration descriptor.
//
UsbBuildGetDescriptorRequest(
urb,
(USHORT)sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
configurationDescriptor,
NULL,
size,
NULL);
//
// Submit the request to the device.
//
status = SubmitUrb(DevExt,urb);
//
// If the request is not successful, clean up after the error.
//
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("ConfigureUsbDevice: Failed to read configuration descriptor\n"));
goto ConfigureDevice_Exit;
}
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("ConfigureUsbDevice: Failed to alloc mem for config Descriptor\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
goto ConfigureDevice_Exit;
}
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("ConfigureUsbDevice: Failed to allocate memory for urb\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
goto ConfigureDevice_Exit;
}
//
// Check to make sure that a configuration descriptor was allocated.
//
if(configurationDescriptor) {
//
// Save a copy of configurationDescriptor in deviceExtension
// remember to free it later.
//
DevExt->UsbConfigurationDescriptor = configurationDescriptor;
//
// Determine if the USB configuration is cabable of supporting
// remote wake.
//
if(configurationDescriptor->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) {
//
// This configuration supports remote wakeup
//
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("ConfigureUsbDevice: Remote Wakeup Enabled.\n"));
DevExt->WaitWakeEnable = TRUE;
} else {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_PNP_INFO,
("ConfigureUsbDevice: Remote Wakeup Disabled.\n"));
DevExt->WaitWakeEnable = FALSE;
}
//
// Select the interface(s) that we are going to use to communicate with the device.
//
status = SelectUsbInterfaces(DevExt, configurationDescriptor);
//
// And also determine the speed at which the device is running
//
DetermineDeviceSpeed(DevExt);
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_PNP_INFO,
("ConfigureUsbDevice: Failed to allocate configuration descriptor.\n"));
DevExt->UsbConfigurationDescriptor = NULL;
}
//
// Cleanup memory and exit.
//
ConfigureDevice_Exit:
if(urb) {
ExFreePool(urb);
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ConfigureUsbDevice: Exit\n"));
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// SelectUsbInterfaces
//
// This routine is called by ConfigureUsbDevice to read the USB
// select the interfaces that will be used to talk to the usb device.
//
//
// INPUTS:
//
// DevExt - Address of the Devices Device Extension.
// ConfigurationDescriptor - Address of the Configuration Descriptor
// selected.
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary Context
//
// NOTES:
//
// The OSR FX2 Learning Kit device running the OSR standard firmware only
// offers one USB Interface.
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SelectUsbInterfaces(PUSBFX2LK_EXT DevExt,
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
{
LONG numberOfInterfaces = ConfigurationDescriptor->bNumInterfaces;
LONG interfaceNumber = 0;
LONG interfaceindex = 0;
ULONG i;
PURB urb = NULL;
NTSTATUS status;
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = NULL;
PUSBD_INTERFACE_LIST_ENTRY interfaceList = NULL;
PUSBD_INTERFACE_LIST_ENTRY tmp = NULL;
PUSBD_INTERFACE_INFORMATION Interface = NULL;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SelectUsbInterfaces: Enter\n"));
//
// Allocate memory for the devices supported interfaces.
//
interfaceList = (PUSBD_INTERFACE_LIST_ENTRY) ExAllocatePoolWithTag(NonPagedPool,
sizeof(USBD_INTERFACE_LIST_ENTRY) * (numberOfInterfaces + 1),'eliU');
//
// Confirm memory was allocated.
//
if(!interfaceList) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("SelectUsbInterfaces: Failed to allocate mem for interfaceList\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
tmp = interfaceList;
//
// Parse the received USB interfaces selecting one that matches our input criteria.
// Fortunately, we are not fussy and will take any interface found, which for our
// device is the only one we return.
//
while(interfaceNumber < numberOfInterfaces) {
//
// A driver would call USBD_ParseConfigurationDescriptorEx in order
// to select a interface that meets the input criteria of driver.
// This would work well, if the a device had different interfaces.
// Unfortunately, our device only has one interface, so this will
// select it.
//
interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
ConfigurationDescriptor,
ConfigurationDescriptor,
interfaceindex,
0, -1, -1, -1);
if(interfaceDescriptor) {
//
// An interface met our criteria, save the information
// in our interface list.
//
interfaceList->InterfaceDescriptor = interfaceDescriptor;
interfaceList->Interface = NULL;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("--------- Interface %d\n",interfaceNumber));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbLength = %d\n",interfaceList->InterfaceDescriptor->bLength));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbDescriptorType = %d\n",interfaceList->InterfaceDescriptor->bDescriptorType));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbInterfaceNumber = %d\n",interfaceList->InterfaceDescriptor->bInterfaceNumber));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbAlternateSetting = %d\n",interfaceList->InterfaceDescriptor->bAlternateSetting));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbNumEndpoints = %d\n",interfaceList->InterfaceDescriptor->bNumEndpoints));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbInterfaceClass = %d\n",interfaceList->InterfaceDescriptor->bInterfaceClass));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbInterfaceSubClass = %d\n",interfaceList->InterfaceDescriptor->bInterfaceSubClass));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tbInterfaceProtocol = %d\n",interfaceList->InterfaceDescriptor->bInterfaceProtocol));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tiInterface = %d\n\n",interfaceList->InterfaceDescriptor->iInterface));
interfaceList++;
interfaceNumber++;
}
interfaceindex++;
}
//
// Format a URB that will be used to select the input configuration
// that will be used to interface to the device.
//
interfaceList->InterfaceDescriptor = NULL;
interfaceList->Interface = NULL;
urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor, tmp);
//
// Make sure that a URB was allocated.
//
if(urb) {
//
// Set our pipe information into the interface pipes list.
// This tells our device our we will use the pipe.
//
Interface = &urb->UrbSelectConfiguration.Interface;
for(i=0; iNumberOfPipes; i++) {
//
// Set the transfer size and any pipe flags we use
// USBD sets the rest of the Interface struct members
//
Interface->Pipes[i].MaximumTransferSize =
USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
}
//
// Submit the urb to the device.
//
status = SubmitUrb(DevExt, urb);
if(NT_SUCCESS(status)) {
//
// save a copy of interface information in the device extension.
//
DevExt->UsbInterface = (PUSBD_INTERFACE_INFORMATION) ExAllocatePoolWithTag(NonPagedPool,
Interface->Length,'eliU');
if(DevExt->UsbInterface) {
RtlCopyMemory(DevExt->UsbInterface,
Interface,
Interface->Length);
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("SelectUsbInterfaces: memory alloc for UsbInterface failed\n"));
goto SelectUsbInterfacesExit;
}
//
// Dump the interface to the debugger
//
Interface = &urb->UrbSelectConfiguration.Interface;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("---------\n"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("NumberOfPipes 0x%x\n",
Interface->NumberOfPipes));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Length 0x%x\n",
Interface->Length));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Alt Setting 0x%x\n",
Interface->AlternateSetting));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Interface Number 0x%x\n",
Interface->InterfaceNumber));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Class, subclass, protocol 0x%x 0x%x 0x%x\n",
Interface->Class,
Interface->SubClass,
Interface->Protocol));
//
// Initialize the PipeContext
// Dump the pipe info
//
if(Interface->NumberOfPipes) {
DevExt->PipeContext = (PUSBFX2LK_PIPE_CONTEXT) ExAllocatePoolWithTag(NonPagedPool,
Interface->NumberOfPipes *
sizeof(USBFX2LK_PIPE_CONTEXT),'xtcP');
if(DevExt->PipeContext) {
for(i=0; iNumberOfPipes; i++) {
RtlCopyMemory(&DevExt->PipeContext[i].PipeInformation,
&Interface->Pipes[i],sizeof(USBD_PIPE_INFORMATION));
//
// Setup our convenience pointer
//
if (Interface->Pipes[i].PipeType == UsbdPipeTypeBulk) {
if (USBD_PIPE_DIRECTION_IN(&Interface->Pipes[i])) {
//
// This is the bulk IN pipe. Make sure we only
// have one
//
ASSERT(DevExt->BulkInPipe == NULL);
DevExt->BulkInPipe = &DevExt->PipeContext[i];
} else {
//
// This is the bulk OUT pipe. Make sure we only
// have one
//
ASSERT(DevExt->BulkOutPipe == NULL);
DevExt->BulkOutPipe = &DevExt->PipeContext[i];
}
} else {
//
// Our device has two bulk pipes and one iso pipe,
// we shouldn't get any other pipe besides iso here
//
ASSERT(Interface->Pipes[i].PipeType == UsbdPipeTypeInterrupt);
//
// And we only have one
//
ASSERT(DevExt->InterruptPipe == NULL);
DevExt->InterruptPipe = &DevExt->PipeContext[i];
}
}
DevExt->NumberOfPipes = Interface->NumberOfPipes;
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("SelectUsbInterfaces: memory alloc for UsbInterface failed\n"));
goto SelectUsbInterfacesExit;
}
}
for(i=0; iNumberOfPipes; i++) {
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("---------\n"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("PipeType 0x%x\n",
Interface->Pipes[i].PipeType));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("EndpointAddress 0x%x\n",
Interface->Pipes[i].EndpointAddress));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("MaxPacketSize 0x%x\n",
Interface->Pipes[i].MaximumPacketSize));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Interval 0x%x\n",
Interface->Pipes[i].Interval));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("Handle %p\n",
Interface->Pipes[i].PipeHandle));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("MaximumTransferSize 0x%x\n",
Interface->Pipes[i].MaximumTransferSize));
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("---------\n"));
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("Failed to select an interface\n"));
}
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("SelectUsbInterfaces: USBD_CreateConfigurationRequestEx failed\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
}
//
// Clean up after ourselves and exit.
//
SelectUsbInterfacesExit:
if(tmp) {
ExFreePool(tmp);
}
if(urb) {
ExFreePool(urb);
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SelectUsbInterfaces: Exit\n"));
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// DeconfigureUsbDevice
//
// This routine is called to release the Usb Device and deconfigure the
// descriptors.
//
//
// INPUTS:
//
// DevExt - Address of the Devices Device Extension.
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary Context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS DeconfigureUsbDevice(PUSBFX2LK_EXT DevExt)
{
PURB urb;
ULONG size = sizeof(struct _URB_SELECT_CONFIGURATION);;
NTSTATUS status;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DeconfigureUsbDevice: Enter\n"));
urb = (PURB) ExAllocatePoolWithTag(NonPagedPool, size,'csuO');
if(urb) {
UsbBuildSelectConfigurationRequest(urb, (USHORT)size, NULL);
status = SubmitUrb(DevExt,urb);
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("DeconfigureUsbDevice: Failed to deconfigure device %08.8x %s\n",
status,OsrNtStatusToString(status)));
}
ExFreePool(urb);
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("DeconfigureUsbDevice: Failed to allocate urb\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DeconfigureUsbDevice: Exit\n"));
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// DetermineDeviceSpeed
//
// This routine is called by ConfigureUsbDevice to determine if the device
// is running at low or high speed.
//
//
// INPUTS:
//
// DevExt - Address of the Devices Device Extension.
//
// OUTPUTS:
//
// When finished, the RunningAtHighSpeed member of the
// device extension is set to either TRUE or FALSE
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary Context
//
// NOTES:
// We need to determine if the device is running at high speed by querying
// for the USB_BUS_INTERFACE_USBDI_V1 interface. One slight problem here,
// USB 2.0 support wasn't added to Windows 2000 until SP4 and so the latest
// DDK is a bit behind. If you were to believe the DDK documentation and
// headers, you would think that this interface is not supported at ALL in
// Windows 2000. However, this exchange in
// microsoft.public.development.device.drivers in July 2004 says otherwise:
//
////////////////////////////////////////////////////////////////////////////
//
// Subject: Availability of USB_BUS_INTERFACE_USBDI_V1 in Windows 2000 Sp4 ?
//
// Hello,
//
// Since Windows 2000 Service PAck4 has support for USB 2.0 Enhanced USB
// Host Controller , I was wondering if it has support for
// USB_BUS_INTERFACE_USBDI_V1 structure , since i want to use its member
// ( PUSB_BUSIFFN_IS_DEVICE_HIGH_SPEED IsDeviceHighSpeed ) .
// MSDN says that this is supported only on WinXP onwards but i am
// thinking why should this not be available when Enhanced USB Host
// Controller driver is available on W2k sp4
//
// could anybody please clarify this?
//
// thanks in advance
// Taha
//
////////////////////////////////////////////////////////////////////////////
//
// Eliyas Yakub [MSFT] Jul 12, 10:41 am show options
// From: "Eliyas Yakub [MSFT]"
// Date: Mon, 12 Jul 2004 10:41:52 -0700
//
// Looking at the code USBPORT code, I can definitely say it's available. I
// will bring this to our doc team's attention. Thanks.
//
// -Eliyas
//
////////////////////////////////////////////////////////////////////////////
//
// Since the support in the DDK isn't there, we simply
// added our own vendor specific command to determine if
// we're running at full or high speed. If you don't have
// this amount of flexibility with your device, you would
// need to cut and paste the appropriate definitions out
// of USBBUSIF.H in the Windows XP or Server 2003 build environment
// with the caveat of it not being officially documented or
// supported
//
///////////////////////////////////////////////////////////////////////////////
VOID DetermineDeviceSpeed(PUSBFX2LK_EXT DevExt)
{
DevExt->RunningAtHighSpeed = FALSE;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DetermineDeviceSpeed: Enter\n"));
#ifdef W2K
NTSTATUS status;
URB urb;
ULONG transferFlags;
//
// See the Notes section above, we've created
// a custom command to determine this while
// running on Win2K
//
RtlZeroMemory(&urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
//
// Build the vendor request with the appropriate
// flags and command
//
UsbBuildVendorRequest(&urb,
URB_FUNCTION_VENDOR_DEVICE,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
(USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN),
0,
USBFX2LK_IS_HIGH_SPEED,
0,
0,
&DevExt->RunningAtHighSpeed,
NULL,
sizeof(BOOLEAN),
NULL);
//
// Make the request active on the device
//
status = SubmitUrb(DevExt, &urb);
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("DetermineDeviceSpeed: Failed to query speed - 0x%x (%s)\n",
status,OsrNtStatusToString(status)));
} else {
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,
("DetermineDeviceSpeed: Device is running at %s speed.\n",
DevExt->RunningAtHighSpeed ? "HIGH" : "FULL"));
}
#else
NTSTATUS status;
PIRP irp;
KEVENT event;
PIO_STACK_LOCATION ioNextStack;
USB_BUS_INTERFACE_USBDI_V1 usbInterface;
//
// The way we determine our device speed on
// XP and later is by sending an IRP_MJ_PNP/
// IRP_MN_QUERY_INTERFACE IRP for the
// USB_BUS_INTERFACE_USBDI_GUID interface.
//
//
// Allocate an IRP with an appropriate number
// of stack locations for this request
//
irp = IoAllocateIrp(DevExt->DeviceToSendIrpsTo->StackSize,
FALSE);
if(!irp) {
//
// Can't allocate an IRP so we can't determine if
// we're at high speed.
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("DetermineDeviceSpeed: Failed to allocate an IRP. Defaulting to full speed\n"));
return;
}
//
// Assume failure.
//
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
//
// Initialize the IRP that we will be waiting on for the
// IRP to complete
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// Get a pointer to the NEXT irp stack location.
// Because we are the ones who allocated the IRP,
// we do not have a current IRP stack location.
// Also, since we are passing the IRP down to the
// next lower driver, we want to modify the next
// stack location
//
ioNextStack = IoGetNextIrpStackLocation(irp);
//
// This is a PNP/QUERY_INTERFACE request
//
ioNextStack->MajorFunction = IRP_MJ_PNP;
ioNextStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
//
// Setup the QUERY_INTERFACE stack location parameters
//
//
// Indicate which interface we're querying for
//
ioNextStack->Parameters.QueryInterface.InterfaceType =
&USB_BUS_INTERFACE_USBDI_GUID;
//
// Indicate which version of the interface we are querying
//
ioNextStack->Parameters.QueryInterface.Version = USB_BUSIF_USBDI_VERSION_1;
//
// Setup the buffer for the returned interface
//
ioNextStack->Parameters.QueryInterface.Interface = (PINTERFACE)&usbInterface;
//
// Set up the size of the buffer
//
ioNextStack->Parameters.QueryInterface.Size =
sizeof(USB_BUS_INTERFACE_USBDI_V1);
#ifdef IoForwardIrpSynchronously
//
// Pass the IRP down to the lower driver
//
if(IoForwardIrpSynchronously(DevExt->DeviceToSendIrpsTo,irp)) {
status = Irp->IoStatus.Status;
} else {
status = STATUS_UNSUCCESSFUL;
}
#else //IoForwardIrpSynchronously
//
// Setup a completion routine, passing the event as the
// context parameter. When the completion routine runs, it
// will set the event and stop completion processing by
// returning STATUS_MORE_PROCESSING_REQUIRED.
//
IoSetCompletionRoutine(irp,
DetermineDeviceSpeedCompletionRoutine,
&event,
TRUE,
TRUE,
TRUE);
//
// Pass the IRP down to the lower driver
//
status = IoCallDriver(DevExt->DeviceToSendIrpsTo, irp);
if(status == STATUS_PENDING) {
//
// If the IRP was pended, then we must wait for the
// event to be signalled by our completion routine
//
(VOID)OsrWaitForSingleObject(&event);
//
// Retrieve the real completion status from the
// IRP
//
status = irp->IoStatus.Status;
}
#endif //IoForwardIrpSynchronously
//
// DId the call succeed?
//
if(NT_SUCCESS(status)) {
//
// We should have a valid IsDeviceHighSpeed routine to
// call through the interface
//
ASSERT(usbInterface.IsDeviceHighSpeed);
//
// Call the routine and see what we are running at
//
DevExt->RunningAtHighSpeed = usbInterface.IsDeviceHighSpeed(usbInterface.BusContext);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,
("DetermineDeviceSpeed: Device is running at %s speed.\n",
DevExt->RunningAtHighSpeed ? "HIGH" : "FULL"));
} else {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("DetermineDeviceSpeed: Failed to query interface - 0x%x (%s)\n",
status,OsrNtStatusToString(status)));
}
//
// Delete the Irp that we allocated.
//
IoFreeIrp(irp);
#endif
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DetermineDeviceSpeed: Exit\n"));
return;
}
#ifndef IoForwardIrpSynchronously
///////////////////////////////////////////////////////////////////////////////
//
// DetermineDeviceSpeedCompletionRoutine
//
// This routine is a completion routine used to signal the completion
// of the IRP sent down by DetermineDeviceSpeed. It's only job is to
// set the event passed in as the context parameter and stop the processing
// of the IRP.
//
//
// INPUTS:
//
// DeviceObject - Address of the Devices Device Extension.
// Irp - Address of the QUERY_INTERFACE IRP sent down by
// DetermineDeviceSpeed
// Context - A pointer to a KEVENT
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// STATUS_MORE_PROCESSING_REQUIRED to stop completion processing of the IRP
//
// IRQL:
//
// IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// Arbitrary Context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS DetermineDeviceSpeedCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
PKEVENT event = (PKEVENT)Context;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DetermineDeviceSpeedCompletionRoutine: Enter\n"));
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(Irp);
//
// Set the event
//
KeSetEvent(event, EVENT_INCREMENT, FALSE);
//
// And stop completion processing of the IRP
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("DetermineDeviceSpeedCompletionRoutine: Exit\n"));
return STATUS_MORE_PROCESSING_REQUIRED;
}
#endif //IoForwardIrpSynchronously
///////////////////////////////////////////////////////////////////////////////
//
// SubmitUrb
//
// This routine is called to synchronously submit the Input Urb to the USB
// device.
//
//
// INPUTS:
//
// DevExt - Address of the Devices Device Extension.
// Urb - Address of the USB to be delivered.
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary Context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SubmitUrb(PUSBFX2LK_EXT DevExt,PURB Urb)
{
PIRP irp = NULL;
KEVENT event;
NTSTATUS status;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SubmitUrb: Enter\n"));
//
// Initialize the Event that will be waited on if the underlying
// driver returns STATUS_PENDING
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// Build the Irp to be used to submit the URB.
//
irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
DevExt->DeviceToSendIrpsTo,
NULL,
0,
NULL,
0,
TRUE,
&event,
&ioStatus);
if(!irp) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("SubmitUrb: IoBuildDeviceIoControlRequest failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Put the URB to be submitted into the Others part of the next stack location.
// This urb will be passed to the USB Bus Driver for submission to our USB
// device.
//
nextStack = IoGetNextIrpStackLocation(irp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = Urb;
//
// Increment the number of outstanding requests.
//
OsrIncrementOutstandingIoCount(DevExt,__FILE__,__LINE__);
//
// Submit the Irp to the driver.
//
status = IoCallDriver(DevExt->DeviceToSendIrpsTo,irp);
//
// Wait for a response if not already completed.
//
if(status == STATUS_PENDING) {
(VOID)OsrWaitForSingleObject(&event);
//
// Get the completion status
//
status = ioStatus.Status;
}
//
// Decrement the number of outstanding requests.
//
OsrDecrementOutstandingIoCount(DevExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SubmitUrb: Exit\n"));
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// SubmitIrpAndUrbAsync
//
// This routine is called to asynchronously submit the Input IRP and Urb to
// the USB device.
//
//
// INPUTS:
//
// DevExt - Address of the Devices Device Extension.
// IRP - Address of the IRP to setup for the URB transfer
// and submit to the device
// Urb - Address of the USB to be delivered.
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary Context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SubmitIrpAndUrbAsync(PUSBFX2LK_EXT DevExt, PIRP Irp, PURB Urb)
{
PIO_STACK_LOCATION nextStack;
NTSTATUS status;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,
("SubmitIrpAndUrbAsync: Enter\n"));
//
// We need to submit this request as a USB request,
// so we'll get the next IRP stack location and set
// it up as a USB interrupt transfer.
//
nextStack = IoGetNextIrpStackLocation(Irp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
nextStack->Parameters.Others.Argument1 = Urb;
//
// Setup our completion routine that will free the URB
//
IoSetCompletionRoutine(Irp, AsynchronousUrbRequestCompletion,
Urb, TRUE, TRUE, TRUE);
//
// We're submitting this URB to the device and it may
// complete at an arbitrary point in the future, so
// we need to mark it pending
//
IoMarkIrpPending(Irp);
//
// While we have the Irp in our queue, store the address of the URB
// in the DriverContext[1] field of the Irp. We do this so that
// if the Irp is canceled while in our queue, we have enough information
// to do the correct cleanup.
//
Irp->Tail.Overlay.DriverContext[1] = Urb;
//
// Queue the using the appropriate cancel safe queue routin
//
#ifdef W2K3
//
// IoCsqInsertIrpEx returns whatever we return from OsrCsqInsertIoIrpEx,
// which for us is STATUS_SUCCESS.
//
status = IoCsqInsertIrpEx(&DevExt->CancelSafeIoQueue,Irp,NULL,DevExt);
ASSERT(status == STATUS_SUCCESS);
#else // W2K3
IoCsqInsertIrp(&DevExt->CancelSafeIoQueue,Irp,NULL);
#endif // W2K3
//
// We have queued this IRP onto our internal queue.
// Now call our helper routine ProcessNextIrpInQueue
// to pass this request (or possibly another request
// that was running parallel and beat us to the queue)
// to the host controller.
//
// ProcessNextIrpInQueue will pass the request on to the
// host if we are in an applicable PnP state otherwise the
// request will just stay in the queue.
//
ProcessNextIrpInQueue(DevExt);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,
("SubmitIrpAndUrbAsync: Exit\n"));
return STATUS_PENDING;
}
///////////////////////////////////////////////////////////////////////////////
//
// SubmitResetPipe
//
// Resets the passed in pipe
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// Irp - Pointer to an IOCTL_OSRUSBFX2_RESET_PIPE
// IRP.
//
// Pipe - The USBFX2_PIPE_ENUM for the pipe to reset
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// An appropriate NTSTATUS value
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User context
//
// NOTES:
//
// Routine assumes that the output data buffer in the IRP is
// valid for this request. Must be checked by caller.
//
// Called relinquishes ownership of the IRP when calling this
// routine, IRP must NOT be touched by caller after this routine
// returns
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SubmitResetPipe(PUSBFX2LK_EXT DevExt, PIRP Irp, USBFX2_PIPE_ENUM Pipe)
{
NTSTATUS status;
PURB resetUrb;
PUSBFX2LK_PIPE_CONTEXT pipeContext = NULL;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ResetPipe: Enter\n"));
//
// Find the pipe context for the pipe that we're resetting
//
switch(Pipe) {
case USBFx2BulkInPipe:
pipeContext = DevExt->BulkInPipe;
break;
case USBFx2BulkOutPipe:
pipeContext = DevExt->BulkOutPipe;
break;
case USBFx2InterruptPipe:
pipeContext = DevExt->InterruptPipe;
break;
default:
//
// Bogus pipe
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("ResetPipe: Exit Invalid Pipe\n"));
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_PARAMETER;
}
//
// We'd better have a pipe at this point,
// otherwise our device configuration failed
//
ASSERT(pipeContext);
//
// Allocate our reset URB
//
resetUrb =
(PURB)ExAllocatePoolWithTag(NonPagedPool,
sizeof(struct _URB_PIPE_REQUEST),
'PRxF');
if (!resetUrb) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("ResetPipe: Failed to allocate memory, Exiting.\n"));
//
// We need to complete the IRP ourselves
//
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Setup the URB_FUNCTION_RESET_PIPE URB appropriately
//
resetUrb->UrbHeader.Length = sizeof(struct _URB_PIPE_REQUEST);
resetUrb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
resetUrb->UrbPipeRequest.PipeHandle = pipeContext->PipeInformation.PipeHandle;
status = SubmitIrpAndUrbAsync(DevExt, Irp, resetUrb);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("ResetPipe: Exit\n"));
//
// Return whatever status SubmitIrpAndUrbAsync returned
//
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// SubmitGetBarGraphState
//
// This routine gets the state of the bar graph on the board
//
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// Irp - Pointer to an IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY
// IRP. User's buffer has already been validated
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// An appropriate NTSTATUS value
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User context
//
// NOTES:
//
// Routine assumes that the output data buffer in the IRP is
// valid for this request. Must be checked by caller.
//
// Called relinquishes ownership of the IRP when calling this
// routine, IRP must NOT be touched by caller after this routine
// returns
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SubmitGetBarGraphState(PUSBFX2LK_EXT DevExt, PIRP Irp)
{
NTSTATUS status;
PURB getBarGraphUrb;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetBarGraphState: Enter\n"));
//
// Allocate our get bar graph URB
//
getBarGraphUrb =
(PURB)ExAllocatePoolWithTag(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
'BGxF');
if (!getBarGraphUrb) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("GetBarGraphState: Failed to allocate memory, Exiting.\n"));
//
// We need to complete the IRP ourselves
//
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(getBarGraphUrb,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
//
// Build the vendor request with the appropriate
// flags and command
//
// We're getting data from the device,
// to we need to set the USBD_TRANSFER_DIRECTION_IN flag
//
UsbBuildVendorRequest(getBarGraphUrb,
URB_FUNCTION_VENDOR_DEVICE,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN,
0,
USBFX2LK_READ_BARGRAPH_DISPLAY,
0,
0,
Irp->AssociatedIrp.SystemBuffer,
NULL,
sizeof(BAR_GRAPH_STATE),
NULL);
status = SubmitIrpAndUrbAsync(DevExt, Irp, getBarGraphUrb);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetBarGraphState: Exit\n"));
//
// Return whatever status SubmitIrpAndUrbAsync returned
//
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// SubmitSetBarGraphState
//
// This routine sets the state of the bar graph on the board
//
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// Irp - Pointer to an IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY
// IRP. User's buffer has already been validated
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// An appropriate NTSTATUS value
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User context
//
// NOTES:
//
// Routine assumes that the output data buffer in the IRP is
// valid for this request. Must be checked by caller.
//
// Called relinquishes ownership of the IRP when calling this
// routine, IRP must NOT be touched by caller after this routine
// returns
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SubmitSetBarGraphState(PUSBFX2LK_EXT DevExt, PIRP Irp)
{
NTSTATUS status;
PURB setBarGraphUrb;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SetBarGraphState: Enter\n"));
//
// Allocate our set bar graph URB
//
setBarGraphUrb =
(PURB)ExAllocatePoolWithTag(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
'BSxF');
if (!setBarGraphUrb) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("SetBarGraphState: Failed to allocate memory, Exiting.\n"));
//
// We need to complete the IRP ourselves
//
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(setBarGraphUrb,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
//
// Build the vendor request with the appropriate
// flags and command
//
// We're getting data from the device,
// to we need to set the USBD_TRANSFER_DIRECTION_IN flag
//
UsbBuildVendorRequest(setBarGraphUrb,
URB_FUNCTION_VENDOR_DEVICE,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
USBD_SHORT_TRANSFER_OK,
0,
USBFX2LK_SET_BARGRAPH_DISPLAY,
0,
0,
Irp->AssociatedIrp.SystemBuffer,
NULL,
sizeof(BAR_GRAPH_STATE),
NULL);
status = SubmitIrpAndUrbAsync(DevExt, Irp, setBarGraphUrb);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SetBarGraphState: Exit\n"));
//
// Return whatever status SubmitIrpAndUrbAsync returned
//
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// SubmitGetSevenSegmentState
//
// This routine gets or sets the state of the 7 segment display on the board
//
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// Irp - Pointer to an IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY
// IRP. User's buffer has already been validated
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// An appropriate NTSTATUS value
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User context
//
// NOTES:
//
// Routine assumes that the output data buffer in the IRP is
// valid for this request. Must be checked by caller.
//
// Called relinquishes ownership of the IRP when calling this
// routine, IRP must NOT be touched by caller after this routine
// returns
//
/////////////////////////////////////////////////////////////////////////////
NTSTATUS SubmitGetSevenSegmentState(PUSBFX2LK_EXT DevExt, PIRP Irp)
{
NTSTATUS status;
PURB getSevenSegmentUrb;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetSevenSegmentState: Enter\n"));
//
// Allocate our get seven segment URB
//
getSevenSegmentUrb =
(PURB)ExAllocatePoolWithTag(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
'SGxF');
if (!getSevenSegmentUrb) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("GetSevenSegmentState: Failed to allocate memory, Exiting.\n"));
//
// We need to complete the IRP ourselves
//
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(getSevenSegmentUrb,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
//
// Build the vendor request with the appropriate
// flags and command
//
// We're getting data from the device,
// to we need to set the USBD_TRANSFER_DIRECTION_IN flag
//
UsbBuildVendorRequest(getSevenSegmentUrb,
URB_FUNCTION_VENDOR_DEVICE,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN,
0,
USBFX2LK_READ_7SEGMENT_DISPLAY,
0,
0,
Irp->AssociatedIrp.SystemBuffer,
NULL,
sizeof(UCHAR),
NULL);
status = SubmitIrpAndUrbAsync(DevExt, Irp, getSevenSegmentUrb);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetSevenSegmentState: Exit\n"));
//
// Return whatever status SubmitIrpAndUrbAsync returned
//
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// SubmitSetSevenSegmentState
//
// This routine sets the state of the 7 segment display on the board
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// Irp - Pointer to an IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY
// IRP. User's buffer has already been validated
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// An appropriate NTSTATUS value
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User context
//
// NOTES:
//
// Routine assumes that the output data buffer in the IRP is
// valid for this request. Must be checked by caller.
//
// Called relinquishes ownership of the IRP when calling this
// routine, IRP must NOT be touched by caller after this routine
// returns
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SubmitSetSevenSegmentState(PUSBFX2LK_EXT DevExt, PIRP Irp)
{
NTSTATUS status;
PURB setSevenSegmentUrb;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SetSevenSegmentState: Enter\n"));
//
// Allocate our set seven segment URB
//
setSevenSegmentUrb =
(PURB)ExAllocatePoolWithTag(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
'SSxF');
if (!setSevenSegmentUrb) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("SetSevenSegmentState: Failed to allocate memory, Exiting.\n"));
//
// We need to complete the IRP ourselves
//
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(setSevenSegmentUrb,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
//
// Build the vendor request with the appropriate
// flags and command
//
// We're getting data from the device,
// to we need to set the USBD_TRANSFER_DIRECTION_IN flag
//
UsbBuildVendorRequest(setSevenSegmentUrb,
URB_FUNCTION_VENDOR_DEVICE,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
USBD_SHORT_TRANSFER_OK,
0,
USBFX2LK_SET_7SEGMENT_DISPLAY,
0,
0,
Irp->AssociatedIrp.SystemBuffer,
NULL,
sizeof(UCHAR),
NULL);
status = SubmitIrpAndUrbAsync(DevExt, Irp, setSevenSegmentUrb);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SetSevenSegmentState: Exit\n"));
//
// Return whatever status SubmitIrpAndUrbAsync returned
//
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// SubmitGetSwitchState
//
// This routine gets the state of the switches on the board
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// Irp - Pointer to an IOCTL_OSRUSBFX2_READ_SWITCHES
// IRP. User's buffer has already been validated
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// An appropriate NTSTATUS value
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User context
//
// NOTES:
//
// Routine assumes that the output data buffer in the IRP is
// valid for this request. Must be checked by caller.
//
// Called relinquishes ownership of the IRP when calling this
// routine, IRP must NOT be touched by caller after this routine
// returns
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SubmitGetSwitchState(PUSBFX2LK_EXT DevExt, PIRP Irp)
{
NTSTATUS status;
PURB getSwitchUrb;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetSwitchState: Enter\n"));
//
// Allocate our get seven segment URB
//
getSwitchUrb =
(PURB)ExAllocatePoolWithTag(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
'WGxF');
if (!getSwitchUrb) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("GetSwitchState: Failed to allocate memory, Exiting.\n"));
//
// We need to complete the IRP ourselves
//
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(getSwitchUrb,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
//
// Build the vendor request with the appropriate
// flags and command
//
// We're getting data from the device,
// to we need to set the USBD_TRANSFER_DIRECTION_IN flag
//
UsbBuildVendorRequest(getSwitchUrb,
URB_FUNCTION_VENDOR_DEVICE,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN,
0,
USBFX2LK_READ_SWITCHES,
0,
0,
Irp->AssociatedIrp.SystemBuffer,
NULL,
sizeof(SWITCH_STATE),
NULL);
status = SubmitIrpAndUrbAsync(DevExt, Irp, getSwitchUrb);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetSwitchState: Exit\n"));
//
// Return whatever status SubmitIrpAndUrbAsync returned
//
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// GetDeviceDescriptor
//
// Returns the USB device descriptor for the device
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// OUTPUTS:
//
// DeviceDescriptor - If successful, contains the USB device descriptor
// for the device
//
// BytesTransferred - The actual amount of data transferred by this
// operation
//
// RETURNS:
//
// An appropriate NTSTATUS value
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS GetDeviceDescriptor(PUSBFX2LK_EXT DevExt, PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
PULONG BytesTransferred)
{
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetDeviceDescriptor: Enter\n"));
//
// We've already saved the device descriptor away
// so we just need to copy it out of the device
// extension
//
RtlCopyMemory(DeviceDescriptor, DevExt->UsbDeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
//
// Indicate the amount of data that was actually
// transferred
//
*BytesTransferred = sizeof(USB_DEVICE_DESCRIPTOR);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetDeviceDescriptor: Exit\n"));
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// GetConfigurationDescriptor
//
// Returns the USB configuration descriptor for the device
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// OUTPUTS:
//
// ConfigDescriptor - If successful, contains the USB configuration descriptor
// for the device
//
// BytesTransferred - The actual amount of data transferred by this
// operation
//
// RETURNS:
//
// An appropriate NTSTATUS value
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS GetConfigurationDescriptor(PUSBFX2LK_EXT DevExt,
PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
PULONG BytesTransferred)
{
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetConfigurationDescriptor: Enter\n"));
//
// We've already saved the config descriptor away
// so we just need to copy it out of the device
// extension
//
RtlCopyMemory(ConfigDescriptor, DevExt->UsbConfigurationDescriptor,
sizeof(USB_CONFIGURATION_DESCRIPTOR));
//
// Indicate the amount of data that was actually
// transferred
//
*BytesTransferred = sizeof(USB_CONFIGURATION_DESCRIPTOR);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetConfigurationDescriptor: Exit\n"));
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// GetInterfaceInformation
//
// Returns the USB interface information for the device
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// OUTPUTS:
//
// InterfaceDescriptor - If successful, contains the USB Interface Information
// for the device
//
// BytesTransferred - The actual amount of data transferred by this
// operation
//
// RETURNS:
//
// An appropriate NTSTATUS value
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS GetInterfaceInformation(PUSBFX2LK_EXT DevExt,
PUSBD_INTERFACE_INFORMATION InterfaceDescriptor,
PULONG BytesTransferred)
{
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetInterfaceInformation: Enter\n"));
//
// We've already saved the interface information away so we just need to copy
// it out of the device extension
//
RtlCopyMemory(InterfaceDescriptor, DevExt->UsbInterface, DevExt->UsbInterface->Length);
*BytesTransferred = DevExt->UsbInterface->Length;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetInterfaceInformation: Exit\n"));
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// GetPipeInformation
//
// Returns information about the passed in Pipe
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// Pipe - The USBFX2_PIPE_ENUM for the pipe to reset
//
// OUTPUTS:
//
// PipeInformation - If successful, contains information about the
// passed in pipe
//
// BytesTransferred - The actual amount of data transferred by this
// operation
//
// RETURNS:
//
// An appropriate NTSTATUS value
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS GetPipeInformation(PUSBFX2LK_EXT DevExt, USBFX2_PIPE_ENUM Pipe,
PUSBD_PIPE_INFORMATION PipeInformation,
PULONG BytesTransferred)
{
PUSBFX2LK_PIPE_CONTEXT pipeContext;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetPipeInformation: Enter\n"));
//
// Find the pipe context for the pipe that we're resetting
//
switch(Pipe) {
case USBFx2BulkInPipe:
pipeContext = DevExt->BulkInPipe;
break;
case USBFx2BulkOutPipe:
pipeContext = DevExt->BulkOutPipe;
break;
case USBFx2InterruptPipe:
pipeContext = DevExt->InterruptPipe;
break;
default:
//
// Bogus pipe
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,("GetPipeInformation: Exit Invalid Pipe\n"));
//
// Failure case, indicate that no data was transferred.
//
*BytesTransferred = 0;
return STATUS_INVALID_PARAMETER;
}
//
// We'd better have a pipe at this point,
// otherwise our device configuration failed
//
ASSERT(pipeContext);
//
// Just copy the pipe info out of the pipe context
//
RtlCopyMemory(PipeInformation, &pipeContext->PipeInformation, sizeof(USBD_PIPE_INFORMATION));
//
// Indicate the amount of data that was actually
// transferred
//
*BytesTransferred = sizeof(USBD_PIPE_INFORMATION);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("GetPipeInformation: Exit\n"));
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// GetUserInterruptRequest
//
// Queries the interrupt pipe on the USBFX2LK board
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// Irp - Pointer to an IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE
// IRP. User's buffer has already been validated
//
// OUTPUTS:
//
// BytesReturned - Number of bytes actually transferred
//
// RETURNS:
//
// An appropriate NTSTATUS value
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User context
//
// NOTES:
//
// Routine assumes that the output data buffer in the IRP is
// valid for this request. Must be checked by caller.
//
// Called relinquishes ownership of the IRP when calling this
// routine, IRP must NOT be touched by caller after this routine
// returns
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SubmitInterruptDataRequest(PUSBFX2LK_EXT DevExt, PIRP Irp)
{
PUCHAR interruptData;
PURB interruptUrb;
NTSTATUS status;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SubmitInterruptDataRequest: Enter\n"));
//
// This is a METHOD_BUFFERED request
//
interruptData = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
//
// Initialize the data
//
*interruptData = 0;
//
// Allocate our interrupt URB
//
interruptUrb =
(PURB)ExAllocatePoolWithTag(NonPagedPool,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
'IGxF');
if (!interruptUrb) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_USB,
("SubmitInterruptDataRequest: Failed to allocate memory, Exiting.\n"));
//
// We need to complete the IRP ourselves
//
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(interruptUrb,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
//
// Build the interrupt buffer
//
UsbBuildInterruptOrBulkTransferRequest(
interruptUrb,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
DevExt->InterruptPipe->PipeInformation.PipeHandle,
interruptData,
NULL,
sizeof(UCHAR),
(USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN),
NULL);
status = SubmitIrpAndUrbAsync(DevExt, Irp, interruptUrb);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,("SubmitInterruptDataRequest: Exit\n"));
//
// Return whatever status SubmitIrpAndUrbAsync returned
//
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// AsynchronousUrbRequestCompletion
//
// Generic completion routine for USB requests.
//
//
// INPUTS:
//
// DeviceObject - Our Device Object
// Irp - Address of completing Irp
// Context - A PURB
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// STATUS_SUCCESS
//
// IRQL:
//
// IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// Any
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS AsynchronousUrbRequestCompletion(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp, IN PVOID Context)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)DeviceObject->DeviceExtension;
PURB urb = (PURB)Context;
UNREFERENCED_PARAMETER(DeviceObject);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,
("AsynchronousUrbRequestCompletion: Entered.\n"));
//
// If successful, indicate how much interrupt data was
// transferred. We get this out of the interrupt URB
// that was submitted to the device
//
if(NT_SUCCESS(Irp->IoStatus.Status)) {
//
// Determine where the bytes transferred field
// for this URB is based on the function type.
//
switch (urb->UrbHeader.Function) {
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
Irp->IoStatus.Information
= urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
break;
case URB_FUNCTION_CONTROL_TRANSFER:
Irp->IoStatus.Information
= urb->UrbControlVendorClassRequest.TransferBufferLength;
break;
default:
//
// Uknown type, no data
//
Irp->IoStatus.Information = 0;
break;
}
}
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_USB,
("AsynchronousUrbRequestCompletion: Completion status - 0x%x (%s). "\
"Bytes Transferred - 0x%p\n",
Irp->IoStatus.Status,OsrNtStatusToString(Irp->IoStatus.Status),
(PVOID)Irp->IoStatus.Information));
//
// That's one less operation outstanding on the device
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
//
// Free the URB
//
ExFreePool(urb);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_USB,
("AsynchronousUrbRequestCompletion: Exited.\n"));
//
// Tell the I/O Mgr that he can continue Irp Completion
//
return STATUS_SUCCESS;
}