1 /*
2 * Copyright (C) 2005-2009 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: Generic ISA bus framework
29 *
30 * This is not a normal device, but it can be used as a quick way of adding
31 * most of the common legacy ISA devices to a machine.
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #define BUS_ISA_C
39
40 #include "bus_isa.h"
41 #include "device.h"
42 #include "devices.h"
43 #include "diskimage.h"
44 #include "interrupt.h"
45 #include "machine.h"
46 #include "misc.h"
47
48
49 /*
50 * isa_interrupt_common():
51 */
isa_interrupt_common(struct bus_isa_data * d,int old_isa_assert)52 void isa_interrupt_common(struct bus_isa_data *d, int old_isa_assert)
53 {
54 int new_isa_assert, x;
55
56 /* Any interrupt assertions on PIC2 go to irq 2 on PIC1 */
57 /* (TODO: don't hardcode this here) */
58 if (d->pic2->irr & ~d->pic2->ier)
59 d->pic1->irr |= 0x04;
60 else
61 d->pic1->irr &= ~0x04;
62
63 /* printf("ISA: irr=%02x%02x ier=%02x%02x\n",
64 d->pic2->irr, d->pic1->irr, d->pic2->ier, d->pic1->ier); */
65
66 new_isa_assert = d->pic1->irr & ~d->pic1->ier;
67
68 if (old_isa_assert == new_isa_assert)
69 return;
70
71 if (!new_isa_assert) {
72 INTERRUPT_DEASSERT(d->irq);
73 return;
74 }
75
76 for (x=0; x<16; x++) {
77 if (x == 2)
78 continue;
79
80 if (x < 8 && (d->pic1->irr & ~d->pic1->ier & (1 << x)))
81 break;
82
83 if (x >= 8 && (d->pic2->irr & ~d->pic2->ier & (1 << (x&7))))
84 break;
85 }
86
87 *d->ptr_to_last_int = x;
88
89 INTERRUPT_ASSERT(d->irq);
90 }
91
92
93 /*
94 * isa_interrupt_assert():
95 *
96 * Called whenever an ISA device asserts an interrupt (0..15).
97 */
isa_interrupt_assert(struct interrupt * interrupt)98 void isa_interrupt_assert(struct interrupt *interrupt)
99 {
100 struct bus_isa_data *d = (struct bus_isa_data *) interrupt->extra;
101 int old_isa_assert, line = interrupt->line;
102 int mask = 1 << (line & 7);
103
104 old_isa_assert = d->pic1->irr & ~d->pic1->ier;
105
106 if (line < 8)
107 d->pic1->irr |= mask;
108 else if (d->pic2 != NULL)
109 d->pic2->irr |= mask;
110
111 isa_interrupt_common(d, old_isa_assert);
112 }
113
114
115 /*
116 * isa_interrupt_deassert():
117 *
118 * Called whenever an ISA device deasserts an interrupt (0..15).
119 */
isa_interrupt_deassert(struct interrupt * interrupt)120 void isa_interrupt_deassert(struct interrupt *interrupt)
121 {
122 struct bus_isa_data *d = (struct bus_isa_data *) interrupt->extra;
123 int line = interrupt->line, mask = 1 << (line & 7);
124 int old_irr1 = d->pic1->irr, old_isa_assert;
125
126 old_isa_assert = old_irr1 & ~d->pic1->ier;
127
128 if (line < 8)
129 d->pic1->irr &= ~mask;
130 else if (d->pic2 != NULL)
131 d->pic2->irr &= ~mask;
132
133 /* If IRQ 0 has been cleared, then this is a timer interrupt.
134 Let's ack it here: */
135 if (old_irr1 & 1 && !(d->pic1->irr & 1) &&
136 d->ptr_to_pending_timer_interrupts != NULL &&
137 (*d->ptr_to_pending_timer_interrupts) > 0)
138 (*d->ptr_to_pending_timer_interrupts) --;
139
140 isa_interrupt_common(d, old_isa_assert);
141 }
142
143
144 /*
145 * bus_isa_init():
146 *
147 * Flags are zero or more of the following, ORed together:
148 *
149 * BUS_ISA_EXTERNAL_PIC Don't register/use isa_interrupt_*().
150 * BUS_ISA_IDE0 Include wdc0.
151 * BUS_ISA_IDE1 Include wdc1.
152 * BUS_ISA_FDC Include a floppy controller. (Dummy.)
153 * BUS_ISA_VGA Include old-style (non-PCI) VGA. (*1)
154 * BUS_ISA_VGA_FORCE Include VGA even when running without X11. (*2)
155 * BUS_ISA_PCKBC_FORCE_USE Always assume keyboard console, not serial. (*3)
156 * BUS_ISA_PCKBC_NONPCSTYLE Don't set the pc-style flag for the keyboard.
157 * BUS_ISA_NO_SECOND_PIC Only useful for 8086 XT (pre-AT) emulation. :-)
158 * BUS_ISA_LPTBASE_3BC Set lptbase to 0x3bc instead of 0x378.
159 *
160 * (*1) For machines with a PCI bus, this flag should not be used. Instead, a
161 * PCI VGA card should be added to the PCI bus.
162 *
163 * (*2) For machines where it is easy to select VGA vs serial console during
164 * boot, this flag should not be used. Machines that "always" boot up
165 * in VGA console mode should have it set.
166 *
167 * (*3) Similar to *2 above; machines that always boot up with VGA console
168 * should have this flag set, so that the keyboard is always used.
169 *
170 * The interrupt_base_path is the name of the bus, CPU, or controller onto
171 * which this ISA bus will be attached, e.g. "machine[0].lca" or
172 * "machine[0].cpu[0].pic1".
173 */
bus_isa_init(struct machine * machine,char * interrupt_base_path,uint32_t bus_isa_flags,uint64_t isa_portbase,uint64_t isa_membase)174 struct bus_isa_data *bus_isa_init(struct machine *machine,
175 char *interrupt_base_path, uint32_t bus_isa_flags,
176 uint64_t isa_portbase, uint64_t isa_membase)
177 {
178 struct bus_isa_data *d;
179 char tmpstr[300], tmpstr2[300];
180 int wdc0_irq = 14, wdc1_irq = 15;
181 int i, tmp_handle, kbd_in_use;
182 int lptbase = 0x378;
183
184 CHECK_ALLOCATION(d = (struct bus_isa_data *) malloc(sizeof(struct bus_isa_data)));
185 memset(d, 0, sizeof(struct bus_isa_data));
186
187 d->isa_portbase = isa_portbase;
188 d->isa_membase = isa_membase;
189
190 if (!(bus_isa_flags & BUS_ISA_EXTERNAL_PIC)) {
191 /* Connect to the interrupt which we're interrupting
192 at (usually a CPU): */
193 INTERRUPT_CONNECT(interrupt_base_path, d->irq);
194
195 /* Register the 16 possible ISA interrupts: */
196 for (i=0; i<16; i++) {
197 struct interrupt templ;
198 char name[300];
199 snprintf(name, sizeof(name),
200 "%s.isa.%i", interrupt_base_path, i);
201 memset(&templ, 0, sizeof(templ));
202 templ.line = i;
203 templ.name = name;
204 templ.extra = d;
205 templ.interrupt_assert = isa_interrupt_assert;
206 templ.interrupt_deassert = isa_interrupt_deassert;
207 interrupt_handler_register(&templ);
208 }
209 }
210
211 kbd_in_use = ((bus_isa_flags & BUS_ISA_PCKBC_FORCE_USE) ||
212 (machine->x11_md.in_use))? 1 : 0;
213
214 if (machine->machine_type == MACHINE_PREP) {
215 /* PReP with obio controller has both WDCs on irq 13! */
216 wdc0_irq = wdc1_irq = 13;
217 }
218
219 if (!(bus_isa_flags & BUS_ISA_EXTERNAL_PIC)) {
220 snprintf(tmpstr, sizeof(tmpstr), "8259 irq=%s addr=0x%llx",
221 interrupt_base_path, (long long)(isa_portbase + 0x20));
222 d->pic1 = machine->isa_pic_data.pic1 = (struct pic8259_data *)
223 device_add(machine, tmpstr);
224 d->ptr_to_pending_timer_interrupts =
225 machine->isa_pic_data.pending_timer_interrupts;
226 d->ptr_to_last_int = &machine->isa_pic_data.last_int;
227
228 if (bus_isa_flags & BUS_ISA_NO_SECOND_PIC)
229 bus_isa_flags &= ~BUS_ISA_NO_SECOND_PIC;
230 else {
231 snprintf(tmpstr, sizeof(tmpstr),
232 "8259 irq=%s.isa.2 addr=0x%llx",
233 interrupt_base_path,(long long)(isa_portbase+0xa0));
234 d->pic2 = machine->isa_pic_data.pic2 = (struct pic8259_data *)
235 device_add(machine, tmpstr);
236 }
237 } else {
238 bus_isa_flags &= ~BUS_ISA_EXTERNAL_PIC;
239 }
240
241 snprintf(tmpstr, sizeof(tmpstr), "8253 irq=%s.isa.%i addr=0x%llx "
242 "in_use=0", interrupt_base_path, 0,
243 (long long)(isa_portbase + 0x40));
244 device_add(machine, tmpstr);
245
246 snprintf(tmpstr, sizeof(tmpstr), "pccmos irq=%s.isa.%i addr=0x%llx",
247 interrupt_base_path, 8, (long long)(isa_portbase + 0x70));
248 device_add(machine, tmpstr);
249
250 snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.isa.%i addr=0x%llx "
251 "name2=tty0 in_use=%i", interrupt_base_path, 4,
252 (long long)(isa_portbase + 0x3f8), 1 - kbd_in_use);
253 machine->main_console_handle = (size_t)device_add(machine, tmpstr);
254
255 snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.isa.%i addr=0x%llx "
256 "name2=tty1 in_use=0", interrupt_base_path, 3,
257 (long long)(isa_portbase + 0x2f8));
258 device_add(machine, tmpstr);
259
260 if (bus_isa_flags & BUS_ISA_LPTBASE_3BC) {
261 bus_isa_flags &= ~BUS_ISA_LPTBASE_3BC;
262 lptbase = 0x3bc;
263 }
264
265 snprintf(tmpstr, sizeof(tmpstr), "lpt irq=%s.isa.%i addr=0x%llx "
266 "name2=lpt in_use=0", interrupt_base_path, 7,
267 (long long)(isa_portbase + lptbase));
268 device_add(machine, tmpstr);
269
270 if (bus_isa_flags & BUS_ISA_IDE0) {
271 bus_isa_flags &= ~BUS_ISA_IDE0;
272 snprintf(tmpstr, sizeof(tmpstr), "wdc irq=%s.isa.%i "
273 "addr=0x%llx", interrupt_base_path, wdc0_irq,
274 (long long)(isa_portbase + 0x1f0));
275 if (diskimage_exist(machine, 0, DISKIMAGE_IDE) ||
276 diskimage_exist(machine, 1, DISKIMAGE_IDE))
277 device_add(machine, tmpstr);
278 }
279
280 if (bus_isa_flags & BUS_ISA_IDE1) {
281 bus_isa_flags &= ~BUS_ISA_IDE1;
282 snprintf(tmpstr, sizeof(tmpstr), "wdc irq=%s.isa.%i "
283 "addr=0x%llx", interrupt_base_path, wdc1_irq,
284 (long long)(isa_portbase + 0x170));
285 if (diskimage_exist(machine, 2, DISKIMAGE_IDE) ||
286 diskimage_exist(machine, 3, DISKIMAGE_IDE))
287 device_add(machine, tmpstr);
288 }
289
290 if (bus_isa_flags & BUS_ISA_FDC) {
291 bus_isa_flags &= ~BUS_ISA_FDC;
292 snprintf(tmpstr, sizeof(tmpstr), "fdc irq=%s.isa.%i "
293 "addr=0x%llx", interrupt_base_path, 6,
294 (long long)(isa_portbase + 0x3f0));
295 device_add(machine, tmpstr);
296 }
297
298 if (bus_isa_flags & BUS_ISA_VGA) {
299 if (machine->x11_md.in_use || bus_isa_flags & BUS_ISA_VGA_FORCE)
300 dev_vga_init(machine, machine->memory,
301 isa_membase + 0xa0000, isa_portbase + 0x3c0,
302 machine->machine_name);
303 bus_isa_flags &= ~(BUS_ISA_VGA | BUS_ISA_VGA_FORCE);
304 }
305
306 snprintf(tmpstr, sizeof(tmpstr), "%s.isa.1", interrupt_base_path);
307 snprintf(tmpstr2, sizeof(tmpstr2), "%s.isa.12", interrupt_base_path);
308 tmp_handle = dev_pckbc_init(machine, machine->memory,
309 isa_portbase + 0x60, PCKBC_8042, tmpstr, tmpstr2,
310 kbd_in_use, bus_isa_flags & BUS_ISA_PCKBC_NONPCSTYLE? 0 : 1);
311
312 if (kbd_in_use)
313 machine->main_console_handle = tmp_handle;
314
315 bus_isa_flags &= ~(BUS_ISA_PCKBC_NONPCSTYLE | BUS_ISA_PCKBC_FORCE_USE);
316
317 if (bus_isa_flags != 0)
318 fatal("WARNING! bus_isa(): unimplemented bus_isa_flags 0x%x\n",
319 bus_isa_flags);
320
321 return d;
322 }
323
324