public static void WaitForQueueHead(EHCIController controller, EHCIQueueHead *head) { while (!head->Transfer->Executed) { ProcessHead(controller, head); } }
public static void RemoveHead(EHCIController controller, EHCIQueueHead *head) { mMutex.Lock(); /** * Set next to previous */ if (head->Previous != null) { if (head->Next != null) { head->Previous->Head = head->Head; head->Previous->Next = head->Next; } else { head->Previous->Head = TD_TERMINATE; head->Previous->Next = null; } } /** * Set previous to next */ if (head->Next != null) { head->Next->Previous = head->Previous; } head->Allocated = false; mMutex.Unlock(); }
/// <summary> /// Insert head /// </summary> /// <param name="controller">UHCIController</param> /// <param name="head"></param> public static void InsertHead(EHCIController controller, EHCIQueueHead *head) { mMutex.Lock(); EHCIQueueHead *end = controller.FirstHead; while (true) { if (end->Next != null) { end = end->Next; } else { break; } } head->Head = TD_TERMINATE; head->Previous = end; head->Next = null; end->Next = head; end->Head = (int)Paging.GetPhysicalFromVirtual(head); mMutex.Unlock(); }
private static unsafe void resetPort(EHCIController controller, int portNum) { /** * Set reset bit */ setPortBit(controller, portNum, PORTSC_RESET); /** * Wait for 60 ms */ Tasking.CurrentTask.CurrentThread.Sleep(0, 60); /** * Unset reset bit */ unsetPortBit(controller, portNum, PORTSC_RESET); /** * Wait for atleast 150ms for link to go up */ for (int i = 0; i < 15; i++) { Tasking.CurrentTask.CurrentThread.Sleep(0, 10); int status = *(int *)((controller.OperationalRegisters + REG_PORTSC) + (portNum * 4)); /** * Is it even connected? */ if (((status) & PORTSC_CUR_STAT) == 0) { break; } /** * Status changed? */ if (((status) & (PORTSC_CON | PORTSC_EN_CHNG)) > 0) { unsetPortBit(controller, portNum, PORTSC_CON | PORTSC_EN_CHNG); continue; } /** * Enabled? */ if ((status & PORTSC_EN) > 0) { break; } } }
/// <summary> /// Set bit on port /// </summary> /// <param name="port">Port number</param> /// <param name="bit">Bit to setr</param> private unsafe static void setPortBit(EHCIController uhciDev, int port, ushort bit) { int *portAdr = (int *)((uhciDev.OperationalRegisters + REG_PORTSC) + (port * 4)); int status = *portAdr; status |= bit; // Reset port changes status &= ~PORTSC_CHANGE; *portAdr = status; }
private unsafe static EHCIQueueHead *AllocateEmptyQH(EHCIController controller) { EHCIQueueHead *queueHead = GetQueueHead(controller); queueHead->Head = FL_TERMINATE; queueHead->EPCapabilities = 0x00; queueHead->EPCharacteristics = 0x00; queueHead->CurLink = 0x00; queueHead->NextLink = 0x00; queueHead->Token = 0x00; queueHead->BufferPointer = 0x00; queueHead->Next = null; queueHead->Previous = null; queueHead->Transfer = null; return(queueHead); }
/// <summary> /// Probe usb devices on port /// </summary> /// <param name="uhciDev">The UHCI device</param> private static unsafe void probe(EHCIController controller) { /** * UHCI only supports 2 ports, so just 2 :-) */ for (int portNum = 0; portNum < controller.PortNum; portNum++) { resetPort(controller, portNum); int status = *(int *)((controller.OperationalRegisters + REG_PORTSC) + (portNum * 4)); /** * Is the port even connected? */ if ((status & PORTSC_CUR_STAT) == 0) { continue; } USBDevice dev = new USBDevice(); dev.Controller = controller; dev.Control = Control; dev.PrepareInterrupt = PrepareInterrupt; dev.TransferOne = TransferOne; /** * Root hub */ dev.Parent = null; dev.Port = (uint)portNum; dev.State = USBDeviceState.ATTACHED; dev.Speed = USBDeviceSpeed.HIGH_SPEED; if (!dev.Init()) { Console.Write("[EHCI] Device init failed on port "); Console.WriteNum(portNum); Console.WriteLine(""); Heap.Free(dev); } } }
/// <summary> /// Process Queue Head /// </summary> /// <param name="device"></param> /// <param name="head"></param> public static void ProcessHead(EHCIController controller, EHCIQueueHead *head) { USBTransfer *transfer = head->Transfer; EHCITransferDescriptor *td = head->Transmit; Console.WriteHex(td->Token); Console.WriteLine(" :)"); if (transfer->Executed) { //if(transfer->ID > 0) //{ // PrintQueue(transfer->ID, head); //} head->Transfer = null; /** * We need to toggle endpoint state here */ /** * Remove head from schedule */ RemoveHead(controller, head); /** * Free transmit descriptors */ EHCITransferDescriptor *tdE = td; while (tdE != null) { EHCITransferDescriptor *next = tdE->Next; FreeTransmit(controller, tdE); tdE = next; } } }
/// <summary> /// Get Queue head item /// </summary> /// <param name="dev">Device</param> /// <returns></returns> private unsafe static EHCIQueueHead *GetQueueHead(EHCIController dev) { mMutex.Lock(); int i = 0; while (i < MAX_HEADS) { if (!dev.QueueHeadPool[i].Allocated) { dev.QueueHeadPool[i].Allocated = true; dev.QueueHeadPool[i].Next = null; dev.QueueHeadPool[i].Previous = null; mMutex.Unlock(); return((EHCIQueueHead *)(((int)dev.QueueHeadPool) + (sizeof(EHCIQueueHead) * i))); } i++; } mMutex.Unlock(); return(null); }
/// <summary> /// Get Transmit descriptor item /// </summary> /// <param name="dev">Device</param> /// <returns></returns> private unsafe static EHCITransferDescriptor *GetTransmitDescriptor(EHCIController dev) { mMutex.Lock(); int i = 0; while (i < MAX_HEADS) { if (!dev.TransferPool[i].Allocated) { dev.TransferPool[i].Allocated = true; dev.TransferPool[i].Next = null; dev.TransferPool[i].Previous = null; mMutex.Unlock(); return((EHCITransferDescriptor *)(((int)dev.TransferPool) + (sizeof(EHCITransferDescriptor) * i))); } i++; } mMutex.Unlock(); return(null); }
private unsafe static void initDevice(PciDevice dev) { if ((dev.BAR0.flags & Pci.BAR_IO) != 0) { Console.WriteLine("[EHCI] Only Memory mapped IO supported"); } /** * Enable bus mastering */ Pci.EnableBusMastering(dev); ulong barAddress = dev.BAR0.Address; EHCIController controller = new EHCIController(); controller.MemoryBase = (int)Paging.MapToVirtual(Paging.KernelDirectory, (int)barAddress, 20 * 0x1000, Paging.PageFlags.Writable | Paging.PageFlags.Present); controller.FrameList = (int *)Heap.AlignedAlloc(0x1000, sizeof(int) * 1024); controller.CapabilitiesRegisters = (EHCIHostCapRegister *)(controller.MemoryBase); controller.OperationalRegisters = controller.MemoryBase + (*controller.CapabilitiesRegisters).CapLength; controller.PortNum = ReadPorts(controller); controller.QueueHeadPool = (EHCIQueueHead *)Heap.AlignedAlloc(0x1000, sizeof(EHCIQueueHead) * MAX_HEADS); controller.TransferPool = (EHCITransferDescriptor *)Heap.AlignedAlloc(0x1000, sizeof(EHCITransferDescriptor) * MAX_TRANSFERS); controller.AsyncQueueHead = AllocateEmptyQH(controller); // Link to itself controller.AsyncQueueHead[0].Head = (int)controller.AsyncQueueHead | FL_QUEUEHEAD; controller.PeriodicQueuehead = AllocateEmptyQH(controller); for (int i = 0; i < 1024; i++) { controller.FrameList[i] = FL_QUEUEHEAD | (int)controller.PeriodicQueuehead; } // Set device *(int *)(controller.OperationalRegisters + REG_FRINDEX) = 0; *(int *)(controller.OperationalRegisters + REG_PERIODICLISTBASE) = (int)Paging.GetPhysicalFromVirtual(controller.FrameList); *(int *)(controller.OperationalRegisters + REG_ASYNCLISTADDR) = (int)Paging.GetPhysicalFromVirtual(controller.AsyncQueueHead); *(int *)(controller.OperationalRegisters + REG_CTRLDSSEGMENT) = 0; Console.Write("Periodic: "); Console.WriteHex((int)Paging.GetPhysicalFromVirtual(controller.FrameList)); Console.WriteLine(""); Console.Write("Periodic: "); Console.WriteHex((int)Paging.GetPhysicalFromVirtual(controller.FrameList)); Console.WriteLine(""); Console.Write("FRAME LIST PHYS: "); Console.WriteHex((int)Paging.GetPhysicalFromVirtual(controller.FrameList)); Console.WriteLine(""); Console.Write("FRAME LIST ENTRY: "); Console.WriteHex((int)controller.FrameList); Console.WriteLine(""); Console.Write("FRAME LIST ENTRY 1: "); Console.WriteHex(controller.FrameList[0]); Console.WriteLine(""); // Reset status *(int *)(controller.OperationalRegisters + REG_USBSTS) = 0x3F; // enable device *(int *)(controller.OperationalRegisters + REG_USBCMD) = USBCMD_PSE | USBCMD_RUN | USBCMD_ASPME | (ITC_8MICROFRAMES << USBCMD_ITC); // Wait till done while ((*(int *)(controller.OperationalRegisters + REG_USBSTS) & (1 << 12)) > 0) { CPU.HLT(); } Console.Write("[EHCI] Detected with "); Console.WriteHex(controller.PortNum); Console.WriteLine(" ports"); probe(controller); }
public static void FreeTransmit(EHCIController controller, EHCITransferDescriptor *transmit) { transmit->Allocated = false; }
private unsafe static EHCITransferDescriptor *AllocateEmptyTransmit(EHCIController controller) { EHCITransferDescriptor *queueHead = GetTransmitDescriptor(controller); return(queueHead); }
/// <summary> /// Control USB Device /// </summary> /// <param name="dev"></param> /// <param name="transfer"></param> private unsafe static void Control(USBDevice dev, USBTransfer *transfer) { USBDeviceRequest request = transfer->Request; transfer->Executed = false; EHCIController controller = (EHCIController)dev.Controller; EHCITransferDescriptor *td = AllocateEmptyTransmit(controller); EHCITransferDescriptor *head = td; EHCITransferDescriptor *prev = null; USBDeviceRequest *a = (USBDeviceRequest *)Heap.Alloc(sizeof(USBDeviceRequest)); a->Request = request.Request; a->Index = request.Index; a->Length = request.Length; a->Type = request.Type; a->Value = request.Value; InitTransmit(td, prev, dev.Speed, dev.Address, 0, 0, TRANS_PACKET_SETUP, (uint)sizeof(USBDeviceRequest), (byte *)a); prev = td; uint packetType = ((request.Type & USBDevice.TYPE_DEVICETOHOST) > 0) ? TRANS_PACKET_IN : TRANS_PACKET_OUT; byte *ptr = transfer->Data; uint packetSize = transfer->Length; uint offset = 0; uint toggle = 0; uint remaining = packetSize; while (remaining > 0) { td = AllocateEmptyTransmit(controller); if (td == null) { return; } packetSize = remaining; if (packetSize > dev.MaxPacketSize) { packetSize = dev.MaxPacketSize; } remaining -= packetSize; toggle ^= 1; InitTransmit(td, prev, dev.Speed, dev.Address, 0, toggle, packetType, packetSize, ptr + offset); prev = td; offset += packetSize; } td = AllocateEmptyTransmit(controller); if (td == null) { return; } packetType = ((request.Type & USBDevice.TYPE_DEVICETOHOST) > 0) ? TRANS_PACKET_OUT : TRANS_PACKET_IN; toggle = 1; InitTransmit(td, prev, dev.Speed, dev.Address, 0, toggle, packetType, 0, null); EHCIQueueHead *qh = AllocateEmptyQH(controller); InitHead(qh, null, dev.Address, 0, packetSize); qh->NextLink = (int)td; qh->Transmit = td; qh->Transfer = transfer; InsertHead(controller, qh); WaitForQueueHead(controller, qh); }
/// <summary> /// Read ports from controller /// </summary> /// <param name="controller"></param> /// <returns></returns> private unsafe static int ReadPorts(EHCIController controller) { return((int)((*controller.CapabilitiesRegisters).HCSParams & HCSPARAMS_PORTS_MASK)); }