149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini * QEMU 8259 interrupt controller emulation
349ab747fSPaolo Bonzini *
449ab747fSPaolo Bonzini * Copyright (c) 2003-2004 Fabrice Bellard
549ab747fSPaolo Bonzini *
649ab747fSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy
749ab747fSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal
849ab747fSPaolo Bonzini * in the Software without restriction, including without limitation the rights
949ab747fSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1049ab747fSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is
1149ab747fSPaolo Bonzini * furnished to do so, subject to the following conditions:
1249ab747fSPaolo Bonzini *
1349ab747fSPaolo Bonzini * The above copyright notice and this permission notice shall be included in
1449ab747fSPaolo Bonzini * all copies or substantial portions of the Software.
1549ab747fSPaolo Bonzini *
1649ab747fSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1749ab747fSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1849ab747fSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1949ab747fSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2049ab747fSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2149ab747fSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2249ab747fSPaolo Bonzini * THE SOFTWARE.
2349ab747fSPaolo Bonzini */
2464552b6bSMarkus Armbruster
2590191d07SPeter Maydell #include "qemu/osdep.h"
26852c27e2SPaolo Bonzini #include "hw/intc/i8259.h"
2764552b6bSMarkus Armbruster #include "hw/irq.h"
2849ab747fSPaolo Bonzini #include "hw/isa/isa.h"
2949ab747fSPaolo Bonzini #include "qemu/timer.h"
3003dd024fSPaolo Bonzini #include "qemu/log.h"
3149ab747fSPaolo Bonzini #include "hw/isa/i8259_internal.h"
320880a873SPeter Xu #include "trace.h"
33db1015e9SEduardo Habkost #include "qom/object.h"
3449ab747fSPaolo Bonzini
3549ab747fSPaolo Bonzini /* debug PIC */
3649ab747fSPaolo Bonzini //#define DEBUG_PIC
3749ab747fSPaolo Bonzini
3849ab747fSPaolo Bonzini //#define DEBUG_IRQ_LATENCY
3949ab747fSPaolo Bonzini
40d1eebf4eSAndreas Färber #define TYPE_I8259 "isa-i8259"
41db1015e9SEduardo Habkost typedef struct PICClass PICClass;
428110fa1dSEduardo Habkost DECLARE_CLASS_CHECKERS(PICClass, PIC,
438110fa1dSEduardo Habkost TYPE_I8259)
44d2628b7dSAndreas Färber
45d2628b7dSAndreas Färber /**
46d2628b7dSAndreas Färber * PICClass:
47d2628b7dSAndreas Färber * @parent_realize: The parent's realizefn.
48d2628b7dSAndreas Färber */
49db1015e9SEduardo Habkost struct PICClass {
50d2628b7dSAndreas Färber PICCommonClass parent_class;
51d2628b7dSAndreas Färber
52d2628b7dSAndreas Färber DeviceRealize parent_realize;
53db1015e9SEduardo Habkost };
54d1eebf4eSAndreas Färber
5549ab747fSPaolo Bonzini #ifdef DEBUG_IRQ_LATENCY
5649ab747fSPaolo Bonzini static int64_t irq_time[16];
5749ab747fSPaolo Bonzini #endif
582aaf0ec7SBernhard Beschow PICCommonState *isa_pic;
5949ab747fSPaolo Bonzini static PICCommonState *slave_pic;
6049ab747fSPaolo Bonzini
6149ab747fSPaolo Bonzini /* return the highest priority found in mask (highest = smallest
6249ab747fSPaolo Bonzini number). Return 8 if no irq */
get_priority(PICCommonState * s,int mask)6349ab747fSPaolo Bonzini static int get_priority(PICCommonState *s, int mask)
6449ab747fSPaolo Bonzini {
6549ab747fSPaolo Bonzini int priority;
6649ab747fSPaolo Bonzini
6749ab747fSPaolo Bonzini if (mask == 0) {
6849ab747fSPaolo Bonzini return 8;
6949ab747fSPaolo Bonzini }
7049ab747fSPaolo Bonzini priority = 0;
7149ab747fSPaolo Bonzini while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) {
7249ab747fSPaolo Bonzini priority++;
7349ab747fSPaolo Bonzini }
7449ab747fSPaolo Bonzini return priority;
7549ab747fSPaolo Bonzini }
7649ab747fSPaolo Bonzini
7749ab747fSPaolo Bonzini /* return the pic wanted interrupt. return -1 if none */
pic_get_irq(PICCommonState * s)7849ab747fSPaolo Bonzini static int pic_get_irq(PICCommonState *s)
7949ab747fSPaolo Bonzini {
8049ab747fSPaolo Bonzini int mask, cur_priority, priority;
8149ab747fSPaolo Bonzini
8249ab747fSPaolo Bonzini mask = s->irr & ~s->imr;
8349ab747fSPaolo Bonzini priority = get_priority(s, mask);
8449ab747fSPaolo Bonzini if (priority == 8) {
8549ab747fSPaolo Bonzini return -1;
8649ab747fSPaolo Bonzini }
8749ab747fSPaolo Bonzini /* compute current priority. If special fully nested mode on the
8849ab747fSPaolo Bonzini master, the IRQ coming from the slave is not taken into account
8949ab747fSPaolo Bonzini for the priority computation. */
9049ab747fSPaolo Bonzini mask = s->isr;
9149ab747fSPaolo Bonzini if (s->special_mask) {
9249ab747fSPaolo Bonzini mask &= ~s->imr;
9349ab747fSPaolo Bonzini }
9449ab747fSPaolo Bonzini if (s->special_fully_nested_mode && s->master) {
9549ab747fSPaolo Bonzini mask &= ~(1 << 2);
9649ab747fSPaolo Bonzini }
9749ab747fSPaolo Bonzini cur_priority = get_priority(s, mask);
9849ab747fSPaolo Bonzini if (priority < cur_priority) {
9949ab747fSPaolo Bonzini /* higher priority found: an irq should be generated */
10049ab747fSPaolo Bonzini return (priority + s->priority_add) & 7;
10149ab747fSPaolo Bonzini } else {
10249ab747fSPaolo Bonzini return -1;
10349ab747fSPaolo Bonzini }
10449ab747fSPaolo Bonzini }
10549ab747fSPaolo Bonzini
10649ab747fSPaolo Bonzini /* Update INT output. Must be called every time the output may have changed. */
pic_update_irq(PICCommonState * s)10749ab747fSPaolo Bonzini static void pic_update_irq(PICCommonState *s)
10849ab747fSPaolo Bonzini {
10949ab747fSPaolo Bonzini int irq;
11049ab747fSPaolo Bonzini
11149ab747fSPaolo Bonzini irq = pic_get_irq(s);
11249ab747fSPaolo Bonzini if (irq >= 0) {
1130880a873SPeter Xu trace_pic_update_irq(s->master, s->imr, s->irr, s->priority_add);
11449ab747fSPaolo Bonzini qemu_irq_raise(s->int_out[0]);
11549ab747fSPaolo Bonzini } else {
11649ab747fSPaolo Bonzini qemu_irq_lower(s->int_out[0]);
11749ab747fSPaolo Bonzini }
11849ab747fSPaolo Bonzini }
11949ab747fSPaolo Bonzini
12049ab747fSPaolo Bonzini /* set irq level. If an edge is detected, then the IRR is set to 1 */
pic_set_irq(void * opaque,int irq,int level)12149ab747fSPaolo Bonzini static void pic_set_irq(void *opaque, int irq, int level)
12249ab747fSPaolo Bonzini {
12349ab747fSPaolo Bonzini PICCommonState *s = opaque;
12449ab747fSPaolo Bonzini int mask = 1 << irq;
12549ab747fSPaolo Bonzini int irq_index = s->master ? irq : irq + 8;
1260880a873SPeter Xu
1270880a873SPeter Xu trace_pic_set_irq(s->master, irq, level);
1281b23190aSPeter Xu pic_stat_update_irq(irq_index, level);
129f260f736SPeter Xu
13049ab747fSPaolo Bonzini #ifdef DEBUG_IRQ_LATENCY
13149ab747fSPaolo Bonzini if (level) {
132bc72ad67SAlex Bligh irq_time[irq_index] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
13349ab747fSPaolo Bonzini }
13449ab747fSPaolo Bonzini #endif
13549ab747fSPaolo Bonzini
136ecb0e98bSDavid Woodhouse if (s->ltim || (s->elcr & mask)) {
13749ab747fSPaolo Bonzini /* level triggered */
13849ab747fSPaolo Bonzini if (level) {
13949ab747fSPaolo Bonzini s->irr |= mask;
14049ab747fSPaolo Bonzini s->last_irr |= mask;
14149ab747fSPaolo Bonzini } else {
14249ab747fSPaolo Bonzini s->irr &= ~mask;
14349ab747fSPaolo Bonzini s->last_irr &= ~mask;
14449ab747fSPaolo Bonzini }
14549ab747fSPaolo Bonzini } else {
14649ab747fSPaolo Bonzini /* edge triggered */
14749ab747fSPaolo Bonzini if (level) {
14849ab747fSPaolo Bonzini if ((s->last_irr & mask) == 0) {
14949ab747fSPaolo Bonzini s->irr |= mask;
15049ab747fSPaolo Bonzini }
15149ab747fSPaolo Bonzini s->last_irr |= mask;
15249ab747fSPaolo Bonzini } else {
15349ab747fSPaolo Bonzini s->last_irr &= ~mask;
15449ab747fSPaolo Bonzini }
15549ab747fSPaolo Bonzini }
15649ab747fSPaolo Bonzini pic_update_irq(s);
15749ab747fSPaolo Bonzini }
15849ab747fSPaolo Bonzini
15949ab747fSPaolo Bonzini /* acknowledge interrupt 'irq' */
pic_intack(PICCommonState * s,int irq)16049ab747fSPaolo Bonzini static void pic_intack(PICCommonState *s, int irq)
16149ab747fSPaolo Bonzini {
16249ab747fSPaolo Bonzini if (s->auto_eoi) {
16349ab747fSPaolo Bonzini if (s->rotate_on_auto_eoi) {
16449ab747fSPaolo Bonzini s->priority_add = (irq + 1) & 7;
16549ab747fSPaolo Bonzini }
16649ab747fSPaolo Bonzini } else {
16749ab747fSPaolo Bonzini s->isr |= (1 << irq);
16849ab747fSPaolo Bonzini }
16949ab747fSPaolo Bonzini /* We don't clear a level sensitive interrupt here */
170ecb0e98bSDavid Woodhouse if (!s->ltim && !(s->elcr & (1 << irq))) {
17149ab747fSPaolo Bonzini s->irr &= ~(1 << irq);
17249ab747fSPaolo Bonzini }
17349ab747fSPaolo Bonzini pic_update_irq(s);
17449ab747fSPaolo Bonzini }
17549ab747fSPaolo Bonzini
pic_read_irq(PICCommonState * s)1762aaf0ec7SBernhard Beschow int pic_read_irq(PICCommonState *s)
17749ab747fSPaolo Bonzini {
17852ad57a9SPhilippe Mathieu-Daudé int irq, intno;
17949ab747fSPaolo Bonzini
18049ab747fSPaolo Bonzini irq = pic_get_irq(s);
18149ab747fSPaolo Bonzini if (irq >= 0) {
18252ad57a9SPhilippe Mathieu-Daudé int irq2;
18352ad57a9SPhilippe Mathieu-Daudé
18449ab747fSPaolo Bonzini if (irq == 2) {
18549ab747fSPaolo Bonzini irq2 = pic_get_irq(slave_pic);
18649ab747fSPaolo Bonzini if (irq2 >= 0) {
18749ab747fSPaolo Bonzini pic_intack(slave_pic, irq2);
18849ab747fSPaolo Bonzini } else {
18949ab747fSPaolo Bonzini /* spurious IRQ on slave controller */
19049ab747fSPaolo Bonzini irq2 = 7;
19149ab747fSPaolo Bonzini }
19249ab747fSPaolo Bonzini intno = slave_pic->irq_base + irq2;
19352ad57a9SPhilippe Mathieu-Daudé pic_intack(s, irq);
19452ad57a9SPhilippe Mathieu-Daudé irq = irq2 + 8;
19549ab747fSPaolo Bonzini } else {
19649ab747fSPaolo Bonzini intno = s->irq_base + irq;
19749ab747fSPaolo Bonzini pic_intack(s, irq);
19852ad57a9SPhilippe Mathieu-Daudé }
19949ab747fSPaolo Bonzini } else {
20049ab747fSPaolo Bonzini /* spurious IRQ on host controller */
20149ab747fSPaolo Bonzini irq = 7;
20249ab747fSPaolo Bonzini intno = s->irq_base + irq;
20349ab747fSPaolo Bonzini }
20449ab747fSPaolo Bonzini
20549ab747fSPaolo Bonzini #ifdef DEBUG_IRQ_LATENCY
20649ab747fSPaolo Bonzini printf("IRQ%d latency=%0.3fus\n",
20749ab747fSPaolo Bonzini irq,
208bc72ad67SAlex Bligh (double)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
20973bcb24dSRutuja Shah irq_time[irq]) * 1000000.0 / NANOSECONDS_PER_SECOND);
21049ab747fSPaolo Bonzini #endif
2110880a873SPeter Xu
2120880a873SPeter Xu trace_pic_interrupt(irq, intno);
21349ab747fSPaolo Bonzini return intno;
21449ab747fSPaolo Bonzini }
21549ab747fSPaolo Bonzini
pic_init_reset(PICCommonState * s)21649ab747fSPaolo Bonzini static void pic_init_reset(PICCommonState *s)
21749ab747fSPaolo Bonzini {
21849ab747fSPaolo Bonzini pic_reset_common(s);
21949ab747fSPaolo Bonzini pic_update_irq(s);
22049ab747fSPaolo Bonzini }
22149ab747fSPaolo Bonzini
pic_reset(DeviceState * dev)22249ab747fSPaolo Bonzini static void pic_reset(DeviceState *dev)
22349ab747fSPaolo Bonzini {
22429bb5317SAndreas Färber PICCommonState *s = PIC_COMMON(dev);
22549ab747fSPaolo Bonzini
22649ab747fSPaolo Bonzini s->elcr = 0;
227ecb0e98bSDavid Woodhouse s->ltim = 0;
22849ab747fSPaolo Bonzini pic_init_reset(s);
22949ab747fSPaolo Bonzini }
23049ab747fSPaolo Bonzini
pic_ioport_write(void * opaque,hwaddr addr64,uint64_t val64,unsigned size)23149ab747fSPaolo Bonzini static void pic_ioport_write(void *opaque, hwaddr addr64,
23249ab747fSPaolo Bonzini uint64_t val64, unsigned size)
23349ab747fSPaolo Bonzini {
23449ab747fSPaolo Bonzini PICCommonState *s = opaque;
23549ab747fSPaolo Bonzini uint32_t addr = addr64;
23649ab747fSPaolo Bonzini uint32_t val = val64;
23749ab747fSPaolo Bonzini int priority, cmd, irq;
23849ab747fSPaolo Bonzini
2390880a873SPeter Xu trace_pic_ioport_write(s->master, addr, val);
2400880a873SPeter Xu
24149ab747fSPaolo Bonzini if (addr == 0) {
24249ab747fSPaolo Bonzini if (val & 0x10) {
24349ab747fSPaolo Bonzini pic_init_reset(s);
24449ab747fSPaolo Bonzini s->init_state = 1;
24549ab747fSPaolo Bonzini s->init4 = val & 1;
24649ab747fSPaolo Bonzini s->single_mode = val & 2;
247ecb0e98bSDavid Woodhouse s->ltim = val & 8;
24849ab747fSPaolo Bonzini } else if (val & 0x08) {
24949ab747fSPaolo Bonzini if (val & 0x04) {
25049ab747fSPaolo Bonzini s->poll = 1;
25149ab747fSPaolo Bonzini }
25249ab747fSPaolo Bonzini if (val & 0x02) {
25349ab747fSPaolo Bonzini s->read_reg_select = val & 1;
25449ab747fSPaolo Bonzini }
25549ab747fSPaolo Bonzini if (val & 0x40) {
25649ab747fSPaolo Bonzini s->special_mask = (val >> 5) & 1;
25749ab747fSPaolo Bonzini }
25849ab747fSPaolo Bonzini } else {
25949ab747fSPaolo Bonzini cmd = val >> 5;
26049ab747fSPaolo Bonzini switch (cmd) {
26149ab747fSPaolo Bonzini case 0:
26249ab747fSPaolo Bonzini case 4:
26349ab747fSPaolo Bonzini s->rotate_on_auto_eoi = cmd >> 2;
26449ab747fSPaolo Bonzini break;
26549ab747fSPaolo Bonzini case 1: /* end of interrupt */
26649ab747fSPaolo Bonzini case 5:
26749ab747fSPaolo Bonzini priority = get_priority(s, s->isr);
26849ab747fSPaolo Bonzini if (priority != 8) {
26949ab747fSPaolo Bonzini irq = (priority + s->priority_add) & 7;
27049ab747fSPaolo Bonzini s->isr &= ~(1 << irq);
27149ab747fSPaolo Bonzini if (cmd == 5) {
27249ab747fSPaolo Bonzini s->priority_add = (irq + 1) & 7;
27349ab747fSPaolo Bonzini }
27449ab747fSPaolo Bonzini pic_update_irq(s);
27549ab747fSPaolo Bonzini }
27649ab747fSPaolo Bonzini break;
27749ab747fSPaolo Bonzini case 3:
27849ab747fSPaolo Bonzini irq = val & 7;
27949ab747fSPaolo Bonzini s->isr &= ~(1 << irq);
28049ab747fSPaolo Bonzini pic_update_irq(s);
28149ab747fSPaolo Bonzini break;
28249ab747fSPaolo Bonzini case 6:
28349ab747fSPaolo Bonzini s->priority_add = (val + 1) & 7;
28449ab747fSPaolo Bonzini pic_update_irq(s);
28549ab747fSPaolo Bonzini break;
28649ab747fSPaolo Bonzini case 7:
28749ab747fSPaolo Bonzini irq = val & 7;
28849ab747fSPaolo Bonzini s->isr &= ~(1 << irq);
28949ab747fSPaolo Bonzini s->priority_add = (irq + 1) & 7;
29049ab747fSPaolo Bonzini pic_update_irq(s);
29149ab747fSPaolo Bonzini break;
29249ab747fSPaolo Bonzini default:
29349ab747fSPaolo Bonzini /* no operation */
29449ab747fSPaolo Bonzini break;
29549ab747fSPaolo Bonzini }
29649ab747fSPaolo Bonzini }
29749ab747fSPaolo Bonzini } else {
29849ab747fSPaolo Bonzini switch (s->init_state) {
29949ab747fSPaolo Bonzini case 0:
30049ab747fSPaolo Bonzini /* normal mode */
30149ab747fSPaolo Bonzini s->imr = val;
30249ab747fSPaolo Bonzini pic_update_irq(s);
30349ab747fSPaolo Bonzini break;
30449ab747fSPaolo Bonzini case 1:
30549ab747fSPaolo Bonzini s->irq_base = val & 0xf8;
30649ab747fSPaolo Bonzini s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
30749ab747fSPaolo Bonzini break;
30849ab747fSPaolo Bonzini case 2:
30949ab747fSPaolo Bonzini if (s->init4) {
31049ab747fSPaolo Bonzini s->init_state = 3;
31149ab747fSPaolo Bonzini } else {
31249ab747fSPaolo Bonzini s->init_state = 0;
31349ab747fSPaolo Bonzini }
31449ab747fSPaolo Bonzini break;
31549ab747fSPaolo Bonzini case 3:
31649ab747fSPaolo Bonzini s->special_fully_nested_mode = (val >> 4) & 1;
31749ab747fSPaolo Bonzini s->auto_eoi = (val >> 1) & 1;
31849ab747fSPaolo Bonzini s->init_state = 0;
31949ab747fSPaolo Bonzini break;
32049ab747fSPaolo Bonzini }
32149ab747fSPaolo Bonzini }
32249ab747fSPaolo Bonzini }
32349ab747fSPaolo Bonzini
pic_ioport_read(void * opaque,hwaddr addr,unsigned size)32449ab747fSPaolo Bonzini static uint64_t pic_ioport_read(void *opaque, hwaddr addr,
32549ab747fSPaolo Bonzini unsigned size)
32649ab747fSPaolo Bonzini {
32749ab747fSPaolo Bonzini PICCommonState *s = opaque;
32849ab747fSPaolo Bonzini int ret;
32949ab747fSPaolo Bonzini
33049ab747fSPaolo Bonzini if (s->poll) {
33149ab747fSPaolo Bonzini ret = pic_get_irq(s);
33249ab747fSPaolo Bonzini if (ret >= 0) {
33349ab747fSPaolo Bonzini pic_intack(s, ret);
33449ab747fSPaolo Bonzini ret |= 0x80;
33549ab747fSPaolo Bonzini } else {
33649ab747fSPaolo Bonzini ret = 0;
33749ab747fSPaolo Bonzini }
33849ab747fSPaolo Bonzini s->poll = 0;
33949ab747fSPaolo Bonzini } else {
34049ab747fSPaolo Bonzini if (addr == 0) {
34149ab747fSPaolo Bonzini if (s->read_reg_select) {
34249ab747fSPaolo Bonzini ret = s->isr;
34349ab747fSPaolo Bonzini } else {
34449ab747fSPaolo Bonzini ret = s->irr;
34549ab747fSPaolo Bonzini }
34649ab747fSPaolo Bonzini } else {
34749ab747fSPaolo Bonzini ret = s->imr;
34849ab747fSPaolo Bonzini }
34949ab747fSPaolo Bonzini }
3500880a873SPeter Xu trace_pic_ioport_read(s->master, addr, ret);
35149ab747fSPaolo Bonzini return ret;
35249ab747fSPaolo Bonzini }
35349ab747fSPaolo Bonzini
pic_get_output(PICCommonState * s)3542aaf0ec7SBernhard Beschow int pic_get_output(PICCommonState *s)
35549ab747fSPaolo Bonzini {
35649ab747fSPaolo Bonzini return (pic_get_irq(s) >= 0);
35749ab747fSPaolo Bonzini }
35849ab747fSPaolo Bonzini
elcr_ioport_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)35949ab747fSPaolo Bonzini static void elcr_ioport_write(void *opaque, hwaddr addr,
36049ab747fSPaolo Bonzini uint64_t val, unsigned size)
36149ab747fSPaolo Bonzini {
36249ab747fSPaolo Bonzini PICCommonState *s = opaque;
36349ab747fSPaolo Bonzini s->elcr = val & s->elcr_mask;
36449ab747fSPaolo Bonzini }
36549ab747fSPaolo Bonzini
elcr_ioport_read(void * opaque,hwaddr addr,unsigned size)36649ab747fSPaolo Bonzini static uint64_t elcr_ioport_read(void *opaque, hwaddr addr,
36749ab747fSPaolo Bonzini unsigned size)
36849ab747fSPaolo Bonzini {
36949ab747fSPaolo Bonzini PICCommonState *s = opaque;
37049ab747fSPaolo Bonzini return s->elcr;
37149ab747fSPaolo Bonzini }
37249ab747fSPaolo Bonzini
37349ab747fSPaolo Bonzini static const MemoryRegionOps pic_base_ioport_ops = {
37449ab747fSPaolo Bonzini .read = pic_ioport_read,
37549ab747fSPaolo Bonzini .write = pic_ioport_write,
37649ab747fSPaolo Bonzini .impl = {
37749ab747fSPaolo Bonzini .min_access_size = 1,
37849ab747fSPaolo Bonzini .max_access_size = 1,
37949ab747fSPaolo Bonzini },
38049ab747fSPaolo Bonzini };
38149ab747fSPaolo Bonzini
38249ab747fSPaolo Bonzini static const MemoryRegionOps pic_elcr_ioport_ops = {
38349ab747fSPaolo Bonzini .read = elcr_ioport_read,
38449ab747fSPaolo Bonzini .write = elcr_ioport_write,
38549ab747fSPaolo Bonzini .impl = {
38649ab747fSPaolo Bonzini .min_access_size = 1,
38749ab747fSPaolo Bonzini .max_access_size = 1,
38849ab747fSPaolo Bonzini },
38949ab747fSPaolo Bonzini };
39049ab747fSPaolo Bonzini
pic_realize(DeviceState * dev,Error ** errp)391a7737e44SMarkus Armbruster static void pic_realize(DeviceState *dev, Error **errp)
39249ab747fSPaolo Bonzini {
393d2628b7dSAndreas Färber PICCommonState *s = PIC_COMMON(dev);
394d2628b7dSAndreas Färber PICClass *pc = PIC_GET_CLASS(dev);
39529bb5317SAndreas Färber
3961437c94bSPaolo Bonzini memory_region_init_io(&s->base_io, OBJECT(s), &pic_base_ioport_ops, s,
3971437c94bSPaolo Bonzini "pic", 2);
3981437c94bSPaolo Bonzini memory_region_init_io(&s->elcr_io, OBJECT(s), &pic_elcr_ioport_ops, s,
3991437c94bSPaolo Bonzini "elcr", 1);
40049ab747fSPaolo Bonzini
40129bb5317SAndreas Färber qdev_init_gpio_out(dev, s->int_out, ARRAY_SIZE(s->int_out));
40229bb5317SAndreas Färber qdev_init_gpio_in(dev, pic_set_irq, 8);
403d2628b7dSAndreas Färber
404a7737e44SMarkus Armbruster pc->parent_realize(dev, errp);
40549ab747fSPaolo Bonzini }
40649ab747fSPaolo Bonzini
i8259_init(ISABus * bus,qemu_irq parent_irq_in)40778827d5fSPhilippe Mathieu-Daudé qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq_in)
40849ab747fSPaolo Bonzini {
40949ab747fSPaolo Bonzini qemu_irq *irq_set;
410d1eebf4eSAndreas Färber DeviceState *dev;
411d1eebf4eSAndreas Färber ISADevice *isadev;
41249ab747fSPaolo Bonzini int i;
41349ab747fSPaolo Bonzini
4148945c7f7SPeter Crosthwaite irq_set = g_new0(qemu_irq, ISA_NUM_IRQS);
41549ab747fSPaolo Bonzini
416d1eebf4eSAndreas Färber isadev = i8259_init_chip(TYPE_I8259, bus, true);
417d1eebf4eSAndreas Färber dev = DEVICE(isadev);
41849ab747fSPaolo Bonzini
41978827d5fSPhilippe Mathieu-Daudé qdev_connect_gpio_out(dev, 0, parent_irq_in);
42049ab747fSPaolo Bonzini for (i = 0 ; i < 8; i++) {
421d1eebf4eSAndreas Färber irq_set[i] = qdev_get_gpio_in(dev, i);
42249ab747fSPaolo Bonzini }
42349ab747fSPaolo Bonzini
4242aaf0ec7SBernhard Beschow isa_pic = PIC_COMMON(dev);
42549ab747fSPaolo Bonzini
426d1eebf4eSAndreas Färber isadev = i8259_init_chip(TYPE_I8259, bus, false);
427d1eebf4eSAndreas Färber dev = DEVICE(isadev);
42849ab747fSPaolo Bonzini
429d1eebf4eSAndreas Färber qdev_connect_gpio_out(dev, 0, irq_set[2]);
43049ab747fSPaolo Bonzini for (i = 0 ; i < 8; i++) {
431d1eebf4eSAndreas Färber irq_set[i + 8] = qdev_get_gpio_in(dev, i);
43249ab747fSPaolo Bonzini }
43349ab747fSPaolo Bonzini
43429bb5317SAndreas Färber slave_pic = PIC_COMMON(dev);
43549ab747fSPaolo Bonzini
43649ab747fSPaolo Bonzini return irq_set;
43749ab747fSPaolo Bonzini }
43849ab747fSPaolo Bonzini
i8259_class_init(ObjectClass * klass,void * data)43949ab747fSPaolo Bonzini static void i8259_class_init(ObjectClass *klass, void *data)
44049ab747fSPaolo Bonzini {
441d2628b7dSAndreas Färber PICClass *k = PIC_CLASS(klass);
44249ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
44349ab747fSPaolo Bonzini
444bf853881SPhilippe Mathieu-Daudé device_class_set_parent_realize(dc, pic_realize, &k->parent_realize);
445*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, pic_reset);
44649ab747fSPaolo Bonzini }
44749ab747fSPaolo Bonzini
44849ab747fSPaolo Bonzini static const TypeInfo i8259_info = {
449d1eebf4eSAndreas Färber .name = TYPE_I8259,
45049ab747fSPaolo Bonzini .instance_size = sizeof(PICCommonState),
45149ab747fSPaolo Bonzini .parent = TYPE_PIC_COMMON,
45249ab747fSPaolo Bonzini .class_init = i8259_class_init,
453d2628b7dSAndreas Färber .class_size = sizeof(PICClass),
45449ab747fSPaolo Bonzini };
45549ab747fSPaolo Bonzini
pic_register_types(void)45649ab747fSPaolo Bonzini static void pic_register_types(void)
45749ab747fSPaolo Bonzini {
45849ab747fSPaolo Bonzini type_register_static(&i8259_info);
45949ab747fSPaolo Bonzini }
46049ab747fSPaolo Bonzini
46149ab747fSPaolo Bonzini type_init(pic_register_types)
462