update for HEAD-2003091401
[reactos.git] / hal / halx86 / adapter.c
1 /* $Id$
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