public static void RemoveHead(UHCIController controller, UHCIQueueHead *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_POINTER_TERMINATE; head->Previous->Next = null; } } /** * Set previous to next */ if (head->Next != null) { head->Next->Previous = head->Previous; } FreeHead(controller, head); mMutex.Unlock(); }
/// <summary> /// Prepare interrupt /// </summary> /// <param name="dev"></param> /// <param name="transfer"></param> private static void PrepareInterrupt(USBDevice dev, USBTransfer *transfer) { UHCIController controller = (UHCIController)dev.Controller; uint endp = (uint)(dev.EndPointDesc->Address & 0xF); UHCITransmitDescriptor *td = GetTransmit(controller); if (td == null) { transfer->Success = false; transfer->Executed = true; } UHCITransmitDescriptor *head = td; /** * Initalize read */ InitTransmit(td, null, dev.Speed, dev.Address, endp, dev.Toggle, TRANS_PACKET_IN, transfer->Length, transfer->Data); UHCIQueueHead *qh = GetQueueHead(controller); qh->Element = (int)Paging.GetPhysicalFromVirtual(head); qh->Head = 0; qh->Transfer = transfer; qh->Transmit = head; InsertHead(controller, qh); }
public static void WaitForQueueHead(UHCIController controller, UHCIQueueHead *head) { while (!head->Transfer->Executed) { ProcessHead(controller, head); } }
/// <summary> /// Unset bit on port /// </summary> /// <param name="port">Port number</param> /// <param name="bit">Bit to unset</param> private static void unsetPortBit(UHCIController uhciDev, ushort port, ushort bit) { ushort status = PortIO.In16((ushort)(uhciDev.IOBase + port)); status &= (ushort)~bit; PortIO.Out16((ushort)(uhciDev.IOBase + port), status); }
/// <summary> /// Insert head /// </summary> /// <param name="controller">UHCIController</param> /// <param name="head"></param> public static void InsertHead(UHCIController controller, UHCIQueueHead *head) { mMutex.Lock(); UHCIQueueHead *end = controller.FirstHead; while (true) { if (end->Next != null) { end = end->Next; } else { break; } } head->Head = TD_POINTER_TERMINATE; head->Previous = end; head->Next = null; end->Next = head; end->Head = (int)Paging.GetPhysicalFromVirtual(head) | TD_POINTER_QH; mMutex.Unlock(); }
/// <summary> /// Reset port /// </summary> /// <param name="port">Port num to reset</param> private static void resetPort(UHCIController uhciDev, ushort port) { /** * Set reset bit */ setPortBit(uhciDev, port, PORTSC_RESET); /** * Wait for 60 ms */ Tasking.CurrentTask.CurrentThread.Sleep(0, 60); /** * Unset reset bit */ unsetPortBit(uhciDev, port, PORTSC_RESET); /** * Wait for atleast 150ms for link to go up */ for (int i = 0; i < 15; i++) { Tasking.CurrentTask.CurrentThread.Sleep(0, 10); ushort status = PortIO.In16((ushort)(uhciDev.IOBase + port)); /** * Is it even connected? */ if (((status) & PORTSC_CUR_STAT) == 0) { break; } /** * Status changed? */ if (((status) & (PORTSC_STAT_CHNG | PORTSC_ENABLE_STAT)) > 0) { unsetPortBit(uhciDev, port, PORTSC_STAT_CHNG | PORTSC_ENABLE_STAT); continue; } /** * Enabled? */ if ((status & PORTSC_CUR_ENABLE) > 0) { break; } } }
/// <summary> /// Poll queue heads /// </summary> /// <param name="controller"></param> public static void Poll(IUSBController controller) { UHCIController uhciController = (UHCIController)controller; for (int i = 0; i < MAX_HEADS; i++) { if (uhciController.QueueHeadPool[i].Transfer != null) { int address = (int)uhciController.QueueHeadPool; address += sizeof(UHCIQueueHead) * i; ProcessHead(uhciController, (UHCIQueueHead *)(address)); } } }
public static void RemoveTransmit(UHCIController controller, UHCITransmitDescriptor *transmit) { if (transmit->Previous != null) { if (transmit->Next != null) { transmit->Previous->Link = transmit->Next->Link; transmit->Previous->Next = transmit->Next; } else { transmit->Previous->Link = 0; transmit->Previous->Next = null; } } FreeTransmit(controller, transmit); }
/// <summary> /// Probe usb devices on port /// </summary> /// <param name="uhciDev">The UHCI device</param> private static void probe(UHCIController uhciDev) { /** * UHCI only supports 2 ports, so just 2 :-) */ for (int i = 0; i < 2; i++) { ushort port = (i == 0)? REG_PORTSC1 : REG_PORTSC2; resetPort(uhciDev, port); ushort status = PortIO.In16((ushort)(uhciDev.IOBase + port)); /** * Is the port even connected? */ if ((status & PORTSC_CUR_STAT) == 0) { continue; } bool lowSpeed = ((status & PORTSC_LOW_SPEED) > 0); USBDevice dev = new USBDevice(); dev.Controller = uhciDev; dev.Control = Control; dev.PrepareInterrupt = PrepareInterrupt; dev.TransferOne = TransferOne; /** * Root hub */ dev.Parent = null; dev.Port = port; dev.State = USBDeviceState.ATTACHED; dev.Speed = (lowSpeed) ? USBDeviceSpeed.LOW_SPEED : USBDeviceSpeed.HIGH_SPEED; if (!dev.Init()) { Heap.Free(dev); } } }
/// <summary> /// Transfer /// </summary> /// <param name="dev">Device</param> /// <param name="transfer">Transfers</param> /// <param name="length">Number of transfers</param> private static unsafe void TransferOne(USBDevice dev, USBTransfer *transfer) { USBDeviceRequest request = transfer->Request; UHCIController controller = (UHCIController)dev.Controller; UHCITransmitDescriptor *td = GetTransmit(controller); InitTransmit(td, null, dev.Speed, dev.Address, transfer->Endpoint, dev.Toggle, (transfer->Type == 0) ? TRANS_PACKET_IN : TRANS_PACKET_OUT, transfer->Length, transfer->Data); UHCIQueueHead *qh = GetQueueHead(controller); qh->Element = (int)Paging.GetPhysicalFromVirtual(td); qh->Head = 0; qh->Transfer = transfer; qh->Transmit = td; InsertHead(controller, qh); WaitForQueueHead(controller, qh); }
/// <summary> /// Insert head /// </summary> /// <param name="controller">UHCIController</param> /// <param name="head"></param> public static void InsertTransmit(UHCIController controller, UHCITransmitDescriptor *transmit) { UHCITransmitDescriptor *end = transmit; while (true) { if (end->Next != null) { end = end->Next; } else { break; } } end->Next = transmit; end->Link = (int)transmit | 1; transmit->Link = 0; }
/// <summary> /// Get Queue head item /// </summary> /// <param name="dev">Device</param> /// <returns></returns> private static UHCITransmitDescriptor *GetTransmit(UHCIController dev) { int i = 0; while (i < MAX_TRANSMIT) { if (!dev.TransmitPool[i].Allocated) { dev.TransmitPool[i].Allocated = true; dev.TransmitPool[i].Next = null; dev.TransmitPool[i].Previous = null; return((UHCITransmitDescriptor *)(((int)dev.TransmitPool) + (sizeof(UHCITransmitDescriptor) * i))); } i++; } Console.WriteLine("NO TRANSMIT LEFT"); return(null); }
/// <summary> /// Get Queue head item /// </summary> /// <param name="dev">Device</param> /// <returns></returns> private static UHCIQueueHead *GetQueueHead(UHCIController 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((UHCIQueueHead *)(((int)dev.QueueHeadPool) + (sizeof(UHCIQueueHead) * i))); } i++; } mMutex.Unlock(); return(null); }
private static void initDevice(PciDevice dev) { if ((dev.BAR4.flags & Pci.BAR_IO) == 0) { Console.WriteLine("[UHCI] Only Portio supported"); } Pci.EnableBusMastering(dev); UHCIController uhciDev = new UHCIController(); uhciDev.IOBase = (ushort)dev.BAR4.Address; uhciDev.Poll = Poll; Console.Write("[UHCI] Initalize at 0x"); Console.WriteHex(uhciDev.IOBase); Console.WriteLine(""); uhciDev.FrameList = (int *)Heap.AlignedAlloc(0x1000, sizeof(int) * 1024); uhciDev.QueueHeadPool = (UHCIQueueHead *)Heap.AlignedAlloc(0x1000, sizeof(UHCIQueueHead) * MAX_HEADS); uhciDev.TransmitPool = (UHCITransmitDescriptor *)Heap.AlignedAlloc(0x1000, sizeof(UHCITransmitDescriptor) * MAX_TRANSMIT); Memory.Memclear(uhciDev.QueueHeadPool, sizeof(UHCIQueueHead) * MAX_HEADS); Memory.Memclear(uhciDev.TransmitPool, sizeof(UHCITransmitDescriptor) * MAX_TRANSMIT); UHCIQueueHead *head = GetQueueHead(uhciDev); head->Head = TD_POINTER_TERMINATE; head->Element = TD_POINTER_TERMINATE; uhciDev.FirstHead = head; for (int i = 0; i < 1024; i++) { uhciDev.FrameList[i] = TD_POINTER_QH | (int)Paging.GetPhysicalFromVirtual(head); } PortIO.Out16((ushort)(uhciDev.IOBase + REG_LEGSUP), 0x8f00); /** * Initalize framelist */ PortIO.Out16((ushort)(uhciDev.IOBase + REG_FRNUM), 0); PortIO.Out32((ushort)(uhciDev.IOBase + REG_FRBASEADD), (uint)Paging.GetPhysicalFromVirtual(uhciDev.FrameList)); PortIO.Out8(((ushort)(uhciDev.IOBase + REG_SOFMOD)), 0x40); // Ensure default value of 64 (aka cycle time of 12000) /** * We are going to poll! */ PortIO.Out16((ushort)(uhciDev.IOBase + REG_USBINTR), 0x00); /** * Clear any pending statusses */ PortIO.Out16((ushort)(uhciDev.IOBase + REG_USBSTS), 0xFFFF); /** * Enable device */ PortIO.Out16((ushort)(uhciDev.IOBase + REG_USBCMD), USBCMD_RS); probe(uhciDev); Sharpen.USB.USB.RegisterController(uhciDev); }
public static void FreeTransmit(UHCIController controller, UHCITransmitDescriptor *transmit) { transmit->Allocated = false; }
/// <summary> /// Control USB Device /// </summary> /// <param name="dev"></param> /// <param name="transfer"></param> private static void Control(USBDevice dev, USBTransfer *transfer) { USBDeviceRequest request = transfer->Request; #if __UHCI_DIAG Console.WriteLine("------ UHCI Control message ---------"); Console.Write("Request: "); Console.WriteHex(request.Request); Console.WriteLine(""); Console.Write("Index: "); Console.WriteHex(request.Index); Console.WriteLine(""); Console.Write("Length:"); Console.WriteHex(request.Length); Console.WriteLine(""); Console.Write("Type:"); Console.WriteHex(request.Type); Console.WriteLine(""); Console.Write("Value:"); Console.WriteHex(request.Value); Console.WriteLine(""); Console.WriteLine("--------------------------------------"); #endif UHCIController controller = (UHCIController)dev.Controller; UHCITransmitDescriptor *td = GetTransmit(controller); UHCITransmitDescriptor *head = td; UHCITransmitDescriptor *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 = GetTransmit(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 = GetTransmit(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); UHCIQueueHead *qh = GetQueueHead(controller); qh->Element = (int)Paging.GetPhysicalFromVirtual(head); qh->Head = 0; qh->Transfer = transfer; qh->Transmit = head; InsertHead(controller, qh); WaitForQueueHead(controller, qh); }
public static void FreeHead(UHCIController controller, UHCIQueueHead *head) { head->Allocated = false; }
/// <summary> /// Process Queue Head /// </summary> /// <param name="device"></param> /// <param name="head"></param> public static void ProcessHead(UHCIController controller, UHCIQueueHead *head) { USBTransfer *transfer = head->Transfer; UHCITransmitDescriptor *td = head->Transmit; if ((head->Element & ~0xF) == 0) { transfer->Executed = true; transfer->Success = true; } else { if ((td->Control & TD_CONTROL_NAK) > 0) { } if ((td->Control & TD_CONTROL_STALLED) > 0) { Console.WriteLine("Stalled"); transfer->Executed = true; transfer->Success = false; } if ((td->Control & TD_CONTROL_BABBLE) > 0) { Console.WriteLine("Control Babble error"); } if ((td->Control & TD_CONTROL_CRC) > 0) { Console.WriteLine("CRC Timeout"); transfer->Executed = true; transfer->Success = false; } if ((td->Control & TD_CONTROL_BITSTUFF) > 0) { Console.WriteLine("Bitstuff error"); } } 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 */ UHCITransmitDescriptor *tdE = td; while (tdE != null) { UHCITransmitDescriptor *next = tdE->Next; FreeTransmit(controller, tdE); tdE = next; } } }