예제 #1
0
 public static void WaitForQueueHead(EHCIController controller, EHCIQueueHead *head)
 {
     while (!head->Transfer->Executed)
     {
         ProcessHead(controller, head);
     }
 }
예제 #2
0
        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();
        }
예제 #3
0
        /// <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();
        }
예제 #4
0
        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;
                }
            }
        }
예제 #5
0
        /// <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;
        }
예제 #6
0
        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);
        }
예제 #7
0
        /// <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);
                }
            }
        }
예제 #8
0
        /// <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;
                }
            }
        }
예제 #9
0
        /// <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);
        }
예제 #10
0
        /// <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);
        }
예제 #11
0
        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);
        }
예제 #12
0
 public static void FreeTransmit(EHCIController controller, EHCITransferDescriptor *transmit)
 {
     transmit->Allocated = false;
 }
예제 #13
0
        private unsafe static EHCITransferDescriptor *AllocateEmptyTransmit(EHCIController controller)
        {
            EHCITransferDescriptor *queueHead = GetTransmitDescriptor(controller);

            return(queueHead);
        }
예제 #14
0
        /// <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);
        }
예제 #15
0
 /// <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));
 }