2002-10-01 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / hal / halx86 / adapter.c
1 /* $Id: adapter.c,v 1.4 2002/10/01 19:27:18 chorns Exp $
2 *
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)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <ddk/iotypes.h>
16 #include <internal/debug.h>
17 #include <hal.h>
18
19 /* FUNCTIONS *****************************************************************/
20
21 /* NOTE: IoAllocateAdapterChannel in NTOSKRNL.EXE */
22
23 NTSTATUS STDCALL
24 HalAllocateAdapterChannel(PADAPTER_OBJECT AdapterObject,
25 PDEVICE_OBJECT DeviceObject,
26 ULONG NumberOfMapRegisters,
27 PDRIVER_CONTROL ExecutionRoutine,
28 PVOID Context )
29 {
30 KIRQL OldIrql;
31 PVOID Buffer;
32 int ret;
33 LARGE_INTEGER MaxAddress;
34
35 MaxAddress.QuadPart = 0x1000000;
36 Buffer = MmAllocateContiguousAlignedMemory( NumberOfMapRegisters * PAGE_SIZE,
37 MaxAddress,
38 0x10000 );
39 if( !Buffer )
40 return STATUS_INSUFFICIENT_RESOURCES;
41 KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
42 if( AdapterObject->Inuse )
43 {
44 // someone is already using it, we need to wait
45 // create a wait block, and add it to the chain
46 UNIMPLEMENTED;
47 }
48 else {
49 AdapterObject->Inuse = TRUE;
50 KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
51 ret = ExecutionRoutine( DeviceObject,
52 NULL,
53 Buffer,
54 Context );
55 KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
56 if( ret == DeallocateObject )
57 {
58 MmFreeContiguousMemory( Buffer );
59 AdapterObject->Inuse = FALSE;
60 }
61 else AdapterObject->Buffer = Buffer;
62 }
63 KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
64 return STATUS_SUCCESS;
65 }
66
67
68 BOOLEAN STDCALL
69 IoFlushAdapterBuffers (PADAPTER_OBJECT AdapterObject,
70 PMDL Mdl,
71 PVOID MapRegisterBase,
72 PVOID CurrentVa,
73 ULONG Length,
74 BOOLEAN WriteToDevice)
75 {
76 // if this was a read from device, copy data back to caller buffer, otherwise, do nothing
77 if( !WriteToDevice )
78 memcpy( (PVOID)((DWORD)MmGetSystemAddressForMdl( Mdl ) + (DWORD)CurrentVa - (DWORD)MmGetMdlVirtualAddress( Mdl )), MapRegisterBase, Length );
79 return TRUE;
80 }
81
82
83 VOID STDCALL
84 IoFreeAdapterChannel (PADAPTER_OBJECT AdapterObject)
85 {
86 KIRQL OldIrql;
87
88 KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
89 if( AdapterObject->Inuse == FALSE )
90 {
91 DbgPrint( "Attempting to IoFreeAdapterChannel on a channel not in use\n" );
92 KeBugCheck(0);
93 }
94 AdapterObject->Inuse = FALSE;
95 if( AdapterObject->Buffer )
96 {
97 MmFreeContiguousMemory( AdapterObject->Buffer );
98 AdapterObject->Buffer = 0;
99 }
100 KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
101 }
102
103
104 VOID STDCALL
105 IoFreeMapRegisters (PADAPTER_OBJECT AdapterObject,
106 PVOID MapRegisterBase,
107 ULONG NumberOfMapRegisters)
108 {
109 UNIMPLEMENTED;
110 }
111
112
113 PHYSICAL_ADDRESS STDCALL
114 IoMapTransfer (PADAPTER_OBJECT AdapterObject,
115 PMDL Mdl,
116 PVOID MapRegisterBase,
117 PVOID CurrentVa,
118 PULONG Length,
119 BOOLEAN WriteToDevice)
120 {
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
124 if( WriteToDevice )
125 memcpy( MapRegisterBase,
126 MmGetSystemAddressForMdl( Mdl ) + ( (DWORD)CurrentVa - (DWORD)MmGetMdlVirtualAddress( Mdl ) ),
127 *Length );
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;
146 return Address;
147 }
148
149
150 /* EOF */
151
152
153
154