www.pudn.com > pdiusbd12 source.rar > D12.c
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
D12.c
Abstract:
USB device driver for Philips D12 USB test board
Environment:
kernel mode only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
Revision History:
5-4-96 : created
--*/
#define DRIVER
#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"
#include "usbdi.h"
#include "usbdlib.h"
#include "D12.h"
#include "d12irp.h"
#include "guid829.h"
//
// Global pointer to Driver Object
//
PDRIVER_OBJECT D12_DriverObject;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path
to driver-specific key in the registry
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
D12_KdPrint (("D12TEST.SYS: entering (D12) DriverEntry\n"));
D12_DriverObject = DriverObject;
//
// Create dispatch points for device control, create, close.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = D12_Create;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = D12_Close;
DriverObject->DriverUnload = D12_Unload;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = D12_ProcessIOCTL;
DriverObject->MajorFunction[IRP_MJ_WRITE] = D12_Write;
DriverObject->MajorFunction[IRP_MJ_READ] = D12_Read;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] =
DriverObject->MajorFunction[IRP_MJ_PNP] = D12_Dispatch;
DriverObject->MajorFunction[IRP_MJ_POWER] = D12_ProcessPowerIrp;
DriverObject->DriverExtension->AddDevice = D12_PnPAddDevice;
D12_KdPrint (("D12TEST.SYS: exiting (D12) DriverEntry (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
D12_PoRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
PIRP irp;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT deviceObject = Context;
NTSTATUS ntStatus;
deviceExtension = deviceObject->DeviceExtension;
irp = deviceExtension->PowerIrp;
ntStatus = IoStatus->Status;
D12_KdPrint(("'D12_PoRequestCompletion\n"));
IoCopyCurrentIrpStackLocationToNext(irp);
PoStartNextPowerIrp(irp);
PoCallDriver(deviceExtension->TopOfStackDeviceObject,
irp);
D12_DecrementIoCount(deviceObject);
return ntStatus;
}
NTSTATUS
D12_PowerIrp_Complete(
IN PDEVICE_OBJECT NullDeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
D12_KdPrint(("D12TEST.SYS: enter D12_PowerIrp_Complete\n"));
deviceObject = (PDEVICE_OBJECT) Context;
deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
// BUGBUG
// kenray sez we should be calling IoMarkIrpPending
// from our completion routine.
//
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
ASSERT(irpStack->MinorFunction == IRP_MN_SET_POWER);
ASSERT(irpStack->Parameters.Power.Type==DevicePowerState);
ASSERT(irpStack->Parameters.Power.State.DeviceState==PowerDeviceD0);
deviceExtension->CurrentDevicePowerState = PowerDeviceD0;
KdPrint(("D12TEST.SYS: enter D0 complete\n"));
Irp->IoStatus.Status = ntStatus;
D12_DecrementIoCount(deviceObject);
return ntStatus;
}
NTSTATUS
D12_SetDevicePowerState(
IN PDEVICE_OBJECT DeviceObject,
IN DEVICE_POWER_STATE DeviceState,
IN PBOOLEAN HookIt
)
/*++
Routine Description:
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
DeviceState - Device specific power state to set the device in to.
Return Value:
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
switch (DeviceState) {
case PowerDeviceD3:
//
// device will be going OFF, save any state now.
//
D12_KdPrint(("D12TEST.SYS: PowerDeviceD3 (OFF)\n"));
KdPrint(("D12: PM power off\n"));
deviceExtension->CurrentDevicePowerState = DeviceState;
break;
case PowerDeviceD1:
case PowerDeviceD2:
//
// power states D1,D2 translate to USB suspend
D12_KdPrint(("D12TEST.SYS: PowerDeviceD1/D2 (SUSPEND)\n"));
KdPrint(("D12: device entered D%d\n", DeviceState-1));
deviceExtension->CurrentDevicePowerState = DeviceState;
break;
case PowerDeviceD0:
D12_KdPrint(("D12TEST.SYS: PowerDeviceD0 (ON)\n"));
//
// finish the rest in the completion routine
//
*HookIt = TRUE;
// pass on to PDO
break;
default:
D12_KdPrint(("D12TEST.SYS: Bogus DeviceState = %x\n", DeviceState));
}
return ntStatus;
}
NTSTATUS
D12_DeferIrpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
PKEVENT event = Context;
KeSetEvent(event,
1,
FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
D12_QueryCapabilities(
IN PDEVICE_OBJECT PdoDeviceObject,
IN PDEVICE_CAPABILITIES DeviceCapabilities
)
/*++
Routine Description:
This routine reads or write config space.
Arguments:
DeviceObject - Physical DeviceObject for this USB controller.
Return Value:
None.
--*/
{
PIO_STACK_LOCATION nextStack;
PIRP irp;
NTSTATUS ntStatus;
KEVENT event;
PAGED_CODE();
irp = IoAllocateIrp(PdoDeviceObject->StackSize, FALSE);
if (!irp) {
return STATUS_INSUFFICIENT_RESOURCES;
}
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
nextStack->MajorFunction= IRP_MJ_PNP;
nextStack->MinorFunction= IRP_MN_QUERY_CAPABILITIES;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoSetCompletionRoutine(irp,
D12_DeferIrpCompletion,
&event,
TRUE,
TRUE,
TRUE);
//BUGBUG this is different from the latest version of busdd.doc
nextStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
ntStatus = IoCallDriver(PdoDeviceObject,
irp);
D12_KdPrint(("D12TEST.SYS: ntStatus from IoCallDriver to PCI = 0x%x\n", ntStatus));
if (ntStatus == STATUS_PENDING) {
// wait for irp to complete
TRAP(); // first time we hit this
KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
}
#if DBG
if (!NT_SUCCESS(ntStatus)) {
// failed? this is probably a bug
D12_KdPrint(("D12TEST.SYS: QueryCapabilities failed, why?\n"));
}
#endif
IoFreeIrp(irp);
return STATUS_SUCCESS;
}
NTSTATUS
D12_ProcessPowerIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the Power IRPs sent to the PDO for this device.
Arguments:
DeviceObject - pointer to a hcd device object (FDO)
Irp - pointer to an I/O Request Packet
Return Value:
NT status code
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
BOOLEAN hookIt = FALSE;
D12_KdPrint(("D12TEST.SYS: IRP_MJ_POWER\n"));
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation (Irp);
D12_IncrementIoCount(DeviceObject);
switch (irpStack->MinorFunction) {
case IRP_MN_WAIT_WAKE:
D12_KdPrint(("D12TEST.SYS: IRP_MN_WAIT_WAKE\n"));
//
// someone is enabling us for wakeup
//
TRAP(); // never seen this before?
// pass this on to our PDO
break;
case IRP_MN_SET_POWER:
{
switch (irpStack->Parameters.Power.Type) {
case SystemPowerState:
//
// find the device power state equivalent to the given system state
//
{
POWER_STATE powerState;
D12_KdPrint(("D12TEST.SYS: Set Power, SystemPowerState (%d)\n",
irpStack->Parameters.Power.State.SystemState));
if (irpStack->Parameters.Power.State.SystemState ==
PowerSystemWorking) {
powerState.DeviceState = PowerDeviceD0;
} else if (/* deviceExtension->EnabledForWakeup*/FALSE) {
// BUGBUG for now act as if we are always enabled for wakeup
D12_KdPrint(("D12TEST.SYS: D12 always enabled for wakeup\n"));
powerState.DeviceState =
deviceExtension->DeviceCapabilities.DeviceState[
irpStack->Parameters.Power.State.SystemState];
} else {
//
// wakeup not enabled, just go in to the 'OFF' state.
//
powerState.DeviceState = PowerDeviceD3;
} //irpStack->Parameters.Power.State.SystemState
//
// are we already in this state?
//
if (powerState.DeviceState !=
deviceExtension->CurrentDevicePowerState) {
// No,
// request that we be put into this state
deviceExtension->PowerIrp = Irp;
ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
IRP_MN_SET_POWER,
powerState,
D12_PoRequestCompletion,
DeviceObject,
NULL);
} else {
// Yes,
// just pass it on
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
D12_DecrementIoCount(DeviceObject);
}
}
break;
case DevicePowerState:
ntStatus = D12_SetDevicePowerState(DeviceObject,
irpStack->Parameters.Power.State.DeviceState,
&hookIt);
IoCopyCurrentIrpStackLocationToNext(Irp);
if (hookIt) {
D12_KdPrint(("D12TEST.SYS: Set PowerIrp Completion Routine\n"));
IoSetCompletionRoutine(Irp,
D12_PowerIrp_Complete,
// always pass FDO to completion routine
DeviceObject,
hookIt,
hookIt,
hookIt);
}
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
D12_DecrementIoCount(DeviceObject);
break;
} /* case irpStack->Parameters.Power.Type */
}
break; /* IRP_MN_SET_POWER */
case IRP_MN_QUERY_POWER:
D12_KdPrint(("D12TEST.SYS: IRP_MN_QUERY_POWER\n"));
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
D12_DecrementIoCount(DeviceObject);
break; /* IRP_MN_QUERY_POWER */
default:
D12_KdPrint(("D12TEST.SYS: UNKNOWN POWER MESSAGE (%x)\n", irpStack->MinorFunction));
//
// All unahndled PnP messages are passed on to the PDO
//
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// All PNP_POWER POWER messages get passed to
// TopOfStackDeviceObject and some are handled in the completion routine
//
// pass on to our PDO
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
D12_DecrementIoCount(DeviceObject);
} /* irpStack->MinorFunction */
return ntStatus;
}
NTSTATUS
D12_Dispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
--*/
{
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT stackDeviceObject;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
//
// Get a pointer to the device extension
//
deviceExtension = DeviceObject->DeviceExtension;
stackDeviceObject = deviceExtension->TopOfStackDeviceObject;
D12_IncrementIoCount(DeviceObject);
switch (irpStack->MajorFunction) {
case IRP_MJ_SYSTEM_CONTROL:
D12_KdPrint (("D12TEST.SYS: IRP_MJ_SYSTEM_CONTROL\n"));
IoCopyCurrentIrpStackLocationToNext(Irp);
D12_KdPrint (("D12TEST.SYS: Passing SysCtrl Irp down\n"));
D12_DecrementIoCount(DeviceObject);
ntStatus = IoCallDriver(stackDeviceObject,
Irp);
goto D12_Dispatch_Done;
break;
case IRP_MJ_PNP:
D12_KdPrint (("D12TEST.SYS: IRP_MJ_PNP\n"));
switch (irpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
{
KEVENT event;
D12_KdPrint (("D12TEST.SYS: IRP_MN_START_DEVICE\n"));
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
D12_DeferIrpCompletion,
&event,
TRUE,
TRUE,
TRUE);
ntStatus = IoCallDriver(stackDeviceObject,
Irp);
if (ntStatus == STATUS_PENDING) {
// wait for irp to complete
TRAP(); // first time we hit this
KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
}
ntStatus = D12_StartDevice(DeviceObject);
Irp->IoStatus.Status = ntStatus;
goto D12_Dispatch_CompleteRequest;
}
break;
case IRP_MN_STOP_DEVICE:
D12_KdPrint (("D12TEST.SYS: IRP_MN_STOP_DEVICE\n"));
ntStatus = D12_StopDevice(DeviceObject);
break;
case IRP_MN_REMOVE_DEVICE:
D12_KdPrint (("D12TEST.SYS: IRP_MN_REMOVE_DEVICE\n"));
// match the inc at the begining of the dispatch
// routine
D12_DecrementIoCount(DeviceObject);
//
// ounce this flag is set no irps will be pased
// down the stack to lower drivers
//
deviceExtension->AcceptingRequests = FALSE;
if (deviceExtension->UserEvent != NULL) {
KeSetEvent(deviceExtension->UserEvent,
1,
FALSE);
}
if (NT_SUCCESS(ntStatus)) {
LONG pendingIoCount;
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus = IoCallDriver(stackDeviceObject,
Irp);
//
// final decrement will trigger the remove
//
pendingIoCount = D12_DecrementIoCount(DeviceObject);
{
NTSTATUS status;
// wait for any io request pending in our driver to
// complete for finishing the remove
status = KeWaitForSingleObject(
&deviceExtension->RemoveEvent,
Suspended,
KernelMode,
FALSE,
NULL);
// TRAP();
}
//
// Delete the link and FDO we created
//
D12_RemoveDevice(DeviceObject);
D12_KdPrint (("D12TEST.SYS: Detaching from %08X\n",
deviceExtension->TopOfStackDeviceObject));
IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
D12_KdPrint (("D12TEST.SYS: Deleting %08X\n",
DeviceObject));
IoDeleteDevice (DeviceObject);
goto D12_Dispatch_Done;
}
break;
case IRP_MN_QUERY_STOP_DEVICE:
D12_KdPrint (("D12TEST.SYS: IRP_MN_QUERY_STOP_DEVICE\n"));
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
D12_KdPrint (("D12TEST.SYS: IRP_MN_QUERY_REMOVE_DEVICE\n"));
break;
case IRP_MN_CANCEL_STOP_DEVICE:
D12_KdPrint (("D12TEST.SYS: IRP_MN_CANCEL_STOP_DEVICE\n"));
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
D12_KdPrint (("D12TEST.SYS: IRP_MN_CANCEL_REMOVE_DEVICE\n"));
break;
default:
D12_KdPrint (("D12TEST.SYS: PnP IOCTL not handled\n"));
} /* case MinorFunction, MajorFunction == IRP_MJ_PNP_POWER */
if (!NT_SUCCESS(ntStatus)) {
Irp->IoStatus.Status = ntStatus;
goto D12_Dispatch_CompleteRequest;
}
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// All PNP_POWER messages get passed to the TopOfStackDeviceObject
// we were given in PnPAddDevice
//
D12_KdPrint (("D12TEST.SYS: Passing PnP Irp down, status = %x\n", ntStatus));
ntStatus = IoCallDriver(stackDeviceObject,
Irp);
D12_DecrementIoCount(DeviceObject);
goto D12_Dispatch_Done;
break; // IRP_MJ_PNP
default:
D12_KdPrint (("D12TEST.SYS: MAJOR IOCTL not handled\n"));
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
} /* case MajorFunction */
ntStatus = Irp->IoStatus.Status;
D12_Dispatch_CompleteRequest:
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
D12_DecrementIoCount(DeviceObject);
D12_Dispatch_Done:
D12_KdPrint (("D12TEST.SYS: Exit D12_Dispatch %x\n", ntStatus));
return ntStatus;
}
VOID
D12_Unload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Free all the allocated resources, etc.
Arguments:
DriverObject - pointer to a driver object
Return Value:
--*/
{
D12_KdPrint (("D12TEST.SYS: enter D12_Unload\n"));
//
// Free any global resources allocated
// in DriverEntry
//
D12_KdPrint (("D12TEST.SYS: exit D12_Unload\n"));
}
NTSTATUS
D12_StartDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Initializes a given instance of the device on the USB.
All we do here is get the device descriptor and store it
Arguments:
DeviceObject - pointer to the device object for this instance of a
82930
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus;
PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
PURB urb;
ULONG siz;
D12_KdPrint (("D12TEST.SYS: enter D12_StartDevice\n"));
deviceExtension = DeviceObject->DeviceExtension;
D12_ResetIrpQueue(DeviceObject);
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb) {
siz = sizeof(USB_DEVICE_DESCRIPTOR);
deviceDescriptor = ExAllocatePool(NonPagedPool,
siz);
if (deviceDescriptor) {
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE,
0,
0,
deviceDescriptor,
NULL,
siz,
NULL);
ntStatus = D12_CallUSBD(DeviceObject, urb);
if (NT_SUCCESS(ntStatus)) {
D12_KdPrint (("D12TEST.SYS: Device Descriptor = %x, len %x\n",
deviceDescriptor,
urb->UrbControlDescriptorRequest.TransferBufferLength));
D12_KdPrint (("D12TEST.SYS: D12 Device Descriptor:\n"));
D12_KdPrint (("D12TEST.SYS: -------------------------\n"));
D12_KdPrint (("D12TEST.SYS: bLength %d\n", deviceDescriptor->bLength));
D12_KdPrint (("D12TEST.SYS: bDescriptorType 0x%x\n", deviceDescriptor->bDescriptorType));
D12_KdPrint (("D12TEST.SYS: bcdUSB 0x%x\n", deviceDescriptor->bcdUSB));
D12_KdPrint (("D12TEST.SYS: bDeviceClass 0x%x\n", deviceDescriptor->bDeviceClass));
D12_KdPrint (("D12TEST.SYS: bDeviceSubClass 0x%x\n", deviceDescriptor->bDeviceSubClass));
D12_KdPrint (("D12TEST.SYS: bDeviceProtocol 0x%x\n", deviceDescriptor->bDeviceProtocol));
D12_KdPrint (("D12TEST.SYS: bMaxPacketSize0 0x%x\n", deviceDescriptor->bMaxPacketSize0));
D12_KdPrint (("D12TEST.SYS: idVendor 0x%x\n", deviceDescriptor->idVendor));
D12_KdPrint (("D12TEST.SYS: idProduct 0x%x\n", deviceDescriptor->idProduct));
D12_KdPrint (("D12TEST.SYS: bcdDevice 0x%x\n", deviceDescriptor->bcdDevice));
D12_KdPrint (("D12TEST.SYS: iManufacturer 0x%x\n", deviceDescriptor->iManufacturer));
D12_KdPrint (("D12TEST.SYS: iProduct 0x%x\n", deviceDescriptor->iProduct));
D12_KdPrint (("D12TEST.SYS: iSerialNumber 0x%x\n", deviceDescriptor->iSerialNumber));
D12_KdPrint (("D12TEST.SYS: bNumConfigurations 0x%x\n", deviceDescriptor->bNumConfigurations));
}
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(ntStatus)) {
deviceExtension->DeviceDescriptor = deviceDescriptor;
} else if (deviceDescriptor) {
ExFreePool(deviceDescriptor);
}
ExFreePool(urb);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS(ntStatus)) {
ntStatus = D12_ConfigureDevice(DeviceObject);
}
if (NT_SUCCESS(ntStatus)) {
ntStatus = D12_BuildPipeList(DeviceObject);
}
D12_KdPrint (("D12TEST.SYS: exit D12_StartDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
D12_RemoveDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Stops a given instance of a 82930 device on the USB.
Arguments:
DeviceObject - pointer to the device object for this instance of a 82930
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
UNICODE_STRING deviceLinkUnicodeString;
D12_KdPrint (("D12TEST.SYS: enter D12_RemoveDevice\n"));
deviceExtension = DeviceObject->DeviceExtension;
RtlInitUnicodeString (&deviceLinkUnicodeString,
deviceExtension->DeviceLinkNameBuffer);
// remove the GUID-based symbolic link
ntStatus = IoSetDeviceInterfaceState(&deviceLinkUnicodeString, FALSE);
//
// Free device descriptor structure
//
if (deviceExtension->DeviceDescriptor) {
ExFreePool(deviceExtension->DeviceDescriptor);
}
//
// Free up any interface structures
//
if (deviceExtension->Interface) {
ExFreePool(deviceExtension->Interface);
}
D12_KdPrint (("D12TEST.SYS: exit D12_RemoveDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
D12_StopDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Stops a given instance of a 82930 device on the USB, this is only
stuff we need to do if the device is still present.
Arguments:
DeviceObject - pointer to the device object for this instance of a 82930
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb;
ULONG siz;
D12_KdPrint (("D12TEST.SYS: enter D12_StopDevice\n"));
D12_CancelAllPendingIrps(DeviceObject);
//
// Send the select configuration urb with a NULL pointer for the configuration
// handle, this closes the configuration and puts the device in the 'unconfigured'
// state.
//
siz = sizeof(struct _URB_SELECT_CONFIGURATION);
urb = ExAllocatePool(NonPagedPool,
siz);
if (urb) {
NTSTATUS status;
UsbBuildSelectConfigurationRequest(urb,
(USHORT) siz,
NULL);
status = D12_CallUSBD(DeviceObject, urb);
D12_KdPrint (("D12TEST.SYS: Device Configuration Closed status = %x usb status = %x.\n",
status, urb->UrbHeader.Status));
ExFreePool(urb);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
D12_KdPrint (("D12TEST.SYS: exit D12_StopDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
D12_PnPAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
This routine is called to create a new instance of the device
Arguments:
DriverObject - pointer to the driver object for this instance of D12
PhysicalDeviceObject - pointer to a device object created by the bus
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION deviceExtension;
USBD_VERSION_INFORMATION versionInformation;
static ULONG instance = 0;
D12_KdPrint (("D12TEST.SYS: enter D12_PnPAddDevice\n"));
//
// create our funtional device object (FDO)
//
ntStatus =
BulkUsb_CreateDeviceObject(DriverObject, PhysicalDeviceObject, &deviceObject);
if (NT_SUCCESS(ntStatus)) {
deviceExtension = deviceObject->DeviceExtension;
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//
// we support direct io for read/write
//
deviceObject->Flags |= DO_DIRECT_IO;
//** initialize our device extension
//
// remember the Physical device Object
//
deviceExtension->PhysicalDeviceObject=PhysicalDeviceObject;
//
// Attach to the PDO
//
deviceExtension->TopOfStackDeviceObject =
IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
D12_QueryCapabilities(PhysicalDeviceObject,
&deviceExtension->DeviceCapabilities);
//
// display the device caps
//
#if DBG
{
ULONG i;
D12_KdPrint(("D12TEST.SYS: >>>>>> DeviceCaps\n"));
D12_KdPrint(("D12TEST.SYS: SystemWake = (%d)\n",
deviceExtension->DeviceCapabilities.SystemWake));
D12_KdPrint(("D12TEST.SYS: DeviceWake = (D%d)\n",
deviceExtension->DeviceCapabilities.DeviceWake-1));
for (i=PowerSystemUnspecified; i< PowerSystemMaximum; i++) {
D12_KdPrint(("D12TEST.SYS: Device State Map: sysstate %d = devstate 0x%x\n", i,
deviceExtension->DeviceCapabilities.DeviceState[i]));
}
D12_KdPrint(("D12TEST.SYS: '<<<<<<<DeviceExtension);
RtlCopyMemory(deviceExtension->DeviceLinkNameBuffer,
deviceLinkUnicodeString.Buffer,
deviceLinkUnicodeString.Length);
deviceExtension->DeviceDescriptor = NULL;
deviceExtension->Interface = NULL;
deviceExtension->ConfigurationHandle = NULL;
deviceExtension->AcceptingRequests = TRUE;
deviceExtension->PendingIoCount = 0;
deviceExtension->UserEvent = NULL;
KeInitializeEvent(&deviceExtension->RemoveEvent, NotificationEvent, FALSE);
for (i=0; iPipeList[i].PipeInfo = NULL;
}
RtlFreeUnicodeString( &deviceLinkUnicodeString );
}
return ntStatus;
}
NTSTATUS
D12_CallUSBD(
IN PDEVICE_OBJECT DeviceObject,
IN PURB Urb
)
/*++
Routine Description:
Passes a URB to the USBD class driver
Arguments:
DeviceObject - pointer to the device object for this instance of an 82930
Urb - pointer to 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;
D12_KdPrint (("D12TEST.SYS: enter D12_CallUSBD\n"));
deviceExtension = DeviceObject->DeviceExtension;
//
// issue a synchronous request
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
deviceExtension->TopOfStackDeviceObject,
NULL,
0,
NULL,
0,
TRUE, /* INTERNAL */
&event,
&ioStatus);
//
// Call the class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
//
// pass the URB to the USB driver stack
//
nextStack->Parameters.Others.Argument1 = Urb;
D12_KdPrint (("D12TEST.SYS: calling USBD\n"));
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
irp);
D12_KdPrint (("D12TEST.SYS: return from IoCallDriver USBD %x\n", ntStatus));
if (ntStatus == STATUS_PENDING) {
D12_KdPrint (("D12TEST.SYS: Wait for single object\n"));
status = KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
D12_KdPrint (("D12TEST.SYS: Wait for single object, returned %x\n", status));
} else {
ioStatus.Status = ntStatus;
}
D12_KdPrint (("D12TEST.SYS: 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;
D12_KdPrint (("D12TEST.SYS: exit D12_CallUSBD (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
D12_ConfigureDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Initializes a given instance of the device on the USB and selects the
configuration.
Arguments:
DeviceObject - pointer to the device object for this instance of the 82930
devcice.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus;
PURB urb;
ULONG siz;
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
D12_KdPrint (("D12TEST.SYS: enter D12_ConfigureDevice\n"));
deviceExtension = DeviceObject->DeviceExtension;
//
// first configure the device
//
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb) {
// BUGBUG 82930 chokes if on the next command if you don't get
// the entire descriptor on the first try
siz = sizeof(USB_CONFIGURATION_DESCRIPTOR)+256;
get_config_descriptor_retry:
configurationDescriptor = ExAllocatePool(NonPagedPool,
siz);
if (configurationDescriptor) {
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
configurationDescriptor,
NULL,
siz,
NULL);
ntStatus = D12_CallUSBD(DeviceObject, urb);
D12_KdPrint (("D12TEST.SYS: Configuration Descriptor = %x, len %x\n",
configurationDescriptor,
urb->UrbControlDescriptorRequest.TransferBufferLength));
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
//
// 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 &&
configurationDescriptor->wTotalLength > siz) {
siz = configurationDescriptor->wTotalLength;
ExFreePool(configurationDescriptor);
configurationDescriptor = NULL;
goto get_config_descriptor_retry;
}
ExFreePool(urb);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
if (configurationDescriptor) {
//
// 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 = D12_SelectInterface(DeviceObject,
configurationDescriptor, NULL);
ExFreePool(configurationDescriptor);
}
D12_KdPrint (("D12TEST.SYS: exit D12_ConfigureDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
D12_SelectInterface(
IN PDEVICE_OBJECT DeviceObject,
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
PUSBD_INTERFACE_INFORMATION Interface
)
/*++
Routine Description:
Initializes an 82930 with multiple interfaces
Arguments:
DeviceObject - pointer to the device object for this instance of the 82930
devcice.
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;
UCHAR alternateSetting, interfaceNumber;
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = NULL;
USHORT siz;
D12_KdPrint (("D12TEST.SYS: enter D12_SelectInterface\n"));
deviceExtension = DeviceObject->DeviceExtension;
if (Interface == NULL) {
//
// D12 driver only supports one interface, we must search
// the configuration descriptor for the interface we want
// and remember the pipes.
//
urb = USBD_CreateConfigurationRequest(ConfigurationDescriptor, &siz);
if (urb) {
//
// search thru all the interfaces
// and find any we are interested in
//
interfaceNumber = 0;
alternateSetting = 0;
// alternateSetting = 3;
interfaceDescriptor =
USBD_ParseConfigurationDescriptor(ConfigurationDescriptor,
interfaceNumber,
alternateSetting);
Interface = &urb->UrbSelectConfiguration.Interface;
for (i=0; i< Interface->NumberOfPipes; i++) {
//
// perform any pipe initialization here
//
Interface->Pipes[i].MaximumTransferSize = 64*1024-1;
}
UsbBuildSelectConfigurationRequest(urb,
(USHORT) siz,
ConfigurationDescriptor);
// Interface->AlternateSetting = 3;
ntStatus = D12_CallUSBD(DeviceObject, urb);
deviceExtension->ConfigurationHandle =
urb->UrbSelectConfiguration.ConfigurationHandle;
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
} else {
//
// we were give an interface already set up
//
// do a selectinterface here if we want to change any of the
// pipe parameters.
//
TRAP();
}
ASSERT(Interface != NULL);
if (NT_SUCCESS(ntStatus)) {
//
// Save the configuration handle for this device
//
deviceExtension->ConfigurationHandle =
urb->UrbSelectConfiguration.ConfigurationHandle;
deviceExtension->Interface = ExAllocatePool(NonPagedPool,
Interface->Length);
if (deviceExtension->Interface) {
ULONG j;
//
// save a copy of the interface information returned
//
RtlCopyMemory(deviceExtension->Interface, Interface, Interface->Length);
//
// Dump the interface to the debugger
//
D12_KdPrint (("D12TEST.SYS: ---------\n"));
D12_KdPrint (("D12TEST.SYS: NumberOfPipes 0x%x\n", deviceExtension->Interface->NumberOfPipes));
D12_KdPrint (("D12TEST.SYS: Length 0x%x\n", deviceExtension->Interface->Length));
D12_KdPrint (("D12TEST.SYS: Alt Setting 0x%x\n", deviceExtension->Interface->AlternateSetting));
D12_KdPrint (("D12TEST.SYS: Interface Number 0x%x\n", deviceExtension->Interface->InterfaceNumber));
D12_KdPrint (("D12TEST.SYS: Class, subclass, protocol 0x%x 0x%x 0x%x\n",
deviceExtension->Interface->Class,
deviceExtension->Interface->SubClass,
deviceExtension->Interface->Protocol));
// Dump the pipe info
for (j=0; jNumberOfPipes; j++) {
PUSBD_PIPE_INFORMATION pipeInformation;
pipeInformation = &deviceExtension->Interface->Pipes[j];
D12_KdPrint (("D12TEST.SYS: ---------\n"));
D12_KdPrint (("D12TEST.SYS: PipeType 0x%x\n", pipeInformation->PipeType));
D12_KdPrint (("D12TEST.SYS: EndpointAddress 0x%x\n", pipeInformation->EndpointAddress));
D12_KdPrint (("D12TEST.SYS: MaxPacketSize 0x%x\n", pipeInformation->MaximumPacketSize));
D12_KdPrint (("D12TEST.SYS: Interval 0x%x\n", pipeInformation->Interval));
D12_KdPrint (("D12TEST.SYS: Handle 0x%x\n", pipeInformation->PipeHandle));
D12_KdPrint (("D12TEST.SYS: MaximumTransferSize 0x%x\n", pipeInformation->MaximumTransferSize));
}
D12_KdPrint (("D12TEST.SYS: ---------\n"));
}
}
if (urb) {
ExFreePool(urb);
urb = NULL;
}
// Retrieve the selected Configuration and Interface setting from the
// device. (The only purpose of doing this here is to exercise the
// URB_FUNCTION_GET_CONFIGURATION and URB_FUNCTION_GET_INTERFACE
// requests).
//
if (NT_SUCCESS(ntStatus)) {
urb = ExAllocatePool(
NonPagedPool,
sizeof(struct _URB_CONTROL_GET_CONFIGURATION_REQUEST) + 1);
if (urb)
{
PUCHAR configuration;
configuration = (PUCHAR)urb + sizeof(struct _URB_CONTROL_GET_CONFIGURATION_REQUEST);
*configuration = 0xFF;
urb->UrbHeader.Function = URB_FUNCTION_GET_CONFIGURATION;
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_GET_CONFIGURATION_REQUEST);
urb->UrbControlGetConfigurationRequest.TransferBufferLength = 1;
urb->UrbControlGetConfigurationRequest.TransferBuffer = configuration;
urb->UrbControlGetConfigurationRequest.TransferBufferMDL = NULL;
urb->UrbControlGetConfigurationRequest.UrbLink = NULL;
ntStatus = D12_CallUSBD(DeviceObject, urb);
D12_KdPrint (("D12TEST.SYS: Configuration %d (%x)\n",
*configuration, ntStatus));
ExFreePool(urb);
urb = NULL;
}
urb = ExAllocatePool(
NonPagedPool,
sizeof(struct _URB_CONTROL_GET_INTERFACE_REQUEST) + 1);
if (urb)
{
PUCHAR interface;
interface = (PUCHAR)urb + sizeof(struct _URB_CONTROL_GET_INTERFACE_REQUEST);
*interface = 0xFF;
urb->UrbHeader.Function = URB_FUNCTION_GET_INTERFACE;
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_GET_INTERFACE_REQUEST);
urb->UrbControlGetInterfaceRequest.TransferBufferLength = 1;
urb->UrbControlGetInterfaceRequest.TransferBuffer = interface;
urb->UrbControlGetInterfaceRequest.TransferBufferMDL = NULL;
urb->UrbControlGetInterfaceRequest.UrbLink = NULL;
urb->UrbControlGetInterfaceRequest.Interface =
deviceExtension->Interface->InterfaceNumber;
ntStatus = D12_CallUSBD(DeviceObject, urb);
D12_KdPrint (("D12TEST.SYS: Interface %d (%x)\n",
*interface, ntStatus));
ExFreePool(urb);
urb = NULL;
}
}
D12_KdPrint (("D12TEST.SYS: exit D12_SelectInterface (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
D12_BuildPipeList(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Arguments:
DeviceObject - pointer to the device object for this instance of the 82930
devcice.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
ULONG i;
WCHAR Name[] = L"\\PIPE00";
PUSBD_INTERFACE_INFORMATION interface;
deviceExtension = DeviceObject->DeviceExtension;
interface = deviceExtension->Interface;
D12_KdPrint (("D12TEST.SYS: enter D12_BuildPipeList\n"));
deviceExtension = DeviceObject->DeviceExtension;
for (i=0; iPipeList[i].Name,
Name,
sizeof(Name));
}
//
// build a list of pipe names based on the interface
//
for (i=0; iNumberOfPipes; i++) {
Name[6] = '0' + (USHORT) i;
RtlCopyMemory(deviceExtension->PipeList[i].Name,
Name,
sizeof(Name));
deviceExtension->PipeList[i].PipeInfo =
&interface->Pipes[i];
deviceExtension->PipeList[i].Opened = FALSE;
}
return STATUS_SUCCESS;
}
NTSTATUS
D12_ResetPipe(
IN PDEVICE_OBJECT DeviceObject,
IN PD12_PIPE Pipe,
IN BOOLEAN IsoClearStall
)
/*++
Routine Description:
Reset a given USB pipe.
NOTES:
This will reset the host to Data0 and should also reset the device
to Data0 for Bulk and Interrupt pipes.
For Iso pipes this will set the virgin state of pipe so that ASAP
transfers begin with the current bus frame instead of the next frame
after the last transfer occurred.
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus;
PURB urb;
D12_KdPrint (("D12TEST.SYS: Reset Pipe %x\n", Pipe));
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_PIPE_REQUEST));
if (urb) {
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
urb->UrbPipeRequest.PipeHandle =
Pipe->PipeInfo->PipeHandle;
ntStatus = D12_CallUSBD(DeviceObject, urb);
ExFreePool(urb);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
//
// Memphis RESET_PIPE will send a Clear-Feature Endpoint Stall to
// reset the data toggle of non-Iso pipes as part of a RESET_PIPE
// request. It does not do this for Iso pipes as Iso pipes do not use
// the data toggle (all Iso packets are Data0). However, we also use
// the Clear-Feature Endpoint Stall request in our device firmware to
// reset data buffer points inside the device so we explicitly send
// this request to the device for Iso pipes if desired.
//
if (NT_SUCCESS(ntStatus) && IsoClearStall &&
(Pipe->PipeInfo->PipeType == UsbdPipeTypeIsochronous)) {
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_FEATURE_REQUEST));
if (urb) {
UsbBuildFeatureRequest(urb,
URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT,
USB_FEATURE_ENDPOINT_STALL,
Pipe->PipeInfo->EndpointAddress,
NULL);
ntStatus = D12_CallUSBD(DeviceObject, urb);
ExFreePool(urb);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
return ntStatus;
}
LONG
D12_DecrementIoCount(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION deviceExtension;
LONG ioCount;
deviceExtension = DeviceObject->DeviceExtension;
ioCount = InterlockedDecrement(&deviceExtension->PendingIoCount);
D12_KdPrint (("D12TEST.SYS: Pending io count = %x\n", ioCount));
if (ioCount==0) {
KeSetEvent(&deviceExtension->RemoveEvent,
1,
FALSE);
}
return ioCount;
}
VOID
D12_IncrementIoCount(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION deviceExtension;
deviceExtension = DeviceObject->DeviceExtension;
InterlockedIncrement(&deviceExtension->PendingIoCount);
}
NTSTATUS
D12_ReconfigureDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Initializes a given instance of the device on the USB and selects the
configuration.
Arguments:
DeviceObject - pointer to the device object for this instance of the 82930
devcice.
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
PUSBD_INTERFACE_INFORMATION interface;
ULONG i;
D12_KdPrint (("D12TEST.SYS: enter D12_ReconfigureDevice\n"));
deviceExtension = DeviceObject->DeviceExtension;
if (NT_SUCCESS(ntStatus)) {
ntStatus = D12_ConfigureDevice(DeviceObject);
}
//
// new interface structure is now set up
//
interface = deviceExtension->Interface;
//
// set up the pipe handles again
//
for (i=0; iNumberOfPipes; i++) {
D12_KdPrint (("D12TEST.SYS: pipe list = %x\n", &deviceExtension->PipeList[i]));
deviceExtension->PipeList[i].PipeInfo =
&interface->Pipes[i];
//deviceExtension->PipeList[i].Opened = FALSE;
}
return ntStatus;
}