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