Ziel: USB-Treiber
-
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
-
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).
-
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)".
-
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:
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:
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.
-
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#1865696SETUP:
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.
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.
-
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.
-
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#SECTION001221600000000000000Allerdings 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.
-
Geht übrigens auch mit qemu:
http://www.henkessoft.de/OS_Dev/Bilder/rev219qemu.jpgDas 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
-
... 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.
-
Hier ein Test mit 2 QHs in der async. Liste, einer davon mit 3 QTD: http://www.henkessoft.de/OS_Dev/Bilder/rev268_asyncList.PNG (ab Rev. 268)
-
Nach dem Einbau des Multithreadings geht es langsam wieder weiter bei USB:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-254893-and-start-is-378.htmlAllerdings klappt es im EHCI-Bereich noch nicht sauber auf real PC.
-
Bei der Suche nach Problemen bezüglich Real PC und Simulationen bezüglich USB-Transfer sind wir bisher auf folgendes gestoßen:
-
Extended Buffer Pointer (64 Bit) bei QTD notwendig
-
PCI Command Register: Bus Mastering (Bit 2) muss gesetzt sein (real PC: das erledigt das BIOS bereits); VMWare: setzt dies nicht, USB läuft aber erst nach dem Setzen dieses Bits
-
PCI Capabilities List: hier ist unklar, ob dies eine Bedeutung für EHCI hat?!
Hier eine Auswertung:
**
PCI Capabilities List: first Pointer: 0050h
PCI Capabilities List: ID: 01h, next Pointer: 00h**
PrettyOS [Version 0.0.0.384] Console 0: EHCI -------------------------------------------------------------------------------- >>> >>> function: initEHCIHostController PCI Command Register before: 0106h PCI Command Register plus bus master: 0106h PCI Capabilities List: first Pointer: 0050h PCI Capabilities List: ID: 01h, next Pointer: 00h >>> >>> function: startHostController (reset HC) DeactivateLegacySupport: eecp = 0070h eecp = 0070h, eecp_id = 0001h BIOS did not own the EHCI. No action needed. >>> >>> function: enablePorts >>> >>> function: resetPort 1 >>> >>> function: resetPort 2 >>> >>> function: resetPort 3 >>> >>> function: resetPort 4 >>> >>> function: resetPort 5 >>> >>> function: resetPort 6 >>> Press key to close this console. <<< -------------------------------------------------------------------------------- Saturday, April 19, 2064, 19:13:42 51 s runtime. CPU: 1121 MHz /
Zugehöriger Code in ehci.c:
uint16_t pciCapabilitiesList = pci_config_read(bus, dev, func, 0x0234); printf("\nPCI Capabilities List: first Pointer: %x", pciCapabilitiesList); if (pciCapabilitiesList) // pointer != NULL { uint16_t nextCapability = pci_config_read(bus, dev, func, 0x0200 | pciCapabilitiesList); printf("\nPCI Capabilities List: ID: %y, next Pointer: %y",BYTE1(nextCapability),BYTE2(nextCapability)); while (BYTE2(nextCapability)) // pointer != NULL { nextCapability = pci_config_read(bus, dev, func, 0x0200 | BYTE2(nextCapability)); printf("\nPCI Capabilities List: ID: %y, next Pointer: %y",BYTE1(nextCapability),BYTE2(nextCapability)); } }
Die Bedeutungen der IDs sind in Anhang H der PCI Local Bus Specification beschrieben:
Die ID=1 von obigem PC bedeutet:
PCI Power Management Interface – This capability structure provides a standard interface to control power management features in a PCI device. ...
Hier ein Beispiel eines PC, der mit Host System Error reagiert:**
PCI Capabilities List: first Pointer: 0050h
PCI Capabilities List: ID: 01h, next Pointer: 58h
PCI Capabilities List: ID: 0Ah, next Pointer: 00h**PrettyOS [Version 0.0.0.384] Console 0: EHCI -------------------------------------------------------------------------------- >>> >>> function: initEHCIHostController PCI Command Register before: 0006h PCI Command Register plus bus master: 0006h PCI Capabilities List: first Pointer: 0050h PCI Capabilities List: ID: 01h, next Pointer: 58h PCI Capabilities List: ID: 0Ah, next Pointer: 00h >>> >>> function: startHostController (reset HC)waiting for HC reset DeactivateLegacySupport: eecp = 0068h eecp = 0068h, eecp_id = 0001h set OS-Semaphore. BIOS-Semaphore being not set. OS-Semaphore being set. Check: BIOSownedSemaphore: 0 OSownedSemaphore: 1 ehci_handler: Port Change >>> >>> function: enablePorts >>> >>> function: resetPort 1 Port 1: high speed enabled, device attached >>> Press key to start USB-Test. <<<
ID 0x0A bedeuetet: Debug Port Capability (siehe EHCI spec, Appendix C. Debug Port)
-
-
http://www.c-plusplus.net/forum/viewtopic-var-p-is-1885822.html#1885822
Die Ursache für den hartnäckigen Host System Error ist gefunden.
Er liegt im USB-Transfer begraben (hält am H-Bit nicht an).
-
Ein Meilenstein erreicht:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-254893-and-start-is-423.html
LBA 0 von einem USB-Stick auf einem real PC korrekt mit read(10) ausgelesen. Version ist allerdings noch nicht stabil (klappt nur bei wenigen Konstellationen), aber das Ziel ist in Sicht, nun ist wieder die übliche Fleißarbeit angesagt.