当前位置:   article > 正文

petalinux驱动实践10:中断_petalinux 查看中断源

petalinux 查看中断源

接口函数

Linux 内核中的中断框架使用已经相当便捷,一般需要做三件事申请中断、实现中断服务函数、使能中断。对应的接口函数如下:
( ) 中断申请和释放函数
1) 中断申请凼数 request_irq ,该凼数可能会导致睡眠,在申请成功后会使能中断,凼数
原型:
int request_irq(unsignedintirq,irq_handler_t handler, unsigned long flags, const char*name,void*dev);
参数说明:
irq :申请的中断号,中断号也可以叫中断线,是中断的唯一标识,也是内核找到对应中断
服务函数的依据。
handler :中断服务函数,中断触发后会执行的函数。
flags :中断标志,用于设置中断的触发方式和其他特性,常用的标识有
/* 无触发  */
IRQF_TRIGGER_NONE
/* 上升沿触发*/
IRQF_TRIGGER_RISING
/* 下降沿触发*/
IRQF_TRIGGER_FALLING
/* 高电平触发*/
IRQF_TRIGGER_HIGH
/* 低电平触发*/
IRQF_TRIGGER_LOW
/* 单次中断 */
IRQF_ONESHOT
/* 作为定时器中断 */
IRQF_TIMER
/* 共享中断,多个设备共享一个中断号时需要此标志 */
IRQF_SHARED
可在 /include/linux/interrupt.h 文件中可以查看全部的 flag 和 英文释义。中断标志可以使用 |
号来组合,如 IRQF_TRIGGER_RISING|IRQF_ONESHOT 意为上升沿触发的单次中断。
name :中断名称,申请中断成功后,在 /proc/interrupts 文件中可以找到这个名字。
dev flag 设 IRQF_SHARED 时,使用 dev 来区分不同的讴备, dev 的值会传递经中断服务函数的第二个参数。
返回值 0- 申请成功, -EBUSY- 中断已被占用,其他值都表示申请失败。
2) 和 中断申请相对的中断释放函数 free_irq ,如果目标中断不是共享中断,那么  free_irq
凼数在释放中断后,会禁止中断并删除中断服务函数,原型如下:
void free_irq(unsigned int irq, void *dev);
参数说明:
irq :需要释放的中断。
dev :释放的中断如果是共享中断,用这个参数来区分具体的中断,只有共享中断下所有的
dev 都被释放时, free_irq 函 数才会禁止中断并删除中断服务函数。

中断服务函数的格式为:

irqreturn_t (*irq_handler_t) (int, void *)
第一个参数 是int类型, 中断服务函数对应的中断号。
第二个参数是通用指针,需要和 request_irq 函 数的参数 dev 一致。
返回值 irqreturn_t 为枚举类型,一般在服务函数中用下面的方式返回值:
return IRQ_RETVAL(IRQ_HANDLED);

中断使能和禁止函数

1) enable_irq(unsigned int irq) disable_irq(unsigned int irq)和   disable_irq_nosync(unsigned int irq)
enable_irq 和   disable_irq 分别是中断使能和禁止函数, irq 是目标中断号。 disable_irq 会等待目标中断的中断服务函数执行结束才会禁止中断,如果想要立即禁止中断则可以使用
disable_irq_nosync()函 数。
2) local_irq_enable()和   local_irq_disable()
local_irq_enable()函 数用于使能当前处理器的中断系统。
local_irq_disable()函 数用于禁止当前处理器的中断系统。
3) local_irq_save(flags)和 local_irq_restore(flags)
local_irq_save(flags)函 数也是用于禁止当前处理器中断,但是会把之前前的中断状态保存在
输入参数 flags 中。而 local_irq_restore(flags)函 数则是把中断恢复到 flags 中记录的状态。

struct tasklet_struct

  1. struct tasklet_struct
  2. {
  3. struct tasklet_struct *next;
  4. unsigned long state;
  5. atomic_t count;
  6. void (*func)(unsigned long);
  7. unsigned long data;
  8. };

extern void tasklet_kill(struct tasklet_struct *t);
extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu);
extern void tasklet_init(struct tasklet_struct *t,
             void (*func)(unsigned long), unsigned long data);
static inline void tasklet_enable(struct tasklet_struct *t)
static inline void tasklet_disable(struct tasklet_struct *t)
static inline void tasklet_disable_nosync(struct tasklet_struct *t)

static inline void tasklet_schedule(struct tasklet_struct *t)

struct tasklet_struct和timer测试 

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/cdev.h>
  4. #include <linux/slab.h>
  5. #include <linux/fs.h>
  6. #include <linux/device.h>
  7. #include <linux/kernel.h>
  8. #include <linux/types.h>
  9. #include <linux/kref.h>
  10. #include <linux/uaccess.h>
  11. #include <linux/ide.h>
  12. #include <linux/of.h>
  13. #include <linux/gpio/consumer.h>
  14. #include <linux/delay.h>
  15. #include <linux/timer.h>
  16. #include <linux/jiffies.h>
  17. #define DEBUG_INFO(format,...) printk(KERN_ERR"%s:%d"format"\n",\
  18. __func__,__LINE__,##__VA_ARGS__)
  19. struct ch7_private_data{
  20. struct timer_list timer;
  21. int count;
  22. long last_jiffies;
  23. struct tasklet_struct tasklet;
  24. };
  25. void tasklet_func(unsigned long arg)
  26. {
  27. struct ch7_private_data *p = (struct ch7_private_data*)arg;
  28. DEBUG_INFO("p->count = %d",p->count++);
  29. }
  30. void ch7_timer_function(struct timer_list *ptimer){
  31. struct ch7_private_data *p = (struct ch7_private_data*)container_of(ptimer,struct ch7_private_data,timer);
  32. if(p == NULL){
  33. DEBUG_INFO("container_of error");
  34. return ;
  35. }
  36. if(p->count >= 5){
  37. }else{
  38. mod_timer(&p->timer,jiffies + msecs_to_jiffies(1000));
  39. }
  40. tasklet_schedule(&p->tasklet);
  41. }
  42. struct ch7_private_data *ch7_02;
  43. static int __init ch7_init(void)
  44. {
  45. struct ch7_private_data *p = (struct ch7_private_data*)kmalloc(sizeof(struct ch7_private_data),GFP_KERNEL);
  46. if(p == NULL){
  47. DEBUG_INFO("kmalloc error");
  48. return -ENOMEM;
  49. }
  50. DEBUG_INFO("%ld" ,sizeof(jiffies));
  51. ch7_02 = p;
  52. p->count = 0;
  53. timer_setup(&p->timer,ch7_timer_function,0);
  54. tasklet_init(&p->tasklet, tasklet_func, (unsigned long)p);
  55. mod_timer(&p->timer,jiffies + msecs_to_jiffies(1000));
  56. DEBUG_INFO("init");
  57. return 0;
  58. }
  59. static void __exit ch7_exit(void)
  60. {
  61. struct ch7_private_data *p = ch7_02;
  62. del_timer_sync(&p->timer);
  63. DEBUG_INFO("exit");
  64. }
  65. // #define nodule_init(x) (x)
  66. module_init(ch7_init);
  67. module_exit(ch7_exit);
  68. MODULE_LICENSE("GPL");

makefile

  1. modname:=ch08-tasklet
  2. obj-m:=$(modname).o
  3. PWD :=$(shell pwd)
  4. KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/petalinux_bsp/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
  5. # KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/ch6-petalinux/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
  6. CROSS_COMPILE=aarch64-linux-gnu-
  7. ARCH=arm64
  8. all:
  9. $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
  10. cp $(modname).ko ~/work/nfsroot/
  11. # aarch64-linux-gnu-gcc -o app app.c
  12. # cp app ~/work/nfsroot/
  13. clean:
  14. rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions
  15. .PHONY: all clean

测试结果:

 struct work_struct

  1. struct work_struct {
  2. atomic_long_t data;
  3. struct list_head entry;
  4. work_func_t func;
  5. #ifdef CONFIG_LOCKDEP
  6. struct lockdep_map lockdep_map;
  7. #endif
  8. };

初始化函数 

#define INIT_WORK(_work, _func)                     \

    __INIT_WORK((_work), (_func), 0)

_work: struct work_struct*指针。

_func:void (*func)(unsigned long)类型

调度函数 

 static inline bool schedule_work(struct work_struct *work)

测试代码:

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/cdev.h>
  4. #include <linux/slab.h>
  5. #include <linux/fs.h>
  6. #include <linux/device.h>
  7. #include <linux/kernel.h>
  8. #include <linux/types.h>
  9. #include <linux/kref.h>
  10. #include <linux/uaccess.h>
  11. #include <linux/ide.h>
  12. #include <linux/of.h>
  13. #include <linux/gpio/consumer.h>
  14. #include <linux/delay.h>
  15. #include <linux/timer.h>
  16. #include <linux/jiffies.h>
  17. #include <linux/workqueue.h>
  18. #define DEBUG_INFO(format,...) printk(KERN_ERR"%s:%d"format"\n",\
  19. __func__,__LINE__,##__VA_ARGS__)
  20. struct ch7_private_data{
  21. struct timer_list timer;
  22. int count;
  23. long last_jiffies;
  24. struct work_struct work;
  25. };
  26. void ch8_work_func_t(struct work_struct *pwork){
  27. struct ch7_private_data *p = (struct ch7_private_data*)container_of(pwork,struct ch7_private_data,work);
  28. DEBUG_INFO("p->count = %d",p->count++);
  29. }
  30. void ch7_timer_function(struct timer_list *ptimer){
  31. struct ch7_private_data *p = (struct ch7_private_data*)container_of(ptimer,struct ch7_private_data,timer);
  32. if(p == NULL){
  33. DEBUG_INFO("container_of error");
  34. return ;
  35. }
  36. if(p->count >= 5){
  37. }else{
  38. mod_timer(&p->timer,jiffies + msecs_to_jiffies(1000));
  39. }
  40. schedule_work(&p->work);
  41. }
  42. struct ch7_private_data *ch7_02;
  43. static int __init ch7_init(void)
  44. {
  45. struct ch7_private_data *p = (struct ch7_private_data*)kmalloc(sizeof(struct ch7_private_data),GFP_KERNEL);
  46. if(p == NULL){
  47. DEBUG_INFO("kmalloc error");
  48. return -ENOMEM;
  49. }
  50. DEBUG_INFO("%ld" ,sizeof(jiffies));
  51. ch7_02 = p;
  52. p->count = 0;
  53. timer_setup(&p->timer,ch7_timer_function,0);
  54. INIT_WORK(&p->work,ch8_work_func_t);
  55. mod_timer(&p->timer,jiffies + msecs_to_jiffies(1000));
  56. DEBUG_INFO("init");
  57. return 0;
  58. }
  59. static void __exit ch7_exit(void)
  60. {
  61. struct ch7_private_data *p = ch7_02;
  62. del_timer_sync(&p->timer);
  63. DEBUG_INFO("exit");
  64. }
  65. // #define nodule_init(x) (x)
  66. module_init(ch7_init);
  67. module_exit(ch7_exit);
  68. MODULE_LICENSE("GPL");

makefile

  1. modname:=ch8-workqueue
  2. obj-m:=$(modname).o
  3. PWD :=$(shell pwd)
  4. KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/petalinux_bsp/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
  5. # KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/ch6-petalinux/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
  6. CROSS_COMPILE=aarch64-linux-gnu-
  7. ARCH=arm64
  8. all:
  9. $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
  10. cp $(modname).ko ~/work/nfsroot/
  11. # aarch64-linux-gnu-gcc -o app app.c
  12. # cp app ~/work/nfsroot/
  13. clean:
  14. rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions
  15. .PHONY: all clean

测试结果:

 按键中断测试:

测试代码:

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/cdev.h>
  4. #include <linux/slab.h>
  5. #include <linux/fs.h>
  6. #include <linux/device.h>
  7. #include <linux/kernel.h>
  8. #include <linux/types.h>
  9. #include <linux/kref.h>
  10. #include <linux/uaccess.h>
  11. #include <linux/ide.h>
  12. #include <linux/of.h>
  13. #include <linux/gpio/consumer.h>
  14. #include <linux/delay.h>
  15. #include <linux/timer.h>
  16. #define _DEBUG_INFO
  17. #ifdef _DEBUG_INFO
  18. #define DEBUG_INFO(format,...) printk(KERN_ERR"%s:%d -- "format"\n",\
  19. __func__,__LINE__,##__VA_ARGS__)
  20. #else
  21. #define DEBUG_INFO(format,...)
  22. #endif
  23. #define CH2_DRIVER_NAME "ch8_key"
  24. #define CH2_CLASS_NAME "ch8_driver_class_name"
  25. #define CH2_BUF_MAX_LEN 20
  26. struct ch2_private_data{
  27. struct cdev cdev;
  28. dev_t devid;
  29. int dev_count;
  30. int major,minor;
  31. struct file_operations *fops;
  32. struct class *class;
  33. struct device *device;
  34. struct device_node *nd;
  35. struct gpio_desc *gpio_d;
  36. struct semaphore lock;
  37. unsigned int irq;
  38. struct timer_list timer;
  39. char key_state;
  40. };
  41. static irqreturn_t key_handler(int irq, void *dev)
  42. {
  43. struct ch2_private_data * cpd = (struct ch2_private_data*)dev;
  44. mod_timer(&cpd->timer, jiffies + msecs_to_jiffies(10));
  45. // DEBUG_INFO("key pressed");
  46. return IRQ_RETVAL(IRQ_HANDLED);
  47. }
  48. void timer_function(struct timer_list *ptimer)
  49. {
  50. struct ch2_private_data * cpd = (struct ch2_private_data*)container_of(ptimer,struct ch2_private_data,timer);
  51. cpd->key_state = 1;
  52. DEBUG_INFO("key up");
  53. }
  54. static int ch2_open(struct inode *inode, struct file *file){
  55. int ret = 0;
  56. struct ch2_private_data * cpd = (struct ch2_private_data*)container_of(inode->i_cdev,struct ch2_private_data,cdev);
  57. DEBUG_INFO("major = %d, minor = %d\n", cpd->major, cpd->minor);
  58. file->private_data = cpd;
  59. ret = down_interruptible(&cpd->lock);
  60. if(ret){
  61. DEBUG_INFO("open fail");
  62. ret = -EBUSY;
  63. }else{
  64. DEBUG_INFO("open ok");
  65. }
  66. return ret;
  67. }
  68. static ssize_t ch2_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
  69. {
  70. int ret = 0;
  71. char state[2] = {0x30,0x00};
  72. struct ch2_private_data * cpd = (struct ch2_private_data*)file->private_data;
  73. if(cpd->key_state == 1){
  74. state[0] = 0x31;
  75. }else{
  76. state[0] = 0x30;
  77. }
  78. cpd->key_state = 0;
  79. ret = copy_to_user(buf,state,1);
  80. if(ret){
  81. DEBUG_INFO("copy_to_user error");
  82. return 0;
  83. }
  84. if(*pos == 0){
  85. *pos = 1;
  86. ret = 1;
  87. return ret;
  88. }
  89. return 0;
  90. }
  91. static int ch2_release(struct inode *inode, struct file *file){
  92. struct ch2_private_data * cpd = (struct ch2_private_data*)container_of(inode->i_cdev,struct ch2_private_data,cdev);
  93. up(&cpd->lock);
  94. DEBUG_INFO("release");
  95. return 0;
  96. }
  97. struct file_operations ch2_fops={
  98. .owner = THIS_MODULE,
  99. .open = ch2_open,
  100. .release = ch2_release,
  101. .read = ch2_read,
  102. };
  103. struct ch2_private_data *global_chd = NULL;
  104. static int __init ps_led_init(void)
  105. {
  106. int res = 0;
  107. // u32 reg_data[6] = {0};
  108. struct ch2_private_data *chd = (struct ch2_private_data*)kmalloc(sizeof(struct ch2_private_data),GFP_KERNEL);
  109. if(chd == NULL){
  110. DEBUG_INFO("kmalloc");
  111. return -ENOMEM;
  112. }
  113. global_chd = chd;
  114. chd->dev_count = 1;
  115. chd->fops = &ch2_fops;
  116. cdev_init(&chd->cdev,chd->fops);
  117. res = alloc_chrdev_region(&chd->devid,1,chd->dev_count,CH2_DRIVER_NAME);
  118. if(res != 0){
  119. DEBUG_INFO("kmaalloc_chrdev_regionlloc");
  120. return -EINVAL;
  121. }
  122. chd->major = MAJOR(chd->devid);
  123. chd->minor = MINOR(chd->devid);
  124. cdev_add(&chd->cdev,chd->devid,chd->dev_count);
  125. chd->class = class_create(THIS_MODULE,CH2_CLASS_NAME);
  126. if(IS_ERR(chd->class)){
  127. DEBUG_INFO("class_create");
  128. return -EINVAL;
  129. }
  130. chd->device = device_create(chd->class,NULL,chd->devid,NULL,CH2_DRIVER_NAME"_%d",0);
  131. if(IS_ERR(chd->class)){
  132. DEBUG_INFO("device_create");
  133. return -EINVAL;
  134. }
  135. chd->nd = of_find_node_by_path("/alinxkeypl");
  136. if(chd->nd == NULL){
  137. DEBUG_INFO("of_find_node_by_path error");
  138. return 0;
  139. }
  140. chd->device->of_node = chd->nd;
  141. chd->gpio_d = gpiod_get_index(chd->device, "key", 0, GPIOD_IN);
  142. if(chd->gpio_d == NULL){
  143. DEBUG_INFO("gpiod_get_index error");
  144. return 0;
  145. }
  146. gpiod_direction_input(chd->gpio_d);
  147. sema_init(&chd->lock, 1);
  148. chd->key_state = 0;
  149. chd->irq = gpiod_to_irq(chd->gpio_d);
  150. res = request_irq(chd->irq, key_handler, IRQF_TRIGGER_RISING, "alinxkey", chd);
  151. if(res < 0){
  152. DEBUG_INFO("request_irq error");
  153. return 0;
  154. }
  155. timer_setup(&chd->timer, timer_function, 0);
  156. // add_timer(&chd->timer);
  157. DEBUG_INFO("init ok");
  158. return 0;
  159. }
  160. static void __exit ps_led_exit(void)
  161. {
  162. del_timer(&global_chd->timer);
  163. free_irq(global_chd->irq,global_chd);
  164. gpiod_put(global_chd->gpio_d);
  165. device_destroy(global_chd->class,global_chd->devid);
  166. class_destroy(global_chd->class);
  167. cdev_del(&global_chd->cdev);
  168. unregister_chrdev_region(global_chd->devid,global_chd->dev_count);
  169. kfree(global_chd);
  170. DEBUG_INFO("exit");
  171. }
  172. module_init(ps_led_init);
  173. module_exit(ps_led_exit);
  174. MODULE_LICENSE("GPL");

makefile:

  1. modname:=ch8-01
  2. obj-m:=$(modname).o
  3. PWD :=$(shell pwd)
  4. # KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/petalinux_bsp/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
  5. KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/ch6-petalinux/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
  6. CROSS_COMPILE=aarch64-linux-gnu-
  7. ARCH=arm64
  8. all:
  9. $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
  10. cp $(modname).ko ~/work/nfsroot/
  11. # aarch64-linux-gnu-gcc -o app app.c
  12. # cp app ~/work/nfsroot/
  13. clean:
  14. rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions
  15. .PHONY: all clean

 小结

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/713228
推荐阅读
相关标签
  

闽ICP备14008679号