Ziel: USB-Treiber


  • Mod

    Tests zeigen, dass man Bit3 im USBINTR zu Beginn nicht setzen darf:

    pOpRegs->USBINTR       = *((volatile uint32_t*)(opregs + 0x08)) = 0x1 | 0x2 | 0x4 | /*0x8 |*/ 0x10 | 0x20;
        /// TEST: Bit 3 cannot be set to 1, Frame List Rollover Enable, otherwise keyboard does not come through
    

    Den Rest darf man auf 1 setzen.



  • Ich habe jetzt zumindest genau die Stelle gefunden wo der Fehler auftritt. Das setzen der Adresse für die Periodic Frame List:

    uint32_t virtualMemoryPERIODICLISTBASE = (uint32_t) malloc(0x1000,PAGESIZE);
    uint32_t physicalMemoryPERIODICLISTBASE = paging_get_phys_addr( kernel_pd, (void*)virtualMemoryPERIODICLISTBASE );
    pOpRegs->PERIODICLISTBASE = *((volatile uint32_t*)(opregs + 0x14)) = physicalMemoryPERIODICLISTBASE;
    

    Kommentiert man die letzte Zeile aus hängt es nicht mehr. Da mir der Code komisch vorkommt habe ich den mal neu geschrieben und auch wie in der Spezifikation die T-Bits gesetzt, hängen tut es aber trotzdem noch.

    Mein Code:

    void* virtualMemoryPERIODICLISTBASE = malloc(0x1000,PAGESIZE);
    uint32_t physicalMemoryPERIODICLISTBASE = paging_get_phys_addr(kernel_pd, virtualMemoryPERIODICLISTBASE);
    pOpRegs->PERIODICLISTBASE = physicalMemoryPERIODICLISTBASE;
    memset(virtualMemoryPERIODICLISTBASE, 0xFF, 0x1000); // Alles auf 1 Setzen setzt auch das T-Bit auf 1
    

  • Mod

    Danke für die Unterstützung! Bei Memory-Adressen bevorzuge ich i.d.R. uint32_t, caste es nach void*, wenn notwendig. Hier macht void* aber wirklich mehr Sinn. Ins Register PERIODICLISTBASE muss die physikalische Adresse der Frame-Pointer.

    Es sind nur 1024 Elemente in der Pointer-Liste, also 0x400 nicht 0x1000.


  • Mod

    Tobiking: Ich kann das nicht nachvollziehen mit dem "Nichthängen". Leider hängt es immer noch.

    Hier die Rev. 162: http://www.c-plusplus.net/forum/viewtopic-var-p-is-1863106.html#1863106

    Versuche bitte nochmal die genaue Stelle zu finden und den Trick, wie man es "laufend" halten kann beim Einstecken von USB-Devices.

    Bei mir läuft es mit real PC und mit Sun VB (aber nur, wenn man nur funktionierende USB-Devices einhängt). Alles sehr eigenwillig.


  • Mod

    Mit rev. 168 sind wir dem ersten Meilenstein "HC Init" schon nahe. Bei mir läuft es gut auf dem Test-PC, in VB nicht sicher, bei Tobiking gibt es noch "Hänger".
    Bitte um Mithilfe.

    Die Interrupts müssen noch per installHandler und Handler verarbeitet werden. Bisher sind (Periodic)FrameListRollover und PortChangeDetect angefallen.



  • Hallo,

    ich hab noch mal nach Debug-Möglichkeiten für den USB recherchiert, vor allem auf der Embedded-World.

    Gefunden hab ich das http://www.lecroy.com/ProtocolAnalyzer/ProtocolStandard.aspx?standardID=4&capid=103, hier fangen die Preise erst oberhalb 1000$ an aber man bekommt auch wirklich ne tolle Rund-um-Sorglos-Lösung die einem wirklich jeden Aspekt des USB-Trafics analysieren lässt.
    Als einzige Alternative hab ich noch dieses http://www.totalphase.com/products/beagle_usb12/ gefunden, was zwar noch einen nicht total abschreckenden Preis hat aber eben auch nur bis Full-Speed kommt oder jenes http://www.totalphase.com/products/beagle_usb480/ was dann High-Speed bietet aber eben auch wieder die 1000$-Marke deutlich überschreitet. Die Software macht einen ähnlich guten Eindruck wie bei LeCroy aber die Hardware ist etwas bescheidener.

    Für die Bedürfnisse eines USB-Host-Treiber-Programmierers sind diese Analyse-Produkte sicher sehr interessant aber für ein Hobby-Projekt eben auch unbezahlbar. Ich persönlich bin der Meinung dass das Olimex-Board http://www.olimex.com/dev/lpc-h2888.html die beste Lösung (zu einem vertretbaren Preis) darstellt und zusätzlich noch etwas Wissen über die µC-Programmierung vermittelt (was für jemanden der ein OS bauen will, also auch auf der Low-Level-Ebene arbeitet, sicher von Vorteil ist). Andere Boards mit vergelichbarer Ausstattung und vernünftigem Preis (unter 150Euro) hab ich nicht gefunden. Keiner der üblichen Verdächtigen (welche alle auf der Messe präsent waren) konnte mir was passendes zeigen.
    Wer wirklich Geld investieren möchte der sollte sich IMHO für den Beagle-USB480 entscheiden, die Vorführung hat einen wirklich guten Eindruck gemacht. Außerdem hab ich noch einen 15%-Rabat-Coupon bekommen der allerdings nur ein paar Monate gilt.

    Grüße
    Erik


  • Mod

    Momentan fehlt uns eine zuverlässige gemeinsame Simulationsbasis. VBox erweist sich bei mir als störrisch, was die dauerhafte Anbindung der USB-Geräte an die Simulation angeht.

    EDIT: Tobiking und ich haben VMWare Player mit EHCI getestet, und das klappt hervorragend! 🙂
    Wer also bei EHCI mitmachen will, unbedingt VMWare Player installieren.



  • Hier der Code für das Prüfen der EECP (EHCI Extended Capabilities):

    uint32_t offset = (pCapRegs->HCCPARAMS & 0xFF00) >> 8;
    uint32_t* pointer = (uint32_t*)(ubar+offset);
    
    while(offset) {
        offset = (*pointer & 0xFF00) >> 8;
        printformat("Pointer: %X Value: %X Next: %X\n", pointer, *pointer, offset); 
        pointer = (uint32_t*)(ubar + offset);
    }
    

    Wenn ich keinen Fehler gemacht habe hilft das allerdings nicht weiter. VirtualBox besitzt demnach keine EECP und mein Laptop hat zwar zwei Listeneinträge, allerdings ist dort die Capability ID 0 was bedeutet das kein Handoff ?möglich/nötig? ist.



  • Hm, du versuchst, auf die EECP im Hauptspeicher zuzugreifen? Da sind aber keine, die sind im PCI-Konfigurationsraum. Bei mir sieht das Deaktivieren des Legacy Supports so aus:

    eecp = (hc->usbbase->hcc_params & 0x0000FF00) >> 8;
        if (eecp >= 0x40)
        {
            int eecp_id;
    
            while (eecp)
            {
                eecp_id = pci_inb(pci->bus, pci->dev, pci->func, eecp);
                // Legacy-Support-Zeugs
                if (eecp_id == 1)
                    break;
                eecp = pci_inb(pci->bus, pci->dev, pci->func, eecp + 0x01);
            }
    
            // Nachsehen, ob eine Legacy-Support-EC gefunden wurde und der BIOS-Semaphor gesetzt ist
            if ((eecp_id == 1) && pci_inb(pci->bus, pci->dev, pci->func, eecp + 0x02) & 0x01)
            {
                // OS-Semaphor setzen
                pci_outb(pci->bus, pci->dev, pci->func, eecp + 0x03, 0x01);
    
                failed = 1;
                // Eine Sekunde
                timeout = heart_beat_count + 1000000000LL;
                // Warten, bis der BIOS-Semaphor nicht mehr gesetzt ist
                while ((pci_inb(pci->bus, pci->dev, pci->func, eecp + 0x02) & 0x01) && (heart_beat_count < timeout));
                if (!(pci_inb(pci->bus, pci->dev, pci->func, eecp + 0x02) & 0x01))
                {
                    // Wieder eine Sekunde
                    timeout = heart_beat_count + 1000000000LL;
                    // Warten, bis der OS-Semaphor gesetzt ist
                    while (!(pci_inb(pci->bus, pci->dev, pci->func, eecp + 0x03) & 0x01) && (heart_beat_count < timeout));
                    if (pci_inb(pci->bus, pci->dev, pci->func, eecp + 0x03) & 0x01)
                        failed = 0;
                }
    
                if (failed)
                {
                    // Manuell den Legacy Support deaktivieren
                    pci_outl(pci->bus, pci->dev, pci->func, eecp + 0x04, 0x0000);
                }
            }
        }
    

    Hinweis: heart_beat_count ist die Zeitzählvariable meines OS. Sie ist vom Typ unsigned long long und zählt in Nanosekunden (eine Millisekunde ist also 1000000).


  • Mod

    Danke für den Versuch und den Code.

    Nach Diskussion mit XanClic im IRC gehört der Code offensichtlich hierhin:

    void initEHCIHostController(uint32_t number)
    {
        irq_install_handler(32 + pciDev_Array[number].irq, ehci_handler);
    
        /// TODO: with EECP: DeactivateLegacySupport(number)
    
        // ...
    
        /// TODO 
    
        pOpRegs->USBCMD &= ~CMD_RUN_STOP; // set Run-Stop-Bit to 0
    
        // ...
    }
    

    Aber gekapselt in eine Funktion "DeactivateLegacySupport(number)".


  • Mod

    Rev. 181:
    ...

    PC-Test bei Cuervo:

    jetzt kommt er bis zum 2. 'waiting for HC reset'



  • Hab mal wieder angefangenen nicht funktionierenden Code zum Datentransfer:

    ehci.c
    ehci.h

    Bei mir schaltet der Host Controller auf Halted. Ich hab versucht das ganze recht ausführlich zu Kommentieren, da ich teilweise echt suchen musste wie manche Werte gesetzt werden müssen.



  • Mein aktueller Stand:

    ehci.c

    Es fehlt noch nen ganzes Stückchen, aber man sieht wie es funktionieren soll. CreateQH/CreateQTD erstellt eine recht generische Version, die dann in den spezifischen Funktionen wie die IN und OUT Varianten weiter manipuliert werden. Durch die übergebene Adresse werden die Einträge direkt an der richtigen Stelle erstellt. Am Ende müssen diese nur noch zusammen gehängt werden. Fehlen tun auf jeden Fall noch ein paar Parameter und die spezifische Funktion für SETUP Einträge. Das mit dem SETUP ist allerdings wieder etwas komplexer.


  • Mod

    Echt toll! 🙂 👍

    Ich habe den aktuellen Stand als Zwischenschritt in Rev. 194 implementiert, damit sich da nichts auseinander entwickelt.
    http://www.c-plusplus.net/forum/viewtopic-var-p-is-1865696.html#1865696

    SETUP:
    http://wiki.osdev.org/USB#USB_Device_Requests
    http://lowlevel.brainsware.org/wiki/index.php/Universal_Serial_Bus#Setuppaket
    USB 2.0 Spec: 5.3.1.1 Endpoint Zero Requirements, 9.4 Standard Device Requests, Table 9-4: Standard Request Codes, Table 11-14: Hub Responses to Standard Device Requests.

    Da gibt es das gesuchte SET_ADDRESS, damit wir von der 0 weg kommen.



  • Erhard Henkes schrieb:

    Da gibt es das gesuchte SET_ADDRESS, damit wir von der 0 weg kommen.

    Ja, nur bringt es im Moment nicht viel damit anzufangen, da man nicht überprüfen kann ob das ganze geklappt hat. Der erste Schritt ist daher erstmal das auslesen des Device Desciptor.

    Ich hab das ganze nochmal umgebaut, und es sieht nun deutlich sinniger aus. Der QH beinhaltet jetzt einen kompletten QTD. Das elemeniert einiges an doppelten Code.

    ehci.h
    ehci.c

    Der Test sollte eigentlich soweit vollständig sein. Funktionieren tut es allerdings nicht. Data ist nicht 18 wie es sein sollte und der Controller schaltet auf Halted. Das heißt jetzt erstmal Fehler suchen.


  • Mod

    Ich habe es in Rev. 196 als Zwischenschritt eingespielt. Bei mir kommt immer 80h als Data zurück. Ich werde da mal an einigen Parametern drehen, mir sind beim Lesen der EHCI und USB 2.0 Specs einiges aufgefallen, was noch nicht passt bei uns.



  • Und der nächste neue Ansatz.

    Meine komplette ehci.c. Ich hab die alten Funktionen und die Ausgaben komplett rausgeworfen. Die passten nicht mehr so richtig.

    Hintergrund ist das ich die EHCI Spezifikation mal gezielt nach Schritten durchsucht habe, die von der Software durchgeführt werden müssen. Da habe ich in dem Abschnitt vor 4.10.1 folgendes gefunden:

    For the very first use of a queue head, software may zero-out the queue head transfer overlay, then set the Next qTD Pointer field value to reference a valid qTD.

    Das ist im Prinzip auch das was ich nun mache. Der Overlay Bereich wird genullt und nur der next pointer wird auf die Setup QTD gesetzt, dessen next pointer dann auf die In QTD zeigt. Also keinerlei queue heads außer dem ersten mehr.

    Die qemu ehci Testversion läuft damit schon recht weit. An meinem Laptop kriege ich leider wieder Host System Error.


  • Mod

    Der erste Erfolg! http://www.henkessoft.de/OS_Dev/Bilder/rev219a.jpg
    die lang ersehnte 12h wurde mittels 80 06 00 01 00 00 12 00 (setup request) geholt. http://www.jungo.com/st/support/documentation/windriver/1002/wdusb_man_mhtml/node55.html#SECTION001221600000000000000 👍

    Allerdings noch nicht stabil und schwierig reproduzierbar an anderen Stellen und Sims.

    ➡ Das Problem liegt in resetPort(...) (<--- grausam). da müssen wir weiter machen.

    ➡ resetPort wird einmal vom initEHCI... udn einmal vom EHCI-Handler via ShowPortSC(...) aufgerufen, einmal mit sleep... und einmal mit diesem bescheuerten Zähler-Work-around. 🙄


  • Mod

    Geht übrigens auch mit qemu:
    http://www.henkessoft.de/OS_Dev/Bilder/rev219qemu.jpg

    Das qemu erhält man hier: http://download.tyndur.org/temp/qemu-ehci.tgz 👍

    Skript:

    qemu.exe  -fda FloppyImage.bin -soundhw pcspk -localtime -usb -usbdevice disk:format=raw:dummy.bin
    

    oder mit netzwerk

    qemu.exe  -fda FloppyImage.bin -soundhw pcspk -net nic,model=rtl8139,addr=1F,macaddr=00:12:12:12:12:12 -localtime -usb -usbdevice disk:format=raw:dummy.bin
    

  • Mod

    ... und nach einem Tipp von XanClic, dass VBox eine IRQ tiefer verwendet (also 10 anstelle 11 wie beim PCI festgestellt), nun auch VBox:
    http://www.henkessoft.de/OS_Dev/Bilder/rev221VB.jpg (data: 12h)

    Also alles bestens. 🙂


Anmelden zum Antworten