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