Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Um Den Zugriff auf einen PWM-Controller (Pulse Width Modulation) zu ermöglichen, der Teil des SoC ist und dem SoC-Adressraum speicherseitig zugeordnet ist, müssen Sie einen Kernelmodustreiber erstellen. Der Treiber muss die Geräteklassenschnittstelle des PWM-Controllers registrieren, damit UWP-Apps über die im Windows.Devices.Pwm-Namespace definierten PWM-WinRT-APIs auf die vom System verfügbar gemachten PWM-Geräte zugreifen können.
Hinweis
Wenn Sie über ein PWM-Add-On-Modul über I2C, SPI oder einen UART-Controller verfügen, können Sie über eine UWP-App auf das Modul zugreifen, indem Sie die apIs verwenden, die im Namespace Windows.Devices.Pwm und Windows.Devices.Pwm.Provider definiert sind.
Ein PWM-Gerät wird in einen einzelnen Controller und einen oder mehrere Pins abstrahiert. Die Steuerung des Controllers oder der Pins erfolgt über die PWM-definierten IOCTLs. Beispielsweise sendet ein LCD-Anzeigetreiber solche Anforderungen an den PWM-Treiber, um die LCD-Hintergrundbeleuchtung zu steuern.
Mehrcontroller- und Mehrkanal-PWM-Signalgenerierung mit konfigurierbarem Zeitraum, Polarität und Tastzyklus, die die folgenden Aufgaben ermöglichen:
- Antrieb eines Servomotors.
- Fahren Sie eine Last wie LED- oder DC-Bürstenmotor.
- Generieren Sie ein analoges Signal.
- Generieren Sie eine präzise Uhr.
In diesem Thema wird beschrieben,
Aktivieren des UWP-Zugriffs auf die vom System verfügbar gemachten PWM-Geräte
Behandeln von PWM-IOCTL-Anforderungen, die von einer Win32-Anwendung oder einem Drittanbieter-Kernelmodustreiber gesendet werden.
Zielgruppe
- OEMs und IHVs, die ein System mit einem PWM-Controller in SoC entwickeln.
Zuletzt aktualisiert
- August 2017
Windows-Version
- Windows 10-Version
Wichtige APIs
Über PWM
PWM beschreibt die grundlegende Technik zum Generieren einer rechteckigen Impulswelle mit modulierter Pulsbreite, die zu einer Variation des Mittelwerts der Wellenform führt.
Eine PWM-Wellenform kann nach 2 Parametern kategorisiert werden: Wellenformperiode (T) und Tastzyklus. Die Wellenformfrequenz (f) ist der Kehrwert der Wellenformperiode f=1/T. Der Tastzyklus beschreibt den Anteil der "On"- oder "Active"-Zeit in Bezug auf das reguläre Intervall oder den "Zeitraum"; ein niedriger Tastzyklus entspricht einem Mittel der niedrigen Ausgangsleistung, da die Stromversorgung für die meiste Zeit ausgeschaltet ist. Der Tastzyklus wird in Prozent ausgedrückt, wobei 100 % vollständig eingeschaltet sind, 0 % vollständig ausgeschaltet sind und 50 % "aktiv" sind.
Zugreifen auf den vom System verfügbaren PWM-Controller und die Pins
Der PWM-Treiber muss registriert werden.
GUID_DEVINTERFACE_PWM_CONTROLLER als GUID für die Geräteschnittstelle zum Verfügbarmachen und Zugreifen auf PWM-Geräte.
// {60824B4C-EED1-4C9C-B49C-1B961461A819}
DEFINE_GUID(GUID_DEVINTERFACE_PWM_CONTROLLER, 0x60824b4c, 0xeed1, 0x4c9c, 0xb4, 0x9c, 0x1b, 0x96, 0x14, 0x61, 0xa8, 0x19);
#define GUID_DEVINTERFACE_PWM_CONTROLLER_WSZ L"{60824B4C-EED1-4C9C-B49C-1B961461A819}"
Um die GUID der Geräteschnittstelle zu registrieren, muss der Treiber WdfDeviceCreateDeviceInterface in der Implementierung der EVT_WDF_DRIVER_DEVICE_ADD Rückruffunktion des Treibers aufrufen. Nach der Registrierung weist das System dem Controller und den Pins eine symbolische Verknüpfung zu.
Eine Anwendung oder ein anderer Treiber kann entweder den Controller oder die Pins über die von PWM definierten IOCTLs steuern. Vor dem Senden der IOCTLs muss die Absenderanwendung oder der -Treiber ein Dateihandle für den Controller und die Pin öffnen, indem sie die symbolische Verknüpfung angeben. Dies erfordert, dass sich der Treiber für Dateierstellungs- und -schließen-Ereignisse registriert. Siehe (Link)
Hier sehen Sie ein Beispiel für den symbolischen Pfad für den Controller:
\??\ACPI#FSCL000E#1#{60824b4c-eed1-4c9c-b49c-1b961461a819}
In ähnlicher Weise ist das Format der Pins wie folgt: Das Format des Pfads ist wie folgt:
<DeviceInterfaceSymbolicLinkName>\<PinNumber>
wobei <PinNumber>
der 0-basierte Index des zu öffnenden Pins ist.
Hier sehen Sie ein Beispiel für den symbolischen Pfad für Pins:
\??\ACPI#FSCL000E#1#{60824b4c-eed1-4c9c-b49c-1b961461a819}\0 ; Opens pin 0
\??\ACPI#FSCL000E#1#{60824b4c-eed1-4c9c-b49c-1b961461a819}\0001 ; Opens pin 1 with the leading 0s have no effect.
Zum Öffnen des Dateihandles muss die Anwendung die Configuration Manager-APIs (CM_Get_Device_Interface_*) aufrufen.
Nachdem das Dateihandle geöffnet wurde, kann die Anwendung diese Anforderungen senden, indem sie die DeviceIoControl-Funktion aufruft. Weitere Informationen finden Sie im Abschnitt PWM.
Der Treiber sollte die bereitgestellte PWM-Unterstützungsroutine PwmParsePinPath verwenden, um Pinpfade zu analysieren und zu überprüfen und die Pinnummer zu extrahieren.
Festlegen von Geräteschnittstelleneigenschaften
Um PWM WinRT-APIs aus UWP-Apps verwenden zu können, müssen diese Geräteschnittstelleneigenschaften festgelegt werden.
DEVPKEY_DeviceInterface_Restricted
Gemäß dem aktuellen UWP-Gerätezugriffsmodell muss die Eigenschaft Eingeschränkte Geräteschnittstelle auf FALSE festgelegt werden, um UWP-Apps Zugriff auf die PWM-Geräteschnittstelle zu gewähren.
DEVPKEY_DeviceInterface_SchematicName (Link???)
Das Zuweisen eines schematischen Namens zur PWM-Geräteschnittstelle statisch verbundener PWM-Geräte ist für die Verwendung der Factorymethode PwmController.GetDeviceSelector(FriendlyName) erforderlich. Der schematische Name ist der Name, der dem PWM-Gerät in den Systementwurfsschemas z. B. (PWM0, PWM_1, et..)) zugewiesen wird. Es wird davon ausgegangen, dass schematische Namen im gesamten System eindeutig sind, aber dies wird nicht erzwungen. Zumindest sollte es nicht 2 PWM-Geräte mit dem gleichen Schemanamen geben, andernfalls ist das WinRT PWM PwmController.GetDeviceSelector(FriendlyName)-Verhalten nicht deterministisch.
Die Eigenschaften können auf zwei Arten festgelegt werden:
Verwenden der INF-Datei für den PWM-Treiber
Verwenden Sie die AddProperty-Anweisung , um Geräteeigenschaften festzulegen. Die INF-Datei sollte das Festlegen unterschiedlicher Werte für dieselbe Eigenschaft für eine oder eine Teilmenge der PWM-Geräteinstanzen zulassen. Hier sehen Sie ein Beispiel für das Festlegen DEVPKEY_DeviceInterface_Restricted.
;***************************************** ; Device interface installation ;***************************************** [PWM_Device.NT.Interfaces] AddInterface={60824B4C-EED1-4C9C-B49C-1B961461A819},,PWM_Interface [PWM_Interface] AddProperty=PWM_Interface_AddProperty ; Set DEVPKEY_DeviceInterface_Restricted property to false to allow UWP access ; to the device interface without the need to be bound with device metadata. ; If Restricted property is set to true, then only applications which are bound ; with device metadata would be allowed access to the device interface. [PWM_Interface_AddProperty] {026e516e-b814-414b-83cd-856d6fef4822},6,0x11,,0
Nicht alle Designs verfügen über die gleiche Richtlinie für die Offenlegung des PWM-Geräts für UWP. Die Richtlinie kann beispielsweise sein, UWP-Zugriff auf eine Teilmenge der PWM-Geräteinstanzen zuzulassen. Zum Verfügbarmachen einer Teilmenge der PWM-Geräte oder zum Zuweisen eines anderen Eigenschaftswerts zu einer oder einer Teilmenge der PWM-Geräteinstanzen ist eine andere Hardware-ID für jedes PWM-Gerät erforderlich, instance und INF-Abschnitte basierend auf der Richtlinie selektiv abgleichen.
Betrachten Sie einen soC-basierten Entwurf, bei dem es vier identische PWM-Geräteinstanzen (IP-Blöcke) mit dem Namen PWM0,...,PWM3 gibt, bei denen ihre ACPI zugewiesene Hardware-ID (_HID) FSCL00E0 und ihre eindeutige ID (_UID) 0,...,3 ist. Um alle PWM-Geräte für UWP verfügbar zu machen, sind die INF-Abschnitte erforderlich, die festlegen, dass die DEVPKEY_DeviceInterface_Restricted für die Hardware-ID ACPI\FSCL00E0 übereinstimmen.
Diese Methode zum Festlegen von Eigenschaften erfordert keine Änderung im Treibercode. Dies ist eine einfachere Option, da die Wartung einer INF-Datei einfacher ist als eine Treiberbinärdatei. Der Nachteil besteht darin, dass für diesen Ansatz eine maßgeschneiderte INF-Datei für jeden Entwurf erforderlich ist.
Programmgesteuert im PWM-Treiber
Ein PWM-Treiber kann IoSetDeviceInterfacePropertyData aufrufen, um Geräteschnittstelleneigenschaften in seiner EVT_WDF_DRIVER_DEVICE_ADD Implementierung festzulegen, nachdem er die PWM-Geräteschnittstelle erstellt und veröffentlicht hat. Der Treiber ist für die Entscheidung des zuzuweisenden Werts und der Geräteeigenschaft verantwortlich. Diese Informationen werden normalerweise im ACPI-System für SoC-basierte Designs gespeichert. Der Wert jeder Geräteschnittstelleneigenschaft kann in jedem ACPI-Geräteknoten _DSD Methode als Geräteeigenschaften angegeben werden. Der Treiber muss the_DSD von ACPI abfragen, die Geräteeigenschaftendaten analysieren, den Wert jeder Eigenschaft extrahieren und ihr die Geräteschnittstelle zuweisen.
Das programmgesteuerte Festlegen der Eigenschaften macht den Treiber und seine INF-Datei designübergreifend portierbar und damit BSPs, bei denen die einzige Änderung im ACPI DSDT liegen würde, der jeden PWM-Geräteknoten definiert. Das Lesen und Analysieren von ACPI-Binärblöcken ist jedoch mühsam und erfordert viel Code, der anfällig für Fehler und Sicherheitsrisiken sein kann, die zu einer größeren Fehleroberfläche führen.
Behandeln von Datei öffnen/schließen-Ereignissen
Ein PWM-Treiber muss sich für Dateierstellungs- und -schließen-Ereignisse registrieren, indem er EVT_WDF_DEVICE_FILE_CREATE- und EVT_WDF_FILE_CLEANUP/EVT_WDF_FILE_CLOSE-Rückruffunktionen implementiert. In der Implementierung muss der Treiber die folgenden Aufgaben ausführen:
Bestimmen Sie, ob die Erstellungsanforderung für einen Controller oder einen Pin gilt.
Wenn es sich bei der Anforderung um einen Pin handelt, muss der Treiber den Pinpfad für die Erstellung von Pinanforderungen analysieren und überprüfen und sicherstellen, dass sich die angeforderte Pinnummer innerhalb der Controllergrenzen befindet.
Gewähren oder Verweigern des Zugriffs auf Controller und Pins erstellen Anforderungen.
Halten Sie controller- und pins-Zustandsintegrität für einen klar definierten Zustandscomputer aufrecht.
In der vorherigen Gruppe von Aufgaben kann die zweite Aufgabe der Überprüfung in EVT_WDF_DEVICE_FILE_CREATE wie folgt ausgeführt werden:
Wenn der dem Anforderungsdateiobjekt zugeordnete Dateiname NULL ist, führen Sie die Anforderung mit STATUS_INVALID_DEVICE_REQUEST aus.
Wenn der dem Anforderungsdateiobjekt zugeordnete Dateiname eine leere Zeichenfolge ist, handelt es sich um eine Controllererstellungsanforderung, andernfalls handelt es sich um eine Anhefterstellungsanforderung.
Wenn es sich um eine Pin-Erstellungsanforderung handelt, dann:
Analysieren Sie den Pinpfad basierend auf dem Format <DecimalName> , und extrahieren Sie die Pinnummer, indem Sie PwmParsePinPath aufrufen.
Wenn beim Analysieren und Überprüfen des Pinpfads ein Fehler aufgetreten ist, schließen Sie die Anforderung mit STATUS_NO_SUCH_FILE ab.
Wenn die Pinnummer größer oder gleich der Anzahl der Controller-Pins ist, führen Sie die Anforderung mit STATUS_NO_SUCH_FILE aus. Beachten Sie, dass die Pinnummer ein nullbasierter Index ist.
Andernfalls können Sie EVT_WDF_DEVICE_FILE_CREATE weiter verarbeiten.
Hier ist ein Beispielcode, der die zuvor erwähnten Validierungsschritte für einen EVT_WDF_DEVICE_FILE_CREATE-Handler implementiert:
EVT_WDF_DEVICE_FILE_CREATE PwmEvtDeviceFileCreate;
VOID
PwmEvtDeviceFileCreate (
WDFDEVICE WdfDevice,
WDFREQUEST WdfRequest,
WDFFILEOBJECT WdfFileObject
)
{
UNICODE_STRING* filenamePtr = WdfFileObjectGetFileName(WdfFileObject);
IMXPWM_DEVICE_CONTEXT* deviceContextPtr = PwmGetDeviceContext(WdfDevice);
NTSTATUS status;
ULONG pinNumber;
//
// Parse and validate the filename associated with the file object
//
bool isPinInterface;
if (filenamePtr == nullptr) {
WdfRequestComplete(WdfRequest, STATUS_INVALID_DEVICE_REQUEST);
return;
} else if (filenamePtr->Length > 0) {
//
// A non-empty filename means to open a pin under the controller namespace
//
status = PwmParsePinPath(filenamePtr, &pinNumber);
if (!NT_SUCCESS(status)) {
WdfRequestComplete(WdfRequest, status);
return;
}
if (pinNumber >= deviceContextPtr->ControllerInfo.PinCount) {
WdfRequestComplete(WdfRequest, STATUS_NO_SUCH_FILE);
return;
}
isPinInterface = true;
} else {
//
// An empty filename means that the create is against the root controller
//
isPinInterface = false;
}
//
// Continue request processing here
//
}
Controller- und Pinfreigabe
Das Freigabemodell für Controller und Pins folgt dem Muster mit mehreren Readern und einem einzelnen Writer. Ein Controller/Pin kann zum Lesen durch mehrere Aufrufer geöffnet werden, aber nur ein Aufrufer kann diesen Controller/Pin gleichzeitig zum Schreiben öffnen.
Dieses Modell kann implementiert werden, indem beim Öffnen eines Dateihandles eine Kombination aus Gewünschtem Zugriff und Freigabezugriffsflags verwendet wird. Das DDI-Freigabemodell entscheidet sich für eine einfachere Freigabesemantik, bei der nur die Spezifikation gewünschter Zugriff zum Steuern des Zugriffs verwendet wird. Die Freigabezugriffsspezifikation spielt keine Rolle im Freigabemodell und wird nicht berücksichtigt, wenn sie beim Öffnen eines Controllers oder einer Pin angegeben wird.
In EVT_WDF_DEVICE_FILE_CREATE sollte die Erstellungsanforderung Desired Access und Share Access basierend auf dem Controller/Pin-Zustand oder wie folgt extrahiert und überprüft werden:
Wenn Share Access nicht 0 ist, verweigern Sie den Zugriff, und schließen Sie die Anforderung mit STATUS_SHARING_VIOLATION ab.
Wenn Desired Access schreibgeschützt ist, gewähren Sie zugriff, und fahren Sie mit der Verarbeitung EVT_WDF_DEVICE_FILE_CREATE fort.
Wenn Desired Access für Schreibvorgänge vorgesehen ist, dann:
Wenn der Controller/Pin bereits für das Schreiben geöffnet ist, verweigern Sie den Zugriff, und schließen Sie die Anforderung mit STATUS_SHARING_VIOLATION ab, andernfalls gewähren Sie Zugriff, markieren Sie den Controller oder die Pin als geöffnet für schreibbereit, und fahren Sie mit der Verarbeitung EVT_WDF_DEVICE_FILE_CREATE fort.
Hier sehen Sie ein Beispiel, das zeigt, wie Sie den gewünschten Zugriff und den Zugriff freigeben aus einer Erstellungsanforderung extrahieren:
void
PwmCreateRequestGetAccess(
_In_ WDFREQUEST WdfRequest,
_Out_ ACCESS_MASK* DesiredAccessPtr,
_Out_ ULONG* ShareAccessPtr
)
{
NT_ASSERT(ARGUMENT_PRESENT(DesiredAccessPtr));
NT_ASSERT(ARGUMENT_PRESENT(ShareAccessPtr));
WDF_REQUEST_PARAMETERS wdfRequestParameters;
WDF_REQUEST_PARAMETERS_INIT(&wdfRequestParameters);
WdfRequestGetParameters(WdfRequest, &wdfRequestParameters);
NT_ASSERTMSG(
"Expected create request",
wdfRequestParameters.Type == WdfRequestTypeCreate);
*DesiredAccessPtr =
wdfRequestParameters.Parameters.Create.SecurityContext->DesiredAccess;
*ShareAccessPtr = wdfRequestParameters.Parameters.Create.ShareAccess;
}
Controller- und Pinunabhängigkeit
Controller und Pin haben eine Beziehung zwischen übergeordnetem und untergeordnetem Element. Um einen Pin zu öffnen, müssen Sie zuerst den übergeordneten Controller öffnen. Eine andere Möglichkeit besteht darin, Pins als unabhängige Entitäten zu betrachten, bei denen der übergeordnete Controller nur einen Dienst für den Pin bereitstellt, der den globalen PWM-Zeitraum für alle in diesem Controller enthaltenen Pins festlegt.
Hier finden Sie einige Beispielszenarien:
Einzelprozesszugriff:
Prozess A kann den Pin öffnen, seinen Arbeitszyklus festlegen, ihn mit dem Standardzeitraum des Controllers starten und später den Controller öffnen und seinen Zeitraum bei Bedarf festlegen. Möglicherweise muss der Controller nie geöffnet werden, wenn der Standardzeitraum für die Anwendung OK ist.
Ein Prozess kann mehrere Threads haben, bei denen jeder einen anderen Pin unter demselben Controller steuert.
Zugriff mit mehreren Prozessen:
Ein Befehlszeilenprogramm kann den Controller mit schreibgeschütztem Zugriff öffnen, um Informationen für die Konsole anzuzeigen. Gleichzeitig kann eine Hintergrund-UWP-Aufgabe den Controller zum Schreiben öffnen und steuert eine LED mit einem einzigen Stift.
Ein Kernelmodusanzeigetreiber, der die LCD-Hintergrundbeleuchtung über Pin0 steuert, während er den Controller zum Schreiben und Sperren des PWM-Zeitraums hält. Gleichzeitig verwendet ein Win32-Dienst den vom Anzeigetreiber festgelegten PWM-Zeitraum und verwendet Pin1, um eine LED zu dimmen, um dem Benutzer einige status mitzuteilen.
Beachten Sie, dass das Öffnen und Schließen eines Controllers unabhängig von seinen Pins einige wichtige Auswirkungen hat. Weitere Informationen finden Sie im Abschnitt zu Zustandscomputern.
Controller- und Pin-Zustandscomputer
Controllerstatusdefinition
Statusfeature | Standardwert | BESCHREIBUNG |
---|---|---|
Is-Opened-for-Write | False | False gibt an, dass der Controller entweder geschlossen oder zum Lesen geöffnet ist. True gibt an, dass es zum Schreiben geöffnet wird. |
Desired-Period | MinimumPeriod |
Der folgende Controllerstatuscomputer ist nur um den Zustand Is-Opened-For-Write zentriert. Der gewünschte Periodenwert wird ebenfalls weggelassen, da er sich nicht auf die Art des Vorgangs auswirkt, der auf dem Controller ausgeführt werden kann. Beachten Sie, dass der Controller immer dann auf die Standardwerte zurückgesetzt wird, wenn ein Für schreibvorgang geöffneter Controller von dem Aufrufer geschlossen wird, der ihn zum Schreiben geöffnet hat.
Definition des Anheftzustands
Statusfeature | Standardwert | BESCHREIBUNG |
---|---|---|
Is-Opened-for-Write | False | False gibt an, dass der Pin entweder geschlossen oder zum Lesen geöffnet ist. True gibt an, dass es zum Schreiben geöffnet wird. |
Aktiv-Duty-Cycle | 0 | |
Is-Started | False | False gibt an, dass dies beendet ist. True gibt an, dass gestartet wurde. |
Der Pinstatuscomputer ist um die Kombination der 2 Zustände Is-Opened-For-Write und Is-Started zentriert. Andere Pinzustände wie Polarität und aktive Betriebszyklen werden weggelassen, da ihre Werte sich nicht auf die Art von Vorgängen auswirken, die am Pin ausgeführt werden können. Beachten Sie, dass immer dann, wenn eine Pin, die zum Schreiben geöffnet wird, von dem Aufrufer geschlossen wird, der ihn zum Schreiben geöffnet hat, der Pin auf die Standardwerte (angehalten, Standardpolarität und aktiver Arbeitszyklus) zurückbekommt. Beachten Sie auch, dass Set-Polarity Übergang in einen Zustand mit Is-Started = true nicht vorhanden ist, da er in diesem Zustand ungültig ist.
Jeder Übergang, der für einen bestimmten Zustand nicht erwähnt wird, impliziert, dass dieser Übergang entweder ungültig oder nicht möglich ist, und die entsprechende Anforderung sollte mit dem entsprechenden Fehler abgeschlossen werden, status.
Implementierungsüberlegungen für Zustandsübergänge
In EVT_WDF_DEVICE_FILE_CREATE sollte der Treiber den Zugriff basierend auf dem gewünschten Zugriff für die Erstellungsanforderung und dem Controller- oder Pinstatus Is-Opened-For-Write wie folgt gewähren oder verweigern:
Wenn die Anforderung den gewünschten Schreibzugriff hat und der Controller/Pin bereits zum Schreiben geöffnet ist, schließen Sie die Anforderung mit STATUS_SHARING_VIOLATION ab, andernfalls markieren Sie den Controller/Pin als geöffnet für das Schreiben (Is-Opened-For-Write = true), gewähren Sie den Zugriff, und fahren Sie mit der Verarbeitung fort.
In diesem Beispiel werden die zuvor erwähnten Schritte zur Zugriffsüberprüfung für einen EVT_WDF_DEVICE_FILE_CREATE-Handler implementiert, bei dem die erforderliche Sperrlogik zum Verarbeiten gleichzeitiger Dateierstellungsanforderungen weggelassen wird:
// // Verify request desired access // const bool hasWriteAccess = desiredAccess & FILE_WRITE_DATA; if (isPinInterface) { PWM_PIN_STATE* pinPtr = deviceContextPtr->Pins + pinNumber; if (hasWriteAccess) { if (pinPtr->IsOpenForReadWrite) { PWM_LOG_TRACE("Pin%lu access denied.", pinNumber); WdfRequestComplete(WdfRequest, STATUS_SHARING_VIOLATION); return; } pinPtr->IsOpenForReadWrite = true; } PWM_LOG_TRACE( "Pin%lu Opened. (IsOpenForReadWrite = %lu)", pinNumber, (pinPtr->IsOpenForReadWrite ? 1 : 0)); } else { if (hasWriteAccess) { if (deviceContextPtr->IsControllerOpenForReadWrite) { PWM_LOG_TRACE("Controller access denied."); WdfRequestComplete(WdfRequest, STATUS_SHARING_VIOLATION); return; } deviceContextPtr->IsControllerOpenForReadWrite = true; } PWM_LOG_TRACE( "Controller Opened. (IsControllerOpenForReadWrite = %lu)", (deviceContextPtr->IsControllerOpenForReadWrite ? 1 : 0)); } // // Allocate and fill a file object context // IMXPWM_FILE_OBJECT_CONTEXT* fileObjectContextPtr; { WDF_OBJECT_ATTRIBUTES wdfObjectAttributes; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( &wdfObjectAttributes, IMXPWM_FILE_OBJECT_CONTEXT); void* contextPtr; NTSTATUS status = WdfObjectAllocateContext( WdfFileObject, &wdfObjectAttributes, &contextPtr); if (!NT_SUCCESS(status)) { IMXPWM_LOG_ERROR( "WdfObjectAllocateContext(...) failed. (status = %!STATUS!)", status); WdfRequestComplete(WdfRequest, status); return; } fileObjectContextPtr = static_cast<IMXPWM_FILE_OBJECT_CONTEXT*>(contextPtr); NT_ASSERT(fileObjectContextPtr != nullptr); fileObjectContextPtr->IsPinInterface = isPinInterface; fileObjectContextPtr->IsOpenForWrite = hasWriteAccess; fileObjectContextPtr->PinNumber = pinNumber; }
In EVT_WDF_FILE_CLOSE/EVT_WDF_FILE_CLEANUP sollte der Treiber die Controller-/Pin-Zustandsintegrität beibehalten.
Wenn das Dateiobjekt zu einem Controller/Pin gehört, der diesen Controller/Pin zum Schreiben geöffnet hat, setzen Sie den Controller/Pin auf den Standardzustand zurück, und heben Sie die Markierung auf, dass controller/pin zum Schreiben geöffnet wird (Is-Opened-For-Write = false).
In diesem Beispiel werden die zuvor erwähnten Schritte zur Zugriffsüberprüfung für einen EVT_WDF_DEVICE_FILE_CLOSE-Handler implementiert, bei dem die erforderliche Sperrlogik zum Verarbeiten gleichzeitiger Anforderungen zum Schließen von Dateien ausgelassen wird.
EVT_WDF_DEVICE_FILE_CLOSE PwmEvtFileClose; VOID PwmEvtFileClose ( WDFFILEOBJECT WdfFileObject ) { WDFDEVICE wdfDevice = WdfFileObjectGetDevice(WdfFileObject); PWM_DEVICE_CONTEXT* deviceContextPtr = PwmGetDeviceContext(wdfDevice); PWM_FILE_OBJECT_CONTEXT* fileObjectContextPtr = PwmGetFileObjectContext(WdfFileObject); if (fileObjectContextPtr->IsPinInterface) { if (fileObjectContextPtr->IsOpenForReadWrite) { const ULONG pinNumber = fileObjectContextPtr->PinNumber; NTSTATUS status = PwmResetPinDefaults(deviceContextPtr, pinNumber); if (!NT_SUCCESS(status)) { PWM_LOG_ERROR( "PwmResetPinDefaults(...) failed. " "(pinNumber = %lu, status = %!STATUS!)", pinNumber, status); // // HW Error Recovery // } NT_ASSERT(deviceContextPtr->Pins[pinNumber].IsOpenForReadWrite); deviceContextPtr->Pins[pinNumber].IsOpenForReadWrite = false; } PWM_LOG_TRACE("Pin%lu Closed.", fileObjectContextPtr->PinNumber); } else { if (fileObjectContextPtr->IsOpenForReadWrite) { NTSTATUS status = PwmResetControllerDefaults(deviceContextPtr); if (!NT_SUCCESS(status)) { IMXPWM_LOG_ERROR( "PwmResetControllerDefaults(...) failed. (status = %!STATUS!)", status); // // HW Error Recovery // } NT_ASSERT(deviceContextPtr->IsControllerOpenForReadWrite); deviceContextPtr->IsControllerOpenForReadWrite = false; } PWM_LOG_TRACE("Controller Closed."); } }
PWM IOCTL-Anforderungen
PWM-IOCTL-Anforderungen werden von einer Anwendung oder einem anderen Treiber gesendet und sind für einen Controller oder einen bestimmten Pin vorgesehen.
Controller-IOCTLs
- IOCTL_PWM_CONTROLLER_GET_ACTUAL_PERIOD
- IOCTL_PWM_CONTROLLER_GET_INFO
- IOCTL_PWM_CONTROLLER_SET_DESIRED_PERIOD
ANHEFTEN VON IOCTLs
- IOCTL_PWM_PIN_GET_ACTIVE_DUTY_CYCLE_PERCENTAGE
- IOCTL_PWM_PIN_SET_ACTIVE_DUTY_CYCLE_PERCENTAGE
- IOCTL_PWM_PIN_GET_POLARITY
- IOCTL_PWM_PIN_SET_POLARITY
- IOCTL_PWM_PIN_START
- IOCTL_PWM_PIN_STOP
- IOCTL_PWM_PIN_IS_STARTED
Für jede IOCTL-Anforderung muss der PWM-Treiber Folgendes überprüfen:
Der angeforderte Vorgang (IOCTL-Code) ist für das Anforderung zugeordnete Dateiobjekt gültig.
Fordern Sie Eingabe- und Ausgabepuffer an, und stellen Sie sicher, dass sie mindestens die erwartete Mindestgröße aufweisen.
Die Gültigkeit des angeforderten Vorgangs im aktuellen Controller-/Pin-Zustand.
Die Gültigkeit der einzelnen Eingabeparameter. Beispiel: Ein gewünschter Zeitraum von 0 ist ein ungültiger Parameter für IOCTL_PWM_CONTROLLER_SET_DESIRED_PERIOD.
IOCTL-Vervollständigung status Codes
Der PWM-Treiber muss die IOCTL-Anforderung mit dem entsprechenden status Code ausfüllen. Hier finden Sie die gängigen Vervollständigungscodes status. Im Allgemeinen sollte eine IOCTL, die eine Eigenschaft mit einem bereits festgelegten Wert festlegt, immer erfolgreich sein. Beispiel: Festlegen des gleichen Zeitraums, der bereits festgelegt ist, Beenden einer bereits beendeten Pin, Festlegen der Polarität, die bereits festgelegt ist usw.
STATUS_NOT_SUPPORTED
Der angeforderte IOCTL-Vorgang wird nicht implementiert oder unterstützt. Beispielsweise können einige Controller das Festlegen der Ausgangssignalpolarität möglicherweise nicht unterstützen. In diesem Fall sollte IOCTL_PWM_PIN_SET_POLARITY implementiert werden, schlägt jedoch mit STATUS_NOT_SUPPORTED für die nicht standardmäßige Polarität fehl.
STATUS_INVALID_DEVICE_REQUEST
Die IOCTL-Anforderung wurde an das falsche Ziel gesendet. Beispielsweise wurde eine Controller-IOCTL-Anforderung mithilfe eines Pindateihandles gesendet.
STATUS_BUFFER_TOO_SMALL
Die Größe des Eingabe- oder Ausgabepuffers ist kleiner als die mindeste erforderliche Puffergröße für die Verarbeitung der Anforderung. Ein WDF-Treiber, der WdfRequestRetrieveInputBuffer oder WdfRequestRetrieveOutputBuffer zum Abrufen und Überprüfen der Eingabe- und Ausgabepuffer verwendet, kann den entsprechenden Fehler status zurückgeben. Alle IOCTLs mit für sie definierten Eingabe- und/oder Ausgabepuffern verfügen über eine entsprechende Struktur, die diesen Puffer beschreibt, wobei die Namen der Eingabe- und Ausgabestruktur INPUT bzw. _OUTPUT postfix aufweisen. Die Minimale Größe des Eingabepuffers ist sizeof(PWMINPUT), während die Minimale Größe des Ausgabepuffers sizeof(PWM_OUTPUT) ist.
IOCTL-Code | BESCHREIBUNG |
---|---|
IOCTL_PWM_CONTROLLER_GET_ACTUAL_PERIOD | Ruft den effektiven Ausgabesignalzeitraum des PWM-Controllers (Pulse Width Modulation) ab, wie er auf seinen Ausgabekanälen gemessen wird. Gibt einen PWM_CONTROLLER_GET_ACTUAL_PERIOD_OUTPUT Wert zurück. Irp-IoStatus.Status> ist auf einen der Werte in der folgenden Liste festgelegt.
|
IOCTL_PWM_CONTROLLER_GET_INFO | Ruft Informationen zu einem PWM-Controller (Pulse Width Modulation) ab. Diese Informationen ändern sich nicht, nachdem der Controller initialisiert wurde. Der Aufrufer sollte einen Ausgabepuffer übergeben, der genau die Größe der PWM_CONTROLLER_INFO Struktur aufweist. Der Treiber leitet die Version der Struktur aus der Größe des Anforderungsausgabepuffers ab. Wenn die Puffergröße kleiner als die Größe der niedrigsten Strukturversion ist, wird die Anforderung mithilfe einer IOCTL-Vervollständigung status STATUS_BUFFER_TOO_SMALL abgeschlossen. Andernfalls geht der Treiber von der höchsten Strukturversion aus, die in den angegebenen Ausgabepuffer passen kann, und schließt die Anforderung erfolgreich ab. Eine neuere PWM_CONTROLLER_INFO Version weist eine Bytegröße auf, die größer als die der vorherigen Version ist. Irp-IoStatus.Status> ist auf einen der Werte in der folgenden Liste festgelegt.
|
IOCTL_PWM_CONTROLLER_SET_DESIRED_PERIOD | Legt den Ausgabesignalzeitraum eines PWM-Controllers (Pulse Width Modulation) auf einen vorgeschlagenen Wert fest. Der PWM-Controller versucht, den Zeitraum basierend auf seinen Funktionen so nahe wie möglich an den angeforderten Wert festzulegen. Der effektive Zeitraum wird als IOCTL-Ausgabe zurückgegeben. Sie kann später mithilfe von IOCTL_PWM_CONTROLLER_GET_ACTUAL_PERIOD abgerufen werden. Der gewünschte Zeitraum muss größer als 0 (0) und im vom Controller unterstützten Zeitraum liegen. Das heißt, es muss sich im Bereich von MinimumPeriod und MaximumPeriod (einschließlich) bewegen, der mithilfe von IOCTL_PWM_CONTROLLER_GET_INFO abgerufen werden kann. Irp-IoStatus.Status> ist auf einen der Werte in der folgenden Liste festgelegt.
|
IOCTL_PWM_PIN_GET_ACTIVE_DUTY_CYCLE_PERCENTAGE | Ruft den aktuellen Tastzyklusprozentsatz für eine Pin oder einen Kanal ab. Der Steuerelementcode gibt den Prozentsatz als PWM_PIN_GET_ACTIVE_DUTY_CYCLE_PERCENTAGE_OUTPUT-Struktur zurück. Irp-IoStatus.Status> ist auf einen der Werte in der folgenden Liste festgelegt.
|
IOCTL_PWM_PIN_SET_ACTIVE_DUTY_CYCLE_PERCENTAGE | Legen Sie einen gewünschten Tastzyklusprozentwert für die Controller-Pin oder den Kanal fest. Der Steuerelementcode gibt den Prozentsatz als PWM_PIN_SET_ACTIVE_DUTY_CYCLE_PERCENTAGE_INPUT-Struktur an. Irp-IoStatus.Status> ist auf einen der Werte in der folgenden Liste festgelegt.
|
IOCTL_PWM_PIN_GET_POLARITY | Ruft die aktuelle Signalpolarität des Pins oder Kanals ab. Der Steuercode ruft die Signalpolarität als PWM_PIN_GET_POLARITY_OUTPUT-Struktur ab. Die Signalpolarität ist entweder Aktiv Hoch oder Aktiv niedrig, wie in der PWM_POLARITY-Enumeration definiert. Irp-IoStatus.Status> ist auf einen der Werte in der folgenden Liste festgelegt.
|
IOCTL_PWM_PIN_SET_POLARITY | Legt die Signalpolarität des Pins oder Kanals fest. Der Steuercode legt die Signalpolarität basierend auf einer PWM_PIN_SET_POLARITY_INPUT-Struktur fest. Die Signalpolarität ist entweder Aktiv Hoch oder Aktiv niedrig, wie in der PWM_POLARITY-Enumeration definiert. Das Ändern der Polarität ist nur zulässig, wenn der Pin beendet wird. Sie können feststellen, ob die Pin beendet wird, indem Sie den IOCTL_PWM_PIN_IS_STARTED-Steuerelementcode verwenden. Wenn der Pin beendet wird und sich die angeforderte Polarität von der aktuellen Polpolarität unterscheidet, wird die Anforderung mit einem STATUS_INVALID_DEVICE_STATE-Wert abgeschlossen. Das Ändern der Polarität, während ein Pin gestartet wird, kann zu Störungen auf einigen PWM-Controllern (Pulse Width Modulation) führen. Wenn Sie die Polarität ändern möchten, beenden Sie zuerst den Pin, ändern Sie die Polarität, und starten Sie dann den Stift. Irp-IoStatus.Status> ist auf einen der Werte in der folgenden Liste festgelegt.
|
IOCTL_PWM_PIN_START | Startet die Generierung von PWM-Signalen (Pulse Width Modulation) an einem Pin oder Kanal. Um zu überprüfen, ob eine Pin gestartet wurde, verwenden Sie IOCTL_PWM_PIN_IS_STARTED. Das Ausstellen dieser IOCTL für einen bereits gestarteten Pin oder Kanal hat keine Auswirkung, ist aber erfolgreich. Irp-IoStatus.Status> ist auf einen der Werte in der folgenden Liste festgelegt. >
|
IOCTL_PWM_PIN_STOP | Beendet die Generierung von PWM-Signalen (Pulse Width Modulation) an einem Pin oder Kanal. Um zu überprüfen, ob eine Pin gestartet wurde, verwenden Sie IOCTL_PWM_PIN_IS_STARTED. Das Ausgeben dieser IOCTL für eine Pin oder einen Kanal, der bereits beendet wurde, hat keine Auswirkung, ist aber erfolgreich. Irp-IoStatus.Status> ist auf einen der Werte in der folgenden Liste festgelegt.
|
IOCTL_PWM_PIN_IS_STARTED | Ruft den Status der Signalgenerierung für einen Pin oder Kanal ab. Jeder Pin weist den Status "Gestartet" oder "Beendet" als PWM_PIN_IS_STARTED_OUTPUT Struktur auf. Der Startzustand weist den booleschen Wert true auf. Der Status "Beendet" ist "false". Standardmäßig wird ein Pin beendet, wenn er geöffnet wird, und kehrt in den Zustand beendet zurück, wenn er geschlossen oder freigegeben wird. Irp-IoStatus.Status> ist auf einen der Werte in der folgenden Liste festgelegt.
|