If you look at the KMDF headers, you will see two names, pipes and endpoints, that refer to the same concept. They can be confusing, I had to spend a few minutes explaining them to one our technical writers awhile back explaining why we had two names in the first place (and, yes, there is a method to the madness).
If you have read the USB specification or looked at descriptors before, the term endpoint should not be anything new to you. An endpoint is an address on the device. The endpoint is unidirectional (unless it is a control endpoint), has a type (control, interrupt, bulk, isoch) and other properties. The endpoint is self descriptive, you can retrieve the endpoint descriptor by retrieving the config descriptor and then parsing for each endpoint. Endpoint is a term that relates to the hardware itself, independent of the host operating system.
Pipes on the other hand is purely an OS term (IIRC, the USB core spec does mention pipes as well, but uses them as an abstract term). A pipe is an endpoint that has been configured through a select configuration or selecting an interface’s alternate setting. A pipe has all the properties of an endpoint, but it is active and be used to communicate with the host. To put it bluntly, an unconfigured endpoint is called an endpoint while a configured endpoint is called a pipe.
Why even make this distinction?
We made the distinction because what you do with an endpoint and a pipe are completely different. If a driver is going to look at endpoint information, it will be before the device has been configured or during selection of an alternate setting. The driver will iterate over all of the interfaces (WdfUsbTargetDeviceGetNumInterfaces, WdfUsbTargetDeviceGetInterface) and then iterate over each interfaces list of settings (WdfUsbInterfaceGetNumSettings, WdfUsbInterfaceGetNumEndpoints) and look at the properties of each endpoint (WdfUsbInterfaceGetEndpointInformation) or the entire set of endpoints in the setting. Looking at the endpoint information is cheap and does not affect the configured state of the device. Note that each of these DDIs use the term “Endpoint” in their name; any DDI which has “Endpoint” in its name operates on an unconfigured endpoint.
While (IMHO) very few drivers will search for specific unconfigured endpoint information, every USB driver will be looking at configured pipe information after selecting a configuration. A driver will iterate over an interface’s pipes (WdfUsbInterfaceGetNumConfiguredPipes, WdfUsbInterfaceGetConfiguredPipe) and then retrieve the pipe’s information (WdfUsbTargetPipeGetInformation). If a driver has multiple interfaces then this is repeated for each interface. Note that each of these DDIs use the term “Pipe” to in their name; any DDI which has “Pipe” in its name operates on a configured pipe.
One question that I have been asked is why the WdfUsbTargetPipeXxx DDIs aren’t called WdfUsbTargetConfiguredPipeXxx and the reason is that a WDFUSBPIPE can only be a configured pipe and the only way to get a WDFUSBPIPE is to make a call to WdfUsbGetConfiguredPipe. Also while I have referred to the KMDF DDIs, the UMDF DDIs have very similar names and follow the same pattern.