3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: hal/x86/adapter.c (from ntoskrnl/io/adapter.c)
6 * PURPOSE: DMA handling
7 * PROGRAMMER: David Welch (welch@mcmail.com)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <ddk/iotypes.h>
16 #include <internal/debug.h>
19 /* FUNCTIONS *****************************************************************/
21 /* NOTE: IoAllocateAdapterChannel in NTOSKRNL.EXE */
24 HalAllocateAdapterChannel(PADAPTER_OBJECT AdapterObject,
25 PDEVICE_OBJECT DeviceObject,
26 ULONG NumberOfMapRegisters,
27 PDRIVER_CONTROL ExecutionRoutine,
33 LARGE_INTEGER MaxAddress;
35 MaxAddress.QuadPart = 0x1000000;
36 Buffer = MmAllocateContiguousAlignedMemory( NumberOfMapRegisters * PAGE_SIZE,
40 return STATUS_INSUFFICIENT_RESOURCES;
41 KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
42 if( AdapterObject->Inuse )
44 // someone is already using it, we need to wait
45 // create a wait block, and add it to the chain
49 AdapterObject->Inuse = TRUE;
50 KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
51 ret = ExecutionRoutine( DeviceObject,
55 KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
56 if( ret == DeallocateObject )
58 MmFreeContiguousMemory( Buffer );
59 AdapterObject->Inuse = FALSE;
61 else AdapterObject->Buffer = Buffer;
63 KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
64 return STATUS_SUCCESS;
69 IoFlushAdapterBuffers (PADAPTER_OBJECT AdapterObject,
71 PVOID MapRegisterBase,
74 BOOLEAN WriteToDevice)
76 // if this was a read from device, copy data back to caller buffer, otherwise, do nothing
78 memcpy( (PVOID)((DWORD)MmGetSystemAddressForMdl( Mdl ) + (DWORD)CurrentVa - (DWORD)MmGetMdlVirtualAddress( Mdl )), MapRegisterBase, Length );
84 IoFreeAdapterChannel (PADAPTER_OBJECT AdapterObject)
88 KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
89 if( AdapterObject->Inuse == FALSE )
91 DbgPrint( "Attempting to IoFreeAdapterChannel on a channel not in use\n" );
94 AdapterObject->Inuse = FALSE;
95 if( AdapterObject->Buffer )
97 MmFreeContiguousMemory( AdapterObject->Buffer );
98 AdapterObject->Buffer = 0;
100 KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
105 IoFreeMapRegisters (PADAPTER_OBJECT AdapterObject,
106 PVOID MapRegisterBase,
107 ULONG NumberOfMapRegisters)
113 PHYSICAL_ADDRESS STDCALL
114 IoMapTransfer (PADAPTER_OBJECT AdapterObject,
116 PVOID MapRegisterBase,
119 BOOLEAN WriteToDevice)
121 PHYSICAL_ADDRESS Address;
122 // program up the dma controller, and return
123 // if it is a write to the device, copy the caller buffer to the low buffer
125 memcpy( MapRegisterBase,
126 MmGetSystemAddressForMdl( Mdl ) + ( (DWORD)CurrentVa - (DWORD)MmGetMdlVirtualAddress( Mdl ) ),
128 Address = MmGetPhysicalAddress( MapRegisterBase );
129 // port 0xA is the dma mask register, or a 0x10 on to the channel number to mask it
130 WRITE_PORT_UCHAR( (PVOID)0x0A, AdapterObject->Channel | 0x10 );
131 // write zero to the reset register
132 WRITE_PORT_UCHAR( (PVOID)0x0C, 0 );
133 // mode register, or channel with 0x4 for write memory, 0x8 for read memory, 0x10 for non auto initialize
134 WRITE_PORT_UCHAR( (PVOID)0x0B, AdapterObject->Channel | ( WriteToDevice ? 0x8 : 0x4 ) );
135 // set the 64k page register for the channel
136 WRITE_PORT_UCHAR( AdapterObject->PagePort, (UCHAR)(((ULONG)Address.QuadPart)>>16) );
137 // low, then high address byte, which is always 0 for us, because we have a 64k alligned address
138 WRITE_PORT_UCHAR( AdapterObject->OffsetPort, 0 );
139 WRITE_PORT_UCHAR( AdapterObject->OffsetPort, 0 );
140 // count is 1 less than length, low then high
141 WRITE_PORT_UCHAR( AdapterObject->CountPort, (UCHAR)(*Length - 1) );
142 WRITE_PORT_UCHAR( AdapterObject->CountPort, (UCHAR)((*Length - 1)>>8) );
143 // unmask the channel to let it rip
144 WRITE_PORT_UCHAR( (PVOID)0x0A, AdapterObject->Channel );
145 Address.QuadPart = (DWORD)MapRegisterBase;