问题
I'm trying to use interrupts to see if there are errors in an UART 16550D and when a character is available to be read.
The UART configurations is as follows:
#define UART 0x03f8 // Endereço da Porta Serial - I (com1)
#define UART_IER 1
#define UART_LCR 3
#define UART_LSR 5
#define UART_DLL 0 /* Out: Divisor Latch Low */
#define UART_DLM 1 /* Out: Divisor Latch High */
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
#define UART_LSR_DR 0x01 /* Receiver data ready */
#define UART_RX 0 /* In: Receive buffer */
#define UART_TX 0 /* Out: Transmit buffer */
void UART_init(void){
outb( 0x80 , UART + UART_LCR );
outb( 0x00 , UART + UART_DLM );
outb( 0x60 , UART + UART_DLL );
outb( 0x1f , UART + UART_LCR );
outb( 0x07 , UART + UART_IER );
return;
}
And the interrupt
irqreturn_t short_interrupt(int irq, void *dev_id){
printk("INTERRUPT HAPPENED. WILL NOW RETURN\n");
return 0;
}
static int seri_init(void){
int result, i;
UART_init();
request_irq(4, short_interrupt, SA_SHIRQ, "seri", NULL);
....
So for now I just want to see if the handler is called or not. 4 is defined as the IRQ in the virtual box settings I'm using.
What I want to know is, is there something wrong about this setup? When testing, I have no problem reading and processing what I'm reading. Thing is, the handler is never called.
The return from request_irq() is -22. There are no problems during compilation.
回答1:
My analysis on why the interrupt handler is not triggered:
(1) Make sure the first parameter passed to request_irq(virq,...) is hardware irq number or virtual irq number. On some platform, there is a mapping between the hardware irq and the number which used by request_irq(...). If there is a mapping on your box, then you connect your handler to other interrupt source mistakenly;
(2) Make sure the interrupt mask register on 16550D is set correctly. I think there should be an interrupt mask register on 16550D which can mask/unmask the interrupt events;
(3) Check the return value of request_irq(...) to make sure the interrupt is connected successfully.
Hope the above help you.
回答2:
Change
outb( 0x80 , UART + UART_LCR );
outb( 0x00 , UART + UART_DLM );
outb( 0x60 , UART + UART_DLL );
outb( 0x1f , UART + UART_LCR );
outb( 0x07 , UART + UART_IER );
To
outb( 0x80 , UART + UART_LCR );
outb( 0x00 , UART + UART_DLM );
outb( 0x60 , UART + UART_DLL );
outb( 0x07 , UART + UART_IER ); // Set IER before clearing DLAB bit in LCR
outb( 0x1f , UART + UART_LCR );
// You may also need
outb( 8 , UART + 4 ); // Some systems use this as a master interrupt enable
回答3:
-22 is EINVAL
and I think it's because of NULL last argument. This page: http://www.makelinux.net/books/lkd2/ch06lev1sec3 says:
The fifth parameter, dev_id, is used primarily for shared interrupt lines. When an interrupt handler is freed (discussed later), dev_id provides a unique cookie to allow the removal of only the desired interrupt handler from the interrupt line. Without this parameter, it would be impossible for the kernel to know which handler to remove on a given interrupt line. You can pass NULL here if the line is not shared, but you must pass a unique cookie if your interrupt line is shared
So requesting a shared irq wiht NULLed dev_id won't work.
回答4:
I know this is an old post, but thought I would throw up an answer. use gpio_to_irq to get interrupt number. The third parameter determines when the interrupt occurs.
irqNumber = gpio_to_irq(gpioUART);
// This next call requests an interrupt line
result = request_irq(irqNumber, // The interrupt number requested
(irq_handler_t) short_interrupt, // The pointer to handler function below
IRQF_TRIGGER_FALLING, // Interrupt on FALL edge ()
"seri", // For /proc/interrupts identity
NULL); // The *dev_id for shared interrupt
来源:https://stackoverflow.com/questions/16594098/interrupts-in-uart-16550-and-linux-kernel