1 | /* |
---|
2 | * pic.h - Programmable Interrupt Controller driver implementation |
---|
3 | * |
---|
4 | * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless |
---|
5 | * Copyright (c) 2011,2012 UPMC Sorbonne Universites |
---|
6 | * |
---|
7 | * This file is part of ALMOS-kernel. |
---|
8 | * |
---|
9 | * ALMOS-kernel is free software; you can redistribute it and/or modify it |
---|
10 | * under the terms of the GNU General Public License as published by |
---|
11 | * the Free Software Foundation; version 2.0 of the License. |
---|
12 | * |
---|
13 | * ALMOS-kernel is distributed in the hope that it will be useful, but |
---|
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
16 | * General Public License for more details. |
---|
17 | * |
---|
18 | * You should have received a copy of the GNU General Public License |
---|
19 | * along with ALMOS-kernel; if not, write to the Free Software Foundation, |
---|
20 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
---|
21 | */ |
---|
22 | |
---|
23 | #include <types.h> |
---|
24 | #include <cpu.h> |
---|
25 | #include <chdev.h> |
---|
26 | #include <driver.h> |
---|
27 | #include <cpu-io.h> |
---|
28 | #include <kmem.h> |
---|
29 | #include <string.h> |
---|
30 | #include <kdmsg.h> |
---|
31 | #include <pic.h> |
---|
32 | |
---|
33 | #define PIC_PRIMARY_PIO 0x20 |
---|
34 | #define PIC_SECONDARY_PIO 0xA0 |
---|
35 | |
---|
36 | struct irq_action_s *irq_vector[PIC_IRQ_MAX]; |
---|
37 | |
---|
38 | static void pic_set_mask(struct device_s *pic, uint_t mask, uint_t type, uint_t output_irq) |
---|
39 | { |
---|
40 | switch(type) |
---|
41 | { |
---|
42 | case 0: |
---|
43 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_IMR_REG, ~(mask & 0xFF)); |
---|
44 | break; |
---|
45 | case 1: |
---|
46 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_IMR_REG, ~(mask & 0xFF)); |
---|
47 | break; |
---|
48 | default: |
---|
49 | printk(ERROR, "ERROR: Un expected mask value, PIC has 16 IRQ line only [ type 0 & 1 ]"); |
---|
50 | } |
---|
51 | } |
---|
52 | |
---|
53 | static uint_t pic_get_mask(struct device_s *icu, uint_t type, uint_t output_irq) |
---|
54 | { |
---|
55 | register uint_t mask = ~0; |
---|
56 | |
---|
57 | switch(type) |
---|
58 | { |
---|
59 | case 0: |
---|
60 | mask = cpu_io_in8(PIC_PRIMARY_PIO + PIC_IMR_REG); |
---|
61 | break; |
---|
62 | case 1: |
---|
63 | mask = cpu_io_in8(PIC_SECONDARY_PIO + PIC_IMR_REG); |
---|
64 | break; |
---|
65 | default: |
---|
66 | printk(ERROR, "ERROR: Un expected mask value, PIC has 16 IRQ line only [ type 0 & 1 ]"); |
---|
67 | } |
---|
68 | |
---|
69 | return ((~mask) & 0xFF); |
---|
70 | } |
---|
71 | |
---|
72 | static sint_t pic_get_highest_irq(struct device_s *icu, uint_t type, uint_t output_irq) |
---|
73 | { |
---|
74 | return -1; |
---|
75 | } |
---|
76 | |
---|
77 | static void pic_default_irq_handler(struct irq_action_s *action) |
---|
78 | { |
---|
79 | register unsigned int irq_num = (unsigned int) action->data; |
---|
80 | register unsigned int cpu_id = cpu_get_id(); |
---|
81 | |
---|
82 | isr_dmsg(WARNING, "WARNING: No ISR registered handler for IRQ %d on CPU %d\n",irq_num, cpu_id); |
---|
83 | } |
---|
84 | |
---|
85 | static void pic_ICWs() |
---|
86 | { |
---|
87 | /* ICW1 */ |
---|
88 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_CMD_REG, 0x11); /* Put Primary PIC in Initialization mode with ICW4 enabled */ |
---|
89 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_CMD_REG, 0x11); /* Same ICW1 as Primary */ |
---|
90 | |
---|
91 | /* ICW2 */ |
---|
92 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_DATA_REG, 0x20); /* Set Primary PIC's interrupt vector base number */ |
---|
93 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_DATA_REG, 0x28); /* Set Secondary PIC's interrupt vector base number */ |
---|
94 | |
---|
95 | /* ICW3 */ |
---|
96 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_DATA_REG, 0x4); /* Informe Primary that Secondary is connected to line 2 */ |
---|
97 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_DATA_REG, 0x2); /* Inform Secondary of it's identification */ |
---|
98 | |
---|
99 | /* ICW4 */ |
---|
100 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_DATA_REG, 0x1); /* Put Primary in x86 mode */ |
---|
101 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_DATA_REG, 0x1); /* Put Primary in x86 mode */ |
---|
102 | |
---|
103 | /* CLEAR DATA REGISTERS */ |
---|
104 | cpu_io_out8(PIC_PRIMARY_PIO + PIC_DATA_REG, 0); |
---|
105 | cpu_io_out8(PIC_SECONDARY_PIO + PIC_DATA_REG, 0); |
---|
106 | } |
---|
107 | |
---|
108 | |
---|
109 | void pic_irq_handler(struct irq_action_s *action) |
---|
110 | { |
---|
111 | register uint_t irq = (uint_t)action->data; |
---|
112 | irq_vector[irq]->data = (void*)irq; |
---|
113 | irq_vector[irq]->irq_handler(irq_vector[irq]); |
---|
114 | } |
---|
115 | |
---|
116 | void ibmpc_pic_init(struct device_s *pic, void *base, uint_t irq) |
---|
117 | { |
---|
118 | register uint_t _irq; |
---|
119 | struct irq_action_s *action_ptr; |
---|
120 | |
---|
121 | pic->base = base; |
---|
122 | pic->type = DEV_ICU; |
---|
123 | pic->action.irq_handler = &pic_irq_handler; |
---|
124 | |
---|
125 | strcpy(pic->name, "PIC"); |
---|
126 | metafs_init(&pic->node, pic->name); |
---|
127 | |
---|
128 | pic->op.icu.set_mask = &pic_set_mask; |
---|
129 | pic->op.icu.get_mask = &pic_get_mask; |
---|
130 | pic->op.icu.get_highest_irq = &pic_get_highest_irq; |
---|
131 | |
---|
132 | for(_irq=0; _irq < PIC_IRQ_MAX; _irq++) |
---|
133 | { |
---|
134 | action_ptr = kbootMem_calloc(sizeof(*action_ptr)); |
---|
135 | action_ptr->dev = pic; |
---|
136 | action_ptr->irq_handler = &pic_default_irq_handler; |
---|
137 | action_ptr->data = (void*) _irq; |
---|
138 | irq_vector[_irq] = action_ptr; |
---|
139 | } |
---|
140 | |
---|
141 | pic_ICWs(); |
---|
142 | } |
---|
143 | |
---|
144 | void ibmpc_pic_bind(struct device_s *pic, struct device_s *dev) |
---|
145 | { |
---|
146 | assert(dev->irq < PIC_IRQ_MAX && "Unexpected IRQ, connot bind this device"); |
---|
147 | |
---|
148 | if(dev->irq < PIC_IRQ_MAX) |
---|
149 | { |
---|
150 | irq_vector[dev->irq] = &dev->action; |
---|
151 | metafs_register(&pic->node, &dev->node); |
---|
152 | } |
---|
153 | } |
---|