]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIo.c
Check in the IsaIoDxe device driver that consumes EFI_SIO_PROTOCOL to produce EFI_ISA...
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaIoDxe / IsaIo.c
1 /** @file
2 The implementation for EFI_ISA_IO_PROTOCOL.
3
4 Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "IsaIo.h"
16
17 //
18 // Module Variables
19 //
20 EFI_ISA_IO_PROTOCOL mIsaIoInterface = {
21 {
22 IsaIoMemRead,
23 IsaIoMemWrite
24 },
25 {
26 IsaIoIoRead,
27 IsaIoIoWrite
28 },
29 IsaIoCopyMem,
30 IsaIoMap,
31 IsaIoUnmap,
32 IsaIoAllocateBuffer,
33 IsaIoFreeBuffer,
34 IsaIoFlush,
35 NULL,
36 0,
37 NULL
38 };
39
40 EFI_ISA_DMA_REGISTERS mDmaRegisters[8] = {
41 {
42 0x00,
43 0x87,
44 0x01
45 },
46 {
47 0x02,
48 0x83,
49 0x03
50 },
51 {
52 0x04,
53 0x81,
54 0x05
55 },
56 {
57 0x06,
58 0x82,
59 0x07
60 },
61 {
62 0x00,
63 0x00,
64 0x00
65 }, // Channel 4 is invalid
66 {
67 0xC4,
68 0x8B,
69 0xC6
70 },
71 {
72 0xC8,
73 0x89,
74 0xCA
75 },
76 {
77 0xCC,
78 0x8A,
79 0xCE
80 },
81 };
82
83 /**
84 Verifies access to an ISA device
85
86 @param[in] IsaIoDevice The ISA device to be verified.
87 @param[in] Type The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
88 @param[in] Width The width of the memory operation.
89 @param[in] Count The number of memory operations to perform.
90 @param[in] Offset The offset in ISA memory space to start the memory operation.
91
92 @retval EFI_SUCCESS Verify success.
93 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
94 @retval EFI_UNSUPPORTED The device ont support the access type.
95 **/
96 EFI_STATUS
97 IsaIoVerifyAccess (
98 IN ISA_IO_DEVICE *IsaIoDevice,
99 IN ISA_ACCESS_TYPE Type,
100 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
101 IN UINTN Count,
102 IN UINT32 Offset
103 )
104 {
105 EFI_ISA_ACPI_RESOURCE *Item;
106 EFI_STATUS Status;
107
108 if (Width < EfiIsaIoWidthUint8 ||
109 Width >= EfiIsaIoWidthMaximum ||
110 Width == EfiIsaIoWidthReserved ||
111 Width == EfiIsaIoWidthFifoReserved ||
112 Width == EfiIsaIoWidthFillReserved
113 ) {
114 return EFI_INVALID_PARAMETER;
115 }
116
117 //
118 // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX
119 // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX
120 //
121 if (Width >= EfiIsaIoWidthFifoUint8 && Width < EfiIsaIoWidthFifoReserved) {
122 Count = 1;
123 }
124
125 Width = (EFI_ISA_IO_PROTOCOL_WIDTH) (Width & 0x03);
126
127 Status = EFI_UNSUPPORTED;
128 Item = IsaIoDevice->IsaIo.ResourceList->ResourceItem;
129 while (Item->Type != EfiIsaAcpiResourceEndOfList) {
130 if ((Type == IsaAccessTypeMem && Item->Type == EfiIsaAcpiResourceMemory) ||
131 (Type == IsaAccessTypeIo && Item->Type == EfiIsaAcpiResourceIo)) {
132 if (Offset >= Item->StartRange && (Offset + Count * (UINT32)(1 << Width)) - 1 <= Item->EndRange) {
133 return EFI_SUCCESS;
134 }
135
136 if (Offset >= Item->StartRange && Offset <= Item->EndRange) {
137 Status = EFI_INVALID_PARAMETER;
138 }
139 }
140
141 Item++;
142 }
143
144 return Status;
145 }
146
147 /**
148 Convert the IO Information in ACPI descriptor to IO ISA Attribute.
149
150 @param[in] Information The IO Information in ACPI descriptor
151
152 @return UINT32 The IO ISA Attribute
153 **/
154 UINT32
155 IsaIoAttribute (
156 IN UINT8 Information
157 )
158 {
159 UINT32 Attribute;
160
161 Attribute = 0;
162
163 switch (Information & EFI_ACPI_IO_DECODE_MASK) {
164 case EFI_ACPI_IO_DECODE_16_BIT:
165 Attribute |= EFI_ISA_ACPI_IO_DECODE_16_BITS;
166 break;
167
168 case EFI_ACPI_IO_DECODE_10_BIT:
169 Attribute |= EFI_ISA_ACPI_IO_DECODE_10_BITS;
170 break;
171 }
172
173 return Attribute;
174 }
175
176 /**
177 Convert the IRQ Information in ACPI descriptor to IRQ ISA Attribute.
178
179 @param[in] Information The IRQ Information in ACPI descriptor
180
181 @return UINT32 The IRQ ISA Attribute
182 **/
183 UINT32
184 IsaIrqAttribute (
185 IN UINT8 Information
186 )
187 {
188 UINT32 Attribute;
189
190 Attribute = 0;
191
192 if ((Information & EFI_ACPI_IRQ_POLARITY_MASK) == EFI_ACPI_IRQ_HIGH_TRUE) {
193 if ((Information & EFI_ACPI_IRQ_MODE) == EFI_ACPI_IRQ_LEVEL_TRIGGERED) {
194 Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_LEVEL_SENSITIVE;
195 } else {
196 Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE;
197 }
198 } else {
199 if ((Information & EFI_ACPI_IRQ_MODE) == EFI_ACPI_IRQ_LEVEL_TRIGGERED) {
200 Attribute = EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_LEVEL_SENSITIVE;
201 } else {
202 Attribute = EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_EDGE_SENSITIVE;
203 }
204 }
205 return Attribute;
206 }
207
208 /**
209 Convert the Memory Information in ACPI descriptor to Memory ISA Attribute.
210
211 @param[in] Information The Memory Information in ACPI descriptor
212
213 @return UINT32 The Memory ISA Attribute
214 **/
215 UINT32
216 IsaMemoryAttribute (
217 IN UINT8 Information
218 )
219 {
220 UINT32 Attribute;
221
222 Attribute = 0;
223
224 switch (Information & EFI_ACPI_MEMORY_WRITE_STATUS_MASK) {
225 case EFI_ACPI_MEMORY_WRITABLE:
226 Attribute |= EFI_ISA_ACPI_MEMORY_WRITEABLE;
227 break;
228 }
229
230 return Attribute;
231 }
232
233 /**
234 Convert the DMA Information in ACPI descriptor to DMA ISA Attribute.
235
236 @param[in] Information The DMA Information in ACPI descriptor
237
238 @return UINT32 The DMA ISA Attribute
239 **/
240 UINT32
241 IsaDmaAttribute (
242 IN UINT8 Information
243 )
244 {
245 UINT32 Attribute;
246
247 Attribute = EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE;
248
249 switch (Information & EFI_ACPI_DMA_SPEED_TYPE_MASK) {
250 case EFI_ACPI_DMA_SPEED_TYPE_COMPATIBILITY:
251 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE;
252 break;
253 case EFI_ACPI_DMA_SPEED_TYPE_A:
254 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A;
255 break;
256 case EFI_ACPI_DMA_SPEED_TYPE_B:
257 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B;
258 break;
259 case EFI_ACPI_DMA_SPEED_TYPE_F:
260 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C;
261 break;
262 }
263
264 switch (Information & EFI_ACPI_DMA_TRANSFER_TYPE_MASK) {
265 case EFI_ACPI_DMA_TRANSFER_TYPE_8_BIT:
266 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8;
267 break;
268 case EFI_ACPI_DMA_TRANSFER_TYPE_16_BIT:
269 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16;
270 break;
271 }
272
273 return Attribute;
274 }
275
276 /**
277 Convert the ACPI resource descriptor to ISA resource descriptor.
278
279 @param[in] AcpiResource Pointer to the ACPI resource descriptor
280 @param[out] IsaResource The optional pointer to the buffer to
281 store the converted ISA resource descriptor
282
283 @return UINTN Number of ISA resource descriptor needed
284 **/
285 UINTN
286 AcpiResourceToIsaResource (
287 IN ACPI_RESOURCE_HEADER_PTR AcpiResource,
288 OUT EFI_ISA_ACPI_RESOURCE *IsaResource OPTIONAL
289 )
290 {
291 UINT32 Index;
292 UINTN Count;
293 UINT32 LastIndex;
294 EFI_ACPI_IO_PORT_DESCRIPTOR *Io;
295 EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo;
296 EFI_ACPI_IRQ_DESCRIPTOR *Irq;
297 EFI_ACPI_DMA_DESCRIPTOR *Dma;
298 EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR *Memory;
299 EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR *FixedMemory;
300
301 Count = 0;
302 LastIndex = 0;
303
304 switch (AcpiResource.SmallHeader->Byte) {
305 case ACPI_DMA_DESCRIPTOR:
306 Dma = (EFI_ACPI_DMA_DESCRIPTOR *) AcpiResource.SmallHeader;
307 for (Index = 0; Index < sizeof (Dma->ChannelMask) * 8; Index++) {
308 if (Dma->ChannelMask & (1 << Index)) {
309 if ((Count > 0) && (LastIndex + 1 == Index)) {
310 if (IsaResource != NULL) {
311 IsaResource[Count - 1].EndRange ++;
312 }
313 } else {
314 if (IsaResource != NULL) {
315 IsaResource[Count].Type = EfiIsaAcpiResourceDma;
316 IsaResource[Count].Attribute = IsaDmaAttribute (Dma->Information);
317 IsaResource[Count].StartRange = Index;
318 IsaResource[Count].EndRange = Index;
319 }
320 Count ++;
321 }
322
323 LastIndex = Index;
324 }
325 }
326 break;
327
328 case ACPI_IO_PORT_DESCRIPTOR:
329 Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) AcpiResource.SmallHeader;
330 if (IsaResource != NULL) {
331 IsaResource[Count].Type = EfiIsaAcpiResourceIo;
332 IsaResource[Count].Attribute = IsaIoAttribute (Io->Information);
333 IsaResource[Count].StartRange = Io->BaseAddressMin;
334 IsaResource[Count].EndRange = Io->BaseAddressMin + Io->Length - 1;
335 }
336 Count ++;
337 break;
338
339 case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:
340 FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) AcpiResource.SmallHeader;
341 if (IsaResource != NULL) {
342 IsaResource[Count].Type = EfiIsaAcpiResourceIo;
343 IsaResource[Count].Attribute = EFI_ISA_ACPI_IO_DECODE_10_BITS;
344 IsaResource[Count].StartRange = FixedIo->BaseAddress;
345 IsaResource[Count].EndRange = FixedIo->BaseAddress + FixedIo->Length - 1;
346 }
347 Count ++;
348 break;
349
350 case ACPI_IRQ_DESCRIPTOR:
351 case ACPI_IRQ_NOFLAG_DESCRIPTOR:
352 Irq = (EFI_ACPI_IRQ_DESCRIPTOR *) AcpiResource.SmallHeader;
353 for (Index = 0; Index < sizeof (Irq->Mask) * 8; Index++) {
354 if (Irq->Mask & (1 << Index)) {
355 if ((Count > 0) && (LastIndex + 1 == Index)) {
356 if (IsaResource != NULL) {
357 IsaResource[Count - 1].EndRange ++;
358 }
359 } else {
360 if (IsaResource != NULL) {
361 IsaResource[Count].Type = EfiIsaAcpiResourceInterrupt;
362 if (AcpiResource.SmallHeader->Byte == ACPI_IRQ_DESCRIPTOR) {
363 IsaResource[Count].Attribute = IsaIrqAttribute (Irq->Information);
364 } else {
365 IsaResource[Count].Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE;
366 }
367 IsaResource[Count].StartRange = Index;
368 IsaResource[Count].EndRange = Index;
369 }
370 Count++;
371 }
372
373 LastIndex = Index;
374 }
375 }
376 break;
377
378 case ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR:
379 Memory = (EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR *) AcpiResource.LargeHeader;
380 if (IsaResource != NULL) {
381 IsaResource[Count].Type = EfiIsaAcpiResourceMemory;
382 IsaResource[Count].Attribute = IsaMemoryAttribute (Memory->Information);
383 IsaResource[Count].StartRange = Memory->BaseAddressMin;
384 IsaResource[Count].EndRange = Memory->BaseAddressMin + Memory->Length - 1;
385 }
386 Count ++;
387 break;
388
389 case ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR:
390 FixedMemory = (EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR *) AcpiResource.LargeHeader;
391 if (IsaResource != NULL) {
392 IsaResource[Count].Type = EfiIsaAcpiResourceMemory;
393 IsaResource[Count].Attribute = IsaMemoryAttribute (FixedMemory->Information);
394 IsaResource[Count].StartRange = FixedMemory->BaseAddress;
395 IsaResource[Count].EndRange = FixedMemory->BaseAddress + FixedMemory->Length - 1;
396 }
397 Count ++;
398 break;
399
400 case ACPI_END_TAG_DESCRIPTOR:
401 if (IsaResource != NULL) {
402 IsaResource[Count].Type = EfiIsaAcpiResourceEndOfList;
403 IsaResource[Count].Attribute = 0;
404 IsaResource[Count].StartRange = 0;
405 IsaResource[Count].EndRange = 0;
406 }
407 Count ++;
408 break;
409 }
410
411 return Count;
412 }
413
414 /**
415 Initializes an ISA I/O Instance
416
417 @param[in] IsaIoDevice The isa device to be initialized.
418 @param[in] DevicePath The device path of the isa device.
419 @param[in] Resources The ACPI resource list.
420
421 **/
422 VOID
423 InitializeIsaIoInstance (
424 IN ISA_IO_DEVICE *IsaIoDevice,
425 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
426 IN ACPI_RESOURCE_HEADER_PTR Resources
427 )
428 {
429 UINTN Index;
430 ACPI_HID_DEVICE_PATH *AcpiNode;
431 ACPI_RESOURCE_HEADER_PTR ResourcePtr;
432
433 //
434 // Use the ISA IO Protocol structure template to initialize the ISA IO instance
435 //
436 CopyMem (
437 &IsaIoDevice->IsaIo,
438 &mIsaIoInterface,
439 sizeof (EFI_ISA_IO_PROTOCOL)
440 );
441
442 //
443 // Count the resources including the ACPI End Tag
444 //
445 ResourcePtr = Resources;
446 Index = 0;
447 while (ResourcePtr.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {
448
449 Index += AcpiResourceToIsaResource (ResourcePtr, NULL);
450
451 if (ResourcePtr.SmallHeader->Bits.Type == 0) {
452 ResourcePtr.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.SmallHeader
453 + ResourcePtr.SmallHeader->Bits.Length
454 + sizeof (*ResourcePtr.SmallHeader));
455 } else {
456 ResourcePtr.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.LargeHeader
457 + ResourcePtr.LargeHeader->Length
458 + sizeof (*ResourcePtr.LargeHeader));
459 }
460
461 }
462 //
463 // Get the Isa Resource count for ACPI End Tag
464 //
465 Index += AcpiResourceToIsaResource (ResourcePtr, NULL);
466
467 //
468 // Initialize the ResourceList
469 //
470 IsaIoDevice->IsaIo.ResourceList = AllocatePool (sizeof (EFI_ISA_ACPI_RESOURCE_LIST) + Index * sizeof (EFI_ISA_ACPI_RESOURCE));
471 ASSERT (IsaIoDevice->IsaIo.ResourceList != NULL);
472 IsaIoDevice->IsaIo.ResourceList->ResourceItem = (EFI_ISA_ACPI_RESOURCE *) (IsaIoDevice->IsaIo.ResourceList + 1);
473
474 AcpiNode = (ACPI_HID_DEVICE_PATH *) ((UINT8 *) DevicePath + GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH - sizeof (ACPI_HID_DEVICE_PATH));
475 IsaIoDevice->IsaIo.ResourceList->Device.HID = AcpiNode->HID;
476 IsaIoDevice->IsaIo.ResourceList->Device.UID = AcpiNode->UID;
477
478 ResourcePtr = Resources;
479 Index = 0;
480 while (ResourcePtr.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {
481
482 Index += AcpiResourceToIsaResource (ResourcePtr, &IsaIoDevice->IsaIo.ResourceList->ResourceItem[Index]);
483
484 if (ResourcePtr.SmallHeader->Bits.Type == 0) {
485 ResourcePtr.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.SmallHeader
486 + ResourcePtr.SmallHeader->Bits.Length
487 + sizeof (*ResourcePtr.SmallHeader));
488 } else {
489 ResourcePtr.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.LargeHeader
490 + ResourcePtr.LargeHeader->Length
491 + sizeof (*ResourcePtr.LargeHeader));
492 }
493 }
494
495 //
496 // Convert the ACPI End Tag
497 //
498 AcpiResourceToIsaResource (ResourcePtr, &IsaIoDevice->IsaIo.ResourceList->ResourceItem[Index]);
499 }
500
501 /**
502 Performs an ISA I/O Read Cycle
503
504 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
505 @param[in] Width Specifies the width of the I/O operation.
506 @param[in] Offset The offset in ISA I/O space to start the I/O operation.
507 @param[in] Count The number of I/O operations to perform.
508 @param[out] Buffer The destination buffer to store the results
509
510 @retval EFI_SUCCESS The data was read from the device sucessfully.
511 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
512 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
513 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
514 **/
515 EFI_STATUS
516 EFIAPI
517 IsaIoIoRead (
518 IN EFI_ISA_IO_PROTOCOL *This,
519 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
520 IN UINT32 Offset,
521 IN UINTN Count,
522 OUT VOID *Buffer
523 )
524 {
525 EFI_STATUS Status;
526 ISA_IO_DEVICE *IsaIoDevice;
527
528 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
529
530 //
531 // Verify Isa IO Access
532 //
533 Status = IsaIoVerifyAccess (
534 IsaIoDevice,
535 IsaAccessTypeIo,
536 Width,
537 Count,
538 Offset
539 );
540 if (EFI_ERROR (Status)) {
541 return Status;
542 }
543
544 Status = IsaIoDevice->PciIo->Io.Read (
545 IsaIoDevice->PciIo,
546 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
547 EFI_PCI_IO_PASS_THROUGH_BAR,
548 Offset,
549 Count,
550 Buffer
551 );
552
553 if (EFI_ERROR (Status)) {
554 REPORT_STATUS_CODE (
555 EFI_ERROR_CODE | EFI_ERROR_MINOR,
556 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
557 );
558 }
559
560 return Status;
561 }
562
563 /**
564 Performs an ISA I/O Write Cycle
565
566 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
567 @param[in] Width Specifies the width of the I/O operation.
568 @param[in] Offset The offset in ISA I/O space to start the I/O operation.
569 @param[in] Count The number of I/O operations to perform.
570 @param[in] Buffer The source buffer to write data from
571
572 @retval EFI_SUCCESS The data was writen to the device sucessfully.
573 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
574 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
575 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
576 **/
577 EFI_STATUS
578 EFIAPI
579 IsaIoIoWrite (
580 IN EFI_ISA_IO_PROTOCOL *This,
581 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
582 IN UINT32 Offset,
583 IN UINTN Count,
584 IN VOID *Buffer
585 )
586 {
587 EFI_STATUS Status;
588 ISA_IO_DEVICE *IsaIoDevice;
589
590 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
591
592 //
593 // Verify Isa IO Access
594 //
595 Status = IsaIoVerifyAccess (
596 IsaIoDevice,
597 IsaAccessTypeIo,
598 Width,
599 Count,
600 Offset
601 );
602 if (EFI_ERROR (Status)) {
603 return Status;
604 }
605
606 Status = IsaIoDevice->PciIo->Io.Write (
607 IsaIoDevice->PciIo,
608 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
609 EFI_PCI_IO_PASS_THROUGH_BAR,
610 Offset,
611 Count,
612 Buffer
613 );
614
615 if (EFI_ERROR (Status)) {
616 REPORT_STATUS_CODE (
617 EFI_ERROR_CODE | EFI_ERROR_MINOR,
618 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
619 );
620 }
621
622 return Status;
623 }
624
625 /**
626 Writes an 8-bit I/O Port
627
628 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
629 @param[in] Offset The offset in ISA IO space to start the IO operation.
630 @param[in] Value The data to write port.
631
632 @retval EFI_SUCCESS Success.
633 @retval EFI_INVALID_PARAMETER Parameter is invalid.
634 @retval EFI_UNSUPPORTED The address range specified by Offset is not valid.
635 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
636 **/
637 EFI_STATUS
638 WritePort (
639 IN EFI_ISA_IO_PROTOCOL *This,
640 IN UINT32 Offset,
641 IN UINT8 Value
642 )
643 {
644 EFI_STATUS Status;
645 ISA_IO_DEVICE *IsaIoDevice;
646
647 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
648
649 Status = IsaIoDevice->PciIo->Io.Write (
650 IsaIoDevice->PciIo,
651 EfiPciIoWidthUint8,
652 EFI_PCI_IO_PASS_THROUGH_BAR,
653 Offset,
654 1,
655 &Value
656 );
657 if (EFI_ERROR (Status)) {
658 REPORT_STATUS_CODE (
659 EFI_ERROR_CODE | EFI_ERROR_MINOR,
660 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
661 );
662 return Status;
663 }
664
665 //
666 // Wait for 50 microseconds to take affect.
667 //
668 gBS->Stall (50);
669
670 return EFI_SUCCESS;
671 }
672
673 /**
674 Writes I/O operation base address and count number to a 8 bit I/O Port.
675
676 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
677 @param[in] AddrOffset The address' offset.
678 @param[in] PageOffset The page's offest.
679 @param[in] CountOffset The count's offset.
680 @param[in] BaseAddress The base address.
681 @param[in] Count The number of I/O operations to perform.
682
683 @retval EFI_SUCCESS Success.
684 @retval EFI_INVALID_PARAMETER Parameter is invalid.
685 @retval EFI_UNSUPPORTED The address range specified by these Offsets and Count is not valid.
686 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
687 **/
688 EFI_STATUS
689 WriteDmaPort (
690 IN EFI_ISA_IO_PROTOCOL *This,
691 IN UINT32 AddrOffset,
692 IN UINT32 PageOffset,
693 IN UINT32 CountOffset,
694 IN UINT32 BaseAddress,
695 IN UINT16 Count
696 )
697 {
698 EFI_STATUS Status;
699
700 Status = WritePort (This, AddrOffset, (UINT8) (BaseAddress & 0xff));
701 if (EFI_ERROR (Status)) {
702 return Status;
703 }
704
705 Status = WritePort (This, AddrOffset, (UINT8) ((BaseAddress >> 8) & 0xff));
706 if (EFI_ERROR (Status)) {
707 return Status;
708 }
709
710 Status = WritePort (This, PageOffset, (UINT8) ((BaseAddress >> 16) & 0xff));
711 if (EFI_ERROR (Status)) {
712 return Status;
713 }
714
715 Status = WritePort (This, CountOffset, (UINT8) (Count & 0xff));
716 if (EFI_ERROR (Status)) {
717 return Status;
718 }
719
720 Status = WritePort (This, CountOffset, (UINT8) ((Count >> 8) & 0xff));
721 return Status;
722 }
723
724 /**
725 Unmaps a memory region for DMA
726
727 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
728 @param[in] Mapping The mapping value returned from EFI_ISA_IO.Map().
729
730 @retval EFI_SUCCESS The range was unmapped.
731 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
732 **/
733 EFI_STATUS
734 EFIAPI
735 IsaIoUnmap (
736 IN EFI_ISA_IO_PROTOCOL *This,
737 IN VOID *Mapping
738 )
739 {
740 ISA_MAP_INFO *IsaMapInfo;
741
742 //
743 // Check if DMA is supported.
744 //
745 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
746 return EFI_UNSUPPORTED;
747 }
748
749 //
750 // See if the Map() operation associated with this Unmap() required a mapping
751 // buffer.If a mapping buffer was not required, then this function simply
752 // returns EFI_SUCCESS.
753 //
754 if (Mapping != NULL) {
755 //
756 // Get the MAP_INFO structure from Mapping
757 //
758 IsaMapInfo = (ISA_MAP_INFO *) Mapping;
759
760 //
761 // If this is a write operation from the Agent's point of view,
762 // then copy the contents of the mapped buffer into the real buffer
763 // so the processor can read the contents of the real buffer.
764 //
765 if (IsaMapInfo->Operation == EfiIsaIoOperationBusMasterWrite) {
766 CopyMem (
767 (VOID *) (UINTN) IsaMapInfo->HostAddress,
768 (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
769 IsaMapInfo->NumberOfBytes
770 );
771 }
772 //
773 // Free the mapped buffer and the MAP_INFO structure.
774 //
775 gBS->FreePages (IsaMapInfo->MappedHostAddress, IsaMapInfo->NumberOfPages);
776 FreePool (IsaMapInfo);
777 }
778
779 return EFI_SUCCESS;
780 }
781
782 /**
783 Flushes any posted write data to the system memory.
784
785 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
786
787 @retval EFI_SUCCESS The buffers were flushed.
788 @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.
789 **/
790 EFI_STATUS
791 EFIAPI
792 IsaIoFlush (
793 IN EFI_ISA_IO_PROTOCOL *This
794 )
795 {
796 EFI_STATUS Status;
797 ISA_IO_DEVICE *IsaIoDevice;
798
799 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
800
801 Status = IsaIoDevice->PciIo->Flush (IsaIoDevice->PciIo);
802
803 if (EFI_ERROR (Status)) {
804 REPORT_STATUS_CODE (
805 EFI_ERROR_CODE | EFI_ERROR_MINOR,
806 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
807 );
808 }
809
810 return Status;
811 }
812
813 /**
814 Performs an ISA Memory Read Cycle
815
816 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
817 @param[in] Width Specifies the width of the memory operation.
818 @param[in] Offset The offset in ISA memory space to start the memory operation.
819 @param[in] Count The number of memory operations to perform.
820 @param[out] Buffer The destination buffer to store the results
821
822 @retval EFI_SUCCESS The data was read from the device successfully.
823 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
824 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
825 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
826 **/
827 EFI_STATUS
828 EFIAPI
829 IsaIoMemRead (
830 IN EFI_ISA_IO_PROTOCOL *This,
831 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
832 IN UINT32 Offset,
833 IN UINTN Count,
834 OUT VOID *Buffer
835 )
836 {
837 EFI_STATUS Status;
838 ISA_IO_DEVICE *IsaIoDevice;
839
840 //
841 // Check if ISA memory is supported.
842 //
843 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
844 return EFI_UNSUPPORTED;
845 }
846
847 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
848
849 //
850 // Verify the Isa Io Access
851 //
852 Status = IsaIoVerifyAccess (
853 IsaIoDevice,
854 IsaAccessTypeMem,
855 Width,
856 Count,
857 Offset
858 );
859 if (EFI_ERROR (Status)) {
860 return Status;
861 }
862
863 Status = IsaIoDevice->PciIo->Mem.Read (
864 IsaIoDevice->PciIo,
865 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
866 EFI_PCI_IO_PASS_THROUGH_BAR,
867 Offset,
868 Count,
869 Buffer
870 );
871
872 if (EFI_ERROR (Status)) {
873 REPORT_STATUS_CODE (
874 EFI_ERROR_CODE | EFI_ERROR_MINOR,
875 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
876 );
877 }
878
879 return Status;
880 }
881
882 /**
883 Performs an ISA Memory Write Cycle
884
885 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
886 @param[in] Width Specifies the width of the memory operation.
887 @param[in] Offset The offset in ISA memory space to start the memory operation.
888 @param[in] Count The number of memory operations to perform.
889 @param[in] Buffer The source buffer to write data from
890
891 @retval EFI_SUCCESS The data was written to the device sucessfully.
892 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
893 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
894 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
895 **/
896 EFI_STATUS
897 EFIAPI
898 IsaIoMemWrite (
899 IN EFI_ISA_IO_PROTOCOL *This,
900 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
901 IN UINT32 Offset,
902 IN UINTN Count,
903 IN VOID *Buffer
904 )
905 {
906 EFI_STATUS Status;
907 ISA_IO_DEVICE *IsaIoDevice;
908
909 //
910 // Check if ISA memory is supported.
911 //
912 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
913 return EFI_UNSUPPORTED;
914 }
915
916 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
917
918 //
919 // Verify Isa IO Access
920 //
921 Status = IsaIoVerifyAccess (
922 IsaIoDevice,
923 IsaAccessTypeMem,
924 Width,
925 Count,
926 Offset
927 );
928 if (EFI_ERROR (Status)) {
929 return Status;
930 }
931
932 Status = IsaIoDevice->PciIo->Mem.Write (
933 IsaIoDevice->PciIo,
934 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
935 EFI_PCI_IO_PASS_THROUGH_BAR,
936 Offset,
937 Count,
938 Buffer
939 );
940
941 if (EFI_ERROR (Status)) {
942 REPORT_STATUS_CODE (
943 EFI_ERROR_CODE | EFI_ERROR_MINOR,
944 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
945 );
946 }
947
948 return Status;
949 }
950
951 /**
952 Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.
953
954 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
955 @param[in] Width Specifies the width of the memory copy operation.
956 @param[in] DestOffset The offset of the destination
957 @param[in] SrcOffset The offset of the source
958 @param[in] Count The number of memory copy operations to perform
959
960 @retval EFI_SUCCESS The data was copied sucessfully.
961 @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.
962 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
963 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
964 **/
965 EFI_STATUS
966 EFIAPI
967 IsaIoCopyMem (
968 IN EFI_ISA_IO_PROTOCOL *This,
969 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
970 IN UINT32 DestOffset,
971 IN UINT32 SrcOffset,
972 IN UINTN Count
973 )
974 {
975 EFI_STATUS Status;
976 ISA_IO_DEVICE *IsaIoDevice;
977
978 //
979 // Check if ISA memory is supported.
980 //
981 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
982 return EFI_UNSUPPORTED;
983 }
984
985 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
986
987 //
988 // Verify Isa IO Access for destination and source
989 //
990 Status = IsaIoVerifyAccess (
991 IsaIoDevice,
992 IsaAccessTypeMem,
993 Width,
994 Count,
995 DestOffset
996 );
997 if (EFI_ERROR (Status)) {
998 return Status;
999 }
1000
1001 Status = IsaIoVerifyAccess (
1002 IsaIoDevice,
1003 IsaAccessTypeMem,
1004 Width,
1005 Count,
1006 SrcOffset
1007 );
1008 if (EFI_ERROR (Status)) {
1009 return Status;
1010 }
1011
1012 Status = IsaIoDevice->PciIo->CopyMem (
1013 IsaIoDevice->PciIo,
1014 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
1015 EFI_PCI_IO_PASS_THROUGH_BAR,
1016 DestOffset,
1017 EFI_PCI_IO_PASS_THROUGH_BAR,
1018 SrcOffset,
1019 Count
1020 );
1021
1022 if (EFI_ERROR (Status)) {
1023 REPORT_STATUS_CODE (
1024 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1025 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
1026 );
1027 }
1028
1029 return Status;
1030 }
1031
1032 /**
1033 Maps a memory region for DMA, note this implementation
1034 only supports slave read/write operation to save code size.
1035
1036 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1037 @param Operation Indicates the type of DMA (slave or bus master), and if
1038 the DMA operation is going to read or write to system memory.
1039 @param ChannelNumber The slave channel number to use for this DMA operation.
1040 If Operation and ChannelAttributes shows that this device
1041 performs bus mastering DMA, then this field is ignored.
1042 The legal range for this field is 0..7.
1043 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
1044 @param HostAddress The system memory address to map to the device.
1045 @param NumberOfBytes On input the number of bytes to map. On output the number
1046 of bytes that were mapped.
1047 @param DeviceAddress The resulting map address for the bus master device to use
1048 to access the hosts HostAddress.
1049 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
1050
1051 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
1052 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
1053 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
1054 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
1055 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1056 **/
1057 EFI_STATUS
1058 IsaIoMapOnlySupportSlaveReadWrite (
1059 IN EFI_ISA_IO_PROTOCOL *This,
1060 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
1061 IN UINT8 ChannelNumber OPTIONAL,
1062 IN UINT32 ChannelAttributes,
1063 IN VOID *HostAddress,
1064 IN OUT UINTN *NumberOfBytes,
1065 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
1066 OUT VOID **Mapping
1067 )
1068 {
1069 EFI_STATUS Status;
1070 EFI_PHYSICAL_ADDRESS PhysicalAddress;
1071 ISA_MAP_INFO *IsaMapInfo;
1072 UINT8 DmaMode;
1073 UINTN MaxNumberOfBytes;
1074 UINT32 BaseAddress;
1075 UINT16 Count;
1076 UINT8 DmaMask;
1077 UINT8 DmaClear;
1078 UINT8 DmaChannelMode;
1079
1080 if ((NULL == This) ||
1081 (NULL == HostAddress) ||
1082 (NULL == NumberOfBytes) ||
1083 (NULL == DeviceAddress) ||
1084 (NULL == Mapping)
1085 ) {
1086 return EFI_INVALID_PARAMETER;
1087 }
1088
1089 //
1090 // Initialize the return values to their defaults
1091 //
1092 *Mapping = NULL;
1093
1094 //
1095 // Make sure the Operation parameter is valid.
1096 // Light IsaIo only supports two operations.
1097 //
1098 if (!(Operation == EfiIsaIoOperationSlaveRead ||
1099 Operation == EfiIsaIoOperationSlaveWrite)) {
1100 return EFI_INVALID_PARAMETER;
1101 }
1102
1103 if (ChannelNumber >= 4) {
1104 //
1105 // The Light IsaIo doesn't support channelNumber larger than 4.
1106 //
1107 return EFI_INVALID_PARAMETER;
1108 }
1109
1110 //
1111 // Map the HostAddress to a DeviceAddress.
1112 //
1113 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
1114 if ((PhysicalAddress + *NumberOfBytes) > BASE_16MB) {
1115 //
1116 // Common Buffer operations can not be remapped. If the common buffer
1117 // is above 16MB, then it is not possible to generate a mapping, so return
1118 // an error.
1119 //
1120 if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
1121 return EFI_UNSUPPORTED;
1122 }
1123 //
1124 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
1125 // is called later.
1126 //
1127 IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
1128 if (IsaMapInfo == NULL) {
1129 *NumberOfBytes = 0;
1130 return EFI_OUT_OF_RESOURCES;
1131 }
1132 //
1133 // Return a pointer to the MAP_INFO structure in Mapping
1134 //
1135 *Mapping = IsaMapInfo;
1136
1137 //
1138 // Initialize the MAP_INFO structure
1139 //
1140 IsaMapInfo->Operation = Operation;
1141 IsaMapInfo->NumberOfBytes = *NumberOfBytes;
1142 IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);
1143 IsaMapInfo->HostAddress = PhysicalAddress;
1144 IsaMapInfo->MappedHostAddress = BASE_16MB - 1;
1145
1146 //
1147 // Allocate a buffer below 16MB to map the transfer to.
1148 //
1149 Status = gBS->AllocatePages (
1150 AllocateMaxAddress,
1151 EfiBootServicesData,
1152 IsaMapInfo->NumberOfPages,
1153 &IsaMapInfo->MappedHostAddress
1154 );
1155 if (EFI_ERROR (Status)) {
1156 FreePool (IsaMapInfo);
1157 *NumberOfBytes = 0;
1158 *Mapping = NULL;
1159 return Status;
1160 }
1161 //
1162 // If this is a read operation from the DMA agents's point of view,
1163 // then copy the contents of the real buffer into the mapped buffer
1164 // so the DMA agent can read the contents of the real buffer.
1165 //
1166 if (Operation == EfiIsaIoOperationSlaveRead) {
1167 CopyMem (
1168 (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
1169 (VOID *) (UINTN) IsaMapInfo->HostAddress,
1170 IsaMapInfo->NumberOfBytes
1171 );
1172 }
1173 //
1174 // The DeviceAddress is the address of the maped buffer below 16 MB
1175 //
1176 *DeviceAddress = IsaMapInfo->MappedHostAddress;
1177 } else {
1178 //
1179 // The transfer is below 16 MB, so the DeviceAddress is simply the
1180 // HostAddress
1181 //
1182 *DeviceAddress = PhysicalAddress;
1183 }
1184
1185 //
1186 // Figure out what to program into the DMA Channel Mode Register
1187 //
1188 DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
1189 if (Operation == EfiIsaIoOperationSlaveRead) {
1190 DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
1191 } else {
1192 DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
1193 }
1194 //
1195 // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo
1196 //
1197 DmaMode |= V_8237_DMA_CHMODE_SINGLE;
1198
1199 //
1200 // A Slave DMA transfer can not cross a 64K boundary.
1201 // Compute *NumberOfBytes based on this restriction.
1202 //
1203 MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
1204 if (*NumberOfBytes > MaxNumberOfBytes) {
1205 *NumberOfBytes = MaxNumberOfBytes;
1206 }
1207 //
1208 // Compute the values to program into the BaseAddress and Count registers
1209 // of the Slave DMA controller
1210 //
1211 BaseAddress = (UINT32) (*DeviceAddress);
1212 Count = (UINT16) (*NumberOfBytes - 1);
1213 //
1214 // Program the DMA Write Single Mask Register for ChannelNumber
1215 // Clear the DMA Byte Pointer Register
1216 //
1217 DmaMask = R_8237_DMA_WRSMSK_CH0_3;
1218 DmaClear = R_8237_DMA_CBPR_CH0_3;
1219 DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;
1220
1221 Status = WritePort (
1222 This,
1223 DmaMask,
1224 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
1225 );
1226 if (EFI_ERROR (Status)) {
1227 return Status;
1228 }
1229
1230 Status = WritePort (
1231 This,
1232 DmaClear,
1233 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
1234 );
1235 if (EFI_ERROR (Status)) {
1236 return Status;
1237 }
1238
1239 Status = WritePort (This, DmaChannelMode, DmaMode);
1240 if (EFI_ERROR (Status)) {
1241 return Status;
1242 }
1243
1244 Status = WriteDmaPort (
1245 This,
1246 mDmaRegisters[ChannelNumber].Address,
1247 mDmaRegisters[ChannelNumber].Page,
1248 mDmaRegisters[ChannelNumber].Count,
1249 BaseAddress,
1250 Count
1251 );
1252 if (EFI_ERROR (Status)) {
1253 return Status;
1254 }
1255
1256 Status = WritePort (
1257 This,
1258 DmaMask,
1259 (UINT8) (ChannelNumber & 0x03)
1260 );
1261 if (EFI_ERROR (Status)) {
1262 return Status;
1263 }
1264
1265 return EFI_SUCCESS;
1266 }
1267
1268 /**
1269 Maps a memory region for DMA. This implementation implement the
1270 the full mapping support.
1271
1272 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1273 @param Operation Indicates the type of DMA (slave or bus master), and if
1274 the DMA operation is going to read or write to system memory.
1275 @param ChannelNumber The slave channel number to use for this DMA operation.
1276 If Operation and ChannelAttributes shows that this device
1277 performs bus mastering DMA, then this field is ignored.
1278 The legal range for this field is 0..7.
1279 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
1280 @param HostAddress The system memory address to map to the device.
1281 @param NumberOfBytes On input the number of bytes to map. On output the number
1282 of bytes that were mapped.
1283 @param DeviceAddress The resulting map address for the bus master device to use
1284 to access the hosts HostAddress.
1285 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
1286
1287 @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
1288 @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
1289 @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.
1290 @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.
1291 @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
1292 **/
1293 EFI_STATUS
1294 IsaIoMapFullSupport (
1295 IN EFI_ISA_IO_PROTOCOL *This,
1296 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
1297 IN UINT8 ChannelNumber OPTIONAL,
1298 IN UINT32 ChannelAttributes,
1299 IN VOID *HostAddress,
1300 IN OUT UINTN *NumberOfBytes,
1301 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
1302 OUT VOID **Mapping
1303 )
1304 {
1305 EFI_STATUS Status;
1306 BOOLEAN Master;
1307 BOOLEAN Read;
1308 EFI_PHYSICAL_ADDRESS PhysicalAddress;
1309 ISA_MAP_INFO *IsaMapInfo;
1310 UINT8 DmaMode;
1311 UINTN MaxNumberOfBytes;
1312 UINT32 BaseAddress;
1313 UINT16 Count;
1314 UINT8 DmaMask;
1315 UINT8 DmaClear;
1316 UINT8 DmaChannelMode;
1317
1318 if ((NULL == This) ||
1319 (NULL == HostAddress) ||
1320 (NULL == NumberOfBytes) ||
1321 (NULL == DeviceAddress) ||
1322 (NULL == Mapping)
1323 ) {
1324 return EFI_INVALID_PARAMETER;
1325 }
1326
1327 //
1328 // Initialize the return values to their defaults
1329 //
1330 *Mapping = NULL;
1331
1332 //
1333 // Make sure the Operation parameter is valid
1334 //
1335 if (Operation < 0 || Operation >= EfiIsaIoOperationMaximum) {
1336 return EFI_INVALID_PARAMETER;
1337 }
1338
1339 if (ChannelNumber >= 8) {
1340 return EFI_INVALID_PARAMETER;
1341 }
1342
1343 //
1344 // See if this is a Slave DMA Operation
1345 //
1346 Master = TRUE;
1347 Read = FALSE;
1348 if (Operation == EfiIsaIoOperationSlaveRead) {
1349 Operation = EfiIsaIoOperationBusMasterRead;
1350 Master = FALSE;
1351 Read = TRUE;
1352 }
1353
1354 if (Operation == EfiIsaIoOperationSlaveWrite) {
1355 Operation = EfiIsaIoOperationBusMasterWrite;
1356 Master = FALSE;
1357 Read = FALSE;
1358 }
1359
1360 if (!Master) {
1361 //
1362 // Make sure that ChannelNumber is a valid channel number
1363 // Channel 4 is used to cascade, so it is illegal.
1364 //
1365 if (ChannelNumber == 4 || ChannelNumber > 7) {
1366 return EFI_INVALID_PARAMETER;
1367 }
1368 //
1369 // This implementation only support COMPATIBLE DMA Transfers
1370 //
1371 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE) == 0) {
1372 return EFI_INVALID_PARAMETER;
1373 }
1374
1375 if ((ChannelAttributes &
1376 (EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A |
1377 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B |
1378 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C)) != 0) {
1379 return EFI_INVALID_PARAMETER;
1380 }
1381
1382 if (ChannelNumber < 4) {
1383 //
1384 // If this is Channel 0..3, then the width must be 8 bit
1385 //
1386 if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) == 0) ||
1387 ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) != 0)
1388 ) {
1389 return EFI_INVALID_PARAMETER;
1390 }
1391 } else {
1392 //
1393 // If this is Channel 4..7, then the width must be 16 bit
1394 //
1395 if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) != 0) ||
1396 ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) == 0)) {
1397 return EFI_INVALID_PARAMETER;
1398 }
1399 }
1400 //
1401 // Either Demand Mode or Single Mode must be selected, but not both
1402 //
1403 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
1404 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
1405 return EFI_INVALID_PARAMETER;
1406 }
1407 } else {
1408 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) == 0) {
1409 return EFI_INVALID_PARAMETER;
1410 }
1411 }
1412 }
1413 //
1414 // Map the HostAddress to a DeviceAddress.
1415 //
1416 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
1417 if ((PhysicalAddress +*NumberOfBytes) > BASE_16MB) {
1418 //
1419 // Common Buffer operations can not be remapped. If the common buffer
1420 // is above 16MB, then it is not possible to generate a mapping, so return
1421 // an error.
1422 //
1423 if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
1424 return EFI_UNSUPPORTED;
1425 }
1426 //
1427 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
1428 // is called later.
1429 //
1430 IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
1431 if (IsaMapInfo == NULL) {
1432 *NumberOfBytes = 0;
1433 return EFI_OUT_OF_RESOURCES;
1434 }
1435 //
1436 // Return a pointer to the MAP_INFO structure in Mapping
1437 //
1438 *Mapping = IsaMapInfo;
1439
1440 //
1441 // Initialize the MAP_INFO structure
1442 //
1443 IsaMapInfo->Operation = Operation;
1444 IsaMapInfo->NumberOfBytes = *NumberOfBytes;
1445 IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);
1446 IsaMapInfo->HostAddress = PhysicalAddress;
1447 IsaMapInfo->MappedHostAddress = BASE_16MB - 1;
1448
1449 //
1450 // Allocate a buffer below 16MB to map the transfer to.
1451 //
1452 Status = gBS->AllocatePages (
1453 AllocateMaxAddress,
1454 EfiBootServicesData,
1455 IsaMapInfo->NumberOfPages,
1456 &IsaMapInfo->MappedHostAddress
1457 );
1458 if (EFI_ERROR (Status)) {
1459 FreePool (IsaMapInfo);
1460 *NumberOfBytes = 0;
1461 *Mapping = NULL;
1462 return Status;
1463 }
1464 //
1465 // If this is a read operation from the DMA agents's point of view,
1466 // then copy the contents of the real buffer into the mapped buffer
1467 // so the DMA agent can read the contents of the real buffer.
1468 //
1469 if (Operation == EfiIsaIoOperationBusMasterRead) {
1470 CopyMem (
1471 (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
1472 (VOID *) (UINTN) IsaMapInfo->HostAddress,
1473 IsaMapInfo->NumberOfBytes
1474 );
1475 }
1476 //
1477 // The DeviceAddress is the address of the maped buffer below 16 MB
1478 //
1479 *DeviceAddress = IsaMapInfo->MappedHostAddress;
1480 } else {
1481 //
1482 // The transfer is below 16 MB, so the DeviceAddress is simply the
1483 // HostAddress
1484 //
1485 *DeviceAddress = PhysicalAddress;
1486 }
1487 //
1488 // If this is a Bus Master operation then return
1489 //
1490 if (Master) {
1491 return EFI_SUCCESS;
1492 }
1493 //
1494 // Figure out what to program into the DMA Channel Mode Register
1495 //
1496 DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
1497 if (Read) {
1498 DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
1499 } else {
1500 DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
1501 }
1502
1503 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE) != 0) {
1504 DmaMode |= B_8237_DMA_CHMODE_AE;
1505 }
1506
1507 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
1508 DmaMode |= V_8237_DMA_CHMODE_DEMAND;
1509 }
1510
1511 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
1512 DmaMode |= V_8237_DMA_CHMODE_SINGLE;
1513 }
1514 //
1515 // A Slave DMA transfer can not cross a 64K boundary.
1516 // Compute *NumberOfBytes based on this restriction.
1517 //
1518 MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
1519 if (*NumberOfBytes > MaxNumberOfBytes) {
1520 *NumberOfBytes = MaxNumberOfBytes;
1521 }
1522 //
1523 // Compute the values to program into the BaseAddress and Count registers
1524 // of the Slave DMA controller
1525 //
1526 if (ChannelNumber < 4) {
1527 BaseAddress = (UINT32) (*DeviceAddress);
1528 Count = (UINT16) (*NumberOfBytes - 1);
1529 } else {
1530 BaseAddress = (UINT32) (((UINT32) (*DeviceAddress) & 0xff0000) | (((UINT32) (*DeviceAddress) & 0xffff) >> 1));
1531 Count = (UINT16) ((*NumberOfBytes - 1) >> 1);
1532 }
1533 //
1534 // Program the DMA Write Single Mask Register for ChannelNumber
1535 // Clear the DMA Byte Pointer Register
1536 //
1537 if (ChannelNumber < 4) {
1538 DmaMask = R_8237_DMA_WRSMSK_CH0_3;
1539 DmaClear = R_8237_DMA_CBPR_CH0_3;
1540 DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;
1541 } else {
1542 DmaMask = R_8237_DMA_WRSMSK_CH4_7;
1543 DmaClear = R_8237_DMA_CBPR_CH4_7;
1544 DmaChannelMode = R_8237_DMA_CHMODE_CH4_7;
1545 }
1546
1547 Status = WritePort (
1548 This,
1549 DmaMask,
1550 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
1551 );
1552 if (EFI_ERROR (Status)) {
1553 return Status;
1554 }
1555
1556 Status = WritePort (
1557 This,
1558 DmaClear,
1559 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
1560 );
1561 if (EFI_ERROR (Status)) {
1562 return Status;
1563 }
1564
1565 Status = WritePort (This, DmaChannelMode, DmaMode);
1566 if (EFI_ERROR (Status)) {
1567 return Status;
1568 }
1569
1570 Status = WriteDmaPort (
1571 This,
1572 mDmaRegisters[ChannelNumber].Address,
1573 mDmaRegisters[ChannelNumber].Page,
1574 mDmaRegisters[ChannelNumber].Count,
1575 BaseAddress,
1576 Count
1577 );
1578 if (EFI_ERROR (Status)) {
1579 return Status;
1580 }
1581
1582 Status = WritePort (
1583 This,
1584 DmaMask,
1585 (UINT8) (ChannelNumber & 0x03)
1586 );
1587 if (EFI_ERROR (Status)) {
1588 return Status;
1589 }
1590
1591 return EFI_SUCCESS;
1592 }
1593
1594 /**
1595 Maps a memory region for DMA
1596
1597 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1598 @param Operation Indicates the type of DMA (slave or bus master), and if
1599 the DMA operation is going to read or write to system memory.
1600 @param ChannelNumber The slave channel number to use for this DMA operation.
1601 If Operation and ChannelAttributes shows that this device
1602 performs bus mastering DMA, then this field is ignored.
1603 The legal range for this field is 0..7.
1604 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
1605 @param HostAddress The system memory address to map to the device.
1606 @param NumberOfBytes On input the number of bytes to map. On output the number
1607 of bytes that were mapped.
1608 @param DeviceAddress The resulting map address for the bus master device to use
1609 to access the hosts HostAddress.
1610 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
1611
1612 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
1613 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
1614 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
1615 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
1616 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1617 **/
1618 EFI_STATUS
1619 EFIAPI
1620 IsaIoMap (
1621 IN EFI_ISA_IO_PROTOCOL *This,
1622 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
1623 IN UINT8 ChannelNumber OPTIONAL,
1624 IN UINT32 ChannelAttributes,
1625 IN VOID *HostAddress,
1626 IN OUT UINTN *NumberOfBytes,
1627 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
1628 OUT VOID **Mapping
1629 )
1630 {
1631 //
1632 // Check if DMA is supported.
1633 //
1634 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
1635 return EFI_UNSUPPORTED;
1636 }
1637 //
1638 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
1639 // ISA Bus Master.
1640 //
1641 // So we just return EFI_UNSUPPORTED for these functions.
1642 //
1643 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0) {
1644 return IsaIoMapOnlySupportSlaveReadWrite (
1645 This,
1646 Operation,
1647 ChannelNumber,
1648 ChannelAttributes,
1649 HostAddress,
1650 NumberOfBytes,
1651 DeviceAddress,
1652 Mapping
1653 );
1654
1655 } else {
1656 return IsaIoMapFullSupport (
1657 This,
1658 Operation,
1659 ChannelNumber,
1660 ChannelAttributes,
1661 HostAddress,
1662 NumberOfBytes,
1663 DeviceAddress,
1664 Mapping
1665 );
1666 }
1667 }
1668
1669 /**
1670 Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
1671
1672 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1673 @param[in] Type The type allocation to perform.
1674 @param[in] MemoryType The type of memory to allocate.
1675 @param[in] Pages The number of pages to allocate.
1676 @param[out] HostAddress A pointer to store the base address of the allocated range.
1677 @param[in] Attributes The requested bit mask of attributes for the allocated range.
1678
1679 @retval EFI_SUCCESS The requested memory pages were allocated.
1680 @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL
1681 @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified
1682 by HostAddress, Pages, and Type is not available for common buffer use.
1683 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1684 **/
1685 EFI_STATUS
1686 EFIAPI
1687 IsaIoAllocateBuffer (
1688 IN EFI_ISA_IO_PROTOCOL *This,
1689 IN EFI_ALLOCATE_TYPE Type,
1690 IN EFI_MEMORY_TYPE MemoryType,
1691 IN UINTN Pages,
1692 OUT VOID **HostAddress,
1693 IN UINT64 Attributes
1694 )
1695 {
1696 EFI_STATUS Status;
1697 EFI_PHYSICAL_ADDRESS PhysicalAddress;
1698
1699 //
1700 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1701 // ISA Bus Master.
1702 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1703 //
1704 if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
1705 ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
1706 return EFI_UNSUPPORTED;
1707 }
1708
1709 if (HostAddress == NULL) {
1710 return EFI_INVALID_PARAMETER;
1711 }
1712
1713 if (Type < AllocateAnyPages || Type >= MaxAllocateType) {
1714 return EFI_INVALID_PARAMETER;
1715 }
1716 //
1717 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
1718 //
1719 if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {
1720 return EFI_INVALID_PARAMETER;
1721 }
1722
1723 if ((Attributes & ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED)) != 0) {
1724 return EFI_UNSUPPORTED;
1725 }
1726
1727 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (BASE_16MB - 1);
1728 if (Type == AllocateAddress) {
1729 if ((UINTN) (*HostAddress) >= BASE_16MB) {
1730 return EFI_UNSUPPORTED;
1731 } else {
1732 PhysicalAddress = (UINTN) (*HostAddress);
1733 }
1734 }
1735
1736 if (Type == AllocateAnyPages) {
1737 Type = AllocateMaxAddress;
1738 }
1739
1740 Status = gBS->AllocatePages (Type, MemoryType, Pages, &PhysicalAddress);
1741 if (EFI_ERROR (Status)) {
1742 REPORT_STATUS_CODE (
1743 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1744 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
1745 );
1746 return Status;
1747 }
1748
1749 *HostAddress = (VOID *) (UINTN) PhysicalAddress;
1750 return Status;
1751 }
1752
1753 /**
1754 Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
1755
1756 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1757 @param[in] Pages The number of pages to free.
1758 @param[in] HostAddress The base address of the allocated range.
1759
1760 @retval EFI_SUCCESS The requested memory pages were freed.
1761 @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().
1762 **/
1763 EFI_STATUS
1764 EFIAPI
1765 IsaIoFreeBuffer (
1766 IN EFI_ISA_IO_PROTOCOL *This,
1767 IN UINTN Pages,
1768 IN VOID *HostAddress
1769 )
1770 {
1771 EFI_STATUS Status;
1772
1773 //
1774 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1775 // ISA Bus Master.
1776 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1777 //
1778 if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
1779 ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
1780 return EFI_UNSUPPORTED;
1781 }
1782
1783 Status = gBS->FreePages (
1784 (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,
1785 Pages
1786 );
1787 if (EFI_ERROR (Status)) {
1788 REPORT_STATUS_CODE (
1789 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1790 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
1791 );
1792 }
1793
1794 return Status;
1795 }
1796