深入淺出 Linux裝置驅動中斷處理介紹

來源:互聯網
上載者:User

深入淺出 Linux裝置驅動中斷處理介紹

與Linux裝置驅動中中斷處理相關的首先是申請與釋放IRQ的API: request_irq()和free_irq()。

request_irq()的原型為:

 

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是要申請的硬體中斷號;

handler是向系統登記的中斷處理函數,是一個回呼函數,中斷髮生時,系統調用這個函數,dev_id參數將被傳遞;

irqflags是中斷處理的屬性,若設定SA_INTERRUPT,標明中斷處理 程式是快速處理常式,快速處理常式被調用時屏蔽所有中斷,慢速處理常式不屏蔽;若設定SA_SHIRQ,則多個裝置共用中斷,dev_id在中斷共用時會 用到,一般設定為這個裝置的device結構本身或者NULL。

free_irq()的原型為:

void free_irq(unsigned int irq,void *dev_id);

另外,與Linux中斷息息相關的一個重要概念是Linux中斷分為兩個半部:上半 部(tophalf)和下半部(bottom half)。上半部的功能是"登記中斷",當一個中斷髮生時,它進行相應地硬體讀寫後就把中斷常式的下半部掛到該裝置的下半部執行隊列中去。因此,上半部 執行的速度就會很快,可以服務更多的插斷要求。但是,僅有"登記中斷"是遠遠不夠的,因為中斷的事件可能很複雜。因此,Linux引入了一個下半部,來完 成中斷事件的絕大多數使命。下半部和上半部最大的不同是下半部是可中斷的,而上半部是不可中斷的,下半部幾乎做了中斷處理常式所有的事情,而且可以被新的 中斷打斷!下半部則相對來說並不是非常緊急的,通常還是比較耗時的,因此由系統自行安排運行時機,不在中斷服務上下文中執行。

Linux實現下半部的機制主要有tasklet和工作隊列。

tasklet基於Linux softirq,其使用相當簡單,我們只需要定義tasklet及其處理函數並將二者關聯:

void my_tasklet_func(unsigned long); //定義一個處理函數:

DECLARE_TASKLET(my_tasklet,my_tasklet_func,data); //定義一個tasklet結構my_tasklet,與my_tasklet_func(data)函數相關聯

然後,在需要調度tasklet的時候引用一個簡單的API就能使系統在適當的時候進行調度運行:

tasklet_schedule(&my_tasklet);

此外,Linux還提供了另外一些其它的控制tasklet調度與啟動並執行API:

 

DECLARE_TASKLET_DISABLED(name,function,data); //與DECLARE_TASKLET類似,但等待tasklet被使能 tasklet_enable(struct tasklet_struct *); //使能tasklet tasklet_disble(struct tasklet_struct *); //禁用tasklet tasklet_init(struct tasklet_struct *,void (*func)(unsigned long),unsigned long); //類似DECLARE_TASKLET() tasklet_kill(struct tasklet_struct *); // 清除指定tasklet的可調度位,即不允許調度該tasklet

我們先來看一個tasklet的運行執行個體,這個執行個體沒有任何實際意義,僅僅為了示範。它的功能是:在globalvar被寫入一次後,就調度一個tasklet,函數中輸出"tasklet is executing":

 

#include <linux/interrupt.h> … //定義與綁定tasklet函數 void test_tasklet_action(unsigned long t); DECLARE_TASKLET(test_tasklet, test_tasklet_action, 0); void test_tasklet_action(unsigned long t) {  printk("tasklet is executing/n"); } … ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off) {  …  if (copy_from_user(&global_var, buf, sizeof(int)))  {   return - EFAULT;  }  //調度tasklet執行 tasklet_schedule(&test_tasklet);  return sizeof(int); }

由於中斷與真實的硬體息息相關,脫離硬體而空談中斷是毫無意義的,我們還是來舉一個簡單的例子。這個例子來源於SAMSUNG S3C2410嵌入式系統執行個體,看看其中即時鐘的驅動中與中斷相關的部分:

 

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 the * low byte and the number of interrupts received since * the last read in the remainder 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);                        }

RTC中斷髮生後,激發了一個非同步訊號,因此本驅動程式提供了對第6節非同步訊號的支援。並不是每個中斷都需要一個下半部,如果本身要處理的事情並不複雜,可能只有一個上半部,本例中的RTC驅動就是如此。

 

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/gothicane/archive/2007/08/12/1739562.aspx

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.