|
|
/*
************************************************************************* * File: URBFUNC.C * * Module: USBCCGP.SYS * USB Common Class Generic Parent driver. * * Copyright (c) 1998 Microsoft Corporation * * * Author: ervinp * ************************************************************************* */
#include <wdm.h>
#include <stdio.h>
#include <usbdi.h>
#include <usbdlib.h>
#include <usbioctl.h>
#include "usbccgp.h"
#include "debug.h"
/*
* UrbFunctionSelectConfiguration * * */ NTSTATUS UrbFunctionSelectConfiguration(PFUNCTION_PDO_EXT functionPdoExt, PURB urb) { NTSTATUS status = NO_STATUS;
if (urb->UrbSelectConfiguration.ConfigurationDescriptor){ PUSBD_INTERFACE_INFORMATION urbIface = &urb->UrbSelectConfiguration.Interface; PUSBD_INTERFACE_LIST_ENTRY iface, funcIface = NULL; ULONG i;
ASSERT(ISPTR(functionPdoExt->functionInterfaceList));
iface = functionPdoExt->functionInterfaceList; for (i = 0; i < functionPdoExt->numInterfaces; i++){ if (iface->Interface->InterfaceNumber == urbIface->InterfaceNumber){ funcIface = iface; break; } iface++; }
if (funcIface && funcIface->Interface){ BOOLEAN sendSelectIface = FALSE; BOOLEAN selectAltIface = FALSE;
/*
* To service the client's SELECT_CONFIGURATION call, we only need to * call the parent if the client is: * 1. Selecting a different alternate interface * or * 2. Changing the MaximumTransferSize for one of the pipes. * * In either of those cases, we send down a SELECT_INTERFACE request. */ if (funcIface->Interface->AlternateSetting != urbIface->AlternateSetting){ DBGWARN(("Coverage: Changing alt iface in UrbFunctionSelectConfiguration (iface #%xh from %xh to %xh).", urbIface->InterfaceNumber, funcIface->Interface->AlternateSetting, urbIface->AlternateSetting)); sendSelectIface = TRUE; selectAltIface = TRUE; } else { ULONG numPipes; //
// We shouldn't be looking at NumberOfPipes in the URB because this is an
// OUTPUT field.
// ASSERT(urbIface->NumberOfPipes == funcIface->Interface->NumberOfPipes);
// numPipes = MIN(urbIface->NumberOfPipes, funcIface->Interface->NumberOfPipes);
numPipes = funcIface->Interface->NumberOfPipes; for (i = 0; i < numPipes; i++){ if (urbIface->Pipes[i].MaximumTransferSize != funcIface->Interface->Pipes[i].MaximumTransferSize){ DBGWARN(("Coverage: Changing MaximumTransferSize in UrbFunctionSelectConfiguration (from %xh to %xh).", funcIface->Interface->Pipes[i].MaximumTransferSize, urbIface->Pipes[i].MaximumTransferSize)); sendSelectIface = TRUE; } } }
if (sendSelectIface){ PURB selectIfaceUrb; USHORT size; //
// BUT, when choosing an alternate interface, we must use the NumberOfPipes in
// the URB.
//
if (selectAltIface){ size = (USHORT)(GET_SELECT_INTERFACE_REQUEST_SIZE(urbIface->NumberOfPipes)); } else { size = (USHORT)(GET_SELECT_INTERFACE_REQUEST_SIZE(funcIface->Interface->NumberOfPipes)); } selectIfaceUrb = ALLOCPOOL(NonPagedPool, size); if (selectIfaceUrb){ PUSBD_INTERFACE_INFORMATION selectIface = &selectIfaceUrb->UrbSelectInterface.Interface;
selectIfaceUrb->UrbSelectInterface.Hdr.Function = URB_FUNCTION_SELECT_INTERFACE; selectIfaceUrb->UrbSelectInterface.Hdr.Length = size; ASSERT(functionPdoExt->parentFdoExt->selectedConfigHandle); selectIfaceUrb->UrbSelectInterface.ConfigurationHandle = functionPdoExt->parentFdoExt->selectedConfigHandle;
RtlCopyMemory(selectIface, urbIface, urbIface->Length); status = SubmitUrb(functionPdoExt->parentFdoExt, selectIfaceUrb, TRUE, NULL, NULL); if (NT_SUCCESS(status)){ /*
* Replace the old PUSBD_INTERFACE_INFORMATION * (which we got when we did select-configuration for the parent) * with the new one. */ ASSERT(funcIface->Interface); FREEPOOL(funcIface->Interface); funcIface->Interface = MemDup(selectIface, selectIface->Length); if (!funcIface->Interface){ status = STATUS_INSUFFICIENT_RESOURCES; } } else { ASSERT(NT_SUCCESS(status)); }
FREEPOOL(selectIfaceUrb); } else { ASSERT(selectIfaceUrb); status = STATUS_INSUFFICIENT_RESOURCES; } } else { status = STATUS_SUCCESS; }
if (NT_SUCCESS(status)){ /*
* Copy the interface information */ ASSERT(urbIface->Length == funcIface->Interface->Length); RtlCopyMemory(urbIface, funcIface->Interface, funcIface->Interface->Length);
ASSERT(functionPdoExt->parentFdoExt->selectedConfigHandle); urb->UrbSelectConfiguration.ConfigurationHandle = functionPdoExt->parentFdoExt->selectedConfigHandle; } } else { DBGERR(("invalid interface number")); status = STATUS_INVALID_PARAMETER; } } else { DBGVERBOSE(("FunctionInternalDeviceControl - closing configuration")); status = STATUS_SUCCESS; }
return status; }
/*
* UrbFunctionGetDescriptorFromDevice * * * Note: this function cannot be pageable because internal * ioctls may be sent at IRQL==DISPATCH_LEVEL. */ NTSTATUS UrbFunctionGetDescriptorFromDevice(PFUNCTION_PDO_EXT functionPdoExt, PURB urb) { NTSTATUS status;
switch (urb->UrbControlDescriptorRequest.DescriptorType){
case USB_DEVICE_DESCRIPTOR_TYPE: DBGVERBOSE((" USB_DEVICE_DESCRIPTOR_TYPE")); if (urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR)){ RtlCopyMemory( urb->UrbControlDescriptorRequest.TransferBuffer, &functionPdoExt->functionDeviceDesc, sizeof(USB_DEVICE_DESCRIPTOR)); status = STATUS_SUCCESS; } else { status = STATUS_INVALID_BUFFER_SIZE; } urb->UrbControlDescriptorRequest.TransferBufferLength = sizeof(USB_DEVICE_DESCRIPTOR); break;
case USB_CONFIGURATION_DESCRIPTOR_TYPE: DBGVERBOSE((" USB_CONFIGURATION_DESCRIPTOR_TYPE")); status = BuildFunctionConfigurationDescriptor( functionPdoExt, urb->UrbControlDescriptorRequest.TransferBuffer, urb->UrbControlDescriptorRequest.TransferBufferLength, &urb->UrbControlDescriptorRequest.TransferBufferLength); break;
default: /*
* Return NO_STATUS so that URB gets passed down to USBHUB. */ DBGVERBOSE(("UrbFunctionGetDescriptorFromDevice: Unhandled desc type: %xh.", (ULONG)urb->UrbControlDescriptorRequest.DescriptorType)); status = NO_STATUS; break; }
return status; }
|