mirror of
https://github.com/reactos/reactos.git
synced 2024-08-23 19:58:25 +00:00
![Cameron Gutman](/assets/img/avatar_default.png)
- Handle invalid device handles gracefully instead of crashing svn path=/branches/usb-bringup-trunk/; revision=55154
3530 lines
96 KiB
C++
3530 lines
96 KiB
C++
/*
|
|
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: drivers/usb/usbehci/hub_controller.cpp
|
|
* PURPOSE: USB EHCI device driver.
|
|
* PROGRAMMERS:
|
|
* Michael Martin (michael.martin@reactos.org)
|
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
|
*/
|
|
|
|
#define INITGUID
|
|
#include "usbehci.h"
|
|
|
|
VOID StatusChangeEndpointCallBack(
|
|
PVOID Context);
|
|
|
|
class CHubController : public IHubController,
|
|
public IDispatchIrp
|
|
{
|
|
public:
|
|
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
|
|
|
|
STDMETHODIMP_(ULONG) AddRef()
|
|
{
|
|
InterlockedIncrement(&m_Ref);
|
|
return m_Ref;
|
|
}
|
|
STDMETHODIMP_(ULONG) Release()
|
|
{
|
|
InterlockedDecrement(&m_Ref);
|
|
|
|
if (!m_Ref)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return m_Ref;
|
|
}
|
|
|
|
// IHubController interface functions
|
|
virtual NTSTATUS Initialize(IN PDRIVER_OBJECT DriverObject, IN PHCDCONTROLLER Controller, IN PUSBHARDWAREDEVICE Device, IN BOOLEAN IsRootHubDevice, IN ULONG DeviceAddress);
|
|
virtual NTSTATUS GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject);
|
|
virtual NTSTATUS GetHubControllerSymbolicLink(ULONG BufferLength, PVOID Buffer, PULONG RequiredLength);
|
|
|
|
// IDispatchIrp interface functions
|
|
virtual NTSTATUS HandlePnp(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
|
|
virtual NTSTATUS HandlePower(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
|
|
virtual NTSTATUS HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
|
|
|
|
// local functions
|
|
NTSTATUS HandleQueryInterface(PIO_STACK_LOCATION IoStack);
|
|
NTSTATUS SetDeviceInterface(BOOLEAN bEnable);
|
|
NTSTATUS CreatePDO(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * OutDeviceObject);
|
|
PUSBHARDWAREDEVICE GetUsbHardware();
|
|
ULONG AcquireDeviceAddress();
|
|
VOID ReleaseDeviceAddress(ULONG DeviceAddress);
|
|
BOOLEAN ValidateUsbDevice(PUSBDEVICE UsbDevice);
|
|
NTSTATUS AddUsbDevice(PUSBDEVICE UsbDevice);
|
|
NTSTATUS RemoveUsbDevice(PUSBDEVICE UsbDevice);
|
|
VOID SetNotification(PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine);
|
|
// internal ioctl routines
|
|
NTSTATUS HandleGetDescriptor(IN OUT PIRP Irp, PURB Urb);
|
|
NTSTATUS HandleGetDescriptorFromInterface(IN OUT PIRP Irp, PURB Urb);
|
|
NTSTATUS HandleClassDevice(IN OUT PIRP Irp, PURB Urb);
|
|
NTSTATUS HandleGetStatusFromDevice(IN OUT PIRP Irp, PURB Urb);
|
|
NTSTATUS HandleSelectConfiguration(IN OUT PIRP Irp, PURB Urb);
|
|
NTSTATUS HandleSelectInterface(IN OUT PIRP Irp, PURB Urb);
|
|
NTSTATUS HandleClassOther(IN OUT PIRP Irp, PURB Urb);
|
|
NTSTATUS HandleClassInterface(IN OUT PIRP Irp, PURB Urb);
|
|
NTSTATUS HandleClassEndpoint(IN OUT PIRP Irp, PURB Urb);
|
|
NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb);
|
|
NTSTATUS HandleIsochronousTransfer(IN OUT PIRP Irp, PURB Urb);
|
|
|
|
friend VOID StatusChangeEndpointCallBack(PVOID Context);
|
|
|
|
// constructor / destructor
|
|
CHubController(IUnknown *OuterUnknown){}
|
|
virtual ~CHubController(){}
|
|
|
|
protected:
|
|
LONG m_Ref;
|
|
PHCDCONTROLLER m_Controller;
|
|
PUSBHARDWAREDEVICE m_Hardware;
|
|
BOOLEAN m_IsRootHubDevice;
|
|
ULONG m_DeviceAddress;
|
|
|
|
BOOLEAN m_InterfaceEnabled;
|
|
UNICODE_STRING m_HubDeviceInterfaceString;
|
|
|
|
PDEVICE_OBJECT m_HubControllerDeviceObject;
|
|
PDRIVER_OBJECT m_DriverObject;
|
|
|
|
PVOID m_HubCallbackContext;
|
|
PRH_INIT_CALLBACK m_HubCallbackRoutine;
|
|
|
|
USB_DEVICE_DESCRIPTOR m_DeviceDescriptor;
|
|
|
|
KSPIN_LOCK m_Lock;
|
|
RTL_BITMAP m_DeviceAddressBitmap;
|
|
PULONG m_DeviceAddressBitmapBuffer;
|
|
LIST_ENTRY m_UsbDeviceList;
|
|
PIRP m_PendingSCEIrp;
|
|
|
|
//Internal Functions
|
|
BOOLEAN QueryStatusChageEndpoint(PIRP Irp);
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
LIST_ENTRY Entry;
|
|
PUSBDEVICE Device;
|
|
}USBDEVICE_ENTRY, *PUSBDEVICE_ENTRY;
|
|
|
|
/* 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 USB_CONFIGURATION_DESCRIPTOR ROOTHUB2_CONFIGURATION_DESCRIPTOR =
|
|
{
|
|
sizeof(USB_CONFIGURATION_DESCRIPTOR),
|
|
USB_CONFIGURATION_DESCRIPTOR_TYPE,
|
|
sizeof(USB_CONFIGURATION_DESCRIPTOR) + sizeof(USB_INTERFACE_DESCRIPTOR) + sizeof(USB_ENDPOINT_DESCRIPTOR),
|
|
1,
|
|
1,
|
|
0,
|
|
0x40, /* self powered */
|
|
0x0
|
|
};
|
|
|
|
const USB_INTERFACE_DESCRIPTOR ROOTHUB2_INTERFACE_DESCRIPTOR =
|
|
{
|
|
sizeof(USB_INTERFACE_DESCRIPTOR), /* bLength */
|
|
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType; Interface */
|
|
0, /* bInterfaceNumber; */
|
|
0, /* bAlternateSetting; */
|
|
0x1, /* bNumEndpoints; */
|
|
0x09, /* bInterfaceClass; HUB_CLASSCODE */
|
|
0x01, /* bInterfaceSubClass; */
|
|
0x00, /* bInterfaceProtocol: */
|
|
0x00, /* iInterface; */
|
|
};
|
|
|
|
const USB_ENDPOINT_DESCRIPTOR ROOTHUB2_ENDPOINT_DESCRIPTOR =
|
|
{
|
|
sizeof(USB_ENDPOINT_DESCRIPTOR), /* bLength */
|
|
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
0x81, /* bEndPointAddress */
|
|
USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */
|
|
0x01, /* wMaxPacketSize */
|
|
0xC /* bInterval */
|
|
};
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
STDMETHODCALLTYPE
|
|
CHubController::QueryInterface(
|
|
IN REFIID refiid,
|
|
OUT PVOID* Output)
|
|
{
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::Initialize(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PHCDCONTROLLER Controller,
|
|
IN PUSBHARDWAREDEVICE Device,
|
|
IN BOOLEAN IsRootHubDevice,
|
|
IN ULONG DeviceAddress)
|
|
{
|
|
NTSTATUS Status;
|
|
PCOMMON_DEVICE_EXTENSION DeviceExtension;
|
|
USHORT VendorID, DeviceID;
|
|
ULONG Dummy1;
|
|
|
|
DPRINT1("CHubController::Initialize\n");
|
|
|
|
//
|
|
// initialize members
|
|
//
|
|
m_Controller = Controller;
|
|
m_Hardware = Device;
|
|
m_IsRootHubDevice = IsRootHubDevice;
|
|
m_DeviceAddress = DeviceAddress;
|
|
m_DriverObject = DriverObject;
|
|
KeInitializeSpinLock(&m_Lock);
|
|
InitializeListHead(&m_UsbDeviceList);
|
|
|
|
//
|
|
// allocate device address bitmap buffer
|
|
//
|
|
m_DeviceAddressBitmapBuffer = (PULONG)ExAllocatePoolWithTag(NonPagedPool, 16, TAG_USBEHCI);
|
|
if (!m_DeviceAddressBitmapBuffer)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// initialize device address bitmap
|
|
//
|
|
RtlInitializeBitMap(&m_DeviceAddressBitmap, m_DeviceAddressBitmapBuffer, 128);
|
|
RtlClearAllBits(&m_DeviceAddressBitmap);
|
|
|
|
|
|
//
|
|
// create PDO
|
|
//
|
|
Status = CreatePDO(m_DriverObject, &m_HubControllerDeviceObject);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// failed to create hub device object
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)m_HubControllerDeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// initialize device extension
|
|
//
|
|
DeviceExtension->IsFDO = FALSE;
|
|
DeviceExtension->IsHub = TRUE; //FIXME
|
|
DeviceExtension->Dispatcher = PDISPATCHIRP(this);
|
|
|
|
//
|
|
// intialize device descriptor
|
|
//
|
|
C_ASSERT(sizeof(USB_DEVICE_DESCRIPTOR) == sizeof(ROOTHUB2_DEVICE_DESCRIPTOR));
|
|
RtlMoveMemory(&m_DeviceDescriptor, ROOTHUB2_DEVICE_DESCRIPTOR, sizeof(USB_DEVICE_DESCRIPTOR));
|
|
|
|
if (NT_SUCCESS(m_Hardware->GetDeviceDetails(&VendorID, &DeviceID, &Dummy1, &Dummy1)))
|
|
{
|
|
//
|
|
// update device descriptor
|
|
//
|
|
m_DeviceDescriptor.idVendor = VendorID;
|
|
m_DeviceDescriptor.idProduct = DeviceID;
|
|
m_DeviceDescriptor.bcdUSB = 0x200; //FIXME
|
|
}
|
|
|
|
//
|
|
// Set the SCE Callback that the Hardware Device will call on port status change
|
|
//
|
|
Device->SetStatusChangeEndpointCallBack((PVOID)StatusChangeEndpointCallBack, this);
|
|
|
|
//
|
|
// clear init flag
|
|
//
|
|
m_HubControllerDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Queries the ports to see if there has been a device connected or removed.
|
|
//
|
|
BOOLEAN
|
|
CHubController::QueryStatusChageEndpoint(
|
|
PIRP Irp)
|
|
{
|
|
ULONG PortCount, PortId;
|
|
PIO_STACK_LOCATION IoStack;
|
|
USHORT PortStatus, PortChange;
|
|
PURB Urb;
|
|
PUCHAR TransferBuffer;
|
|
UCHAR Changed = FALSE;
|
|
|
|
//
|
|
// get current stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
ASSERT(IoStack);
|
|
|
|
//
|
|
// Get the Urb
|
|
//
|
|
Urb = (PURB)IoStack->Parameters.Others.Argument1;
|
|
ASSERT(Urb);
|
|
|
|
//
|
|
// Get the number of ports and check each one for device connected
|
|
//
|
|
m_Hardware->GetDeviceDetails(NULL, NULL, &PortCount, NULL);
|
|
DPRINT1("SCE Request %p TransferBufferLength %lu Flags %x MDL %p\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength, Urb->UrbBulkOrInterruptTransfer.TransferFlags, Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL);
|
|
|
|
TransferBuffer = (PUCHAR)Urb->UrbBulkOrInterruptTransfer.TransferBuffer;
|
|
|
|
//
|
|
// Loop the ports
|
|
//
|
|
for (PortId = 0; PortId < PortCount; PortId++)
|
|
{
|
|
m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange);
|
|
|
|
DPRINT1("Port %d: Status %x, Change %x\n", PortId, PortStatus, PortChange);
|
|
|
|
|
|
//
|
|
// If theres a flag in PortChange return TRUE so the SCE Irp will be completed
|
|
//
|
|
if (PortChange != 0)
|
|
{
|
|
DPRINT1("Change state on port %d\n", PortId);
|
|
// Set the value for the port number
|
|
*TransferBuffer = 1 << ((PortId + 1) & 7);
|
|
Changed = TRUE;
|
|
}
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject)
|
|
{
|
|
//
|
|
// store controller object
|
|
//
|
|
*HubDeviceObject = m_HubControllerDeviceObject;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::GetHubControllerSymbolicLink(
|
|
ULONG BufferLength,
|
|
PVOID Buffer,
|
|
PULONG RequiredLength)
|
|
{
|
|
if (!m_InterfaceEnabled)
|
|
{
|
|
//
|
|
// device interface not yet enabled
|
|
//
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (BufferLength < (ULONG)m_HubDeviceInterfaceString.Length - 8)
|
|
{
|
|
//
|
|
// buffer too small
|
|
// length is without '\??\'
|
|
//
|
|
*RequiredLength = m_HubDeviceInterfaceString.Length- 8;
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
//
|
|
// copy symbolic link
|
|
//
|
|
RtlCopyMemory(Buffer, &m_HubDeviceInterfaceString.Buffer[4], m_HubDeviceInterfaceString.Length - 8);
|
|
|
|
//
|
|
// store length, length is without '\??\'
|
|
//
|
|
*RequiredLength = m_HubDeviceInterfaceString.Length - 8;
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandlePnp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PCOMMON_DEVICE_EXTENSION DeviceExtension;
|
|
PDEVICE_CAPABILITIES DeviceCapabilities;
|
|
PPNP_BUS_INFORMATION BusInformation;
|
|
PDEVICE_RELATIONS DeviceRelations;
|
|
NTSTATUS Status;
|
|
ULONG Index = 0, Length;
|
|
USHORT VendorID, DeviceID;
|
|
ULONG HiSpeed, NumPorts;
|
|
WCHAR Buffer[300];
|
|
LPWSTR DeviceName;
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
ASSERT(DeviceExtension->IsFDO == FALSE);
|
|
|
|
//
|
|
// get current stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
switch(IoStack->MinorFunction)
|
|
{
|
|
case IRP_MN_START_DEVICE:
|
|
{
|
|
DPRINT1("CHubController::HandlePnp IRP_MN_START_DEVICE\n");
|
|
//
|
|
// register device interface
|
|
//
|
|
Status = SetDeviceInterface(TRUE);
|
|
break;
|
|
}
|
|
case IRP_MN_QUERY_ID:
|
|
{
|
|
DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_ID Type %x\n", IoStack->Parameters.QueryId.IdType);
|
|
|
|
if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
|
|
{
|
|
if (m_Hardware)
|
|
{
|
|
//
|
|
// query device id
|
|
//
|
|
Status = m_Hardware->GetDeviceDetails(&VendorID, &DeviceID, &NumPorts, &HiSpeed);
|
|
|
|
if (HiSpeed == 0x200)
|
|
{
|
|
//
|
|
// USB 2.0 hub
|
|
//
|
|
swprintf(Buffer, L"USB\\ROOT_HUB20");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// USB 1.1 hub
|
|
//
|
|
swprintf(Buffer, L"USB\\ROOT_HUB");
|
|
}
|
|
|
|
DPRINT1("Name %S\n", Buffer);
|
|
|
|
//
|
|
// calculate length
|
|
//
|
|
Length = (wcslen(Buffer) + 1);
|
|
|
|
//
|
|
// allocate buffer
|
|
//
|
|
DeviceName = (LPWSTR)ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), TAG_USBEHCI);
|
|
|
|
if (!DeviceName)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// copy device name
|
|
//
|
|
wcscpy(DeviceName, Buffer);
|
|
|
|
//
|
|
// store result
|
|
//
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceName;
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
PC_ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
|
|
{
|
|
if (m_Hardware)
|
|
{
|
|
//
|
|
// query device id
|
|
//
|
|
Status = m_Hardware->GetDeviceDetails(&VendorID, &DeviceID, &NumPorts, &HiSpeed);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CHubController::HandlePnp> failed to get hardware id %x\n", Status);
|
|
VendorID = 0x8086;
|
|
DeviceID = 0x3A37;
|
|
}
|
|
|
|
if (HiSpeed == 0x200)
|
|
{
|
|
//
|
|
// USB 2.0 hub
|
|
//
|
|
Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20&VID%04x&PID%04x&REV0000", VendorID, DeviceID) + 1;
|
|
Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20&VID%04x&PID%04x", VendorID, DeviceID) + 1;
|
|
Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20") + 1;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// USB 1.1 hub
|
|
//
|
|
Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB&VID%04x&PID%04x&REV0000", VendorID, DeviceID) + 1;
|
|
Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB&VID%04x&PID%04x", VendorID, DeviceID) + 1;
|
|
Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB") + 1;
|
|
}
|
|
|
|
Buffer[Index] = UNICODE_NULL;
|
|
Index++;
|
|
|
|
|
|
DPRINT1("Name %S\n", Buffer);
|
|
|
|
//
|
|
// allocate buffer
|
|
//
|
|
DeviceName = (LPWSTR)ExAllocatePoolWithTag(PagedPool, Index * sizeof(WCHAR), TAG_USBEHCI);
|
|
|
|
if (!DeviceName)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// copy device name
|
|
//
|
|
RtlMoveMemory(DeviceName, Buffer, Index * sizeof(WCHAR));
|
|
|
|
//
|
|
// store result
|
|
//
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceName;
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
{
|
|
DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_CAPABILITIES\n");
|
|
|
|
DeviceCapabilities = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
DeviceCapabilities->LockSupported = FALSE;
|
|
DeviceCapabilities->EjectSupported = FALSE;
|
|
DeviceCapabilities->Removable = FALSE;
|
|
DeviceCapabilities->DockDevice = FALSE;
|
|
DeviceCapabilities->UniqueID = FALSE;
|
|
DeviceCapabilities->SilentInstall = FALSE;
|
|
DeviceCapabilities->RawDeviceOK = FALSE;
|
|
DeviceCapabilities->SurpriseRemovalOK = FALSE;
|
|
DeviceCapabilities->Address = 0;
|
|
DeviceCapabilities->UINumber = 0;
|
|
DeviceCapabilities->DeviceD2 = 1;
|
|
|
|
/* FIXME */
|
|
DeviceCapabilities->HardwareDisabled = FALSE;
|
|
DeviceCapabilities->NoDisplayInUI = FALSE;
|
|
DeviceCapabilities->DeviceState[0] = PowerDeviceD0;
|
|
for (Index = 1; Index < PowerSystemMaximum; Index++)
|
|
DeviceCapabilities->DeviceState[Index] = PowerDeviceD3;
|
|
DeviceCapabilities->DeviceWake = PowerDeviceUnspecified;
|
|
DeviceCapabilities->D1Latency = 0;
|
|
DeviceCapabilities->D2Latency = 0;
|
|
DeviceCapabilities->D3Latency = 0;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
case IRP_MN_QUERY_INTERFACE:
|
|
{
|
|
DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_INTERFACE\n");
|
|
|
|
//
|
|
// handle device interface requests
|
|
//
|
|
Status = HandleQueryInterface(IoStack);
|
|
break;
|
|
}
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
{
|
|
DPRINT1("CHubController::HandlePnp IRP_MN_REMOVE_DEVICE\n");
|
|
|
|
//
|
|
// deactivate device interface for BUS PDO
|
|
//
|
|
SetDeviceInterface(FALSE);
|
|
|
|
//
|
|
// complete the request first
|
|
//
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
//
|
|
// now delete device
|
|
//
|
|
IoDeleteDevice(m_HubControllerDeviceObject);
|
|
|
|
//
|
|
// nullify pointer
|
|
//
|
|
m_HubControllerDeviceObject = 0;
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
{
|
|
DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %x\n", IoStack->Parameters.QueryDeviceRelations.Type);
|
|
|
|
if (IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
|
|
{
|
|
//
|
|
// allocate device relations
|
|
//
|
|
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), TAG_USBEHCI);
|
|
if (!DeviceRelations)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// initialize device relations
|
|
//
|
|
DeviceRelations->Count = 1;
|
|
DeviceRelations->Objects[0] = DeviceObject;
|
|
ObReferenceObject(DeviceObject);
|
|
|
|
//
|
|
// done
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// not handled
|
|
//
|
|
Status = Irp->IoStatus.Status;
|
|
}
|
|
break;
|
|
}
|
|
case IRP_MN_QUERY_BUS_INFORMATION:
|
|
{
|
|
DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_BUS_INFORMATION\n");
|
|
|
|
//
|
|
// allocate buffer for bus information
|
|
//
|
|
BusInformation = (PPNP_BUS_INFORMATION)ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
|
|
if (BusInformation)
|
|
{
|
|
//
|
|
// copy BUS guid
|
|
//
|
|
RtlMoveMemory(&BusInformation->BusTypeGuid, &GUID_BUS_TYPE_USB, sizeof(GUID));
|
|
|
|
//
|
|
// set bus type
|
|
//
|
|
BusInformation->LegacyBusType = PNPBus;
|
|
BusInformation->BusNumber = 0;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
break;
|
|
}
|
|
case IRP_MN_STOP_DEVICE:
|
|
{
|
|
DPRINT1("CHubController::HandlePnp IRP_MN_STOP_DEVICE\n");
|
|
//
|
|
// stop device
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
//
|
|
// ignore request with default status
|
|
//
|
|
Status = Irp->IoStatus.Status;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// complete request
|
|
//
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
//
|
|
// done
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandlePower(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp)
|
|
{
|
|
UNIMPLEMENTED
|
|
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleIsochronousTransfer(
|
|
IN OUT PIRP Irp,
|
|
PURB Urb)
|
|
{
|
|
PUSBDEVICE UsbDevice;
|
|
PUSB_ENDPOINT_DESCRIPTOR EndPointDesc = NULL;
|
|
|
|
//
|
|
// Check PipeHandle to determine if this is a Bulk or Interrupt Transfer Request
|
|
//
|
|
EndPointDesc = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbIsochronousTransfer.PipeHandle;
|
|
|
|
if (!EndPointDesc)
|
|
{
|
|
DPRINT1("No EndpointDesc\n");
|
|
Urb->UrbIsochronousTransfer.Hdr.Status = USBD_STATUS_INVALID_PIPE_HANDLE;
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// sanity checks
|
|
//
|
|
ASSERT(EndPointDesc);
|
|
ASSERT((EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_ISOCHRONOUS);
|
|
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("HandleIsochronousTransfer invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
return UsbDevice->SubmitIrp(Irp);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleBulkOrInterruptTransfer(
|
|
IN OUT PIRP Irp,
|
|
PURB Urb)
|
|
{
|
|
PUSBDEVICE UsbDevice;
|
|
PUSB_ENDPOINT_DESCRIPTOR EndPointDesc = NULL;
|
|
//
|
|
// First check if the request is for the Status Change Endpoint
|
|
//
|
|
|
|
//
|
|
// Is the Request for the root hub
|
|
//
|
|
if (Urb->UrbHeader.UsbdDeviceHandle == 0)
|
|
{
|
|
ASSERT(m_PendingSCEIrp == NULL);
|
|
if (QueryStatusChageEndpoint(Irp))
|
|
{
|
|
StatusChangeEndpointCallBack(this);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Else pend the IRP, to be completed when a device connects or disconnects.
|
|
//
|
|
DPRINT1("Pending SCE Irp\n");;
|
|
m_PendingSCEIrp = Irp;
|
|
IoMarkIrpPending(Irp);
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
//
|
|
// Check PipeHandle to determine if this is a Bulk or Interrupt Transfer Request
|
|
//
|
|
EndPointDesc = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
|
|
|
|
//
|
|
// sanity checks
|
|
//
|
|
ASSERT(EndPointDesc);
|
|
ASSERT((EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK || (EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
|
|
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("HandleBulkOrInterruptTransfer invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
return UsbDevice->SubmitIrp(Irp);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleClassOther(
|
|
IN OUT PIRP Irp,
|
|
PURB Urb)
|
|
{
|
|
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
|
|
USHORT PortStatus = 0, PortChange = 0;
|
|
PUSHORT Buffer;
|
|
ULONG NumPort;
|
|
ULONG PortId;
|
|
|
|
DPRINT("CHubController::HandleClassOther> Request %x Value %x\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value);
|
|
|
|
//
|
|
// get number of ports available
|
|
//
|
|
Status = m_Hardware->GetDeviceDetails(NULL, NULL, &NumPort, NULL);
|
|
PC_ASSERT(Status == STATUS_SUCCESS);
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(Urb->UrbControlVendorClassRequest.Index - 1 < (USHORT)NumPort);
|
|
|
|
//
|
|
// port range reported start from 1 -n
|
|
// convert back port id so it matches the hardware
|
|
//
|
|
PortId = Urb->UrbControlVendorClassRequest.Index - 1;
|
|
|
|
//
|
|
// check request code
|
|
//
|
|
switch(Urb->UrbControlVendorClassRequest.Request)
|
|
{
|
|
case USB_REQUEST_GET_STATUS:
|
|
{
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength == sizeof(USHORT) * 2);
|
|
PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer);
|
|
|
|
//
|
|
// get port status
|
|
//
|
|
Status = m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// request contains buffer of 2 ushort which are used from submitting port status and port change status
|
|
//
|
|
DPRINT("PortId %x PortStatus %x PortChange %x\n", PortId, PortStatus, PortChange);
|
|
Buffer = (PUSHORT)Urb->UrbControlVendorClassRequest.TransferBuffer;
|
|
|
|
//
|
|
// store status, then port change
|
|
//
|
|
*Buffer = PortStatus;
|
|
Buffer++;
|
|
*Buffer = PortChange;
|
|
}
|
|
|
|
//
|
|
// done
|
|
//
|
|
break;
|
|
}
|
|
case USB_REQUEST_CLEAR_FEATURE:
|
|
{
|
|
switch (Urb->UrbControlVendorClassRequest.Value)
|
|
{
|
|
case C_PORT_CONNECTION:
|
|
Status = m_Hardware->ClearPortStatus(PortId, C_PORT_CONNECTION);
|
|
break;
|
|
case C_PORT_RESET:
|
|
Status= m_Hardware->ClearPortStatus(PortId, C_PORT_RESET);
|
|
break;
|
|
default:
|
|
DPRINT("Unknown Value for Clear Feature %x \n", Urb->UrbControlVendorClassRequest.Value);
|
|
break;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
case USB_REQUEST_SET_FEATURE:
|
|
{
|
|
//
|
|
// request set feature
|
|
//
|
|
switch(Urb->UrbControlVendorClassRequest.Value)
|
|
{
|
|
case PORT_ENABLE:
|
|
{
|
|
//
|
|
// port enable is a no-op for EHCI
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case PORT_SUSPEND:
|
|
{
|
|
//
|
|
// set suspend port feature
|
|
//
|
|
Status = m_Hardware->SetPortFeature(PortId, PORT_SUSPEND);
|
|
break;
|
|
}
|
|
case PORT_POWER:
|
|
{
|
|
//
|
|
// set power feature on port
|
|
//
|
|
Status = m_Hardware->SetPortFeature(PortId, PORT_POWER);
|
|
break;
|
|
}
|
|
|
|
case PORT_RESET:
|
|
{
|
|
//
|
|
// reset port feature
|
|
//
|
|
Status = m_Hardware->SetPortFeature(PortId, PORT_RESET);
|
|
PC_ASSERT(Status == STATUS_SUCCESS);
|
|
break;
|
|
}
|
|
default:
|
|
DPRINT1("Unsupported request id %x\n", Urb->UrbControlVendorClassRequest.Value);
|
|
PC_ASSERT(FALSE);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
DPRINT1("CHubController::HandleClassOther Unknown request code %x\n", Urb->UrbControlVendorClassRequest.Request);
|
|
PC_ASSERT(0);
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleSelectConfiguration(
|
|
IN OUT PIRP Irp,
|
|
PURB Urb)
|
|
{
|
|
PUSBDEVICE UsbDevice;
|
|
PUSBD_INTERFACE_INFORMATION InterfaceInfo;
|
|
|
|
//
|
|
// is the request for the Root Hub
|
|
//
|
|
if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
|
|
{
|
|
//
|
|
// FIXME: support setting device to unconfigured state
|
|
//
|
|
PC_ASSERT(Urb->UrbSelectConfiguration.ConfigurationDescriptor);
|
|
|
|
//
|
|
// set device handle
|
|
//
|
|
Urb->UrbSelectConfiguration.ConfigurationHandle = (PVOID)&ROOTHUB2_CONFIGURATION_DESCRIPTOR;
|
|
|
|
//
|
|
// copy interface info
|
|
//
|
|
InterfaceInfo = &Urb->UrbSelectConfiguration.Interface;
|
|
|
|
InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)&ROOTHUB2_INTERFACE_DESCRIPTOR;
|
|
InterfaceInfo->Class = ROOTHUB2_INTERFACE_DESCRIPTOR.bInterfaceClass;
|
|
InterfaceInfo->SubClass = ROOTHUB2_INTERFACE_DESCRIPTOR.bInterfaceSubClass;
|
|
InterfaceInfo->Protocol = ROOTHUB2_INTERFACE_DESCRIPTOR.bInterfaceProtocol;
|
|
InterfaceInfo->Reserved = 0;
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(InterfaceInfo->NumberOfPipes == 1);
|
|
|
|
//
|
|
// copy pipe info
|
|
//
|
|
InterfaceInfo->Pipes[0].MaximumPacketSize = ROOTHUB2_ENDPOINT_DESCRIPTOR.wMaxPacketSize;
|
|
InterfaceInfo->Pipes[0].EndpointAddress = ROOTHUB2_ENDPOINT_DESCRIPTOR.bEndpointAddress;
|
|
InterfaceInfo->Pipes[0].Interval = ROOTHUB2_ENDPOINT_DESCRIPTOR.bInterval;
|
|
InterfaceInfo->Pipes[0].PipeType = (USBD_PIPE_TYPE)(ROOTHUB2_ENDPOINT_DESCRIPTOR.bmAttributes & USB_ENDPOINT_TYPE_MASK);
|
|
InterfaceInfo->Pipes[0].PipeHandle = (PVOID)&ROOTHUB2_ENDPOINT_DESCRIPTOR;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("HandleSelectConfiguration invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// select configuration
|
|
//
|
|
return UsbDevice->SelectConfiguration(Urb->UrbSelectConfiguration.ConfigurationDescriptor, &Urb->UrbSelectConfiguration.Interface, &Urb->UrbSelectConfiguration.ConfigurationHandle);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleSelectInterface(
|
|
IN OUT PIRP Irp,
|
|
PURB Urb)
|
|
{
|
|
PUSBDEVICE UsbDevice;
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(Urb->UrbSelectInterface.ConfigurationHandle);
|
|
|
|
//
|
|
// is the request for the Root Hub
|
|
//
|
|
if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
|
|
{
|
|
//
|
|
// no op for root hub
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("HandleSelectInterface invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// select interface
|
|
//
|
|
return UsbDevice->SelectInterface(Urb->UrbSelectInterface.ConfigurationHandle, &Urb->UrbSelectInterface.Interface);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleGetStatusFromDevice(
|
|
IN OUT PIRP Irp,
|
|
PURB Urb)
|
|
{
|
|
PUSHORT DeviceStatus;
|
|
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
|
|
NTSTATUS Status;
|
|
PUSBDEVICE UsbDevice;
|
|
|
|
//
|
|
// sanity checks
|
|
//
|
|
PC_ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
|
|
PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBufferLength >= sizeof(USHORT));
|
|
PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBuffer);
|
|
|
|
//
|
|
// get status buffer
|
|
//
|
|
DeviceStatus = (PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer;
|
|
|
|
|
|
if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
|
|
{
|
|
//
|
|
// FIXME need more flags ?
|
|
//
|
|
*DeviceStatus = USB_PORT_STATUS_CONNECT;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("HandleGetStatusFromDevice invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
|
|
//
|
|
// generate setup packet
|
|
//
|
|
CtrlSetup.bRequest = USB_REQUEST_GET_STATUS;
|
|
CtrlSetup.wValue.LowByte = 0;
|
|
CtrlSetup.wValue.HiByte = 0;
|
|
CtrlSetup.wIndex.W = Urb->UrbControlGetStatusRequest.Index;
|
|
CtrlSetup.wLength = (USHORT)Urb->UrbControlGetStatusRequest.TransferBufferLength;
|
|
CtrlSetup.bmRequestType.B = 0x80;
|
|
|
|
//
|
|
// submit setup packet
|
|
//
|
|
Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
DPRINT1("CHubController::HandleGetStatusFromDevice Status %x Length %lu DeviceStatus %x\n", Status, Urb->UrbControlDescriptorRequest.TransferBufferLength, *DeviceStatus);
|
|
|
|
//
|
|
// done
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleClassDevice(
|
|
IN OUT PIRP Irp,
|
|
IN OUT PURB Urb)
|
|
{
|
|
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
|
|
PUSB_HUB_DESCRIPTOR UsbHubDescriptor;
|
|
ULONG PortCount, Dummy2;
|
|
USHORT Dummy1;
|
|
PUSBDEVICE UsbDevice;
|
|
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
|
|
|
|
DPRINT("CHubController::HandleClassDevice Request %x Class %x\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value >> 8);
|
|
|
|
//
|
|
// check class request type
|
|
//
|
|
switch(Urb->UrbControlVendorClassRequest.Request)
|
|
{
|
|
case USB_REQUEST_GET_STATUS:
|
|
{
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("HandleClassDevice invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
|
|
//
|
|
// generate setup packet
|
|
//
|
|
CtrlSetup.bRequest = USB_REQUEST_GET_STATUS;
|
|
CtrlSetup.wValue.LowByte = Urb->UrbControlVendorClassRequest.Index;
|
|
CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
|
|
CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
|
|
CtrlSetup.wLength = (USHORT)Urb->UrbControlGetStatusRequest.TransferBufferLength;
|
|
CtrlSetup.bmRequestType.B = 0xA0;
|
|
|
|
//
|
|
// submit setup packet
|
|
//
|
|
Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
break;
|
|
}
|
|
case USB_REQUEST_GET_DESCRIPTOR:
|
|
{
|
|
switch (Urb->UrbControlVendorClassRequest.Value >> 8)
|
|
{
|
|
case USB_DEVICE_CLASS_RESERVED: // FALL THROUGH
|
|
case USB_DEVICE_CLASS_HUB:
|
|
{
|
|
//
|
|
// sanity checks
|
|
//
|
|
PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer);
|
|
PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength >= sizeof(USB_HUB_DESCRIPTOR));
|
|
|
|
//
|
|
// get hub descriptor
|
|
//
|
|
UsbHubDescriptor = (PUSB_HUB_DESCRIPTOR)Urb->UrbControlVendorClassRequest.TransferBuffer;
|
|
|
|
//
|
|
// one hub is handled
|
|
//
|
|
UsbHubDescriptor->bDescriptorLength = sizeof(USB_HUB_DESCRIPTOR);
|
|
Urb->UrbControlVendorClassRequest.TransferBufferLength = sizeof(USB_HUB_DESCRIPTOR);
|
|
|
|
//
|
|
// type should 0x29 according to msdn
|
|
//
|
|
UsbHubDescriptor->bDescriptorType = 0x29;
|
|
|
|
//
|
|
// get port count
|
|
//
|
|
Status = m_Hardware->GetDeviceDetails(&Dummy1, &Dummy1, &PortCount, &Dummy2);
|
|
PC_ASSERT(Status == STATUS_SUCCESS);
|
|
|
|
//
|
|
// FIXME: retrieve values
|
|
//
|
|
UsbHubDescriptor->bNumberOfPorts = (UCHAR)PortCount;
|
|
UsbHubDescriptor->wHubCharacteristics = 0x00;
|
|
UsbHubDescriptor->bPowerOnToPowerGood = 0x01;
|
|
UsbHubDescriptor->bHubControlCurrent = 0x00;
|
|
|
|
//
|
|
// done
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
default:
|
|
DPRINT1("CHubController::HandleClassDevice Class %x not implemented\n", Urb->UrbControlVendorClassRequest.Value >> 8);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
DPRINT1("CHubController::HandleClassDevice Type %x not implemented\n", Urb->UrbControlVendorClassRequest.Request);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleGetDescriptorFromInterface(
|
|
IN OUT PIRP Irp,
|
|
IN OUT PURB Urb)
|
|
{
|
|
PUSBDEVICE UsbDevice;
|
|
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength);
|
|
ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
|
|
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("HandleGetDescriptorFromInterface invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// generate setup packet
|
|
//
|
|
CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
|
|
CtrlSetup.wValue.LowByte = Urb->UrbControlDescriptorRequest.Index;
|
|
CtrlSetup.wValue.HiByte = Urb->UrbControlDescriptorRequest.DescriptorType;
|
|
CtrlSetup.wIndex.W = Urb->UrbControlDescriptorRequest.LanguageId;
|
|
CtrlSetup.wLength = (USHORT)Urb->UrbControlDescriptorRequest.TransferBufferLength;
|
|
CtrlSetup.bmRequestType.B = 0x81;
|
|
|
|
//
|
|
// submit setup packet
|
|
//
|
|
Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
|
|
//
|
|
// done
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleGetDescriptor(
|
|
IN OUT PIRP Irp,
|
|
IN OUT PURB Urb)
|
|
{
|
|
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
|
|
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
|
|
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
|
|
PUCHAR Buffer;
|
|
PUSBDEVICE UsbDevice;
|
|
ULONG Length;
|
|
|
|
DPRINT("CHubController::HandleGetDescriptor\n");
|
|
|
|
//
|
|
// check descriptor type
|
|
//
|
|
switch(Urb->UrbControlDescriptorRequest.DescriptorType)
|
|
{
|
|
case USB_DEVICE_DESCRIPTOR_TYPE:
|
|
{
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR));
|
|
PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
|
|
|
|
if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
|
|
{
|
|
//
|
|
// copy root hub device descriptor
|
|
//
|
|
RtlCopyMemory((PUCHAR)Urb->UrbControlDescriptorRequest.TransferBuffer, &m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("HandleGetDescriptor invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// retrieve device descriptor from device
|
|
//
|
|
UsbDevice->GetDeviceDescriptor((PUSB_DEVICE_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
}
|
|
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
|
|
{
|
|
//
|
|
// sanity checks
|
|
//
|
|
PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
|
|
PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR));
|
|
|
|
if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
|
|
{
|
|
//
|
|
// request is for the root bus controller
|
|
//
|
|
RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, &ROOTHUB2_CONFIGURATION_DESCRIPTOR, sizeof(USB_CONFIGURATION_DESCRIPTOR));
|
|
|
|
//
|
|
// get configuration descriptor, very retarded!
|
|
//
|
|
ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer;
|
|
|
|
//
|
|
// check if buffer can hold interface and endpoint descriptor
|
|
//
|
|
if (ConfigurationDescriptor->wTotalLength > Urb->UrbControlDescriptorRequest.TransferBufferLength)
|
|
{
|
|
//
|
|
// buffer too small
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// copy interface descriptor template
|
|
//
|
|
Buffer = (PUCHAR)(ConfigurationDescriptor + 1);
|
|
RtlCopyMemory(Buffer, &ROOTHUB2_INTERFACE_DESCRIPTOR, sizeof(USB_INTERFACE_DESCRIPTOR));
|
|
|
|
//
|
|
// copy end point descriptor template
|
|
//
|
|
Buffer += sizeof(USB_INTERFACE_DESCRIPTOR);
|
|
RtlCopyMemory(Buffer, &ROOTHUB2_ENDPOINT_DESCRIPTOR, sizeof(USB_ENDPOINT_DESCRIPTOR));
|
|
|
|
//
|
|
// done
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("USB_CONFIGURATION_DESCRIPTOR_TYPE invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
if (sizeof(USB_CONFIGURATION_DESCRIPTOR) > Urb->UrbControlDescriptorRequest.TransferBufferLength)
|
|
{
|
|
//
|
|
// buffer too small
|
|
//
|
|
Urb->UrbControlDescriptorRequest.TransferBufferLength = UsbDevice->GetConfigurationDescriptorsLength();
|
|
|
|
//
|
|
// bail out
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// perform work in IUSBDevice
|
|
//
|
|
UsbDevice->GetConfigurationDescriptors((PUSB_CONFIGURATION_DESCRIPTOR)Urb->UrbControlDescriptorRequest.TransferBuffer, Urb->UrbControlDescriptorRequest.TransferBufferLength, &Length);
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength >= Length);
|
|
|
|
//
|
|
// store result size
|
|
//
|
|
Urb->UrbControlDescriptorRequest.TransferBufferLength = Length;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
}
|
|
case USB_STRING_DESCRIPTOR_TYPE:
|
|
{
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
|
|
PC_ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength);
|
|
|
|
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("USB_STRING_DESCRIPTOR_TYPE invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// generate setup packet
|
|
//
|
|
CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
|
|
CtrlSetup.wValue.LowByte = Urb->UrbControlDescriptorRequest.Index;
|
|
CtrlSetup.wValue.HiByte = Urb->UrbControlDescriptorRequest.DescriptorType;
|
|
CtrlSetup.wIndex.W = Urb->UrbControlDescriptorRequest.LanguageId;
|
|
CtrlSetup.wLength = (USHORT)Urb->UrbControlDescriptorRequest.TransferBufferLength;
|
|
CtrlSetup.bmRequestType.B = 0x80;
|
|
|
|
//
|
|
// submit setup packet
|
|
//
|
|
Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
|
|
break;
|
|
}
|
|
default:
|
|
DPRINT1("CHubController::HandleGetDescriptor DescriptorType %x unimplemented\n", Urb->UrbControlDescriptorRequest.DescriptorType);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// done
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleClassEndpoint(
|
|
IN OUT PIRP Irp,
|
|
IN OUT PURB Urb)
|
|
{
|
|
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
|
|
NTSTATUS Status;
|
|
PUSBDEVICE UsbDevice;
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer);
|
|
PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength);
|
|
PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("HandleClassEndpoint invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
|
|
DPRINT1("URB_FUNCTION_CLASS_ENDPOINT\n");
|
|
DPRINT1("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags);
|
|
DPRINT1("TransferBufferLength %x\n", Urb->UrbControlVendorClassRequest.TransferBufferLength);
|
|
DPRINT1("TransferBuffer %x\n", Urb->UrbControlVendorClassRequest.TransferBuffer);
|
|
DPRINT1("TransferBufferMDL %x\n", Urb->UrbControlVendorClassRequest.TransferBufferMDL);
|
|
DPRINT1("RequestTypeReservedBits %x\n", Urb->UrbControlVendorClassRequest.RequestTypeReservedBits);
|
|
DPRINT1("Request %x\n", Urb->UrbControlVendorClassRequest.Request);
|
|
DPRINT1("Value %x\n", Urb->UrbControlVendorClassRequest.Value);
|
|
DPRINT1("Index %x\n", Urb->UrbControlVendorClassRequest.Index);
|
|
|
|
//
|
|
// initialize setup packet
|
|
//
|
|
CtrlSetup.bmRequestType.B = 0xa2; //FIXME: Const.
|
|
CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
|
|
CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
|
|
CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
|
|
CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength;
|
|
|
|
//
|
|
// issue request
|
|
//
|
|
Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlVendorClassRequest.TransferBufferLength, Urb->UrbControlVendorClassRequest.TransferBuffer);
|
|
|
|
//
|
|
// assert on failure
|
|
//
|
|
PC_ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
//
|
|
// done
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleClassInterface(
|
|
IN OUT PIRP Irp,
|
|
IN OUT PURB Urb)
|
|
{
|
|
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
|
|
NTSTATUS Status;
|
|
PUSBDEVICE UsbDevice;
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
//ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer || Urb->UrbControlVendorClassRequest.TransferBufferMDL);
|
|
//ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength);
|
|
PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// check if this is a valid usb device handle
|
|
//
|
|
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
|
|
{
|
|
DPRINT1("HandleClassInterface invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device
|
|
//
|
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
|
|
|
|
|
DPRINT1("URB_FUNCTION_CLASS_INTERFACE\n");
|
|
DPRINT1("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags);
|
|
DPRINT1("TransferBufferLength %x\n", Urb->UrbControlVendorClassRequest.TransferBufferLength);
|
|
DPRINT1("TransferBuffer %x\n", Urb->UrbControlVendorClassRequest.TransferBuffer);
|
|
DPRINT1("TransferBufferMDL %x\n", Urb->UrbControlVendorClassRequest.TransferBufferMDL);
|
|
DPRINT1("RequestTypeReservedBits %x\n", Urb->UrbControlVendorClassRequest.RequestTypeReservedBits);
|
|
DPRINT1("Request %x\n", Urb->UrbControlVendorClassRequest.Request);
|
|
DPRINT1("Value %x\n", Urb->UrbControlVendorClassRequest.Value);
|
|
DPRINT1("Index %x\n", Urb->UrbControlVendorClassRequest.Index);
|
|
|
|
//
|
|
// initialize setup packet
|
|
//
|
|
CtrlSetup.bmRequestType.B = 0xa1; //FIXME: Const.
|
|
CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
|
|
CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
|
|
CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
|
|
CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength;
|
|
|
|
//
|
|
// issue request
|
|
//
|
|
Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlVendorClassRequest.TransferBufferLength, Urb->UrbControlVendorClassRequest.TransferBuffer);
|
|
|
|
//
|
|
// assert on failure
|
|
//
|
|
PC_ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
//
|
|
// done
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::HandleDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PCOMMON_DEVICE_EXTENSION DeviceExtension;
|
|
PURB Urb;
|
|
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
//
|
|
// get current stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// determine which request should be performed
|
|
//
|
|
switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case IOCTL_INTERNAL_USB_SUBMIT_URB:
|
|
{
|
|
//
|
|
// get urb
|
|
//
|
|
Urb = (PURB)IoStack->Parameters.Others.Argument1;
|
|
PC_ASSERT(Urb);
|
|
|
|
switch (Urb->UrbHeader.Function)
|
|
{
|
|
case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE:
|
|
Status = HandleGetDescriptorFromInterface(Irp, Urb);
|
|
break;
|
|
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
|
|
Status = HandleGetDescriptor(Irp, Urb);
|
|
break;
|
|
case URB_FUNCTION_CLASS_DEVICE:
|
|
Status = HandleClassDevice(Irp, Urb);
|
|
break;
|
|
case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
|
|
Status = HandleGetStatusFromDevice(Irp, Urb);
|
|
break;
|
|
case URB_FUNCTION_SELECT_CONFIGURATION:
|
|
Status = HandleSelectConfiguration(Irp, Urb);
|
|
break;
|
|
case URB_FUNCTION_SELECT_INTERFACE:
|
|
Status = HandleSelectInterface(Irp, Urb);
|
|
break;
|
|
case URB_FUNCTION_CLASS_OTHER:
|
|
Status = HandleClassOther(Irp, Urb);
|
|
break;
|
|
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
|
|
Status = HandleBulkOrInterruptTransfer(Irp, Urb);
|
|
break;
|
|
case URB_FUNCTION_ISOCH_TRANSFER:
|
|
Status = HandleIsochronousTransfer(Irp, Urb);
|
|
break;
|
|
case URB_FUNCTION_CLASS_INTERFACE:
|
|
Status = HandleClassInterface(Irp, Urb);
|
|
break;
|
|
case URB_FUNCTION_CLASS_ENDPOINT:
|
|
Status = HandleClassEndpoint(Irp, Urb);
|
|
break;
|
|
default:
|
|
DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x NOT IMPLEMENTED\n", Urb->UrbHeader.Function);
|
|
break;
|
|
}
|
|
//
|
|
// request completed
|
|
//
|
|
break;
|
|
}
|
|
case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE:
|
|
{
|
|
DPRINT("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE %p\n", this);
|
|
|
|
if (IoStack->Parameters.Others.Argument1)
|
|
{
|
|
//
|
|
// store object as device handle
|
|
//
|
|
*(PVOID *)IoStack->Parameters.Others.Argument1 = (PVOID)this;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// mis-behaving hub driver
|
|
//
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
//
|
|
// request completed
|
|
//
|
|
break;
|
|
}
|
|
case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO:
|
|
{
|
|
DPRINT("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO\n");
|
|
|
|
//
|
|
// this is the first request send, it delivers the PDO to the caller
|
|
//
|
|
if (IoStack->Parameters.Others.Argument1)
|
|
{
|
|
//
|
|
// store root hub pdo object
|
|
//
|
|
*(PVOID *)IoStack->Parameters.Others.Argument1 = DeviceObject;
|
|
}
|
|
|
|
if (IoStack->Parameters.Others.Argument2)
|
|
{
|
|
//
|
|
// documentation claims to deliver the hcd controller object, although it is wrong
|
|
//
|
|
*(PVOID *)IoStack->Parameters.Others.Argument2 = DeviceObject;
|
|
}
|
|
|
|
//
|
|
// request completed
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
case IOCTL_INTERNAL_USB_GET_HUB_COUNT:
|
|
{
|
|
DPRINT("IOCTL_INTERNAL_USB_GET_HUB_COUNT\n");
|
|
|
|
//
|
|
// after IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO is delivered, the usbhub driver
|
|
// requests this ioctl to deliver the number of presents.
|
|
|
|
if (IoStack->Parameters.Others.Argument1)
|
|
{
|
|
//
|
|
// FIXME / verify: there is only one hub
|
|
//
|
|
*(PULONG)IoStack->Parameters.Others.Argument1 = 1;
|
|
}
|
|
|
|
//
|
|
// request completed
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
break;
|
|
}
|
|
case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
|
|
{
|
|
DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION UNIMPLEMENTED\n");
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
DPRINT1("HandleDeviceControl>Type: IoCtl %x InputBufferLength %lu OutputBufferLength %lu NOT IMPLEMENTED\n",
|
|
IoStack->Parameters.DeviceIoControl.IoControlCode,
|
|
IoStack->Parameters.DeviceIoControl.InputBufferLength,
|
|
IoStack->Parameters.DeviceIoControl.OutputBufferLength);
|
|
break;
|
|
}
|
|
}
|
|
if (Status != STATUS_PENDING)
|
|
{
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
PUSBHARDWAREDEVICE
|
|
CHubController::GetUsbHardware()
|
|
{
|
|
return m_Hardware;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
ULONG
|
|
CHubController::AcquireDeviceAddress()
|
|
{
|
|
KIRQL OldLevel;
|
|
ULONG DeviceAddress;
|
|
|
|
//
|
|
// acquire device lock
|
|
//
|
|
KeAcquireSpinLock(&m_Lock, &OldLevel);
|
|
|
|
//
|
|
// find address
|
|
//
|
|
DeviceAddress = RtlFindClearBits(&m_DeviceAddressBitmap, 1, 0);
|
|
if (DeviceAddress != MAXULONG)
|
|
{
|
|
//
|
|
// reserve address
|
|
//
|
|
RtlSetBits(&m_DeviceAddressBitmap, DeviceAddress, 1);
|
|
|
|
//
|
|
// device addresses start from 0x1 - 0xFF
|
|
//
|
|
DeviceAddress++;
|
|
}
|
|
|
|
//
|
|
// release spin lock
|
|
//
|
|
KeReleaseSpinLock(&m_Lock, OldLevel);
|
|
|
|
//
|
|
// return device address
|
|
//
|
|
return DeviceAddress;
|
|
}
|
|
//-----------------------------------------------------------------------------------------
|
|
VOID
|
|
CHubController::ReleaseDeviceAddress(
|
|
ULONG DeviceAddress)
|
|
{
|
|
KIRQL OldLevel;
|
|
|
|
//
|
|
// acquire device lock
|
|
//
|
|
KeAcquireSpinLock(&m_Lock, &OldLevel);
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(DeviceAddress != 0);
|
|
|
|
//
|
|
// convert back to bit number
|
|
//
|
|
DeviceAddress--;
|
|
|
|
//
|
|
// clear bit
|
|
//
|
|
RtlClearBits(&m_DeviceAddressBitmap, DeviceAddress, 1);
|
|
|
|
//
|
|
// release lock
|
|
//
|
|
KeReleaseSpinLock(&m_Lock, OldLevel);
|
|
}
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::RemoveUsbDevice(
|
|
PUSBDEVICE UsbDevice)
|
|
{
|
|
PUSBDEVICE_ENTRY DeviceEntry;
|
|
PLIST_ENTRY Entry;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
KIRQL OldLevel;
|
|
|
|
//
|
|
// acquire lock
|
|
//
|
|
KeAcquireSpinLock(&m_Lock, &OldLevel);
|
|
|
|
//
|
|
// point to first entry
|
|
//
|
|
Entry = m_UsbDeviceList.Flink;
|
|
|
|
//
|
|
// find matching entry
|
|
//
|
|
while(Entry != &m_UsbDeviceList)
|
|
{
|
|
//
|
|
// get entry
|
|
//
|
|
DeviceEntry = (PUSBDEVICE_ENTRY)CONTAINING_RECORD(Entry, USBDEVICE_ENTRY, Entry);
|
|
|
|
//
|
|
// is it current entry
|
|
//
|
|
if (DeviceEntry->Device == UsbDevice)
|
|
{
|
|
//
|
|
// remove entry
|
|
//
|
|
RemoveEntryList(Entry);
|
|
|
|
//
|
|
// free entry
|
|
//
|
|
ExFreePoolWithTag(DeviceEntry, TAG_USBEHCI);
|
|
|
|
//
|
|
// done
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// goto next device
|
|
//
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
//
|
|
// release lock
|
|
//
|
|
KeReleaseSpinLock(&m_Lock, OldLevel);
|
|
|
|
//
|
|
// return result
|
|
//
|
|
return Status;
|
|
}
|
|
//-----------------------------------------------------------------------------------------
|
|
BOOLEAN
|
|
CHubController::ValidateUsbDevice(PUSBDEVICE UsbDevice)
|
|
{
|
|
PUSBDEVICE_ENTRY DeviceEntry;
|
|
PLIST_ENTRY Entry;
|
|
KIRQL OldLevel;
|
|
BOOLEAN Result = FALSE;
|
|
|
|
//
|
|
// acquire lock
|
|
//
|
|
KeAcquireSpinLock(&m_Lock, &OldLevel);
|
|
|
|
//
|
|
// point to first entry
|
|
//
|
|
Entry = m_UsbDeviceList.Flink;
|
|
|
|
//
|
|
// find matching entry
|
|
//
|
|
while(Entry != &m_UsbDeviceList)
|
|
{
|
|
//
|
|
// get entry
|
|
//
|
|
DeviceEntry = (PUSBDEVICE_ENTRY)CONTAINING_RECORD(Entry, USBDEVICE_ENTRY, Entry);
|
|
|
|
//
|
|
// is it current entry
|
|
//
|
|
if (DeviceEntry->Device == UsbDevice)
|
|
{
|
|
//
|
|
// device is valid
|
|
//
|
|
Result = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// goto next device
|
|
//
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
//
|
|
// release lock
|
|
//
|
|
KeReleaseSpinLock(&m_Lock, OldLevel);
|
|
|
|
//
|
|
// return result
|
|
//
|
|
return Result;
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CHubController::AddUsbDevice(
|
|
PUSBDEVICE UsbDevice)
|
|
{
|
|
PUSBDEVICE_ENTRY DeviceEntry;
|
|
KIRQL OldLevel;
|
|
|
|
//
|
|
// allocate device entry
|
|
//
|
|
DeviceEntry = (PUSBDEVICE_ENTRY)ExAllocatePoolWithTag(NonPagedPool, sizeof(USBDEVICE_ENTRY), TAG_USBEHCI);
|
|
if (!DeviceEntry)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// initialize entry
|
|
//
|
|
DeviceEntry->Device = UsbDevice;
|
|
|
|
//
|
|
// acquire lock
|
|
//
|
|
KeAcquireSpinLock(&m_Lock, &OldLevel);
|
|
|
|
//
|
|
// insert entry
|
|
//
|
|
InsertTailList(&m_UsbDeviceList, &DeviceEntry->Entry);
|
|
|
|
//
|
|
// release spin lock
|
|
//
|
|
KeReleaseSpinLock(&m_Lock, OldLevel);
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
VOID
|
|
CHubController::SetNotification(
|
|
PVOID CallbackContext,
|
|
PRH_INIT_CALLBACK CallbackRoutine)
|
|
{
|
|
KIRQL OldLevel;
|
|
|
|
//
|
|
// acquire hub controller lock
|
|
//
|
|
KeAcquireSpinLock(&m_Lock, &OldLevel);
|
|
|
|
//
|
|
// now set the callback routine and context of the hub
|
|
//
|
|
m_HubCallbackContext = CallbackContext;
|
|
m_HubCallbackRoutine = CallbackRoutine;
|
|
|
|
//
|
|
// release hub controller lock
|
|
//
|
|
KeReleaseSpinLock(&m_Lock, OldLevel);
|
|
}
|
|
|
|
//=================================================================================================
|
|
//
|
|
// Generic Interface functions
|
|
//
|
|
VOID
|
|
USB_BUSIFFN
|
|
USBI_InterfaceReference(
|
|
PVOID BusContext)
|
|
{
|
|
CHubController * Controller = (CHubController*)BusContext;
|
|
|
|
DPRINT1("USBH_InterfaceReference\n");
|
|
|
|
//
|
|
// add reference
|
|
//
|
|
Controller->AddRef();
|
|
}
|
|
|
|
VOID
|
|
USB_BUSIFFN
|
|
USBI_InterfaceDereference(
|
|
PVOID BusContext)
|
|
{
|
|
CHubController * Controller = (CHubController*)BusContext;
|
|
|
|
DPRINT1("USBH_InterfaceDereference\n");
|
|
|
|
//
|
|
// release
|
|
//
|
|
Controller->Release();
|
|
}
|
|
//=================================================================================================
|
|
//
|
|
// USB Hub Interface functions
|
|
//
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_CreateUsbDevice(
|
|
PVOID BusContext,
|
|
PUSB_DEVICE_HANDLE *NewDevice,
|
|
PUSB_DEVICE_HANDLE HubDeviceHandle,
|
|
USHORT PortStatus,
|
|
USHORT PortNumber)
|
|
{
|
|
PUSBDEVICE NewUsbDevice;
|
|
CHubController * Controller;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT1("USBHI_CreateUsbDevice\n");
|
|
|
|
//
|
|
// first get hub controller
|
|
//
|
|
Controller = (CHubController *)BusContext;
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(Controller);
|
|
PC_ASSERT(BusContext == HubDeviceHandle);
|
|
|
|
//
|
|
// now allocate usb device
|
|
//
|
|
Status = CreateUSBDevice(&NewUsbDevice);
|
|
|
|
//
|
|
// check for success
|
|
//
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// release controller
|
|
//
|
|
Controller->Release();
|
|
DPRINT1("USBHI_CreateUsbDevice: failed to create usb device %x\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// now initialize device
|
|
//
|
|
Status = NewUsbDevice->Initialize(PHUBCONTROLLER(Controller), Controller->GetUsbHardware(),PVOID(Controller), PortNumber, PortStatus);
|
|
|
|
//
|
|
// check for success
|
|
//
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// release usb device
|
|
//
|
|
NewUsbDevice->Release();
|
|
DPRINT1("USBHI_CreateUsbDevice: failed to initialize usb device %x\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// insert into list
|
|
//
|
|
Status = Controller->AddUsbDevice(NewUsbDevice);
|
|
//
|
|
// check for success
|
|
//
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// release usb device
|
|
//
|
|
NewUsbDevice->Release();
|
|
|
|
DPRINT1("USBHI_CreateUsbDevice: failed to add usb device %x\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// store the handle
|
|
//
|
|
*NewDevice = NewUsbDevice;
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_InitializeUsbDevice(
|
|
PVOID BusContext,
|
|
PUSB_DEVICE_HANDLE DeviceHandle)
|
|
{
|
|
PUSBDEVICE UsbDevice;
|
|
CHubController * Controller;
|
|
ULONG DeviceAddress;
|
|
NTSTATUS Status;
|
|
ULONG Index = 0;
|
|
|
|
DPRINT1("USBHI_InitializeUsbDevice\n");
|
|
|
|
//
|
|
// first get controller
|
|
//
|
|
Controller = (CHubController *)BusContext;
|
|
PC_ASSERT(Controller);
|
|
|
|
//
|
|
// get device object
|
|
//
|
|
UsbDevice = (PUSBDEVICE)DeviceHandle;
|
|
PC_ASSERT(UsbDevice);
|
|
|
|
//
|
|
// validate device handle
|
|
//
|
|
if (!Controller->ValidateUsbDevice(UsbDevice))
|
|
{
|
|
DPRINT1("USBHI_InitializeUsbDevice invalid device handle %p\n", DeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// now reserve an address
|
|
//
|
|
DeviceAddress = Controller->AcquireDeviceAddress();
|
|
|
|
//
|
|
// is the device address valid
|
|
//
|
|
if (DeviceAddress == MAXULONG)
|
|
{
|
|
//
|
|
// failed to get an device address from the device address pool
|
|
//
|
|
DPRINT1("USBHI_InitializeUsbDevice failed to get device address\n");
|
|
return STATUS_DEVICE_DATA_ERROR;
|
|
}
|
|
|
|
do
|
|
{
|
|
//
|
|
// now set the device address
|
|
//
|
|
Status = UsbDevice->SetDeviceAddress((UCHAR)DeviceAddress);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
break;
|
|
|
|
}while(Index++ < 3 );
|
|
|
|
//
|
|
// check for failure
|
|
//
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// failed to set device address
|
|
//
|
|
DPRINT1("USBHI_InitializeUsbDevice failed to set address with %x\n", Status);
|
|
|
|
//
|
|
// release address
|
|
//
|
|
Controller->ReleaseDeviceAddress(DeviceAddress);
|
|
|
|
//
|
|
// return error
|
|
//
|
|
return STATUS_DEVICE_DATA_ERROR;
|
|
}
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_GetUsbDescriptors(
|
|
PVOID BusContext,
|
|
PUSB_DEVICE_HANDLE DeviceHandle,
|
|
PUCHAR DeviceDescriptorBuffer,
|
|
PULONG DeviceDescriptorBufferLength,
|
|
PUCHAR ConfigDescriptorBuffer,
|
|
PULONG ConfigDescriptorBufferLength)
|
|
{
|
|
PUSBDEVICE UsbDevice;
|
|
CHubController * Controller;
|
|
|
|
DPRINT1("USBHI_GetUsbDescriptors\n");
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(DeviceDescriptorBuffer);
|
|
PC_ASSERT(DeviceDescriptorBufferLength);
|
|
PC_ASSERT(*DeviceDescriptorBufferLength >= sizeof(USB_DEVICE_DESCRIPTOR));
|
|
PC_ASSERT(ConfigDescriptorBufferLength);
|
|
PC_ASSERT(*ConfigDescriptorBufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR));
|
|
|
|
//
|
|
// first get controller
|
|
//
|
|
Controller = (CHubController *)BusContext;
|
|
PC_ASSERT(Controller);
|
|
|
|
|
|
//
|
|
// get device object
|
|
//
|
|
UsbDevice = (PUSBDEVICE)DeviceHandle;
|
|
PC_ASSERT(UsbDevice);
|
|
|
|
//
|
|
// validate device handle
|
|
//
|
|
if (!Controller->ValidateUsbDevice(UsbDevice))
|
|
{
|
|
DPRINT1("USBHI_GetUsbDescriptors invalid device handle %p\n", DeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// get device descriptor
|
|
//
|
|
UsbDevice->GetDeviceDescriptor((PUSB_DEVICE_DESCRIPTOR)DeviceDescriptorBuffer);
|
|
|
|
//
|
|
// store result length
|
|
//
|
|
*DeviceDescriptorBufferLength = sizeof(USB_DEVICE_DESCRIPTOR);
|
|
|
|
//
|
|
// get configuration descriptor
|
|
//
|
|
UsbDevice->GetConfigurationDescriptors((PUSB_CONFIGURATION_DESCRIPTOR)ConfigDescriptorBuffer, *ConfigDescriptorBufferLength, ConfigDescriptorBufferLength);
|
|
|
|
//
|
|
// complete the request
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_RemoveUsbDevice(
|
|
PVOID BusContext,
|
|
PUSB_DEVICE_HANDLE DeviceHandle,
|
|
ULONG Flags)
|
|
{
|
|
PUSBDEVICE UsbDevice;
|
|
CHubController * Controller;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT1("USBHI_RemoveUsbDevice\n");
|
|
|
|
//
|
|
// first get controller
|
|
//
|
|
Controller = (CHubController *)BusContext;
|
|
PC_ASSERT(Controller);
|
|
|
|
//
|
|
// get device object
|
|
//
|
|
UsbDevice = (PUSBDEVICE)DeviceHandle;
|
|
PC_ASSERT(UsbDevice);
|
|
|
|
//
|
|
// validate device handle
|
|
//
|
|
if (!Controller->ValidateUsbDevice(UsbDevice))
|
|
{
|
|
DPRINT1("USBHI_RemoveUsbDevice invalid device handle %p\n", DeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// check if there were flags passed
|
|
//
|
|
if (Flags & USBD_KEEP_DEVICE_DATA || Flags & USBD_MARK_DEVICE_BUSY)
|
|
{
|
|
//
|
|
// ignore flags for now
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// remove device
|
|
//
|
|
Status = Controller->RemoveUsbDevice(UsbDevice);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// invalid device handle
|
|
//
|
|
DPRINT1("USBHI_RemoveUsbDevice Invalid device handle %p\n", UsbDevice);
|
|
PC_ASSERT(0);
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// release usb device
|
|
//
|
|
UsbDevice->Release();
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_RestoreUsbDevice(
|
|
PVOID BusContext,
|
|
PUSB_DEVICE_HANDLE OldDeviceHandle,
|
|
PUSB_DEVICE_HANDLE NewDeviceHandle)
|
|
{
|
|
PUSBDEVICE OldUsbDevice, NewUsbDevice;
|
|
CHubController * Controller;
|
|
|
|
DPRINT1("USBHI_RestoreUsbDevice\n");
|
|
|
|
//
|
|
// first get controller
|
|
//
|
|
Controller = (CHubController *)BusContext;
|
|
PC_ASSERT(Controller);
|
|
|
|
//
|
|
// get device object
|
|
//
|
|
OldUsbDevice = (PUSBDEVICE)OldDeviceHandle;
|
|
NewUsbDevice = (PUSBDEVICE)NewDeviceHandle;
|
|
PC_ASSERT(OldUsbDevice);
|
|
PC_ASSERT(NewDeviceHandle);
|
|
|
|
//
|
|
// validate device handle
|
|
//
|
|
PC_ASSERT(Controller->ValidateUsbDevice(NewUsbDevice));
|
|
PC_ASSERT(Controller->ValidateUsbDevice(OldUsbDevice));
|
|
|
|
DPRINT1("NewUsbDevice: DeviceAddress %x\n", NewUsbDevice->GetDeviceAddress());
|
|
DPRINT1("OldUsbDevice: DeviceAddress %x\n", OldUsbDevice->GetDeviceAddress());
|
|
|
|
//
|
|
// remove old device handle
|
|
//
|
|
USBHI_RemoveUsbDevice(BusContext, OldDeviceHandle, 0);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_QueryDeviceInformation(
|
|
PVOID BusContext,
|
|
PUSB_DEVICE_HANDLE DeviceHandle,
|
|
PVOID DeviceInformationBuffer,
|
|
ULONG DeviceInformationBufferLength,
|
|
PULONG LengthReturned)
|
|
{
|
|
PUSB_DEVICE_INFORMATION_0 DeviceInfo;
|
|
PUSBDEVICE UsbDevice;
|
|
CHubController * Controller;
|
|
|
|
DPRINT1("USBHI_QueryDeviceInformation %p\n", BusContext);
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(DeviceInformationBufferLength >= sizeof(USB_DEVICE_INFORMATION_0));
|
|
PC_ASSERT(DeviceInformationBuffer);
|
|
PC_ASSERT(LengthReturned);
|
|
|
|
//
|
|
// get controller object
|
|
//
|
|
Controller = (CHubController*)BusContext;
|
|
PC_ASSERT(Controller);
|
|
|
|
//
|
|
// get device object
|
|
//
|
|
UsbDevice = (PUSBDEVICE)DeviceHandle;
|
|
PC_ASSERT(UsbDevice);
|
|
|
|
if (BusContext != DeviceHandle)
|
|
{
|
|
//
|
|
// validate device handle
|
|
//
|
|
if (!Controller->ValidateUsbDevice(UsbDevice))
|
|
{
|
|
DPRINT1("USBHI_QueryDeviceInformation invalid device handle %p\n", DeviceHandle);
|
|
|
|
//
|
|
// invalid device handle
|
|
//
|
|
return STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// access information buffer
|
|
//
|
|
DeviceInfo = (PUSB_DEVICE_INFORMATION_0)DeviceInformationBuffer;
|
|
|
|
//
|
|
// initialize with default values
|
|
//
|
|
DeviceInfo->InformationLevel = 0;
|
|
DeviceInfo->ActualLength = sizeof(USB_DEVICE_INFORMATION_0);
|
|
DeviceInfo->PortNumber = UsbDevice->GetPort();
|
|
DeviceInfo->CurrentConfigurationValue = UsbDevice->GetConfigurationValue();
|
|
DeviceInfo->DeviceAddress = UsbDevice->GetDeviceAddress();
|
|
DeviceInfo->HubAddress = 0; //FIXME
|
|
DeviceInfo->DeviceSpeed = UsbDevice->GetSpeed();
|
|
DeviceInfo->DeviceType = UsbDevice->GetType();
|
|
DeviceInfo->NumberOfOpenPipes = 0; //FIXME
|
|
|
|
//
|
|
// get device descriptor
|
|
//
|
|
UsbDevice->GetDeviceDescriptor(&DeviceInfo->DeviceDescriptor);
|
|
|
|
//
|
|
// FIXME return pipe information
|
|
//
|
|
|
|
//
|
|
// store result length
|
|
//
|
|
*LengthReturned = sizeof(USB_DEVICE_INFORMATION_0);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// access information buffer
|
|
//
|
|
DeviceInfo = (PUSB_DEVICE_INFORMATION_0)DeviceInformationBuffer;
|
|
|
|
//
|
|
// initialize with default values
|
|
//
|
|
DeviceInfo->InformationLevel = 0;
|
|
DeviceInfo->ActualLength = sizeof(USB_DEVICE_INFORMATION_0);
|
|
DeviceInfo->PortNumber = 0;
|
|
DeviceInfo->CurrentConfigurationValue = 0; //FIXME;
|
|
DeviceInfo->DeviceAddress = 0;
|
|
DeviceInfo->HubAddress = 0; //FIXME
|
|
DeviceInfo->DeviceSpeed = UsbHighSpeed; //FIXME
|
|
DeviceInfo->DeviceType = Usb20Device; //FIXME
|
|
DeviceInfo->NumberOfOpenPipes = 0; //FIXME
|
|
|
|
//
|
|
// get device descriptor
|
|
//
|
|
RtlMoveMemory(&DeviceInfo->DeviceDescriptor, ROOTHUB2_DEVICE_DESCRIPTOR, sizeof(USB_DEVICE_DESCRIPTOR));
|
|
|
|
//
|
|
// FIXME return pipe information
|
|
//
|
|
|
|
//
|
|
// store result length
|
|
//
|
|
#ifdef _MSC_VER
|
|
*LengthReturned = FIELD_OFFSET(USB_DEVICE_INFORMATION_0, PipeList[DeviceInfo->NumberOfOpenPipes]);
|
|
#else
|
|
*LengthReturned = sizeof(USB_DEVICE_INFORMATION_0) + (DeviceInfo->NumberOfOpenPipes > 1 ? (DeviceInfo->NumberOfOpenPipes - 1) * sizeof(USB_PIPE_INFORMATION_0) : 0);
|
|
#endif
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_GetControllerInformation(
|
|
PVOID BusContext,
|
|
PVOID ControllerInformationBuffer,
|
|
ULONG ControllerInformationBufferLength,
|
|
PULONG LengthReturned)
|
|
{
|
|
PUSB_CONTROLLER_INFORMATION_0 ControllerInfo;
|
|
|
|
DPRINT1("USBHI_GetControllerInformation\n");
|
|
|
|
//
|
|
// sanity checks
|
|
//
|
|
PC_ASSERT(ControllerInformationBuffer);
|
|
PC_ASSERT(ControllerInformationBufferLength >= sizeof(USB_CONTROLLER_INFORMATION_0));
|
|
|
|
//
|
|
// get controller info buffer
|
|
//
|
|
ControllerInfo = (PUSB_CONTROLLER_INFORMATION_0)ControllerInformationBuffer;
|
|
|
|
//
|
|
// FIXME only version 0 is supported for now
|
|
//
|
|
PC_ASSERT(ControllerInfo->InformationLevel == 0);
|
|
|
|
//
|
|
// fill in information
|
|
//
|
|
ControllerInfo->ActualLength = sizeof(USB_CONTROLLER_INFORMATION_0);
|
|
ControllerInfo->SelectiveSuspendEnabled = FALSE; //FIXME
|
|
ControllerInfo->IsHighSpeedController = TRUE;
|
|
|
|
//
|
|
// set length returned
|
|
//
|
|
*LengthReturned = ControllerInfo->ActualLength;
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_ControllerSelectiveSuspend(
|
|
PVOID BusContext,
|
|
BOOLEAN Enable)
|
|
{
|
|
UNIMPLEMENTED
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_GetExtendedHubInformation(
|
|
PVOID BusContext,
|
|
PDEVICE_OBJECT HubPhysicalDeviceObject,
|
|
PVOID HubInformationBuffer,
|
|
ULONG HubInformationBufferLength,
|
|
PULONG LengthReturned)
|
|
{
|
|
PUSB_EXTHUB_INFORMATION_0 HubInfo;
|
|
CHubController * Controller;
|
|
PUSBHARDWAREDEVICE Hardware;
|
|
ULONG Index;
|
|
ULONG NumPort, Dummy2;
|
|
USHORT Dummy1;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT1("USBHI_GetExtendedHubInformation\n");
|
|
|
|
//
|
|
// sanity checks
|
|
//
|
|
PC_ASSERT(HubInformationBuffer);
|
|
PC_ASSERT(HubInformationBufferLength == sizeof(USB_EXTHUB_INFORMATION_0));
|
|
PC_ASSERT(LengthReturned);
|
|
|
|
//
|
|
// get hub controller
|
|
//
|
|
Controller = (CHubController *)BusContext;
|
|
PC_ASSERT(Controller);
|
|
|
|
//
|
|
// get usb hardware device
|
|
//
|
|
Hardware = Controller->GetUsbHardware();
|
|
|
|
//
|
|
// retrieve number of ports
|
|
//
|
|
Status = Hardware->GetDeviceDetails(&Dummy1, &Dummy1, &NumPort, &Dummy2);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// failed to get hardware details, ouch ;)
|
|
//
|
|
DPRINT1("USBHI_GetExtendedHubInformation failed to get hardware details with %x\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// get hub information buffer
|
|
//
|
|
HubInfo = (PUSB_EXTHUB_INFORMATION_0)HubInformationBuffer;
|
|
|
|
//
|
|
// initialize hub information
|
|
//
|
|
HubInfo->InformationLevel = 0;
|
|
|
|
//
|
|
// store port count
|
|
//
|
|
HubInfo->NumberOfPorts = NumPort;
|
|
|
|
//
|
|
// initialize port information
|
|
//
|
|
for(Index = 0; Index < NumPort; Index++)
|
|
{
|
|
HubInfo->Port[Index].PhysicalPortNumber = Index + 1;
|
|
HubInfo->Port[Index].PortLabelNumber = Index + 1;
|
|
HubInfo->Port[Index].VidOverride = 0;
|
|
HubInfo->Port[Index].PidOverride = 0;
|
|
HubInfo->Port[Index].PortAttributes = USB_PORTATTR_SHARED_USB2; //FIXME
|
|
}
|
|
|
|
//
|
|
// store result length
|
|
//
|
|
#ifdef _MSC_VER
|
|
*LengthReturned = FIELD_OFFSET(USB_EXTHUB_INFORMATION_0, Port[HubInfo->NumberOfPorts]);
|
|
#else
|
|
*LengthReturned = FIELD_OFFSET(USB_EXTHUB_INFORMATION_0, Port) + sizeof(USB_EXTPORT_INFORMATION_0) * HubInfo->NumberOfPorts;
|
|
#endif
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_GetRootHubSymbolicName(
|
|
PVOID BusContext,
|
|
PVOID HubSymNameBuffer,
|
|
ULONG HubSymNameBufferLength,
|
|
PULONG HubSymNameActualLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
PVOID
|
|
USB_BUSIFFN
|
|
USBHI_GetDeviceBusContext(
|
|
PVOID HubBusContext,
|
|
PVOID DeviceHandle)
|
|
{
|
|
UNIMPLEMENTED
|
|
return NULL;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_Initialize20Hub(
|
|
PVOID BusContext,
|
|
PUSB_DEVICE_HANDLE HubDeviceHandle,
|
|
ULONG TtCount)
|
|
{
|
|
DPRINT("USBHI_Initialize20Hub HubDeviceHandle %p UNIMPLEMENTED TtCount %lu\n", HubDeviceHandle, TtCount);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBHI_RootHubInitNotification(
|
|
PVOID BusContext,
|
|
PVOID CallbackContext,
|
|
PRH_INIT_CALLBACK CallbackRoutine)
|
|
{
|
|
CHubController * Controller;
|
|
|
|
DPRINT("USBHI_RootHubInitNotification %p \n", CallbackContext);
|
|
|
|
//
|
|
// get controller object
|
|
//
|
|
Controller = (CHubController*)BusContext;
|
|
PC_ASSERT(Controller);
|
|
|
|
//
|
|
// set notification routine
|
|
//
|
|
Controller->SetNotification(CallbackContext, CallbackRoutine);
|
|
|
|
//
|
|
// FIXME: determine when to perform callback
|
|
//
|
|
CallbackRoutine(CallbackContext);
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
USB_BUSIFFN
|
|
USBHI_FlushTransfers(
|
|
PVOID BusContext,
|
|
PVOID DeviceHandle)
|
|
{
|
|
UNIMPLEMENTED
|
|
}
|
|
|
|
VOID
|
|
USB_BUSIFFN
|
|
USBHI_SetDeviceHandleData(
|
|
PVOID BusContext,
|
|
PVOID DeviceHandle,
|
|
PDEVICE_OBJECT UsbDevicePdo)
|
|
{
|
|
PUSBDEVICE UsbDevice;
|
|
CHubController * Controller;
|
|
|
|
//
|
|
// get controller
|
|
//
|
|
Controller = (CHubController *)BusContext;
|
|
PC_ASSERT(Controller);
|
|
|
|
//
|
|
// get device handle
|
|
//
|
|
UsbDevice = (PUSBDEVICE)DeviceHandle;
|
|
|
|
//
|
|
// validate device handle
|
|
//
|
|
if (!Controller->ValidateUsbDevice(UsbDevice))
|
|
{
|
|
DPRINT1("USBHI_SetDeviceHandleData DeviceHandle %p is invalid\n", DeviceHandle);
|
|
|
|
//
|
|
// invalid handle
|
|
//
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// usbhub sends this request as a part of the Pnp startup sequence
|
|
// looks like we need apply a dragon voodoo to fixup the device stack
|
|
// otherwise usbhub will cause a bugcheck
|
|
//
|
|
DPRINT1("USBHI_SetDeviceHandleData %p\n", UsbDevicePdo);
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
PC_ASSERT(UsbDevicePdo->AttachedDevice);
|
|
|
|
//
|
|
// should be usbstor
|
|
// fixup device stack voodoo part #2
|
|
//
|
|
UsbDevicePdo->AttachedDevice->StackSize++;
|
|
|
|
//
|
|
// set device handle data
|
|
//
|
|
UsbDevice->SetDeviceHandleData(UsbDevicePdo);
|
|
}
|
|
}
|
|
|
|
//=================================================================================================
|
|
//
|
|
// USB Device Interface functions
|
|
//
|
|
|
|
VOID
|
|
USB_BUSIFFN
|
|
USBDI_GetUSBDIVersion(
|
|
PVOID BusContext,
|
|
PUSBD_VERSION_INFORMATION VersionInformation,
|
|
PULONG HcdCapabilites)
|
|
{
|
|
CHubController * Controller;
|
|
PUSBHARDWAREDEVICE Device;
|
|
ULONG Speed, Dummy2;
|
|
USHORT Dummy1;
|
|
|
|
DPRINT1("USBDI_GetUSBDIVersion\n");
|
|
|
|
//
|
|
// get controller
|
|
//
|
|
Controller = (CHubController*)BusContext;
|
|
|
|
//
|
|
// get usb hardware
|
|
//
|
|
Device = Controller->GetUsbHardware();
|
|
PC_ASSERT(Device);
|
|
|
|
if (VersionInformation)
|
|
{
|
|
//
|
|
// windows xp supported
|
|
//
|
|
VersionInformation->USBDI_Version = 0x00000500;
|
|
|
|
//
|
|
// get device speed
|
|
//
|
|
Device->GetDeviceDetails(&Dummy1, &Dummy1, &Dummy2, &Speed);
|
|
|
|
//
|
|
// store speed details
|
|
//
|
|
VersionInformation->Supported_USB_Version = Speed;
|
|
}
|
|
|
|
//
|
|
// no flags supported
|
|
//
|
|
*HcdCapabilites = 0;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBDI_QueryBusTime(
|
|
PVOID BusContext,
|
|
PULONG CurrentFrame)
|
|
{
|
|
UNIMPLEMENTED
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBDI_SubmitIsoOutUrb(
|
|
PVOID BusContext,
|
|
PURB Urb)
|
|
{
|
|
UNIMPLEMENTED
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBDI_QueryBusInformation(
|
|
PVOID BusContext,
|
|
ULONG Level,
|
|
PVOID BusInformationBuffer,
|
|
PULONG BusInformationBufferLength,
|
|
PULONG BusInformationActualLength)
|
|
{
|
|
UNIMPLEMENTED
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
BOOLEAN
|
|
USB_BUSIFFN
|
|
USBDI_IsDeviceHighSpeed(
|
|
PVOID BusContext)
|
|
{
|
|
CHubController * Controller;
|
|
PUSBHARDWAREDEVICE Device;
|
|
ULONG Speed, Dummy2;
|
|
USHORT Dummy1;
|
|
|
|
DPRINT1("USBDI_IsDeviceHighSpeed\n");
|
|
|
|
//
|
|
// get controller
|
|
//
|
|
Controller = (CHubController*)BusContext;
|
|
|
|
//
|
|
// get usb hardware
|
|
//
|
|
Device = Controller->GetUsbHardware();
|
|
PC_ASSERT(Device);
|
|
|
|
//
|
|
// get device speed
|
|
//
|
|
Device->GetDeviceDetails(&Dummy1, &Dummy1, &Dummy2, &Speed);
|
|
|
|
//
|
|
// USB 2.0 equals 0x200
|
|
//
|
|
return (Speed == 0x200);
|
|
}
|
|
|
|
NTSTATUS
|
|
USB_BUSIFFN
|
|
USBDI_EnumLogEntry(
|
|
PVOID BusContext,
|
|
ULONG DriverTag,
|
|
ULONG EnumTag,
|
|
ULONG P1,
|
|
ULONG P2)
|
|
{
|
|
UNIMPLEMENTED
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
CHubController::HandleQueryInterface(
|
|
PIO_STACK_LOCATION IoStack)
|
|
{
|
|
PUSB_BUS_INTERFACE_HUB_V5 InterfaceHub;
|
|
PUSB_BUS_INTERFACE_USBDI_V2 InterfaceDI;
|
|
UNICODE_STRING GuidBuffer;
|
|
NTSTATUS Status;
|
|
|
|
if (IsEqualGUIDAligned(*IoStack->Parameters.QueryInterface.InterfaceType, USB_BUS_INTERFACE_HUB_GUID))
|
|
{
|
|
//
|
|
// get request parameters
|
|
//
|
|
InterfaceHub = (PUSB_BUS_INTERFACE_HUB_V5)IoStack->Parameters.QueryInterface.Interface;
|
|
InterfaceHub->Version = IoStack->Parameters.QueryInterface.Version;
|
|
|
|
//
|
|
// check version
|
|
//
|
|
if (IoStack->Parameters.QueryInterface.Version >= 6)
|
|
{
|
|
DPRINT1("USB_BUS_INTERFACE_HUB_GUID version %x not supported!\n", IoStack->Parameters.QueryInterface.Version);
|
|
|
|
//
|
|
// version not supported
|
|
//
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Interface version 0
|
|
//
|
|
if (IoStack->Parameters.QueryInterface.Version >= 0)
|
|
{
|
|
InterfaceHub->Size = IoStack->Parameters.QueryInterface.Size;
|
|
InterfaceHub->BusContext = PVOID(this);
|
|
InterfaceHub->InterfaceReference = USBI_InterfaceReference;
|
|
InterfaceHub->InterfaceDereference = USBI_InterfaceDereference;
|
|
}
|
|
|
|
//
|
|
// Interface version 1
|
|
//
|
|
if (IoStack->Parameters.QueryInterface.Version >= 1)
|
|
{
|
|
InterfaceHub->CreateUsbDevice = USBHI_CreateUsbDevice;
|
|
InterfaceHub->InitializeUsbDevice = USBHI_InitializeUsbDevice;
|
|
InterfaceHub->GetUsbDescriptors = USBHI_GetUsbDescriptors;
|
|
InterfaceHub->RemoveUsbDevice = USBHI_RemoveUsbDevice;
|
|
InterfaceHub->RestoreUsbDevice = USBHI_RestoreUsbDevice;
|
|
InterfaceHub->QueryDeviceInformation = USBHI_QueryDeviceInformation;
|
|
}
|
|
|
|
//
|
|
// Interface version 2
|
|
//
|
|
if (IoStack->Parameters.QueryInterface.Version >= 2)
|
|
{
|
|
InterfaceHub->GetControllerInformation = USBHI_GetControllerInformation;
|
|
InterfaceHub->ControllerSelectiveSuspend = USBHI_ControllerSelectiveSuspend;
|
|
InterfaceHub->GetExtendedHubInformation = USBHI_GetExtendedHubInformation;
|
|
InterfaceHub->GetRootHubSymbolicName = USBHI_GetRootHubSymbolicName;
|
|
InterfaceHub->GetDeviceBusContext = USBHI_GetDeviceBusContext;
|
|
InterfaceHub->Initialize20Hub = USBHI_Initialize20Hub;
|
|
|
|
}
|
|
|
|
//
|
|
// Interface version 3
|
|
//
|
|
if (IoStack->Parameters.QueryInterface.Version >= 3)
|
|
{
|
|
InterfaceHub->RootHubInitNotification = USBHI_RootHubInitNotification;
|
|
}
|
|
|
|
//
|
|
// Interface version 4
|
|
//
|
|
if (IoStack->Parameters.QueryInterface.Version >= 4)
|
|
{
|
|
InterfaceHub->FlushTransfers = USBHI_FlushTransfers;
|
|
}
|
|
|
|
//
|
|
// Interface version 5
|
|
//
|
|
if (IoStack->Parameters.QueryInterface.Version >= 5)
|
|
{
|
|
InterfaceHub->SetDeviceHandleData = USBHI_SetDeviceHandleData;
|
|
}
|
|
|
|
//
|
|
// request completed
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else if (IsEqualGUIDAligned(*IoStack->Parameters.QueryInterface.InterfaceType, USB_BUS_INTERFACE_USBDI_GUID))
|
|
{
|
|
//
|
|
// get request parameters
|
|
//
|
|
InterfaceDI = (PUSB_BUS_INTERFACE_USBDI_V2) IoStack->Parameters.QueryInterface.Interface;
|
|
InterfaceDI->Version = IoStack->Parameters.QueryInterface.Version;
|
|
|
|
//
|
|
// check version
|
|
//
|
|
if (IoStack->Parameters.QueryInterface.Version >= 3)
|
|
{
|
|
DPRINT1("USB_BUS_INTERFACE_USBDI_GUID version %x not supported!\n", IoStack->Parameters.QueryInterface.Version);
|
|
|
|
//
|
|
// version not supported
|
|
//
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// interface version 0
|
|
//
|
|
if (IoStack->Parameters.QueryInterface.Version >= 0)
|
|
{
|
|
InterfaceDI->Size = IoStack->Parameters.QueryInterface.Size;
|
|
InterfaceDI->BusContext = PVOID(this);
|
|
InterfaceDI->InterfaceReference = USBI_InterfaceReference;
|
|
InterfaceDI->InterfaceDereference = USBI_InterfaceDereference;
|
|
InterfaceDI->GetUSBDIVersion = USBDI_GetUSBDIVersion;
|
|
InterfaceDI->QueryBusTime = USBDI_QueryBusTime;
|
|
InterfaceDI->SubmitIsoOutUrb = USBDI_SubmitIsoOutUrb;
|
|
InterfaceDI->QueryBusInformation = USBDI_QueryBusInformation;
|
|
}
|
|
|
|
//
|
|
// interface version 1
|
|
//
|
|
if (IoStack->Parameters.QueryInterface.Version >= 1)
|
|
{
|
|
InterfaceDI->IsDeviceHighSpeed = USBDI_IsDeviceHighSpeed;
|
|
}
|
|
|
|
//
|
|
// interface version 2
|
|
//
|
|
if (IoStack->Parameters.QueryInterface.Version >= 2)
|
|
{
|
|
InterfaceDI->EnumLogEntry = USBDI_EnumLogEntry;
|
|
}
|
|
|
|
//
|
|
// request completed
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// convert guid to string
|
|
//
|
|
Status = RtlStringFromGUID(*IoStack->Parameters.QueryInterface.InterfaceType, &GuidBuffer);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// print interface
|
|
//
|
|
DPRINT1("HandleQueryInterface UNKNOWN INTERFACE GUID: %wZ Version %x\n", &GuidBuffer, IoStack->Parameters.QueryInterface.Version);
|
|
|
|
//
|
|
// free guid buffer
|
|
//
|
|
RtlFreeUnicodeString(&GuidBuffer);
|
|
}
|
|
}
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
CHubController::SetDeviceInterface(
|
|
BOOLEAN Enable)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
if (Enable)
|
|
{
|
|
//
|
|
// register device interface
|
|
//
|
|
Status = IoRegisterDeviceInterface(m_HubControllerDeviceObject, &GUID_DEVINTERFACE_USB_HUB, 0, &m_HubDeviceInterfaceString);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// now enable the device interface
|
|
//
|
|
Status = IoSetDeviceInterfaceState(&m_HubDeviceInterfaceString, TRUE);
|
|
|
|
//
|
|
// enable interface
|
|
//
|
|
m_InterfaceEnabled = TRUE;
|
|
}
|
|
}
|
|
else if (m_InterfaceEnabled)
|
|
{
|
|
//
|
|
// disable device interface
|
|
//
|
|
Status = IoSetDeviceInterfaceState(&m_HubDeviceInterfaceString, FALSE);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// now delete interface string
|
|
//
|
|
RtlFreeUnicodeString(&m_HubDeviceInterfaceString);
|
|
}
|
|
|
|
//
|
|
// disable interface
|
|
//
|
|
m_InterfaceEnabled = FALSE;
|
|
}
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
CHubController::CreatePDO(
|
|
PDRIVER_OBJECT DriverObject,
|
|
PDEVICE_OBJECT * OutDeviceObject)
|
|
{
|
|
WCHAR CharDeviceName[64];
|
|
NTSTATUS Status;
|
|
ULONG UsbDeviceNumber = 0;
|
|
UNICODE_STRING DeviceName;
|
|
|
|
while (TRUE)
|
|
{
|
|
//
|
|
// construct device name
|
|
//
|
|
swprintf(CharDeviceName, L"\\Device\\USBPDO-%d", UsbDeviceNumber);
|
|
|
|
//
|
|
// initialize device name
|
|
//
|
|
RtlInitUnicodeString(&DeviceName, CharDeviceName);
|
|
|
|
//
|
|
// create device
|
|
//
|
|
Status = IoCreateDevice(DriverObject,
|
|
sizeof(COMMON_DEVICE_EXTENSION),
|
|
&DeviceName,
|
|
FILE_DEVICE_CONTROLLER,
|
|
0,
|
|
FALSE,
|
|
OutDeviceObject);
|
|
|
|
/* check for success */
|
|
if (NT_SUCCESS(Status))
|
|
break;
|
|
|
|
//
|
|
// is there a device object with that same name
|
|
//
|
|
if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
|
|
{
|
|
//
|
|
// Try the next name
|
|
//
|
|
UsbDeviceNumber++;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// bail out on other errors
|
|
//
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("CreatePDO: Failed to create %wZ, Status %x\n", &DeviceName, Status);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
DPRINT1("CHubController::CreatePDO: DeviceName %wZ\n", &DeviceName);
|
|
|
|
//
|
|
// fixup device stack voodoo part #1
|
|
//
|
|
(*OutDeviceObject)->StackSize++;
|
|
|
|
/* done */
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CreateHubController(
|
|
PHUBCONTROLLER *OutHcdController)
|
|
{
|
|
PHUBCONTROLLER This;
|
|
|
|
//
|
|
// allocate controller
|
|
//
|
|
This = new(NonPagedPool, TAG_USBEHCI) CHubController(0);
|
|
if (!This)
|
|
{
|
|
//
|
|
// failed to allocate
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// add reference count
|
|
//
|
|
This->AddRef();
|
|
|
|
//
|
|
// return result
|
|
//
|
|
*OutHcdController = (PHUBCONTROLLER)This;
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID StatusChangeEndpointCallBack(PVOID Context)
|
|
{
|
|
CHubController* This;
|
|
PIRP Irp;
|
|
This = (CHubController*)Context;
|
|
|
|
ASSERT(This);
|
|
|
|
Irp = This->m_PendingSCEIrp;
|
|
if (!Irp)
|
|
{
|
|
DPRINT1("There was no pending IRP for SCE. Did the usb hub 2.0 driver (usbhub2) load?\n");
|
|
return;
|
|
}
|
|
|
|
This->m_PendingSCEIrp = NULL;
|
|
This->QueryStatusChageEndpoint(Irp);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|