--- trunk/src/devices/dev_8259.c 2007/10/08 16:18:38 12 +++ trunk/src/devices/dev_8259.c 2007/10/08 16:22:32 42 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Anders Gavare. All rights reserved. + * Copyright (C) 2005-2007 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,9 +25,9 @@ * SUCH DAMAGE. * * - * $Id: dev_8259.c,v 1.14 2005/08/05 09:08:20 debug Exp $ + * $Id: dev_8259.c,v 1.30 2007/06/15 18:13:04 debug Exp $ * - * 8259 Programmable Interrupt Controller. + * COMMENT: Intel 8259 Programmable Interrupt Controller * * See the following URL for more details: * http://www.nondot.org/sabre/os/files/MiscHW/8259pic.txt @@ -51,18 +51,14 @@ /* #define DEV_8259_DEBUG */ -/* - * dev_8259_access(): - */ -int dev_8259_access(struct cpu *cpu, struct memory *mem, - uint64_t relative_addr, unsigned char *data, size_t len, - int writeflag, void *extra) +DEVICE_ACCESS(8259) { - struct pic8259_data *d = (struct pic8259_data *) extra; + struct pic8259_data *d = extra; uint64_t idata = 0, odata = 0; int i; - idata = memory_readmax64(cpu, data, len); + if (writeflag == MEM_WRITE) + idata = memory_readmax64(cpu, data, len); #ifdef DEV_8259_DEBUG if (writeflag == MEM_READ) @@ -99,62 +95,50 @@ " it was aborted? ]\n"); d->init_state = 0; - switch (idata) { - case 0x0a: + if (idata == 0x0a) { d->current_command = 0x0a; - break; - case 0x0b: + } else if (idata == 0x0b) { d->current_command = 0x0b; - break; - case 0x0c: + } else if (idata == 0x0c) { /* Put Master in Buffered Mode */ d->current_command = 0x0c; - break; - case 0x20: /* End Of Interrupt */ - /* - * TODO: in buffered mode, is this an EOI 0? - */ + } else if (idata == 0x20) { + int old_irr = d->irr; + /* End Of Interrupt */ + /* TODO: in buffered mode, is this an EOI 0? */ d->irr &= ~d->isr; d->isr = 0; - /* Recalculate interrupt assertions: */ - cpu_interrupt(cpu, d->irq_nr); - break; - case 0x21: /* Specific EOI */ - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: /* Specific EOI */ + /* Recalculate interrupt assertions, + if necessary: */ + if ((old_irr & ~d->ier) != (d->irr & ~d->ier)) { + if (d->irr & ~d->ier) + INTERRUPT_ASSERT(d->irq); + else + INTERRUPT_DEASSERT(d->irq); + } + } else if ((idata >= 0x21 && idata <= 0x27) || + (idata >= 0x60 && idata <= 0x67) || + (idata >= 0xe0 && idata <= 0xe7)) { + /* Specific EOI */ + int old_irr = d->irr; d->irr &= ~(1 << (idata & 7)); d->isr &= ~(1 << (idata & 7)); - /* Recalculate interrupt assertions: */ - cpu_interrupt(cpu, d->irq_nr); - break; - case 0x68: /* Set Special Mask Mode */ + /* Recalc. int assertions, if necessary: */ + if ((old_irr & ~d->ier) != (d->irr & ~d->ier)) { + if (d->irr & ~d->ier) + INTERRUPT_ASSERT(d->irq); + else + INTERRUPT_DEASSERT(d->irq); + } + } else if (idata == 0x68) { + /* Set Special Mask Mode */ /* TODO */ - break; - case 0xc0: - case 0xc1: - case 0xc2: - case 0xc3: - case 0xc4: - case 0xc5: - case 0xc6: - case 0xc7: /* Set IRQ Priority Order */ + } else if (idata >= 0xc0 && idata <= 0xc7) { + /* Set IRQ Priority Order */ /* TODO */ - break; - default: + } else { fatal("[ 8259: unimplemented command 0x%02x" - " ]\n", idata); + " ]\n", (int)idata); cpu->running = 0; } } else { @@ -167,6 +151,13 @@ break; case 0x0c: /* Buffered mode. */ + odata = 0x00; + for (i=0; i<8; i++) + if ((d->irr >> i) & 1) { + odata = 0x80 | i; + break; + } + break; default: odata = 0x00; for (i=0; i<8; i++) @@ -204,9 +195,12 @@ /* Slave attachment. TODO */ d->init_state = 3; } else if (d->init_state == 3) { - if (idata & 0x02) - fatal("[ 8259: WARNING! Bit 1 i" + if (idata & 0x02) { + /* Should not be set in PCs, but + on CATS, for example, it is set. */ + debug("[ 8259: WARNING! Bit 1 i" "n Init Cmd 4 is set! ]\n"); + } if (!(idata & 0x01)) fatal("[ 8259: WARNING! Bit 0 " "in Init Cmd 4 is not" @@ -217,9 +211,17 @@ } if (writeflag == MEM_WRITE) { + int old_ier = d->ier; d->ier = idata; - /* Recalculate interrupt assertions: */ - cpu_interrupt(cpu, d->irq_nr); + + /* Recalculate interrupt assertions, + if necessary: */ + if ((d->irr & ~old_ier) != (d->irr & ~d->ier)) { + if (d->irr & ~d->ier) + INTERRUPT_ASSERT(d->irq); + else + INTERRUPT_DEASSERT(d->irq); + } } else { odata = d->ier; } @@ -256,20 +258,18 @@ * which the PIC is connected. (That is left to machine specific * code in src/machine.c.) */ -int devinit_8259(struct devinit *devinit) +DEVINIT(8259) { - struct pic8259_data *d = malloc(sizeof(struct pic8259_data)); + struct pic8259_data *d; char *name2; size_t nlen = strlen(devinit->name) + 20; - if (d == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); - } + CHECK_ALLOCATION(d = malloc(sizeof(struct pic8259_data))); memset(d, 0, sizeof(struct pic8259_data)); - d->irq_nr = devinit->irq_nr; - name2 = malloc(nlen); + INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); + + CHECK_ALLOCATION(name2 = malloc(nlen)); snprintf(name2, nlen, "%s", devinit->name); if ((devinit->addr & 0xfff) == 0xa0) { strlcat(name2, " [secondary]", nlen); @@ -278,7 +278,7 @@ memory_device_register(devinit->machine->memory, name2, devinit->addr, DEV_8259_LENGTH, dev_8259_access, d, - MEM_DEFAULT, NULL); + DM_DEFAULT, NULL); devinit->return_ptr = d; return 1;