国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Linux設(shè)備驅(qū)動編程之中斷處理
Linux設(shè)備驅(qū)動編程之中斷處理

 

Linux設(shè)備驅(qū)動中中斷處理相關(guān)的首先是申請與釋放IRQAPI 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是向系統(tǒng)登記的中斷處理函數(shù),是一個(gè)回調(diào)函數(shù),中斷發(fā)生時(shí),系統(tǒng)調(diào)用這個(gè)函數(shù),dev_id參數(shù)將被傳遞;

  irqflags是中斷處理的屬性,若設(shè)置SA_INTERRUPT,標(biāo)明中斷處理程序是快速處理程序,快速處理程序被調(diào)用時(shí)屏蔽所有中斷,慢速處理程序不屏蔽;若設(shè)置SA_SHIRQ,則多個(gè)設(shè)備共享中斷,dev_id在中斷共享時(shí)會用到,一般設(shè)置為這個(gè)設(shè)備的device結(jié)構(gòu)本身或者NULL。

  free_irq()的原型為:

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


  另外,與Linux中斷息息相關(guān)的一個(gè)重要概念是Linux中斷分為兩個(gè)半部:上半部(tophalf)和下半部(bottom half)。上半部的功能是"登記中斷",當(dāng)一個(gè)中斷發(fā)生時(shí),它進(jìn)行相應(yīng)地硬件讀寫后就把中斷例程的下半部掛到該設(shè)備的下半部執(zhí)行隊(duì)列中去。因此,上半部執(zhí)行的速度就會很快,可以服務(wù)更多的中斷請求。但是,僅有"登記中斷"是遠(yuǎn)遠(yuǎn)不夠的,因?yàn)橹袛嗟氖录赡芎軓?fù)雜。因此,Linux引入了一個(gè)下半部,來完成中斷事件的絕大多數(shù)使命。下半部和上半部最大的不同是下半部是可中斷的,而上半部是不可中斷的,下半部幾乎做了中斷處理程序所有的事情,而且可以被新的中斷打斷!下半部則相對來說并不是非常緊急的,通常還是比較耗時(shí)的,因此由系統(tǒng)自行安排運(yùn)行時(shí)機(jī),不在中斷服務(wù)上下文中執(zhí)行。

  Linux實(shí)現(xiàn)下半部的機(jī)制主要有tasklet和工作隊(duì)列。

  tasklet基于Linux softirq,其使用相當(dāng)簡單,我們只需要定義tasklet及其處理函數(shù)并將二者關(guān)聯(lián):

void my_tasklet_func(unsigned long); //定義一個(gè)處理函數(shù):
DECLARE_TASKLET(my_tasklet,my_tasklet_func,data); //
定義一個(gè)tasklet結(jié)構(gòu)my_tasklet,與my_tasklet_func(data)函數(shù)相關(guān)聯(lián)


  然后,在需要調(diào)度tasklet的時(shí)候引用一個(gè)簡單的API就能使系統(tǒng)在適當(dāng)?shù)臅r(shí)候進(jìn)行調(diào)度運(yùn)行:

tasklet_schedule(&my_tasklet);


  此外,Linux還提供了另外一些其它的控制tasklet調(diào)度與運(yùn)行的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的可調(diào)度位,即不允許調(diào)度該tasklet


  我們先來看一個(gè)tasklet的運(yùn)行實(shí)例,這個(gè)實(shí)例沒有任何實(shí)際意義,僅僅為了演示。它的功能是:在globalvar被寫入一次后,就調(diào)度一個(gè)tasklet,函數(shù)中輸出"tasklet is executing"

#include <linux/interrupt.h>

//
定義與綁定tasklet函數(shù)
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;
 }

 //調(diào)度tasklet執(zhí)行
 tasklet_schedule(&test_tasklet);
 return sizeof(int);
}


  由于中斷與真實(shí)的硬件息息相關(guān),脫離硬件而空談中斷是毫無意義的,我們還是來舉一個(gè)簡單的例子。這個(gè)例子來源于SAMSUNG S3C2410嵌入式系統(tǒng)實(shí)例,看看其中實(shí)時(shí)鐘的驅(qū)動中與中斷相關(guān)的部分:

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中斷發(fā)生后,激發(fā)了一個(gè)異步信號,因此本驅(qū)動程序提供了對第6節(jié)異步信號的支持。并不是每個(gè)中斷都需要一個(gè)下半部,如果本身要處理的事情并不復(fù)雜,可能只有一個(gè)上半部,本例中的RTC驅(qū)動就是如此。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
項(xiàng)目經(jīng)驗(yàn)雜記
linux內(nèi)核--中斷處理程序
Linux內(nèi)核開發(fā)之中斷與時(shí)鐘
SDIO架構(gòu)初解
linux設(shè)備驅(qū)動歸納總結(jié)(六):3.中斷的上半部和下半部——tasklet
Linux RTC驅(qū)動分析(二)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服