|
|
/*++
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; }
|