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