IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO | Used internally by hub driver |
IOCTL_INTERNAL_USB_GET_HUB_NAME | Get the device name of the USB hub |
IOCTL_INTERNAL_USB_GET_BUS_INFO | Fills in a USB_BUS_NOTIFICATION structure (W2000 only) |
IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME | Get the host controller device name (W2000 only) |
The most important Internal IOCTL is IOCTL_INTERNAL_USB_SUBMIT_URB, which lets you submit a USB Request Block (URB) for processing by the USB class drivers. There are thirty-odd different URB function codes. USB clients use URBs to do most of their hard work.
The URB structure itself is a union of some 16 different _URB_* structures, as shown in Listing 21.1. Each function code uses one of these other URB structures to detail its input or output parameters. All URB structures begin with a common header _URB_HEADER structure. The header
Listing 21.1 URB structures
typedef struct _URB {
union {
struct _URB_HEADER UrbHeader;
struct _URB_SELECT_INTERFACE UrbSelectInterface;
struct _URB_SELECT_CONFIGURATION UrbSelectConfiguration;
// …
};
} URB, *PURB;
struct _URB_HEADER {
USHORT Length;
USHORT Function;
USBD_STATUS Status;
// …
};
The
Table 21.3 URB
State code bits | Interpretation | Macro |
---|---|---|
00 | Completed successfully | USBD_SUCCESS |
01 | Request is pending | USBD_PENDING |
10 | Error, endpoint not stalled | USBD_ERROR |
11 | Error, endpoint stalled | USBD_ERROR or USBD_HALTED |
To make it easier to construct suitable URBs, various build macros are provided, such as
The reference section towards the end of this chapter lists the URB function codes. The reference section also details the other crucial USB structures. However, this chapter first illustrates how to perform most common USB actions by describing how these jobs are done in the UsbKbd driver.
Several URB structures have a
Listing 21.2 shows the Call USBDI routine in Usb.cpp. This is used to issue all the Internal lOCTLs to the USB system class drivers. It has default parameters that make it easy to ask for a URB to be processed.
CallUSBDI has to create a new IRP for the Internal IOCTL, fill in the IRP, and send off the IRP down the device stack to the USB system drivers. Further, it then waits until the IRP has been processed. CallUSBDI can only be called at PASSIVE_LEVEL
The USB Internal IOCTLs do not use the standard input and output IRP stack locations. Instead, the stack
Allocating IRPs
If you want to call a lower driver, it is usually simplest to reuse an existing IRP. You simply fill in the next IRP stack location with the correct function codes and parameters and call the next driver down the stack.
In some cases however, you will need to build an IRP from scratch. For example, you may wish to generate an IRP in your DriverEntry routine. Alternatively, you may process a large incoming request by splitting it into several different IRPs.
UsbKbd could reuse an existing IRP. However, it is straightforward to allocate a new IOCTL IRP. The
Building and issuing an IOCTL IRP is made particularly easy with the
Internally, it seems as though
The USB Internal IOCTLs do not use the standard input and output buffers[51]. Instead, you have to set up the next stack location