Handling a UART interrupt A look at some recent changes in the Linux kernel’s programming interface for device-interrupts.
Download ReportTranscript Handling a UART interrupt A look at some recent changes in the Linux kernel’s programming interface for device-interrupts.
Handling a UART interrupt
A look at some recent changes in the Linux kernel’s programming interface for device-interrupts
The new ‘anchor’ cluster
• To reduce contention for CS workstations that have null-modem cables attached, we are bringing online an additional cluster of eight servers – you access them remotely ‘anchor00’ ‘anchor01’ ‘anchor02’ ‘anchor04’ ‘anchor03’ ‘anchor05’ ‘anchor06’ ‘anchor07’
Thanks to overnight efforts by Alex Fedosov and our CS support-team!
LDD3: kernel 2.6.10
• Our text “
Linux Device Drivers (3 rd Ed)”
is published by O’Reilly in February 2005 • The kernel version it covers is 2.6.10
• But in our classroom we are using a more recent version of the kernel (i.e., 2.6.22.5) which was released in mid-August 2007 • Various changes (improvements) are now implemented (and differ from LDD3 book)
Example 1
• Our textbook shows the prototype for a device driver’s interrupt service routine: irqreturn_t
isr
( int irq, void *dev_id, struct pt_regs *regs ); • But this has changed in kernel 2.6.22.5 to: Irqreturn_t
isr
( int irq, void *dev_id ); • What prompted the kernel developers to remove that third function-argument? • Just a guess, but probably it was because programmers were not actually using it
Example 2
• The kernel’s header-files
Consequences
• If you try to apply the textbook discussion about interrupt-handlers to your LKMs for this class, the compiler will generate error messages and/or warning messages • So you will need to use the “new” kernel’s interfaces, not documented in our textbook • Maybe you can locate an online tutorial, or look at other device drivers’ source-code
Our ‘uartintr.c’ module
• We have written a kernel module that you can study (and experiment with) showing an interrupt-handler for the UART device that we created purely for demonstration purposes using kernel version 2.6.22.5 • Obviously you would need to modify it if you wanted to use an interrupt-handler in your solution for our course’s Project #2
Module’s components
The LKM layout the usual pair of module-administration functions The isr function init exit module’s ‘payload’ is just a single callback-function that will ‘handle’ a UART interrupt
registers the ‘isr’ and then enables the UART device to generate interrupt-signals disables the UART’s interrupt-signals and then unregisters this module’s ‘isr’
Interrupt Identification Register
7 6 5 4 3 2 1 0 0 0 00 = FIFO-mode has not been enabled 11 = FIFO-mode is currently enabled ‘highest priority’ UART interrupt still pending highest 011 = receiver line-status 010 = received data ready 100 = character timeout 001 = Tx Holding Reg empty 000 = modem-status change lowest
1 = No UART interrupts are pending 0 = At least one UART interrupt is pending
An interrupt service routine
• Whenever the UART receives a new byte of data, it will transmit it back to the sender #include
my_uart_isr
( int irq, void *dev_id ) int intr_identify = inb( UART_BASE + 2 ) & 0x0F; if ( intr_identify == 0x01 ) return IRQ_NONE; if ( intr_identify == 0x04 ) // a new character has arrived outb( inb( UART_BASE ), UART_BASE ); return IRQ_HANDLED;
Installing the ‘isr()’
• Here is how your module asks the kernel to execute your UART interrupt-handler: #define UART_IRQ 4 // signal line’s number to the IO-APIC char modname[] = “uartintr”; // kernel displays this in ‘/proc/interrupts’ } { static int __init
my_init
( void ) … if (
request_irq
( UART_IRQ, &my_uart_isr, IRQF_SHARED, modname, &modname ) < 0 ) return –EBUSY; … // your code to enable the UART’s interrupts goes here … return 0; // SUCCESS
Interrupt Enable Register
7 6 5 4 3 2 1 0 0 0 0 0
Modem Status change Rx Line Status change THR is empty Received data is available
If
enabled
(by setting the bit to 1), the UART will generate an interrupt: (bit 3) whenever modem status changes (bit 2) whenever a receive-error is detected (bit 1) whenever the transmit-buffer is empty (bit 0) whenever the receive-buffer is nonempty Also, in FIFO mode, a ‘timeout’ interrupt will be generated if neither FIFO has been ‘serviced’ for at least four character-clock times
FIFO Control Register
7 6 5 4 3 2 1 0 RCVR FIFO trigger-level
reserved reserved DMA Mode select
XMIT FIFO reset RCVR FIFO reset FIFO enable 00 = 1 byte 01 = 4 bytes 10 = 8 bytes 11 = 14 bytes NOTE: DMA is unsupported for the UART on our systems
Writing 1 empties the FIFO, writing 0 has no effect Writing 0 will disable the UART’s FIFO-mode, writing 1 will enable FIFO-mode
Modem Control Register
7 6 5 4 3 2 1 0 0 0 0 LOOP BACK OUT2 OUT1 RTS DTR Legend: DTR = Data Terminal Ready (1=yes, 0=no) RTS = Request To Send (1=yes, 0=no) OUT1 = not used (except in loopback mode) OUT2 = enables the UART to issue interrupts LOOPBACK-mode (1=enabled, 0=disabled)
UART initialization
• Here is code that initializes the UART (its baud-rate and data-format) and enables it to generate ‘character received’ interrupts: // initialize the UART device for the desired demo operations outb( 0x01, UART_BASE + 1 ); // issue RDR interrupts outb( 0x00, UART_BASE + 2 ); outb( 0x80, UART_BASE + 3 ); // turn off FIFO-mode // SET DLAB=1 outw( 0x0001, UART_BASE ); outb( 0x03, UART_BASE + 3 ); outb( 0x0B, UART_BASE + 4 ); // DIVISOR_LATCH = 1 // data-format is 8-N-1 // DSR=1, RTS=1, OUT2=1
Disabling UART interrupts
• Here is code that disables any more UART interrupts, so that your module’s ‘cleanup’ can safely remove your interrupt-handler: { static __exit
my_exit
( void ) … // disable any further UART interrupt-requests outb( 0x00, UART_BASE + 1 ); outb( 0x00, UART_BASE + 4 ); // INTERRUPT_ENABLE // MODEM_CONTROL // remove your UART interrupt-service routine
free_irq
( UART_IRQ, modname ); … }
In-class exercise
• Try running our ‘trycable.cpp’ application on an adjacent workstation after you have downloaded, compiled, and installed our ‘uartintr.c’ demo-module • What do you see on the two screens?
• Tonight’s class ends early -- so that you can attend the ACM Chapter’s Pizza Night