[usb/usbehci]

- Define Device and Configuration Descriptors for RootHub20.
- Queue all USB_SUBMIT_URBs and create a separate thread to handle them.
- For PNP START_DEVICE, Create the internal RootHub usb device and register usb hub device interface.
- Fill in direct call interface for USB_BUS_INTERFACE_USBDI_V2 and USB_BUS_INTERFACE_HUB_V5.
- Implement Direct Call Interface function GetExtendedHubInformation.
- Remove duplicate structures that are already defined in USB Headers. Some reorganization.

svn path=/trunk/; revision=45552
This commit is contained in:
Michael Martin 2010-02-10 12:21:23 +00:00
parent 909e0c1b43
commit b028cb1e4e
5 changed files with 757 additions and 163 deletions

View file

@ -7,15 +7,108 @@
* Michael Martin
*/
/* INCLUDES *******************************************************************/
#define INITGUID
#define NDEBUG
#include "usbehci.h"
#include <wdmguid.h>
#include "usbiffn.h"
#include <stdio.h>
#define NDEBUG
#include <debug.h>
/* Lifted from Linux with slight changes */
const UCHAR ROOTHUB2_DEVICE_DESCRIPTOR [] =
{
0x12, /* bLength; */
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType; Device */
0x00, 0x20, /* bcdUSB; v1.1 */
USB_DEVICE_CLASS_HUB, /* bDeviceClass; HUB_CLASSCODE */
0x01, /* bDeviceSubClass; */
0x00, /* bDeviceProtocol; [ low/full speeds only ] */
0x08, /* bMaxPacketSize0; 8 Bytes */
/* Fill Vendor and Product in when init root hub */
0x00, 0x00, /* idVendor; */
0x00, 0x00, /* idProduct; */
0x00, 0x00, /* bcdDevice */
0x00, /* iManufacturer; */
0x00, /* iProduct; */
0x00, /* iSerialNumber; */
0x01 /* bNumConfigurations; */
};
const UCHAR ROOTHUB2_CONFIGURATION_DESCRIPTOR [] =
{
/* one configuration */
0x09, /* bLength; */
0x02, /* bDescriptorType; Configuration */
0x19, 0x00, /* wTotalLength; */
0x01, /* bNumInterfaces; (1) */
0x23, /* bConfigurationValue; */
0x00, /* iConfiguration; */
0x40, /* bmAttributes;
Bit 7: must be set,
6: Self-powered,
5: Remote wakeup,
4..0: reserved */
0x00, /* MaxPower; */
/* one interface */
0x09, /* bLength: Interface; */
0x04, /* bDescriptorType; Interface */
0x00, /* bInterfaceNumber; */
0x00, /* bAlternateSetting; */
0x01, /* bNumEndpoints; */
0x09, /* bInterfaceClass; HUB_CLASSCODE */
0x01, /* bInterfaceSubClass; */
0x00, /* bInterfaceProtocol: */
0x00, /* iInterface; */
/* one endpoint (status change endpoint) */
0x07, /* bLength; */
0x05, /* bDescriptorType; Endpoint */
0x81, /* bEndpointAddress; IN Endpoint 1 */
0x03, /* bmAttributes; Interrupt */
0x08, 0x00, /* wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
0xFF /* bInterval; (255ms -- usb 2.0 spec) */
};
/* FIXME: Do something better */
VOID NTAPI
UrbWorkerThread(PVOID Context)
{
PPDO_DEVICE_EXTENSION PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Context;
while (PdoDeviceExtension->HaltUrbHandling == FALSE)
{
CompletePendingURBRequest(PdoDeviceExtension);
}
DPRINT1("Thread terminated\n");
}
/* FIXME: Do something better */
PVOID InternalCreateUsbDevice(UCHAR DeviceNumber, ULONG Port, PUSB_DEVICE Parent, BOOLEAN Hub)
{
PUSB_DEVICE UsbDevicePointer = NULL;
UsbDevicePointer = ExAllocatePool(NonPagedPool, sizeof(USB_DEVICE));
if (!UsbDevicePointer)
{
DPRINT1("Out of memory\n");
return NULL;
}
if ((Hub) && (!Parent))
{
DPRINT1("This is the root hub\n");
}
UsbDevicePointer->Address = DeviceNumber;
UsbDevicePointer->Port = Port;
UsbDevicePointer->ParentDevice = Parent;
return UsbDevicePointer;
}
NTSTATUS NTAPI
PdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
@ -24,125 +117,94 @@ PdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
PIO_STACK_LOCATION Stack = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
ULONG_PTR Information = 0;
DPRINT("PdoDispatchInternalDeviceControl\n");
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION) PdoDeviceExtension->ControllerFdo->DeviceExtension;
ASSERT(PdoDeviceExtension->Common.IsFdo == FALSE);
Stack = IoGetCurrentIrpStackLocation(Irp);
DPRINT("IoControlCode %x\n", Stack->Parameters.DeviceIoControl.IoControlCode);
switch(Stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_INTERNAL_USB_SUBMIT_URB:
{
URB *Urb;
DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB\n");
DPRINT("Stack->Parameters.DeviceIoControl.InputBufferLength %d\n",
Stack->Parameters.DeviceIoControl.InputBufferLength);
DPRINT("Stack->Parameters.Others.Argument1 %x\n", Stack->Parameters.Others.Argument1);
Urb = (PURB) Stack->Parameters.Others.Argument1;
DPRINT("Header Size %d\n", Urb->UrbHeader.Length);
DPRINT("Header Type %d\n", Urb->UrbHeader.Function);
DPRINT("Index %x\n", Urb->UrbControlDescriptorRequest.Index);
DPRINT("Header Length %d\n", Urb->UrbHeader.Length);
DPRINT("Header Function %d\n", Urb->UrbHeader.Function);
/* Check the type */
switch(Urb->UrbHeader.Function)
{
case URB_FUNCTION_SELECT_CONFIGURATION:
{
DPRINT1("URB_FUNCTION_SELECT_CONFIGURATION\n");
break;
}
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
{
URB *Urb;
DPRINT1("URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n");
Urb = (PURB) Stack->Parameters.Others.Argument1;
Urb->UrbHeader.Status = 0;
DPRINT1("Irp->CancelRoutine %x\n",Irp->CancelRoutine);
QueueRequest(FdoDeviceExtension, Irp);
Information = 0;
IoMarkIrpPending(Irp);
Status = STATUS_PENDING;
break;
}
/* FIXME: Handle all other Functions */
default:
DPRINT1("Not handled yet!\n");
}
/* Queue all request for now, kernel thread will complete them */
QueueURBRequest(PdoDeviceExtension, Irp);
Information = 0;
IoMarkIrpPending(Irp);
Status = STATUS_PENDING;
break;
}
case IOCTL_INTERNAL_USB_CYCLE_PORT:
{
DPRINT("IOCTL_INTERNAL_USB_CYCLE_PORT\n");
DPRINT1("IOCTL_INTERNAL_USB_CYCLE_PORT\n");
break;
}
case IOCTL_INTERNAL_USB_ENABLE_PORT:
{
DPRINT("IOCTL_INTERNAL_USB_ENABLE_PORT\n");
DPRINT1("IOCTL_INTERNAL_USB_ENABLE_PORT\n");
break;
}
case IOCTL_INTERNAL_USB_GET_BUS_INFO:
{
DPRINT("IOCTL_INTERNAL_USB_GET_BUS_INFO\n");
DPRINT1("IOCTL_INTERNAL_USB_GET_BUS_INFO\n");
break;
}
case IOCTL_INTERNAL_USB_GET_BUSGUID_INFO:
{
DPRINT("IOCTL_INTERNAL_USB_GET_BUSGUID_INFO\n");
DPRINT1("IOCTL_INTERNAL_USB_GET_BUSGUID_INFO\n");
break;
}
case IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME:
{
DPRINT("IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME\n");
DPRINT1("IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME\n");
break;
}
case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE:
{
DPRINT("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n");
DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n");
break;
}
case IOCTL_INTERNAL_USB_GET_HUB_COUNT:
{
DPRINT("IOCTL_INTERNAL_USB_GET_HUB_COUNT\n");
DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_COUNT\n");
break;
}
case IOCTL_INTERNAL_USB_GET_HUB_NAME:
{
DPRINT("IOCTL_INTERNAL_USB_GET_HUB_NAME\n");
DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_NAME\n");
break;
}
case IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO:
{
DPRINT("IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO\n");
DPRINT1("IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO\n");
break;
}
case IOCTL_INTERNAL_USB_GET_PORT_STATUS:
{
DPRINT("IOCTL_INTERNAL_USB_GET_PORT_STATUS\n");
DPRINT1("IOCTL_INTERNAL_USB_GET_PORT_STATUS\n");
break;
}
case IOCTL_INTERNAL_USB_RESET_PORT:
{
DPRINT("IOCTL_INTERNAL_USB_RESET_PORT\n");
DPRINT1("IOCTL_INTERNAL_USB_RESET_PORT\n");
break;
}
case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO:
{
DPRINT("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO\n");
/* This is document as Argument1 = PDO and Argument2 = FDO.
Its actually reversed, the FDO goes in Argument1 and PDO goes in Argument2 */
DPRINT1("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO\n");
if (Stack->Parameters.Others.Argument1)
Stack->Parameters.Others.Argument1 = FdoDeviceExtension->DeviceObject;
*(PVOID *)Stack->Parameters.Others.Argument1 = FdoDeviceExtension->Pdo;
if (Stack->Parameters.Others.Argument2)
Stack->Parameters.Others.Argument2 = FdoDeviceExtension->Pdo;
*(PVOID *)Stack->Parameters.Others.Argument2 = IoGetAttachedDevice(FdoDeviceExtension->DeviceObject);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
@ -151,7 +213,7 @@ PdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
}
case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
{
DPRINT("IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION\n");
DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION\n");
break;
}
default:
@ -162,6 +224,7 @@ PdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
}
Irp->IoStatus.Information = Information;
if (Status != STATUS_PENDING)
IoCompleteRequest(Irp, IO_NO_INCREMENT);
@ -171,8 +234,6 @@ PdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
NTSTATUS
PdoQueryId(PDEVICE_OBJECT DeviceObject, PIRP Irp, ULONG_PTR* Information)
{
PPDO_DEVICE_EXTENSION PdoDeviceExtension;
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
WCHAR Buffer[256];
ULONG Index = 0;
ULONG IdType;
@ -181,25 +242,18 @@ PdoQueryId(PDEVICE_OBJECT DeviceObject, PIRP Irp, ULONG_PTR* Information)
NTSTATUS Status;
IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)PdoDeviceExtension->ControllerFdo->DeviceExtension;
/* FIXME: Read values from registry */
switch (IdType)
{
case BusQueryDeviceID:
{
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
RtlInitUnicodeString(&SourceString, L"USB\\ROOT_HUB20");
break;
}
case BusQueryHardwareIDs:
{
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20&VID8086&PID265C&REV0000") + 1;
Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20&VID8086&PID265") + 1;
Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20&VID8086&PID265C") + 1;
Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20") + 1;
Buffer[Index] = UNICODE_NULL;
@ -209,24 +263,12 @@ PdoQueryId(PDEVICE_OBJECT DeviceObject, PIRP Irp, ULONG_PTR* Information)
}
case BusQueryCompatibleIDs:
{
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
/* We have none */
/* We have none */
return STATUS_SUCCESS;
break;
}
case BusQueryInstanceID:
{
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
/*
Do we need to implement this?
At one point I hade DeviceCapabilities->UniqueID set to TRUE.
And caused usbhub to fail attaching
to the PDO. Setting UniqueID to FALSE, it works
*/
return STATUS_SUCCESS;
break;
}
default:
{
@ -247,18 +289,15 @@ PdoQueryId(PDEVICE_OBJECT DeviceObject, PIRP Irp, ULONG_PTR* Information)
NTSTATUS
PdoQueryDeviceRelations(PDEVICE_OBJECT DeviceObject, PDEVICE_RELATIONS* pDeviceRelations)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
PDEVICE_RELATIONS DeviceRelations;
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
if (!DeviceRelations)
return STATUS_INSUFFICIENT_RESOURCES;
ObReferenceObject(DeviceObject);
DeviceRelations->Count = 1;
DeviceRelations->Objects[0] = DeviceObject;
ObReferenceObject(DeviceObject);
*pDeviceRelations = DeviceRelations;
return STATUS_SUCCESS;
@ -271,8 +310,8 @@ PdoDispatchPnp(
{
ULONG MinorFunction;
PIO_STACK_LOCATION Stack;
ULONG_PTR Information = 0;
NTSTATUS Status;
ULONG_PTR Information = Irp->IoStatus.Information;
NTSTATUS Status = Irp->IoStatus.Status;
Stack = IoGetCurrentIrpStackLocation(Irp);
MinorFunction = Stack->MinorFunction;
@ -284,17 +323,70 @@ PdoDispatchPnp(
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_STOP_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_QUERY_DEVICE_TEXT:
case IRP_MN_SURPRISE_REMOVAL:
case IRP_MN_QUERY_RESOURCES:
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
{
Information = Irp->IoStatus.Information;
Status = STATUS_SUCCESS;
break;
}
case IRP_MN_START_DEVICE:
{
DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
PUSB_DEVICE RootHubDevice;
PPDO_DEVICE_EXTENSION PdoDeviceExtension;
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
UNICODE_STRING InterfaceSymLinkName;
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)PdoDeviceExtension->ControllerFdo->DeviceExtension;
/* Create the root hub */
RootHubDevice = InternalCreateUsbDevice(0, 0, NULL, TRUE);
RootHubDevice->Address = 1;
RootHubDevice->Port = 0;
RtlCopyMemory(&RootHubDevice->DeviceDescriptor,
ROOTHUB2_DEVICE_DESCRIPTOR,
sizeof(ROOTHUB2_DEVICE_DESCRIPTOR));
RootHubDevice->DeviceDescriptor.idVendor = FdoDeviceExtension->VendorId;
RootHubDevice->DeviceDescriptor.idProduct = FdoDeviceExtension->DeviceId;
RtlCopyMemory(&RootHubDevice->ConfigurationDescriptor,
ROOTHUB2_CONFIGURATION_DESCRIPTOR,
sizeof(ROOTHUB2_CONFIGURATION_DESCRIPTOR));
PdoDeviceExtension->UsbDevices[0] = RootHubDevice;
/* Create a thread to handle the URB's */
Status = PsCreateSystemThread(&PdoDeviceExtension->ThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
NULL,
UrbWorkerThread,
(PVOID)PdoDeviceExtension);
if (!NT_SUCCESS(Status))
DPRINT1("Failed Thread Creation with Status: %x\n", Status);
Status = IoRegisterDeviceInterface(DeviceObject, &GUID_DEVINTERFACE_USB_HUB, NULL, &InterfaceSymLinkName);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to register interface\n");
}
else
{
Status = IoSetDeviceInterfaceState(&InterfaceSymLinkName, TRUE);
DPRINT1("Set interface state %x\n", Status);
}
Status = STATUS_SUCCESS;
break;
}
@ -305,16 +397,17 @@ PdoDispatchPnp(
case TargetDeviceRelation:
{
PDEVICE_RELATIONS DeviceRelations = NULL;
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
Status = PdoQueryDeviceRelations(DeviceObject, &DeviceRelations);
Information = (ULONG_PTR)DeviceRelations;
break;
}
case BusRelations:
case RemovalRelations:
case EjectionRelations:
default:
{
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unhandled type 0x%lx\n",
Stack->Parameters.QueryDeviceRelations.Type);
//ASSERT(FALSE);
Status = STATUS_NOT_SUPPORTED;
break;
}
@ -325,17 +418,20 @@ PdoDispatchPnp(
{
PDEVICE_CAPABILITIES DeviceCapabilities;
ULONG i;
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
DeviceCapabilities = (PDEVICE_CAPABILITIES)Stack->Parameters.DeviceCapabilities.Capabilities;
/* FIXME: capabilities can change with connected device */
DeviceCapabilities->LockSupported = FALSE;
DeviceCapabilities->EjectSupported = FALSE;
DeviceCapabilities->Removable = FALSE;
DeviceCapabilities->DockDevice = FALSE;
DeviceCapabilities->UniqueID = FALSE;//TRUE;
DeviceCapabilities->UniqueID = FALSE;
DeviceCapabilities->SilentInstall = FALSE;
DeviceCapabilities->RawDeviceOK = TRUE;
DeviceCapabilities->RawDeviceOK = FALSE;
DeviceCapabilities->SurpriseRemovalOK = FALSE;
DeviceCapabilities->Address = 0;
DeviceCapabilities->UINumber = 0;
DeviceCapabilities->DeviceD2 = 1;
/* FIXME */
DeviceCapabilities->HardwareDisabled = FALSE;
@ -343,47 +439,101 @@ PdoDispatchPnp(
DeviceCapabilities->DeviceState[0] = PowerDeviceD0;
for (i = 0; i < PowerSystemMaximum; i++)
DeviceCapabilities->DeviceState[i] = PowerDeviceD3;
//DeviceCapabilities->DeviceWake = PowerDeviceUndefined;
DeviceCapabilities->DeviceWake = 0;
DeviceCapabilities->D1Latency = 0;
DeviceCapabilities->D2Latency = 0;
DeviceCapabilities->D3Latency = 0;
Information = 0;
Status = STATUS_SUCCESS;
break;
}
case IRP_MN_QUERY_RESOURCES:
{
Information = Irp->IoStatus.Information;
Status = Irp->IoStatus.Status;
break;
}
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
{
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
Information = Irp->IoStatus.Information;
Status = Irp->IoStatus.Status;
break;
}
/*case IRP_MN_QUERY_DEVICE_TEXT:
{
Status = STATUS_NOT_SUPPORTED;
break;
}*/
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
{
DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
Information = Irp->IoStatus.Information;
Status = Irp->IoStatus.Status;
break;
}
case IRP_MN_QUERY_ID:
{
Status = PdoQueryId(DeviceObject, Irp, &Information);
break;
}
case IRP_MN_QUERY_INTERFACE:
{
UNICODE_STRING GuidString;
PUSB_BUS_INTERFACE_HUB_V5 InterfaceHub;
PUSB_BUS_INTERFACE_USBDI_V2 InterfaceDI;
PPDO_DEVICE_EXTENSION PdoDeviceExtension;
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)PdoDeviceExtension->ControllerFdo->DeviceExtension;
Status = RtlStringFromGUID(Stack->Parameters.QueryInterface.InterfaceType, &GuidString);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create string from GUID!\n");
}
DPRINT1("Interface GUID requested %wZ\n", &GuidString);
DPRINT1("QueryInterface.Size %x\n", Stack->Parameters.QueryInterface.Size);
DPRINT1("QueryInterface.Version %x\n", Stack->Parameters.QueryInterface.Version);
Status = STATUS_SUCCESS;
Information = 0;
/* FIXME: Check the actual Guid */
if (Stack->Parameters.QueryInterface.Size == sizeof(USB_BUS_INTERFACE_USBDI_V2) && (Stack->Parameters.QueryInterface.Version == 2))
{
InterfaceDI = (PUSB_BUS_INTERFACE_USBDI_V2) Stack->Parameters.QueryInterface.Interface;
InterfaceDI->Size = sizeof(USB_BUS_INTERFACE_USBDI_V2);
InterfaceDI->Version = 2;
InterfaceDI->BusContext = PdoDeviceExtension->DeviceObject;
InterfaceDI->InterfaceReference = (PINTERFACE_REFERENCE)InterfaceReference;
InterfaceDI->InterfaceDereference = (PINTERFACE_DEREFERENCE)InterfaceDereference;
InterfaceDI->GetUSBDIVersion = GetUSBDIVersion;
InterfaceDI->QueryBusTime = QueryBusTime;
InterfaceDI->SubmitIsoOutUrb = SubmitIsoOutUrb;
InterfaceDI->QueryBusInformation = QueryBusInformation;
InterfaceDI->IsDeviceHighSpeed = IsDeviceHighSpeed;
InterfaceDI->EnumLogEntry = EnumLogEntry;
}
/* FIXME: Check the actual Guid */
else if (Stack->Parameters.QueryInterface.Size == sizeof(USB_BUS_INTERFACE_HUB_V5) &&
(Stack->Parameters.QueryInterface.Version == 5))
{
InterfaceHub = (PUSB_BUS_INTERFACE_HUB_V5)Stack->Parameters.QueryInterface.Interface;
InterfaceHub->Version = 5;
InterfaceHub->Size = sizeof(USB_BUS_INTERFACE_HUB_V5);
InterfaceHub->BusContext = PdoDeviceExtension->DeviceObject;
InterfaceHub->InterfaceReference = (PINTERFACE_REFERENCE)InterfaceReference;
InterfaceHub->InterfaceDereference = (PINTERFACE_DEREFERENCE)InterfaceDereference;
InterfaceHub->CreateUsbDevice = CreateUsbDevice;
InterfaceHub->InitializeUsbDevice = InitializeUsbDevice;
InterfaceHub->GetUsbDescriptors = GetUsbDescriptors;
InterfaceHub->RemoveUsbDevice = RemoveUsbDevice;
InterfaceHub->RestoreUsbDevice = RestoreUsbDevice;
InterfaceHub->GetPortHackFlags = GetPortHackFlags;
InterfaceHub->QueryDeviceInformation = QueryDeviceInformation;
InterfaceHub->GetControllerInformation = GetControllerInformation;
InterfaceHub->ControllerSelectiveSuspend = ControllerSelectiveSuspend;
InterfaceHub->GetExtendedHubInformation = GetExtendedHubInformation;
InterfaceHub->GetRootHubSymbolicName = GetRootHubSymbolicName;
InterfaceHub->GetDeviceBusContext = GetDeviceBusContext;
InterfaceHub->Initialize20Hub = Initialize20Hub;
InterfaceHub->RootHubInitNotification = RootHubInitNotification;
InterfaceHub->FlushTransfers = FlushTransfers;
InterfaceHub->SetDeviceHandleData = SetDeviceHandleData;
}
else
{
DPRINT1("Not Supported\n");
Status = STATUS_NOT_SUPPORTED;
}
break;
}
case IRP_MN_QUERY_BUS_INFORMATION:
{
PPNP_BUS_INFORMATION BusInfo;
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
if (!BusInfo)
@ -407,9 +557,6 @@ PdoDispatchPnp(
{
/* We are the PDO. So ignore */
DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", MinorFunction);
Information = Irp->IoStatus.Information;
Status = Irp->IoStatus.Status;
break;
}
}

View file

@ -176,24 +176,6 @@ typedef struct _EHCI_SETUP_FORMAT
USHORT wLength;
} EHCI_SETUP_FORMAT, *PEHCI_SETUP_FORMAT;
typedef struct _STANDARD_DEVICE_DESC
{
UCHAR bLength;
UCHAR bDescriptorType;
USHORT bcdUSB;
UCHAR bDeviceClass;
UCHAR bDeviceSubClass;
UCHAR bDeviceProtocal;
UCHAR bMaxPacketSize;
USHORT idVendor;
USHORT idProduct;
USHORT bcdDevice;
UCHAR iManufacturer;
UCHAR iProduct;
UCHAR iSerialNumber;
UCHAR bNumConfigurations;
} STANDARD_DEVICE_DESC, *PSTANDARD_DEVICE_DESC;
typedef struct _STRING_DESCRIPTOR
{
UCHAR bLength; /* Size of this descriptor in bytes */
@ -201,6 +183,17 @@ typedef struct _STRING_DESCRIPTOR
UCHAR bString[0]; /* UNICODE encoded string */
} STRING_DESCRIPTOR, *PSTRING_DESCRIPTOR;
typedef struct _USB_DEVICE
{
UCHAR Address;
ULONG Port;
PVOID ParentDevice;
USB_DEVICE_DESCRIPTOR DeviceDescriptor;
USB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
USB_ENDPOINT_DESCRIPTOR EndPointDescriptor;
} USB_DEVICE, *PUSB_DEVICE;
/* USBCMD register 32 bits */
typedef struct _EHCI_USBCMD_CONTENT
{
@ -292,7 +285,6 @@ typedef struct _EHCI_CAPS {
UCHAR PortRoute [8];
} EHCI_CAPS, *PEHCI_CAPS;
typedef struct _COMMON_DEVICE_EXTENSION
{
BOOLEAN IsFdo;
@ -309,9 +301,7 @@ typedef struct _FDO_DEVICE_EXTENSION
PDEVICE_OBJECT Pdo;
ULONG DeviceState;
/* USB Specs says a max of 127 devices */
ULONG ChildDeviceCount;
PVOID RootHubDeviceHandle;
PDMA_ADAPTER pDmaAdapter;
ULONG Vector;
@ -323,10 +313,6 @@ typedef struct _FDO_DEVICE_EXTENSION
KDPC DpcObject;
KAFFINITY Affinity;
LIST_ENTRY IrpQueue;
KSPIN_LOCK IrpQueueLock;
PIRP CurrentIrp;
ULONG MapRegisters;
ULONG BusNumber;
@ -354,7 +340,6 @@ typedef struct _FDO_DEVICE_EXTENSION
PULONG ResourceBase;
ULONG Size;
} FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;
typedef struct _PDO_DEVICE_EXTENSION
@ -362,16 +347,26 @@ typedef struct _PDO_DEVICE_EXTENSION
COMMON_DEVICE_EXTENSION Common;
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT ControllerFdo;
PUSB_DEVICE UsbDevices[127];
LIST_ENTRY IrpQueue;
KSPIN_LOCK IrpQueueLock;
PIRP CurrentIrp;
HANDLE ThreadHandle;
ULONG ChildDeviceCount;
BOOLEAN HaltUrbHandling;
} PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
typedef struct _WORKITEM_DATA
{
PIO_WORKITEM IoWorkItem;
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
PDEVICE_OBJECT PortDeviceObject;
} WORKITEM_DATA, *PWORKITEM_DATA;
VOID NTAPI
UrbWorkerThread(PVOID Context);
NTSTATUS NTAPI
GetBusInterface(PDEVICE_OBJECT pcifido, PBUS_INTERFACE_STANDARD busInterface);
@ -406,27 +401,18 @@ NTSTATUS NTAPI
PdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp);
BOOLEAN
GetDeviceDescriptor (PFDO_DEVICE_EXTENSION DeviceExtension, UCHAR Index);
GetDeviceDescriptor(PFDO_DEVICE_EXTENSION DeviceExtension, UCHAR Index, PUSB_DEVICE_DESCRIPTOR OutBuffer, BOOLEAN Hub);
BOOLEAN
GetDeviceStringDescriptor(PFDO_DEVICE_EXTENSION DeviceExtension, UCHAR Index);
VOID
CompletePendingRequest(PFDO_DEVICE_EXTENSION DeviceExtension);
QueueURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension, PIRP Irp);
VOID
QueueRequest(PFDO_DEVICE_EXTENSION DeviceExtension, PIRP Irp);
CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension);
VOID
QueueRequest(PFDO_DEVICE_EXTENSION DeviceExtension, PIRP Irp);
VOID
CompletePendingRequest(PFDO_DEVICE_EXTENSION DeviceExtension);
VOID
DeviceArrivalWorkItem(PDEVICE_OBJECT DeviceObject, PVOID Context);
VOID
RequestCancel (PDEVICE_OBJECT DeviceObject, PIRP Irp);
URBRequestCancel (PDEVICE_OBJECT DeviceObject, PIRP Irp);
#endif

View file

@ -9,5 +9,6 @@
<file>common.c</file>
<file>misc.c</file>
<file>irp.c</file>
<file>usbiffn.c</file>
<file>urbreq.c</file>
</module>

View file

@ -0,0 +1,260 @@
/*
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbehci/usbiffn.c
* PURPOSE: Direct Call Interface Functions.
* PROGRAMMERS:
* Michael Martin
*/
/* usbbusif.h and hubbusif.h need to be imported */
#include "usbehci.h"
#include "usbiffn.h"
#define NDEBUG
#include <debug.h>
VOID
USB_BUSIFFN
InterfaceReference(PVOID BusContext)
{
DPRINT1("InterfaceReference called\n");
}
VOID
USB_BUSIFFN
InterfaceDereference(PVOID BusContext)
{
DPRINT1("InterfaceDereference called\n");
}
/* Bus Interface Hub V5 Functions */
NTSTATUS
USB_BUSIFFN
CreateUsbDevice(PVOID BusContext,
PUSB_DEVICE_HANDLE *NewDevice,
PUSB_DEVICE_HANDLE HubDeviceHandle,
USHORT PortStatus, USHORT PortNumber)
{
DPRINT1("CreateUsbDevice called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
InitializeUsbDevice(PVOID BusContext, PUSB_DEVICE_HANDLE DeviceHandle)
{
DPRINT1("InitializeUsbDevice called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
GetUsbDescriptors(PVOID BusContext,
PUSB_DEVICE_HANDLE DeviceHandle,
PUCHAR DeviceDescriptorBuffer,
PULONG DeviceDescriptorBufferLength,
PUCHAR ConfigurationBuffer,
PULONG ConfigDescriptorBufferLength)
{
DPRINT1("GetUsbDescriptor called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
RemoveUsbDevice(PVOID BusContext, PUSB_DEVICE_HANDLE DeviceHandle, ULONG Flags)
{
DPRINT1("RemoveUsbDevice called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
RestoreUsbDevice(PVOID BusContext, PUSB_DEVICE_HANDLE OldDeviceHandle, PUSB_DEVICE_HANDLE NewDeviceHandle)
{
DPRINT1("RestoreUsbDevice called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
GetPortHackFlags(PVOID BusContext, PULONG Flags)
{
DPRINT1("GetPortHackFlags called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
QueryDeviceInformation(PVOID BusContext,
PUSB_DEVICE_HANDLE DeviceHandle,
PVOID DeviceInformationBuffer,
ULONG DeviceInformationBufferLength,
PULONG LengthReturned)
{
DPRINT1("QueryDeviceInformation called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
GetControllerInformation(PVOID BusContext,
PVOID ControllerInformationBuffer,
ULONG ControllerInformationBufferLength,
PULONG LengthReturned)
{
DPRINT1("GetControllerInformation called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
ControllerSelectiveSuspend(PVOID BusContext, BOOLEAN Enable)
{
DPRINT1("ControllerSelectiveSuspend called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
GetExtendedHubInformation(PVOID BusContext,
PDEVICE_OBJECT HubPhysicalDeviceObject,
PVOID HubInformationBuffer,
ULONG HubInformationBufferLength,
PULONG LengthReturned)
{
PUSB_EXTHUB_INFORMATION_0 UsbExtHubInfo = HubInformationBuffer;
PPDO_DEVICE_EXTENSION PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)BusContext)->DeviceExtension;
PFDO_DEVICE_EXTENSION FdoDeviceExntension = (PFDO_DEVICE_EXTENSION)PdoDeviceExtension->ControllerFdo->DeviceExtension;
LONG i;
/* Set the default return value */
*LengthReturned = 0;
/* Caller must have set InformationLevel to 0 */
if (UsbExtHubInfo->InformationLevel != 0)
{
return STATUS_NOT_SUPPORTED;
}
UsbExtHubInfo->NumberOfPorts = 8;
for (i=0; i < UsbExtHubInfo->NumberOfPorts; i++)
{
UsbExtHubInfo->Port[i].PhysicalPortNumber = i + 1;
UsbExtHubInfo->Port[i].PortLabelNumber = FdoDeviceExntension->ECHICaps.HCSParams.PortCount;
UsbExtHubInfo->Port[i].VidOverride = 0;
UsbExtHubInfo->Port[i].PidOverride = 0;
UsbExtHubInfo->Port[i].PortAttributes = USB_PORTATTR_SHARED_USB2;
}
*LengthReturned = FIELD_OFFSET(USB_EXTHUB_INFORMATION_0, Port[8]);
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
GetRootHubSymbolicName(PVOID BusContext,
PVOID HubSymNameBuffer,
ULONG HubSymNameBufferLength,
PULONG HubSymNameActualLength)
{
DPRINT1("GetRootHubSymbolicName called\n");
return STATUS_SUCCESS;
}
PVOID
USB_BUSIFFN
GetDeviceBusContext(PVOID HubBusContext, PVOID DeviceHandle)
{
DPRINT1("GetDeviceBusContext called\n");
return NULL;
}
NTSTATUS
USB_BUSIFFN
Initialize20Hub(PVOID BusContext, PUSB_DEVICE_HANDLE HubDeviceHandle, ULONG TtCount)
{
DPRINT1("Initialize20Hub called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
RootHubInitNotification(PVOID BusContext, PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine)
{
DPRINT1("RootHubInitNotification\n");
return STATUS_SUCCESS;
}
VOID
USB_BUSIFFN
FlushTransfers(PVOID BusContext, PVOID DeviceHandle)
{
DPRINT1("FlushTransfers\n");
}
VOID
USB_BUSIFFN
SetDeviceHandleData(PVOID BusContext, PVOID DeviceHandle, PDEVICE_OBJECT UsbDevicePdo)
{
DPRINT1("SetDeviceHandleData called\n");
}
/* USB_BUS_INTERFACE_USBDI_V2 Functions */
NTSTATUS
USB_BUSIFFN
GetUSBDIVersion(PVOID BusContext, PUSBD_VERSION_INFORMATION VersionInformation, PULONG HcdCapabilites)
{
DPRINT1("GetUSBDIVersion called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
QueryBusTime(PVOID BusContext, PULONG CurrentFrame)
{
DPRINT1("QueryBusTime called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
SubmitIsoOutUrb(PVOID BusContext, PURB Urb)
{
DPRINT1("SubmitIsoOutUrb called\n");
return STATUS_SUCCESS;
}
NTSTATUS
USB_BUSIFFN
QueryBusInformation(PVOID BusContext,
ULONG Level,
PVOID BusInformationBuffer,
PULONG BusInformationBufferLength,
PULONG BusInformationActualLength)
{
DPRINT1("QueryBusInformation called\n");
return STATUS_SUCCESS;
}
BOOLEAN
USB_BUSIFFN
IsDeviceHighSpeed(PVOID BusCOntext)
{
DPRINT1("IsDeviceHighSpeed called\n");
return TRUE;
}
NTSTATUS
USB_BUSIFFN
EnumLogEntry(PVOID BusContext, ULONG DriverTag, ULONG EnumTag, ULONG P1, ULONG P2)
{
DPRINT1("EnumLogEntry called\n");
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,200 @@
#ifndef __USBIFFN_H__
#define __USBIFFN_H__
#define USB_BUSIFFN __stdcall
#include <ntifs.h>
#include <ntddk.h>
#include <usb.h>
/* usbbusif.h and hubbusif.h need to be imported */
typedef PVOID PUSB_DEVICE_HANDLE;
typedef
VOID
USB_BUSIFFN
RH_INIT_CALLBACK (PVOID CallBackContext);
typedef RH_INIT_CALLBACK *PRH_INIT_CALLBACK;
typedef struct _USB_EXTPORT_INFORMATION_0
{
ULONG PhysicalPortNumber;
ULONG PortLabelNumber;
USHORT VidOverride;
USHORT PidOverride;
ULONG PortAttributes;
} USB_EXTPORT_INFORMATION_0, *PUSB_EXTPORT_INFORMATION;
typedef struct _USB_EXTHUB_INFORMATION_0
{
ULONG InformationLevel;
ULONG NumberOfPorts;
USB_EXTPORT_INFORMATION_0 Port[255];
} USB_EXTHUB_INFORMATION_0, *PUSB_EXTHUB_INFORMATION_0;
typedef struct _USB_BUS_INTERFACE_USBDI_V2
{
USHORT Size;
USHORT Version;
PVOID BusContext;
PINTERFACE_REFERENCE InterfaceReference;
PINTERFACE_DEREFERENCE InterfaceDereference;
PVOID GetUSBDIVersion;
PVOID QueryBusTime;
PVOID SubmitIsoOutUrb;
PVOID QueryBusInformation;
PVOID IsDeviceHighSpeed;
PVOID EnumLogEntry;
} USB_BUS_INTERFACE_USBDI_V2, *PUSB_BUS_INTERFACE_USBDI_V2;
typedef struct _USB_BUS_INTERFACE_HUB_V5
{
USHORT Size;
USHORT Version;
PVOID BusContext;
PINTERFACE_REFERENCE InterfaceReference;
PINTERFACE_DEREFERENCE InterfaceDereference;
PVOID CreateUsbDevice;
PVOID InitializeUsbDevice;
PVOID GetUsbDescriptors;
PVOID RemoveUsbDevice;
PVOID RestoreUsbDevice;
PVOID GetPortHackFlags;
PVOID QueryDeviceInformation;
PVOID GetControllerInformation;
PVOID ControllerSelectiveSuspend;
PVOID GetExtendedHubInformation;
PVOID GetRootHubSymbolicName;
PVOID GetDeviceBusContext;
PVOID Initialize20Hub;
PVOID RootHubInitNotification;
PVOID FlushTransfers;
PVOID SetDeviceHandleData;
} USB_BUS_INTERFACE_HUB_V5, *PUSB_BUS_INTERFACE_HUB_V5;
VOID
USB_BUSIFFN
InterfaceReference(PVOID BusContext);
VOID
USB_BUSIFFN
InterfaceDereference(PVOID BusContext);
NTSTATUS
USB_BUSIFFN
CreateUsbDevice(PVOID BusContext,
PUSB_DEVICE_HANDLE *NewDevice,
PUSB_DEVICE_HANDLE HubDeviceHandle,
USHORT PortStatus, USHORT PortNumber);
NTSTATUS
USB_BUSIFFN
InitializeUsbDevice(PVOID BusContext, PUSB_DEVICE_HANDLE DeviceHandle);
NTSTATUS
USB_BUSIFFN
GetUsbDescriptors(PVOID BusContext,
PUSB_DEVICE_HANDLE DeviceHandle,
PUCHAR DeviceDescriptorBuffer,
PULONG DeviceDescriptorBufferLength,
PUCHAR ConfigurationBuffer,
PULONG ConfigDescriptorBufferLength);
NTSTATUS
USB_BUSIFFN
RemoveUsbDevice(PVOID BusContext, PUSB_DEVICE_HANDLE DeviceHandle, ULONG Flags);
NTSTATUS
USB_BUSIFFN
RestoreUsbDevice(PVOID BusContext, PUSB_DEVICE_HANDLE OldDeviceHandle, PUSB_DEVICE_HANDLE NewDeviceHandle);
NTSTATUS
USB_BUSIFFN
GetPortHackFlags(PVOID BusContext, PULONG Flags);
NTSTATUS
USB_BUSIFFN
QueryDeviceInformation(PVOID BusContext,
PUSB_DEVICE_HANDLE DeviceHandle,
PVOID DeviceInformationBuffer,
ULONG DeviceInformationBufferLength,
PULONG LengthReturned);
NTSTATUS
USB_BUSIFFN
GetControllerInformation(PVOID BusContext,
PVOID ControllerInformationBuffer,
ULONG ControllerInformationBufferLength,
PULONG LengthReturned);
NTSTATUS
USB_BUSIFFN
ControllerSelectiveSuspend(PVOID BusContext, BOOLEAN Enable);
NTSTATUS
USB_BUSIFFN
GetExtendedHubInformation(PVOID BusContext,
PDEVICE_OBJECT HubPhysicalDeviceObject,
PVOID HubInformationBuffer,
ULONG HubInformationBufferLength,
PULONG LengthReturned);
NTSTATUS
USB_BUSIFFN
GetRootHubSymbolicName(PVOID BusContext,
PVOID HubSymNameBuffer,
ULONG HubSymNameBufferLength,
PULONG HubSymNameActualLength);
PVOID
USB_BUSIFFN
GetDeviceBusContext(PVOID HubBusContext, PVOID DeviceHandle);
NTSTATUS
USB_BUSIFFN
Initialize20Hub(PVOID BusContext, PUSB_DEVICE_HANDLE HubDeviceHandle, ULONG TtCount);
NTSTATUS
USB_BUSIFFN
RootHubInitNotification(PVOID BusContext, PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine);
VOID
USB_BUSIFFN
FlushTransfers(PVOID BusContext, PVOID DeviceHandle);
VOID
USB_BUSIFFN
SetDeviceHandleData(PVOID BusContext, PVOID DeviceHandle, PDEVICE_OBJECT UsbDevicePdo);
NTSTATUS
USB_BUSIFFN
GetUSBDIVersion(PVOID BusContext, PUSBD_VERSION_INFORMATION VersionInformation, PULONG HcdCapabilites);
NTSTATUS
USB_BUSIFFN
QueryBusTime(PVOID BusContext, PULONG CurrentFrame);
NTSTATUS
USB_BUSIFFN
SubmitIsoOutUrb(PVOID BusContext, PURB Urb);
NTSTATUS
USB_BUSIFFN
QueryBusInformation(PVOID BusContext,
ULONG Level,
PVOID BusInformationBuffer,
PULONG BusInformationBufferLength,
PULONG BusInformationActualLength);
BOOLEAN
USB_BUSIFFN
IsDeviceHighSpeed(PVOID BusCOntext);
NTSTATUS
USB_BUSIFFN
EnumLogEntry(PVOID BusContext, ULONG DriverTag, ULONG EnumTag, ULONG P1, ULONG P2);
#endif