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