Page 1 of 1

Serial - interrupt-pending-flag not being set

Posted: Wed Jul 22, 2009 11:54 pm
by alethiophile
I have written some serial-port code, hopefully as a debugging aid for my other problems. I have tried a busy-wait loop for input, as it shows in the wiki, and it worked just fine. I then wrote an IRQ handler for the serial port, and it broke. Code:

Code: Select all

void serial_irq(registers_t regs) {
  if (regs.eax) {} // prevent GCC complaining about unused parameter
  printf("serial irq called\n");
  u8int iir = inportb(COM1_PORT + 2); // interrupt identification register
  printf("%x\n", iir);
   if (!(iir & 1)) {  // starts here
     /* The UART didn't cause this IRQ; in future, we'll probably want to handle this, 
        but for now just return. */ 
     printf("not a serial irq\n"); 
     return; 
   }  // ends here
  if ((iir & 0x0e) != 4) {
    /* This isn't a received-data-available interrupt; again, just return. */
    printf("not a received-data interrupt\n");
    return;
  }
  u8int read = inportb(COM1_PORT);
  // for now just print it
  printf("%c", read);
}
When the code from 'starts here' to 'ends here' is commented out, it works as advertised. This code checks the interrupt-pending flag in the interrupt identification register. With the code intact, however, it returns early--and in returning early, doesn't reset the data-available interrupt in the UART, and hence no more interrupts get fired. My question is, why is the interrupt-pending flag not being set? I'm using Qemu.

Edit: syntax

Re: Serial - interrupt-pending-flag not being set

Posted: Thu Jul 23, 2009 9:36 pm
by alethiophile
OK, issue resolved. It turns out that the interrupt-pending flag is zero on true, one on false. Sigh.

Re: Serial - interrupt-pending-flag not being set

Posted: Fri Jul 24, 2009 9:26 am
by Troy Martin
Good to know you figured it out by yourself, but I might recommend that you re-format your code so it's easier to read. For example, here's a tidier formatting for your code:

Code: Select all

void serial_irq(registers_t regs)
{
  if (regs.eax); // prevent GCC complaining about unused parameter

  printf("serial irq called\n");
  u8int iir = inportb(COM1_PORT + 2); // interrupt identification register
  printf("%x\n", iir);

  if (!(iir & 1))
  {
    /* The UART didn't cause this IRQ; in future, we'll probably want to handle this,
       but for now just return. */
    printf("not a serial irq\n");
    return;
  }

  if ((iir & 0x0e) != 4)
  {
    /* This isn't a received-data-available interrupt; again, just return. */
    printf("not a received-data interrupt\n");
    return;
  }

  u8int read = inportb(COM1_PORT);
  // for now just print it
  printf("%c", read);
}
Whitespace makes everything nice :)

Also, I hope your IRQ stub in assembly sends the appropriate EOI acknowledgement to the PIC. If it doesn't, you're up a creek. :P

--Troy

Re: Serial - interrupt-pending-flag not being set

Posted: Fri Jul 24, 2009 9:58 am
by -m32
FYI, there's an "official" way to declare a parameter as "unused" in GCC ;)

Code: Select all

void serial_irq(__attribute__((unused)) registers_t regs)

Re: Serial - interrupt-pending-flag not being set

Posted: Fri Jul 24, 2009 10:00 am
by alethiophile
What happens if you use an unused param?

Re: Serial - interrupt-pending-flag not being set

Posted: Fri Jul 24, 2009 10:01 am
by -m32
alethiophile wrote:What happens if you use an unused param?
The planet will ASPLODE! Zomg! :shock: