Utilisation de la structure SPB_TRANSFER_LIST pour les IOCTL personnalisées
Si votre pilote de contrôleur de bus périphérique simple (SPB) prend en charge une ou plusieurs demandes de contrôle d’E/S personnalisés (IOCTL), utilisez la structure SPB_TRANSFER_LIST pour décrire les mémoires tampons de lecture et d’écriture dans ces demandes. Cette structure fournit un moyen uniforme de décrire les mémoires tampons dans une requête et évite la surcharge de copie de mémoire tampon associée aux opérations d’E/S METHOD_BUFFERED.
Si vos demandes IOCTL personnalisées utilisent la structure SPB_TRANSFER_LIST , votre pilote de contrôleur SPB doit appeler la méthode SpbRequestCaptureIoOtherTransferList pour capturer ces mémoires tampons dans le contexte de processus de l’initiateur de la demande. Votre pilote peut appeler la méthode SpbRequestGetTransferParameters pour accéder à ces mémoires tampons.
Les requêtes IOCTL_SPB_FULL_DUPLEX et IOCTL_SPB_EXECUTE_SEQUENCE , qui sont définies dans le cadre de l’interface de demande d’E/S SPB, utilisent la structure SPB_TRANSFER_LIST pour décrire leurs mémoires tampons de lecture et d’écriture. La structure SPB_TRANSFER_LIST d’une demande de IOCTL_SPB_FULL_DUPLEX décrit à la fois la mémoire tampon d’écriture et la mémoire tampon de lecture (dans cet ordre) dans la requête. La structure SPB_TRANSFER_LIST d’une demande de IOCTL_SPB_EXECUTE_SEQUENCE peut décrire une séquence arbitraire de mémoires tampons de lecture et d’écriture.
De même, vous pouvez définir vos IOCTL personnalisées pour exiger que leurs structures SPB_TRANSFER_LIST utilisent une combinaison de mémoires tampons de lecture et d’écriture, et spécifier l’ordre des mémoires tampons dans la liste qui peut être nécessaire.
Le pilote KMDF (Kernel-Mode Driver Foundation) pour un périphérique SPB appelle une méthode telle que WdfIoTargetSendIoctlSynchronously pour envoyer une requête IOCTL à un contrôleur SPB. Cette méthode a des paramètres InputBuffer et OutputBuffer . Les pilotes de certains types d’appareils peuvent utiliser ces deux paramètres pour pointer vers la mémoire tampon d’écriture et la mémoire tampon de lecture, respectivement, pour une requête IOCTL. Toutefois, pour envoyer une requête IOCTL à un contrôleur SPB, le pilote de périphérique SPB définit le paramètre InputBuffer pour qu’il pointe vers un descripteur de mémoire qui pointe vers une structure SPB_TRANSFER_LIST . Cette structure décrit toutes les mémoires tampons de lecture ou d’écriture requises pour l’opération de contrôle d’E/S. Le pilote définit le paramètre OutputBuffer sur NULL.
De même, le pilote UMDF (User-Mode Driver Foundation) pour un périphérique SPB appelle une méthode telle que IWDFIoTarget::FormatRequestForIoctl pour mettre en forme une demande d’E/S pour une opération de contrôle d’E/S. Cette méthode a des paramètres pInputMemory et pOutputMemory . Les pilotes de certains types d’appareils peuvent utiliser ces deux paramètres pour pointer vers la mémoire tampon d’écriture et la mémoire tampon de lecture pour une requête IOCTL. Toutefois, pour envoyer une requête IOCTL à un contrôleur SPB, le pilote de périphérique SPB définit le paramètre pInputMemory pour qu’il pointe vers un objet mémoire qui contient une structure SPB_TRANSFER_LIST . Cette structure décrit toutes les mémoires tampons de lecture ou d’écriture requises pour l’opération de contrôle d’E/S. Le pilote définit le paramètre pOutputMemory sur NULL.
Vérification des paramètres et capture de mémoire tampon
Lorsque l’extension de l’infrastructure SPB (SpbCx) reçoit une demande de IOCTL_SPB_EXECUTE_SEQUENCE , SpbCx transmet cette requête au pilote du contrôleur SPB en appelant la fonction EvtSpbControllerIoSequence du pilote. Avant cet appel, SpbCx inspecte la structure SPB_TRANSFER_LIST qui décrit les mémoires tampons dans la demande. SpbCx capture ces mémoires tampons dans le contexte de processus de l’initiateur de la demande. (Les mémoires tampons en mode utilisateur sont accessibles uniquement dans le processus dans lequel la mémoire est allouée.) En outre, SpbCx vérifie si les valeurs de paramètre de la demande sont valides.
Lorsque SpbCx reçoit une demande de IOCTL_SPB_FULL_DUPLEX ou une requête IOCTL personnalisée, SpbCx transmet cette demande au pilote du contrôleur SPB en appelant la fonction de rappel EvtSpbControllerIoOther du pilote. Avant d’effectuer cet appel, SpbCx n’effectue aucune vérification de validation des valeurs de paramètre dans la requête et ne capture pas les mémoires tampons de la requête dans le contexte de l’initiateur. La vérification des paramètres et la capture de mémoire tampon pour ces requêtes sont de la responsabilité du pilote du contrôleur SPB.
Si un pilote de contrôleur SPB prend en charge la demande IOCTL_SPB_FULL_DUPLEX ou prend en charge une requête IOCTL personnalisée qui utilise la structure SPB_TRANSFER_LIST pour ses mémoires tampons, le pilote doit implémenter une fonction de rappel EvtIoInCallerContext . Le pilote fournit un pointeur vers cette fonction en tant que paramètre d’entrée dans l’appel à la méthode SpbControllerSetIoOtherCallback qui inscrit la fonction de rappel EvtSpbControllerIoOther du pilote. Lorsque SpbCx reçoit une demande IOCTL_SPB_FULL_DUPLEX ou une requête IOCTL personnalisée, SpbCx appelle la fonction EvtIoInCallerContext du pilote dans le contexte de l’initiateur. Si la requête IOCTL utilise la structure SPB_TRANSFER_LIST , la fonction EvtIoInCallerContext appelle la méthode SpbRequestCaptureIoOtherTransferList pour capturer les mémoires tampons dans la requête. La fonction EvtIoInCallerContext peut également effectuer un traitement préliminaire de la demande.
L’exemple de code suivant montre une fonction EvtIoInCallerContext implémentée par un pilote de contrôleur SPB.
VOID
EvtIoInCallerContext(
_In_ WDFDEVICE SpbController,
_In_ WDFREQUEST FxRequest
)
{
NTSTATUS status = STATUS_SUCCESS;
WDF_REQUEST_PARAMETERS fxParams;
WDF_REQUEST_PARAMETERS_INIT(&fxParams);
WdfRequestGetParameters(FxRequest, &fxParams);
if ((fxParams.Type != WdfRequestTypeDeviceControl) &&
(fxParams.Type != WdfRequestTypeDeviceControlInternal))
{
status = STATUS_NOT_SUPPORTED;
goto exit;
}
//
// The driver should check for custom IOCTLs that it handles.
// If the IOCTL is not recognized, complete the request with a
// status of STATUS_NOT_SUPPORTED.
//
switch (fxParams.Parameters.DeviceIoControl.IoControlCode)
{
...
default:
status = STATUS_NOT_SUPPORTED;
goto exit;
}
//
// The IOCTL is recognized. Capture the buffers in the request.
//
status = SpbRequestCaptureIoOtherTransferList((SPBREQUEST)FxRequest);
//
// If the capture fails, the driver must complete the request instead
// of placing it in the SPB controller's request queue.
//
if (!NT_SUCCESS(status))
{
goto exit;
}
status = WdfDeviceEnqueueRequest(SpbController, FxRequest);
if (!NT_SUCCESS(status))
{
goto exit;
}
exit:
if (!NT_SUCCESS(status))
{
WdfRequestComplete(FxRequest, status);
}
}
Dans l’exemple de code précédent, l’instruction switch
vérifie que la requête contient un IOCTL que le pilote du contrôleur SPB reconnaît. (Par souci de concision, le corps de l’instruction switch
n’est pas affiché.) Ensuite, l’appel à la méthode SpbRequestCaptureIoOtherTransferList capture les mémoires tampons dans la requête. Si cet appel réussit, la demande est ajoutée à la file d’attente d’E/S du contrôleur SPB. Sinon, la demande est terminée avec un code d’état d’erreur.
Pour obtenir un exemple de code montrant la vérification des paramètres par une fonction EvtSpbControllerIoOther , consultez Gestion des demandes IOCTL_SPB_FULL_DUPLEX.