pasckr 发表于 2016-5-9 15:49:32

linux中断--内核中断编程




                Linux中断内核编程
  前言
  在前面分析了中断的基本原理后,就可以写一个内核中断程序来体验以下,也可以借此程序继续深入来了解内核中断的执行过程
  一.内核中断程序:
  我们还是来看一看成程序:
  在看程序之前,要熟悉如何进行模块编程,和了解module_pararm()的用法。如果不熟悉的话请大家看,module_param()的学习和Linux内核模块编程,在此不作解释。
  1.程序interrupt.c
   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 forworking!/n");
  19 if(request_irq(irq,myirq_handler,IRQF_SHARED,interface,&irq)){ 20printk(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 byebye!/n");
  35 free_irq(irq,&irq); 36 printk("%s interrupt free %dIRQ/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 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 viewplaincopy
  /* * 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 tooccur
  * 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 * performancereasons)
  */ #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
   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 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 intstatus; /* IRQ status */
  189 190 unsigned int depth; /* nested irq disables */
  191 unsigned int wake_depth; /* nested wake enables */ 192 unsigned intirq_count; /* For detecting broken IRQs */
  193 unsigned long last_unhandled; /* Aging timer for unhandled count */ 194unsigned 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 voidarch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc);
  215 216#ifndef CONFIG_SPARSE_IRQ
  217extern struct irq_desc irq_desc; 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 intirq);
  117 118 void (*ack)(unsigned int irq);
  119 void (*mask)(unsigned int irq); 120 void (*mask_ack)(unsigned intirq);
  121 void (*unmask)(unsigned int irq); 122 void (*eoi)(unsigned intirq);
  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 intirq, 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 * Willdisappear.
  141 */ 142 const char *typename;
  143}; 144
   view plaincopy
  135request_irq(unsigned int irq, irq_handler_t handler, unsigned longflags, 136 const char *name, void *dev)
  137{ 138 return request_threaded_irq(irq, handler, NULL, flags, name,dev);
  139} 140 view plaincopy
  1006/** 1007 * request_threaded_irq - allocate an interrupt line
  1008 * @irq: Interrupt line to allocate 1009 * @handler: Function to becalled 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 fromthe irq handler thread
  1014 * If NULL, no irq thread is created 1015 * @irqflags: Interrupt typeflags
  1016 * @devname: An ascii name for the claiming device 1017 * @dev_id: Acookie 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 ismade 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 ofthe
  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 NULLdev_id
  1040 * as this is required when freeing the interrupt. 1041 *
  1042 * Flags: 1043 *
  1044 * IRQF_SHARED Interrupt is shared 1045 * IRQF_SAMPLE_RANDOM Theinterrupt can be used for entropy
  1046 * IRQF_TRIGGER_* Specify active edge(s) or level 1047 *
  1048 */ view plaincopy
  1049int request_threaded_irq(unsigned int irq, irq_handler_t handler, 1050irq_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 realdev-ID,
  1059 * otherwise we'll have trouble later trying to figure out 1060 * whichinterrupt 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 * runin 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} 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}
页: [1]
查看完整版本: linux中断--内核中断编程