I3MPS - Exercise 6: LDD With Interrupts

Introduction
In this exercise an interrupt service routine is added to the BOOT_KEY driver from I3MPS - Exercise 5: LDD with GPIO. The implemented interrupt routine has to wake up the read method, so that applications blocked while calling read, are released.

Important header files and methods
Extra header files: Important method from gpio.h: /* get interrupt line attached to GPIO port # */ unsigned int gpio_to_irq(unsigned int gpio); Important methods from interrupt.h: /* Request IRQ */ request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) void free_irq(unsigned int, void *);
 * 1) include 
 * 2) include 
 * 3) include 

/* ISR funktions prototype */ typedef irqreturn_t (*irq_handler_t)(int, void *) Important methods from wait.h: /* Erklære en 'wait queue' */ DECLARE_WAIT_QUEUE_HEAD(name); /* sleep until woken up and condition is true */ wait_event_interruptible(queue, condition); /* wake up queue subscriber */ void wake_up_interruptible(wait_queue_head_t *queue);

Interrupting GPIO Device Driver
Modify the BOOT_KEY driver adding blocking read functionality. The driver should include a ISR which wakes up the read method, when the BOOT_KEY is either pressed or released.

Subexercise Description
Request an interrupt line in the init method and free it in the exit method. Remember to request GPIO before calling the methods gpio_to_irq and request_irq.

Print the assigned IRQ line using printk. Check the output with dmesg, and check in /proc/interrupts that the driver has been assigned an IRQ line.

Solution
The modified init method:

The added part is line 30-33. The modified exit method:

The added part is line 3. Checking the output from printk: root@beagleboard:~# dmesg | grep GPIO_BOOTKEY [  33.739227] IRQ assigned to GPIO_BOOTKEY: 167 root@beagleboard:~# Checking in /proc/interrupts that the driver has been assigned an interrupt line: root@beagleboard:~# cat /proc/interrupts | grep boot_key 167:         0      GPIO  boot_key root@beagleboard:~#

Subexerise Description
Implement the interrupt service routine as shown in LDD pp. 270. Function parameter number 3 shown in the book is deprecated. Instead the function should look like the following: static irqreturn_t mygpio_isr(int irq, void *dev_id) {  // YOUR CODE HERE return IRQ_HANDLED; } The interrupt routine should only do the following: printk(”IRQ event!!!\n);

Solution
The implemented ISR: Testing the driver:

dmesg after just tapping the BOOT_KEY: [ 1305.539367] IRQ event!!! root@beagleboard:~# Checking that the interrupt is not triggered when the BOOT_KEY is not pressed:

After a while we check dmesg to see that the latest output from the driver is still [ 1305.539367] IRQ event!!!: [ 1305.539367] IRQ event!!! root@beagleboard:~#

Subexercise Description
Modify the read method and the ISR so that read is blocked until the interrupt is triggered. Answer the following questions:
 * Where is the best place to call request_irq method. In the init method or the open method.

Solution
The modified read method: The modified ISR: The best place for calling request_irq and free_irq:

In this exercise request_irq is placed in the init function, and free_irq is placed in the exit function. Another possibility would to place request_irq in the open function and free_irq in the release function. This would mean that the irq would be free until an application opens the device, as opposed to being taken when the driver was loaded.

Checking that read is blocking:

root@beagleboard:~# cat /dev/boot_key 0101010101010101010101010101010

The output shown above was achieved by pressing BOOT_KEY a number of times. The output shifted between 0 and 1 only once for each time BOOT_KEY was pressed or released. This confirms that the reading the device is happening with blocking access as planned.