Linux中断内核编程
前言
在前面分析了中断的基本原理后,就可以写一个内核中断程序来体验以下,也可以借此程序继续深入来了解内核中断的执行过程
一.内核中断程序:
我们还是来看一看成程序:
在看程序之前,要熟悉如何进行模块编程,和了解module_pararm【】的用法。如果不熟悉的话请大家看,module_param【】的学习和Linux内核模块编程,在此不作解释。
1.程序interrupt.c
[c-sharp] view plaincopy
1 /* 2 *file name :interrupt.c
3 *atuthor : john 4 */
5 #include 6 #include
7 #include 8 #include
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 [c-sharp] view plaincopy
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 [c-sharp] view plaincopy
/* * 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
[c-sharp] view plaincopy
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 [c-sharp] view plaincopy
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]; [c-sharp] view plaincopy
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
[c-sharp] view plaincopy
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 [c-sharp] view plaincopy
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 */ [c-sharp] view plaincopy
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} [c-sharp] view plaincopy
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}