Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Una risorsa I/O GPIO è un set di uno o più pin GPIO configurati come input di dati o output di dati. Il driver per un dispositivo periferico che si connette fisicamente a questi pin acquisisce la risorsa I/O GPIO corrispondente dal sistema operativo. Il driver di dispositivo periferico apre una connessione ai pin GPIO in questa risorsa e invia richieste di I/O all'handle che rappresenta questa connessione.
L'esempio di codice seguente mostra come il framework del driver in modalità kernel (KMDF) per un dispositivo periferico possa ottenere una descrizione della risorsa I/O GPIO che il gestore Plug and Play (PnP) ha assegnato al driver.
NTSTATUS
EvtDevicePrepareHardware(
_In_ WDFDEVICE Device,
_In_ WDFCMRESLIST ResourcesRaw,
_In_ WDFCMRESLIST ResourcesTranslated
)
{
int ResourceCount, Index;
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
XYZ_DEVICE_CONTEXT *DeviceExtension;
...
DeviceExtension = XyzDrvGetDeviceExtension(Device);
ResourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
for (Index = 0; Index < ResourceCount; Index += 1) {
Descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, Index);
switch (Descriptor->Type) {
//
// GPIO I/O descriptors
//
case CmResourceTypeConnection:
//
// Check against expected connection type.
//
if ((Descriptor->u.Connection.Class == CM_RESOURCE_CONNECTION_CLASS_GPIO) &&
(Descriptor->u.Connection.Type == CM_RESOURCE_CONNECTION_TYPE_GPIO_IO)) {
DeviceExtension->ConnectionId.LowPart = Descriptor->u.Connection.IdLowPart;
DeviceExtension->ConnectionId.HighPart = Descriptor->u.Connection.IdHighPart;
...
}
Nell'esempio di codice precedente, la variabile DeviceExtension
è un puntatore al contesto di dispositivo per il dispositivo periferico. La funzione XyzDrvGetDeviceExtension
, che recupera questo contesto di dispositivo, viene implementata dal driver di dispositivo periferico. Questo driver aveva precedentemente registrato la propria funzione di callback EvtDevicePrepareHardware chiamando il metodo WdfDeviceInitSetPnpPowerEventCallbacks.
Nell'esempio di codice seguente viene illustrato come il driver di dispositivo periferico può usare la descrizione della risorsa GPIO ottenuta nell'esempio di codice precedente per aprire un handle WDFIOTARGET alla risorsa I/O GPIO del driver.
NTSTATUS IoRoutine(WDFDEVICE Device, BOOLEAN ReadOperation)
{
WDFIOTARGET IoTarget;
XYZ_DEVICE_CONTEXT *DeviceExtension;
UNICODE_STRING ReadString;
WCHAR ReadStringBuffer[100];
BOOL DesiredAccess;
NTSTATUS Status;
WDF_OBJECT_ATTRIBUTES ObjectAttributes;
WDF_IO_TARGET_OPEN_PARAMS OpenParams
DeviceExtension = XyzDrvGetDeviceExtension(Device);
RtlInitEmptyUnicodeString(&ReadString,
ReadStringBuffer,
sizeof(ReadStringBuffer));
Status = RESOURCE_HUB_CREATE_PATH_FROM_ID(&ReadString,
DeviceExtension->ConnectionId.LowPart,
DeviceExtension->ConnectionId.HighPart);
NT_ASSERT(NT_SUCCESS(Status));
WDF_OBJECT_ATTRIBUTES_INIT(&ObjectAttributes);
ObjectAttributes.ParentObject = Device;
Status = WdfIoTargetCreate(Device, &ObjectAttributes, &IoTarget);
if (!NT_SUCCESS(Status)) {
goto IoErrorEnd;
}
if (ReadOperation != FALSE) {
DesiredAccess = GENERIC_READ;
} else {
DesiredAccess = GENERIC_WRITE;
}
WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(&OpenParams, ReadString, DesiredAccess);
Status = WdfIoTargetOpen(IoTarget, &OpenParams);
if (!NT_SUCCESS(Status)) {
goto IoErrorEnd;
}
...
Nell'esempio di codice precedente, la variabile Device
è un handle WDFDEVICE per l'oggetto dispositivo del framework per il dispositivo periferico. La funzione RESOURCE_HUB_CREATE_PATH_FROM_ID crea una stringa contenente il nome della risorsa I/O GPIO. Nell'esempio di codice viene usata questa stringa per aprire la risorsa I/O GPIO in base al nome.
Dopo che il driver di dispositivo periferico ha ottenuto un handle per una risorsa I/O GPIO, questo driver può inviare richieste di controllo I/O per leggere o scrivere dati nei pin GPIO. Un driver che apre una risorsa I/O GPIO per le letture usa IOCTL_GPIO_READ_PINS richieste di controllo di I/O per leggere i dati dai pin nella risorsa. Un driver che apre una risorsa I/O GPIO per le scritture utilizza le richieste di controllo di I/O IOCTL_GPIO_WRITE_PINS per scrivere dati nei pin della risorsa. Nell'esempio di codice seguente viene illustrato come eseguire un'operazione di lettura o scrittura GPIO.
WDF_OBJECT_ATTRIBUTES RequestAttributes;
WDF_OBJECT_ATTRIBUTES Attributes;
WDF_REQUEST_SEND_OPTIONS SendOptions;
WDFREQUEST IoctlRequest;
WDFIOTARGET IoTarget;
WDFMEMORY WdfMemory;
NTSTATUS Status;
WDF_OBJECT_ATTRIBUTES_INIT(&RequestAttributes);
Status = WdfRequestCreate(&RequestAttributes, IoTarget, &IoctlRequest);
if (!NT_SUCCESS(Status)) {
goto RwErrorExit;
}
//
// Set up a WDF memory object for the IOCTL request.
//
WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
Attributes.ParentObject = IoctlRequest;
Status = WdfMemoryCreatePreallocated(&Attributes, Data, Size, &WdfMemory);
if (!NT_SUCCESS(Status)) {
goto RwErrorExit;
}
//
// Format the request.
//
if (ReadOperation != FALSE) {
Status = WdfIoTargetFormatRequestForIoctl(IoTarget,
IoctlRequest,
IOCTL_GPIO_READ_PINS,
NULL,
0,
WdfMemory,
0);
} else {
Status = WdfIoTargetFormatRequestForIoctl(IoTarget,
IoctlRequest,
IOCTL_GPIO_WRITE_PINS,
WdfMemory,
0,
WdfMemory,
0);
}
if (!NT_SUCCESS(Status)) {
goto RwErrorExit;
}
//
// Send the request synchronously (with a 60-second time-out).
//
WDF_REQUEST_SEND_OPTIONS_INIT(&SendOptions,
WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&SendOptions,
WDF_REL_TIMEOUT_IN_SEC(60));
Status = WdfRequestAllocateTimer(IoctlRequest);
if (!NT_SUCCESS(Status)) {
goto RwErrorExit;
}
if (!WdfRequestSend(IoctlRequest, IoTarget, &SendOptions)) {
Status = WdfRequestGetStatus(IoctlRequest);
}
...
Nell'esempio di codice precedente, Data
è un puntatore a un buffer di dati, Size
è la dimensione, in byte, di questo buffer di dati e ReadOperation
indica se l'operazione richiesta è una lettura (TRUE) o una scrittura (FALSE).
Per altre informazioni
Per altre informazioni sulle richieste di IOCTL_GPIO_READ_PINS, incluso il mapping dei pin di input dei dati ai bit nel buffer di output della richiesta, vedere IOCTL_GPIO_READ_PINS. Per altre informazioni sulle richieste di IOCTL_GPIO_WRITE_PINS, incluso il mapping dei bit nel buffer di input della richiesta ai pin di output dei dati, vedere IOCTL_GPIO_WRITE_PINS.
Per un driver di esempio che mostra come scrivere un driver di periferica GPIO eseguito in modalità kernel, vedere il driver di esempio SimDevice nel driver di esempio GPIO raccolta su GitHub.