diff --git a/reactos/hal/halx86/adapter.c b/reactos/hal/halx86/adapter.c index 581d1e240a9..9bd90e48e4f 100644 --- a/reactos/hal/halx86/adapter.c +++ b/reactos/hal/halx86/adapter.c @@ -1,4 +1,4 @@ -/* $Id: adapter.c,v 1.10 2003/12/31 05:33:03 jfilby Exp $ +/* $Id: adapter.c,v 1.11 2004/07/22 18:49:18 navaraf Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -66,7 +66,7 @@ HalAllocateAdapterChannel( WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters; /* returns true if queued, else returns false and sets the queue to busy */ - if(KeInsertDeviceQueue(&AdapterObject->DeviceQueue, (PKDEVICE_QUEUE_ENTRY)WaitContextBlock)) + if(KeInsertDeviceQueue(&AdapterObject->DeviceQueue, &WaitContextBlock->WaitQueueEntry)) return STATUS_SUCCESS; /* 24-bit max address due to 16-bit dma controllers */ @@ -79,6 +79,10 @@ HalAllocateAdapterChannel( * X86 lacks map registers, so for now, we allocate a contiguous * block of physical memory <16MB and copy all DMA buffers into * that. This can be optimized. + * + * FIXME: We propably shouldn't allocate the memory here for common + * buffer transfers. See a comment in IoMapTransfer about common buffer + * support. */ AdapterObject->MapRegisterBase = MmAllocateContiguousAlignedMemory( NumberOfMapRegisters * PAGE_SIZE, @@ -159,6 +163,12 @@ IoFlushAdapterBuffers ( if(!MapRegisterBase) return TRUE; + /* mask out (disable) the dma channel */ + if (AdapterObject->Channel < 4) + WRITE_PORT_UCHAR( (PVOID)0x0A, (UCHAR)(AdapterObject->Channel | 0x4) ); + else + WRITE_PORT_UCHAR( (PVOID)0xD4, (UCHAR)((AdapterObject->Channel - 4) | 0x4) ); + if(WriteToDevice) return TRUE; @@ -166,19 +176,6 @@ IoFlushAdapterBuffers ( (PVOID)((DWORD)MmGetSystemAddressForMdl( Mdl ) + (DWORD)CurrentVa - (DWORD)MmGetMdlVirtualAddress( Mdl )), MapRegisterBase, Length ); - /* - FIXME: mask off (disable) channel if doing System DMA? - - From linux: - - if (dmanr<=3) - dma_outb(dmanr | 4, DMA1_MASK_REG 0x0A) ; - else - dma_outb((dmanr & 3) | 4, DMA2_MASK_REG 0x0A); - - */ - - return TRUE; } @@ -304,14 +301,18 @@ IoMapTransfer ( * - If the controller supports scatter/gather, the copyover should not happen */ { - PHYSICAL_ADDRESS Address; + PHYSICAL_ADDRESS Address; + PVOID MaskReg, ClearReg, ModeReg; + UCHAR ModeMask, LengthShift; + KIRQL OldIrql; + #if defined(__GNUC__) - Address.QuadPart = 0ULL; + Address.QuadPart = 0ULL; #else - Address.QuadPart = 0; + Address.QuadPart = 0; #endif - /* Isa System (slave) DMA? */ + /* Isa System (slave) DMA? */ if (AdapterObject && AdapterObject->InterfaceType == Isa && !AdapterObject->Master) { #if 0 @@ -321,38 +322,76 @@ IoMapTransfer ( assert(AdapterObject->Channel != 4); #endif + KeAcquireSpinLock(&AdapterObject->SpinLock, &OldIrql); + /* - FIXME: Handle case when doing common-buffer System DMA. In this case, the buffer described - by MDL is allready phys. contiguous and below 16 mega. Driver makes a one-shot call to - IoMapTransfer during init. to program controller with the common-buffer. - */ - + * FIXME: Handle case when doing common-buffer System DMA. In this case, + * the buffer described by MDL is already phys. contiguous and below + * 16 mega. Driver makes a one-shot call to IoMapTransfer during init. + * to program controller with the common-buffer. + * + * UPDATE: Common buffer support is in place, but it's not done in a + * clean way. We use the buffer passed by the MDL in case that the + * adapter object is marked as auto initialize. I'm not sure if this + * is correct and if not, how to do it properly. Note that it's also + * possible to allocate the common buffer with different adapter object + * and IoMapTransfer must still work in this case. Eventually this should + * be cleaned up somehow or at least this comment modified to reflect + * the reality. + * -- Filip Navara, 19/07/2004 + */ + /* if it is a write to the device, copy the caller buffer to the low buffer */ - if( WriteToDevice ) + if( WriteToDevice && !AdapterObject->AutoInitialize ) { memcpy(MapRegisterBase, (char*)MmGetSystemAddressForMdl(Mdl) + ((ULONG)CurrentVa - (ULONG)MmGetMdlVirtualAddress(Mdl)), *Length ); } + // 16-bit DMA + if( AdapterObject->Channel >= 4 ) + { + MaskReg = (PVOID)0xD4; ClearReg = (PVOID)0xD8; ModeReg = (PVOID)0xD6; + LengthShift = 1; + } + else + { + MaskReg = (PVOID)0x0A; ClearReg = (PVOID)0x0C; ModeReg = (PVOID)0x0B; + LengthShift = 0; + } + + // calculate the mask we will later set to the mode register + ModeMask = (AdapterObject->Channel & 3) | ( WriteToDevice ? 0x8 : 0x4 ); + // FIXME: if not demand mode, which mode to use? 0x40 for single mode + if (!AdapterObject->DemandMode) + ModeMask |= 0x40; + if (AdapterObject->AutoInitialize) + ModeMask |= 0x10; + // program up the dma controller, and return - Address = MmGetPhysicalAddress( MapRegisterBase ); - // port 0xA is the dma mask register, or a 0x10 on to the channel number to mask it - WRITE_PORT_UCHAR( (PVOID)0x0A, (UCHAR)(AdapterObject->Channel | 0x10)); + if (!AdapterObject->AutoInitialize) + Address = MmGetPhysicalAddress( MapRegisterBase ); + else + Address = MmGetPhysicalAddress( CurrentVa ); + // disable and select the channel number + WRITE_PORT_UCHAR( MaskReg, (UCHAR)((AdapterObject->Channel & 3) | 0x4) ); // write zero to the reset register - WRITE_PORT_UCHAR( (PVOID)0x0C, 0 ); - // mode register, or channel with 0x4 for write memory, 0x8 for read memory, 0x10 for non auto initialize - WRITE_PORT_UCHAR( (PVOID)0x0B, (UCHAR)(AdapterObject->Channel | ( WriteToDevice ? 0x8 : 0x4 )) ); + WRITE_PORT_UCHAR( ClearReg, 0 ); + // mode register, or channel with 0x4 for write memory, 0x8 for read memory, 0x10 for auto initialize + WRITE_PORT_UCHAR( ModeReg, ModeMask); // set the 64k page register for the channel - WRITE_PORT_UCHAR( AdapterObject->PagePort, (UCHAR)(((ULONG)Address.QuadPart)>>16) ); + WRITE_PORT_UCHAR( AdapterObject->PagePort, (UCHAR)(Address.u.LowPart >> 16) ); // low, then high address byte, which is always 0 for us, because we have a 64k alligned address WRITE_PORT_UCHAR( AdapterObject->OffsetPort, 0 ); WRITE_PORT_UCHAR( AdapterObject->OffsetPort, 0 ); // count is 1 less than length, low then high - WRITE_PORT_UCHAR( AdapterObject->CountPort, (UCHAR)(*Length - 1) ); - WRITE_PORT_UCHAR( AdapterObject->CountPort, (UCHAR)((*Length - 1)>>8) ); + WRITE_PORT_UCHAR( AdapterObject->CountPort, (UCHAR)((*Length >> LengthShift) - 1) ); + WRITE_PORT_UCHAR( AdapterObject->CountPort, (UCHAR)(((*Length >> LengthShift) - 1)>>8) ); // unmask the channel to let it rip - WRITE_PORT_UCHAR( (PVOID)0x0A, (UCHAR)AdapterObject->Channel ); + WRITE_PORT_UCHAR( MaskReg, AdapterObject->Channel & 3 ); + + KeReleaseSpinLock(&AdapterObject->SpinLock, OldIrql); /* NOTE: Return value should be ignored when doing System DMA. @@ -436,7 +475,7 @@ IoMapTransfer ( return MmGetPhysicalAddress(MapRegisterBase); } - + DPRINT1("IoMapTransfer: Unsupported operation\n"); KEBUGCHECK(0); return Address; diff --git a/reactos/hal/halx86/dma.c b/reactos/hal/halx86/dma.c index 87ae7e64a96..652cf1d0e63 100644 --- a/reactos/hal/halx86/dma.c +++ b/reactos/hal/halx86/dma.c @@ -1,4 +1,4 @@ -/* $Id: dma.c,v 1.8 2003/10/23 09:03:51 vizzini Exp $ +/* $Id: dma.c,v 1.9 2004/07/22 18:49:18 navaraf Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -18,21 +18,38 @@ /* XXX This initialization is out of date - ADAPTER_OBJECT has changed */ /* NOTE: The following initializations have to be kept in synch with ADAPTER_OBJECT in hal.h */ -/* FIXME: we need the 16-bit dma channels */ ADAPTER_OBJECT IsaSlaveAdapterObjects[] = { { Isa, FALSE, 0, (PVOID)0x87, (PVOID)0x1, (PVOID)0x0, 0, NULL }, { Isa, FALSE, 1, (PVOID)0x83, (PVOID)0x3, (PVOID)0x2, 0, NULL }, { Isa, FALSE, 2, (PVOID)0x81, (PVOID)0x5, (PVOID)0x4, 0, NULL }, - { Isa, FALSE, 3, (PVOID)0x82, (PVOID)0x7, (PVOID)0x6, 0, NULL } }; + { Isa, FALSE, 3, (PVOID)0x82, (PVOID)0x7, (PVOID)0x6, 0, NULL }, + /* 16-bit DMA */ + { Isa, FALSE, 4, (PVOID)0x8F, (PVOID)0xC2, (PVOID)0xC0, 0, NULL }, + { Isa, FALSE, 5, (PVOID)0x8B, (PVOID)0xC6, (PVOID)0xC4, 0, NULL }, + { Isa, FALSE, 6, (PVOID)0x89, (PVOID)0xCA, (PVOID)0xC8, 0, NULL }, + { Isa, FALSE, 7, (PVOID)0x8A, (PVOID)0xCE, (PVOID)0xCC, 0, NULL } }; ADAPTER_OBJECT PciBusMasterAdapterObjects[] = { { PCIBus, TRUE, 0, (PVOID)0, (PVOID)0, (PVOID)0x0, 0, NULL } }; -/* Global flag to tell whether or not the adapter's device queue should be initialized (first call only) */ -BOOLEAN AdaptersInitialized = FALSE; - /* FUNCTIONS *****************************************************************/ +VOID +HalpInitDma (VOID) +{ + ULONG Index; + + KeInitializeDeviceQueue(&PciBusMasterAdapterObjects[0].DeviceQueue); + KeInitializeSpinLock(&PciBusMasterAdapterObjects[0].SpinLock); + PciBusMasterAdapterObjects[0].Inuse = FALSE; + for (Index = 0; Index < 8; Index++) + { + KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[Index].DeviceQueue); + KeInitializeSpinLock(&IsaSlaveAdapterObjects[Index].SpinLock); + IsaSlaveAdapterObjects[Index].Inuse = FALSE; + } +} + PVOID STDCALL HalAllocateCommonBuffer (PADAPTER_OBJECT AdapterObject, ULONG Length, @@ -52,11 +69,15 @@ HalAllocateCommonBuffer (PADAPTER_OBJECT AdapterObject, * NULL on failure * NOTES: * CacheEnabled is ignored - it's all cache-disabled (like in NT) + * UPDATE: It's not ignored now. If that's wrong just modify the + * CacheEnabled comparsion below. */ { - PHYSICAL_ADDRESS HighestAddress; + PHYSICAL_ADDRESS LowestAddress, HighestAddress, BoundryAddressMultiple; PVOID BaseAddress; + LowestAddress.QuadPart = 0; + BoundryAddressMultiple.QuadPart = 0; HighestAddress.u.HighPart = 0; if (AdapterObject->InterfaceType == Isa || (AdapterObject->InterfaceType == MicroChannel && AdapterObject->Master == FALSE)) @@ -68,7 +89,13 @@ HalAllocateCommonBuffer (PADAPTER_OBJECT AdapterObject, HighestAddress.u.LowPart = 0xFFFFFFFF; /* 32Bit: 4GB address range */ } - BaseAddress = MmAllocateContiguousMemory(Length, HighestAddress); + BaseAddress = MmAllocateContiguousAlignedMemory( + Length, + LowestAddress, + HighestAddress, + BoundryAddressMultiple, + CacheEnabled ? MmCached : MmNonCached, + 0x10000 ); if (!BaseAddress) return 0; @@ -114,56 +141,80 @@ HalGetAdapter (PDEVICE_DESCRIPTION DeviceDescription, * RETURNS: The allocated adapter object on success * NULL on failure * TODO: - * Figure out what to do with the commented-out cases + * Honour all the fields in DeviceDescription structure. */ { - /* TODO: find a better home for this */ - if(!AdaptersInitialized) - { - KeInitializeDeviceQueue(&PciBusMasterAdapterObjects[0].DeviceQueue); - KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[0].DeviceQueue); - KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[1].DeviceQueue); - KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[2].DeviceQueue); - KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[3].DeviceQueue); - AdaptersInitialized = TRUE; - } + PADAPTER_OBJECT AdapterObject; /* Validate parameters in device description, and return a pointer to the adapter object for the requested dma channel */ if( DeviceDescription->Version != DEVICE_DESCRIPTION_VERSION ) return NULL; - if (DeviceDescription->InterfaceType == PCIBus) + switch (DeviceDescription->InterfaceType) { - if (DeviceDescription->Master == FALSE) - return NULL; + case PCIBus: + if (DeviceDescription->Master == FALSE) + return NULL; + return &PciBusMasterAdapterObjects[0]; - return &PciBusMasterAdapterObjects[0]; + case Isa: + /* There are only 8 DMA channels on ISA. */ + if (DeviceDescription->DmaChannel >= 8) + return NULL; + /* Channels 1-4 are for 8-bit transfers... */ + if (DeviceDescription->DmaWidth != Width8Bits && + DeviceDescription->DmaChannel < 4) + return NULL; + /* ...and the rest is for 16-bit transfers. */ + if (DeviceDescription->DmaWidth != Width16Bits && + DeviceDescription->DmaChannel >= 4) + return NULL; + AdapterObject = &IsaSlaveAdapterObjects[DeviceDescription->DmaChannel]; + AdapterObject->Master = DeviceDescription->Master; + AdapterObject->ScatterGather = DeviceDescription->ScatterGather; + AdapterObject->AutoInitialize = DeviceDescription->AutoInitialize; + AdapterObject->DemandMode = DeviceDescription->DemandMode; + AdapterObject->Buffer = 0; + /* FIXME: Is this correct? */ + *NumberOfMapRegisters = 16; + return AdapterObject; + + default: + /* Unsupported bus. */ + return NULL; } - - /* - if( DeviceDescription->Master ) - return NULL; - if( DeviceDescription->ScatterGather ) - return NULL; - if( DeviceDescription->AutoInitialize ) - return NULL; - if( DeviceDescription->Dma32BitAddresses ) - return NULL; - if( DeviceDescription->InterfaceType != Isa ) - return NULL; - */ - /* if( DeviceDescription->DmaWidth != Width8Bits ) - return NULL;*/ - *NumberOfMapRegisters = 0x10; - IsaSlaveAdapterObjects[DeviceDescription->DmaChannel].Buffer = 0; - return &IsaSlaveAdapterObjects[DeviceDescription->DmaChannel]; } ULONG STDCALL HalReadDmaCounter (PADAPTER_OBJECT AdapterObject) { - UNIMPLEMENTED; + KIRQL OldIrql; + ULONG Count; + + if (AdapterObject && AdapterObject->InterfaceType == Isa && !AdapterObject->Master) + { + KeAcquireSpinLock(&AdapterObject->SpinLock, &OldIrql); + + /* Clear the flip/flop register */ + WRITE_PORT_UCHAR( AdapterObject->Channel < 4 ? (PVOID)0x0C : (PVOID)0xD8, 0 ); + /* Read the offset */ + Count = READ_PORT_UCHAR( AdapterObject->CountPort ); + Count |= READ_PORT_UCHAR( AdapterObject->CountPort ) << 8; + + KeReleaseSpinLock(&AdapterObject->SpinLock, OldIrql); + + /* + * We must return twice the sound for channel >= 4 because it's the size + * of words (16-bit) and not bytes. + */ + if (AdapterObject->Channel < 4) + return Count; + else + return Count << 1; + } + + return 0; } /* EOF */ diff --git a/reactos/hal/halx86/halinit.c b/reactos/hal/halx86/halinit.c index 4d5936f030e..3318e616f09 100644 --- a/reactos/hal/halx86/halinit.c +++ b/reactos/hal/halx86/halinit.c @@ -1,4 +1,4 @@ -/* $Id: halinit.c,v 1.8 2004/05/15 22:45:51 hbirr Exp $ +/* $Id: halinit.c,v 1.9 2004/07/22 18:49:18 navaraf Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -63,6 +63,7 @@ HalInitSystem (ULONG BootPhase, else if (BootPhase == 1) { HalpInitBusHandlers(); + HalpInitDma(); HalpCalibrateStallExecution(); /* Enumerate the devices on the motherboard */ diff --git a/reactos/hal/halx86/include/hal.h b/reactos/hal/halx86/include/hal.h index f0c198fc244..4186002d28b 100644 --- a/reactos/hal/halx86/include/hal.h +++ b/reactos/hal/halx86/include/hal.h @@ -19,6 +19,7 @@ BOOLEAN Hal_bios32_is_service_present(ULONG service); VOID FASTCALL HalInitializeDisplay (PLOADER_PARAMETER_BLOCK LoaderBlock); VOID FASTCALL HalClearDisplay (UCHAR CharAttribute); +/* bus.c */ VOID HalpInitBusHandlers (VOID); /* irql.c */ @@ -33,6 +34,9 @@ VOID HalpInitPciBus (VOID); /* enum.c */ VOID HalpStartEnumerator (VOID); +/* dma.c */ +VOID HalpInitDma (VOID); + /* * ADAPTER_OBJECT - Track a busmaster DMA adapter and its associated resources * @@ -59,6 +63,15 @@ struct _ADAPTER_OBJECT { PWAIT_CONTEXT_BLOCK WaitContextBlock; KDEVICE_QUEUE DeviceQueue; BOOLEAN ScatterGather; + + /* + * 18/07/04: Added these members. It's propably not the exact place where + * this should be stored, but I can't find better one. I haven't checked + * how Windows handles this. + * -- Filip Navara + */ + BOOLEAN DemandMode; + BOOLEAN AutoInitialize; }; /* sysinfo.c */