📄 uscrusb.c
字号:
}
USCR_KdPrintCond( DBGLVL_DEFAULT,
(!(NT_SUCCESS(ntStatus))),
("USCR_CreateDeviceObject() IoCreateDevice() FAILED\n"));
if (!NT_SUCCESS(ntStatus)) {
return ntStatus;
}
//default maximum transfer size per staged io request
deviceExtension->MaximumTransferSize = USCR_MAX_TRANSFER_SIZE ;
#if DBG
// may be overridden in registry
USCR_GetRegistryDword( USCR_REGISTRY_PARAMETERS_PATH,
L"MaximumTransferSize",
&(deviceExtension->MaximumTransferSize) );
#endif
// Name buffer for our named Functional device object link
// The name is generated based on the driver's class GUID
RtlCopyMemory(deviceExtension->DeviceLinkNameBuffer,
deviceLinkUnicodeString.Buffer,
deviceLinkUnicodeString.Length);
// this event is triggered when there is no pending io of any kind and device is removed
KeInitializeEvent(&deviceExtension->RemoveEvent, NotificationEvent, FALSE);
// this event is triggered when self-requested power irps complete
KeInitializeEvent(&deviceExtension->SelfRequestedPowerIrpEvent, NotificationEvent, FALSE);
// this event is triggered when there is no pending io (pending io count == 1 )
KeInitializeEvent(&deviceExtension->NoPendingIoEvent, NotificationEvent, FALSE);
// spinlock used to protect inc/dec iocount logic
KeInitializeSpinLock (&deviceExtension->IoCountSpinLock);
//free buffer from unicode string we used to init interface
RtlFreeUnicodeString(&deviceLinkUnicodeString );
deviceExtension->UsbDeviceDescriptor = NULL;
deviceExtension->UsbInterface = NULL;
deviceExtension->UsbConfigurationDescriptor = NULL;
InitializeSmartcardExtension(*DeviceObject);
deviceExtension->bFileOpened = FALSE;
}
USCR_KdPrint( DBGLVL_DEFAULT,
("exiting USCR_CreateDeviceObject (%x) \n",ntStatus)
);
return ntStatus;
}
NTSTATUS
USCR_CallUSBD(
IN PDEVICE_OBJECT DeviceObject,
IN PURB Urb
)
/*++
Routine Description:
Passes a URB to the USBD class driver
The client device driver passes USB request block (URB) structures
to the class driver as a parameter in an IRP with Irp->MajorFunction
set to IRP_MJ_INTERNAL_DEVICE_CONTROL and the next IRP stack location
Parameters.DeviceIoControl.IoControlCode field set to
IOCTL_INTERNAL_USB_SUBMIT_URB.
Arguments:
DeviceObject - pointer to the physical device object (PDO)
Urb - pointer to an already-formatted Urb request block
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus, status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
USCR_KdPrint( DBGLVL_MAXIMUM,("enter USCR_CallUSBD\n"));
deviceExtension = DeviceObject->DeviceExtension;
//
// issue a synchronous request
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
deviceExtension->TopOfStackDeviceObject, //Points to the next-lower driver's device object
NULL, // optional input bufer; none needed here
0, // input buffer len if used
NULL, // optional output bufer; none needed here
0, // output buffer len if used
TRUE, // If InternalDeviceControl is TRUE the target driver's Dispatch
// outine for IRP_MJ_INTERNAL_DEVICE_CONTROL or IRP_MJ_SCSI
// is called; otherwise, the Dispatch routine for
// IRP_MJ_DEVICE_CONTROL is called.
&event, // event to be signalled on completion
&ioStatus); // Specifies an I/O status block to be set when the request is completed the lower driver.
//
// As an alternative, we could call KeDelayExecutionThread, wait for some
// period of time, and try again....but we keep it simple for right now
//
if (!irp) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//USCR_KdPrint(DBGLVL_DEFAULT,("irp=%p\n",irp));
//
// Call the class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
nextStack = IoGetNextIrpStackLocation(irp);
USCR_ASSERT(nextStack != NULL);
//
// pass the URB to the USB driver stack
//
nextStack->Parameters.Others.Argument1 = Urb;
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
USCR_KdPrint( DBGLVL_MAXIMUM,("USCR_CallUSBD() return from IoCallDriver USBD %x\n", ntStatus));
if (ntStatus == STATUS_PENDING) {
LARGE_INTEGER timeout;
timeout.QuadPart = -USB_REQUEST_TIMEOUT;
status = KeWaitForSingleObject(
&event,
Executive,
KernelMode,
FALSE,
&timeout);
if (status == STATUS_TIMEOUT) {
ntStatus = STATUS_IO_TIMEOUT;
// Cancel the Irp we just sent.
//
IoCancelIrp(irp);
// And wait until the cancel completes
//
KeWaitForSingleObject(&event,Executive, KernelMode, FALSE,NULL);
}else
ntStatus = ioStatus.Status;
} else {
ioStatus.Status = ntStatus;
}
USCR_KdPrint( DBGLVL_MAXIMUM,("USCR_CallUSBD() URB status = %x status = %x irp status %x\n",
Urb->UrbHeader.Status, status, ioStatus.Status));
//
// USBD maps the error code for us
//
//ntStatus = ioStatus.Status;
USCR_KdPrintCond( DBGLVL_MAXIMUM, !NT_SUCCESS( ntStatus ), ("exit USCR_CallUSBD FAILED (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USCR_ConfigureDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Initializes a given instance of the device on the USB and
selects and saves the configuration.
Arguments:
DeviceObject - pointer to the physical device object for this instance of the 82930
device.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus;
PURB urb;
ULONG siz;
USCR_KdPrint( DBGLVL_HIGH,("enter USCR_ConfigureDevice\n"));
deviceExtension = DeviceObject->DeviceExtension;
USCR_ASSERT( deviceExtension->UsbConfigurationDescriptor == NULL );
urb = USCR_ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if ( !urb )
return STATUS_INSUFFICIENT_RESOURCES;
// When USB_CONFIGURATION_DESCRIPTOR_TYPE is specified for DescriptorType
// in a call to UsbBuildGetDescriptorRequest(),
// all interface, endpoint, class-specific, and vendor-specific descriptors
// for the configuration also are retrieved.
// The caller must allocate a buffer large enough to hold all of this
// information or the data is truncated without error.
// Therefore the 'siz' set below is just a 'good guess', and we may have to retry
siz = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 128;
// We will break out of this 'retry loop' when UsbBuildGetDescriptorRequest()
// has a big enough deviceExtension->UsbConfigurationDescriptor buffer not to truncate
while( 1 ) {
deviceExtension->UsbConfigurationDescriptor = USCR_ExAllocatePool(NonPagedPool, siz);
if ( !deviceExtension->UsbConfigurationDescriptor ) {
USCR_ExFreePool(urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
deviceExtension->UsbConfigurationDescriptor,
NULL,
siz,
NULL);
ntStatus = USCR_CallUSBD(DeviceObject, urb);
USCR_KdPrint( DBGLVL_HIGH,("USCR_CallUSBD() Configuration Descriptor = %x, len %x\n",
deviceExtension->UsbConfigurationDescriptor,
urb->UrbControlDescriptorRequest.TransferBufferLength));
//
// if we got some data see if it was enough.
// NOTE: we may get an error in URB because of buffer overrun
if (urb->UrbControlDescriptorRequest.TransferBufferLength>0 &&
deviceExtension->UsbConfigurationDescriptor->wTotalLength > siz) {
siz = deviceExtension->UsbConfigurationDescriptor->wTotalLength;
USCR_ExFreePool(deviceExtension->UsbConfigurationDescriptor);
deviceExtension->UsbConfigurationDescriptor = NULL;
} else {
break; // we got it on the first try
}
} // end, while (retry loop )
USCR_ExFreePool(urb);
USCR_ASSERT( deviceExtension->UsbConfigurationDescriptor );
//
// We have the configuration descriptor for the configuration we want.
// Now we issue the select configuration command to get
// the pipes associated with this configuration.
//
ntStatus = USCR_SelectInterface(DeviceObject,
deviceExtension->UsbConfigurationDescriptor);
USCR_KdPrint( DBGLVL_HIGH,("exit USCR_ConfigureDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USCR_SelectInterface(
IN PDEVICE_OBJECT DeviceObject,
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
/*++
Routine Description:
Initializes an 82930 with (possibly) multiple interfaces;
This minidriver only supports one interface (with multiple endpoints).
Arguments:
DeviceObject - pointer to the device object for this instance of the 82930
device.
ConfigurationDescriptor - pointer to the USB configuration
descriptor containing the interface and endpoint
descriptors.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus;
PURB urb = NULL;
ULONG i;
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = NULL;
PUSBD_INTERFACE_INFORMATION Interface = NULL;
USHORT siz;
PUCHAR pInf;
USCR_KdPrint( DBGLVL_MEDIUM,("enter USCR_SelectInterface\n"));
deviceExtension = DeviceObject->DeviceExtension;
USCR_KdPrint( DBGLVL_HIGH,("USCR_SelectInterface() called with NULL Interface\n"));
//
// USCR driver only supports one interface, we must parse
// the configuration descriptor for the interface
// and remember the pipes.
//
urb = USBD_CreateConfigurationRequest(ConfigurationDescriptor, &siz);
if (urb) {
//
// USBD_ParseConfigurationDescriptorEx searches a given configuration
// descriptor and returns a pointer to an interface that matches the
// given search criteria. We only support one interface on this device
//
interfaceDescriptor =
USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor,
ConfigurationDescriptor, //search from start of config descriptro
-1, // interface number not a criteria; we only support one interface
-1, // not interested in alternate setting here either
-1, // interface class not a criteria
-1, // interface subclass not a criteria
-1 // interface protocol not a criteria
);
if ( !interfaceDescriptor ) {
USCR_KdPrint( DBGLVL_HIGH,("USCR_SelectInterface() ParseConfigurationDescriptorEx() failed\n returning STATUS_INSUFFICIENT_RESOURCES\n"));
USCR_ExFreePool(urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
Interface = &urb->UrbSelectConfiguration.Interface;
for (i=0; i< Interface->NumberOfPipes; i++) {
//
// Perform any pipe initialization here;
// We set the max transfer size and any Pipe flags we use; USBD sets the rest
// of the Interface struct members
//
Interface->Pipes[i].MaximumTransferSize = deviceExtension->MaximumTransferSize;
}
UsbBuildSelectConfigurationRequest(urb,
(USHORT) siz,
ConfigurationDescriptor);
ntStatus = USCR_CallUSBD(DeviceObject, urb);
deviceExtension->UsbConfigurationHandle =
urb->UrbSelectConfiguration.ConfigurationHandle;
} else {
USCR_KdPrint( DBGLVL_HIGH,("USCR_SelectInterface() USBD_CreateConfigurationRequest() failed\n returning STATUS_INSUFFICIENT_RESOURCES\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(ntStatus)) {
//
// Save the configuration handle for this device
//
deviceExtension->UsbConfigurationHandle =
urb->UrbSelectConfiguration.ConfigurationHandle;
deviceExtension->UsbInterface = USCR_ExAllocatePool(NonPagedPool,
Interface->Length);
if (deviceExtension->UsbInterface) {
ULONG j;
//
// save a copy of the interface information returned
//
RtlCopyMemory(deviceExtension->UsbInterface, Interface, Interface->Length);
//
// Dump the interface to the debugger
//
USCR_KdPrint( DBGLVL_MEDIUM,("---------\n"));
USCR_KdPrint( DBGLVL_MEDIUM,("NumberOfPipes 0x%x\n", deviceExtension->UsbInterface->NumberOfPipes));
USCR_KdPrint( DBGLVL_MEDIUM,("Length 0x%x\n", deviceExtension->UsbInterface->Length));
USCR_KdPrint( DBGLVL_MEDIUM,("Alt Setting 0x%x\n", deviceExtension->UsbInterface->AlternateSetting));
USCR_KdPrint( DBGLVL_MEDIUM,("Interface Number 0x%x\n", deviceExtension->UsbInterface->InterfaceNumber));
USCR_KdPrint( DBGLVL_MEDIUM,("Class, subclass, protocol 0x%x 0x%x 0x%x\n",
deviceExtension->UsbInterface->Class,
deviceExtension->UsbInterface->SubClass,
deviceExtension->UsbInterface->Protocol));
// Dump the pipe info
for (j=0; j<Interface->NumberOfPipes; j++) {
PUSBD_PIPE_INFORMATION pipeInformation;
pipeInformation = &deviceExtension->UsbInterface->Pipes[j];
USCR_KdPrint( DBGLVL_MEDIUM,("---------\n"));
USCR_KdPrint( DBGLVL_MEDIUM,("PipeType 0x%x\n", pipeInformation->PipeType));
USCR_KdPrint( DBGLVL_MEDIUM,("EndpointAddress 0x%x\n", pipeInformation->EndpointAddress));
USCR_KdPrint( DBGLVL_MEDIUM,("MaxPacketSize 0x%x\n", pipeInformation->MaximumPacketSize));
USCR_KdPrint( DBGLVL_MEDIUM,("Interval 0x%x\n", pipeInformation->Interval));
USCR_KdPrint( DBGLVL_MEDIUM,("Handle 0x%x\n", pipeInformation->PipeHandle));
USCR_KdPrint( DBGLVL_MEDIUM,("MaximumTransferSize 0x%x\n", pipeInformation->MaximumTransferSize));
}
USCR_KdPrint( DBGLVL_MEDIUM,("---------\n"));
}
}
if (urb) {
// don't call the USCR_ExFreePool since the buffer was
// alloced by USBD_CreateConfigurationRequest, not USCR_ExAllocatePool()
ExFreePool(urb);
}
USCR_KdPrint( DBGLVL_HIGH,("exit USCR_SelectInterface (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USCR_ResetPipe(
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_PIPE_INFORMATION PipeInfo
)
/*++
Routine Description:
Reset a given USB pipe.
NOTES:
This will reset the host to Data0 and should also reset the device to Data0
Arguments:
Ptrs to our FDO and a USBD_PIPE_INFORMATION struct
Return Value:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -