]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/Legacy8259Dxe/8259.c
Add legacy8259 module for PcAt.
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / Legacy8259Dxe / 8259.c
CommitLineData
1166d068 1/**@file\r
2 This contains the installation function for the driver.\r
3 \r
4Copyright (c) 2005 - 2007, Intel Corporation \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
9 \r
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
12\r
13**/\r
14\r
15#include "8259.h"\r
16\r
17//\r
18// Global for the CPU I/O Protocol that is consumed by this driver\r
19//\r
20EFI_CPU_IO_PROTOCOL *mCpuIo;\r
21\r
22//\r
23// Global for the Legacy 8259 Protocol that is prodiced by this driver\r
24//\r
25EFI_LEGACY_8259_PROTOCOL m8259 = {\r
26 Interrupt8259SetVectorBase,\r
27 Interrupt8259GetMask,\r
28 Interrupt8259SetMask,\r
29 Interrupt8259SetMode,\r
30 Interrupt8259GetVector,\r
31 Interrupt8259EnableIrq,\r
32 Interrupt8259DisableIrq,\r
33 Interrupt8259GetInterruptLine,\r
34 Interrupt8259EndOfInterrupt\r
35};\r
36\r
37//\r
38// Global for the handle that the Legacy 8259 Protocol is installed\r
39//\r
40EFI_HANDLE m8259Handle = NULL;\r
41\r
42UINT8 mMasterBase = 0xff;\r
43UINT8 mSlaveBase = 0xff;\r
44EFI_8259_MODE mMode = Efi8259ProtectedMode;\r
45UINT16 mProtectedModeMask = 0xffff;\r
46UINT16 mLegacyModeMask = 0x06b8;\r
47UINT16 mProtectedModeEdgeLevel = 0x0000;\r
48UINT16 mLegacyModeEdgeLevel = 0x0000;\r
49\r
50//\r
51// Worker Functions\r
52//\r
53VOID\r
54IoWrite8 (\r
55 IN UINT16 Port,\r
56 IN UINT8 Value\r
57 )\r
58/**\r
59\r
60 Routine Description:\r
61 Writes an I/O port using the CPU I/O Protocol\r
62\r
63 Arguments:\r
64 Register - I/O Port to write\r
65 Value - The 8 bit value to write to Port\r
66\r
67 Returns:\r
68 None\r
69\r
70**/\r
71{\r
72 mCpuIo->Io.Write (mCpuIo, EfiCpuIoWidthUint8, Port, 1, &Value);\r
73}\r
74\r
75UINT8\r
76IoRead8 (\r
77 IN UINT16 Port\r
78 )\r
79/**\r
80\r
81 Routine Description:\r
82 Writes an I/O port using the CPU I/O Protocol\r
83\r
84 Arguments:\r
85 Register - I/O Port to write\r
86 Value - The 8 bit value to write to Port\r
87\r
88 Returns:\r
89 None\r
90\r
91**/\r
92{\r
93 UINT8 Value;\r
94\r
95 mCpuIo->Io.Read (mCpuIo, EfiCpuIoWidthUint8, Port, 1, &Value);\r
96 return Value;\r
97}\r
98\r
99VOID\r
100Interrupt8259WriteMask (\r
101 IN UINT16 Mask,\r
102 IN UINT16 EdgeLevel\r
103 )\r
104/**\r
105\r
106 Routine Description:\r
107 Sets the 8250 mask to the valud specified by Mask\r
108\r
109 Arguments:\r
110 Mask - A 16 bit valute that represents the master and slave mask values\r
111\r
112 Returns:\r
113 None\r
114\r
115**/\r
116// TODO: EdgeLevel - add argument and description to function comment\r
117{\r
118 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, (UINT8) Mask);\r
119 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, (UINT8) (Mask >> 8));\r
120 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER, (UINT8) EdgeLevel);\r
121 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE, (UINT8) (EdgeLevel >> 8));\r
122}\r
123\r
124VOID\r
125Interrupt8259ReadMask (\r
126 IN UINT16 *Mask,\r
127 IN UINT16 *EdgeLevel\r
128 )\r
129/**\r
130\r
131 Routine Description:\r
132 Sets the 8250 mask to the valud specified by Mask\r
133\r
134 Arguments:\r
135 Mask - A 16 bit valute that represents the master and slave mask values\r
136\r
137 Returns:\r
138 None\r
139\r
140**/\r
141// TODO: EdgeLevel - add argument and description to function comment\r
142{\r
143 if (Mask != NULL) {\r
144 *Mask = (UINT16) (IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER) | (IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE) << 8));\r
145 }\r
146\r
147 if (EdgeLevel != NULL) {\r
148 *EdgeLevel = (UINT16)\r
149 (\r
150 IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER) |\r
151 (IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE) << 8)\r
152 );\r
153 }\r
154}\r
155//\r
156// Legacy 8259 Protocol Interface Function\r
157//\r
158EFI_STATUS\r
159EFIAPI\r
160Interrupt8259SetVectorBase (\r
161 IN EFI_LEGACY_8259_PROTOCOL *This,\r
162 IN UINT8 MasterBase,\r
163 IN UINT8 SlaveBase\r
164 )\r
165/**\r
166\r
167 Routine Description:\r
168 Sets the base vector for the 8250 Master and Slave interrupt controllers\r
169\r
170 Arguments:\r
171 This - Protocol instance pointer.\r
172 MasterBase - Base vector of the 8259 Master\r
173 SlaveBase - Base vector of the 8259 Slave\r
174\r
175 Returns:\r
176 EFI_SUCCESS - 8259 programmed\r
177\r
178**/\r
179{\r
180 UINT8 Mask;\r
181\r
182 if (SlaveBase != mSlaveBase) {\r
183 mSlaveBase = SlaveBase;\r
184\r
185 //\r
186 // Initialize Slave interrupt controller.\r
187 //\r
188 Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE);\r
189 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, 0x11);\r
190 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, mSlaveBase);\r
191 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x02);\r
192 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x01);\r
193 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, Mask);\r
194 }\r
195\r
196 if (MasterBase != mMasterBase) {\r
197 mMasterBase = MasterBase;\r
198\r
199 //\r
200 // Initialize Master interrupt controller.\r
201 //\r
202 Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER);\r
203 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, 0x11);\r
204 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, mMasterBase);\r
205 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x04);\r
206 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x01);\r
207 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, Mask);\r
208 }\r
209\r
210 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, 0x20);\r
211 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, 0x20);\r
212\r
213 return EFI_SUCCESS;\r
214}\r
215\r
216EFI_STATUS\r
217EFIAPI\r
218Interrupt8259GetMask (\r
219 IN EFI_LEGACY_8259_PROTOCOL * This,\r
220 OUT UINT16 *LegacyMask, OPTIONAL\r
221 OUT UINT16 *LegacyEdgeLevel, OPTIONAL\r
222 OUT UINT16 *ProtectedMask, OPTIONAL\r
223 OUT UINT16 *ProtectedEdgeLevel OPTIONAL\r
224 )\r
225/**\r
226\r
227 Routine Description:\r
228 Get the 8259 master and slave address that maps IRQ to processor interrupt \r
229 vector number. Get the Context of the device including the state of the\r
230 interrupt mask.\r
231\r
232 Arguments:\r
233 This - Protocol instance pointer.\r
234\r
235 Returns:\r
236 EFI_SUCCESS - 8259 programmed\r
237 EFI_DEVICE_ERROR - Error writting to 8259\r
238\r
239**/\r
240// TODO: LegacyMask - add argument and description to function comment\r
241// TODO: LegacyEdgeLevel - add argument and description to function comment\r
242// TODO: ProtectedMask - add argument and description to function comment\r
243// TODO: ProtectedEdgeLevel - add argument and description to function comment\r
244{\r
245 if (LegacyMask != NULL) {\r
246 *LegacyMask = mLegacyModeMask;\r
247 }\r
248\r
249 if (LegacyEdgeLevel != NULL) {\r
250 *LegacyEdgeLevel = mLegacyModeEdgeLevel;\r
251 }\r
252\r
253 if (ProtectedMask != NULL) {\r
254 *ProtectedMask = mProtectedModeMask;\r
255 }\r
256\r
257 if (ProtectedEdgeLevel != NULL) {\r
258 *ProtectedEdgeLevel = mProtectedModeEdgeLevel;\r
259 }\r
260\r
261 return EFI_SUCCESS;\r
262}\r
263\r
264EFI_STATUS\r
265EFIAPI\r
266Interrupt8259SetMask (\r
267 IN EFI_LEGACY_8259_PROTOCOL * This,\r
268 IN UINT16 *LegacyMask, OPTIONAL\r
269 IN UINT16 *LegacyEdgeLevel, OPTIONAL\r
270 IN UINT16 *ProtectedMask, OPTIONAL\r
271 IN UINT16 *ProtectedEdgeLevel OPTIONAL\r
272 )\r
273/**\r
274\r
275 Routine Description:\r
276 Set the 8259 interrupt and edge/level masks for legacy and/or protected \r
277 mode operation. This routine does not touch the hardware but only the\r
278 RAM copies of the masks.\r
279\r
280 Arguments:\r
281 This - Protocol instance pointer.\r
282\r
283 Returns:\r
284 EFI_SUCCESS - 8259 masks updated\r
285\r
286**/\r
287// TODO: LegacyMask - add argument and description to function comment\r
288// TODO: LegacyEdgeLevel - add argument and description to function comment\r
289// TODO: ProtectedMask - add argument and description to function comment\r
290// TODO: ProtectedEdgeLevel - add argument and description to function comment\r
291{\r
292 if (LegacyMask != NULL) {\r
293 mLegacyModeMask = *LegacyMask;\r
294 }\r
295\r
296 if (LegacyEdgeLevel != NULL) {\r
297 mLegacyModeEdgeLevel = *LegacyEdgeLevel;\r
298 }\r
299\r
300 if (ProtectedMask != NULL) {\r
301 mProtectedModeMask = *ProtectedMask;\r
302 }\r
303\r
304 if (ProtectedEdgeLevel != NULL) {\r
305 mProtectedModeEdgeLevel = *ProtectedEdgeLevel;\r
306 }\r
307\r
308 return EFI_SUCCESS;\r
309}\r
310\r
311EFI_STATUS\r
312EFIAPI\r
313Interrupt8259SetMode (\r
314 IN EFI_LEGACY_8259_PROTOCOL * This,\r
315 IN EFI_8259_MODE Mode,\r
316 IN UINT16 *Mask, OPTIONAL\r
317 IN UINT16 *EdgeLevel OPTIONAL\r
318 )\r
319/**\r
320\r
321 Routine Description:\r
322 Set the 8259 master and slave address that maps IRQ to processor interrupt \r
323 vector number. Restore the Context of the device, so that the interrupt\r
324 mask is put back in it's previous mode.\r
325\r
326 Arguments:\r
327 This - Protocol instance pointer.\r
328 Mode - \r
329 Mask -\r
330\r
331 Returns:\r
332 EFI_SUCCESS - 8259 programmed\r
333 EFI_DEVICE_ERROR - Error writting to 8259\r
334\r
335**/\r
336// TODO: EdgeLevel - add argument and description to function comment\r
337// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
338{\r
339 if (Mode == mMode) {\r
340 return EFI_SUCCESS;\r
341 }\r
342\r
343 if (Mode == Efi8259LegacyMode) {\r
344 //\r
345 // Save the protected mode mask\r
346 //\r
347 Interrupt8259ReadMask (&mProtectedModeMask, &mProtectedModeEdgeLevel);\r
348\r
349 if (Mask != NULL) {\r
350 //\r
351 // Update the Mask for the new mode\r
352 //\r
353 mLegacyModeMask = *Mask;\r
354 }\r
355\r
356 if (EdgeLevel != NULL) {\r
357 //\r
358 // Update the Edge/Level triggered mask for the new mode\r
359 //\r
360 mLegacyModeEdgeLevel = *EdgeLevel;\r
361 }\r
362\r
363 mMode = Mode;\r
364\r
365 //\r
366 // Set 8259 Vector Base\r
367 //\r
368 //\r
369 Interrupt8259SetVectorBase (This, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);\r
370\r
371 //\r
372 // Enable Interrupts\r
373 //\r
374 Interrupt8259WriteMask (mLegacyModeMask, mLegacyModeEdgeLevel);\r
375\r
376 return EFI_SUCCESS;\r
377 }\r
378\r
379 if (Mode == Efi8259ProtectedMode) {\r
380 //\r
381 // Save the legacy mode mask\r
382 //\r
383 Interrupt8259ReadMask (&mLegacyModeMask, &mLegacyModeEdgeLevel);\r
384 //\r
385 // Always force Timer to be enabled after return from 16-bit code.\r
386 // This always insures that on next entry, timer is counting.\r
387 //\r
388 mLegacyModeMask &= 0xFFFE;\r
389\r
390 if (Mask != NULL) {\r
391 //\r
392 // Update the Mask for the new mode\r
393 //\r
394 mProtectedModeMask = *Mask;\r
395 }\r
396\r
397 if (EdgeLevel != NULL) {\r
398 //\r
399 // Update the Edge/Level triggered mask for the new mode\r
400 //\r
401 mProtectedModeEdgeLevel = *EdgeLevel;\r
402 }\r
403\r
404 mMode = Mode;\r
405\r
406 //\r
407 // Set 8259 Vector Base\r
408 //\r
409 //\r
410 Interrupt8259SetVectorBase (This, PROTECTED_MODE_BASE_VECTOR_MASTER, PROTECTED_MODE_BASE_VECTOR_SLAVE);\r
411\r
412 //\r
413 // Enable Interrupts\r
414 //\r
415 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);\r
416\r
417 return EFI_SUCCESS;\r
418 }\r
419\r
420 return EFI_INVALID_PARAMETER;\r
421}\r
422\r
423EFI_STATUS\r
424EFIAPI\r
425Interrupt8259GetVector (\r
426 IN EFI_LEGACY_8259_PROTOCOL *This,\r
427 IN EFI_8259_IRQ Irq,\r
428 OUT UINT8 *Vector\r
429 )\r
430/**\r
431\r
432 Routine Description:\r
433 Convert from IRQ to processor interrupt vector number.\r
434\r
435 Arguments:\r
436 This - Protocol instance pointer.\r
437 Irq - 8259 IRQ0 - IRQ15\r
438 Vector - Processor vector number that matches Irq\r
439\r
440 Returns:\r
441 EFI_SUCCESS - The Vector matching Irq is returned\r
442 EFI_INVALID_PARAMETER - Irq not valid\r
443\r
444**/\r
445{\r
446 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {\r
447 return EFI_INVALID_PARAMETER;\r
448 }\r
449\r
450 if (Irq <= Efi8259Irq7) {\r
451 *Vector = (UINT8) (mMasterBase + Irq);\r
452 } else {\r
453 *Vector = (UINT8) (mSlaveBase + (Irq - Efi8259Irq8));\r
454 }\r
455\r
456 return EFI_SUCCESS;\r
457}\r
458\r
459EFI_STATUS\r
460EFIAPI\r
461Interrupt8259EnableIrq (\r
462 IN EFI_LEGACY_8259_PROTOCOL *This,\r
463 IN EFI_8259_IRQ Irq,\r
464 IN BOOLEAN LevelTriggered\r
465 )\r
466/**\r
467\r
468 Routine Description:\r
469 Enable Irq by unmasking interrupt in 8259\r
470\r
471 Arguments:\r
472 This - Protocol instance pointer.\r
473 Irq - 8259 IRQ0 - IRQ15\r
474\r
475 Returns:\r
476 EFI_SUCCESS - Irq enabled on 8259\r
477 EFI_INVALID_PARAMETER - Irq not valid\r
478\r
479**/\r
480// TODO: LevelTriggered - add argument and description to function comment\r
481{\r
482 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {\r
483 return EFI_INVALID_PARAMETER;\r
484 }\r
485\r
486 mProtectedModeMask &= ~(1 << Irq);\r
487 if (LevelTriggered) {\r
488 mProtectedModeEdgeLevel |= (1 << Irq);\r
489 } else {\r
490 mProtectedModeEdgeLevel &= ~(1 << Irq);\r
491 }\r
492\r
493 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);\r
494\r
495 return EFI_SUCCESS;\r
496}\r
497\r
498EFI_STATUS\r
499EFIAPI\r
500Interrupt8259DisableIrq (\r
501 IN EFI_LEGACY_8259_PROTOCOL *This,\r
502 IN EFI_8259_IRQ Irq\r
503 )\r
504/**\r
505\r
506 Routine Description:\r
507 Disable Irq by masking interrupt in 8259\r
508\r
509 Arguments:\r
510 This - Protocol instance pointer.\r
511 Irq - 8259 IRQ0 - IRQ15\r
512\r
513 Returns:\r
514 EFI_SUCCESS - Irq disabled on 8259\r
515 EFI_INVALID_PARAMETER - Irq not valid\r
516\r
517**/\r
518{\r
519 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {\r
520 return EFI_INVALID_PARAMETER;\r
521 }\r
522\r
523 mProtectedModeMask |= (1 << Irq);\r
524 mProtectedModeEdgeLevel &= ~(1 << Irq);\r
525\r
526 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);\r
527\r
528 return EFI_SUCCESS;\r
529}\r
530\r
531EFI_STATUS\r
532EFIAPI\r
533Interrupt8259GetInterruptLine (\r
534 IN EFI_LEGACY_8259_PROTOCOL *This,\r
535 IN EFI_HANDLE PciHandle,\r
536 OUT UINT8 *Vector\r
537 )\r
538/**\r
539\r
540 Routine Description:\r
541 PciHandle represents a PCI config space of a PCI function. Vector \r
542 represents Interrupt Pin (from PCI config space) and it is the data\r
543 that is programmed into the Interrupt Line (from the PCI config space)\r
544 register.\r
545\r
546 Arguments:\r
547 This - Protocol instance pointer.\r
548 PciHandle - PCI function to return vector for \r
549 Vector - Vector for fucntion that matches \r
550\r
551 Returns:\r
552 EFI_SUCCESS - A valid Vector is returned\r
553 EFI_INVALID_PARAMETER - PciHandle not valid\r
554\r
555**/\r
556{\r
557 return EFI_UNSUPPORTED;\r
558}\r
559\r
560EFI_STATUS\r
561EFIAPI\r
562Interrupt8259EndOfInterrupt (\r
563 IN EFI_LEGACY_8259_PROTOCOL *This,\r
564 IN EFI_8259_IRQ Irq\r
565 )\r
566/**\r
567\r
568 Routine Description:\r
569 Send an EOI to 8259\r
570\r
571 Arguments:\r
572 This - Protocol instance pointer.\r
573 Irq - 8259 IRQ0 - IRQ15\r
574\r
575 Returns:\r
576 EFI_SUCCESS - EOI successfully sent to 8259\r
577 EFI_INVALID_PARAMETER - Irq not valid\r
578\r
579**/\r
580{\r
581 if (Irq < Efi8259Irq0 || Irq > Efi8259Irq15) {\r
582 return EFI_INVALID_PARAMETER;\r
583 }\r
584\r
585 if (Irq >= Efi8259Irq8) {\r
586 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, LEGACY_8259_EOI);\r
587 }\r
588\r
589 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, LEGACY_8259_EOI);\r
590\r
591 return EFI_SUCCESS;\r
592}\r
593\r
594//\r
595// Legacy 8259 Driver Entry Point\r
596//\r
597EFI_STATUS\r
598EFIAPI\r
599Install8259 (\r
600 IN EFI_HANDLE ImageHandle,\r
601 IN EFI_SYSTEM_TABLE *SystemTable\r
602 )\r
603/**\r
604\r
605Routine Description:\r
606 \r
607\r
608Arguments:\r
609\r
610 (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)\r
611\r
612Returns:\r
613\r
614 EFI_SUCCESS - Legacy 8259 Protocol Installed\r
615\r
616**/\r
617// TODO: ImageHandle - add argument and description to function comment\r
618// TODO: SystemTable - add argument and description to function comment\r
619{\r
620 EFI_STATUS Status;\r
621 EFI_8259_IRQ Irq;\r
622\r
623 //\r
624 // Find the CPU I/O Protocol\r
625 //\r
626 Status = gBS->LocateProtocol (&gEfiCpuIoProtocolGuid, NULL, (VOID **) &mCpuIo);\r
627 ASSERT_EFI_ERROR (Status);\r
628\r
629 //\r
630 // Clear all pending interrupt\r
631 //\r
632 for (Irq = Efi8259Irq0; Irq <= Efi8259Irq15; Irq++) {\r
633 Interrupt8259EndOfInterrupt (&m8259, Irq);\r
634 }\r
635\r
636 //\r
637 // Set the 8259 Master base to 0x68 and the 8259 Slave base to 0x70\r
638 //\r
639 Status = Interrupt8259SetVectorBase (&m8259, PROTECTED_MODE_BASE_VECTOR_MASTER, PROTECTED_MODE_BASE_VECTOR_SLAVE);\r
640\r
641 //\r
642 // Set all 8259 interrupts to edge triggered and disabled\r
643 //\r
644 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);\r
645\r
646 //\r
647 // Install 8259 Protocol onto a new handle\r
648 //\r
649 Status = gBS->InstallProtocolInterface (\r
650 &m8259Handle,\r
651 &gEfiLegacy8259ProtocolGuid,\r
652 EFI_NATIVE_INTERFACE,\r
653 &m8259\r
654 );\r
655\r
656 return Status;\r
657}\r
658\r