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