USB Stack

From ReactOS Wiki
Revision as of 19:04, 22 March 2010 by EmuandCo (talk | contribs) (Undo revision 27946 by Lone Rifle (Talk))
Jump to: navigation, search

The USB stack is the component which provides the communication between USB devices and their respective drivers and applications. It consists of multiple files, each with a distinct function. The USB stack in ReactOS is currently extremely limited. This page documents the development of the new USB stack. Development work on a USB 3 stack is not planned at this time.


Overview

The goal is to develop a USB stack which:

  • is USB 1.1 - 2.0 compliant
  • uses WDM (NT 5) API
  • is compatible with all USB devices and drivers (which adhere to the standard)

The entire stack will be fully documented and the implementation progress detailed on this page.


Goals

  • Primary Goal: USB HID (human input devices) and storage functionality working (Alpha).
  • Secondary Goal: Audio and other support added.
  • Beyond: testing and debugging.

Due to the complexity and size, no release dates will be provided as of now.

Status

2010-01-08 - Michael Martin has started re-implementation. The plan is to start with the EHCI controller and then work up the stack. Drivers will be developed against Win2k and WinXP for starting off. Progress can be found here.

Outdated information

See here.

Source code template

Hi,

This is probably a scilly suggestion, but I feel a Wiki based development is more modern than an IRC based development. So here is my USB source code template, don't hesitate to fill the many holes:

/*

  usb.C

  Author: JPLR jplr@users.sourceforge.net
  Craeted: 2010-03-10

  This framework is generated by EasySYS 0.3.0
  This template file is copying from QuickSYS 0.3.0 written by Chunhua Liu
  
  MSDN information is used heavily in this code

*/

#include "dbghelp.h"
#include "usb.h"

//
// A structure representing the instance information associated with
// a particular device
//

typedef struct _DEVICE_EXTENSION
{
    ULONG  StateVariable;

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

//
// Device driver routine declarations.
//

NTSTATUS
DriverEntry(
	IN PDRIVER_OBJECT		DriverObject,
	IN PUNICODE_STRING		RegistryPath
	);

NTSTATUS
UsbDispatchCreate(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					Irp
	);

NTSTATUS
UsbDispatchClose(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					Irp
	);

NTSTATUS
UsbDispatchDeviceControl(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					Irp
	);

NTSTATUS
UsbDispatchInternalDeviceControl(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					Irp
	);

VOID
UsbUnload(
	IN PDRIVER_OBJECT		DriverObject
	);

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, UsbDispatchCreate)
#pragma alloc_text(PAGE, UsbDispatchClose)
#pragma alloc_text(PAGE, UsbDispatchDeviceControl)
#pragma alloc_text(PAGE, UsbDispatchInternalDeviceControl)
#pragma alloc_text(PAGE, UsbUnload)
#endif // ALLOC_PRAGMA

NTSTATUS
DriverEntry(
	IN PDRIVER_OBJECT		DriverObject,
	IN PUNICODE_STRING		RegistryPath
	)
{
	NTSTATUS			status = STATUS_SUCCESS;    
    UNICODE_STRING		ntDeviceName;
	UNICODE_STRING		dosDeviceName;
    PDEVICE_EXTENSION	deviceExtension;
	PDEVICE_OBJECT		deviceObject = NULL;
	BOOLEAN				fSymbolicLink = FALSE;

	KdBreakPoint();

    dprintf("[usb] DriverEntry: %wZ\n", RegistryPath);

    //
    // A real driver would:
    //
    //     1. Report it's resources (IoReportResourceUsage)
    //
    //     2. Attempt to locate the device(s) it supports

    //
    // OK, we've claimed our resources & found our h/w, so create
    // a device and initialize stuff...
    //

    RtlInitUnicodeString(&ntDeviceName, USB_DEVICE_NAME_W);

    //
    // Create an EXCLUSIVE device, i.e. only 1 thread at a time can send
    // i/o requests.
    //

    status = IoCreateDevice(
		DriverObject,
		sizeof(DEVICE_EXTENSION), // DeviceExtensionSize
		&ntDeviceName, // DeviceName
		FILE_DEVICE_USB, // DeviceType
		0, // DeviceCharacteristics
		TRUE, // Exclusive
		&deviceObject // [OUT]
		);

    if (!NT_SUCCESS(status))
	{
		dprintf("[usb] IoCreateDevice = 0x%x\n", status);
		goto __failed;
	}

	deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;

	//
	// Set up synchronization objects, state info,, etc.
	//

    //
    // Create a symbolic link that Win32 apps can specify to gain access
    // to this driver/device
    //

    RtlInitUnicodeString(&dosDeviceName, USB_DOS_DEVICE_NAME_W);

    status = IoCreateSymbolicLink(&dosDeviceName, &ntDeviceName);

    if (!NT_SUCCESS(status))
    {
        dprintf("[usb] IoCreateSymbolicLink = 0x%x\n", status);
		goto __failed;
    }

	fSymbolicLink = TRUE;

    //
    // Create dispatch points for device control, create, close.
    //

    DriverObject->MajorFunction[IRP_MJ_CREATE]         			= UsbDispatchCreate;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]          			= UsbDispatchClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] 			= UsbDispatchDeviceControl;
    DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = UsbDispatchInternalDeviceControl;
    DriverObject->DriverUnload                         			= UsbUnload;

    if (NT_SUCCESS(status))
	    return status;

__failed:

	if (fSymbolicLink)
		IoDeleteSymbolicLink(&dosDeviceName);

	if (deviceObject)
		IoDeleteDevice(deviceObject);

	return status;
}

NTSTATUS
UsbDispatchCreate(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					Irp
	)
{
	NTSTATUS status = STATUS_SUCCESS;

    Irp->IoStatus.Information = 0;

	dprintf("[usb] IRP_MJ_CREATE\n");

    Irp->IoStatus.Status = status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return status;
}

NTSTATUS
UsbDispatchClose(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					Irp
	)
{
	NTSTATUS status = STATUS_SUCCESS;

    Irp->IoStatus.Information = 0;

	dprintf("[usb] IRP_MJ_CLOSE\n");

    Irp->IoStatus.Status = status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return status;
}

NTSTATUS
UsbDispatchDeviceControl(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					Irp
	)
{
	NTSTATUS			status = STATUS_SUCCESS;
    PIO_STACK_LOCATION	irpStack;
    PDEVICE_EXTENSION	deviceExtension;
    PVOID				ioBuf;
    ULONG				inBufLength, outBufLength;
	ULONG				ioControlCode;

    irpStack = IoGetCurrentIrpStackLocation(Irp);
    deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

    Irp->IoStatus.Information = 0;

    //
    // Get the pointer to the input/output buffer and it's length
    //

    ioBuf = Irp->AssociatedIrp.SystemBuffer;
    inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
    outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
    ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

    switch (ioControlCode)
    {
	case IOCTL_XYZ :
		{
			//
			// Manage this!
			//

            break;
		}

    default:
        status = STATUS_INVALID_PARAMETER;

        dprintf("[usb] unknown IRP_MJ_DEVICE_CONTROL = 0x%x (%04x,%04x)\n",
			ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode),
			IoGetFunctionCodeFromCtlCode(ioControlCode));

        break;
	}

    //
    // DON'T get cute and try to use the status field of
    // the irp in the return status.  That IRP IS GONE as
    // soon as you call IoCompleteRequest.
    //

    Irp->IoStatus.Status = status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    //
    // We never have pending operation so always return the status code.
    //

    return status;
}

/*
 * USB client drivers must communicate with their devices using IOCTL requests that are delivered to the device by means 
 * of an I/O request packet (IRP) of type IRP_MJ_INTERNAL_DEVICE_CONTROL. 
 * This request must contain one of the device control codes that are defined in I/O Requests for USB Client Drivers. 
 * These device control codes are "internal" in the sense that they provide an I/O interface that a USB client driver uses to manage its device 
 * and the port to which the device is connected. User-mode applications do not have access to this I/O interface.
 */
NTSTATUS
UsbDispatchInternalDeviceControl(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					Irp
	)
{
	NTSTATUS			status = STATUS_SUCCESS;
    PIO_STACK_LOCATION	irpStack;
    PDEVICE_EXTENSION	deviceExtension;
    PVOID				ioBuf;
    ULONG				inBufLength, outBufLength;
	ULONG				ioControlCode;

    irpStack = IoGetCurrentIrpStackLocation(Irp);
    deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

    Irp->IoStatus.Information = 0;

    //
    // Get the pointer to the input/output buffer and it's length
    //

    ioBuf = Irp->AssociatedIrp.SystemBuffer;
    inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
    outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
    ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

    switch (ioControlCode)
    {
	case IOCTL_INTERNAL_USB_SUBMIT_URB:
		{
			//
			// A client driver uses IOCTL_INTERNAL_USB_SUBMIT_URB to deliver a variable-length data structure called a USB Request Block (URB) to the device it manages. 
			// Kernel-mode client drivers perform all device-specific operations, including data transfers, by means of URBs. 
			// Each URB begins with a standard header. The Length member of the URB header specifies the size, in bytes, of the URB. 
			// The Function member, which must be one of a series of system-defined URB_FUNCTION_XXX constants, determines the type of operation that is requested. 
			// In the case of data transfers, for instance, this member indicates the type of transfer.
			//
		    switch (ioControlCode)
		    {
			    case URB_FUNCTION_SELECT_CONFIGURATION
			    //Indicates to the host controller driver that a configuration is to be selected. If set, the URB is used with _    case URB_SELECT_CONFIGURATION as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_SELECT_INTERFACE
			    //Indicates to the host controller driver that an alternate interface setting is being selected for an interface. If set, the URB is used with _    case URB_SELECT_INTERFACE as the data structure. 
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_ABORT_PIPE
			    //Indicates that all outstanding requests for a pipe should be canceled. If set, the URB is used with _    case URB_PIPE_REQUEST as the data structure. This general-purpose request enables a client to cancel any pending transfers for the specified pipe. Pipe state and endpoint state are unaffected. The abort request might complete before all outstanding requests have completed. Do not assume that completion of the abort request implies that all other outstanding requests have completed. 
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL
			    //This URB function is obsolete in Windows 2000 and later operating systems and is not supported by Microsoft. If you specify this function with an URB request, the request will fail and the system will report an error. In the past, this function indicated that the client was requesting sole control of the frame length for the USB bus. It was used with _    case URB_FRAME_LENGTH_CONTROL as the data structure. 
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL
			    //This URB function is obsolete in Windows 2000 and later operating systems and is not supported by Microsoft. If you specify this function with an URB request, the request will fail and the system will report an error. In the past, this function indicated that the client was releasing control of the frame length on the USB bus. It was used with _    case URB_FRAME_LENGTH_CONTROL as the data structure. 
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_GET_FRAME_LENGTH
			    //This URB function is obsolete in Windows 2000 and later operating systems and is not supported by Microsoft. If you use this function with a URB request, the request will fail and the system will report an error. In the past, this function requested the current frame length on the USB bus. If set, the URB is used with _    case URB_GET_FRAME_LENGTH as the data structure. 
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_SET_FRAME_LENGTH
			    //This URB function is obsolete in Windows 2000 and later operating systems. If you use it with a URB request, the request will fail and the system will report an error. In the past, this URB function altered the current frame length on the USB bus. It was used with _    case URB_SET_FRAME_LENGTH as the data structure. 
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_GET_CURRENT_FRAME_NUMBER
			    //Requests the current frame number from the host controller driver. If set, the URB is used with _    case URB_GET_CURRENT_FRAME_NUMBER as the data structure. 
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_CONTROL_TRANSFER
			    //Transfers data to or from a control pipe. If set, the URB is used with _    case URB_CONTROL_TRANSFER as the data structure. 
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_CONTROL_TRANSFER_EX
			    //Transfers data to or from a control pipe without a time limit specified by a timeout value. If set, the URB is used with    case     case URB_CONTROL_TRANSFER_EX as the data structure. 
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
			    //Transfers data from a bulk pipe or interrupt pipe or to an bulk pipe. If set, the URB is used with _    case URB_BULK_OR_INTERRUPT_TRANSFER as the data structure. 
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_ISOCH_TRANSFER
			    //Transfers data to or from an isochronous pipe. If set, the URB is used with _    case URB_ISOCH_TRANSFER as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_RESET_PIPE
			    //Resets the indicated pipe. If set, this URB is used with _    case URB_PIPE_REQUEST.
			    //The bus driver accomplishes three tasks in response to this URB:
			    //First, for all pipes except isochronous pipes, this URB sends a CLEAR_FEATURE request to clear the device's ENDPOINT_HALT feature.
			    //Second, the USB bus driver resets the data toggle on the host side, as required by the USB specification. The USB device should reset the data toggle on the device side when the bus driver clears its ENDPOINT_HALT feature. Since some non-compliant devices do not support this feature, Microsoft provides the two additional URBs:    case     case URB_FUNCTION_SYNC_CLEAR_STALL and    case     case URB_FUNCTION_SYNC_RESET_PIPE. These allow client drivers to clear the ENDPOINT_HALT feature on the device, or reset the pipe on the host side, respectively, without affecting the data toggle on the host side. If the device does not reset the data toggle when it should, then the client driver can compensate for this defect by not resetting the host-side data toggle. If the data toggle is reset on the host side but not on the device side, packets will get out of sequence, and the device might drop packets.
			    //Third, after the bus driver has successfully reset the pipe, it resumes transfers with the next queued URB.
			    //After a pipe reset, transfers resume with the next queued URB.
			    //It is not necessary to clear a halt condition on a default control pipe. The default control pipe must always accept setup packets, and so if it halts, the USB stack will clear the halt condition automatically. The client driver does not need to take any special action to clear the halt condition on a default pipe.
			    //All transfers must be aborted or canceled before attempting to reset the pipe.
			
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    //This URB must be sent at PASSIVE_LEVEL.
			    case URB_FUNCTION_SYNC_RESET_PIPE
			    //Clears the halt condition on the host side of a pipe. If set, this URB is used with _    case URB_PIPE_REQUEST as the data structure.
			    //This URB allows a client to clear the halted state of a pipe without resetting the data toggle and without clearing the endpoint stall condition (feature ENDPOINT_HALT). To clear a halt condition on the pipe, reset the host-side data toggle and clear a stall on the device with a single operation, use    case     case URB_FUNCTION_RESET_PIPE.
			    //The following status codes are important and have the indicated meaning:
			    //USBD_STATUS_INVALID_PIPE_HANDLE
			    //The PipeHandle is not valid
			    //USBD_STATUS_ERROR_BUSY
			    //The endpoint has active transfers pending.
			    //It is not necessary to clear a halt condition on a default control pipe. The default control pipe must always accept setup packets, and so if it halts, the USB stack will clear the halt condition automatically. The client driver does not need to take any special action to clear the halt condition on a default pipe.
			    //All transfers must be aborted or canceled before attempting to reset the pipe.
			
			    //This URB must be sent at PASSIVE_LEVEL.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_SYNC_CLEAR_STALL
			    //Clears the stall condition on the endpoint. For all pipes except isochronous pipes, this URB sends a CLEAR_FEATURE request to clear the device's ENDPOINT_HALT feature. However, unlike the    case     case URB_FUNCTION_RESET_PIPE function, this URB function does not reset the data toggle on the host side of the pipe.
			    //The USB specification requires devices to reset the device-side data toggle after the client clears the device's ENDPOINT_HALT feature, but some non-compliant devices do not reset their data toggle properly. Client drivers that manage such devices can compensate for this defect by clearing the stall condition directly with    case     case URB_FUNCTION_SYNC_CLEAR_STALL instead of resetting the pipe with    case     case URB_FUNCTION_RESET_PIPE.    case     case URB_FUNCTION_SYNC_CLEAR_STALL clears a stall condition on the device without resetting the host-side data toggle. This prevents a non-compliant device from interpreting the next packet as a retransmission and dropping the packet.
			    //If set, the URB is used with _    case URB_PIPE_REQUEST as the data structure.
			
			    //This URB function should be sent at PASSIVE_LEVEL
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
			    //Retrieves the device descriptor from a specific USB device. If set, the URB is used with _    case URB_CONTROL_DESCRIPTOR_REQUEST as the data structure. 
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT
			    //Retrieves the descriptor from an endpoint on an interface for a USB device. If set, the URB is used with _    case URB_CONTROL_DESCRIPTOR_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE
			    //Sets a device descriptor on a device. If set, the URB is used with _    case URB_CONTROL_DESCRIPTOR_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT
			    //Sets an endpoint descriptor on an endpoint for an interface. If set, the URB is used with _    case URB_CONTROL_DESCRIPTOR_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_SET_FEATURE_TO_DEVICE
			    //Sets a USB-defined feature on a device. If set, the URB is used with _    case URB_CONTROL_FEATURE_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_SET_FEATURE_TO_INTERFACE
			    //Sets a USB-defined feature on an interface for a device. If set, the URB is used with _    case URB_CONTROL_FEATURE_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT
			    //Sets a USB-defined feature on an endpoint for an interface on a USB device. If set, the URB is used with _    case URB_CONTROL_FEATURE_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_SET_FEATURE_TO_OTHER
			    //Sets a USB-defined feature on a device-defined target on a USB device. If set, the URB is used with _    case URB_CONTROL_FEATURE_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE
			    //Clears a USB-defined feature on a device. If set, the URB is used with _    case URB_CONTROL_FEATURE_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE
			    //Clears a USB-defined feature on an interface for a device. If set, the URB is used with _    case URB_CONTROL_FEATURE_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT
			    //Clears a USB-defined feature on an endpoint, for an interface, on a USB device. If set, the URB is used with _    case URB_CONTROL_FEATURE_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_CLEAR_FEATURE_TO_OTHER
			    //Clears a USB-defined feature on a device defined target on a USB device. If set, the URB is used with _    case URB_CONTROL_FEATURE_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_GET_STATUS_FROM_DEVICE
			    //Retrieves status from a USB device. If set, the URB is used with _    case URB_CONTROL_GET_STATUS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_GET_STATUS_FROM_INTERFACE
			    //Retrieves status from an interface on a USB device. If set, the URB is used with _    case URB_CONTROL_GET_STATUS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT
			    //Retrieves status from an endpoint for an interface on a USB device. If set, the URB is used with _    case URB_CONTROL_GET_STATUS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_GET_STATUS_FROM_OTHER
			    //Retrieves status from a device-defined target on a USB device. If set, the URB is used with _    case URB_CONTROL_GET_STATUS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_VENDOR_DEVICE
			    //Sends a vendor-specific command to a USB device. If set, the URB is used with _    case URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_VENDOR_INTERFACE
			    //Sends a vendor-specific command for an interface on a USB device. If set, the URB is used with _    case URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_VENDOR_ENDPOINT
			    //Sends a vendor-specific command for an endpoint on an interface on a USB device. If set, the URB is used with _    case URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_VENDOR_OTHER
			    //Sends a vendor-specific command to a device-defined target on a USB device. If set, the URB is used with _    case URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_CLASS_DEVICE
			    //Sends a USB-defined class-specific command to a USB device. If set, the URB is used with _    case URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_CLASS_INTERFACE
			    //Sends a USB-defined class-specific command to an interface on a USB device. If set, the URB is used with _    case URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_CLASS_ENDPOINT
			    //Sends a USB-defined class-specific command to an endpoint, on an interface, on a USB device. If set, the URB is used with _    case URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_CLASS_OTHER
			    //Sends a USB-defined class-specific command to a device defined target on a USB device. If set, the URB is used with _    case URB_CONTROL_VENDOR_OR_CLASS_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_GET_CONFIGURATION
			    //Retrieves the current configuration on a USB device. If set, the URB is used with _    case URB_CONTROL_GET_CONFIGURATION_REQUEST as the data structure.
					{
						//
						// Manage this!
						//
			
			            break;
					}
			    case URB_FUNCTION_GET_INTERFACE
			    //Retrieves the current settings for an interface on a USB device. If set, the URB is used with _    case URB_CONTROL_GET_INTERFACE_REQUEST as the data structure.			
					{
						//
						// Manage this!
						//
			
			            break;
					}
		    default:
		        status = STATUS_INVALID_PARAMETER;
		
		        dprintf("[usb] unknown URB  = 0x%x (%04x,%04x)\n",
					ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode),
					IoGetFunctionCodeFromCtlCode(ioControlCode));
		
		        break;
			}

            break;
		}
		
	case IOCTL_INTERNAL_USB_SUBMIT_URB
		{
			//
			// Manage this!
			//

            break;
		}
	case IOCTL_INTERNAL_USB_RESET_PORT
		{
			//
			// Manage this!
			//

            break;
		}
	case IOCTL_INTERNAL_USB_GET_PORT_STATUS
		{
			//
			// Manage this!
			//

            break;
		}
	case IOCTL_INTERNAL_USB_ENABLE_PORT
		{
			//
			// Manage this!
			//

            break;
		}
	case IOCTL_INTERNAL_USB_GET_HUB_COUNT
		{
			//
			// Manage this!
			//

            break;
		}
	case IOCTL_INTERNAL_USB_CYCLE_PORT
		{
			//
			// Manage this!
			//

            break;
		}
	case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO
		{
			//
			// Manage this!
			//

            break;
		}
	case IOCTL_INTERNAL_USB_GET_HUB_NAME
		{
			//
			// Manage this!
			//

            break;
		}
	case IOCTL_INTERNAL_USB_GET_BUS_INFO
		{
			//
			// Manage this!
			//

            break;
		}
	case IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME
		{
			//
			// Manage this!
			//

            break;
		}
	case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION
		{
			//
			// Manage this!
			//

            break;
		}

    default:
        status = STATUS_INVALID_PARAMETER;

        dprintf("[usb] unknown IRP_MJ_DEVICE_CONTROL = 0x%x (%04x,%04x)\n",
			ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode),
			IoGetFunctionCodeFromCtlCode(ioControlCode));

        break;
	}

    //
    // DON'T get cute and try to use the status field of
    // the irp in the return status.  That IRP IS GONE as
    // soon as you call IoCompleteRequest.
    //

    Irp->IoStatus.Status = status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    //
    // We never have pending operation so always return the status code.
    //

    return status;
}

VOID
UsbUnload(
	IN PDRIVER_OBJECT		DriverObject
	)
{
    UNICODE_STRING dosDeviceName;

	//
    // Free any resources
    //

    //
    // Delete the symbolic link
    //

    RtlInitUnicodeString(&dosDeviceName, USB_DOS_DEVICE_NAME_W);

    IoDeleteSymbolicLink(&dosDeviceName);

    //
    // Delete the device object
    //

    IoDeleteDevice(DriverObject->DeviceObject);

    dprintf("[usb] unloaded\n");
}

References