九、【interrupt】按键中断
一、linux内核中中断的使用
1、申请中断
1 | static inline int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) |
参数:
- irq: 中断号
- handler:中断处理程序
- flags:中断标志,
对应外部中断,flags表示中断触发的方式:
1 2 3 4 5 | #define IRQF_TRIGGER_NONE 0x00000000 #define IRQF_TRIGGER_RISING 0x00000001 #define IRQF_TRIGGER_FALLING 0x00000002 #define IRQF_TRIGGER_HIGH 0x00000004 #define IRQF_TRIGGER_LOW 0x00000008 |
对于其他一般中断,flags用于设置中断的处理方式:
1 2 3 | #define IRQF_DISABLED 0x00000020 #define IRQF_SAMPLE_RANDOM 0x00000040 #define IRQF_SHARED 0x00000080 |
- name:自定义的中断名。
- dev:传递给中断处理程序的实参。
返回值:
成功返回0,否则返回负值。
2、中断处理程序
1 | irqreturn_t xxx_handler( int irq, void * dev |
参数:
- irq:中断号。
- dev:中断申请函数传过来的参数。
返回值:
返回值为以下三个枚举值,IR_HANDLED表示中断被正确处理了
1 2 3 4 5 | enum irqreturn { IRQ_NONE = (0 << 0), IRQ_HANDLED = (1 << 0), IRQ_WAKE_THREAD = (1 << 1), }; |
3、中断注销
1 | void free_irq(unsigned int irq, void *dev_id) |
参数:
- irq:中断号。
- dev_id:中断的结构体
二、查看中断
三、中断号
中断号其实就是一个整数,该整数是内核给每个中断源的唯一编号。
6818主板的中断号定义在s5p6818_irq.h中
1、外部中断号
1 2 3 4 5 | #define IRQ_GPIO_A_START (IRQ_GPIO_START + PAD_GPIO_A) #define IRQ_GPIO_B_START (IRQ_GPIO_START + PAD_GPIO_B) #define IRQ_GPIO_C_START (IRQ_GPIO_START + PAD_GPIO_C) #define IRQ_GPIO_D_START (IRQ_GPIO_START + PAD_GPIO_D) #define IRQ_GPIO_E_START (IRQ_GPIO_START + PAD_GPIO_E) |
2、其他一般中断的中断号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #define IRQ_PHY_MCUSTOP (0 + 32) #define IRQ_PHY_DMA0 (1 + 32) #define IRQ_PHY_DMA1 (2 + 32) #define IRQ_PHY_CLKPWR_INTREQPWR (3 + 32) #define IRQ_PHY_CLKPWR_ALIVEIRQ (4 + 32) #define IRQ_PHY_CLKPWR_RTCIRQ (5 + 32) #define IRQ_PHY_UART1 (6 + 32) // pl01115_Uart_modem #define IRQ_PHY_UART0 (7 + 32) // UART0_MODULE #define IRQ_PHY_UART2 (8 + 32) // UART1_MODULE #define IRQ_PHY_UART3 (9 + 32) // pl01115_Uart_nodma0 #define IRQ_PHY_UART4 (10 + 32) // pl01115_Uart_nodma1 #define IRQ_PHY_UART5 (11 + 32) // pl01115_Uart_nodma2 #define IRQ_PHY_SSP0 (12 + 32) #define IRQ_PHY_SSP1 (13 + 32) #define IRQ_PHY_SSP2 (14 + 32) #define IRQ_PHY_I2C0 (15 + 32) #define IRQ_PHY_I2C1 (16 + 32) #define IRQ_PHY_I2C2 (17 + 32) #define IRQ_PHY_DEINTERLACE (18 + 32) #define IRQ_PHY_SCALER (19 + 32) #define IRQ_PHY_AC97 (20 + 32) #define IRQ_PHY_SPDIFRX (21 + 32) #define IRQ_PHY_SPDIFTX (22 + 32) #define IRQ_PHY_TIMER_INT0 (23 + 32) #define IRQ_PHY_TIMER_INT1 (24 + 32) #define IRQ_PHY_TIMER_INT2 (25 + 32) #define IRQ_PHY_TIMER_INT3 (26 + 32) #define IRQ_PHY_PWM_INT0 (27 + 32) #define IRQ_PHY_PWM_INT1 (28 + 32) #define IRQ_PHY_PWM_INT2 (29 + 32) #define IRQ_PHY_PWM_INT3 (30 + 32) #define IRQ_PHY_WDT (31 + 32) #define IRQ_PHY_MPEGTSI (32 + 32) #define IRQ_PHY_DPC_P (33 + 32) #define IRQ_PHY_DPC_S (34 + 32) #define IRQ_PHY_RESCONV (35 + 32) #define IRQ_PHY_HDMI (36 + 32) #define IRQ_PHY_VIP0 (37 + 32) #define IRQ_PHY_VIP1 (38 + 32) #define IRQ_PHY_MIPI (39 + 32) #define IRQ_PHY_VR (40 + 32) #define IRQ_PHY_ADC (41 + 32) #define IRQ_PHY_PPM (42 + 32) #define IRQ_PHY_SDMMC0 (43 + 32) #define IRQ_PHY_SDMMC1 (44 + 32) #define IRQ_PHY_SDMMC2 (45 + 32) #define IRQ_PHY_CODA960_HOST (46 + 32) #define IRQ_PHY_CODA960_JPG (47 + 32) #define IRQ_PHY_GMAC (48 + 32) #define IRQ_PHY_USB20OTG (49 + 32) #define IRQ_PHY_USB20HOST (50 + 32) #define IRQ_PHY_CAN0 (51 + 32) #define IRQ_PHY_CAN1 (52 + 32) #define IRQ_PHY_GPIOA (53 + 32) #define IRQ_PHY_GPIOB (54 + 32) #define IRQ_PHY_GPIOC (55 + 32) #define IRQ_PHY_GPIOD (56 + 32) #define IRQ_PHY_GPIOE (57 + 32) #define IRQ_PHY_CRYPTO (58 + 32) #define IRQ_PHY_PDM (59 + 32) #define IRQ_PHY_TMU0 (60 + 32) #define IRQ_PHY_TMU1 (61 + 32) #define IRQ_PHY_VIP2 (72 + 32) |
3、三个中断共用一个中断处理程序
如何区分是哪个中断发生导致中断处理程序被内核调用的?
(1)通过中断号----某个中断发生,该中断的中断号会传递给中断处理程序的第一个形参
(2)通过注册时,传递给中断处理程序不同 (void * dev)
4、中断处理程序是一个原子过程
中断处理过程是原子的,不能在中断处理程序中使用可能导致阻塞的函数,例如:
1 | ssleep 、copy_to_user/copy_from_user、获取信号量.. |
不然会导致如下错误:
1 2 3 4 5 6 7 8 9 | [ 39.085000] Exception stack(0xc0a93f58 to 0xc0a93fa0) [ 39.085000] 3f40: ffffffed 00000000 [ 39.085000] 3f60: 00000000 00000000 c0a92000 c0b2c248 c0738290 c0a92000 c0a92000 c0ab0128 [ 39.085000] 3f80: 00000000 00000000 00000019 c0a93fa0 c000f83c c000f840 600d0013 ffffffff [ 39.085000] [<c000e840>] (__irq_svc+0x40/0x70) from [<c000f840>] (default_idle+0x2c/0x30) [ 39.085000] [<c000f840>] (default_idle+0x2c/0x30) from [<c000fb90>] (cpu_idle+0xd8/0x104) [ 39.085000] [<c000fb90>] (cpu_idle+0xd8/0x104) from [<c0a5483c>] (start_kernel+0x328/0x334) [ 39.085000] ---[ end trace 340d61c57173f93b ]--- [ 39.085000] BUG: scheduling while atomic: swapper/0/0/0x00010002---------在原子过程中启动了调度器 |
内核中提供的延时函数:以下的函数是忙等延时,不会休眠。ssleep是休眠延时,我们中断处理程序中不能使用忙等延时。
1 2 | udelay() ndelay() |
四、按键驱动程序
key_drv.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/ioport.h> #include <linux/io.h> #include <linux/uaccess.h> #include <linux/types.h> #include <linux/gpio.h> #include <cfg_type.h> #include <linux/interrupt.h> #include <linux/miscdevice.h> #include <linux/delay.h> struct key_gpio_t{ unsigned int irq; char irqname[20]; unsigned char keyvalue; }; static struct key_gpio_t key_gpio[]= { {IRQ_GPIO_A_START+28, "KEY2_GPIOA28" ,2}, {IRQ_GPIO_B_START+30, "KEY3_GPIOB30" ,3}, {IRQ_GPIO_B_START+31, "KEY4_GPIOB31" ,4}, {IRQ_GPIO_B_START+9, "KEY6_GPIOB9" ,6}, }; static char keyvalue = 0; ssize_t key_read( struct file *filp, char __user * buf, size_t size, loff_t *oft) { int ret; if (size !=1) { return -EINVAL; } ret = copy_to_user(buf, &keyvalue, sizeof (keyvalue)); if (ret != 0) { return (size -ret); } keyvalue=0; return size; } static irqreturn_t key_handler( int irq, void * dev) { struct key_gpio_t keytmp=*( struct key_gpio_t *)dev; keyvalue =keytmp.keyvalue; mdelay(500); //按键防抖 return IRQ_HANDLED; } struct file_operations key_misc_fops= { .read = key_read, }; static struct miscdevice key_misc={ .minor = MISC_DYNAMIC_MINOR, .name = "key_misc" , .fops = &key_misc_fops, }; static int __init key_init( void ) { int ret,i; printk(KERN_INFO "key_init\n" ); ret = misc_register(&key_misc); if (ret < 0) { printk(KERN_INFO "key misc register fail.\n" ); goto misc_register_err; } for (i=0;i<4;i++) { ret = request_irq(key_gpio[i].irq, key_handler,IRQF_TRIGGER_FALLING,key_gpio[i].irqname,( void *)&key_gpio[i]); if (ret < 0) { printk(KERN_INFO "request_irq fail.\n" ); goto irq_request_err; } } return 0; irq_request_err: while (i--) { free_irq(key_gpio[i].irq,NULL); } misc_register_err: return 0; } static void __exit key_exit( void ) { int i; printk(KERN_INFO "key_exit\n" ); misc_deregister(&key_misc); for (i=0;i<4;i++) { free_irq(key_gpio[i].irq,( void *)&key_gpio[i]); } } module_init(key_init); module_exit(key_exit); MODULE_LICENSE( "GPL" ); |
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <sys/ioctl.h> int main() { int fd,ret; char keyvalue=0; fd = open( "/dev/key_misc" ,O_RDWR); if (fd<0) { perror ( "open key_misc error!" ); } while (1) { ret=read(fd,&keyvalue,1); if (ret !=1) { perror ( "read error" ); continue ; } if (keyvalue!=0) { printf ( "keyvalue=%d\n" ,keyvalue); } } close(fd); } |
相关链接:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2017-12-19 crontab定时作业
2017-12-19 linux常用命令
2017-12-19 genstr.py
2017-12-19 vim用法
2017-12-19 Linux 查看CPU信息,机器型号,内存等信息
2017-12-19 grep基础用法
2017-12-19 awk用法