diff --git a/drivers/usb/usbehci_new/hardware.cpp b/drivers/usb/usbehci_new/hardware.cpp index 37449102af0..4a104c9c8f1 100644 --- a/drivers/usb/usbehci_new/hardware.cpp +++ b/drivers/usb/usbehci_new/hardware.cpp @@ -602,6 +602,9 @@ CUSBHardwareDevice::ResetPort( { ULONG PortStatus; + if (PortIndex > m_Capabilities.HCSParams.PortCount) + return STATUS_UNSUCCESSFUL; + PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex)); if (PortStatus & EHCI_PRT_SLOWSPEEDLINE) { @@ -640,7 +643,8 @@ CUSBHardwareDevice::ResetPort( return STATUS_SUCCESS; } -NTSTATUS CUSBHardwareDevice::GetPortStatus( +NTSTATUS +CUSBHardwareDevice::GetPortStatus( ULONG PortId, OUT USHORT *PortStatus, OUT USHORT *PortChange) @@ -648,6 +652,11 @@ NTSTATUS CUSBHardwareDevice::GetPortStatus( ULONG Value; USHORT Status = 0, Change = 0; + DPRINT1("CUSBHardwareDevice::GetPortStatus\n"); + + if (PortId > m_Capabilities.HCSParams.PortCount) + return STATUS_UNSUCCESSFUL; + // // Get the value of the Port Status and Control Register // @@ -703,16 +712,28 @@ NTSTATUS CUSBHardwareDevice::GetPortStatus( if (Value & EHCI_PRT_ENABLEDSTATUSCHANGE) Change |= USB_PORT_STATUS_ENABLE; + *PortStatus = Status; + *PortChange = Change; + + //HACK: Maybe + if (Status == (USB_PORT_STATUS_HIGH_SPEED | USB_PORT_STATUS_CONNECT | USB_PORT_STATUS_POWER)) + *PortChange = USB_PORT_STATUS_CONNECT; return STATUS_SUCCESS; } -NTSTATUS CUSBHardwareDevice::ClearPortStatus( +NTSTATUS +CUSBHardwareDevice::ClearPortStatus( ULONG PortId, ULONG Status) { ULONG Value; + DPRINT1("CUSBHardwareDevice::ClearPortStatus\n"); + + if (PortId > m_Capabilities.HCSParams.PortCount) + return STATUS_UNSUCCESSFUL; + Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId)); if (Status == C_PORT_RESET) @@ -737,18 +758,26 @@ NTSTATUS CUSBHardwareDevice::ClearPortStatus( } -NTSTATUS CUSBHardwareDevice::SetPortFeature( +NTSTATUS +CUSBHardwareDevice::SetPortFeature( ULONG PortId, ULONG Feature) { ULONG Value; + DPRINT1("CUSBHardwareDevice::SetPortFeature\n"); + + if (PortId > m_Capabilities.HCSParams.PortCount) + return STATUS_UNSUCCESSFUL; + Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId)); + if (Feature == PORT_ENABLE) { // // FIXME: EHCI Ports can only be disabled via reset // + DPRINT1("PORT_ENABLE not supported for EHCI\n"); } if (Feature == PORT_RESET) @@ -757,7 +786,6 @@ NTSTATUS CUSBHardwareDevice::SetPortFeature( { DPRINT1("Non HighSpeed device. Releasing Ownership\n"); } - // // Reset and clean enable // @@ -769,17 +797,21 @@ NTSTATUS CUSBHardwareDevice::SetPortFeature( } if (Feature == PORT_POWER) - DPRINT1("Not implemented\n"); + DPRINT1("PORT_POWER Not implemented\n"); return STATUS_SUCCESS; } -VOID CUSBHardwareDevice::SetAsyncListRegister(ULONG PhysicalAddress) +VOID +CUSBHardwareDevice::SetAsyncListRegister( + ULONG PhysicalAddress) { EHCI_WRITE_REGISTER_ULONG(EHCI_ASYNCLISTBASE, PhysicalAddress); } -VOID CUSBHardwareDevice::SetPeriodicListRegister(ULONG PhysicalAddress) +VOID +CUSBHardwareDevice::SetPeriodicListRegister( + ULONG PhysicalAddress) { EHCI_WRITE_REGISTER_ULONG(EHCI_PERIODICLISTBASE, PhysicalAddress); } diff --git a/drivers/usb/usbehci_new/hub_controller.cpp b/drivers/usb/usbehci_new/hub_controller.cpp index 05ca3abf971..f322048c7bb 100644 --- a/drivers/usb/usbehci_new/hub_controller.cpp +++ b/drivers/usb/usbehci_new/hub_controller.cpp @@ -90,6 +90,7 @@ protected: RTL_BITMAP m_DeviceAddressBitmap; PULONG m_DeviceAddressBitmapBuffer; LIST_ENTRY m_UsbDeviceList; + PIRP m_PendingSCEIrp; }; typedef struct @@ -692,6 +693,60 @@ CHubController::HandleBulkOrInterruptTransfer( IN OUT PIRP Irp, PURB Urb) { + ULONG PortCount, PortId; + USHORT PortStatus, PortChange; + + // + // First check if the request is for the Status Change Endpoint + // + + // + // Is the Request for the root hub + // + if (Urb->UrbHeader.UsbdDeviceHandle==0) + { + // + // There should only be one SCE request pending at a time + // + ASSERT (m_PendingSCEIrp == NULL); + + // + // Get the number of ports and check each one for device connected + // + m_Hardware->GetDeviceDetails(NULL, NULL, &PortCount, NULL); + DPRINT1("SCE Request\n"); + DPRINT1("PortCount %d\n", PortCount); + ((PULONG)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] = 0; + for (PortId = 0; PortId < PortCount; PortId++) + { + m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange); + + DPRINT1("Port %d: Status %x, Change %x\n", PortId, PortStatus, PortChange); + + // + // FIXME: Verify that this is correct. + // + if ((PortStatus & USB_PORT_STATUS_CONNECT) && (PortChange & USB_PORT_STATUS_CONNECT)) + { + DPRINT1("Device is connected on port %d\n", PortId); + ((PUCHAR)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] = 1 << ((PortId + 1) & 7); + break; + } + } + + // + // If there were changes then return SUCCESS + // + if (((PULONG)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] != 0) + return STATUS_SUCCESS; + + // + // Else pend the IRP, to be completed when a device connects or disconnects. + // + m_PendingSCEIrp = Irp; + IoMarkIrpPending(Irp); + return STATUS_PENDING; + } UNIMPLEMENTED return STATUS_NOT_IMPLEMENTED; } @@ -743,9 +798,8 @@ CHubController::HandleClassOther( // // get port status // - //Status = m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange); + Status = m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange); - Status = STATUS_SUCCESS; if (NT_SUCCESS(Status)) { // @@ -771,10 +825,10 @@ CHubController::HandleClassOther( switch (Urb->UrbControlVendorClassRequest.Value) { case C_PORT_CONNECTION: - //Status = m_Hardware->ClearPortStatus(PortId, C_PORT_CONNECTION); + Status = m_Hardware->ClearPortStatus(PortId, C_PORT_CONNECTION); break; case C_PORT_RESET: - //Status= m_Hardware->ClearPortStatus(PortId, C_PORT_RESET); + Status= m_Hardware->ClearPortStatus(PortId, C_PORT_RESET); break; default: DPRINT("Unknown Value for Clear Feature %x \n", Urb->UrbControlVendorClassRequest.Value); @@ -806,7 +860,7 @@ CHubController::HandleClassOther( // // set suspend port feature // - Status = STATUS_SUCCESS; //m_Hardware->SetPortFeature(PortId, PORT_SUSPEND); + Status = m_Hardware->SetPortFeature(PortId, PORT_SUSPEND); break; } case PORT_POWER: @@ -814,7 +868,7 @@ CHubController::HandleClassOther( // // set power feature on port // - Status = STATUS_SUCCESS; //m_Hardware->SetPortFeature(PortId, PORT_POWER); + Status = m_Hardware->SetPortFeature(PortId, PORT_POWER); break; } @@ -1232,9 +1286,12 @@ CHubController::HandleDeviceControl( break; } } + if (Status != STATUS_PENDING) + { + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } - Irp->IoStatus.Status = Status; - IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } diff --git a/drivers/usb/usbehci_new/usb_request.cpp b/drivers/usb/usbehci_new/usb_request.cpp index 18a3a1a8205..26136cce7cc 100644 --- a/drivers/usb/usbehci_new/usb_request.cpp +++ b/drivers/usb/usbehci_new/usb_request.cpp @@ -70,6 +70,7 @@ protected: PQUEUE_HEAD m_QueueHead; PQUEUE_TRANSFER_DESCRIPTOR m_TransferDescriptors[3]; PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket; + PHYSICAL_ADDRESS m_DescriptorSetupPacket; }; //---------------------------------------------------------------------------------------- @@ -570,14 +571,15 @@ CUSBRequest::BuildControlTransferQueueHead( } // - // FIXME: where put MDL virtual address? + // Control Transfers have only one in or out buffer if one at all. Put in the QueueHead the + // same as BulkTransfers. USBQueue will use the Mdl to fill in the BufferPointers // - + QueueHead->Mdl = m_TransferBufferMDL; // - // link setup packet into buffer - VIRTUAL Address!!! + // link setup packet into buffer - Physical Address!!! // - m_TransferDescriptors[0]->BufferPointer[0] = (ULONG)PtrToUlong(m_DescriptorPacket); + m_TransferDescriptors[0]->BufferPointer[0] = (ULONG)PtrToUlong(m_DescriptorSetupPacket.LowPart); // // link transfer descriptors to queue head @@ -791,6 +793,7 @@ CUSBRequest::BuildSetupPacket() // copy setup packet // RtlCopyMemory(m_DescriptorPacket, m_SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + m_DescriptorSetupPacket = PhysicalAddress; } //