#if defined(JAZZ) || defined(DUO) /*++ Copyright (c) 1990 Microsoft Corporation Module Name: jxhwsup.c Abstract: This module contains the IopXxx routines for the NT OS/2 I/O system that are hardware dependent. Were these routines not hardware dependent, they would normally reside in the internal.c module. Author: Jeff Havens (jhavens) 14-Feb-1990 Environment: Kernel mode, local to I/O system Revision History: --*/ #include "fwp.h" #include "jxfwhal.h" #include "eisa.h" #include "fwstring.h" PADAPTER_OBJECT HalpInternalAdapters[8]; PADAPTER_OBJECT HalpEisaAdapter[8]; PTRANSLATION_ENTRY FreeTranslationEntry = NULL; VOID IopAllocateCommonBuffer( IN PVOID NonCachedExtension, IN ULONG NonCachedExtensionSize, OUT PPHYSICAL_ADDRESS LogicalAddress ); PADAPTER_OBJECT IopAllocateAdapter( IN ULONG MapRegistersPerChannel, IN PVOID AdapterBaseVa, IN PVOID MapRegisterBase ); PADAPTER_OBJECT IopAllocateEisaAdapter( IN PDEVICE_DESCRIPTION DeviceDescriptor ); #ifndef DUO PADAPTER_OBJECT HalGetAdapter( IN PDEVICE_DESCRIPTION DeviceDescription, IN OUT PULONG NumberOfMapRegisters ) /*++ Routine Description: This function returns the appropriate adapter object for the device defined in the device description structure. Three bus types are supported for the Jazz system: Internal, Isa, and Eisa. Arguments: DeviceDescription - Supplies a description of the deivce. NumberOfMapRegisters - Returns the maximum number of map registers which may be allocated by the device driver. Return Value: A pointer to the requested adpater object or NULL if an adapter could not be created. --*/ { PADAPTER_OBJECT adapterObject; // // Make sure this is the correct version. // if (DeviceDescription->Version != DEVICE_DESCRIPTION_VERSION) { return(NULL); } // // Set the maximum number of map registers if requested. // if (NumberOfMapRegisters != NULL) { // // Return half the total number of map registers per channel. // *NumberOfMapRegisters = DMA_TRANSLATION_LIMIT / sizeof(TRANSLATION_ENTRY) -10; } if (DeviceDescription->InterfaceType == Internal) { // // Return the adapter pointer for internal adapters. // // If this is a master controler such as the SONIC then return the // last channel. // if (DeviceDescription->Master) { // // Create an adapter if necessary. // if (HalpInternalAdapters[7] == NULL) { HalpInternalAdapters[7] = IopAllocateAdapter( 0, (PVOID) &(DMA_CONTROL)->Channel[7], NULL ); } return(HalpInternalAdapters[7]); } // // Make sure the DMA channel range is valid. Only use channels 0-6. // if (DeviceDescription->DmaChannel > 6) { return(NULL); } // // If necessary allocate an adapter; otherwise, // just return the adapter for the requested channel. // if (HalpInternalAdapters[DeviceDescription->DmaChannel] == NULL) { HalpInternalAdapters[DeviceDescription->DmaChannel] = IopAllocateAdapter( 0, (PVOID) &(DMA_CONTROL)->Channel[DeviceDescription->DmaChannel], NULL ); } return(HalpInternalAdapters[DeviceDescription->DmaChannel]); } // // If the request is for a unsupported bus then return NULL. // if (DeviceDescription->InterfaceType != Isa && DeviceDescription->InterfaceType != Eisa) { // // This bus type is unsupported return NULL. // return(NULL); } // // Create an adapter object. // adapterObject = IopAllocateEisaAdapter( DeviceDescription ); return(adapterObject); } #else PADAPTER_OBJECT HalGetAdapter( IN PDEVICE_DESCRIPTION DeviceDescription, IN OUT PULONG NumberOfMapRegisters ) /*++ Routine Description: This function returns the appropriate adapter object for the device defined in the device description structure. Three bus types are supported for the Jazz system: Internal, Isa, and Eisa. Arguments: DeviceDescription - Supplies a description of the deivce. NumberOfMapRegisters - Returns the maximum number of map registers which may be allocated by the device driver. Return Value: A pointer to the requested adpater object or NULL if an adapter could not be created. --*/ { PADAPTER_OBJECT adapterObject; UCHAR adapterMode; // // Make sure this is the correct version. // if (DeviceDescription->Version != DEVICE_DESCRIPTION_VERSION) { return(NULL); } // // Set the maximum number of map registers if requested. // if (NumberOfMapRegisters != NULL) { // // Return half the total number of map registers per channel. // *NumberOfMapRegisters = DMA_TRANSLATION_LIMIT / sizeof(TRANSLATION_ENTRY) -10; } if (DeviceDescription->InterfaceType == Internal) { // // Return the adapter pointer for internal adapters. // // If this is a master controler return NULL; No adapter object is // needed. // if (DeviceDescription->Master) { adapterObject = IopAllocateAdapter(0,NULL,NULL); adapterObject->PagePort = ~0; adapterMode = 0; ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; adapterObject->AdapterMode = adapterMode; return (adapterObject); } else { // // Internal channels not supported // return(NULL); } } // // If the request is for a unsupported bus then return NULL. // if ((DeviceDescription->InterfaceType != Isa) && (DeviceDescription->InterfaceType != Eisa)) { // // This bus type is unsupported return NULL. // return(NULL); } // // Create an adapter object. // adapterObject = IopAllocateEisaAdapter(DeviceDescription); return(adapterObject); } #endif #if 0 VOID FixIsp( ) /*++ Routine Description: This is a temporary routine to set the ISP back to a usable way after the eisa config stuff screws it. This routine is to be used with the ncrc700 ISA debug board. Arguments: None Return Value: None --*/ { // // Initialize the Isp For Channel 5 Isa master // WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD2, 1); WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD4, 5); WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD8, 0); WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xC6, 0); WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xC6, 0); WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD6, 0xD9); WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD4, 0x1); // // Initialize the Isp For Channel 6 Isa master // //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD2, 2); //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD4, 6); //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD8, 0); //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xCA, 0); //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xCA, 0); //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD6, 0xDA); //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD4, 0x2); } #endif BOOLEAN HalTranslateBusAddress( IN INTERFACE_TYPE InterfaceType, IN ULONG BusNumber, IN PHYSICAL_ADDRESS BusAddress, IN OUT PULONG AddressSpace, OUT PPHYSICAL_ADDRESS TranslatedAddress ) /*++ Routine Description: This function returns the system physical address for a specified I/O bus address. The return value is suitable for use in a subsequent call to MmMapIoSpace. Arguments: InterfaceType - Supplies the type of bus which the address is for. BusNumber - Supplies the bus number for the device. BusAddress - Supplies the bus relative address. AddressSpace - Supplies the address space number for the device: 0 for memory and 1 for I/O space. Returns the address space on this system. Return Value: Returns the system physical address for the specificed bus address. --*/ { TranslatedAddress->HighPart = 0; TranslatedAddress->LowPart = 0; // // If this is for the internal bus then just return the passed parameter. // if (InterfaceType == Internal) { // // Return the passed parameters. // TranslatedAddress->LowPart = BusAddress.LowPart; return(TRUE); } if (InterfaceType != Isa && InterfaceType != Eisa) { // // Not on this system return nothing. // *AddressSpace = 0; return (FALSE); } // // Jazz only has one I/O bus which is an EISA, so the bus number is unused. // // Determine the address based on whether the bus address is in I/O space // or bus memory space. // if (*AddressSpace) { // // The address is in I/O space. // *AddressSpace = 0; TranslatedAddress->LowPart = BusAddress.LowPart + EISA_CONTROL_PHYSICAL_BASE; return(TRUE); } else { // // The address is in memory space. // *AddressSpace = 0; TranslatedAddress->LowPart = BusAddress.LowPart + EISA_MEMORY_PHYSICAL_BASE; return(TRUE); } } PADAPTER_OBJECT IopAllocateAdapter( IN ULONG MapRegistersPerChannel, IN PVOID AdapterBaseVa, IN PVOID MapRegisterBase ) /*++ Routine Description: This routine allocates and initializes an adapter object to represent an adapter or a DMA controller on the system. Arguments: MapRegistersPerChannel - Unused. AdapterBaseVa - Base virtual address of the adapter itself. If AdpaterBaseVa is NULL then the MasterAdapterObject is allocated. MapRegisterBase - Unused. Return Value: The function value is a pointer to the allocate adapter object. --*/ { PADAPTER_OBJECT AdapterObject; ULONG Size; ULONG Mode; // // Determine the size of the adapter. // Size = sizeof( ADAPTER_OBJECT ); // // Now create the adapter object. // AdapterObject = FwAllocatePool(Size); // // If the adapter object was successfully created, then attempt to insert // it into the the object table. // if (AdapterObject) { // // Initialize the adapter object itself. // AdapterObject->Type = IO_TYPE_ADAPTER; AdapterObject->Size = Size; AdapterObject->MapRegistersPerChannel = DMA_TRANSLATION_LIMIT / sizeof( TRANSLATION_ENTRY) -10; AdapterObject->AdapterBaseVa = AdapterBaseVa; AdapterObject->PagePort = NULL; AdapterObject->AdapterInUse = FALSE; // // Read the map register base from the Dma registers // The last 10 pages are used to map NonCachedExtension. // AdapterObject->MapRegisterBase = (PVOID)(READ_REGISTER_ULONG(&DMA_CONTROL->TranslationBase.Long) | KSEG1_BASE); #ifndef DUO // // Initialize the DMA mode registers for the Floppy, SCSI and Sound. // The initialization values come fomr the Jazz System Specification. // Mode = 0; ((PDMA_CHANNEL_MODE) &Mode)->AccessTime = ACCESS_80NS; ((PDMA_CHANNEL_MODE) &Mode)->TransferWidth = WIDTH_16BITS; ((PDMA_CHANNEL_MODE) &Mode)->InterruptEnable = 0; WRITE_REGISTER_ULONG( &DMA_CONTROL->Channel[SCSI_CHANNEL].Mode.Long, (ULONG) Mode ); ((PDMA_CHANNEL_MODE) &Mode)->AccessTime = ACCESS_120NS; ((PDMA_CHANNEL_MODE) &Mode)->TransferWidth = WIDTH_8BITS; ((PDMA_CHANNEL_MODE) &Mode)->InterruptEnable = 0; WRITE_REGISTER_ULONG( &DMA_CONTROL->Channel[FLOPPY_CHANNEL].Mode.Long, (ULONG) Mode ); #endif } else { // // An error was incurred for some reason. Set the return value // to NULL. // return(NULL); } return AdapterObject; } VOID IopAllocateCommonBuffer( IN PVOID NonCachedExtension, IN ULONG NonCachedExtensionSize, OUT PPHYSICAL_ADDRESS LogicalAddress ) /*++ Routine Description: This routine sets the mapping in the IO translation table to map the non cached memory (KSEG1) already allocated supplied by NonCachedExtension. It saves the IO logical address in DeviceExtension->PhysicalCommonBuffer so that SpGetPhysicalAddress can return this address. Arguments: NonCachedExtension NonCachedExtensionSize - Supplies the size of the non cached extension. LogicalAddress - Where the IO logical address is returned. Return Value: Returns STATUS_SUCCESS unless too many map registers are requested. Notes: Note that this routine MUST be invoked at DISPATCH_LEVEL or above. --*/ { PTRANSLATION_ENTRY DmaMapRegister; ULONG BasePage; ULONG NumberOfPages; // // If this is the first call. // Initialize FreeTranslationEntry to the last 10 pages of the Translation table // if (FreeTranslationEntry == NULL) { FreeTranslationEntry = READ_REGISTER_ULONG(&DMA_CONTROL->TranslationBase.Long); FreeTranslationEntry += DMA_TRANSLATION_LIMIT/sizeof(TRANSLATION_ENTRY) - 10; } // // Return the IO logical address of the common buffer // LogicalAddress->HighPart = 0; LogicalAddress->LowPart = (FreeTranslationEntry - (PTRANSLATION_ENTRY)(READ_REGISTER_ULONG(&DMA_CONTROL->TranslationBase.Long))) << PAGE_SHIFT; LogicalAddress->LowPart += BYTE_OFFSET(NonCachedExtension); DmaMapRegister =(PTRANSLATION_ENTRY)((ULONG)FreeTranslationEntry | KSEG1_BASE); BasePage = (ULONG)NonCachedExtension - KSEG1_BASE; NumberOfPages = ((BasePage & 0xFFF) + NonCachedExtensionSize + PAGE_SIZE - 1) >> PAGE_SHIFT; BasePage &= 0xFFFFF000; for (;NumberOfPages;NumberOfPages--) { // ScsiDebugPrint(2,"SpGetCommonBuffer Mapping %lx into %lx\n", BasePage,DmaMapRegister); DmaMapRegister->PageFrame = BasePage; BasePage += PAGE_SIZE; DmaMapRegister++; FreeTranslationEntry++; } } NTSTATUS IoAllocateAdapterChannel( IN PADAPTER_OBJECT AdapterObject, IN PDEVICE_OBJECT DeviceObject, IN ULONG NumberOfMapRegisters, IN PDRIVER_CONTROL ExecutionRoutine, IN PVOID Context ) /*++ Routine Description: This routine allocates the adapter channel specified by the adapter object. This is accomplished by placing the device object of the driver that wants to allocate the adapter on the adapter's queue. If the queue is already "busy", then the adapter has already been allocated, so the device object is simply placed onto the queue and waits until the adapter becomes free. Once the adapter becomes free (or if it already is), then the driver's execution routine is invoked. Also, a number of map registers may be allocated to the driver by specifying a non-zero value for NumberOfMapRegisters. Then the map register must be allocated from the master adapter. Once there are a sufficient number of map registers available, then the execution routine is called and the base address of the allocated map registers in the adapter is also passed to the driver's execution routine. Arguments: AdapterObject - Pointer to the adapter control object to allocate to the driver. DeviceObject - Pointer to the driver's device object that represents the device allocating the adapter. NumberOfMapRegisters - The number of map registers that are to be allocated from the channel, if any. ExecutionRoutine - The address of the driver's execution routine that is invoked once the adapter channel (and possibly map registers) have been allocated. Context - An untyped longword context parameter passed to the driver's execution routine. Return Value: Returns STATUS_SUCCESS unless too many map registers are requested. Notes: Note that this routine MUST be invoked at DISPATCH_LEVEL or above. --*/ { IO_ALLOCATION_ACTION action; // // Make sure the adapter if free. // if (AdapterObject->AdapterInUse) { DbgPrint("IoAllocateAdapterChannel: Called while adapter in use.\n"); } // // Make sure there are enough map registers. // if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) { DbgPrint("IoAllocateAdapterChannel: Out of map registers.\n"); return(STATUS_INSUFFICIENT_RESOURCES); } action = ExecutionRoutine( DeviceObject, DeviceObject->CurrentIrp, AdapterObject->MapRegisterBase, Context ); // // If the driver wishes to keep the map registers then // increment the current base and decrease the number of existing map // registers. // if (action == DeallocateObjectKeepRegisters) { AdapterObject->MapRegistersPerChannel -= NumberOfMapRegisters; (PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase += NumberOfMapRegisters; } else if (action == KeepObject) { AdapterObject->AdapterInUse = TRUE; } return(STATUS_SUCCESS); } VOID IoFreeMapRegisters( PADAPTER_OBJECT AdapterObject, PVOID MapRegisterBase, ULONG NumberOfMapRegisters ) /*++ Routine Description: This routine deallocates the map registers for the adapter. If there are any queued adapter waiting for an attempt is made to allocate the next entry. Arguments: AdapterObject - The adapter object to where the map register should be returned. MapRegisterBase - The map register base of the registers to be deallocated. NumberOfMapRegisters - The number of registers to be deallocated. Return Value: None --+*/ { PTRANSLATION_ENTRY translationEntry; // // Determine if this was the last allocation from the adapter. If is was // then free the map registers by restoring the map register base and the // channel count; otherwise the registers are lost. This handles the // normal case. // translationEntry = AdapterObject->MapRegisterBase; translationEntry -= NumberOfMapRegisters; if (translationEntry == MapRegisterBase) { // // The last allocated registers are being freed. // AdapterObject->MapRegisterBase = (PVOID) translationEntry; AdapterObject->MapRegistersPerChannel += NumberOfMapRegisters; } } VOID IoFreeAdapterChannel( IN PADAPTER_OBJECT AdapterObject ) /*++ Routine Description: This routine is invoked to deallocate the specified adapter object. Any map registers that were allocated are also automatically deallocated. No checks are made to ensure that the adapter is really allocated to a device object. However, if it is not, then kernel will bugcheck. If another device is waiting in the queue to allocate the adapter object it will be pulled from the queue and its execution routine will be invoked. Arguments: AdapterObject - Pointer to the adapter object to be deallocated. Return Value: None. --*/ { AdapterObject->AdapterInUse = FALSE; } PHYSICAL_ADDRESS IoMapTransfer( IN PADAPTER_OBJECT AdapterObject, IN PMDL Mdl, IN PVOID MapRegisterBase, IN PVOID CurrentVa, IN OUT PULONG Length, IN BOOLEAN WriteToDevice ) /*++ Routine Description: This routine is invoked to set up the map registers in the DMA controller to allow a transfer to or from a device. Arguments: AdapterObject - Pointer to the adapter object representing the DMA controller channel that has been allocated. Mdl - Pointer to the MDL that describes the pages of memory that are being read or written. MapRegisterBase - The address of the base map register that has been allocated to the device driver for use in mapping the transfer. CurrentVa - Current virtual address in the buffer described by the MDL that the transfer is being done to or from. Length - Supplies the length of the transfer. This determines the number of map registers that need to be written to map the transfer. Returns the length of the transfer which was actually mapped. WriteToDevice - Boolean value that indicates whether this is a write to the device from memory (TRUE), or vice versa. Return Value: Returns the logical address to be used by bus masters. --*/ { PTRANSLATION_ENTRY DmaMapRegister = MapRegisterBase; PULONG PageFrameNumber; ULONG NumberOfPages; PHYSICAL_ADDRESS Offset; ULONG i; // // Begin by determining where in the buffer this portion of the operation // is taking place. // Offset.LowPart = BYTE_OFFSET( (PCHAR) CurrentVa - (PCHAR) Mdl->StartVa ); Offset.HighPart = 0; PageFrameNumber = (PULONG) (Mdl + 1); NumberOfPages = (Offset.LowPart + *Length + PAGE_SIZE - 1) >> PAGE_SHIFT; PageFrameNumber += (((PCHAR) CurrentVa - (PCHAR) Mdl->StartVa) >> PAGE_SHIFT); for (i = 0; i < NumberOfPages; i++) { (DmaMapRegister++)->PageFrame = (ULONG) *PageFrameNumber++ << PAGE_SHIFT; } // // Set the offset to point to the map register plus the offset. // Offset.LowPart += ((PTRANSLATION_ENTRY) MapRegisterBase - (PTRANSLATION_ENTRY) (READ_REGISTER_ULONG(&DMA_CONTROL->TranslationBase.Long) | KSEG1_BASE) << PAGE_SHIFT); // // Invalidate the translation entry. // WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationInvalidate.Long, 1); if ( AdapterObject == NULL) { return(Offset); } if (AdapterObject->PagePort == NULL) { // // Set the local DMA Registers. // WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationInvalidate.Long, 1); WRITE_REGISTER_ULONG(&((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Address.Long, Offset.LowPart); WRITE_REGISTER_ULONG(&((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->ByteCount.Long, *Length); i = 0; ((PDMA_CHANNEL_ENABLE) &i)->ChannelEnable = 1; ((PDMA_CHANNEL_ENABLE) &i)->TransferDirection = WriteToDevice ? DMA_WRITE_OP : DMA_READ_OP; WRITE_REGISTER_ULONG(&((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long, i); } return(Offset); } BOOLEAN IoFlushAdapterBuffers( IN PADAPTER_OBJECT AdapterObject, IN PMDL Mdl, IN PVOID MapRegisterBase, IN PVOID CurrentVa, IN ULONG Length, IN BOOLEAN WriteToDevice ) /*++ Routine Description: This routine flushes the DMA adpater object buffers. For the Jazz system its clears the enable flag which aborts the dma. Arguments: AdapterObject - Pointer to the adapter object representing the DMA controller channel. Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down buffer to/from which the I/O occured. MapRegisterBase - A pointer to the base of the map registers in the adapter or DMA controller. CurrentVa - The current virtual address in the buffer described the the Mdl where the I/O operation occurred. Length - Supplies the length of the transfer. WriteToDevice - Supplies a BOOLEAN value that indicates the direction of the data transfer was to the device. Return Value: TRUE - If the transfer was successful. FALSE - If there was an error in the transfer. --*/ { ULONG i; UCHAR DataByte; if (AdapterObject == NULL) { return TRUE; } if (AdapterObject->PagePort) { // // If this is a master channel, then just return since the DMA // request does not need to be disabled. // DataByte = AdapterObject->AdapterMode; if (((PDMA_EISA_MODE) &DataByte)->RequestMode == CASCADE_REQUEST_MODE) { return(TRUE); } // // Clear the EISA DMA adapter. // if (AdapterObject->AdapterNumber == 1) { // // This request is for DMA controller 1 // PDMA1_CONTROL dmaControl; dmaControl = AdapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) ); } else { // // This request is for DMA controller 2 // PDMA2_CONTROL dmaControl; dmaControl = AdapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) ); } } else { // // Clear on board DMA this must be done, because writes to the // direction bit are disabled while the channel is enabled. // i = READ_REGISTER_ULONG( &((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long ); ((PDMA_CHANNEL_ENABLE) &i)->ChannelEnable = 0; WRITE_REGISTER_ULONG( &((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long, i ); } return(TRUE); } PHYSICAL_ADDRESS MmGetPhysicalAddress ( IN PVOID BaseAddress ) /*++ Routine Description: This function returns the corresponding physical address for a valid virtual address. Arguments: BaseAddress - Supplies the virtual address for which to return the physical address. Return Value: Returns the corresponding physical address. Environment: Kernel mode. Any IRQL level. --*/ { PHYSICAL_ADDRESS PhysicalAddress; PhysicalAddress.HighPart = 0; PhysicalAddress.LowPart = (ULONG)BaseAddress & 0x1fffffff; return(PhysicalAddress); } PVOID MmAllocateNonCachedMemory ( IN ULONG NumberOfBytes ) /*++ Routine Description: This function allocates a range of noncached memory in the non-paged portion of the system address space. This routine is designed to be used by a driver's initialization routine to allocate a noncached block of virtual memory for various device specific buffers. Arguments: NumberOfBytes - Supplies the number of bytes to allocate. Return Value: NULL - the specified request could not be satisfied. NON-NULL - Returns a pointer (virtual address in the nonpaged portion of the system) to the allocated physically contiguous memory. Environment: Kernel mode, IRQL of APC_LEVEL or below. --*/ { PVOID BaseAddress; // // Allocated the memory. // BaseAddress = FwAllocatePool(NumberOfBytes); // // Make it non-cached. // BaseAddress = (PVOID)((ULONG) BaseAddress | KSEG1_BASE); return BaseAddress; } PVOID MmMapIoSpace ( IN PHYSICAL_ADDRESS PhysicalAddress, IN ULONG NumberOfBytes, IN BOOLEAN CacheEnable ) /*++ Routine Description: This function returns the corresponding virtual address for a known physical address. Arguments: PhysicalAddress - Supplies the phiscal address. NumberOfBytes - Unused. CacheEnable - Unused. Return Value: Returns the corresponding virtual address. Environment: Kernel mode. Any IRQL level. --*/ { PCCHAR VirtualAddress; switch ((ULONG) PAGE_ALIGN(PhysicalAddress.LowPart)) { #ifndef DUO case SCSI_PHYSICAL_BASE: VirtualAddress = (PVOID) SCSI_VIRTUAL_BASE; break; #else case SCSI1_PHYSICAL_BASE: VirtualAddress = (PVOID) SCSI1_VIRTUAL_BASE; break; case SCSI2_PHYSICAL_BASE: VirtualAddress = (PVOID) SCSI2_VIRTUAL_BASE; break; #endif case EISA_CONTROL_PHYSICAL_BASE: VirtualAddress = (PVOID) EISA_IO_VIRTUAL_BASE; break; case DMA_PHYSICAL_BASE: VirtualAddress = (PVOID) DMA_VIRTUAL_BASE; break; default: if (PhysicalAddress.LowPart >= EISA_MEMORY_PHYSICAL_BASE) { VirtualAddress = (PVOID) EISA_MEMORY_VIRTUAL_BASE; VirtualAddress += PhysicalAddress.LowPart&0xFFFFFF; return(VirtualAddress); } return(NULL); } VirtualAddress += BYTE_OFFSET(PhysicalAddress.LowPart); return(VirtualAddress); } PADAPTER_OBJECT IopAllocateEisaAdapter( IN PDEVICE_DESCRIPTION DeviceDescriptor ) /*++ Routine Description: This function allocates an EISA 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. Return Value: Returns a pointer to the newly created adapter object or NULL if one cannot be created. --*/ { PADAPTER_OBJECT adapterObject; PVOID adapterBaseVa; ULONG channelNumber; ULONG controllerNumber; DMA_EXTENDED_MODE extendedMode; UCHAR adapterMode; // // Determine if the the channel number is important. Master cards on // Eisa do not use a channel number. // // // Handle Isa master // Channel 4 cannot be used since it is used for chaining. Return null if // it is requested. // if ((DeviceDescriptor->InterfaceType != Isa) || (DeviceDescriptor->DmaChannel == 4) || (DeviceDescriptor->DmaChannel > 7)) { return(NULL); } // // 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)EISA_IO_VIRTUAL_BASE)->Dma1BasePort; } else { controllerNumber = 2; adapterBaseVa = &((PEISA_CONTROL)EISA_IO_VIRTUAL_BASE)->Dma2BasePort; } // // Determine if a new adapter object is necessary. If so then allocate it. // if (HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) { adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel]; } else { // // Allocate an adapter object. // adapterObject = (PADAPTER_OBJECT) IopAllocateAdapter( 0, adapterBaseVa, NULL ); if (adapterObject == NULL) { return(NULL); } HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject; } // // Setup the pointers to all the random registers. // adapterObject->ChannelNumber = channelNumber; if (controllerNumber == 1) { switch ((UCHAR)channelNumber) { case 0: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel0; break; case 1: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel1; break; case 2: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel2; break; case 3: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel3; break; } // // Set the adapter number. // adapterObject->AdapterNumber = 1; // // Save the extended mode register address. // adapterBaseVa = &((PEISA_CONTROL) EISA_IO_VIRTUAL_BASE)->Dma1ExtendedModePort; } else { switch (channelNumber) { case 1: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel5; break; case 2: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel6; break; case 3: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel7; break; } // // Set the adapter number. // adapterObject->AdapterNumber = 2; // // Save the extended mode register address. // adapterBaseVa = &((PEISA_CONTROL) EISA_IO_VIRTUAL_BASE)->Dma2ExtendedModePort; } // // Initialzie the extended mode port. // *((PUCHAR) &extendedMode) = 0; extendedMode.ChannelNumber = 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: return(NULL); } switch (DeviceDescriptor->DmaWidth) { case Width8Bits: extendedMode.TransferSize = BY_BYTE_8_BITS; break; case Width16Bits: extendedMode.TransferSize = BY_BYTE_16_BITS; break; case Width32Bits: extendedMode.TransferSize = BY_BYTE_32_BITS; break; default: return(NULL); } ScsiDebugPrint(1,"Isp 1 initialize reg %lx with %lx\r\n",adapterBaseVa, *((PUCHAR)&extendedMode)); 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; ScsiDebugPrint(1,"Isp 2 initialize reg %lx with %lx\r\n",&dmaControl->Mode, adapterMode); WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); // // Unmask the DMA channel. // ScsiDebugPrint(1,"Isp 3 initialize reg %lx with %lx\r\n",&dmaControl->SingleMask,(UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)); WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) ); } else { // // This request is for DMA controller 1 // PDMA2_CONTROL dmaControl; dmaControl = adapterObject->AdapterBaseVa; ScsiDebugPrint(1,"Isp 2 initialize reg %lx with %lx\r\n",&dmaControl->Mode, adapterMode); WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); // // Unmask the DMA channel. // ScsiDebugPrint(1,"Isp 3 initialize reg %lx with %lx\r\n",&dmaControl->SingleMask,(UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)); 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; adapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY)adapterObject->MapRegisterBase + (0x100000>>PAGE_SHIFT)); return(adapterObject); } #endif