VOID
NTAPI
-EhciDefferedRoutine(
+OhciDefferedRoutine(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
NTSTATUS PnpStop(void);
NTSTATUS HandlePower(PIRP Irp);
NTSTATUS GetDeviceDetails(PUSHORT VendorId, PUSHORT DeviceId, PULONG NumberOfPorts, PULONG Speed);
+ NTSTATUS GetBulkHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor);
+ NTSTATUS GetControlHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor);
+ NTSTATUS GetInterruptEndpointDescriptors(struct _OHCI_ENDPOINT_DESCRIPTOR *** OutDescriptor);
+ NTSTATUS GetIsochronousHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor);
+ VOID HeadEndpointDescriptorModified(ULONG HeadType);
+
+
NTSTATUS GetDMA(OUT struct IDMAMemoryManager **m_DmaManager);
NTSTATUS GetUSBQueue(OUT struct IUSBQueue **OutUsbQueue);
KIRQL AcquireDeviceLock(void);
VOID ReleaseDeviceLock(KIRQL OldLevel);
+ virtual VOID GetCurrentFrameNumber(PULONG FrameNumber);
// local
BOOLEAN InterruptService();
NTSTATUS InitializeController();
// friend function
friend BOOLEAN NTAPI InterruptServiceRoutine(IN PKINTERRUPT Interrupt, IN PVOID ServiceContext);
- friend VOID NTAPI EhciDefferedRoutine(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
+ friend VOID NTAPI OhciDefferedRoutine(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
friend VOID NTAPI StatusChangeWorkItemRoutine(PVOID Context);
// constructor / destructor
CUSBHardwareDevice(IUnknown *OuterUnknown){}
PHYSICAL_ADDRESS m_HCCAPhysicalAddress; // hcca physical address
POHCI_ENDPOINT_DESCRIPTOR m_ControlEndpointDescriptor; // dummy control endpoint descriptor
POHCI_ENDPOINT_DESCRIPTOR m_BulkEndpointDescriptor; // dummy control endpoint descriptor
- POHCI_ENDPOINT_DESCRIPTOR m_IsoEndpointDescriptor; // iso endpoint descriptor
+ POHCI_ENDPOINT_DESCRIPTOR m_IsoEndpointDescriptor; // iso endpoint descriptor
POHCI_ENDPOINT_DESCRIPTOR m_InterruptEndpoints[OHCI_STATIC_ENDPOINT_COUNT]; // endpoints for interrupt / iso transfers
ULONG m_NumberOfPorts; // number of ports
+ OHCI_PORT_STATUS m_PortStatus[OHCI_MAX_PORT_COUNT]; // port change status
PDMAMEMORYMANAGER m_MemoryManager; // memory manager
HD_INIT_CALLBACK* m_SCECallBack; // status change callback routine
PVOID m_SCEContext; // status change callback routine context
- BOOLEAN m_DoorBellRingInProgress; // door bell ring in progress
WORK_QUEUE_ITEM m_StatusChangeWorkItem; // work item for status change callback
ULONG m_SyncFramePhysAddr; // periodic frame list physical address
+ ULONG m_IntervalValue; // periodic interval value
};
//=================================================================================================
case CmResourceTypeInterrupt:
{
KeInitializeDpc(&m_IntDpcObject,
- EhciDefferedRoutine,
+ OhciDefferedRoutine,
this);
Status = IoConnectInterrupt(&m_Interrupt,
}
//
- // Initialize the UsbQueue now that we have an AdapterObject.
+ // initializes the controller
//
- Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, NULL);
+ Status = InitializeController();
if (!NT_SUCCESS(Status))
{
- DPRINT1("Failed to Initialize the UsbQueue\n");
+ DPRINT1("Failed to Initialize the controller \n");
+ ASSERT(FALSE);
return Status;
}
//
- // initializes the controller
+ // Initialize the UsbQueue now that we have an AdapterObject.
//
- Status = InitializeController();
+ Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, NULL);
if (!NT_SUCCESS(Status))
{
- DPRINT1("Failed to Initialize the controller \n");
- ASSERT(FALSE);
+ DPRINT1("Failed to Initialize the UsbQueue\n");
return Status;
}
NTSTATUS
CUSBHardwareDevice::StartController(void)
{
- ULONG Control, NumberOfPorts, Index, Descriptor;
+ ULONG Control, NumberOfPorts, Index, Descriptor, FrameInterval, Periodic;
//
// first write address of HCCA
//
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), Control);
+ //
+ // wait a bit
+ //
+ KeStallExecutionProcessor(100);
+
+ //
+ // is the controller started
+ //
+ Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
+
+ //
+ // assert that the controller has been started
+ //
+ ASSERT((Control & OHCI_HC_FUNCTIONAL_STATE_MASK) == OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL);
+ ASSERT((Control & OHCI_ENABLE_LIST) == OHCI_ENABLE_LIST);
+ DPRINT1("Control %x\n", Control);
+
+ //
+ // get frame interval
+ //
+ FrameInterval = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET));
+ FrameInterval = ((FrameInterval & OHCI_FRAME_INTERVAL_TOGGLE) ^ OHCI_FRAME_INTERVAL_TOGGLE);
+ DPRINT1("FrameInterval %x IntervalValue %x\n", FrameInterval, m_IntervalValue);
+ FrameInterval |= OHCI_FSMPS(m_IntervalValue) | m_IntervalValue;
+ DPRINT1("FrameInterval %x\n", FrameInterval);
+
+ //
+ // write frame interval
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET), FrameInterval);
+
+ //
+ // 90 % periodic
+ //
+ Periodic = OHCI_PERIODIC(m_IntervalValue);
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_PERIODIC_START_OFFSET), Periodic);
+ DPRINT1("Periodic Start %x\n", Periodic);
+
+ //
+ // read descriptor
+ //
+ Descriptor = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_DESCRIPTOR_A_OFFSET));
+
+ //
+ // no over current protection
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_DESCRIPTOR_A_OFFSET), Descriptor | OHCI_RH_NO_OVER_CURRENT_PROTECTION);
+
+ //
+ // enable power on all ports
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_STATUS_OFFSET), OHCI_RH_LOCAL_POWER_STATUS_CHANGE);
+
+ //
+ // wait a bit
+ //
+ KeStallExecutionProcessor(10);
+
+ //
+ // write descriptor
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_DESCRIPTOR_A_OFFSET), Descriptor);
+
+
+
//
// retrieve number of ports
//
//
DPRINT1("NumberOfPorts %lu\n", m_NumberOfPorts);
+
+ //
+ // now enable the interrupts
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_INTERRUPT_ENABLE_OFFSET), OHCI_NORMAL_INTERRUPTS | OHCI_MASTER_INTERRUPT_ENABLE);
+
//
// done
//
return STATUS_SUCCESS;
}
+NTSTATUS
+CUSBHardwareDevice::GetBulkHeadEndpointDescriptor(
+ struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
+{
+ *OutDescriptor = m_BulkEndpointDescriptor;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CUSBHardwareDevice::GetInterruptEndpointDescriptors(
+ struct _OHCI_ENDPOINT_DESCRIPTOR *** OutDescriptor)
+{
+ *OutDescriptor = m_InterruptEndpoints;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CUSBHardwareDevice::GetIsochronousHeadEndpointDescriptor(
+ struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
+{
+ //
+ // get descriptor
+ //
+ *OutDescriptor = m_IsoEndpointDescriptor;
+ return STATUS_SUCCESS;
+}
+
+VOID
+CUSBHardwareDevice::HeadEndpointDescriptorModified(
+ ULONG Type)
+{
+ ULONG Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET));
+
+ if (Type == USB_ENDPOINT_TYPE_CONTROL)
+ {
+ //
+ // notify controller
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), Value | OHCI_CONTROL_LIST_FILLED);
+ }
+ else if (Type == USB_ENDPOINT_TYPE_BULK)
+ {
+ //
+ // notify controller
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), Value | OHCI_BULK_LIST_FILLED);
+ }
+}
+
+NTSTATUS
+CUSBHardwareDevice::GetControlHeadEndpointDescriptor(
+ struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
+{
+ *OutDescriptor = m_ControlEndpointDescriptor;
+ return STATUS_SUCCESS;
+}
+
NTSTATUS
CUSBHardwareDevice::InitializeController()
{
//
m_InterruptEndpoints[0]->NextPhysicalEndpoint = m_IsoEndpointDescriptor->PhysicalAddress.LowPart;
+ //
+ // set iso endpoint type
+ //
+ m_IsoEndpointDescriptor->Flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT;
+
//
// done
//
NTSTATUS
CUSBHardwareDevice::StopController(void)
{
- ULONG Control, Reset;
- ULONG Index;
+ ULONG Control, Reset, Status;
+ ULONG Index, FrameInterval;
//
// first turn off all interrupts
//
Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
- //
- // FIXME: support routing
- //
- ASSERT((Control & OHCI_INTERRUPT_ROUTING) == 0);
+
+ if ((Control & OHCI_INTERRUPT_ROUTING))
+ {
+ //
+ // read command status
+ //
+ Status = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET));
+
+ //
+ // change ownership
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), Status | OHCI_OWNERSHIP_CHANGE_REQUEST);
+ for(Index = 0; Index < 100; Index++)
+ {
+ //
+ // wait a bit
+ //
+ KeStallExecutionProcessor(100);
+
+ //
+ // check control
+ //
+ Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
+ if (!(Control & OHCI_INTERRUPT_ROUTING))
+ {
+ //
+ // acquired ownership
+ //
+ break;
+ }
+ }
+
+ //
+ // if the ownership is still not changed, perform reset
+ //
+ if (Control & OHCI_INTERRUPT_ROUTING)
+ {
+ DPRINT1("SMM not responding\n");
+ //
+ // some controllers also depend on this
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), OHCI_HC_FUNCTIONAL_STATE_RESET);
+
+ //
+ // wait a bit
+ //
+ KeStallExecutionProcessor(100);
+ }
+ }
+
//
// have a break
//
KeStallExecutionProcessor(100);
+ //
+ // read from interval
+ //
+ FrameInterval = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET));
+
+ //
+ // store interval value for later
+ //
+ m_IntervalValue = OHCI_GET_INTERVAL_VALUE(FrameInterval);
+
+ DPRINT1("FrameInterval %x Interval %x\n", FrameInterval, m_IntervalValue);
+
//
// now reset controller
//
//
if ((Reset & OHCI_HOST_CONTROLLER_RESET) == 0)
{
+ //
+ // restore the frame interval register
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET), FrameInterval);
+
//
// controller completed reset
//
OUT USHORT *PortStatus,
OUT USHORT *PortChange)
{
- UNIMPLEMENTED
- *PortStatus = 0;
- *PortChange = 0;
+ //
+ // FIXME: should read status from hardware
+ //
+ *PortStatus = m_PortStatus[PortId].PortStatus;
+ *PortChange = m_PortStatus[PortId].PortChange;
return STATUS_SUCCESS;
}
ULONG PortId,
ULONG Status)
{
- UNIMPLEMENTED
+ ULONG Value;
+
+ DPRINT("CUSBHardwareDevice::ClearPortStatus PortId %x Feature %x\n", PortId, Status);
+
+ if (PortId > m_NumberOfPorts)
+ return STATUS_UNSUCCESSFUL;
+
+ Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)));
+ KeStallExecutionProcessor(100);
+
+ if (Status == C_PORT_RESET)
+ {
+ do
+ {
+ //
+ // read port status
+ //
+ Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)));
+
+ if ((Value & OHCI_RH_PORTSTATUS_PRS) == 0)
+ {
+ //
+ // reset is complete
+ //
+ break;
+ }
+
+ //
+ // wait a bit
+ //
+ KeStallExecutionProcessor(100);
+
+ //DPRINT1("Value %x Index %lu\n", Value, Index);
+
+ }while(TRUE);
+
+ //
+ // check if reset bit is still set
+ //
+ if (Value & OHCI_RH_PORTSTATUS_PRS)
+ {
+ //
+ // reset failed
+ //
+ DPRINT1("PortId %lu Reset failed\n", PortId);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // sanity checks
+ //
+ ASSERT((Value & OHCI_RH_PORTSTATUS_PRS) == 0);
+ ASSERT((Value & OHCI_RH_PORTSTATUS_PRSC));
+
+ //
+ // clear reset bit complete
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)), OHCI_RH_PORTSTATUS_PRSC);
+
+ //
+ // read status register
+ //
+ Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)));
+
+ //
+ // reset complete bit should be cleared
+ //
+ ASSERT((Value & OHCI_RH_PORTSTATUS_PRSC) == 0);
+
+ //
+ // update port status
+ //
+ m_PortStatus[PortId].PortChange &= ~USB_PORT_STATUS_RESET;
+
+ //
+ // sanity check
+ //
+ ASSERT((Value & OHCI_RH_PORTSTATUS_PES));
+
+ //
+ // port is enabled
+ //
+ m_PortStatus[PortId].PortStatus |= USB_PORT_STATUS_ENABLE;
+
+ //
+ // re-enable root hub change
+ //
+ Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_INTERRUPT_ENABLE_OFFSET));
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_INTERRUPT_ENABLE_OFFSET), Value | OHCI_ROOT_HUB_STATUS_CHANGE);
+
+ }
+
+ if (Status == C_PORT_CONNECTION)
+ {
+ //
+ // clear bit
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)), OHCI_RH_PORTSTATUS_CSC);
+ m_PortStatus[PortId].PortChange &= ~USB_PORT_STATUS_CONNECT;
+ }
+
+
+
return STATUS_SUCCESS;
}
ULONG PortId,
ULONG Feature)
{
+ ULONG Value;
+
+ DPRINT1("CUSBHardwareDevice::SetPortFeature PortId %x Feature %x\n", PortId, Feature);
+
+ //
+ // read port status
+ //
+ Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)));
+
+
if (Feature == PORT_ENABLE)
{
//
}
else if (Feature == PORT_RESET)
{
+ //
+ // assert
+ //
+ ASSERT((Value & OHCI_RH_PORTSTATUS_CCS));
+
//
// reset port
//
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)), OHCI_RH_PORTSTATUS_PRS);
+ //
+ // wait
+ //
+ KeStallExecutionProcessor(100);
+
+ //
+ // update cached settings
+ //
+ m_PortStatus[PortId].PortChange |= USB_PORT_STATUS_RESET;
+ m_PortStatus[PortId].PortStatus &= ~USB_PORT_STATUS_ENABLE;
+
//
// is there a status change callback
//
return OldLevel;
}
+VOID
+CUSBHardwareDevice::GetCurrentFrameNumber(
+ PULONG FrameNumber)
+{
+ ULONG Control;
+ ULONG Number;
+
+
+ Number = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_NUMBER_OFFSET));
+ DPRINT1("FrameNumberInterval %x Frame %x\n", Number, m_HCCA->CurrentFrameNumber);
+
+ //
+ // remove reserved bits
+ //
+ Number &= 0xFFFF;
+
+ //
+ // store frame number
+ //
+ *FrameNumber = Number;
+
+ //
+ // is the controller started
+ //
+ Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
+ ASSERT((Control & OHCI_ENABLE_LIST) == OHCI_ENABLE_LIST);
+
+
+}
VOID
CUSBHardwareDevice::ReleaseDeviceLock(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext)
{
- ASSERT(FALSE);
+ CUSBHardwareDevice *This;
+ ULONG DoneHead, Status, Acknowledge = 0;
+
+ //
+ // get context
+ //
+ This = (CUSBHardwareDevice*) ServiceContext;
+
+ DPRINT("InterruptServiceRoutine\n");
+
+ //
+ // get done head
+ //
+ DoneHead = This->m_HCCA->DoneHead;
+
+ //
+ // check if zero
+ //
+ if (DoneHead == 0)
+ {
+ //
+ // the interrupt was not caused by DoneHead update
+ // check if something important happened
+ //
+ Status = READ_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_STATUS_OFFSET)) & READ_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_ENABLE_OFFSET)) & (~OHCI_WRITEBACK_DONE_HEAD);
+ if (Status == 0)
+ {
+ //
+ // nothing happened, appears to be shared interrupt
+ //
+ return FALSE;
+ }
+ }
+ else
+ {
+ //
+ // DoneHead update happened, check if there are other events too
+ //
+ Status = OHCI_WRITEBACK_DONE_HEAD;
+
+ //
+ // since ed descriptors are 16 byte aligned, the controller sets the lower bits if there were other interrupt requests
+ //
+ if (DoneHead & OHCI_DONE_INTERRUPTS)
+ {
+ //
+ // get other events
+ //
+ Status |= READ_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_STATUS_OFFSET)) & READ_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_ENABLE_OFFSET));
+ }
+ }
+
+ //
+ // sanity check
+ //
+ ASSERT(Status != 0);
+
+ if (Status & OHCI_WRITEBACK_DONE_HEAD)
+ {
+ //
+ // head completed
+ //
+ Acknowledge |= OHCI_WRITEBACK_DONE_HEAD;
+ This->m_HCCA->DoneHead = 0;
+ }
+
+ if (Status & OHCI_RESUME_DETECTED)
+ {
+ //
+ // resume
+ //
+ DPRINT1("InterruptServiceRoutine> Resume\n");
+ Acknowledge |= OHCI_RESUME_DETECTED;
+ }
+
+
+ if (Status & OHCI_UNRECOVERABLE_ERROR)
+ {
+ DPRINT1("InterruptServiceRoutine> Controller error\n");
+
+ //
+ // halt controller
+ //
+ ASSERT(FALSE);
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_CONTROL_OFFSET), OHCI_HC_FUNCTIONAL_STATE_RESET);
+ }
+
+ if (Status & OHCI_ROOT_HUB_STATUS_CHANGE)
+ {
+ //
+ // new device has arrived
+ //
+
+ //
+ // disable interrupt as it will fire untill the port has been reset
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_DISABLE_OFFSET), OHCI_ROOT_HUB_STATUS_CHANGE);
+ Acknowledge |= OHCI_ROOT_HUB_STATUS_CHANGE;
+ }
+
+ //
+ // is there something to acknowledge
+ //
+ if (Acknowledge)
+ {
+ //
+ // ack change
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_STATUS_OFFSET), Acknowledge);
+ }
+
+ //
+ // defer processing
+ //
+ DPRINT("Status %x Acknowledge %x FrameNumber %x\n", Status, Acknowledge, This->m_HCCA->CurrentFrameNumber);
+ KeInsertQueueDpc(&This->m_IntDpcObject, (PVOID)Status, (PVOID)(DoneHead & ~1));
+
+ //
+ // interrupt handled
+ //
return TRUE;
}
-VOID NTAPI
-EhciDefferedRoutine(
+VOID
+NTAPI
+OhciDefferedRoutine(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
- ASSERT(FALSE);
- return;
+ CUSBHardwareDevice *This;
+ ULONG CStatus, Index, PortStatus;
+ ULONG DoneHead;
+
+ //
+ // get parameters
+ //
+ This = (CUSBHardwareDevice*)DeferredContext;
+ CStatus = (ULONG) SystemArgument1;
+ DoneHead = (ULONG)SystemArgument2;
+
+ DPRINT("OhciDefferedRoutine Status %x\n", CStatus);
+
+ if (CStatus & OHCI_WRITEBACK_DONE_HEAD)
+ {
+ //
+ // notify queue of event
+ //
+ This->m_UsbQueue->TransferDescriptorCompletionCallback(DoneHead);
+ }
+ if (CStatus & OHCI_ROOT_HUB_STATUS_CHANGE)
+ {
+ //
+ // device connected, lets check which port
+ //
+ for(Index = 0; Index < This->m_NumberOfPorts; Index++)
+ {
+ //
+ // read port status
+ //
+ PortStatus = READ_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_RH_PORT_STATUS(Index)));
+
+ //
+ // check if there is a status change
+ //
+ if (PortStatus & OHCI_RH_PORTSTATUS_CSC)
+ {
+ //
+ // did a device connect
+ //
+ if (PortStatus & OHCI_RH_PORTSTATUS_CCS)
+ {
+ //
+ // device connected
+ //
+ DPRINT1("New device arrival at Port %d LowSpeed %x\n", Index, (PortStatus & OHCI_RH_PORTSTATUS_LSDA));
+
+ //
+ // enable port
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_RH_PORT_STATUS(Index)), OHCI_RH_PORTSTATUS_PES);
+
+
+ //
+ // store change
+ //
+ This->m_PortStatus[Index].PortStatus |= USB_PORT_STATUS_CONNECT;
+ This->m_PortStatus[Index].PortChange |= USB_PORT_STATUS_CONNECT;
+
+ if ((PortStatus & OHCI_RH_PORTSTATUS_LSDA))
+ {
+ //
+ // low speed device connected
+ //
+ This->m_PortStatus[Index].PortStatus |= USB_PORT_STATUS_LOW_SPEED;
+ }
+ }
+ else
+ {
+ //
+ // device disconnected
+ //
+ DPRINT1("Device disconnected at Port %x\n", Index);
+
+ //
+ // update port status flags
+ //
+ This->m_PortStatus[Index].PortStatus &= ~USB_PORT_STATUS_LOW_SPEED;
+ This->m_PortStatus[Index].PortStatus &= ~USB_PORT_STATUS_CONNECT;
+ This->m_PortStatus[Index].PortChange |= USB_PORT_STATUS_CONNECT;
+ }
+
+ //
+ // is there a status change callback
+ //
+ if (This->m_SCECallBack != NULL)
+ {
+ //
+ // queue work item for processing
+ //
+ ExQueueWorkItem(&This->m_StatusChangeWorkItem, DelayedWorkQueue);
+ }
+ }
+ }
+ }
+
+
}
VOID