Linux中斷內核編程
轉自:https://blog.csdn.net/tigerjb/article/details/6069516
在前麵分析了中斷的基本原理後,就可以寫一個內核中斷程序來體驗以下,也可以借此程序繼續深入來了解內核中斷的執行過程
一.內核中斷程序 :
我們還是來看一看成程序:
在看程序之前,要熟悉如何進行模塊編程,和了解module_pararm()的用法。如果不熟悉的話請大家看,module_param()的學習 和Linux內核模塊編程,在此不作解釋。
1.程序interrupt.c
- 1 /*
- 2 *file name :interrupt.c
- 3 *atuthor : john
- 4 */
- 5 #include<linux/init.h>
- 6 #include<linux/module.h>
- 7 #include<linux/kernel.h>
- 8 #include<linux/interrupt.h>
- 9
- 10 MODULE_LICENSE("GPL");
- 11 static int irq;
- 12 char *interface;
- 13 static irqreturn_t myirq_handler(int irq,void *dev);
- 14
- 15 static int __init myirq_init(void)
- 16 {
- 17 printk("the module is working!/n");
- 18 printk("the irq is ready for working!/n");
- 19 if(request_irq(irq,myirq_handler,IRQF_SHARED,interface,&irq)){
- 20 printk(KERN_ERR "%s interrrupt can't register %d IRQ /n",interface,irq);
- 21 return -EIO;
- 22 }
- 23 printk("%s request %d IRQ/n",interface,irq);
- 24 return 0;
- 25 }
- 26 static irqreturn_t myirq_handler(int irq,void *dev)
- 27 {
- 28 printk("%d IRQ is working/n",irq);
- 29 return IRQ_NONE;
- 30 }
- 31 static void __exit myirq_exit(void)
- 32 {
- 33 printk("the module is leaving!/n");
- 34 printk("the irq is bye bye!/n");
- 35 free_irq(irq,&irq);
- 36 printk("%s interrupt free %d IRQ/n",interface,irq);
- 37
- 38 }
- 39 module_init(myirq_init);
- 0 module_exit(myirq_exit);
- 41 module_param(interface,charp,0644);
- 42 module_param(irq,int,0644);
- 43
2.Makefile的編寫
- 1 obj-m:=tiger.o
- 2
- 3 CURRENT_PATH:=$(shell pwd)
- 4 VERSION_NUM:=$(shell uname -r)
- 5 LINUX_PATH:=/usr/src/linux-headers-$(VERSION_NUM)
- 6
- 7
- 8 all :
- 9 make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules
- 10 clean:
- 11 make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean
(程序的調試,加載和運行,在此不進行說明)
3.首先我們來分析下內核加載模塊
在內核加載模塊中最重要的的action就是注冊中斷處理程序。很明顯,這一動作是通過request_irq()函數來完成的。
int request_irq(unsigned int irq, irq_handler_t handler,unsigned long flags, const char *devname, void *dev_id)
A.先來分析形參:
第一個參數irq: 表示要分配的中斷號。對於一些設備(係統時鍾或鍵盤)它的值是預先固定的,而對於大多數設備來說,這個值是動態確定的。
第二個參數 handler: 表示要掛入到中斷請求對列中的中斷服務例程, 這個中斷服務函數的原型是static irqreturn_t handler(int , void *);
中斷處理程序的前綴為static,因為它從來不會被別的文件中的代碼直接調用。
第三個參數flags:為標誌位。可以取IRQF_DISABLED、IRQF_SHARED和IRQF_SAMPLE_RANDOM之一。在本實例程序中取 IRQF_SHARED,該標誌表示多個中斷處理程序共享irq中斷線。一般某個中斷線上的中斷服務程序在執行時會屏蔽請求該線的其他中斷,如果取 IRQF_DISABLED標誌,則在執行該中斷服務程序時會屏蔽所有其他的中斷。取IRQF_SAMPLE_RANDOM則表示設備可以被看做是事件隨見的發生源。
以下是官方解釋:
- /*
- * These flags used only by the kernel as part of the
- * irq handling routines.
- *
- * IRQF_DISABLED - keep irqs disabled when calling the action handler
- * IRQF_SAMPLE_RANDOM - irq is used to feed the random generator
- * IRQF_SHARED - allow sharing the irq among several devices
- * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur
- * IRQF_TIMER - Flag to mark this interrupt as timer interrupt
- * IRQF_PERCPU - Interrupt is per cpu
- * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
- * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
- * registered first in an shared interrupt is considered for
- * performance reasons)
- */
- #define IRQF_DISABLED 0x00000020
- #define IRQF_SAMPLE_RANDOM 0x00000040
- #define IRQF_SHARED 0x00000080
- #define IRQF_PROBE_SHARED 0x00000100
- #define IRQF_TIMER 0x00000200
- #define IRQF_PERCPU 0x00000400
- #define IRQF_NOBALANCING 0x00000800
- #define IRQF_IRQPOLL 0x00001000
第四個參數devname:是請求中斷的設備的名稱。當你加載模塊成功後可以在/proc/interrupts中查看到具體設備的名稱,與此同時也可以看到這個設備對應的中斷號以及請求次數。
第五個參數dev_id:為一個指針型變量。注意該參數為void型,也就是說通過強製轉換可以轉換為任意類型。dev_id主要用於共享中斷線,對每個注冊的中斷處理程序來說,( Dev_id must be globally unique. Normally the address of the device data structure is used as the cookie.)dev_id參數必須唯一(指向任一設備結構的指針就可以滿足此要求,選擇設備結構因為它是唯一的,而且中斷處理程序可能會用到它)如果無需共享中斷線,則將該參數賦值為NULL。
B:函數返回值
requset_irq()函數成功執行後返回0。如果返回非0值,就表示錯誤發生。此時,指定的中斷處理程序不會被注冊。
這裏麵有幾個疑問:
為什麼要注冊中斷函數
共享中斷線的概念,參數dev_id的作用是什麼
看一個圖進行說明 :
1>由圖可知:有16個中斷線。要使用中斷線,就要進行中斷線的 申請 ,也常把申請一條中斷線稱為申請一個中斷號,這就 與request_irq()函數中的第一個形參 irq 有關係 。
2>Linux有256個中斷向量,而外部中中斷向量隻有16個(32~47)。由於硬件上的限製,很多外部設備不得不共享中斷線。
(例如:一些PC機所用的網卡和圖形卡可以把它們分配到一條中斷線上)
讓每個中斷源獨自占用一條中斷線是不實現的。
3>共享中斷線的話雖然解決了中斷資源的問題,但是,此時引出了另一個問題( 任何事物都有其兩麵性 ),此時僅僅用中斷描述符並不能提供中斷產生的所有信息。為了解決這個問題,內核必須對中斷線給出近一步的描述,所以在Linux設計中,為每個中斷請求IRQ設置了一個專用隊列(中斷請求隊列)。
4>中斷服例程序和中斷處理程序的區別:
a.中斷服務例程(interrupt service routine):
Linux中,15條中斷線對應15個中斷處理程序,依次命名是IRQ0x00_interrupt(),IRQ0x01_interrupt()..... IRQ0X1f_interrupt().
中斷處理程序相當於某個中斷向量的總處理程序。
eg:IRQ0X05_interupt()是5號中斷(向量為37)的總處理程序。
b.中斷服務例程是針對一個具體設備的中斷。
5>.注冊中斷服務例程:
在IDT表完成初始化時,每個中斷服務隊列還為空。此時即使打開中斷且某個外設的中斷真的發生了,也得不到實際的服務。因為CPU雖然通過中斷門進入了某個中斷向量的總處理程序。但是,具體的中斷服務例程還沒有掛入中斷請求隊列。所以,在設備驅動程序的初始化階段,必須通過request_irq()函數將響應的中斷服務例程掛入中斷請求隊列,也就是進行注冊。
6>分析一下中斷服務程序,即request_irq()函數中第二個參數所對應的函數
static irqreturn_t myirq_handler(int irq,void *dev_id)
{
printk("ISR is Working/n");
return IRQ_HANDLED;
}
中斷服務例程的形參:
a.int irq :中斷號。
b.void *dev_id :與request_irq()的參數dev_id一致,可以根據這個設備id號得到相應設備的數據結構,進而得到相應設備的信息和相關數據。
c.返回值:中斷程序的返回值是一個特殊類型 rqreturn_t。但是中斷程序的返回值卻隻有兩個值IRQ_NONE和IRQ_HANDLED。
IRQ_NONE:中斷程序接收到中斷信號後發現這並不是注冊時指定的中斷原發出的中斷信號。
IRQ_HANDLED:接收到了準確的中斷信號,並且作了相應正確的處理。
一般 中斷處理程序要做什麼service,主要取決於產生的設備和該設備為什麼要發送中斷。
John哥說明:
1.當一個給定的中斷處理程序正在執行時,這條中斷線上的其它中斷都會被屏蔽。but,所有其他中斷線上的中斷都是打開的。因此這些不同中斷線上的其他中斷都能被處理。
2.request_irq()函數可能會睡眠,所以,不能在中斷上下文或其它不允許阻塞的代碼中調用該函數。
4.在深入分析request_irq()函數之前,先來看幾個重要的數據結構。
A.irqaction的數據結構(用irqaction結構體來描述一個具體的中斷服務例程)
- 113struct irqaction {
- 114 irq_handler_t handler;
- 115 unsigned long flags;
- 116 const char *name;
- 117 void *dev_id;
- 118 struct irqaction *next;
- 119 int irq;
- 120 struct proc_dir_entry *dir;
- 121 irq_handler_t thread_fn;
- 122 struct task_struct *thread;
- 123 unsigned long thread_flags;
- 124};
- 125
1>handler:指向具體的一個中斷服務例程。
2>flags:表示中斷標誌位,對應於request_irq()函數中所傳遞的第三個參數,可取IRQF_DISABLED、IRQF_SAMPLE_RANDOM和IRQF_SHARED其中之一。
3>name:請求中斷的設備名稱,對應request_irq()函數中所傳遞的第四個參數
4>dev_id: 共享中斷時有用。 對應於request_irq()函數中所傳遞的第五個參數,可取任意值,但必須唯一能夠代表發出中斷請求的設備,通常取描述該設備的結構體。
5>strct irqaction *next:指向irqaction描述符的下一個元素。用一條鏈表將共享同一條中斷線上的中斷服務例程鏈接起來。
6>irq:所申請的中斷號
7>dir:指向proc/irq/NN/name entry
8>thread_fn:指向具體的一個線程化的中斷。
9>thread:指向線程中斷的指針。
10>thread_flags:線程中斷的標誌。
B.irq_desc的數據結構體
每個中斷向量都有它自己的irq_desc 描述符。即用irq_desc來描述中斷向量。所有的這些中斷描述符組織在一起就形成了irq_desc irq_desc[NR_IRQS]數組
- 175struct irq_desc {
- 176 unsigned int irq;
- 177 struct timer_rand_state *timer_rand_state;
- 178 unsigned int *kstat_irqs;
- 179#ifdef CONFIG_INTR_REMAP
- 180 struct irq_2_iommu *irq_2_iommu;
- 181#endif
- 182 irq_flow_handler_t handle_irq;
- 183 struct irq_chip *chip;
- 184 struct msi_desc *msi_desc;
- 185 void *handler_data;
- 186 void *chip_data;
- 187 struct irqaction *action; /* IRQ action list */
- 188 unsigned int status; /* IRQ status */
- 189
- 190 unsigned int depth; /* nested irq disables */
- 191 unsigned int wake_depth; /* nested wake enables */
- 192 unsigned int irq_count; /* For detecting broken IRQs */
- 193 unsigned long last_unhandled; /* Aging timer for unhandled count */
- 194 unsigned int irqs_unhandled;
- 195 raw_spinlock_t lock;
- 196#ifdef CONFIG_SMP
- 197 cpumask_var_t affinity;
- 198 const struct cpumask *affinity_hint;
- 199 unsigned int node;
- 200#ifdef CONFIG_GENERIC_PENDING_IRQ
- 201 cpumask_var_t pending_mask;
- 202#endif
- 203#endif
- 204 atomic_t threads_active;
- 205 wait_queue_head_t wait_for_threads;
- 206#ifdef CONFIG_PROC_FS
- 207 struct proc_dir_entry *dir;
- 208#endif
- 209 const char *name;
- 210} ____cacheline_internodealigned_in_smp;
- 211
- 212extern void arch_init_copy_chip_data(struct irq_desc *old_desc,
- 213 struct irq_desc *desc, int node);
- 214extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc);
- 215
- 216#ifndef CONFIG_SPARSE_IRQ
- 217extern struct irq_desc irq_desc[NR_IRQS];
1>irq:表示這個描述符所對應的中斷號。
2>handle_irq:指向該IRQ線的公共服務程序(即該IRQ所對應的中斷處理程序。
3>chip:它是一個struct irq_chip類型的指針,是中斷控製器的描述符 。在2.6以前的版本中它是hw_irq_controller。
4>handler_data:是handler_irq的參數。
5>chip_data:是指向irq_chip的指針。
6>atcion:一個struct irqaction類型的指針,它指向一個單鏈表。該鏈表是由該中斷線上所有中斷服務例程鏈接起來的。
7>status:表示中斷線當前的狀態。
8>depth:中斷線被激活時,值為0;當值為正數時,表示被禁止的次數。
9>irq_count:表示該中斷線上發生中斷的次數
10>irqs_unhandled:該IRQ線上未處理中斷發生的次數
11>name:申請中斷設備的名字。
C.struct irq_chip結構體:
struct irq_chip是一個中斷控製器的描述符。Linux支持N種可編程中斷控製器PIC(中斷控製器),通常不同的體係結構就有一套自己的中斷處理方式。內核為了統一的處理中斷,提供了底層的中斷處理抽象接口,對於每個平台都需要實現底層的接口函數。這樣對於上層的中斷通用處理程序就無需任何改動。
struct irq_chip的具體代碼如下:
- 111struct irq_chip {
- 112 const char *name;
- 113 unsigned int (*startup)(unsigned int irq);
- 114 void (*shutdown)(unsigned int irq);
- 115 void (*enable)(unsigned int irq);
- 116 void (*disable)(unsigned int irq);
- 117
- 118 void (*ack)(unsigned int irq);
- 119 void (*mask)(unsigned int irq);
- 120 void (*mask_ack)(unsigned int irq);
- 121 void (*unmask)(unsigned int irq);
- 122 void (*eoi)(unsigned int irq);
- 123
- 124 void (*end)(unsigned int irq);
- 125 int (*set_affinity)(unsigned int irq,
- 126 const struct cpumask *dest);
- 127 int (*retrigger)(unsigned int irq);
- 128 int (*set_type)(unsigned int irq, unsigned int flow_type);
- 129 int (*set_wake)(unsigned int irq, unsigned int on);
- 130
- 131 void (*bus_lock)(unsigned int irq);
- 132 void (*bus_sync_unlock)(unsigned int irq);
- 133
- 134 /* Currently used only by UML, might disappear one day.*/
- 135#ifdef CONFIG_IRQ_RELEASE_METHOD
- 136 void (*release)(unsigned int irq, void *dev_id);
- 137#endif
- 138 /*
- 139 * For compatibility, ->typename is copied into ->name.
- 140 * Will disappear.
- 141 */
- 142 const char *typename;
- 143};
- 144
name:中斷控製器的名字;
Startup:啟動中斷線;
Shutdown:關閉中斷線;
Enable:允許中斷;
Disable:禁止中斷;
分析了struct irq_desc,struct irq_chip和irqaction的數據結構之後我們來看看他們之間的關係 。
現在深入分析request_irq()內部是如何實現的。
- 135request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
- 136 const char *name, void *dev)
- 137{
- 138 return request_threaded_irq(irq, handler, NULL, flags, name, dev);
- 139}
- 140
可以看到request_irq()函數裏麵有封裝了request_threaded_irq(irq, handler, NULL, flags, name, dev)函數。
先看一下官方的解釋
- 1006/**
- 1007 * request_threaded_irq - allocate an interrupt line
- 1008 * @irq: Interrupt line to allocate
- 1009 * @handler: Function to be called when the IRQ occurs.
- 1010 * Primary handler for threaded interrupts
- 1011 * If NULL and thread_fn != NULL the default
- 1012 * primary handler is installed
- 1013 * @thread_fn: Function called from the irq handler thread
- 1014 * If NULL, no irq thread is created
- 1015 * @irqflags: Interrupt type flags
- 1016 * @devname: An ascii name for the claiming device
- 1017 * @dev_id: A cookie passed back to the handler function
- 1018 *
- 1019 * This call allocates interrupt resources and enables the
- 1020 * interrupt line and IRQ handling. From the point this
- 1021 * call is made your handler function may be invoked. Since
- 1022 * your handler function must clear any interrupt the board
- 1023 * raises, you must take care both to initialise your hardware
- 1024 * and to set up the interrupt handler in the right order.
- 1025 *
- 1026 * If you want to set up a threaded irq handler for your device
- 1027 * then you need to supply @handler and @thread_fn. @handler ist
- 1028 * still called in hard interrupt context and has to check
- 1029 * whether the interrupt originates from the device. If yes it
- 1030 * needs to disable the interrupt on the device and return
- 1031 * IRQ_WAKE_THREAD which will wake up the handler thread and run
- 1032 * @thread_fn. This split handler design is necessary to support
- 1033 * shared interrupts.
- 1034 *
- 1035 * Dev_id must be globally unique. Normally the address of the
- 1036 * device data structure is used as the cookie. Since the handler
- 1037 * receives this value it makes sense to use it.
- 1038 *
- 1039 * If your interrupt is shared you must pass a non NULL dev_id
- 1040 * as this is required when freeing the interrupt.
- 1041 *
- 1042 * Flags:
- 1043 *
- 1044 * IRQF_SHARED Interrupt is shared
- 1045 * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
- 1046 * IRQF_TRIGGER_* Specify active edge(s) or level
- 1047 *
- 1048 */
5.首先分析request_threaded_irq()函數中的各個形參
1>:irq:表示申請的中斷號。
2>:handler:表示中斷服務例程
3.> thread_fn:中斷線程化,此處傳遞的是NULL。NULL表示沒有中斷線程化。
此參數是最新版本中才出現的。為什麼要提出中斷線程化?
在 Linux 中,中斷具有最高的優先級。不論在任何時刻,隻要產生中斷事件,內核將立即執行相應的中斷
處理程序,等到所有掛起的中斷和軟中斷處理完畢後才能執行正常的任務,因此有可能造成實時任務得不
到及時的處理。中斷線程化之後,中斷將作為內核線程運行而且被賦予不同的實時優先級,實時任務可以
有比中斷線程更高的優先級。這樣,具有最高優先級的實時任務就能得到優先處理,即使在嚴重負載下仍
有實時性保證。but,並不是所有的中斷都可以被線程化,比如時鍾中斷,主要用來維護係統時間以及定時器
等,其中定時器是操作係統的脈搏,一旦被線程化,就有可能被掛起,這樣後果將不堪設想,所以不應當
被線程化。
4>.irqflags:表示中斷標誌位。
5>.devname:表示請求中斷的設備的名稱。
6>.dev_id: 對應於request_irq()函數中所傳遞的第五個參數,可取任意值,但必須唯一能夠代表發出中斷請求的設備,通常取描述該設備的結構體。 共享中斷時所用。
現在繼續迭代深入 request_threaded_irq()內部是如何實現的。
- 1049int request_threaded_irq(unsigned int irq, irq_handler_t handler,
- 1050 irq_handler_t thread_fn, unsigned long irqflags,
- 1051 const char *devname, void *dev_id)
- 1052{
- 1053 struct irqaction *action;
- 1054 struct irq_desc *desc;
- 1055 int retval;
- 1056
- 1057 /*
- 1058 * Sanity-check: shared interrupts must pass in a real dev-ID,
- 1059 * otherwise we'll have trouble later trying to figure out
- 1060 * which interrupt is which (messes up the interrupt freeing
- 1061 * logic etc).
- 1062 */
- 1063 if ((irqflags & IRQF_SHARED) && !dev_id)
- 1064 return -EINVAL;
- 1065
- 1066 desc = irq_to_desc(irq);
- 1067 if (!desc)
- 1068 return -EINVAL;
- 1069
- 1070 if (desc->status & IRQ_NOREQUEST)
- 1071 return -EINVAL;
- 1072
- 1073 if (!handler) {
- 1074 if (!thread_fn)
- 1075 return -EINVAL;
- 1076 handler = irq_default_primary_handler;
- 1077 }
- 1078
- 1079 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
- 1080 if (!action)
- 1081 return -ENOMEM;
- 1082
- 1083 action->handler = handler;
- 1084 action->thread_fn = thread_fn;
- 1085 action->flags = irqflags;
- 1086 action->name = devname;
- 1087 action->dev_id = dev_id;
- 1088
- 1089 chip_bus_lock(irq, desc);
- 1090 retval = __setup_irq(irq, desc, action);
- 1091 chip_bus_sync_unlock(irq, desc);
- 1092
- 1093 if (retval)
- 1094 kfree(action);
- 1095
- 1096#ifdef CONFIG_DEBUG_SHIRQ
- 1097 if (!retval && (irqflags & IRQF_SHARED)) {
- 1098 /*
- 1099 * It's a shared IRQ -- the driver ought to be prepared for it
- 1100 * to happen immediately, so let's make sure....
- 1101 * We disable the irq to make sure that a 'real' IRQ doesn't
- 1102 * run in parallel with our fake.
- 1103 */
- 1104 unsigned long flags;
- 1105
- 1106 disable_irq(irq);
- 1107 local_irq_save(flags);
- 1108
- 1109 handler(irq, dev_id);
- 1110
- 1111 local_irq_restore(flags);
- 1112 enable_irq(irq);
- 1113 }
- 1114#endif
- 1115 return retval;
- 1116}
程序的第一行和第二行分別定義了:
(1) struct irqaction *action;
(2)2struct irq_desc *desc;
兩個指針action和desc,它們分別指向了結構體irqaction和 irq_desc。
(3) if ((irqflags & IRQF_SHARED) && !dev_id)
return -EINVAL;
作用是:判斷中斷標誌位,如果是共享中斷的話就必須要有一個唯一的dev_id,否則返回一個錯誤。
(4) desc = irq_to_desc(irq);
irq_to_desc(irq):根據中斷號irq在 irq_desc[NR_IRQS]數組中 返回一個具體的irq_desc。即根據irq找到它的中斷處理程序。
(5) if (!desc)
return -EINVAL;
當返回一個空值時返回一個錯誤。說明申請中斷號失敗。
(6)if (desc->status & IRQ_NOREQUEST)
return -EINVAL;
判斷中斷線的狀態,若為IRQ_NOREQUEST時( IRQ_NOREQUEST表示 IRQ 不能被申請)
(7) if (!handler) {
if (!thread_fn)
return -EINVAL;
handler = irq_default_primary_handler;
}
判斷中斷服務例程是否為空,如果handler為空,則判斷線程中斷服務例程,若線程中斷服務例程也為空,則返回一個錯誤值。否則中斷服務例程指向: rq_default_primary_handler。
(8)
1079 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
1080 if (!action)
1081 return -ENOMEM;
1082
1083 action->handler = handler;
1084 action->thread_fn = thread_fn;
1085 action->flags = irqflags;
1086 action->name = devname;
1087 action->dev_id = dev_id;
從1079~1087:根據requst_irq()函數中傳遞的參數生成一個irqaction.
1097 if (!retval && (irqflags & IRQF_SHARED)) {
1098 /*
1099 * It's a shared IRQ -- the driver ought to be prepared for it
1100 * to happen immediately, so let's make sure....
1101 * We disable the irq to make sure that a 'real' IRQ doesn't
1102 * run in parallel with our fake.
1103 */
1104 unsigned long flags;
1105
1106 disable_irq(irq);
1107 local_irq_save(flags);
1108
1109 handler(irq, dev_id);
1110
1111 local_irq_restore(flags);
1112 enable_irq(irq);
1113 }
1097~1113:如果為共享中斷的話,在執行中斷服務例程之前,要先把這條中斷線上的中斷屏蔽,讓後在執行,執行完之後打開中斷。
6.有注冊中斷服務函數,那必然有相應的釋放中斷函數。
可以調用void free_irq(unsigned int irq, void *dev_id)來釋放我們申請的中斷線。
函數形參:
1>unsigned int riq:表示申請的中斷號與request_irq()函數中的第一個形參對應。
2>void *dev_id:與request_irq()函數中的最後一個形參含義和用法相同,在此不再說明。
函數功能:
如果指定的中斷線不是共享的,那麼,該函數刪除處理程序的同時將禁用這條中斷線。如果中斷線是共享的,則僅刪除dev_id所對應的處理程序,而這條中斷線本省隻有在刪除了最後一個處理程序時才會被禁止。
切記:This function must not be called from interrupt context
freee_irq()函數不能在中斷上下文中被調用。
3>深入分析下free_irq()函數內部是如何實現的
- 993void free_irq(unsigned int irq, void *dev_id)
- 994{
- 995 struct irq_desc *desc = irq_to_desc(irq);
- 996
- 997 if (!desc)
- 998 return;
- 999
- 1000 chip_bus_lock(irq, desc);
- 1001 kfree(__free_irq(irq, dev_id));
- 1002 chip_bus_sync_unlock(irq, desc);
- 1003}
可以看到free_irq()函數了封裝了_free_irq(irq,dev_id)函數。
free_irq()調用_free_irq()把每一個具體的中斷服務例程()釋放。
最後更新:2017-04-03 19:13:18