From c5acda628c73296266856343b510258f619faa46 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Mon, 23 May 2011 11:29:55 +0000 Subject: [PATCH] [USBOHCI] - Fix bug in calculating offset of status register - Start implementing deferred processing routine - Signal status change when new device is arrived - Implement basic GetPortStatus - Start implementing SetPortFeature, ClearPortStatus - ResetPort not yet fully working, WIP svn path=/branches/usb-bringup/; revision=51858 --- drivers/usb/usbohci/hardware.cpp | 186 +++++++++++++++++++++++++++++-- drivers/usb/usbohci/hardware.h | 23 +++- 2 files changed, 199 insertions(+), 10 deletions(-) diff --git a/drivers/usb/usbohci/hardware.cpp b/drivers/usb/usbohci/hardware.cpp index 92a7d067f07..c162721165a 100644 --- a/drivers/usb/usbohci/hardware.cpp +++ b/drivers/usb/usbohci/hardware.cpp @@ -112,6 +112,7 @@ protected: 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 @@ -852,9 +853,11 @@ CUSBHardwareDevice::GetPortStatus( 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; } @@ -863,7 +866,84 @@ CUSBHardwareDevice::ClearPortStatus( ULONG PortId, ULONG Status) { - UNIMPLEMENTED + ULONG Value, Index = 0; + + DPRINT("CUSBHardwareDevice::ClearPortStatus PortId %x Feature %x\n", PortId, Status); + + if (PortId > m_NumberOfPorts) + return STATUS_UNSUCCESSFUL; + + // + // read port status + // + Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId))); + KeStallExecutionProcessor(100); + + if (Status == C_PORT_RESET) + { + // + // complete reset + // + WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)), OHCI_RH_PORTSTATUS_PRSC); + + 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("Wait...\n"); + + }while(Index++ < 10); + + if ((Value & OHCI_RH_PORTSTATUS_PRS)) + { + DPRINT1("Failed to reset\n"); + } + + // + // update port status + // + m_PortStatus[PortId].PortChange &= ~USB_PORT_STATUS_RESET; + + // + // sanity check + // + ASSERT((Value & OHCI_RH_PORTSTATUS_PES)); + + if (Value & OHCI_RH_PORTSTATUS_PES) + { + // + // port is enabled + // + m_PortStatus[PortId].PortStatus |= USB_PORT_STATUS_ENABLE; + } + } + + 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; } @@ -873,6 +953,16 @@ CUSBHardwareDevice::SetPortFeature( 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) { // @@ -899,11 +989,27 @@ CUSBHardwareDevice::SetPortFeature( } 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 // @@ -1045,7 +1151,7 @@ InterruptServiceRoutine( // // halt controller // - WRITE_REGISTER_ULONG((PULONG)((PUCHAR)(This->m_Base + OHCI_CONTROL_OFFSET)), OHCI_HC_FUNCTIONAL_STATE_RESET); + WRITE_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_CONTROL_OFFSET), OHCI_HC_FUNCTIONAL_STATE_RESET); } if (Status & OHCI_ROOT_HUB_STATUS_CHANGE) @@ -1053,12 +1159,11 @@ InterruptServiceRoutine( // // new device has arrived // - DPRINT1("InterruptServiceRoutine> New Device arrival\n"); // // 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); + WRITE_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_DISABLE_OFFSET), OHCI_ROOT_HUB_STATUS_CHANGE); Acknowledge |= OHCI_ROOT_HUB_STATUS_CHANGE; } @@ -1070,7 +1175,7 @@ InterruptServiceRoutine( // // ack change // - WRITE_REGISTER_ULONG((PULONG)((PUCHAR)(This->m_Base + OHCI_INTERRUPT_STATUS_OFFSET)), Acknowledge); + WRITE_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_STATUS_OFFSET), Acknowledge); } // @@ -1094,7 +1199,7 @@ OhciDefferedRoutine( IN PVOID SystemArgument2) { CUSBHardwareDevice *This; - ULONG CStatus; + ULONG CStatus, Index, PortStatus; // // get parameters @@ -1102,6 +1207,69 @@ OhciDefferedRoutine( This = (CUSBHardwareDevice*) SystemArgument1; CStatus = (ULONG) SystemArgument2; + 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)); + + // + // 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; + } + + // + // is there a status change callback + // + if (This->m_SCECallBack != NULL) + { + // + // queue work item for processing + // + ExQueueWorkItem(&This->m_StatusChangeWorkItem, DelayedWorkQueue); + } + } + else + { + // + // device disconnected + // + DPRINT1("Device disconnected at Port %x\n", Index); + } + } + } + } + } diff --git a/drivers/usb/usbohci/hardware.h b/drivers/usb/usbohci/hardware.h index 726ee3832de..e569b8f8ee0 100644 --- a/drivers/usb/usbohci/hardware.h +++ b/drivers/usb/usbohci/hardware.h @@ -210,4 +210,25 @@ typedef struct // // Maximum port count set by OHCI // -#define OHCI_MAX_PORT_COUNT 15 \ No newline at end of file +#define OHCI_MAX_PORT_COUNT 15 + + +typedef struct +{ + ULONG PortStatus; + ULONG PortChange; +}OHCI_PORT_STATUS; + + +typedef struct { + // Hardware part 16 bytes + uint32 flags; // Flags field + uint32 buffer_physical; // Physical buffer pointer + uint32 next_physical_descriptor; // Physical pointer next descriptor + uint32 last_physical_byte_address; // Physical pointer to buffer end + // Software part + addr_t physical_address; // Physical address of this descriptor + size_t buffer_size; // Size of the buffer + void *buffer_logical; // Logical pointer to the buffer + void *next_logical_descriptor; // Logical pointer next descriptor +} ohci_general_td; \ No newline at end of file -- 2.17.1