Книга: Writing Windows WDM Device Drivers
Translating Resources
Translating Resources
At this point, PHDIo has found its raw resource requirements and claimed them for itself. The final stage is to translate the raw resource information into a form that can be used by the driver. Listing 18.6 shows the TranslateAndMapResources routine that does this job.
HalTranslateBusAddress is used to translate a bus address. The bus type and number are passed as the first parameters, followed by the raw address. The AddressSpace parameter is used as both an input and an output. If set to 1, the address is in I/O space. If AddressSpace is 0 on output, the output address in memory space must be mapped using MmMapIoSpace. The PortStartAddress device extension field receives the translated address.
The raw interrupt information must be translated using HalGetInterruptVector. The bus type and number as passed as before. For the ISA bus, specifying the IRQ number for the raw interrupt level and raw vector parameters seems to work. The translated interrupt Vector, Irql, and Affinity are stored in the PHDIo device extension. Do not forget that PHDIo still needs to connect to the interrupt to install its interrupt service routine.
The final step in TranslateAndMapResources is to get a usable pointer to the I/O port. If the port needs mapping, MmMapIoSpace is called to obtain this pointer. Otherwise, PHDIo can just use the low part of the translated port address.
Listing 18.6 TranslateAndMapResources routine
NTSTATUS TranslateAndMapResources(IN PDEVICE_OBJECT phddo) {
PPHDIO_DEVICE_EXTENSION dx = (PPHDIO_DEVICE_EXTENSION)phddo->DeviceExtension;
// Translate IO port values
ULONG AddressSpace = 1; //IO space
if (!HalTranslateBusAddress(Isa, 0, dx->PortStartAddress, &AddressSpace, &dx->PortStartAddress)) {
DebugPrint("Create file: could not translate IO %x", dx->PortStartAddress.LowPart);
return STATUS_INVALID_PARAMETER;
}
DebugPrint("IO trans %x,%d", dx->PortStartAddress.LowPart, dx->PortLength);
dx->PortNeedsMapping = (AddressSpace==0);
dx->PortInIOSpace = (AddressSpace==1);
// Translate IRQ values
if (dx->GotInterrupt) {
ULONG irq = dx->Irql;
dx->Vector = HalGetInterruptVector(Isa, 0, irq, irq, &dx->Irql, &dx->Affinity);
if (dx->Vector==NULL) {
DebugPrint("Create filename: Could not get interrupt vector for IRQ %d", irq);
return STATUS_INVALID_PARAMETER;
}
DebugPrint("Interrupt vector %x IRQL %d Affinity %d Mode %d", dx->Vector, dx->Irql, dx->Affinity, dx->Mode);
}
// Map memory
if (dx->PortNeedsMapping) {
dx->PortBase = (PUCHAR)MmMapIoSpace(dx->PortStartAddress, dx->PortLength, MmNonCached);
if (dx->PortBase==NULL) DebugPrintMsg("Cannot map IO port");
return STATUS_NO_MEMORY;
} else dx->PortBase = (PUCHAR)dx->PortStartAddress.LowPart;
return STATUS_SUCCESS;
}
The FreeResources routine is used to unmap memory and disconnect from the interrupt, if necessary.
Well, that wraps up the discussion of PHDIo. The rest of its functionality is the same as WdmIo. The rest of the chapter backtracks to revisit the subject of finding the resources that a driver needs.
- Appendix E. Other resources and links
- Assessing Your Backup Needs and Resources
- Web Resources
- APPENDIX B Installation Resources
- APPENDIX C Fedora and Linux Internet Resources
- Appendix E. Open Source Resources
- Thread resources on the Internet
- Other resources
- Auditing system resources
- Claiming Resources
- Appendix D. Online Resources
- Appendix A Information Resources