Linux Device Driver Programming interrupt handling

Source: Internet
Author: User

The first step related to interrupt handling in Linux device drivers is to apply for and release IRQ APIs request_irq () and free_irq (). The prototype of request_irq () is:


       Int request_irq (unsigned int IRQ,
Void (* Handler) (int irq, void * dev_id, struct pt_regs * regs ),
Unsigned long irqflags,
Const char * devname,
Void * dev_id );

IRQ is the hardware interrupt number to be applied;

Handler is directedSystemThe registration interrupt processing function is a callback function. When an interrupt occurs,SystemCall this function, and the dev_id parameter will be passed;

Irqflags is the attribute of Interrupt Processing. If sa_interrupt is set, it indicates the interrupt processing.ProgramIt is a fast processing program. When a fast processing program is called, all the interruptions are blocked, while the slow processing program is not blocked. If sa_shirq is set, multiple devices share the interruption and dev_id will be used when the sharing is interrupted, it is generally set to the device structure of the device itself or null.

Free_irq () is prototype:


       Void free_irq (unsigned int IRQ, void * dev_id );

        

In addition, an important concept that is closely related to Linux interrupt is that Linux interrupt is divided into two parts: top half (tophalf) and bottom half (bottom half ). The upper half function is "registration interruption". When an interruption occurs, it reads and writes the relevant hardware and then mounts the lower half of the Interrupt Routine to the execution queue of the device. Therefore, the execution speed in the upper half is very fast, and more interrupt requests can be served. However, only "registration interruption" is far from enough, because the interruption event may be complicated. Therefore, Linux introduces a lower half to accomplish the vast majority of the mission of Interrupt events. The biggest difference between the lower half and the upper half is that the lower half can be interrupted, while the upper half cannot be interrupted. The lower half has almost done all the things of the interrupt handler and can be interrupted by new interruptions! The lower half is relatively not very urgent and usually time-consuming.SystemSchedule the running time on your own, not in the context of the interrupted service.

In Linux, the lower half of the implementation mechanism mainly includes tasklet and work queue.

Tasklet is based on Linux softirq. It is quite simple to use. We only need to define tasklet and its processing functions and associate them:


       Void my_tasklet_func (unsigned long); // defines a processing function:
Declare_tasklet (my_tasklet, my_tasklet_func, data); // defines a tasklet structure my_tasklet, which corresponds
The my_tasklet_func (data) function is associated.

Then, when tasklet needs to be scheduled, a simple API can be referencedSystemSchedule and run as appropriate:


       Tasklet_schedule (& my_tasklet );

        

In addition, Linux provides other APIs for controlling tasklet scheduling and running:


       Declare_tasklet_disabled (name, function, data); // similar to declare_tasklet, but wait for the tasklet to be enabled
Tasklet_enable (struct tasklet_struct *); // enable tasklet
Tasklet_disble (struct tasklet_struct *); // disable tasklet
Tasklet_init (struct tasklet_struct *, void (* func) (unsigned long), unsigned long); // similar
Declare_tasklet ()
Tasklet_kill (struct tasklet_struct *); // clear the scheduling bit of the specified tasklet, that is, the tasklet cannot be scheduled.

Let's first look at a tasklet running instance. This instance has no practical significance, just for demonstration. Its function is to schedule a tasklet once globalvar is written, and the function outputs "tasklet is executing ":


        
        #include 
         
         
...
// define and bind the tasklet function
void test_tasklet_action (unsigned long T);
declare_tasklet (test_tasklet, test_tasklet_action, 0 );
void test_tasklet_action (unsigned long T)
{< br> printk ("tasklet is executing \ n ");
}< br>
...
ssize_t globalvar_write (struct file * filp, const char * Buf, size_t Len, loff_t * off)
{< br>...
If (copy_from_user (& global_var, Buf, sizeof (INT)
{< br> return-efault;
}< br>
// schedule tasklet execution
tasklet_schedule (& test_tasklet);
return sizeof (INT);
}

As interruptions are closely related to real hardware, it is meaningless to talk about interruptions without hardware. Let's give a simple example. This example is from the embedded Samsung S3C2410SystemInstance to see the interrupt-related part of the real-time clock driver:


       
        
      Static struct fasync_struct * rtc_async_queue;
Static int _ init rtc_init (void)
{
Misc_register (& rtc_dev );
Create_proc_read_entry ("Driver/RTC", 0, 0, rtc_read_proc, null );

# If rtc_irq
If (rtc_has_irq = 0)
Goto no_irq2;

Init_timer (& rtc_irq_timer );
Rtc_irq_timer.function = rtc_dropped_irq;
Spin_lock_irq (& rtc_lock );
/* Initialize periodic freq. To CMOS reset default, which is 1024Hz */
Cmos_write (cmos_read (rtc_freq_select) & 0xf0) | 0x06), rtc_freq_select );
Spin_unlock_irq (& rtc_lock );
Rtc_freq = 1024;
No_irq2:
# Endif

Printk (kern_info "real time clock driver v" rtc_version "\ n ");
Return 0;
}

Static void _ exit rtc_exit (void)
{
Remove_proc_entry ("Driver/RTC", null );
Misc_deregister (& rtc_dev );

Release_region (rtc_port (0), rtc_io_extent );
If (rtc_has_irq)
Free_irq (rtc_irq, null );
}
Static void rtc_interrupt (int irq, void * dev_id, struct pt_regs * regs)
{
/*
* Can be an alarm interrupt, update complete interrupt,
* Or a periodic interrupt. we store the status in
* Low byte and the number of interrupts encoded ed since
* The Last read in the r emainder of rtc_irq_data.
*/

Spin_lock (& rtc_lock );
Rtc_irq_data + = 0x100;
Rtc_irq_data & = ~ 0xff;
Rtc_irq_data | = (cmos_read (rtc_intr_flags) & 0xf0 );

If (rtc_status & rtc_timer_on)
Mod_timer (& rtc_irq_timer, jiffies + Hz/rtc_freq + 2 * Hz/100 );

Spin_unlock (& rtc_lock );

/* Now do the rest of the actions */
Wake_up_interruptible (& rtc_wait );

Kill_fasync (& rtc_async_queue, sigio, poll_in );
}

Static int rtc_fasync (int fd, struct file * filp, int on)
{
Return fasync_helper (FD, filp, on, & rtc_async_queue );
}

Static void rtc_dropped_irq (unsigned long data)
{
Unsigned long freq;

Spin_lock_irq (& rtc_lock );

/* Just in case someone disabled the timer from behind our back ...*/
If (rtc_status & rtc_timer_on)
Mod_timer (& rtc_irq_timer, jiffies + Hz/rtc_freq + 2 * Hz/100 );

Rtc_irq_data + = (rtc_freq/Hz) <8 );
Rtc_irq_data & = ~ 0xff;
Rtc_irq_data | = (cmos_read (rtc_intr_flags) & 0xf0);/* restart */

Freq = rtc_freq;

Spin_unlock_irq (& rtc_lock );
Printk (kern_warning "RTC: lost some interrupts at % ldhz. \ n", freq );

/* Now we have new data */
Wake_up_interruptible (& rtc_wait );

Kill_fasync (& rtc_async_queue, sigio, poll_in );
}

After the RTC interrupt occurs, an asynchronous signal is triggered. Therefore, the driver provides support for the asynchronous signal in section 6th. Not every interrupt requires a lower half. If it is not complicated to handle, there may be only one upper half. In this example, the RTC driver is like this.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.