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