Betriebssysteme

Wie entwickle ich einen Gerätetreiber für Windows Embedded CE?

Seite: 2/3

Firmen zum Thema

3. Welche Treiber-Typen existieren unter CE?

WinCE unterstützt verschiedene Gerätetreibermodelle. Dies sind die Native Device Treiber, auch built-in-driver genannt, sowie die Stream Interface Driver, auch installable-driver genannt. Die Treibermodelle unterscheiden sich in erster Linie durch die Softwareschnittstelle, die nach außen angeboten wird. Native Treiber bedienen Geräte, welche fest in das System eingebaut sind, wie z. B. eine Tastatur oder ein LCD-Touchscreen. Diese Geräte haben eine besondere Bedeutung für das Betriebsystem, da sie bereits während des Bootvorgangs ansprechbar sind. Um für diese Treibertypen einen Treiber zu entwickeln, ist jeweils die Treiber-Schnittstellen-Beschreibung von Microsoft notwendig.

Der Stream Interface Driver ist typischerweise für Geräte verantwortlich, die vorübergehend an das System angeschlossen und wieder entfernt werden können. Das heißt, dass sie nach dem Booten von WinCE geladen oder entladen werden. Diese Treiber besitzen alle eine identische Schnittstelle und die 10 APIs haben immer folgenden Aufbau: z.B. xxx_Init() steht für CAN_Init().

Bildergalerie

4. Welche Aufgaben übernimmt der Gerätemanager?

Der Gerätemanager (GM) selbst wird von Bootloader, wie in der Registry aufgeführt ist, [HKEY_LOCAL_MACHINE\init] … “Launch20”=“device.dll” geladen. Alle Treiber, die durch den GM geladen werden sollen, befinden sich unter dem Registy-Schlüssel [HKEY_LOCAL_MACHINE\Drivers\BuiltIn]. Der Registry-Eintrag „Order“=dword:30“ gibt die Ladereihenfolge-Nummer des Treibers an.

Ein geladener Treiber wird als aktiv gekennzeichnet und unter dem Registy-Eintrag „[HKEY_LOCAL_MACHINE\Drivers\Active“ eingetragen und kann nun vom Betriebssystem Power Management Support bekommen. Für die Power-Management-Funktionen im Treiber (CAN_PowerDown(), CAN_PowerUp()) gibt es keine Anwender-Schnittstelle (Aufrufe). Beim Entladen des Treibers wird der Treiber aus dem Verzeichnis „\Active“ entfernt.

Treiber könnten auch durch ein API mit „ActivateDeviceEx“geladen werden. Diese Treiber (z.B. der CAN-Treiber) müssen unter folgendem Eintrag abgelegt sein „[HKEY_LOCAL_MACHINE\Drivers\CAN_Driver“.

Bei Plug- and Play-Geräten gibt das gerade eingefügte Gerät einen Identifer zurück, den der Device Manager nutzt, um den richtigen Treiber zu finden. Andernfalls wird eine Erkennungsroutine durchlaufen, welche die nötigen Informationen beschafft, um den richtigen Treiber ausfindig zu machen. Die Applikation greift auf ein Gerät über Dateisystemfunktionen des Kernels zu. Der Kernel leitet diese Kommandos an den Stream-Treiber weiter.

5. Wie entwickel und integriert man einen Stream-Treiber?

Bild 3: Stream-Treiber bedienen typischerweise Geräte, die vorübergehend an das System anschlossen werden. Sie werden durch einfache File-IO-Befehle realisiert. (Archiv: Vogel Business Media)

Die Schnittstellen für die Stream-Treiber werden durch einfache File-IO-Befehle realisiert (Bild 3). Der GM nimmt alle Anwender-Aufrufe entgegen und entkoppelt sie. Alle WinCE-File-IO-Aufrufe sind synchrone Aufrufe die das Anwenderprogramm solange blockieren, bis der Treiber sich mit einem return zurück meldet.

Bild 4: Stream-Treiber-Schnittstellen. Schematische Darstellung des Zusammenspiels zwischen Anwendung, Gerätemanager und Treiber. (Archiv: Vogel Business Media)

Die Schnittstellen zwischen einem UM- oder KM-Treiber sind identisch. Ein UM- Treiber besitzt nur zusätzliche Registry-Einträge die vom Geratemanager beötigt werden um gemäß den Angaben den Treiber zu laden. Der hier beschriebene Stream-Driver setzt sich aus folgenden Dateien zusammen: CAN_Driver.cpp, CAN_Driver.h, CAN_Driver.def, CAN_Driver.reg und CAN_Driver.bib. Im Bild sind die einzelnen Aufgaben des GM Nummern von 1-20 gekennzeichnet. Nicht alle Parameter des aufrufenden Programmes werden an die Treiberfunktionen weitergegeben.

Das Zusammenspiel (Schnittstellen) zwischen der „Anwendung <> Geräte Manager <> Treiber“ wird durch die Punkte 1-20 beschrieben:

  • 1. hCAN_Device=ActivateDeviceEx (L“Drivers\\CAN_Driver“, NULL, 0, 0);“
  • 2. GM läd den Treiber CAN_Driver.dll und registriert den Treiber unter [HKLM\Drivers\Active]. Ruft die Funktion DLLMain() im CAN_Driver dll auf und führt CAN_Init() aus.
  • 3. CAN_Init() dient zum inizialisieren der Hardware, erzäugen der Events, Thraeds, bereitstellen von Speicher und Interrupt-Initialisierung. CAN_Init( ) {… } return(1); Eine 0 als Return ist immer ein Error vom Treiber.Der Return Wert des Treibers wird im GM gespeichert und als Handle dem Aufrufer bereitgestellt (hCAN_Device).Der Treiber befindet sich im Initial-Zustand (1).
  • 4. Aufruf: bool_var=DeactivateDevice(hCAN_Device);Der Treiber soll entladen weden!
  • 5. Ruft CAN_Deinit() im CAN_Driver.dll auf. Löscht den Treiber aus [HKLM\Drivers\Active]
  • 6. LED_Deinit() {…} return TRUE; wenn der Treiber erfolgreich entladen werden konnte. Alle erzeugten Objekte müssen zurückgegeben werden. Es muss darauf gewartet werden bis alle Threads signalisiert sind „WaitForSingleObject()“. Es wird DLLMain() ausgeführt.
  • 7. hCAN1_Dev=CreateFile( TEXT(„CAN1:“),,,,); Der Anwender hat ein Geräte-Handle von der CAN-Schnittstelle und kann nun vom Treiber lesen oder Daten auf den Treiber schreiben.
  • 8. CAN_Open() {…} return (2); (hCAN1_Dev). Der Treiber befindet sich im Initial-Zustand (2). Ferner können Objekte für den Open-Zustand erzeugt werden.
  • 9. bool_var= CloseHandle(hCAN1_Dev); Geräte Handle wird zurückgegeben.
  • 10. CAN_Close() {…} return (TRUE); Der Treiber befindet sich im Initial-Zustand (1).
  • 11. Die CAN-HW kann benutzt werden: bool_var= WriteFile (hCAN1_Dev, &Buffer, sizeof(Buffer), &nBytesWritten, NULL); Der Buffer-Inhalt wird den Treiber übergeben. Die Variable nBytesWritten enthält die Anzahl der geschriebenen Bytes. (Synchroner Schreibzugriff)
  • 12. CAN_Write() {…} return (nBytes); Der Treiber gibt die Anzahl der geschriebenen Bytes zurück zum Aufrufer.
  • 13. bool_var= ReadFile (hCAN1_Dev, &Buffer, sizeof(Buffer), &nBytesRead, NULL);
  • 14. CAN_Read() {…} return (nBytes);
  • 15. Diese Funktion ist eine bidirektionale Daten-Austausch-Funktion mit dem Treiber. Die übergebenen Adressen werden durch die MMU in den Adressbereich des Treibers gemapped. In diesem Beispiel wird eine Struktur übergeben die Struktur-ElementE als Embedded-Pointer enthält. Diese Pointer werden nicht umgemapped. Die Strukturdefinition: “struct {PBYTE pEmbeddedSource; PBYTE pEmbeddedDest; int len} pcs“; Der Treiber soll die Daten von pEmbeddedSource in den pEmbeddedDest kopieren.Der Aufruf: DeviceIoControl (hFile, 1, &pcs, sizeof (pcs), NULL,0, &dwBytes, NULL);
  • 16. Der Treiber muß die Embedded-Pointer ummappen!LED_IOControl() { PBYTE pMapped1, pMapped2; CeOpenCallerBuffer((PVOID *)&pMapped1,pcs->pBuff1,pcs->nLength,ARG_IO_PTR,false); CeOpenCallerBuffer((PVOID *)&pMapped2,pcs->pBuff2,pcs->nLength,ARG_IO_PTR,false); memcpy (pMapped2, pMapped1, pcs->nLength); }
  • 17. bool_var= SetFilePointer (hCAN1_Dev,,,); Es kann ein File-Pointer auf eine bestimmte Position gesetzt werden.
  • 18. CAN_Seek() {…} return (TRUE);
  • 19. CAN_PowerDown() wird vom Powermanager gerufen. Es gibt kein API auf der Anwender-Seite.
  • 20. CAN_PowerUp() wird vom Powermanager gerufen. Es gibt kein API auf der Anwender-Seite.

(ID:264282)