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