Partager via


Écriture de pilotes audio 64 bits

Si vous écrivez un pilote 64 bits ou si vous écrivez un pilote qui peut être compilé pour s’exécuter sur des systèmes 32 et 64 bits, suivez les instructions de portage dans Techniques de programmation de pilote. Certains des pièges que vous pouvez rencontrer lors de l’écriture d’un pilote audio 64 bits sont décrits ci-dessous.

Tout d’abord, un problème potentiel à rechercher dans le code de pilote 32 bits existant est la conversion entre les types de pointeurs et les types entiers tels que DWORD ou ULONG. Les programmeurs qui ont de l’expérience dans l’écriture de code pour des machines 32 bits peuvent être utilisés pour supposer qu’une valeur de pointeur correspond à un DWORD ou ULONG. Pour le code 64 bits, cette hypothèse est dangereuse. Le cast d’un pointeur de type DWORD ou ULONG peut entraîner la troncation d’un pointeur 64 bits. Une meilleure approche consiste à convertir le pointeur en type DWORD_PTR ou ULONG_PTR. Un entier non signé de type DWORD_PTR ou ULONG_PTR est toujours suffisamment grand pour stocker l’intégralité du pointeur, que le code soit compilé pour une machine 32 ou 64 bits.

Par exemple, le champ pointeur IRP IoStatus. Les informations sont de type ULONG_PTR. Le code suivant montre ce qu’il ne faut pas faire lors de la copie d’une valeur de pointeur 64 bits dans ce champ :

    PDEVICE_RELATIONS pDeviceRelations;
    Irp->IoStatus.Information = (ULONG)pDeviceRelations;  // wrong

Cet exemple de code caste par erreur le pDeviceRelations pointeur en type ULONG, qui peut tronquer la valeur du pointeur si sizeof(pDeviceRelations) > sizeof(ULONG). La bonne approche consiste à convertir le pointeur en ULONG_PTR, comme indiqué dans les sections suivantes :

    PDEVICE_RELATIONS pDeviceRelations;
    Irp->IoStatus.Information = (ULONG_PTR)pDeviceRelations;  // correct

Cela permet de conserver les 64 bits de la valeur du pointeur.

Une liste de ressources stocke l’adresse physique d’une ressource dans une structure de type PHYSICAL_ADDRESS (voir IResourceList). Pour éviter la troncation d’une adresse 64 bits, vous devez accéder au membre QuadPart de la structure plutôt qu’à son membre LowPart lors de la copie d’une adresse dans la structure ou de la lecture d’une adresse à partir de la structure. Par exemple, la macro FindTranslatedPort retourne un pointeur vers une structure CM_PARTIAL_RESOURCE_DESCRIPTOR qui contient l’adresse de base d’un port d’E/S. U.Port. Le membre start de cette structure est un pointeur PHYSICAL_ADDRESS vers l’adresse de base. Le code suivant montre ce qu’il ne faut pas faire :

    PUSHORT pBase = (PUSHORT)FindTranslatedPort(0)->u.Port.Start.LowPart;  // wrong

Là encore, cela peut tronquer le pointeur. Au lieu de cela, vous devez accéder à QuadPart de ce membre, comme indiqué dans les éléments suivants :

    PUSHORT pBase = (PUSHORT)FindTranslatedPort(0)->u.Port.Start.QuadPart;  // correct

Cette opération copie l’intégralité du pointeur 64 bits.

Les fonctions Win64 inline telles que PtrToUlong et UlongToPtr sont converties en toute sécurité entre les types pointeur et entier sans se fier à des hypothèses sur les tailles relatives de ces types. Si un type est plus court que l’autre, il doit être étendu lors de la conversion vers le type plus long. Si le type plus court est étendu en remplissant avec le bit de signe ou avec des zéros est bien défini pour chaque fonction Win64. Cela signifie que tous les extraits de code tels que

    ULONG ulSlotPhysAddr[NUM_PHYS_ADDRS];
    ulSlotPhysAddr[0] = ULONG(pulPhysDmaBuffer) + DMA_BUFFER_SIZE;  // wrong

doit être remplacé par

    ULONG_PTR ulSlotPhysAddr[NUM_PHYS_ADDRS];
    ulSlotPhysAddr[0] = PtrToUlong(pulPhysDmaBuffer) + DMA_BUFFER_SIZE;  // correct

Cela est préférable même si ulSlotPhysAddr peut représenter la valeur d’un registre matériel qui n’est que de 32 bits au lieu de 64 bits. Pour obtenir la liste de toutes les nouvelles fonctions d’assistance Win64 pour la conversion entre les types pointeur et entier, consultez Les nouveaux types de données.