protected static void *AllocQTDbuffer(UHCI_qTD_Struct *td) { #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Alloc qTD Buffer"); BasicConsole.DelayOutput(5); #endif td->virtBuffer = FOS_System.Heap.AllocZeroedAPB(0x1000, 0x1000, "UHCI : AllocQTDBuffer"); td->buffer = (uint *)VirtMemManager.GetPhysicalAddress(td->virtBuffer); return(td->virtBuffer); }
private void CreateHeap() { #if PROCESS_TRACE BasicConsole.WriteLine("Allocating memory for heap..."); #endif // Allocate memory for new heap uint heapPages = 64; // 256KiB, page-aligned FOS_System.HeapBlock *heapPtr = (FOS_System.HeapBlock *)VirtMemManager.MapFreePages( UserMode ? VirtMemImpl.PageFlags.None : VirtMemImpl.PageFlags.KernelOnly, (int)heapPages); #if PROCESS_TRACE BasicConsole.WriteLine("Generating physical addresses..."); #endif uint[] pAddrs = new uint[heapPages]; for (uint currPtr = (uint)heapPtr, i = 0; i < heapPages; currPtr += 4096, i++) { pAddrs[i] = VirtMemManager.GetPhysicalAddress(currPtr); } #if PROCESS_TRACE BasicConsole.WriteLine("Adding memory to current process (kernel task) layout..."); #endif // Add heap memory to current (kernel) process's memory // - Makes sure it won't be mapped out during initialisation ProcessManager.CurrentProcess.TheMemoryLayout.AddDataPages((uint)heapPtr, pAddrs); // Force reload of the memory layout ProcessManager.CurrentProcess.TheMemoryLayout.Load(ProcessManager.CurrentProcess.UserMode); #if PROCESS_TRACE BasicConsole.WriteLine("Initialising heap..."); #endif // Initialise the heap FOS_System.Heap.InitBlock(heapPtr, heapPages * 4096, 32); #if PROCESS_TRACE BasicConsole.WriteLine("Adding memory to layout..."); #endif // Add allocated new process's memory to layout TheMemoryLayout.AddDataPages((uint)heapPtr, pAddrs); #if PROCESS_TRACE BasicConsole.WriteLine("Removing memory from current process (kernel task) layout..."); #endif // Remove heap memory from current (kernel) process's memory ProcessManager.CurrentProcess.TheMemoryLayout.RemovePages((uint)heapPtr, heapPages); #if PROCESS_TRACE BasicConsole.WriteLine("Setting heap pointer..."); #endif // Set heap pointer HeapPtr = heapPtr; }
protected void CreateQH(UHCI_QueueHead_Struct *head, uint horizPtr, UHCI_qTD_Struct *firstTD) { #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Create QH"); BasicConsole.DelayOutput(5); #endif head->next = (UHCI_QueueHead_Struct *)UHCI_Consts.BIT_T; // (paging_getPhysAddr((void*)horizPtr) & 0xFFFFFFF0) | BIT_QH; if (firstTD == null) { head->transfer = (UHCI_qTD_Struct *)UHCI_Consts.BIT_T; } else { head->transfer = (UHCI_qTD_Struct *)((uint)VirtMemManager.GetPhysicalAddress(firstTD) & 0xFFFFFFF0); head->q_first = firstTD; } }
protected override void _INTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, void *buffer, ushort length) { #if UHCI_TRACE BasicConsole.WriteLine("UHCI: IN Transaction"); BasicConsole.DelayOutput(5); #endif UHCITransaction uT = new UHCITransaction(); uTransaction.underlyingTz = uT; uT.inBuffer = buffer; uT.inLength = length; uT.qTD = CreateQTD_IO((UHCI_QueueHead_Struct *)transfer.underlyingTransferData, (uint *)1, UHCI_Consts.TD_IN, toggle, length, transfer.device.address, transfer.endpoint, transfer.packetSize); uT.qTDBuffer = uT.qTD->virtBuffer; if (transfer.transactions.Count > 0) { UHCITransaction uLastTransaction = (UHCITransaction)((USBTransaction)(transfer.transactions[transfer.transactions.Count - 1])).underlyingTz; uLastTransaction.qTD->next = (((uint)VirtMemManager.GetPhysicalAddress(uT.qTD) & 0xFFFFFFF0) | UHCI_Consts.BIT_Vf); // build TD queue uLastTransaction.qTD->q_next = uT.qTD; } }
protected override void _SETUPTransaction(USBTransfer transfer, USBTransaction uTransaction, bool toggle, ushort tokenBytes, byte type, byte req, byte hiVal, byte loVal, ushort index, ushort length) { #if UHCI_TRACE BasicConsole.WriteLine("UHCI: SETUP Transaction"); BasicConsole.DelayOutput(5); #endif UHCITransaction uT = new UHCITransaction(); uTransaction.underlyingTz = uT; uT.inBuffer = null; uT.inLength = 0; uT.qTD = CreateQTD_SETUP((UHCI_QueueHead_Struct *)transfer.underlyingTransferData, (uint *)1, toggle, tokenBytes, type, req, hiVal, loVal, index, length, transfer.device.address, transfer.endpoint, transfer.packetSize); uT.qTDBuffer = uT.qTD->virtBuffer; if (transfer.transactions.Count > 0) { UHCITransaction uLastTransaction = (UHCITransaction)((USBTransaction)(transfer.transactions[transfer.transactions.Count - 1])).underlyingTz; uLastTransaction.qTD->next = (((uint)VirtMemManager.GetPhysicalAddress(uT.qTD) & 0xFFFFFFF0) | UHCI_Consts.BIT_Vf); // build TD queue uLastTransaction.qTD->q_next = uT.qTD; } }
protected override void _IssueTransfer(USBTransfer transfer) { #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Issue Transfer"); BasicConsole.DelayOutput(5); #endif UHCITransaction firstTransaction = (UHCITransaction)((USBTransaction)transfer.transactions[0]).underlyingTz; UHCITransaction lastTransaction = (UHCITransaction)((USBTransaction)transfer.transactions[transfer.transactions.Count - 1]).underlyingTz; UHCI_qTD.SetIntOnComplete(lastTransaction.qTD, true); // We want an interrupt after complete transfer CreateQH((UHCI_QueueHead_Struct *)transfer.underlyingTransferData, (uint)transfer.underlyingTransferData, firstTransaction.qTD); #if UHCI_TRACE BasicConsole.WriteLine(" Queue head data:"); BasicConsole.DumpMemory(transfer.underlyingTransferData, sizeof(UHCI_QueueHead_Struct)); BasicConsole.WriteLine(" Transactions data:"); for (int i = 0; i < transfer.transactions.Count; i++) { BasicConsole.Write(" "); BasicConsole.Write(i); BasicConsole.WriteLine(" : "); BasicConsole.WriteLine(" - qTD:"); BasicConsole.DumpMemory( ((UHCITransaction)((USBTransaction)transfer.transactions[i]).underlyingTz).qTD, sizeof(UHCI_qTD_Struct)); BasicConsole.WriteLine(" - qTDBuffer:"); BasicConsole.DumpMemory( ((UHCITransaction)((USBTransaction)transfer.transactions[i]).underlyingTz).qTDBuffer, 16); } BasicConsole.DelayOutput(60); BasicConsole.WriteLine("UHCI: Issuing transfer..."); #endif for (byte i = 0; i < UHCI_Consts.NUMBER_OF_UHCI_RETRIES && !transfer.success; i++) { TransactionsCompleted = 0; for (int j = 0; j < transfer.transactions.Count; j++) { USBTransaction elem = (USBTransaction)transfer.transactions[j]; UHCITransaction uT = (UHCITransaction)(elem.underlyingTz); uT.qTD->u1 = uT.qTD->u1 & 0xFF00FFFF; UHCI_qTD.SetActive(uT.qTD, true); } // stop scheduler USBSTS.Write_UInt16(UHCI_Consts.STS_MASK); USBCMD.Write_UInt16((ushort)(USBCMD.Read_UInt16() & ~UHCI_Consts.CMD_RS)); while ((USBSTS.Read_UInt16() & UHCI_Consts.STS_HCHALTED) == 0) { Hardware.Devices.Timer.Default.Wait(10); } // update scheduler uint qhPhysAddr = ((uint)VirtMemManager.GetPhysicalAddress(transfer.underlyingTransferData) | UHCI_Consts.BIT_QH); FrameList[0] = qhPhysAddr; FRBASEADD.Write_UInt32((uint)VirtMemManager.GetPhysicalAddress(FrameList)); FRNUM.Write_UInt16(0); // start scheduler USBSTS.Write_UInt16(UHCI_Consts.STS_MASK); USBCMD.Write_UInt16((ushort)(USBCMD.Read_UInt16() | UHCI_Consts.CMD_RS)); while ((USBSTS.Read_UInt16() & UHCI_Consts.STS_HCHALTED) != 0) { Hardware.Devices.Timer.Default.Wait(10); } #if UHCI_TRACE BasicConsole.WriteLine(((FOS_System.String) "USBINT val: ") + USBINTR.Read_UInt16()); #endif // run transactions bool active = true; int timeout = 100; //5 seconds while (active && timeout > 0) { active = false; for (int j = 0; j < transfer.transactions.Count; j++) { USBTransaction elem = (USBTransaction)transfer.transactions[j]; UHCITransaction uT = (UHCITransaction)(elem.underlyingTz); active = active || ((uT.qTD->u1 & 0x00FF0000) == 0x00800000); } Hardware.Devices.Timer.Default.Wait(50); timeout--; } #if UHCI_TRACE BasicConsole.WriteLine("Finished waiting."); #endif FrameList[0] = UHCI_Consts.BIT_T; if (timeout == 0 || TransactionsCompleted != transfer.transactions.Count) { #if UHCI_TRACE BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("UHCI: Error! Transactions wait timed out or wrong number of transactions completed."); BasicConsole.SetTextColour(BasicConsole.default_colour); BasicConsole.WriteLine(((FOS_System.String) "Transactions completed: ") + TransactionsCompleted); if (timeout == 0) { BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("UHCI: Error! Transfer timed out."); BasicConsole.SetTextColour(BasicConsole.default_colour); } #endif transfer.success = false; bool completeDespiteNoInterrupt = true; for (int j = 0; j < transfer.transactions.Count; j++) { USBTransaction elem = (USBTransaction)transfer.transactions[j]; UHCITransaction uT = (UHCITransaction)(elem.underlyingTz); #if UHCI_TRACE BasicConsole.WriteLine(((FOS_System.String) "u1=") + uT.qTD->u1 + ", u2=" + uT.qTD->u2); BasicConsole.WriteLine(((FOS_System.String) "Status=") + (byte)(uT.qTD->u1 >> 16)); #endif completeDespiteNoInterrupt = completeDespiteNoInterrupt && isTransactionSuccessful(uT); } transfer.success = completeDespiteNoInterrupt; #if UHCI_TRACE BasicConsole.SetTextColour(BasicConsole.warning_colour); BasicConsole.WriteLine(((FOS_System.String) "Complete despite no interrupts: ") + completeDespiteNoInterrupt); BasicConsole.SetTextColour(BasicConsole.default_colour); BasicConsole.DelayOutput(5); #endif } else { transfer.success = true; } if (transfer.success) { // check conditions and save data for (int j = 0; j < transfer.transactions.Count; j++) { USBTransaction elem = (USBTransaction)transfer.transactions[j]; UHCITransaction uT = (UHCITransaction)(elem.underlyingTz); transfer.success = transfer.success && isTransactionSuccessful(uT); // executed w/o error if (uT.inBuffer != null && uT.inLength != 0) { MemoryUtils.MemCpy_32((byte *)uT.inBuffer, (byte *)uT.qTDBuffer, uT.inLength); } } } #if UHCI_TRACE if (!transfer.success) { BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("UHCI: Transfer failed."); BasicConsole.SetTextColour(BasicConsole.default_colour); } else { BasicConsole.SetTextColour((char)0x0200); BasicConsole.WriteLine("Transfer succeeded."); BasicConsole.SetTextColour(BasicConsole.default_colour); } #endif } }
protected void ResetHC() { #if UHCI_TRACE BasicConsole.WriteLine("UHCI: ResetHC"); BasicConsole.DelayOutput(5); #endif //Processes.Scheduler.Disable(); // http://www.lowlevel.eu/wiki/Universal_Host_Controller_Interface#Informationen_vom_PCI-Treiber_holen ushort legacySupport = pciDevice.ReadRegister16(UHCI_Consts.PCI_LEGACY_SUPPORT); pciDevice.WriteRegister16(UHCI_Consts.PCI_LEGACY_SUPPORT, UHCI_Consts.PCI_LEGACY_SUPPORT_STATUS); // resets support status bits in Legacy support register USBCMD.Write_UInt16(UHCI_Consts.CMD_GRESET); Hardware.Devices.Timer.Default.Wait(50); USBCMD.Write_UInt16(0); RootPortCount = (byte)(pciDevice.BaseAddresses[4].Size() / 2); #if UHCI_TRACE BasicConsole.WriteLine(((FOS_System.String) "UHCI: RootPortCount=") + RootPortCount); #endif for (byte i = 2; i < RootPortCount; i++) { if ((PORTSC1.Read_UInt16((ushort)(i * 2)) & UHCI_Consts.PORT_VALID) == 0 || (PORTSC1.Read_UInt16((ushort)(i * 2)) == 0xFFFF)) { RootPortCount = i; break; } } #if UHCI_TRACE BasicConsole.WriteLine(((FOS_System.String) "UHCI: RootPortCount=") + RootPortCount); #endif if (RootPortCount > UHCI_Consts.PORTMAX) { RootPortCount = UHCI_Consts.PORTMAX; } #if UHCI_TRACE BasicConsole.WriteLine(((FOS_System.String) "UHCI: RootPortCount=") + RootPortCount); BasicConsole.DelayOutput(1); #endif RootPorts.Empty(); for (byte i = 0; i < RootPortCount; i++) { RootPorts.Add(new HCPort() { portNum = i }); } #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Checking HC state: Get USBCMD..."); BasicConsole.DelayOutput(1); #endif ushort usbcmd = USBCMD.Read_UInt16(); #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Checking HC state: Check..."); BasicConsole.DelayOutput(1); #endif if ((legacySupport & ~(UHCI_Consts.PCI_LEGACY_SUPPORT_STATUS | UHCI_Consts.PCI_LEGACY_SUPPORT_NO_CHG | UHCI_Consts.PCI_LEGACY_SUPPORT_PIRQ)) != 0 || (usbcmd & UHCI_Consts.CMD_RS) != 0 || (usbcmd & UHCI_Consts.CMD_CF) != 0 || (usbcmd & UHCI_Consts.CMD_EGSM) == 0 || (USBINTR.Read_UInt16() & UHCI_Consts.INT_MASK) != 0) { #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Checking HC state: Do reset..."); BasicConsole.DelayOutput(1); #endif USBSTS.Write_UInt16(UHCI_Consts.STS_MASK); Hardware.Devices.Timer.Default.Wait(1); USBCMD.Write_UInt16(UHCI_Consts.CMD_HCRESET); byte timeout = 50; while ((USBCMD.Read_UInt16() & UHCI_Consts.CMD_HCRESET) != 0) { if (timeout == 0) { #if UHCI_TRACE BasicConsole.WriteLine("UHCI: HC Reset timed out!"); BasicConsole.DelayOutput(1); #endif break; } Hardware.Devices.Timer.Default.Wait(10); timeout--; } #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Checking HC state: Turning off interrupts and HC..."); BasicConsole.DelayOutput(1); #endif USBINTR.Write_UInt16(0); // switch off all interrupts USBCMD.Write_UInt16(0); // switch off the host controller #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Checking HC state: Disabling ports..."); BasicConsole.DelayOutput(1); #endif for (byte i = 0; i < RootPortCount; i++) // switch off the valid root ports { PORTSC1.Write_UInt16(0, (ushort)(i * 2)); } } // TODO: mutex for frame list #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Creating queue head..."); BasicConsole.DelayOutput(1); #endif UHCI_QueueHead_Struct *qh = (UHCI_QueueHead_Struct *)FOS_System.Heap.AllocZeroedAPB((uint)sizeof(UHCI_QueueHead_Struct), 32, "UHCI : ResetHC"); qh->next = (UHCI_QueueHead_Struct *)UHCI_Consts.BIT_T; qh->transfer = (UHCI_qTD_Struct *)UHCI_Consts.BIT_T; qh->q_first = null; qh->q_last = null; qhPointer = qh; #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Setting up frame list entries..."); BasicConsole.DelayOutput(1); #endif for (ushort i = 0; i < 1024; i++) { FrameList[i] = UHCI_Consts.BIT_T; } #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Setting SOFMOD..."); BasicConsole.DelayOutput(1); #endif // define each millisecond one frame, provide physical address of frame list, and start at frame 0 SOFMOD.Write_Byte(0x40); // SOF cycle time: 12000. For a 12 MHz SOF counter clock input, this produces a 1 ms Frame period. #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Setting frame base addr and frame num..."); BasicConsole.DelayOutput(1); #endif FRBASEADD.Write_UInt32((uint)VirtMemManager.GetPhysicalAddress(FrameList)); FRNUM.Write_UInt16(0); #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Setting PCI PIRQ..."); BasicConsole.DelayOutput(1); #endif // set PIRQ pciDevice.WriteRegister16(UHCI_Consts.PCI_LEGACY_SUPPORT, UHCI_Consts.PCI_LEGACY_SUPPORT_PIRQ); #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Starting HC..."); BasicConsole.DelayOutput(1); #endif // start host controller and mark it configured with a 64-byte max packet USBSTS.Write_UInt16(UHCI_Consts.STS_MASK); USBINTR.Write_UInt16(UHCI_Consts.INT_MASK); // switch on all interrupts USBCMD.Write_UInt16((ushort)(UHCI_Consts.CMD_RS | UHCI_Consts.CMD_CF | UHCI_Consts.CMD_MAXP)); #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Reset CSC ports..."); BasicConsole.DelayOutput(1); #endif for (byte i = 0; i < RootPortCount; i++) // reset the CSC of the valid root ports { PORTSC1.Write_UInt16(UHCI_Consts.PORT_CS_CHANGE, (ushort)(i * 2)); } #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Forcing global resume..."); BasicConsole.DelayOutput(1); #endif USBSTS.Write_UInt16(UHCI_Consts.STS_MASK); #if UHCI_TRACE BasicConsole.WriteLine(" - STS MASK set"); #endif USBCMD.Write_UInt16((ushort)(UHCI_Consts.CMD_RS | UHCI_Consts.CMD_CF | UHCI_Consts.CMD_MAXP | UHCI_Consts.CMD_FGR)); #if UHCI_TRACE BasicConsole.WriteLine(" - FGR issued"); #endif Hardware.Devices.Timer.Default.Wait(20); USBCMD.Write_UInt16((ushort)(UHCI_Consts.CMD_RS | UHCI_Consts.CMD_CF | UHCI_Consts.CMD_MAXP)); #if UHCI_TRACE BasicConsole.WriteLine(" - FGR cleared"); BasicConsole.DelayOutput(1); #endif Hardware.Devices.Timer.Default.Wait(100); #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Getting run state..."); BasicConsole.DelayOutput(1); #endif run = (USBCMD.Read_UInt16() & UHCI_Consts.CMD_RS) != 0; if (!run) { BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("UHCI: Run/Stop not set!"); BasicConsole.SetTextColour(BasicConsole.default_colour); BasicConsole.DelayOutput(5); } else { if ((USBSTS.Read_UInt16() & UHCI_Consts.STS_HCHALTED) == 0) { Status = HCIStatus.Active; EnablePorts(); // attaches the ports } else { BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("UHCI: HC Halted!"); BasicConsole.SetTextColour(BasicConsole.default_colour); BasicConsole.DelayOutput(5); } } }