You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2349 lines
69 KiB
2349 lines
69 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
roothub.c
|
|
|
|
Abstract:
|
|
|
|
root hub emultation code for usbport driver
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
6-21-99 : created
|
|
|
|
--*/
|
|
|
|
#include "common.h"
|
|
|
|
// paged functions
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, USBPORT_RootHub_CreateDevice)
|
|
#pragma alloc_text(PAGE, USBPORT_RootHub_RemoveDevice)
|
|
#endif
|
|
|
|
// non paged functions
|
|
// USBPORT_RootHub_StandardCommand
|
|
// USBPORT_RootHub_ClassCommand
|
|
// USBPORT_RootHub_Endpoint0
|
|
// USBPORT_RootHub_Endpoint1
|
|
// USBPORT_RootHub_EndpointWorker
|
|
// USBPORT_SetBit
|
|
// USBPORTSVC_InvalidateRootHub
|
|
// USBPORT_RootHub_PortRequest
|
|
|
|
#define RH_STANDARD_REQ 0
|
|
#define RH_CLASS_REQ 1
|
|
|
|
#define MIN(x, y) (((x)<(y)) ? (x) : (y))
|
|
|
|
//
|
|
// HUB feature selectors
|
|
//
|
|
#define C_HUB_LOCAL_POWER 0
|
|
#define C_HUB_OVER_CURRENT 1
|
|
#define PORT_CONNECTION 0
|
|
#define PORT_ENABLE 1
|
|
#define PORT_SUSPEND 2
|
|
#define PORT_OVER_CURRENT 3
|
|
#define PORT_RESET 4
|
|
#define PORT_POWER 8
|
|
#define PORT_LOW_SPEED 9
|
|
#define C_PORT_CONNECTION 16
|
|
#define C_PORT_ENABLE 17
|
|
#define C_PORT_SUSPEND 18
|
|
#define C_PORT_OVER_CURRENT 19
|
|
#define C_PORT_RESET 20
|
|
|
|
|
|
#define HUB_REQUEST_GET_STATUS 0
|
|
#define HUB_REQUEST_CLEAR_FEATURE 1
|
|
#define HUB_REQUEST_GET_STATE 2
|
|
#define HUB_REQUEST_SET_FEATURE 3
|
|
#define HUB_REQUEST_GET_DESCRIPTOR 6
|
|
#define HUB_REQUEST_SET_DESCRIPTOR 7
|
|
|
|
// recipient codes in the bRequestType field
|
|
#define RECIPIENT_DEVICE 0
|
|
#define RECIPIENT_INTRFACE 1
|
|
#define RECIPIENT_ENDPOINT 2
|
|
#define RECIPIENT_PORT 3
|
|
|
|
// Descriptor Templates
|
|
|
|
// the following structures are emulated the same
|
|
// way for all port drivers
|
|
|
|
UCHAR RH_DeviceDescriptor[] = {0x12, //bLength
|
|
0x01, //bDescrpitorType
|
|
0x00, 0x01, //bcdUSB
|
|
0x09, //bDeviceClass
|
|
0x01, //bDeviceSubClass
|
|
0x00, //bDeviceProtocol
|
|
0x08, //bMaxPacketSize0
|
|
0x00, 0x00, //idVendor
|
|
0x00, 0x00, //idProduct
|
|
0x00, 0x00, //bcdDevice
|
|
0x00, //iManufacturer
|
|
0x00, //iProduct
|
|
0x00, //iSerialNumber
|
|
0x01};//bNumConfigurations
|
|
|
|
UCHAR RH_ConfigurationDescriptor[] =
|
|
/* Config Descriptor */
|
|
{0x09, //bLength
|
|
0x02, //bDescriptorType
|
|
0x19, 0x00, //wTotalLength
|
|
0x01, //bNumInterfaces
|
|
0x23, //iConfigurationValue
|
|
0x00, //iConfiguration
|
|
0x40, //bmAttributes
|
|
0x00, //MaxPower
|
|
|
|
/* Interface Descriptor */
|
|
0x09, //bLength
|
|
0x04, //bDescriptorType
|
|
0x00, //bInterfaceNumber
|
|
0x00, //bAlternateSetting
|
|
0x01, //bNumEndpoints
|
|
0x09, //bInterfaceClass
|
|
0x01, //bInterfaceSubClass
|
|
0x00, //bInterfaceProtocol
|
|
0x00, //iInterface
|
|
|
|
/* Endpoint Descriptor */
|
|
0x07, //bLength
|
|
0x05, //bDescriptorType
|
|
0x81, //bEndpointAddress
|
|
0x03, //bmAttributes
|
|
0x08, 0x00, //wMaxPacketSize
|
|
0x0a};//bInterval
|
|
|
|
UCHAR RH_HubDescriptor[] =
|
|
{0x09, //bLength
|
|
0x29, //bDescriptorType
|
|
0x00, //bNbrPorts
|
|
0x00, 0x00, //wHubCharacteristics
|
|
0x00, // bPwrOn2PwrGood
|
|
0x00}; // bHubContrCurrent
|
|
|
|
|
|
|
|
#define RH_DEV_TO_HOST 1
|
|
#define RH_HOST_TO_DEV 0
|
|
|
|
|
|
RHSTATUS
|
|
USBPORT_RootHub_PortRequest(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
|
PORT_OPERATION PortOperation
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a standard command sent on the control endpoint
|
|
of the root hub.
|
|
|
|
Arguments:
|
|
|
|
SetupPacket - pointer to a SetupPacket packet
|
|
|
|
Return Value:
|
|
|
|
Root Hub status code.
|
|
|
|
--*/
|
|
{
|
|
PVOID descriptor = NULL;
|
|
ULONG length;
|
|
RHSTATUS rhStatus = RH_STALL;
|
|
PDEVICE_EXTENSION devExt, rhDevExt;
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
|
|
ASSERT_PDOEXT(rhDevExt);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rSCM', SetupPacket, 0, 0);
|
|
|
|
if (SetupPacket->wIndex.W > 0 &&
|
|
SetupPacket->wIndex.W <= NUMBER_OF_PORTS(rhDevExt)) {
|
|
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
|
|
switch(PortOperation) {
|
|
case SetFeaturePortReset:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortReset(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
break;
|
|
case SetFeaturePortPower:
|
|
if (USBPORT_IS_USB20(devExt)) {
|
|
mpStatus = USBPORT_RootHub_PowerUsb2Port(FdoDeviceObject,
|
|
SetupPacket->wIndex.W);
|
|
} else if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IS_CC)) {
|
|
mpStatus = USBPORT_RootHub_PowerUsbCcPort(FdoDeviceObject,
|
|
SetupPacket->wIndex.W);
|
|
} else {
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortPower(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
}
|
|
break;
|
|
case SetFeaturePortEnable:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortEnable(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
break;
|
|
case SetFeaturePortSuspend:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortSuspend(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
break;
|
|
case ClearFeaturePortEnable:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortEnable(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
break;
|
|
case ClearFeaturePortPower:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortPower(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
break;
|
|
case ClearFeaturePortConnectChange:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortConnectChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
break;
|
|
case ClearFeaturePortResetChange:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortResetChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
break;
|
|
case ClearFeaturePortEnableChange:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortEnableChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
break;
|
|
case ClearFeaturePortSuspend:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortSuspend(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
break;
|
|
case ClearFeaturePortSuspendChange:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortSuspendChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
break;
|
|
case ClearFeaturePortOvercurrentChange:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortOvercurrentChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
SetupPacket->wIndex.W);
|
|
break;
|
|
default:
|
|
mpStatus = USBMP_STATUS_FAILURE;
|
|
DEBUG_BREAK();
|
|
}
|
|
|
|
rhStatus = MPSTATUS_TO_RHSTATUS(mpStatus);
|
|
|
|
} else {
|
|
rhStatus = RH_STALL;
|
|
DEBUG_BREAK();
|
|
}
|
|
|
|
return rhStatus;
|
|
}
|
|
|
|
|
|
RHSTATUS
|
|
USBPORT_RootHub_HubRequest(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PORT_OPERATION PortOperation
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a standard command sent on the control endpoint
|
|
of the root hub.
|
|
|
|
Arguments:
|
|
|
|
SetupPacket - pointer to a SetupPacket packet
|
|
|
|
Return Value:
|
|
|
|
Root Hub status code.
|
|
|
|
--*/
|
|
{
|
|
RHSTATUS rhStatus = RH_STALL;
|
|
PDEVICE_EXTENSION devExt, rhDevExt;
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
|
|
ASSERT_PDOEXT(rhDevExt);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'hSCM', 0, 0, 0);
|
|
|
|
switch(PortOperation) {
|
|
case ClearFeaturePortOvercurrentChange:
|
|
mpStatus =
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortOvercurrentChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
0);
|
|
rhStatus = MPSTATUS_TO_RHSTATUS(mpStatus);
|
|
break;
|
|
}
|
|
|
|
return rhStatus;
|
|
|
|
}
|
|
|
|
|
|
RHSTATUS
|
|
USBPORT_RootHub_StandardCommand(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
|
PUCHAR Buffer,
|
|
PULONG BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a standard command sent on the control endpoint
|
|
of the root hub.
|
|
|
|
Arguments:
|
|
|
|
SetupPacket - pointer to a SetupPacket packet
|
|
|
|
Return Value:
|
|
|
|
Root Hub status code.
|
|
|
|
--*/
|
|
{
|
|
PVOID descriptor = NULL;
|
|
ULONG length;
|
|
RHSTATUS rhStatus = RH_STALL;
|
|
PDEVICE_EXTENSION devExt, rhDevExt;
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
|
|
ASSERT_PDOEXT(rhDevExt);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rSCM', SetupPacket, 0, 0);
|
|
|
|
//
|
|
// switch on the command
|
|
//
|
|
switch (SetupPacket->bRequest) {
|
|
case USB_REQUEST_SET_ADDRESS:
|
|
//
|
|
//
|
|
//
|
|
if (SetupPacket->wIndex.W == 0 &&
|
|
SetupPacket->wLength == 0 &&
|
|
SetupPacket->bmRequestType.Dir == RH_HOST_TO_DEV) {
|
|
rhDevExt->Pdo.RootHubDeviceHandle.DeviceAddress =
|
|
(UCHAR)SetupPacket->wValue.W;
|
|
|
|
rhStatus = RH_SUCCESS;
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rSAD', 0, 0, 0);
|
|
}
|
|
break;
|
|
|
|
case USB_REQUEST_GET_DESCRIPTOR:
|
|
{
|
|
ULONG siz;
|
|
UCHAR descriptorIndex, descriptorType;
|
|
|
|
descriptorType = (UCHAR) SetupPacket->wValue.HiByte;
|
|
descriptorIndex = (UCHAR) SetupPacket->wValue.LowByte;
|
|
|
|
switch (descriptorType) {
|
|
|
|
case USB_DEVICE_DESCRIPTOR_TYPE:
|
|
if (descriptorIndex == 0 &&
|
|
SetupPacket->bmRequestType.Dir == RH_DEV_TO_HOST) {
|
|
|
|
siz = sizeof(RH_DeviceDescriptor);
|
|
// use PDO specific copy
|
|
descriptor = rhDevExt->Pdo.DeviceDescriptor;
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rGDS', descriptor, siz, 0);
|
|
}
|
|
break;
|
|
|
|
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
|
|
if (descriptorIndex == 0 &&
|
|
SetupPacket->bmRequestType.Dir == RH_DEV_TO_HOST) {
|
|
siz = sizeof(RH_ConfigurationDescriptor);
|
|
// use pdo specific copy
|
|
descriptor = rhDevExt->Pdo.ConfigurationDescriptor;
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rGCS', descriptor, siz, 0);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// BUGBUG these descriptor types not handled
|
|
//
|
|
case USB_STRING_DESCRIPTOR_TYPE:
|
|
// we will stall
|
|
TEST_TRAP();
|
|
default:
|
|
// we will stall
|
|
DEBUG_BREAK();
|
|
} /* descriptorType */
|
|
|
|
if (descriptor) {
|
|
|
|
length = MIN(*BufferLength, siz);
|
|
|
|
RtlCopyMemory(Buffer, descriptor, length);
|
|
*BufferLength = length;
|
|
rhStatus = RH_SUCCESS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case USB_REQUEST_GET_STATUS:
|
|
//
|
|
// get_device_status
|
|
//
|
|
// report that we are self powered
|
|
//
|
|
// BUGBUG
|
|
// are we self powered?
|
|
// are we a remote wakeup source?
|
|
//
|
|
// see section 9.4.5 USB 1.0 spec
|
|
//
|
|
{
|
|
PUSHORT status = (PUSHORT) Buffer;
|
|
|
|
if (SetupPacket->wValue.W == 0 && //mbz
|
|
SetupPacket->wLength == 2 &&
|
|
SetupPacket->wIndex.W == 0 && //device
|
|
SetupPacket->bmRequestType.Dir == RH_DEV_TO_HOST) {
|
|
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
|
|
MPRH_GetStatus(devExt, status, mpStatus);
|
|
|
|
*BufferLength = sizeof(*status);
|
|
|
|
rhStatus = MPSTATUS_TO_RHSTATUS(mpStatus);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case USB_REQUEST_GET_CONFIGURATION:
|
|
//
|
|
// get_device_configuration
|
|
//
|
|
if (SetupPacket->wValue.W == 0 && //mbz
|
|
SetupPacket->wIndex.W == 0 && //mbz
|
|
SetupPacket->wLength == 1 &&
|
|
SetupPacket->bmRequestType.Dir == RH_DEV_TO_HOST) {
|
|
|
|
length = MIN(*BufferLength, sizeof(rhDevExt->Pdo.ConfigurationValue));
|
|
RtlCopyMemory(Buffer, &rhDevExt->Pdo.ConfigurationValue, length);
|
|
*BufferLength = length;
|
|
rhStatus = RH_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case USB_REQUEST_CLEAR_FEATURE:
|
|
// bugbug, required
|
|
TEST_TRAP();
|
|
break;
|
|
|
|
case USB_REQUEST_SET_CONFIGURATION:
|
|
{
|
|
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor =
|
|
(PUSB_CONFIGURATION_DESCRIPTOR) RH_ConfigurationDescriptor;
|
|
|
|
if (SetupPacket->wIndex.W == 0 && // mbz
|
|
SetupPacket->wLength == 0 && // mbz
|
|
SetupPacket->bmRequestType.Dir == RH_HOST_TO_DEV &&
|
|
(SetupPacket->wValue.W ==
|
|
configurationDescriptor->bConfigurationValue ||
|
|
SetupPacket->wValue.W == 0)) {
|
|
|
|
rhDevExt->Pdo.ConfigurationValue =
|
|
(UCHAR) SetupPacket->wValue.W;
|
|
rhStatus = RH_SUCCESS;
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rSEC',
|
|
rhDevExt->Pdo.ConfigurationValue, 0, 0);
|
|
}
|
|
}
|
|
break;
|
|
case USB_REQUEST_SET_FEATURE:
|
|
// bugbug, required
|
|
TEST_TRAP();
|
|
break;
|
|
//
|
|
// these commands are optional for the hub
|
|
//
|
|
case USB_REQUEST_SET_DESCRIPTOR:
|
|
case USB_REQUEST_SET_INTERFACE:
|
|
case USB_REQUEST_GET_INTERFACE:
|
|
case USB_REQUEST_SYNC_FRAME:
|
|
default:
|
|
// bad command, probably a bug in the
|
|
// hub driver
|
|
DEBUG_BREAK();
|
|
break;
|
|
}
|
|
|
|
return rhStatus;
|
|
}
|
|
|
|
|
|
RHSTATUS
|
|
USBPORT_RootHub_ClassCommand(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
|
PUCHAR Buffer,
|
|
PULONG BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a hub class command to the root hub control endpoint.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Root Hub status code.
|
|
|
|
--*/
|
|
{
|
|
PVOID descriptor = NULL;
|
|
ULONG length;
|
|
RHSTATUS rhStatus = RH_STALL;
|
|
PDEVICE_EXTENSION devExt, rhDevExt;
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
|
|
ASSERT_PDOEXT(rhDevExt);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rCCM', SetupPacket, 0, 0);
|
|
|
|
//
|
|
// switch on the command
|
|
//
|
|
|
|
switch (SetupPacket->bRequest) {
|
|
case HUB_REQUEST_GET_STATUS:
|
|
//
|
|
//
|
|
//
|
|
if (SetupPacket->bmRequestType.Recipient == RECIPIENT_PORT) {
|
|
//
|
|
// get port status
|
|
//
|
|
PRH_PORT_STATUS portStatus;
|
|
//
|
|
// see if we have a valid request
|
|
//
|
|
|
|
if (Buffer != NULL &&
|
|
SetupPacket->wIndex.W > 0 &&
|
|
SetupPacket->wIndex.W <= NUMBER_OF_PORTS(rhDevExt) &&
|
|
SetupPacket->wLength >= sizeof(*portStatus)) {
|
|
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
|
|
USBPORT_ASSERT(sizeof(*portStatus) == 4);
|
|
USBPORT_ASSERT(*BufferLength >= sizeof(*portStatus));
|
|
portStatus = (PRH_PORT_STATUS) Buffer;
|
|
RtlZeroMemory(Buffer, sizeof(*portStatus));
|
|
|
|
MPRH_GetPortStatus(devExt,
|
|
SetupPacket->wIndex.W,
|
|
portStatus,
|
|
mpStatus);
|
|
|
|
rhStatus = MPSTATUS_TO_RHSTATUS(mpStatus);
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// get hub status
|
|
//
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
PRH_HUB_STATUS hubStatus;
|
|
|
|
if (Buffer != NULL) {
|
|
USBPORT_ASSERT(sizeof(*hubStatus) == 4);
|
|
USBPORT_ASSERT(*BufferLength >= sizeof(*hubStatus));
|
|
hubStatus = (PRH_HUB_STATUS) Buffer;
|
|
RtlZeroMemory(Buffer, sizeof(*hubStatus));
|
|
|
|
MPRH_GetHubStatus(devExt, hubStatus, mpStatus);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rGHS',
|
|
*((PULONG) hubStatus), 0, 0);
|
|
|
|
rhStatus = MPSTATUS_TO_RHSTATUS(mpStatus);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case HUB_REQUEST_CLEAR_FEATURE:
|
|
//
|
|
// Hub/Port Clear Feature
|
|
//
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rCFR',
|
|
SetupPacket->bmRequestType.Recipient, 0, 0);
|
|
if (SetupPacket->bmRequestType.Recipient == RECIPIENT_PORT) {
|
|
//
|
|
// clear port feature
|
|
//
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rCPR',
|
|
SetupPacket->wValue.W, 0, 0);
|
|
switch(SetupPacket->wValue.W) {
|
|
//
|
|
//
|
|
//
|
|
case PORT_ENABLE:
|
|
|
|
// disable the port
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
ClearFeaturePortEnable);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rDsP',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
break;
|
|
|
|
case PORT_POWER:
|
|
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
ClearFeaturePortPower);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rDpP',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
break;
|
|
//
|
|
// the following are not valid commands,
|
|
// return a stall since that is most likely
|
|
// what a real hub would do
|
|
//
|
|
case PORT_CONNECTION:
|
|
case PORT_OVER_CURRENT:
|
|
case PORT_LOW_SPEED:
|
|
case PORT_RESET:
|
|
DEBUG_BREAK();
|
|
break;
|
|
|
|
case C_PORT_CONNECTION:
|
|
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
ClearFeaturePortConnectChange);
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'cfCC',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
break;
|
|
|
|
case C_PORT_ENABLE:
|
|
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
ClearFeaturePortEnableChange);
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'cfEC',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
|
|
break;
|
|
|
|
case C_PORT_RESET:
|
|
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
ClearFeaturePortResetChange);
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'cfRC',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
|
|
break;
|
|
|
|
case PORT_SUSPEND:
|
|
|
|
// clearing port suspend generates resume signalling
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
ClearFeaturePortSuspend);
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'cfPS',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
|
|
break;
|
|
|
|
case C_PORT_SUSPEND:
|
|
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
ClearFeaturePortSuspendChange);
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'cfPS',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
|
|
break;
|
|
|
|
case C_PORT_OVER_CURRENT:
|
|
|
|
// overcuurent generated on NEC machines for ports with
|
|
// no device attached. We want to find out:
|
|
// 1. Does the port still function - Yes
|
|
// 2. Does the UI popup No
|
|
// the overcurrent occurs on the port with no device connected
|
|
// and the system in question has only one USB port.
|
|
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
ClearFeaturePortOvercurrentChange);
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'cfOC',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
|
|
break;
|
|
default:
|
|
DEBUG_BREAK();
|
|
}
|
|
} else {
|
|
//
|
|
// clear hub feature
|
|
//
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rCHR', SetupPacket->wValue.W, 0, 0);
|
|
switch(SetupPacket->wValue.W) {
|
|
case C_HUB_LOCAL_POWER:
|
|
rhStatus = RH_SUCCESS;
|
|
break;
|
|
case C_HUB_OVER_CURRENT:
|
|
rhStatus =
|
|
USBPORT_RootHub_HubRequest(FdoDeviceObject,
|
|
ClearFeaturePortOvercurrentChange);
|
|
break;
|
|
default:
|
|
DEBUG_BREAK();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case HUB_REQUEST_GET_STATE:
|
|
//
|
|
//
|
|
//
|
|
DEBUG_BREAK();
|
|
break;
|
|
|
|
case HUB_REQUEST_SET_FEATURE:
|
|
//
|
|
// Hub/Port feature request
|
|
//
|
|
if (SetupPacket->bmRequestType.Recipient == RECIPIENT_PORT) {
|
|
//
|
|
// set port feature
|
|
//
|
|
switch(SetupPacket->wValue.W) {
|
|
case PORT_RESET:
|
|
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
SetFeaturePortReset);
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'sfPR',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
break;
|
|
|
|
case PORT_SUSPEND:
|
|
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
SetFeaturePortSuspend);
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'sfPS',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
break;
|
|
|
|
case PORT_ENABLE:
|
|
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
SetFeaturePortEnable);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'sfPE',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
break;
|
|
|
|
case PORT_POWER:
|
|
|
|
rhStatus =
|
|
USBPORT_RootHub_PortRequest(FdoDeviceObject,
|
|
SetupPacket,
|
|
SetFeaturePortPower);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'sfPP',
|
|
SetupPacket->wIndex.W, 0, rhStatus);
|
|
break;
|
|
case PORT_CONNECTION:
|
|
case PORT_OVER_CURRENT:
|
|
case PORT_LOW_SPEED:
|
|
|
|
case C_PORT_CONNECTION:
|
|
case C_PORT_ENABLE:
|
|
case C_PORT_SUSPEND:
|
|
case C_PORT_OVER_CURRENT:
|
|
case C_PORT_RESET:
|
|
default:
|
|
DEBUG_BREAK();
|
|
}
|
|
} else {
|
|
//
|
|
// set hub feature
|
|
//
|
|
switch(SetupPacket->wValue.W) {
|
|
case C_HUB_LOCAL_POWER:
|
|
case C_HUB_OVER_CURRENT:
|
|
default:
|
|
DEBUG_BREAK();
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case HUB_REQUEST_GET_DESCRIPTOR:
|
|
//
|
|
// return the hub descriptor
|
|
//
|
|
if (Buffer != NULL &&
|
|
SetupPacket->wValue.W == 0 &&
|
|
// we already know it is a class command
|
|
SetupPacket->bmRequestType.Dir == RH_DEV_TO_HOST) {
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rGHD', SetupPacket, SetupPacket->wLength, 0);
|
|
|
|
length = MIN(*BufferLength, HUB_DESRIPTOR_LENGTH(rhDevExt));
|
|
|
|
RtlCopyMemory(Buffer, rhDevExt->Pdo.HubDescriptor, length);
|
|
*BufferLength = length;
|
|
rhStatus = RH_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case HUB_REQUEST_SET_DESCRIPTOR:
|
|
//
|
|
//
|
|
//
|
|
TEST_TRAP();
|
|
break;
|
|
|
|
default:
|
|
// bad command
|
|
DEBUG_BREAK();
|
|
break;
|
|
}
|
|
|
|
return rhStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
USBPORT_SetBit(
|
|
PVOID Bitmap,
|
|
ULONG BitNumber
|
|
)
|
|
/* ++
|
|
|
|
Description:
|
|
|
|
Set a bit in a given a string of bytes.
|
|
|
|
Arguments:
|
|
|
|
Return:
|
|
|
|
-- */
|
|
{
|
|
ULONG dwordOffset;
|
|
ULONG bitOffset;
|
|
PULONG l = (PULONG) Bitmap;
|
|
|
|
|
|
dwordOffset = BitNumber / 32;
|
|
bitOffset = BitNumber % 32;
|
|
|
|
l[dwordOffset] |= (1 << bitOffset);
|
|
}
|
|
|
|
|
|
RHSTATUS
|
|
USBPORT_RootHub_Endpoint1(
|
|
PHCD_TRANSFER_CONTEXT Transfer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
simulates an interrupt transfer
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
root hub transfer status code
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_OBJECT fdoDeviceObject;
|
|
PDEVICE_EXTENSION rhDevExt, devExt;
|
|
RHSTATUS rhStatus;
|
|
ULONG need;
|
|
RH_HUB_STATUS hubStatus;
|
|
PHCD_ENDPOINT endpoint;
|
|
PTRANSFER_URB urb;
|
|
PVOID buffer;
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
ULONG i;
|
|
|
|
ASSERT_TRANSFER(Transfer);
|
|
|
|
// assume no change
|
|
rhStatus = RH_NAK;
|
|
|
|
endpoint = Transfer->Endpoint;
|
|
ASSERT_ENDPOINT(endpoint);
|
|
|
|
fdoDeviceObject = endpoint->FdoDeviceObject;
|
|
|
|
GET_DEVICE_EXT(devExt, fdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_CONTROLLER_GONE)) {
|
|
return rhStatus;
|
|
}
|
|
|
|
GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
|
|
ASSERT_PDOEXT(rhDevExt);
|
|
|
|
USBPORT_ASSERT(rhDevExt->Pdo.HubInitCallback == NULL);
|
|
|
|
// validate the buffer length
|
|
urb = Transfer->Urb;
|
|
buffer = Transfer->Tp.TransferBufferLength ?
|
|
urb->TransferBufferMDL->MappedSystemVa :
|
|
NULL;
|
|
|
|
// compute how many bytes do we need to report a status
|
|
// change for any port
|
|
// 0,1-7 = 1
|
|
// 8-15 = 2
|
|
|
|
need = (NUMBER_OF_PORTS(rhDevExt)/8)+1;
|
|
|
|
if (buffer == NULL ||
|
|
Transfer->Tp.TransferBufferLength < need) {
|
|
|
|
DEBUG_BREAK();
|
|
rhStatus = RH_STALL;
|
|
goto USBPORT_RootHub_Endpoint1_Done;
|
|
}
|
|
|
|
// zero buffer in case hub driver did not
|
|
RtlZeroMemory(buffer, Transfer->Tp.TransferBufferLength);
|
|
|
|
// get the current port status and
|
|
// construct a bitmask of changed ports
|
|
|
|
for (i=0; i< NUMBER_OF_PORTS(rhDevExt); i++) {
|
|
|
|
RH_PORT_STATUS portStatus;
|
|
|
|
// usb spec does not allow more than 255 ports
|
|
USBPORT_ASSERT(i<256);
|
|
MPRH_GetPortStatus(devExt, (USHORT)(i+1), &portStatus, mpStatus);
|
|
|
|
LOGENTRY(NULL, fdoDeviceObject, LOG_RH, 'gPS+', portStatus.ul,
|
|
mpStatus, i+1);
|
|
|
|
if (mpStatus != USBMP_STATUS_SUCCESS ) {
|
|
DEBUG_BREAK();
|
|
rhStatus = RH_STALL;
|
|
goto USBPORT_RootHub_Endpoint1_Done;
|
|
}
|
|
|
|
if (portStatus.ConnectChange ||
|
|
portStatus.EnableChange ||
|
|
portStatus.SuspendChange ||
|
|
portStatus.OverCurrentChange ||
|
|
portStatus.ResetChange) {
|
|
|
|
USBPORT_SetBit(buffer,
|
|
i+1);
|
|
rhStatus = RH_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We created a bit map (base of 1 not 0) listing whether or not
|
|
// change has occurred on any of the down stream ports of the
|
|
// root hub.
|
|
|
|
// Bit 0 is reserved for the status change of the hub itself.
|
|
//
|
|
|
|
MPRH_GetHubStatus(devExt, &hubStatus, mpStatus);
|
|
|
|
if (mpStatus != USBMP_STATUS_SUCCESS ) {
|
|
DEBUG_BREAK();
|
|
rhStatus = RH_STALL;
|
|
goto USBPORT_RootHub_Endpoint1_Done;
|
|
}
|
|
|
|
if (hubStatus.LocalPowerChange ||
|
|
hubStatus.OverCurrentChange) {
|
|
|
|
USBPORT_SetBit(buffer,
|
|
0);
|
|
rhStatus = RH_SUCCESS;
|
|
}
|
|
|
|
switch (rhStatus) {
|
|
case RH_NAK:
|
|
// we have a transfer pending but no changes yet
|
|
// enable the controller to generate an interrupt
|
|
// if a root hub change occurs
|
|
MPRH_EnableIrq(devExt);
|
|
break;
|
|
|
|
case RH_SUCCESS:
|
|
|
|
// set bytes transferred for this interrupt
|
|
// endpoint
|
|
urb->TransferBufferLength =
|
|
Transfer->Tp.TransferBufferLength;
|
|
break;
|
|
|
|
case RH_STALL:
|
|
DEBUG_BREAK();
|
|
break;
|
|
}
|
|
|
|
USBPORT_RootHub_Endpoint1_Done:
|
|
|
|
return rhStatus;
|
|
}
|
|
|
|
|
|
RHSTATUS
|
|
USBPORT_RootHub_Endpoint0(
|
|
PHCD_TRANSFER_CONTEXT Transfer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
root hub transfer status code
|
|
|
|
--*/
|
|
{
|
|
RHSTATUS rhStatus;
|
|
PTRANSFER_URB urb;
|
|
PUSB_DEFAULT_PIPE_SETUP_PACKET setupPacket;
|
|
PUCHAR buffer;
|
|
ULONG bufferLength;
|
|
PHCD_ENDPOINT endpoint;
|
|
PDEVICE_OBJECT fdoDeviceObject;
|
|
|
|
ASSERT_TRANSFER(Transfer);
|
|
urb = Transfer->Urb;
|
|
|
|
endpoint = Transfer->Endpoint;
|
|
ASSERT_ENDPOINT(endpoint);
|
|
fdoDeviceObject = endpoint->FdoDeviceObject;
|
|
|
|
//
|
|
// convert transfer buffer from MDL
|
|
//
|
|
buffer =
|
|
Transfer->Tp.TransferBufferLength ?
|
|
urb->TransferBufferMDL->MappedSystemVa :
|
|
NULL;
|
|
bufferLength = Transfer->Tp.TransferBufferLength;
|
|
|
|
setupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET)
|
|
&urb->u.SetupPacket[0];
|
|
|
|
if (setupPacket->bmRequestType.Type == RH_STANDARD_REQ) {
|
|
rhStatus =
|
|
USBPORT_RootHub_StandardCommand(fdoDeviceObject,
|
|
setupPacket,
|
|
buffer,
|
|
&bufferLength);
|
|
if (rhStatus == RH_SUCCESS) {
|
|
// set the return length
|
|
Transfer->MiniportBytesTransferred = bufferLength;
|
|
}
|
|
|
|
} else if (setupPacket->bmRequestType.Type == RH_CLASS_REQ) {
|
|
rhStatus =
|
|
USBPORT_RootHub_ClassCommand(fdoDeviceObject,
|
|
setupPacket,
|
|
buffer,
|
|
&bufferLength);
|
|
if (rhStatus == RH_SUCCESS) {
|
|
// set the return length
|
|
Transfer->MiniportBytesTransferred = bufferLength;
|
|
}
|
|
|
|
} else {
|
|
rhStatus = RH_STALL;
|
|
// probably a bug in the hub driver
|
|
DEBUG_BREAK();
|
|
}
|
|
|
|
return rhStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
USBPORT_RootHub_CreateDevice(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PDEVICE_OBJECT PdoDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create the 'ROOT HUB' USB Device
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION rhDevExt, devExt;
|
|
NTSTATUS ntStatus;
|
|
PUCHAR descriptors;
|
|
ROOTHUB_DATA hubData;
|
|
ULONG hubDescriptorLength, length;
|
|
ULONG i, portbytes;
|
|
|
|
PAGED_CODE();
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
|
|
ASSERT_PDOEXT(rhDevExt);
|
|
|
|
USBPORT_ASSERT(devExt->Fdo.RootHubPdo == PdoDeviceObject);
|
|
|
|
// init the device handle
|
|
rhDevExt->Pdo.RootHubDeviceHandle.Sig = SIG_DEVICE_HANDLE;
|
|
rhDevExt->Pdo.RootHubDeviceHandle.DeviceAddress = 0;
|
|
rhDevExt->Pdo.RootHubDeviceHandle.ConfigurationHandle = NULL;
|
|
rhDevExt->Pdo.RootHubDeviceHandle.DeviceFlags =
|
|
USBPORT_DEVICEFLAG_ROOTHUB;
|
|
|
|
// define root hub speed based on the type of conroller
|
|
if (USBPORT_IS_USB20(devExt)) {
|
|
rhDevExt->Pdo.RootHubDeviceHandle.DeviceSpeed = UsbHighSpeed;
|
|
} else {
|
|
rhDevExt->Pdo.RootHubDeviceHandle.DeviceSpeed = UsbFullSpeed;
|
|
}
|
|
|
|
InitializeListHead(&rhDevExt->Pdo.RootHubDeviceHandle.PipeHandleList);
|
|
InitializeListHead(&rhDevExt->Pdo.RootHubDeviceHandle.TtList);
|
|
|
|
USBPORT_AddDeviceHandle(FdoDeviceObject,
|
|
&rhDevExt->Pdo.RootHubDeviceHandle);
|
|
|
|
// assume success
|
|
ntStatus = STATUS_SUCCESS;
|
|
|
|
// root hub device is not configured yet
|
|
rhDevExt->Pdo.ConfigurationValue = 0;
|
|
|
|
// get root hub information from the miniport
|
|
MPRH_GetRootHubData(devExt, &hubData);
|
|
|
|
// use hub data to fabricate a hub descriptor
|
|
// figure out how many bytes the variable part
|
|
// it will be based on the nuber of ports
|
|
// ie how many bytes does it take to represent
|
|
// n ports
|
|
// 1-8 ports = 1 bytes
|
|
// 9-16 ports = 2 bytes
|
|
// 17-24 ports = 3 bytes
|
|
// 25-36 ports = 4 bytes
|
|
//...
|
|
|
|
USBPORT_ASSERT(hubData.NumberOfPorts != 0);
|
|
|
|
// number of bytes we need to represnt the ports
|
|
portbytes = ((((hubData.NumberOfPorts-1)/8)+1));
|
|
|
|
hubDescriptorLength = 7+(portbytes*2);
|
|
|
|
length =
|
|
sizeof(RH_ConfigurationDescriptor) +
|
|
sizeof(RH_DeviceDescriptor) +
|
|
hubDescriptorLength;
|
|
|
|
// allocate space for our descriports
|
|
ALLOC_POOL_Z(descriptors, NonPagedPool,
|
|
length);
|
|
|
|
if (descriptors) {
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject,
|
|
LOG_RH, 'rhDS', descriptors, length, portbytes);
|
|
|
|
rhDevExt->Pdo.Descriptors = descriptors;
|
|
|
|
// set up device descriptor
|
|
rhDevExt->Pdo.DeviceDescriptor =
|
|
(PUSB_DEVICE_DESCRIPTOR) descriptors;
|
|
descriptors += sizeof(RH_DeviceDescriptor);
|
|
RtlCopyMemory(rhDevExt->Pdo.DeviceDescriptor,
|
|
&RH_DeviceDescriptor[0],
|
|
sizeof(RH_DeviceDescriptor));
|
|
|
|
|
|
// hack it up for USB2
|
|
if (USBPORT_IS_USB20(devExt)) {
|
|
rhDevExt->Pdo.DeviceDescriptor->bcdUSB = 0x0200;
|
|
}
|
|
|
|
// use HC vendor and device for root hub
|
|
rhDevExt->Pdo.DeviceDescriptor->idVendor =
|
|
devExt->Fdo.PciVendorId;
|
|
rhDevExt->Pdo.DeviceDescriptor->idProduct =
|
|
devExt->Fdo.PciDeviceId;
|
|
|
|
rhDevExt->Pdo.DeviceDescriptor->bcdDevice =
|
|
devExt->Fdo.PciRevisionId;
|
|
|
|
// set up config descriptor
|
|
rhDevExt->Pdo.ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)
|
|
descriptors;
|
|
LOGENTRY(NULL, FdoDeviceObject,
|
|
LOG_RH, 'rhCS', descriptors,0, 0);
|
|
|
|
descriptors += sizeof(RH_ConfigurationDescriptor);
|
|
RtlCopyMemory(rhDevExt->Pdo.ConfigurationDescriptor,
|
|
&RH_ConfigurationDescriptor[0],
|
|
sizeof(RH_ConfigurationDescriptor));
|
|
|
|
// set up the hub descriptor
|
|
rhDevExt->Pdo.HubDescriptor =
|
|
(PUSB_HUB_DESCRIPTOR) descriptors;
|
|
LOGENTRY(NULL, FdoDeviceObject,
|
|
LOG_RH, 'rhHS', descriptors,0, 0);
|
|
|
|
RtlCopyMemory(rhDevExt->Pdo.HubDescriptor,
|
|
&RH_HubDescriptor[0],
|
|
sizeof(RH_HubDescriptor));
|
|
|
|
rhDevExt->Pdo.HubDescriptor->bDescriptorLength =
|
|
hubDescriptorLength;
|
|
|
|
rhDevExt->Pdo.HubDescriptor->bNumberOfPorts =
|
|
(UCHAR) hubData.NumberOfPorts;
|
|
rhDevExt->Pdo.HubDescriptor->wHubCharacteristics =
|
|
hubData.HubCharacteristics.us;
|
|
rhDevExt->Pdo.HubDescriptor->bPowerOnToPowerGood =
|
|
hubData.PowerOnToPowerGood;
|
|
rhDevExt->Pdo.HubDescriptor->bHubControlCurrent =
|
|
hubData.HubControlCurrent;
|
|
|
|
// fill in the var part
|
|
for (i=0; i<portbytes; i++) {
|
|
rhDevExt->Pdo.HubDescriptor->bRemoveAndPowerMask[i] =
|
|
0;
|
|
rhDevExt->Pdo.HubDescriptor->bRemoveAndPowerMask[i+portbytes] =
|
|
0xff;
|
|
}
|
|
|
|
INITIALIZE_DEFAULT_PIPE(rhDevExt->Pdo.RootHubDeviceHandle.DefaultPipe,
|
|
USB_DEFAULT_MAX_PACKET);
|
|
|
|
// init the default pipe
|
|
ntStatus = USBPORT_OpenEndpoint(
|
|
&rhDevExt->Pdo.RootHubDeviceHandle,
|
|
FdoDeviceObject,
|
|
&rhDevExt->Pdo.RootHubDeviceHandle.DefaultPipe,
|
|
NULL,
|
|
TRUE);
|
|
|
|
|
|
} else {
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
USBPORT_RootHub_RemoveDevice(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PDEVICE_OBJECT PdoDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove the 'ROOT HUB' USB Device
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION rhDevExt;
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject,
|
|
LOG_RH, 'rhrm', 0, 0, 0);
|
|
ASSERT_PASSIVE();
|
|
|
|
GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
|
|
ASSERT_PDOEXT(rhDevExt);
|
|
|
|
// close the current config
|
|
USBPORT_InternalCloseConfiguration(
|
|
&rhDevExt->Pdo.RootHubDeviceHandle,
|
|
FdoDeviceObject,
|
|
0);
|
|
|
|
// close the default pipe
|
|
USBPORT_ClosePipe(
|
|
&rhDevExt->Pdo.RootHubDeviceHandle,
|
|
FdoDeviceObject,
|
|
&rhDevExt->Pdo.RootHubDeviceHandle.DefaultPipe);
|
|
|
|
USBPORT_RemoveDeviceHandle(FdoDeviceObject,
|
|
&rhDevExt->Pdo.RootHubDeviceHandle);
|
|
|
|
FREE_POOL(FdoDeviceObject, rhDevExt->Pdo.Descriptors);
|
|
rhDevExt->Pdo.Descriptors = USBPORT_BAD_POINTER;
|
|
}
|
|
|
|
|
|
VOID
|
|
USBPORT_RootHub_EndpointWorker(
|
|
PHCD_ENDPOINT Endpoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
process transfers for the root hub
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
PLIST_ENTRY listEntry;
|
|
PTRANSFER_URB urb;
|
|
PHCD_TRANSFER_CONTEXT transfer = NULL;
|
|
USBD_STATUS usbdStatus;
|
|
RHSTATUS rhStatus;
|
|
PDEVICE_OBJECT fdoDeviceObject;
|
|
PDEVICE_EXTENSION devExt;
|
|
|
|
ASSERT_ENDPOINT(Endpoint);
|
|
fdoDeviceObject = Endpoint->FdoDeviceObject;
|
|
GET_DEVICE_EXT(devExt, fdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
MP_CheckController(devExt);
|
|
|
|
ACQUIRE_ENDPOINT_LOCK(Endpoint, fdoDeviceObject, 'LeA0');
|
|
|
|
// Now check the active list, and process
|
|
// the transfers on it
|
|
GET_HEAD_LIST(Endpoint->ActiveList, listEntry);
|
|
|
|
if (listEntry) {
|
|
// ACTIVE(r)->
|
|
// extract the urb that is currently on the active
|
|
// list, there should only be one
|
|
transfer = (PHCD_TRANSFER_CONTEXT) CONTAINING_RECORD(
|
|
listEntry,
|
|
struct _HCD_TRANSFER_CONTEXT,
|
|
TransferLink);
|
|
LOGENTRY(NULL, fdoDeviceObject, LOG_RH, 'rACT', transfer, 0, 0);
|
|
ASSERT_TRANSFER(transfer);
|
|
}
|
|
|
|
if (transfer) {
|
|
|
|
ASSERT_TRANSFER(transfer);
|
|
|
|
// is this transfer canceled?
|
|
if ((transfer->Flags & USBPORT_TXFLAG_CANCELED) ||
|
|
(transfer->Flags & USBPORT_TXFLAG_ABORTED)) {
|
|
// yes,
|
|
// just put it on the cancel list
|
|
// since this routine is NOT renetrant
|
|
// it will not be completed
|
|
|
|
// remove from active
|
|
RemoveEntryList(&transfer->TransferLink);
|
|
// insert on cancel
|
|
InsertTailList(&Endpoint->CancelList, &transfer->TransferLink);
|
|
|
|
// removed from active list
|
|
RELEASE_ENDPOINT_LOCK(Endpoint, fdoDeviceObject, 'UeA0');
|
|
|
|
} else {
|
|
|
|
// transfer is not canceled, process it
|
|
// NOTE: if the transfer is canceled at
|
|
// this point it is only marked since it
|
|
// is on the active list
|
|
|
|
RELEASE_ENDPOINT_LOCK(Endpoint, fdoDeviceObject, 'UeA1');
|
|
// relaese the lock no so that the miniport may freely
|
|
// call InvalidateRootHub. Root hub functions so not take
|
|
// the core spinlock
|
|
|
|
// call root hub code
|
|
if (Endpoint->Parameters.TransferType == Control) {
|
|
rhStatus = USBPORT_RootHub_Endpoint0(transfer);
|
|
} else {
|
|
rhStatus = USBPORT_RootHub_Endpoint1(transfer);
|
|
// if the interrupt ep nak'ed enable interrupt
|
|
// changes
|
|
}
|
|
LOGENTRY(NULL, fdoDeviceObject, LOG_RH, 'ACT+', transfer, rhStatus, 0);
|
|
|
|
if (rhStatus != RH_NAK) {
|
|
|
|
// transfer is done.
|
|
// NOTE: that donetransfer can only be called from this
|
|
// routine and that this routine is NOT reentrant.
|
|
// Hence, we don't need to worry about race conditions
|
|
// caused by multiple calls to DoneTransfer
|
|
usbdStatus = RHSTATUS_TO_USBDSTATUS(rhStatus);
|
|
|
|
// This function expects the endpoint lock to be held
|
|
// although it is not necessary in the case of the root
|
|
// hub
|
|
ACQUIRE_ENDPOINT_LOCK(Endpoint, fdoDeviceObject, 'LeX0');
|
|
|
|
USBPORT_QueueDoneTransfer(transfer,
|
|
usbdStatus);
|
|
|
|
RELEASE_ENDPOINT_LOCK(Endpoint, fdoDeviceObject, 'UeX0');
|
|
|
|
}
|
|
|
|
}
|
|
} else {
|
|
// transfer queues empty
|
|
|
|
if (Endpoint->CurrentState == ENDPOINT_REMOVE) {
|
|
// put the endpoint on the closed list
|
|
|
|
LOGENTRY(NULL, fdoDeviceObject, LOG_PNP, 'rmRE', 0, Endpoint, 0);
|
|
|
|
ExInterlockedInsertTailList(&devExt->Fdo.EpClosedList,
|
|
&Endpoint->ClosedLink,
|
|
&devExt->Fdo.EpClosedListSpin.sl);
|
|
}
|
|
RELEASE_ENDPOINT_LOCK(Endpoint, fdoDeviceObject, 'UeA2');
|
|
}
|
|
|
|
// flush out canceled requests
|
|
USBPORT_FlushCancelList(Endpoint);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
USBPORT_InvalidateRootHub(
|
|
PDEVICE_OBJECT FdoDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Invalidates the state of the root hub, this will
|
|
trigger USBPORT to poll the root hub for any
|
|
changes.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PHCD_ENDPOINT endpoint = NULL;
|
|
PDEVICE_EXTENSION devExt, rhDevExt;
|
|
KIRQL irql;
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'rhIV', 0, 0, 0);
|
|
|
|
// disable the root hub notification interrupt
|
|
MPRH_DisableIrq(devExt);
|
|
|
|
if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_SUSPENDED)) {
|
|
USBPORT_HcQueueWakeDpc(FdoDeviceObject);
|
|
return;
|
|
}
|
|
|
|
// make sure we have an endpoint
|
|
ACQUIRE_ROOTHUB_LOCK(FdoDeviceObject, irql);
|
|
if (devExt->Fdo.RootHubPdo) {
|
|
|
|
GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
|
|
ASSERT_PDOEXT(rhDevExt);
|
|
|
|
endpoint = rhDevExt->Pdo.RootHubInterruptEndpoint;
|
|
|
|
}
|
|
RELEASE_ROOTHUB_LOCK(FdoDeviceObject, irql);
|
|
|
|
// if we have an endpoint, hence, a root hub then
|
|
// process requests
|
|
if (endpoint) {
|
|
|
|
USBPORT_InvalidateEndpoint(FdoDeviceObject,
|
|
rhDevExt->Pdo.RootHubInterruptEndpoint,
|
|
IEP_SIGNAL_WORKER);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
USBPORTSVC_InvalidateRootHub(
|
|
PDEVICE_DATA DeviceData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Service exported to miniports.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION devExt;
|
|
PDEVICE_OBJECT fdoDeviceObject;
|
|
|
|
DEVEXT_FROM_DEVDATA(devExt, DeviceData);
|
|
ASSERT_FDOEXT(devExt);
|
|
fdoDeviceObject = devExt->HcFdoDeviceObject;
|
|
|
|
LOGENTRY(NULL, fdoDeviceObject, LOG_RH, 'rhNO', 0, 0, 0);
|
|
|
|
USBPORT_InvalidateRootHub(fdoDeviceObject);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
USBPORT_UserSetRootPortFeature(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PUSBUSER_REQUEST_HEADER Header,
|
|
PRAW_ROOTPORT_FEATURE Parameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cycle a specific Root Port
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Fdo for USB HC
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
ULONG currentFrame, nextFrame;
|
|
PDEVICE_EXTENSION devExt;
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
USB_USER_ERROR_CODE usbUserStatus;
|
|
RH_PORT_STATUS portStatus;
|
|
|
|
USBPORT_KdPrint((2, "'USBPORT_UserSetRootPortFeature\n"));
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
usbUserStatus = UsbUserSuccess;
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'SRpF', 0, Parameters->PortNumber, Parameters->PortFeature);
|
|
|
|
if (!USBPORT_ValidateRootPortApi(FdoDeviceObject, Parameters->PortNumber)) {
|
|
Header->UsbUserStatusCode =
|
|
usbUserStatus = UsbUserInvalidParameter;
|
|
return;
|
|
}
|
|
|
|
if (!USBPORT_DCA_Enabled(FdoDeviceObject)) {
|
|
Header->UsbUserStatusCode = UsbUserFeatureDisabled;
|
|
return;
|
|
}
|
|
|
|
switch(Parameters->PortFeature) {
|
|
|
|
case PORT_RESET:
|
|
{
|
|
ULONG loopCount = 0;
|
|
|
|
// attempt a reset
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortReset(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
// wait for reset change, this process is drive byn the
|
|
// HC root hub hardware or miniport
|
|
|
|
do {
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
|
|
loopCount++;
|
|
|
|
} while ((portStatus.ResetChange == 0) &&
|
|
(loopCount < 5));
|
|
|
|
// clear the change bit
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortResetChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
}
|
|
|
|
case PORT_POWER:
|
|
|
|
// power the port
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortPower(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
|
|
case PORT_ENABLE:
|
|
|
|
// enable the port
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortEnable(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
|
|
case PORT_SUSPEND:
|
|
|
|
// suspend the port
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortSuspend(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
|
|
default:
|
|
|
|
usbUserStatus = UsbUserNotSupported;
|
|
break;
|
|
}
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'SRp>', 0, 0, usbUserStatus);
|
|
|
|
Header->UsbUserStatusCode = usbUserStatus;
|
|
}
|
|
|
|
VOID
|
|
USBPORT_UserClearRootPortFeature(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PUSBUSER_REQUEST_HEADER Header,
|
|
PRAW_ROOTPORT_FEATURE Parameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cycle a specific Root Port
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Fdo for USB HC
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
ULONG currentFrame, nextFrame;
|
|
PDEVICE_EXTENSION devExt;
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
USB_USER_ERROR_CODE usbUserStatus;
|
|
RH_PORT_STATUS portStatus;
|
|
|
|
USBPORT_KdPrint((2, "'USBPORT_UserRawResetPort\n"));
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
usbUserStatus = UsbUserSuccess;
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'CFRp', 0, Parameters->PortNumber, Parameters->PortFeature);
|
|
|
|
if (!USBPORT_ValidateRootPortApi(FdoDeviceObject, Parameters->PortNumber)) {
|
|
Header->UsbUserStatusCode =
|
|
usbUserStatus = UsbUserInvalidParameter;
|
|
return;
|
|
}
|
|
|
|
if (!USBPORT_DCA_Enabled(FdoDeviceObject)) {
|
|
Header->UsbUserStatusCode = UsbUserFeatureDisabled;
|
|
return;
|
|
}
|
|
|
|
switch(Parameters->PortFeature) {
|
|
|
|
case PORT_ENABLE:
|
|
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortEnable(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
|
|
case PORT_POWER:
|
|
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortPower(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
|
|
case PORT_SUSPEND:
|
|
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortSuspend(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
|
|
case C_PORT_ENABLE:
|
|
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortEnableChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
|
|
case C_PORT_CONNECTION:
|
|
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortConnectChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
|
|
case C_PORT_RESET:
|
|
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortResetChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
|
|
case C_PORT_SUSPEND:
|
|
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortSuspendChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
|
|
case C_PORT_OVER_CURRENT:
|
|
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_ClearFeaturePortOvercurrentChange(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Parameters->PortNumber);
|
|
/*
|
|
USBPORT_Wait(FdoDeviceObject, 1);
|
|
*/
|
|
MP_Get32BitFrameNumber(devExt, currentFrame);
|
|
|
|
do {
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
if(nextFrame < currentFrame) {
|
|
// roll-over
|
|
//
|
|
currentFrame = nextFrame;
|
|
MP_Get32BitFrameNumber(devExt, nextFrame);
|
|
}
|
|
} while ((nextFrame - currentFrame) < FRAME_COUNT_WAIT);
|
|
|
|
MPRH_GetPortStatus(devExt, (USHORT)(Parameters->PortNumber),
|
|
&portStatus, mpStatus);
|
|
// status is low 16 bits
|
|
Parameters->PortStatus = (USHORT) portStatus.ul;
|
|
break;
|
|
|
|
default:
|
|
|
|
usbUserStatus = UsbUserNotSupported;
|
|
break;
|
|
}
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'CFR>', 0, 0, usbUserStatus);
|
|
|
|
Header->UsbUserStatusCode = usbUserStatus;
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
USBPORT_RootHub_PowerUsb2Port(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
USHORT Port
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Power up the USB 2 port and the assocaited CC port
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Fdo for USB HC
|
|
|
|
Return Value:
|
|
|
|
miniport status
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_EXTENSION devExt, rhDevExt;
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
PDEVICE_RELATIONS devRelations;
|
|
USHORT p;
|
|
ULONG i;
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
|
|
ASSERT_PDOEXT(rhDevExt);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, '20pw', 0, 0, 0);
|
|
|
|
// power the associated CC controllers ports
|
|
// for now power all ports for any CC
|
|
|
|
devRelations =
|
|
USBPORT_FindCompanionControllers(FdoDeviceObject,
|
|
FALSE,
|
|
TRUE);
|
|
|
|
// may get NULL here if no CCs found or are registered
|
|
|
|
for (i=0; devRelations && i< devRelations->Count; i++) {
|
|
PDEVICE_OBJECT fdo = devRelations->Objects[i];
|
|
PDEVICE_EXTENSION ccDevExt, ccRhDevExt;
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'pwCC', fdo,
|
|
0, 0);
|
|
|
|
GET_DEVICE_EXT(ccDevExt, fdo);
|
|
ASSERT_FDOEXT(ccDevExt);
|
|
|
|
GET_DEVICE_EXT(ccRhDevExt, ccDevExt->Fdo.RootHubPdo);
|
|
ASSERT_PDOEXT(ccRhDevExt);
|
|
|
|
// power the port
|
|
for (p=0;
|
|
(ccRhDevExt->PnpStateFlags & USBPORT_PNP_STARTED) &&
|
|
p< NUMBER_OF_PORTS(ccRhDevExt);
|
|
p++) {
|
|
ccDevExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortPower(
|
|
ccDevExt->Fdo.MiniportDeviceData,
|
|
p+1);
|
|
}
|
|
|
|
}
|
|
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortPower(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Port);
|
|
|
|
// jd xxx
|
|
// chirp it
|
|
//devExt->Fdo.MiniportDriver->
|
|
// RegistrationPacket.MINIPORT_Chirp_RH_Port(
|
|
// devExt->Fdo.MiniportDeviceData,
|
|
// Port);
|
|
|
|
|
|
// thou shall not leak memory
|
|
if (devRelations != NULL) {
|
|
FREE_POOL(FdoDeviceObject, devRelations);
|
|
}
|
|
|
|
return USBMP_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
USBPORT_RootHub_PowerUsbCcPort(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
USHORT Port
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Power up the USB port on a CC
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Fdo for USB HC
|
|
|
|
Return Value:
|
|
|
|
miniport status
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_EXTENSION devExt, rhDevExt;
|
|
// PDEVICE_OBJECT usb2Fdo;
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
|
|
ASSERT_PDOEXT(rhDevExt);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'CCpw', 0, 0, Port);
|
|
|
|
// if there is a 2.0 controller then
|
|
// this a noop, port should already be powered
|
|
|
|
//usb2Fdo = USBPORT_FindUSB2Controller(FdoDeviceObject);
|
|
|
|
// no 2.0 controller power this port
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortPower(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
Port);
|
|
return USBMP_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
USBPORT_RootHub_PowerAndChirpAllCcPorts(
|
|
PDEVICE_OBJECT FdoDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Power up all the USB ports on a CC
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Fdo for USB Companion
|
|
|
|
Return Value:
|
|
|
|
miniport status
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_EXTENSION devExt;
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
USHORT p;
|
|
ULONG i;
|
|
PDEVICE_OBJECT usb2Fdo;
|
|
ROOTHUB_DATA hubData;
|
|
ULONG nPorts;
|
|
|
|
ASSERT_PASSIVE();
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
MPRH_GetRootHubData(devExt, &hubData);
|
|
nPorts = hubData.NumberOfPorts;
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_RH, 'CCpw', 0, 0, 0);
|
|
|
|
usb2Fdo = USBPORT_FindUSB2Controller(FdoDeviceObject);
|
|
// may get NULL if no 2.0 controller registered
|
|
|
|
if (usb2Fdo) {
|
|
PDEVICE_EXTENSION usb2DevExt;
|
|
ULONG usb2Nports;
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'p120', usb2Fdo,
|
|
0, 0);
|
|
|
|
GET_DEVICE_EXT(usb2DevExt, usb2Fdo);
|
|
ASSERT_FDOEXT(usb2DevExt);
|
|
|
|
MPRH_GetRootHubData(usb2DevExt, &hubData);
|
|
usb2Nports = hubData.NumberOfPorts;
|
|
|
|
KeWaitForSingleObject(&usb2DevExt->Fdo.CcLock,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_CC_LOCK);
|
|
USBPORT_KdPrint((1, "'**> powering/chirping CC ports\n"));
|
|
|
|
for (p=0;
|
|
p< nPorts;
|
|
p++) {
|
|
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortPower(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
p+1);
|
|
}
|
|
|
|
// some ammount of time must elapse between powering the CC port and
|
|
// attempting to chirp.
|
|
USBPORT_Wait(FdoDeviceObject, 10);
|
|
|
|
// chirp all the ports on the USB 2 parent
|
|
for (p=0;
|
|
(usb2DevExt->Fdo.MiniportDriver->HciVersion >= USB_MINIPORT_HCI_VERSION_2)
|
|
&&
|
|
p < usb2Nports;
|
|
p++) {
|
|
usb2DevExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_Chirp_RH_Port(
|
|
usb2DevExt->Fdo.MiniportDeviceData,
|
|
p+1);
|
|
}
|
|
|
|
USBPORT_KdPrint((1, "'**< powering/chirping CC ports\n"));
|
|
CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_CC_LOCK);
|
|
KeReleaseSemaphore(&usb2DevExt->Fdo.CcLock,
|
|
LOW_REALTIME_PRIORITY,
|
|
1,
|
|
FALSE);
|
|
|
|
|
|
} else {
|
|
USBPORT_KdPrint((1, "'** powering CC ports\n"));
|
|
|
|
// no CC, just power them
|
|
for (p=0;
|
|
p< nPorts;
|
|
p++) {
|
|
|
|
devExt->Fdo.MiniportDriver->
|
|
RegistrationPacket.MINIPORT_RH_SetFeaturePortPower(
|
|
devExt->Fdo.MiniportDeviceData,
|
|
p+1);
|
|
}
|
|
}
|
|
|
|
return USBMP_STATUS_SUCCESS;
|
|
}
|
|
|