Allocate the map registers according to the dma controllers properties (boundary...
[reactos.git] / reactos / hal / halx86 / generic / 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 * PROGRAMMERS: David Welch (welch@mcmail.com)
8 * Vizzini (vizzini@plasmic.com)
9 * UPDATE HISTORY:
10 * Created 22/05/98
11 * 18-Oct-2003 Vizzini DMA support modifications
12 */
13
14 /* INCLUDES *****************************************************************/
15
16 #include <hal.h>
17 #define NDEBUG
18 #include <debug.h>
19
20 /* FUNCTIONS *****************************************************************/
21
22 /* NOTE: IoAllocateAdapterChannel in NTOSKRNL.EXE */
23
24 \f
25 NTSTATUS STDCALL
26 HalAllocateAdapterChannel(
27 PADAPTER_OBJECT AdapterObject,
28 PWAIT_CONTEXT_BLOCK WaitContextBlock,
29 ULONG NumberOfMapRegisters,
30 PDRIVER_CONTROL ExecutionRoutine)
31 /*
32 * FUNCTION: Sets up an ADAPTER_OBJECT with map registers
33 * ARGUMENTS:
34 * - AdapterObject: pointer to an ADAPTER_OBJECT to set up
35 * - WaitContextBlock: Context block to be used with ExecutionRoutine
36 * - NumberOfMapRegisters: number of map registers requested
37 * - ExecutionRoutine: callback to call when map registers are allocated
38 * RETURNS:
39 * STATUS_INSUFFICIENT_RESOURCES if map registers cannot be allocated
40 * STATUS_SUCCESS in all other cases, including if the callbacak had
41 * to be queued for later delivery
42 * NOTES:
43 * - the ADAPTER_OBJECT struct is undocumented; please make copious
44 * notes in hal.h if anything is changed or improved since there is
45 * no other documentation for this data structure
46 * BUGS:
47 * - it's possible that some of this code is in the wrong place
48 * - there are many unhandled cases
49 */
50 {
51 LARGE_INTEGER MinAddress;
52 LARGE_INTEGER MaxAddress;
53 LARGE_INTEGER BoundryAddressMultiple;
54 IO_ALLOCATION_ACTION Retval;
55
56 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
57
58 /*
59 FIXME: return STATUS_INSUFFICIENT_RESOURCES if the NumberOfMapRegisters
60 requested is larger than the value returned by IoGetDmaAdapter.
61 */
62
63 /* set up the wait context block in case we can't run right away */
64 WaitContextBlock->DeviceRoutine = ExecutionRoutine;
65 WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters;
66
67 /* returns true if queued, else returns false and sets the queue to busy */
68 if(KeInsertDeviceQueue(&AdapterObject->ChannelWaitQueue, &WaitContextBlock->WaitQueueEntry))
69 return STATUS_SUCCESS;
70
71 /* why 64K alignment? */
72 /*
73 * X86 lacks map registers, so for now, we allocate a contiguous
74 * block of physical memory <16MB and copy all DMA buffers into
75 * that. This can be optimized.
76 *
77 * FIXME: We propably shouldn't allocate the memory here for common
78 * buffer transfers. See a comment in IoMapTransfer about common buffer
79 * support.
80 */
81
82 MinAddress.QuadPart = 0;
83 BoundryAddressMultiple.QuadPart = 0;
84 if ((AdapterObject->Dma64BitAddresses) && (AdapterObject->MasterDevice))
85 {
86 MaxAddress.QuadPart = 0xFFFFFFFFFFFFFFFFLL; /* 64Bit: >4GB address range */
87 }
88 else if ((AdapterObject->Dma32BitAddresses) && (AdapterObject->MasterDevice))
89 {
90 MaxAddress.QuadPart = 0xFFFFFFFF; /* 32Bit: 4GB address range */
91 }
92 else
93 {
94 MaxAddress.QuadPart = 0x00FFFFFF; /* 24Bit: 16MB address range */
95 if (AdapterObject->Width16Bits)
96 {
97 BoundryAddressMultiple.QuadPart = 0x20000; /* 128k boundary */
98 }
99 else
100 {
101 BoundryAddressMultiple.QuadPart = 0x10000; /* 64k boundary */
102 }
103 }
104 AdapterObject->MapRegisterBase = MmAllocateContiguousMemorySpecifyCache(
105 NumberOfMapRegisters * PAGE_SIZE,
106 MinAddress,
107 MaxAddress,
108 BoundryAddressMultiple,
109 MmCached);
110
111 if(!AdapterObject->MapRegisterBase)
112 return STATUS_INSUFFICIENT_RESOURCES;
113
114 AdapterObject->CommittedMapRegisters = NumberOfMapRegisters;
115
116 /* call the client's AdapterControl callback with its map registers and context */
117 Retval = ExecutionRoutine(WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp,
118 AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext);
119
120 /*
121 * KeepObject: don't free any resources; the ADAPTER_OBJECT is still in use
122 * and the caller will call IoFreeAdapterChannel later
123 *
124 * DeallocateObject: Deallocate the map registers and release the ADAPTER_OBJECT
125 * so someone else can use it
126 *
127 * DeallocateObjectKeepRegisters: release the ADAPTER_OBJECT but hang on to
128 * the map registers. The client will later call IoFreeMapRegisters.
129 *
130 * NOTE - IoFreeAdapterChannel runs the queue, so it must be called
131 * unless the adapter object is not to be freed.
132 */
133 if( Retval == DeallocateObject )
134 IoFreeAdapterChannel(AdapterObject);
135 else if(Retval == DeallocateObjectKeepRegisters)
136 {
137 /* don't free the allocated map registers - this is what IoFreeAdapterChannel checks */
138 AdapterObject->CommittedMapRegisters = 0;
139 IoFreeAdapterChannel(AdapterObject);
140 }
141
142 /*
143 * if we don't call IoFreeAdapterChannel, the next device won't get de-queued,
144 * which is what we want.
145 */
146
147 return STATUS_SUCCESS;
148 }
149
150
151 BOOLEAN
152 HalpGrowMapBuffers(
153 IN PADAPTER_OBJECT AdapterObject,
154 IN ULONG SizeOfMapBuffers)
155 /*
156 * FUNCTION: Allocate initial, or additional, map buffers for IO adapters.
157 * ARGUMENTS:
158 * AdapterObject: DMA adapter to allocate buffers for.
159 * SizeOfMapBuffers: Size of the map buffers to allocate
160 * NOTES:
161 * - Needs to be tested...
162 */
163 {
164 //ULONG PagesToAllocate = BYTES_TO_PAGES(SizeOfMapBuffers);
165
166 /* TODO: Allocation */
167
168 return TRUE;
169 }
170
171 PADAPTER_OBJECT STDCALL
172 HalpAllocateAdapterEx(
173 ULONG NumberOfMapRegisters,
174 BOOLEAN IsMaster,
175 BOOLEAN Dma32BitAddresses)
176 /*
177 * FUNCTION: Allocates an ADAPTER_OBJECT, optionally creates the Master Adapter.
178 * ARGUMENTS:
179 * - NumberOfMapRegisters: Number of map registers to allocate
180 * - IsMaster: Wether this is a Master Device or not
181 * - Dma32BitAddresses: Wether 32-bit Addresses are supported
182 * RETURNS:
183 * - Pointer to Adapter Object, or NULL if failure.
184 * BUGS:
185 * - Some stuff is unhandled/incomplete
186 */
187 {
188 OBJECT_ATTRIBUTES ObjectAttributes;
189 ULONG ObjectSize;
190 ULONG BitmapSize;
191 NTSTATUS Status;
192 ULONG AllowedMapRegisters = 64;
193 PADAPTER_OBJECT AdapterObject;
194 HANDLE Handle;
195
196 /* Allocate the Master Adapter if we haven't already
197 but make sure we're not asked to do it now, and also check if we need it */
198 if ((MasterAdapter == NULL) && (!IsMaster) && (NumberOfMapRegisters)) {
199
200 /* Allocate and Save */
201 DPRINT("Allocating the Master Adapter Object\n");
202 MasterAdapter = HalpAllocateAdapterEx(NumberOfMapRegisters,
203 TRUE,
204 Dma32BitAddresses);
205
206 /* Cancel on Failure */
207 DPRINT("Checking if Master Adapter was allocated properly\n");
208 if (!MasterAdapter) return NULL;
209 }
210
211 /* Initialize the Object Attributes for the Adapter Object */
212 InitializeObjectAttributes(&ObjectAttributes,
213 NULL,
214 OBJ_PERMANENT,
215 NULL,
216 NULL);
217
218 /* Check if this is the Master Adapter, in which case we need to allocate the bitmap */
219 if (IsMaster) {
220 /* Size due to the Bitmap + Bytes in the Bitmap Buffer (8 bytes, 64 bits)*/
221 BitmapSize = sizeof(RTL_BITMAP) + (AllowedMapRegisters + 7) / 8;
222
223 /* We will put the Bitmap Buffer after the Adapter Object for simplicity */
224 ObjectSize = sizeof(ADAPTER_OBJECT) + BitmapSize;
225 } else {
226 ObjectSize = sizeof(ADAPTER_OBJECT);
227 }
228
229 /* Create and Allocate the Object */
230 DPRINT("Creating the Object\n");
231 Status = ObCreateObject(KernelMode,
232 IoAdapterObjectType,
233 &ObjectAttributes,
234 KernelMode,
235 NULL,
236 ObjectSize,
237 0,
238 0,
239 (PVOID)&AdapterObject);
240
241 if (!NT_SUCCESS(Status)) return NULL;
242
243 /* Add a Reference */
244 DPRINT("Referencing the Object\n");
245 Status = ObReferenceObjectByPointer(AdapterObject,
246 FILE_READ_DATA | FILE_WRITE_DATA,
247 IoAdapterObjectType,
248 KernelMode);
249
250 if (!NT_SUCCESS(Status)) return NULL;
251
252 /* It's a Valid Object, so now we can play with the memory */
253 RtlZeroMemory(AdapterObject, sizeof(ADAPTER_OBJECT));
254
255 /* Insert it into the Object Table */
256 DPRINT("Inserting the Object\n");
257 Status = ObInsertObject(AdapterObject,
258 NULL,
259 FILE_READ_DATA | FILE_WRITE_DATA,
260 0,
261 NULL,
262 &Handle);
263
264 if (!NT_SUCCESS(Status)) return NULL;
265
266 /* We don't want the handle */
267 NtClose(Handle);
268
269 /* Set up the Adapter Object fields */
270 AdapterObject->MapRegistersPerChannel = 1;
271
272 /* Set the Master if needed (master only needed if we use Map Registers) */
273 if (NumberOfMapRegisters) AdapterObject->MasterAdapter = MasterAdapter;
274
275 /* Initalize the Channel Wait queue, which every adapter has */
276 DPRINT("Initializing the Device Queue of the Object\n");
277 KeInitializeDeviceQueue(&AdapterObject->ChannelWaitQueue);
278
279 /* Initialize the SpinLock, Queue and Bitmap, which are kept in the Master Adapter only */
280 if (IsMaster) {
281
282 DPRINT("Initializing the Master Adapter Stuff\n");
283 KeInitializeSpinLock(&AdapterObject->SpinLock);
284 InitializeListHead(&AdapterObject->AdapterQueue);
285
286 /* As said previously, we put them here for simplicity */
287 AdapterObject->MapRegisters = (PVOID)(AdapterObject + 1);
288
289 /* Set up Bitmap */
290 RtlInitializeBitMap(AdapterObject->MapRegisters,
291 (PULONG)(AdapterObject->MapRegisters + 1),
292 AllowedMapRegisters);
293
294 /* Reset the Bitmap */
295 RtlSetAllBits(AdapterObject->MapRegisters);
296 AdapterObject->NumberOfMapRegisters = 0;
297 AdapterObject->CommittedMapRegisters = 0;
298
299 /* Allocate Memory for the Map Registers */
300 AdapterObject->MapRegisterBase = ExAllocatePool(NonPagedPool,
301 AllowedMapRegisters * sizeof(DWORD));
302
303 /* Clear them */
304 RtlZeroMemory(AdapterObject->MapRegisterBase, AllowedMapRegisters * sizeof(DWORD));
305
306 /* Allocate the contigous memory */
307 DPRINT("Allocating Buffers\n");
308 HalpGrowMapBuffers(AdapterObject, 0x1000000);
309 }
310
311 DPRINT("Adapter Object allocated\n");
312 return AdapterObject;
313 }
314
315 \f
316 BOOLEAN STDCALL
317 IoFlushAdapterBuffers (
318 PADAPTER_OBJECT AdapterObject,
319 PMDL Mdl,
320 PVOID MapRegisterBase,
321 PVOID CurrentVa,
322 ULONG Length,
323 BOOLEAN WriteToDevice)
324 /*
325 * FUNCTION: flush any data remaining in the dma controller's memory into the host memory
326 * ARGUMENTS:
327 * AdapterObject: the adapter object to flush
328 * Mdl: original MDL to flush data into
329 * MapRegisterBase: map register base that was just used by IoMapTransfer, etc
330 * CurrentVa: offset into Mdl to be flushed into, same as was passed to IoMapTransfer
331 * Length: length of the buffer to be flushed into
332 * WriteToDevice: True if it's a write, False if it's a read
333 * RETURNS:
334 * TRUE in all cases
335 * NOTES:
336 * - This copies data from the map register-backed buffer to the user's target buffer.
337 * Data is not in the user buffer until this is called.
338 * - This is only meaningful on a read operation. Return immediately for a write.
339 */
340 {
341 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
342
343 /* this can happen if the card supports scatter/gather */
344 if(!MapRegisterBase)
345 return TRUE;
346
347 /* mask out (disable) the dma channel */
348 if (AdapterObject->AdapterNumber == 1) {
349
350 /* Set this for Ease */
351 PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
352
353 /* Set Channel */
354 WRITE_PORT_UCHAR(&DmaControl1->SingleMask, AdapterObject->ChannelNumber | DMA_SETMASK);
355 } else {
356 /* Set this for Ease */
357 PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
358
359 /* Set Channel */
360 WRITE_PORT_UCHAR(&DmaControl2->SingleMask, (AdapterObject->ChannelNumber - 4) | DMA_SETMASK);
361 }
362
363 if(WriteToDevice)
364 return TRUE;
365
366 memcpy(
367 (PVOID)((DWORD)MmGetSystemAddressForMdl( Mdl ) + (DWORD)CurrentVa - (DWORD)MmGetMdlVirtualAddress( Mdl )),
368 MapRegisterBase, Length );
369
370 return TRUE;
371 }
372
373 \f
374 VOID STDCALL
375 IoFreeAdapterChannel (PADAPTER_OBJECT AdapterObject)
376 /*
377 * FUNCTION: frees DMA resources allocated by IoAllocateAdapterChannel
378 * ARGUMENTS:
379 * AdapterObject: Adapter object with resources to free
380 * NOTES:
381 * - This function releases the DMA adapter and optionally the map registers
382 * - After releasing the adapter, it checks the adapter's queue and runs
383 * each queued device object in series until the queue is empty
384 * - This is the only way the device queue is emptied.
385 */
386 {
387 LARGE_INTEGER MaxAddress;
388 LARGE_INTEGER MinAddress;
389 LARGE_INTEGER BoundryAddressMultiple;
390 PWAIT_CONTEXT_BLOCK WaitContextBlock;
391 IO_ALLOCATION_ACTION Retval;
392
393 while(1)
394 {
395 /* To keep map registers, call here with the following set to 0 */
396 if(AdapterObject->CommittedMapRegisters)
397 IoFreeMapRegisters(AdapterObject, AdapterObject->MapRegisterBase, AdapterObject->CommittedMapRegisters);
398
399 if(!(WaitContextBlock = (PWAIT_CONTEXT_BLOCK)KeRemoveDeviceQueue(&AdapterObject->ChannelWaitQueue)))
400 break;
401
402 /*
403 * the following should really be done elsewhere since this
404 * function really can't return an error code. FIXME.
405 */
406
407 MinAddress.QuadPart = 0;
408 BoundryAddressMultiple.QuadPart = 0;
409 if ((AdapterObject->Dma64BitAddresses) && (AdapterObject->MasterDevice))
410 {
411 MaxAddress.QuadPart = 0xFFFFFFFFFFFFFFFFLL; /* 64Bit: >4GB address range */
412 }
413 else if ((AdapterObject->Dma32BitAddresses) && (AdapterObject->MasterDevice))
414 {
415 MaxAddress.QuadPart = 0xFFFFFFFF; /* 32Bit: 4GB address range */
416 }
417 else
418 {
419 MaxAddress.QuadPart = 0x00FFFFFF; /* 24Bit: 16MB address range */
420 if (AdapterObject->Width16Bits)
421 {
422 BoundryAddressMultiple.QuadPart = 0x20000; /* 128k boundary */
423 }
424 else
425 {
426 BoundryAddressMultiple.QuadPart = 0x10000; /* 64k boundary */
427 }
428 }
429
430 AdapterObject->MapRegisterBase = MmAllocateContiguousMemorySpecifyCache(
431 WaitContextBlock->NumberOfMapRegisters * PAGE_SIZE,
432 MinAddress,
433 MaxAddress,
434 BoundryAddressMultiple,
435 MmCached);
436
437 if(!AdapterObject->MapRegisterBase)
438 return;
439
440 /* call the adapter control routine */
441 Retval = ((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)(WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp,
442 AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext);
443
444 if(Retval == KeepObject)
445 {
446 /* we're done until the caller manually calls IoFreeAdapterChannel */
447 break;
448 }
449 else if(Retval == DeallocateObjectKeepRegisters)
450 {
451 /* hide the map registers so they aren't deallocated next time around */
452 AdapterObject->CommittedMapRegisters = 0;
453 }
454 }
455 }
456
457 \f
458 VOID STDCALL
459 IoFreeMapRegisters (
460 IN PADAPTER_OBJECT AdapterObject,
461 IN PVOID MapRegisterBase,
462 IN ULONG NumberOfMapRegisters)
463 /*
464 * FUNCTION: free map registers reserved by the system for a DMA
465 * ARGUMENTS:
466 * AdapterObject: dma adapter to free map registers on
467 * MapRegisterBase: hadle to map registers to free
468 * NumberOfRegisters: number of map registers to be freed
469 * NOTES:
470 * - XXX real windows has a funky interdependence between IoFreeMapRegisters
471 * and IoFreeAdapterChannel
472 * BUGS:
473 * - needs to be improved to use a real map register implementation
474 */
475 {
476 if( AdapterObject->CommittedMapRegisters )
477 {
478 MmFreeContiguousMemory(AdapterObject->MapRegisterBase);
479 AdapterObject->MapRegisterBase = 0;
480 }
481 }
482
483 \f
484 PHYSICAL_ADDRESS STDCALL
485 IoMapTransfer (
486 IN PADAPTER_OBJECT AdapterObject,
487 IN PMDL Mdl,
488 IN PVOID MapRegisterBase,
489 IN PVOID CurrentVa,
490 IN OUT PULONG Length,
491 IN BOOLEAN WriteToDevice)
492 /*
493 * FUNCTION: map a dma for transfer and do the dma if it's a slave
494 * ARGUMENTS:
495 * AdapterObject: adapter object to do the dma on. busmaster may pass NULL.
496 * Mdl: locked-down user buffer to DMA in to or out of
497 * MapRegisterBase: handle to map registers to use for this dma. allways NULL
498 * when doing s/g.
499 * CurrentVa: index into Mdl to transfer into/out of
500 * Length: length of transfer in/out. Only modified on out when doing s/g.
501 * WriteToDevice: TRUE if it's an output dma, FALSE otherwise
502 * RETURNS:
503 * If a busmaster: A logical address that can be used to program a dma controller
504 * Otherwise: nothing meaningful
505 * NOTES:
506 * - This function does a copyover to contiguous memory <16MB
507 * - If it's a slave transfer, this function actually performs it.
508 * BUGS:
509 * - If the controller supports scatter/gather, the copyover should not happen
510 */
511 {
512 PHYSICAL_ADDRESS Address;
513 KIRQL OldIrql;
514 ULONG LengthShift = 0;
515
516 Address.QuadPart = 0;
517
518 /* Isa System (slave) DMA? */
519 if (MapRegisterBase && !AdapterObject->MasterDevice)
520 {
521 KeAcquireSpinLock(&AdapterObject->SpinLock, &OldIrql);
522
523 /*
524 * FIXME: Handle case when doing common-buffer System DMA. In this case,
525 * the buffer described by MDL is already phys. contiguous and below
526 * 16 mega. Driver makes a one-shot call to IoMapTransfer during init.
527 * to program controller with the common-buffer.
528 *
529 * UPDATE: Common buffer support is in place, but it's not done in a
530 * clean way. We use the buffer passed by the MDL in case that the
531 * adapter object is marked as auto initialize. I'm not sure if this
532 * is correct and if not, how to do it properly. Note that it's also
533 * possible to allocate the common buffer with different adapter object
534 * and IoMapTransfer must still work in this case. Eventually this should
535 * be cleaned up somehow or at least this comment modified to reflect
536 * the reality.
537 * -- Filip Navara, 19/07/2004
538 */
539
540 /* if it is a write to the device, copy the caller buffer to the low buffer */
541 if (WriteToDevice && !AdapterObject->AdapterMode.AutoInitialize)
542 {
543 memcpy(MapRegisterBase,
544 (char*)MmGetSystemAddressForMdl(Mdl) + ((ULONG)CurrentVa - (ULONG)MmGetMdlVirtualAddress(Mdl)),
545 *Length );
546 }
547
548 /* Writer Adapter Mode, transfer type */
549 AdapterObject->AdapterMode.TransferType = (WriteToDevice ? WRITE_TRANSFER : READ_TRANSFER);
550
551 /* program up the dma controller, and return */
552 if (!AdapterObject->AdapterMode.AutoInitialize) {
553 Address = MmGetPhysicalAddress( MapRegisterBase );
554 } else {
555 Address = MmGetPhysicalAddress( CurrentVa );
556 }
557
558 /* 16-bit DMA has a shifted length */
559 if (AdapterObject->Width16Bits) {
560 LengthShift = 1;
561 }
562
563 /* Make the Transfer */
564 if (AdapterObject->AdapterNumber == 1) {
565
566 PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; /* For Writing Less Code */
567
568 /* Mask the Channel */
569 WRITE_PORT_UCHAR(&DmaControl1->SingleMask, AdapterObject->ChannelNumber | DMA_SETMASK);
570
571 /* Reset Register */
572 WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
573
574 /* Set the Mode */
575 WRITE_PORT_UCHAR(&DmaControl1->Mode, AdapterObject->AdapterModeByte);
576
577 /* Set the Page Register */
578 WRITE_PORT_UCHAR(AdapterObject->PagePort, (UCHAR)(Address.u.LowPart >> 16));
579
580 /* Set the Offset Register (apparently always 0 for us if I trust the previous comment) */
581 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 0);
582 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 0);
583
584 /* Set the Length */
585 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
586 (UCHAR)((*Length >> LengthShift) - 1));
587 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
588 (UCHAR)(((*Length >> LengthShift) - 1) >> 8));
589
590 /* Unmask the Channel */
591 WRITE_PORT_UCHAR(&DmaControl1->SingleMask, AdapterObject->ChannelNumber | DMA_CLEARMASK);
592 } else {
593 PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; /* For Writing Less Code */
594
595 /* Mask the Channel */
596 WRITE_PORT_UCHAR(&DmaControl2->SingleMask, AdapterObject->ChannelNumber | DMA_SETMASK);
597
598 /* Reset Register */
599 WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
600
601 /* Set the Mode */
602 WRITE_PORT_UCHAR(&DmaControl2->Mode, AdapterObject->AdapterModeByte);
603
604 /* Set the Page Register */
605 WRITE_PORT_UCHAR(AdapterObject->PagePort, (UCHAR)(Address.u.LowPart >> 16));
606
607 /* Set the Offset Register (apparently always 0 for us if I trust the previous comment) */
608 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 0);
609 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 0);
610
611 /* Set the Length */
612 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
613 (UCHAR)((*Length >> LengthShift) - 1));
614 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount,
615 (UCHAR)(((*Length >> LengthShift) - 1) >> 8));
616
617 /* Unmask the Channel */
618 WRITE_PORT_UCHAR(&DmaControl2->SingleMask, AdapterObject->ChannelNumber | DMA_CLEARMASK);
619 }
620
621 /* Release Spinlock */
622 KeReleaseSpinLock(&AdapterObject->SpinLock, OldIrql);
623
624 /*
625 NOTE: Return value should be ignored when doing System DMA.
626 Maybe return some more obvious invalid address here (thou returning
627 MapRegisterBase is also wrong;-)to catch invalid use?
628 */
629 Address.QuadPart = (ULONG)MapRegisterBase;
630 return Address;
631 }
632
633
634 /*
635 Busmaster with s/g support?
636 NOTE: old docs allowed busmasters to pass a NULL Adapter. In this case, MapRegisterBase
637 being NULL is used to detect a s/g busmaster.
638 */
639 if ((!AdapterObject && !MapRegisterBase) ||
640 (AdapterObject && AdapterObject->MasterDevice && AdapterObject->ScatterGather))
641 {
642 /*
643 Just return the passed VA's corresponding phys. address.
644 Update length to the number of phys. contiguous bytes found.
645 */
646
647 PULONG MdlPages;
648 ULONG MdlPageIndex, PhysContiguousLen;
649 ULONG PhysAddress;
650
651 MdlPages = (PULONG)(Mdl + 1);
652
653 /* Get VA's corresponding mdl phys. page index */
654 MdlPageIndex = ((ULONG)CurrentVa - (ULONG)Mdl->StartVa) / PAGE_SIZE;
655
656 /* Get phys. page containing the VA */
657 PhysAddress = MdlPages[MdlPageIndex];
658
659 PhysContiguousLen = PAGE_SIZE - BYTE_OFFSET(CurrentVa);
660
661 /* VA to map may span several contiguous phys. pages (unlikely) */
662 while (PhysContiguousLen < *Length &&
663 MdlPages[MdlPageIndex++] + PAGE_SIZE == MdlPages[MdlPageIndex])
664 {
665 /*
666 Note that allways adding PAGE_SIZE may make PhysContiguousLen greater
667 than Length if buffer doesn't end on page boundary. Take this
668 into consideration below.
669 */
670 PhysContiguousLen += PAGE_SIZE;
671 }
672
673 if (PhysContiguousLen < *Length)
674 {
675 *Length = PhysContiguousLen;
676 }
677
678 //add offset to phys. page address
679 Address.QuadPart = PhysAddress + BYTE_OFFSET(CurrentVa);
680 return Address;
681 }
682
683
684 /*
685 Busmaster without s/g support?
686 NOTE: old docs allowed busmasters to pass a NULL Adapter. In this case, MapRegisterBase
687 not being NULL is used to detect a non s/g busmaster.
688 */
689 if ((!AdapterObject && MapRegisterBase) ||
690 (AdapterObject && AdapterObject->MasterDevice && !AdapterObject->ScatterGather))
691 {
692 /*
693 NOTE: Busmasters doing common-buffer DMA shouldn't call IoMapTransfer, but I don't
694 know if it's illegal... Maybe figure out what to do in this case...
695 */
696
697 if( WriteToDevice )
698 {
699 memcpy(MapRegisterBase,
700 (char*)MmGetSystemAddressForMdl(Mdl) + ((ULONG)CurrentVa - (ULONG)MmGetMdlVirtualAddress(Mdl)),
701 *Length );
702 }
703
704 return MmGetPhysicalAddress(MapRegisterBase);
705 }
706
707 DPRINT("IoMapTransfer: Unsupported operation\n");
708 KEBUGCHECK(0);
709 return Address;
710 }
711
712
713 /* EOF */
714
715
716
717