/* * Copyright (c) 1995 FirePower Systems, Inc. * DO NOT DISTRIBUTE without permission * * $RCSfile: pxsiosup.c $ * $Revision: 1.38 $ * $Date: 1996/05/14 02:35:22 $ * $Locker: $ */ /*++ Copyright (c) 1990 Microsoft Corporation Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file contains copyrighted material. Use of this file is restricted by the provisions of a Motorola Software License Agreement. Module Name: pxsiosup.c Abstract: The module provides the PCI ISA bridge support. Author: Jim Wooldridge (jimw@vnet.ibm.com) Revision History: --*/ #include "fpdebug.h" #include "halp.h" #include "eisa.h" #include "pxsiosup.h" #include "pxpcisup.h" #include "pxmemctl.h" #include "bugcodes.h" #include "phsystem.h" #include "fpio.h" #include "fpcpu.h" extern BOOLEAN HalpHandleIpiInterrupt(PKINTERRUPT, PVOID); // // TODO: // 1) Move to PCR // 2) Put on cache line boundaries for peformance (i.e. don't // cache thrash. // #define MAX_CPU 32 ULONG registeredInts[MAX_CPU] = {0}; #define TBS " " #define SioId 0x04848086 #define AMD_ENET 0x20001022 #define AMD_SCSI 0x20201022 #define ESCId 0x04828086 PVOID HalpPciIsaBridgeConfigBase; extern PADAPTER_OBJECT MasterAdapterObject; extern ULONG BugLvl; // // Define the context structure for use by the interrupt routine. // typedef BOOLEAN (*PSECONDARY_DISPATCH)( PVOID InterruptRoutine, PVOID ServiceContext, PVOID TrapFrame ); // // Declare the interrupt structure for profile interrupt // KINTERRUPT HalpProfileInterrupt; // // The following is the interrupt object used for DMA controller interrupts. // DMA controller interrupts occur when a memory parity error occurs or a // programming error occurs to the DMA controller. // // // Declare the interrupt structure for machine checks // KINTERRUPT HalpMachineCheckInterrupt; // // Declare the interrupt structure for the clock interrupt // KINTERRUPT HalpDecrementerInterrupt; // // Add spurious and bogus interrupt counts // #if DBG ULONG HalpSpuriousInterruptCount = 0; ULONG HalpBogusInterruptCount = 0; #endif // // Define Isa bus interrupt affinity. // KAFFINITY HalpIsaBusAffinity; // // The following function is called when a machine check occurs. // BOOLEAN HalpHandleMachineCheck( IN PKINTERRUPT Interrupt, IN PVOID ServiceContext ); // // Define save area for ISA adapter objects. // PADAPTER_OBJECT HalpIsaAdapter[8]; // // Define save area for ISA interrupt mask resiters and level\edge control // registers. // UCHAR HalpSioInterrupt1Mask = 0xff; UCHAR HalpSioInterrupt2Mask = 0xff; UCHAR HalpSioInterrupt1Level; UCHAR HalpSioInterrupt2Level; /*++ Routine Description: BOOLEAN HalpInitializeInterrupts () This routine is called from phase 0 initialization, it initializes the 8259 interrupt controller ( currently it masks all 8259 interrupts). Arguments: None. Return Value: --*/ BOOLEAN HalpInitializeInterrupts ( VOID ) { ULONG Vector; HDBG(DBG_BREAK, HalpDebugPrint("HalpInitializeInterrupts: Calling Break\n");); HDBG(DBG_BREAK, DbgBreakPoint();); // // Mask all 8259 interrupts (except the cascade interrupt) // HalpDisableInterrupts(); for (Vector=0;Vector<16;Vector++) { if (Vector == 2) continue; HalpDisableSioInterrupt(Vector + DEVICE_VECTORS); } // // Reserve the external interrupt vector for exclusive use by the HAL. // PCR->ReservedVectors |= (1 << EXTERNAL_INTERRUPT_VECTOR); return TRUE; } /*++ Routine Description: BOOLEAN HalpCreateSioStructures () This routine initializes the structures necessary for SIO operations and connects the intermediate interrupt dispatcher. It also initializes the SIO interrupt controller. Arguments: None. Return Value: If the second level interrupt dispatcher is connected, then a value of TRUE is returned. Otherwise, a value of FALSE is returned. --*/ BOOLEAN HalpCreateSioStructures ( VOID ) { UCHAR DataByte; // We have no interrupt handlers setup; make sure interrupts are // disabled. (No need to re-enable them) HalpDisableInterrupts(); // // Initialize the IPI for processor zero: // Connect the IPI interrupt handler directly to the CPU dispatch table // without registering with the kernel. // PCR->InterruptRoutine[DEVICE_VECTORS + 31] = (PKINTERRUPT_ROUTINE) HalpHandleIpiInterrupt; // // register the interrupt vector with the HAL // HalpRegisterVector(InternalUsage, DEVICE_VECTORS + 31, DEVICE_VECTORS + 31, HIGH_LEVEL); // // Now enable the IPI interrupt on this CPU; the HAL must do this // directly since we did not register with the kernel. // We cannot call HalEnableSystemInterrupt because the irql masks have // not been set up. Interrupts are disabled anyway. // HalpEnableSioInterrupt(DEVICE_VECTORS + 31, Latched); // // Initialize the Machine Check interrupt handler // if (HalpEnableInterruptHandler(&HalpMachineCheckInterrupt, HalpHandleMachineCheck, NULL, NULL, MACHINE_CHECK_VECTOR, MACHINE_CHECK_LEVEL, MACHINE_CHECK_LEVEL, Latched, FALSE, 0, FALSE, InternalUsage, MACHINE_CHECK_VECTOR ) == FALSE) { KeBugCheck(HAL_INITIALIZATION_FAILED); } // // Enable NMI IOCHK# and PCI SERR# // DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->NmiStatus); WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->NmiStatus, DataByte & ~DISABLE_IOCHK_NMI & ~DISABLE_PCI_SERR_NMI); // // Clear the SIO NMI disable bit. This bit is the high order of the // NMI enable register. // DataByte = 0; // // Connect the external interrupt handler // PCR->InterruptRoutine[EXTERNAL_INTERRUPT_VECTOR] = (PKINTERRUPT_ROUTINE) HalpHandleExternalInterrupt; // PCR->InterruptRoutine[EXTERNAL_INTERRUPT_VECTOR] = // HalpFieldExternalInterrupt; // PCR->InterruptRoutine[EXTERNAL_INTERRUPT_VECTOR] = // HalpHandleExternalInterrupt; // // register the interrupt vector // HalpRegisterVector(InternalUsage, EXTERNAL_INTERRUPT_VECTOR, EXTERNAL_INTERRUPT_VECTOR, HIGH_LEVEL); // Connect directly to the decrementer handler. This is done // directly rather than thru HalpEnableInterruptHandler due to // special handling required because the handler calls KdPollBreakIn(). // PCR->InterruptRoutine[DECREMENT_VECTOR] = (PKINTERRUPT_ROUTINE) HalpHandleDecrementerInterrupt; // // Initialize and connect the Timer 1 interrupt (IRQ0) // if (HalpEnableInterruptHandler( &HalpProfileInterrupt, (PKSERVICE_ROUTINE) HalpHandleProfileInterrupt, (PVOID) NULL, (PKSPIN_LOCK)NULL, PROFILE_VECTOR, PROFILE_LEVEL, PROFILE_LEVEL, Latched, TRUE, 0, FALSE, DeviceUsage, PROFILE_VECTOR ) == FALSE) { KeBugCheck(HAL_INITIALIZATION_FAILED); } // // Disable Timer 1; only used by profiling // HalDisableSystemInterrupt(PROFILE_VECTOR, PROFILE_LEVEL); // // Set default profile rate // HalSetProfileInterval(5000); // // Initialize any planar registers // HalpInitPlanar(); // // Initialize the PCI/ISA bridge chip // HalpInitPciIsaBridge(); PHalpInterruptSetup(); // // Initialize the edge/level register masks to 0 which is the default // edge sensitive value. // HalpSioInterrupt1Level = 0; HalpSioInterrupt2Level = 0; // // Enable the clock interrupt // HalpUpdateDecrementer(1000); // Get those decrementer ticks going // // Set ISA bus interrupt affinity. // HalpIsaBusAffinity = PCR->SetMember; // // DMA command - set assert level // DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Dma1BasePort.DmaStatus); WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Dma1BasePort.DmaStatus, DataByte & ~DACK_ASSERT_HIGH & ~DREQ_ASSERT_LOW); // // Initialize the DMA mode registers to a default value. // Disable all of the DMA channels except channel 4 which is that // cascade of channels 0-3. // WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpIoControlBase)->Dma1BasePort.AllMask, 0x0F ); WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpIoControlBase)->Dma2BasePort.AllMask, 0x0E ); return(TRUE); } BOOLEAN HalpInitPciIsaBridge ( VOID ) { UCHAR DataByte; BOOLEAN Found; ULONG SlotNumber, Tval, bleah; ULONG ChipId=0, DevInt=0, EvInt=0, AChipId=0; UCHAR PCIReg; ULONG BufferLength; // // Save off the interrupt mask for this cpu and then block all interrupts // from coming through while probing the PCI bus. Decrementer is still // enabled. // Tval = RInterruptMask(GetCpuId()); RInterruptMask(GetCpuId()) = 0x0; WaitForRInterruptMask(GetCpuId()); rInterruptRequest = 0xffffffff; FireSyncRegister(); Found = FALSE; SlotNumber = 0; HDBG(DBG_INTERRUPTS, HalpDebugPrint("HalpInitPciIsaBridge:.......................\n");); while (!Found && SlotNumber 15) { // Since this vector has no corollary with the SIO // world, don't do any of the following stuff... // return; } if (Vector & 0x08) { // The interrupt is in controller 2. // Vector &= 0x7; HalpSioInterrupt2Mask |= (UCHAR) 1 << Vector; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1, HalpSioInterrupt2Mask ); } else { // // The interrupt is in controller 1. // Vector &= 0x7; HalpSioInterrupt1Mask |= (UCHAR) 1 << Vector; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1, HalpSioInterrupt1Mask ); } } /*++ Routine Description: VOID HalpIsaMapTransfer() This function programs the SIO DMA controller for a transfer. Arguments: Adapter - Supplies the DMA adapter object to be programed. Offset - Supplies the logical address to use for the transfer. Length - Supplies the length of the transfer in bytes. WriteToDevice - Indicates the direction of the transfer. Return Value: None. --*/ VOID HalpIsaMapTransfer( IN PADAPTER_OBJECT AdapterObject, IN ULONG Offset, IN ULONG Length, IN BOOLEAN WriteToDevice ) { PUCHAR BytePtr; UCHAR adapterMode; UCHAR dataByte; KIRQL Irql; ASSERT(Offset >= IO_CONTROL_PHYSICAL_BASE); adapterMode = AdapterObject->AdapterMode; // // Check to see if this request is for a master I/O card. // if (((PDMA_EISA_MODE) &adapterMode)->RequestMode == CASCADE_REQUEST_MODE) { // // Set the mode, Disable the request and return. // if (AdapterObject->AdapterNumber == 1) { // // This request is for DMA controller 1 // PDMA1_CONTROL dmaControl; dmaControl = AdapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); // // Unmask the DMA channel. // WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) ); } else { // // This request is for DMA controller 1 // PDMA2_CONTROL dmaControl; dmaControl = AdapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); // // Unmask the DMA channel. // WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) ); } return; } // // Determine the mode based on the transfer direction. // ((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) (WriteToDevice ? WRITE_TRANSFER : READ_TRANSFER); BytePtr = (PUCHAR) &Offset; if (AdapterObject->Width16Bits) { // // If this is a 16 bit transfer then adjust the length and the address // for the 16 bit DMA mode. // Length >>= 1; // // In 16 bit DMA mode the low 16 bits are shifted right one and the // page register value is unchanged. So save the page register value // and shift the logical address then restore the page value. // dataByte = BytePtr[2]; Offset >>= 1; BytePtr[2] = dataByte; } // // grab the spinlock for the system DMA controller // KeAcquireSpinLock( &AdapterObject->MasterAdapter->SpinLock, &Irql ); // // Determine the controller number based on the Adapter number. // if (AdapterObject->AdapterNumber == 1) { // // This request is for DMA controller 1 // PDMA1_CONTROL dmaControl; dmaControl = AdapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); WRITE_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseAddress, BytePtr[0] ); WRITE_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseAddress, BytePtr[1] ); WRITE_REGISTER_UCHAR( ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageLowPort) + (ULONG)AdapterObject->PagePort, BytePtr[2] ); WRITE_REGISTER_UCHAR( ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageHighPort) + (ULONG)AdapterObject->PagePort, BytePtr[3] ); // // Notify DMA chip of the length to transfer. // WRITE_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseCount, (UCHAR) ((Length - 1) & 0xff) ); WRITE_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseCount, (UCHAR) ((Length - 1) >> 8) ); // // Set the DMA chip to read or write mode; and unmask it. // WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) ); } else { // // This request is for DMA controller 2 // PDMA2_CONTROL dmaControl; dmaControl = AdapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); WRITE_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseAddress, BytePtr[0] ); WRITE_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseAddress, BytePtr[1] ); WRITE_REGISTER_UCHAR( ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageLowPort) + (ULONG)AdapterObject->PagePort, BytePtr[2] ); WRITE_REGISTER_UCHAR( ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageHighPort) + (ULONG)AdapterObject->PagePort, BytePtr[3] ); // // Notify DMA chip of the length to transfer. // WRITE_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseCount, (UCHAR) ((Length - 1) & 0xff) ); WRITE_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseCount, (UCHAR) ((Length - 1) >> 8) ); // // Set the DMA chip to read or write mode; and unmask it. // WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) ); } KeReleaseSpinLock (&AdapterObject->MasterAdapter->SpinLock, Irql); } /*++ Routine Description: VOID HalpEnableSioInterrupt() This function enables the SIO interrupt and sets the level/edge register to the requested value. Arguments: Vector - Supplies the vector of the interrupt that is enabled. InterruptMode - Supplies the mode of the interrupt; LevelSensitive or Latched. Return Value: None. --*/ VOID HalpEnableSioInterrupt( IN ULONG Vector, IN KINTERRUPT_MODE InterruptMode ) { ULONG CpuId = GetCpuId(); HASSERT(!MSR(EE)); // Calculate the SIO interrupt vector. // Vector -= DEVICE_VECTORS; // Make sure we're protected while we muck with the interrupt masks. // since we asserted interrupts disabled on the way in, we can turn them // off here and not worry about turning them on. If DbgPrint didn't // turn ints off, we wouldn't have to worry about it. // // Remember which interrupts have been turned on or off // registeredInts[CpuId] |= (1 << Vector); // Turn on the bit in the hardware to allow the interrupt // RInterruptMask(CpuId) |= (1 << Vector); WaitForRInterruptMask(CpuId); if (Vector > 0xf) { // 15 is the effective MAX_DEV_VECTORS after the device vector // offset is removed // return; // Since this vector has no corollary with the SIO // world, don't do any of the following stuff... // } InterruptMode = Latched; // // Determine if this vector is for interrupt controller 1 or 2. // if (Vector & 0x08) { // // The interrupt is in controller 2. // Vector &= 0x7; HalpSioInterrupt2Mask &= (UCHAR) ~(1 << Vector); WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1, HalpSioInterrupt2Mask ); // // Set the level/edge control register. // if (InterruptMode == LevelSensitive) { HalpSioInterrupt2Level |= (UCHAR) (1 << Vector); } else { HalpSioInterrupt2Level &= (UCHAR) ~(1 << Vector); } WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2EdgeLevel, HalpSioInterrupt2Level ); } else { // // The interrupt is in controller 1. // Vector &= 0x7; HalpSioInterrupt1Mask &= (UCHAR) ~(1 << Vector); WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1, HalpSioInterrupt1Mask ); // // Set the level/edge control register. // if (InterruptMode == LevelSensitive) { HalpSioInterrupt1Level |= (UCHAR) (1 << Vector); } else { HalpSioInterrupt1Level &= (UCHAR) ~(1 << Vector); } WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1EdgeLevel, HalpSioInterrupt1Level ); } } /*++ Routine Description: PADAPTER_OBJECT HalpAllocateIsaAdapter() This function allocates an ISA adapter object according to the specification supplied in the device description. The necessary device descriptor information is saved. If there is no existing adapter object for this channel then a new one is allocated. The saved information in the adapter object is used to set the various DMA modes when the channel is allocated or a map transfer is done. Arguments: DeviceDescription - Supplies the description of the device which want to use the DMA adapter. NumberofMapRegisters - number of map registers required for the adapter object created Return Value: Returns a pointer to the newly created adapter object or NULL if one cannot be created. --*/ PADAPTER_OBJECT HalpAllocateIsaAdapter( IN PDEVICE_DESCRIPTION DeviceDescriptor, OUT PULONG NumberOfMapRegisters ) { PADAPTER_OBJECT adapterObject; PVOID adapterBaseVa; ULONG channelNumber; ULONG numberOfMapRegisters; ULONG controllerNumber; DMA_EXTENDED_MODE extendedMode; UCHAR adapterMode; BOOLEAN useChannel; ULONG maximumLength; // // Determine if the the channel number is important. Master cards // do not use a channel number. // if ((DeviceDescriptor->Master) && (DeviceDescriptor->InterfaceType != Isa)) { useChannel = FALSE; } else { useChannel = TRUE; } // // Channel 4 cannot be used since it is used for chaining. Return null if // it is requested. // if ((DeviceDescriptor->DmaChannel == 4 || DeviceDescriptor->DmaChannel > 7) && useChannel) { return(NULL); } // // Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES // macro works correctly. // maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff; // // Determine the number of map registers for this device. // if (DeviceDescriptor->ScatterGather && !(DeviceDescriptor->InterfaceType == Isa && DeviceDescriptor->Master)) { // // Scatter gather not supported in SIO // if (!DeviceDescriptor->Master) // // one map register will be required when the the SIO supports this // // numberOfMapRegisters = 1; return NULL; // // Since the device support scatter/Gather then map registers are not // required. // numberOfMapRegisters = 0; } else { // // Determine the number of map registers required based on the maximum // transfer length, up to a maximum number. // numberOfMapRegisters = BYTES_TO_PAGES(maximumLength) + 1; numberOfMapRegisters = numberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ? MAXIMUM_ISA_MAP_REGISTER : numberOfMapRegisters; // // If the device is not a master then it only needs one map register // and does scatter/Gather. // if (DeviceDescriptor->ScatterGather && !DeviceDescriptor->Master) { numberOfMapRegisters = 1; } } // // Set the channel number number. // channelNumber = DeviceDescriptor->DmaChannel & 0x03; // // Set the adapter base address to the Base address register and controller // number. // if (!(DeviceDescriptor->DmaChannel & 0x04)) { controllerNumber = 1; adapterBaseVa = (PVOID) &((PEISA_CONTROL) HalpIoControlBase)->Dma1BasePort; } else { controllerNumber = 2; adapterBaseVa = &((PEISA_CONTROL) HalpIoControlBase)->Dma2BasePort; } // // Determine if a new adapter object is necessary. If so then allocate it. // if (useChannel && HalpIsaAdapter[DeviceDescriptor->DmaChannel] != NULL) { adapterObject = HalpIsaAdapter[DeviceDescriptor->DmaChannel]; if (adapterObject->NeedsMapRegisters) { if (numberOfMapRegisters > adapterObject->MapRegistersPerChannel) { adapterObject->MapRegistersPerChannel = numberOfMapRegisters; } } } else { // // Allocate an adapter object. // adapterObject = (PADAPTER_OBJECT) HalpAllocateAdapter( numberOfMapRegisters, adapterBaseVa, NULL ); if (adapterObject == NULL) { return(NULL); } if (useChannel) { HalpIsaAdapter[DeviceDescriptor->DmaChannel] = adapterObject; } // // Set the maximum number of map registers for this channel bus on // the number requested and the type of device. // if (numberOfMapRegisters) { // // The specified number of registers are actually allowed to be // allocated. // adapterObject->MapRegistersPerChannel = numberOfMapRegisters; // // Increase the commitment for the map registers. // if (DeviceDescriptor->Master) { // // Master I/O devices use several sets of map registers double // their commitment. // MasterAdapterObject->CommittedMapRegisters += numberOfMapRegisters * 2; } else { MasterAdapterObject->CommittedMapRegisters += numberOfMapRegisters; } // // If the committed map registers is significantly greater than the // number allocated then grow the map buffer. // if (MasterAdapterObject->CommittedMapRegisters > MasterAdapterObject->NumberOfMapRegisters && MasterAdapterObject->CommittedMapRegisters - MasterAdapterObject->NumberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ) { HalpGrowMapBuffers( MasterAdapterObject, INCREMENT_MAP_BUFFER_SIZE ); } adapterObject->NeedsMapRegisters = TRUE; } else { // // No real map registers were allocated. If this is a master // device, then the device can have as may registers as it wants. // adapterObject->NeedsMapRegisters = FALSE; if (DeviceDescriptor->Master) { adapterObject->MapRegistersPerChannel = BYTES_TO_PAGES( maximumLength ) + 1; } else { // // The device only gets one register. It must call // IoMapTransfer repeatedly to do a large transfer. // adapterObject->MapRegistersPerChannel = 1; } } } adapterObject->ScatterGather = DeviceDescriptor->ScatterGather; if (DeviceDescriptor->Master) { adapterObject->MasterDevice = TRUE; } else { adapterObject->MasterDevice = FALSE; } if (DeviceDescriptor->Master && (DeviceDescriptor->InterfaceType == Isa)) { adapterObject->IsaBusMaster = TRUE; } else { adapterObject->IsaBusMaster = FALSE; } // // If the channel number is not used then we are finished. The rest of // the work deals with channels. // *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel; // *NumberOfMapRegisters = numberOfMapRegisters; if (!useChannel) { adapterObject->PagePort = (PVOID) (~0x0); ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; return(adapterObject); } // // Setup the pointers to all the random registers. // adapterObject->ChannelNumber = (UCHAR) channelNumber; if (controllerNumber == 1) { switch ((UCHAR)channelNumber) { case 0: adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel0; break; case 1: adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel1; break; case 2: adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel2; break; case 3: adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel3; break; } // // Set the adapter number. // adapterObject->AdapterNumber = 1; // // Save the extended mode register address. // adapterBaseVa = &((PEISA_CONTROL) HalpIoControlBase)->Dma1ExtendedModePort; } else { switch (channelNumber) { case 1: adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel5; break; case 2: adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel6; break; case 3: adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel7; break; } // // Set the adapter number. // adapterObject->AdapterNumber = 2; // // Save the extended mode register address. // adapterBaseVa = &((PEISA_CONTROL) HalpIoControlBase)->Dma2ExtendedModePort; } adapterObject->Width16Bits = FALSE; // // Initialize the extended mode port. // *((PUCHAR) &extendedMode) = 0; extendedMode.ChannelNumber = (UCHAR) channelNumber; switch (DeviceDescriptor->DmaSpeed) { case Compatible: extendedMode.TimingMode = COMPATIBLITY_TIMING; break; case TypeA: extendedMode.TimingMode = TYPE_A_TIMING; break; case TypeB: extendedMode.TimingMode = TYPE_B_TIMING; break; case TypeC: extendedMode.TimingMode = BURST_TIMING; break; default: ObDereferenceObject( adapterObject ); return(NULL); } switch (DeviceDescriptor->DmaWidth) { case Width8Bits: extendedMode.TransferSize = BY_BYTE_8_BITS; break; case Width16Bits: extendedMode.TransferSize = BY_BYTE_16_BITS; // // Note Width16bits should not be set here because there is no need // to shift the address and the transfer count. // break; default: ObDereferenceObject( adapterObject ); return(NULL); } WRITE_REGISTER_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode)); // // Initialize the adapter mode register value to the correct parameters, // and save them in the adapter object. // adapterMode = 0; ((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber; if (DeviceDescriptor->Master) { ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; // // Set the mode, and enable the request. // if (adapterObject->AdapterNumber == 1) { // // This request is for DMA controller 1 // PDMA1_CONTROL dmaControl; dmaControl = adapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); // // Unmask the DMA channel. // WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) ); } else { // // This request is for DMA controller 1 // PDMA2_CONTROL dmaControl; dmaControl = adapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); // // Unmask the DMA channel. // WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) ); } } else if (DeviceDescriptor->DemandMode) { ((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE; } else { ((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE; } if (DeviceDescriptor->AutoInitialize) { ((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1; } adapterObject->AdapterMode = adapterMode; return(adapterObject); } /*++ Routine Description: ULONG HalReadDmaCounter() This function reads the DMA counter and returns the number of bytes left to be transferred. Arguments: AdapterObject - Supplies a pointer to the adapter object to be read. Return Value: Returns the number of bytes still to be transferred. --*/ ULONG HalReadDmaCounter( IN PADAPTER_OBJECT AdapterObject ) { ULONG count=0; ULONG high; if (AdapterObject->PagePort) { // // Determine the controller number based on the Adapter number. // if (AdapterObject->AdapterNumber == 1) { // // This request is for DMA controller 1 // PDMA1_CONTROL dmaControl; dmaControl = AdapterObject->AdapterBaseVa; // // Initialize count to a value which will not match. // count = 0xFFFF00; // // Loop until the same high byte is read twice. // do { high = count; WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); // // Read the current DMA count. // count = READ_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseCount ); count |= READ_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseCount ) << 8; } while ((count & 0xFFFF00) != (high & 0xFFFF00)); } else { // // This request is for DMA controller 2 // PDMA2_CONTROL dmaControl; dmaControl = AdapterObject->AdapterBaseVa; // // Initialize count to a value which will not match. // count = 0xFFFF00; // // Loop until the same high byte is read twice. // do { high = count; WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); // // Read the current DMA count. // count = READ_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseCount ); count |= READ_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseCount ) << 8; } while ((count & 0xFFFF00) != (high & 0xFFFF00)); } // // The DMA counter has a bias of one and can only be 16 bit long. // count = (count + 1) & 0xFFFF; } return(count); } VOID HalpHandleIoError ( VOID ) { UCHAR StatusByte; // // Read NMI status // StatusByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpIoControlBase)->NmiStatus); // // Test for PCI bus error // if (StatusByte & 0x40) { HalDisplayString ("NMI: IOCHK\n"); } // // Test for ISA IOCHK // if (StatusByte & 0x80) { HalDisplayString ("NMI: PCI System Error\n"); } }