/*++ Copyright (c) 1991 Microsoft Corporation Module Name: init.c Abstract: DriverEntry initialization code for pnp isa bus extender. Author: Shie-Lin Tzong (shielint) 29-Apr-1996 Environment: Kernel mode only. Revision History: --*/ #include "busp.h" #include "pnpisa.h" // // Internal References // PVOID PipGetMappedAddress( IN INTERFACE_TYPE BusType, IN ULONG BusNumber, IN PHYSICAL_ADDRESS IoAddress, IN ULONG NumberOfBytes, IN ULONG AddressSpace, OUT PBOOLEAN MappedAddress ); NTSTATUS PipAcquirePortResources( IN PPI_BUS_EXTENSION BusExtension, IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath, IN PHYSICAL_ADDRESS BaseAddressLow, IN PHYSICAL_ADDRESS BaseAddressHi, IN ULONG Alignment, IN ULONG PortLength, OUT PCM_RESOURCE_LIST *CmResourceList ); #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,DriverEntry) #pragma alloc_text(INIT,PipAcquirePortResources) #pragma alloc_text(INIT,PipGetMappedAddress) #endif NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This is a temporary driver. It isolates all the PNP ISA cards. For each Pnp Isa device, if its driver is installed, we retrieve user specified resource information to configure the card and turn on the device. Otherwise, we create a device instance for the device and record its resource requirements list. All the work is done in the Init/DriverEntry routine. So, this driver always return failure to let itself be unloaded. Arguments: DriverObject - specifies the driver object for the bus extender. RegistryPath - supplies a pointer to a unicode string of the service key name in the CurrentControlSet\Services key for the bus extender. Return Value: Always return STATUS_UNSUCCESSFUL. --*/ { NTSTATUS status; ULONG size, i, j, csn, cardDetected, maxCardDetected = 0; PHYSICAL_ADDRESS baseAddrHi, baseAddrLow; PUCHAR readDataPort = NULL; PCM_RESOURCE_LIST cmResource, maxCmResource = NULL; PCM_PARTIAL_RESOURCE_DESCRIPTOR cmResourceDescriptor; // // In the first pass, we try to isolate pnpisa cards in the machine // using read data port from each predefined ranges. One some machine // different number of isapnp cards can be detected. We will choose // the read data port which gives the max number of pnpisa cards. // for (i = 0; i < READ_DATA_PORT_RANGE_CHOICES; i++) { baseAddrLow.LowPart = PipReadDataPortRanges[i].MinimumAddress; baseAddrLow.HighPart = 0; baseAddrHi.LowPart = PipReadDataPortRanges[i].MaximumAddress; baseAddrHi.HighPart = 0; status = PipAcquirePortResources( &PipBusExtension, DriverObject, RegistryPath, baseAddrLow, baseAddrHi, PipReadDataPortRanges[i].Alignment, 4, &cmResource ); if (!NT_SUCCESS(status)) { continue; } // // Perform Pnp isolation process. This will assign card select number for each // Pnp Isa card isolated by the system. All the isolated cards will be put into // wait-for-key state. // PipIsolateCards(&csn); // // send initiation key to put cards into sleep state // PipLFSRInitiation (); // // For each card selected, make sure it returns valid card resource data // cardDetected = 0; for (j = 1; j <= csn; j++) { ULONG noDevices, dataLength; PUCHAR cardData; status = PipReadCardResourceData ( j, &noDevices, &cardData, &dataLength); if (!NT_SUCCESS(status)) { continue; } else { ExFreePool(cardData); cardDetected++; } } // // Finaly put all cards into wait for key state. // PipWriteAddress(CONFIG_CONTROL_PORT); PipWriteData(CONTROL_WAIT_FOR_KEY); if ((cardDetected != 0) && (cardDetected >= maxCardDetected)) { maxCardDetected = cardDetected; readDataPort = PipReadDataPort; if (maxCmResource) { ExFreePool(maxCmResource); } maxCmResource = cmResource; } else { ExFreePool(cmResource); } } if (readDataPort != NULL) { if (readDataPort != PipReadDataPort) { if (PipReadDataPort) { if (PipBusExtension.DataPortMapped) { MmUnmapIoSpace(PipReadDataPort - 3, 4); } PipReadDataPort = NULL; } cmResourceDescriptor = &maxCmResource->List->PartialResourceList.PartialDescriptors[0]; PipReadDataPort = PipGetMappedAddress( Isa, // InterfaceType 0, // BusNumber, cmResourceDescriptor->u.Port.Start, cmResourceDescriptor->u.Port.Length, cmResourceDescriptor->Flags, &PipBusExtension.DataPortMapped ); if (PipReadDataPort) { PipReadDataPort += 3; ASSERT(readDataPort == PipReadDataPort); PipBusExtension.ReadDataPort = PipReadDataPort; } else { goto exit; } } // // Perform initial bus check to find all the PnP ISA devices // PipCheckBus(&PipBusExtension); ASSERT(PipBusExtension.NumberCSNs == maxCardDetected); // // Perform PnP ISA device check to see if we should enable it. // PipCheckDevices(RegistryPath, &PipBusExtension); // // Delete all the device info structures and card info structures // PipDeleteCards(&PipBusExtension); } // // Release address, command and read data port resources. // exit: if (maxCmResource) { ExFreePool(maxCmResource); } if (PipCommandPort && PipBusExtension.CmdPortMapped) { MmUnmapIoSpace(PipCommandPort, 1); } if (PipAddressPort && PipBusExtension.AddrPortMapped) { MmUnmapIoSpace(PipAddressPort, 1); } if (PipReadDataPort && PipBusExtension.DataPortMapped) { MmUnmapIoSpace(PipReadDataPort - 3, 4); } IoAssignResources(RegistryPath, NULL, DriverObject, NULL, NULL, NULL); // // Finally, return failure to get ourself unloaded. // return STATUS_UNSUCCESSFUL; } NTSTATUS PipAcquirePortResources( IN PPI_BUS_EXTENSION BusExtension, IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath, IN PHYSICAL_ADDRESS BaseAddressLow, IN PHYSICAL_ADDRESS BaseAddressHi, IN ULONG Alignment, IN ULONG PortLength, OUT PCM_RESOURCE_LIST *CmResourceList ) /*++ Routine Description: This routine acquires specified port resources. Arguments: BusExtension - Supplies a pointer to the pnp bus extension. BaseAddressLow, BaseAddressHi - Supplies the read data port base address range to be mapped. Alignment - supplies the port allignment. PortLength = Number of ports required. Return Value: NTSTATUS code. --*/ { #if 1 PCM_RESOURCE_LIST cmResource; PCM_PARTIAL_RESOURCE_DESCRIPTOR cmResourceDescriptor; NTSTATUS status; ULONG size; PIO_RESOURCE_REQUIREMENTS_LIST ioResource; ULONG i; PHYSICAL_ADDRESS physicalAddress; *CmResourceList = NULL; // // Create a static Io resource requirements list and // Call I/O mgr to get address, command and read data port addresses assigned. // size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); ioResource = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size); RtlZeroMemory(ioResource, size); ioResource->ListSize = size; ioResource->InterfaceType = Isa; ioResource->AlternativeLists = 1; ioResource->List[0].Version = 1; ioResource->List[0].Revision = 1; ioResource->List[0].Count = 1; ioResource->List[0].Descriptors[0].Type = CmResourceTypePort; ioResource->List[0].Descriptors[0].ShareDisposition = CmResourceShareDeviceExclusive; ioResource->List[0].Descriptors[0].Flags = CM_RESOURCE_PORT_IO; ioResource->List[0].Descriptors[0].u.Port.Length = PortLength; ioResource->List[0].Descriptors[0].u.Port.Alignment = Alignment; ioResource->List[0].Descriptors[0].u.Port.MinimumAddress = BaseAddressLow; ioResource->List[0].Descriptors[0].u.Port.MaximumAddress = BaseAddressHi; status = IoAssignResources(RegistryPath, NULL, DriverObject, NULL, ioResource, &cmResource); ExFreePool(ioResource); if (!NT_SUCCESS(status)) { DebugPrint((DEBUG_MESSAGE,"PnpIsa: IoAssignResources failed\n")); return status; } // // Map port addr to memory addr if necessary. // if (PipAddressPort == NULL) { physicalAddress.LowPart = ADDRESS_PORT; physicalAddress.HighPart = 0; BusExtension->AddressPort = PipAddressPort = PipGetMappedAddress( Isa, // InterfaceType 0, // BusNumber, physicalAddress, 1, CM_RESOURCE_PORT_IO, &BusExtension->AddrPortMapped ); if (PipAddressPort == NULL) { goto exit0; } } if (PipCommandPort == NULL) { physicalAddress.LowPart = COMMAND_PORT; physicalAddress.HighPart = 0; BusExtension->CommandPort = PipCommandPort = PipGetMappedAddress( Isa, // InterfaceType 0, // BusNumber, physicalAddress, 1, CM_RESOURCE_PORT_IO, &BusExtension->CmdPortMapped ); if (PipCommandPort == NULL) { goto exit0; } } cmResourceDescriptor = &cmResource->List->PartialResourceList.PartialDescriptors[0]; if ((cmResourceDescriptor->u.Port.Start.LowPart & 0xf) == 0) { // // Some cards (e.g. 3COM elnkiii) do not response to 0xyy3 addr. // DebugPrint((DEBUG_BREAK, "PnpIsa:ReadDataPort is at yy3\n")); goto exit0; } if (PipReadDataPort && BusExtension->DataPortMapped) { MmUnmapIoSpace(PipReadDataPort - 3, 4); PipReadDataPort = NULL; BusExtension->DataPortMapped = FALSE; } PipReadDataPort = PipGetMappedAddress( Isa, // InterfaceType 0, // BusNumber, cmResourceDescriptor->u.Port.Start, cmResourceDescriptor->u.Port.Length, cmResourceDescriptor->Flags, &BusExtension->DataPortMapped ); if (PipReadDataPort) { PipReadDataPort += 3; PipBusExtension.ReadDataPort = PipReadDataPort; } exit0: //ExFreePool(cmResource); if (PipReadDataPort && PipCommandPort && PipAddressPort) { *CmResourceList = cmResource; return STATUS_SUCCESS; } else { return STATUS_INSUFFICIENT_RESOURCES; } #else PCM_RESOURCE_LIST cmResource; PCM_PARTIAL_RESOURCE_DESCRIPTOR cmResourceDescriptor; NTSTATUS status; ULONG size; PIO_RESOURCE_REQUIREMENTS_LIST ioResource; ULONG i; // // Create a static Io resource requirements list and // Call I/O mgr to get address, command and read data port addresses assigned. // size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + sizeof (IO_RESOURCE_DESCRIPTOR) * 2; ioResource = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size); RtlZeroMemory(ioResource, size); ioResource->ListSize = size; ioResource->InterfaceType = Isa; ioResource->AlternativeLists = 1; ioResource->List[0].Version = 1; ioResource->List[0].Revision = 1; ioResource->List[0].Count = 3; ioResource->List[0].Descriptors[0].Type = CmResourceTypePort; ioResource->List[0].Descriptors[0].ShareDisposition = CmResourceShareDeviceExclusive; ioResource->List[0].Descriptors[0].Flags = CM_RESOURCE_PORT_IO; ioResource->List[0].Descriptors[0].u.Port.Length = PortLength; ioResource->List[0].Descriptors[0].u.Port.Alignment = Alignment; ioResource->List[0].Descriptors[0].u.Port.MinimumAddress = BaseAddressLow; ioResource->List[0].Descriptors[0].u.Port.MaximumAddress = BaseAddressHi; ioResource->List[0].Descriptors[1].Type = CmResourceTypePort; ioResource->List[0].Descriptors[1].ShareDisposition = CmResourceShareDeviceExclusive; ioResource->List[0].Descriptors[1].Flags = CM_RESOURCE_PORT_IO; ioResource->List[0].Descriptors[1].u.Port.Length = 1; ioResource->List[0].Descriptors[1].u.Port.Alignment = 1; ioResource->List[0].Descriptors[1].u.Port.MinimumAddress.LowPart = ADDRESS_PORT; ioResource->List[0].Descriptors[1].u.Port.MaximumAddress.LowPart = ADDRESS_PORT; ioResource->List[0].Descriptors[2].Type = CmResourceTypePort; ioResource->List[0].Descriptors[2].ShareDisposition = CmResourceShareDeviceExclusive; ioResource->List[0].Descriptors[2].Flags = CM_RESOURCE_PORT_IO; ioResource->List[0].Descriptors[2].u.Port.Length = 1; ioResource->List[0].Descriptors[2].u.Port.Alignment = 1; ioResource->List[0].Descriptors[2].u.Port.MinimumAddress.LowPart = COMMAND_PORT; ioResource->List[0].Descriptors[2].u.Port.MaximumAddress.LowPart = COMMAND_PORT; status = IoAssignResources(RegistryPath, NULL, DriverObject, NULL, ioResource, &cmResource); ExFreePool(ioResource); if (!NT_SUCCESS(status)) { DebugPrint((DEBUG_MESSAGE,"PnpIsa: IoAssignResources failed\n")); return status; } // // Map port addr to memory addr if necessary. // ASSERT(cmResource->List->PartialResourceList.Count == 3); for (i = 0; i < cmResource->List->PartialResourceList.Count; i++) { cmResourceDescriptor = &cmResource->List->PartialResourceList.PartialDescriptors[i]; ASSERT(cmResourceDescriptor->Type == CmResourceTypePort); if (cmResourceDescriptor->u.Port.Start.LowPart == ADDRESS_PORT) { if (PipAddressPort == NULL) { BusExtension->AddressPort = PipAddressPort = PipGetMappedAddress( Isa, // InterfaceType 0, // BusNumber, cmResourceDescriptor->u.Port.Start, cmResourceDescriptor->u.Port.Length, cmResourceDescriptor->Flags, &BusExtension->AddrPortMapped ); } } else if (cmResourceDescriptor->u.Port.Start.LowPart == COMMAND_PORT) { if (PipCommandPort == NULL) { BusExtension->CommandPort = PipCommandPort = PipGetMappedAddress( Isa, // InterfaceType 0, // BusNumber, cmResourceDescriptor->u.Port.Start, cmResourceDescriptor->u.Port.Length, cmResourceDescriptor->Flags, &BusExtension->CmdPortMapped ); } } else { if ((cmResourceDescriptor->u.Port.Start.LowPart & 0xf) == 0) { // // Some cards (e.g. 3COM elnkiii) do not response to 0xyy3 addr. // DebugPrint((DEBUG_BREAK, "PnpIsa:ReadDataPort is at yy3\n")); goto exit0; } if (PipReadDataPort && BusExtension->DataPortMapped) { MmUnmapIoSpace(PipReadDataPort, 4); PipReadDataPort = NULL; BusExtension->DataPortMapped = FALSE; } PipReadDataPort = PipGetMappedAddress( Isa, // InterfaceType 0, // BusNumber, cmResourceDescriptor->u.Port.Start, cmResourceDescriptor->u.Port.Length, cmResourceDescriptor->Flags, &BusExtension->DataPortMapped ); if (PipReadDataPort) { PipReadDataPort += 3; PipBusExtension.ReadDataPort = PipReadDataPort; } } } exit0: ExFreePool(cmResource); if (PipReadDataPort && PipCommandPort && PipAddressPort) { return STATUS_SUCCESS; } else { IoAssignResources(RegistryPath, NULL, DriverObject, NULL, NULL, NULL); return STATUS_INSUFFICIENT_RESOURCES; } #endif // 1 } PVOID PipGetMappedAddress( IN INTERFACE_TYPE BusType, IN ULONG BusNumber, IN PHYSICAL_ADDRESS IoAddress, IN ULONG NumberOfBytes, IN ULONG AddressSpace, OUT PBOOLEAN MappedAddress ) /*++ Routine Description: This routine maps an IO address to system address space. Arguments: BusType - Supplies the type of bus - eisa, mca, isa... IoBusNumber - Supplies the bus number. IoAddress - Supplies the base device address to be mapped. NumberOfBytes - Supplies the number of bytes for which the address is valid. AddressSpace - Supplies whether the address is in io space or memory. MappedAddress - Supplies whether the address was mapped. This only has meaning if the address returned is non-null. Return Value: The mapped address. --*/ { PHYSICAL_ADDRESS cardAddress; PVOID address; HalTranslateBusAddress(BusType, BusNumber, IoAddress, &AddressSpace, &cardAddress); // // Map the device base address into the virtual address space // if the address is in memory space. // if (!AddressSpace) { address = MmMapIoSpace(cardAddress, NumberOfBytes, FALSE); *MappedAddress = (address ? TRUE : FALSE); } else { address = (PVOID) cardAddress.LowPart; *MappedAddress = FALSE; } return address; }