我使用了两种驱动开发的模型来写了smart210上的按键驱动程序,这里做一下总结以及提供他人参考以及建议和改进,最后一个原因是自己很久没有写过博客了,现在想分享一下linux驱动开发程序的编写。
首先是Linux的中断处理机制。裸机开发中,通过中断标识一个函数指明该函数是中断处理函数,在编译器处理时候,也会对该函数的指针保存或特殊处理,当把该程序烧写到板子的时候,会把这个中断函数的地址加载到指定的地址,当中断发生时,通过寄存器保存的该函数的指针,进行中断函数地处理。但是在Linux中采用了类似信号处理这一种机制,在Linux的底层,当有中断发生时,就会有板级的代码产生一个指定的中断号,我们的中断驱动就是在内核中注册当接收的该中断信号后的处理函数,具体函数如下:
int request_irq(irq,func, trigger_type, name, dev_id );
这里我是用伪代码描述:
irq: 需要接受或检测的中断号
func: 中断处理函数
trigger_type: 中断触发模式
name: 中断名称
dev_id: 这个参数是void类型的指针,最终传递给中断处理函数的第二个参数
中断的处理分为Top-part,和 Bottom-part,可以使用多种处理方式进行处理,比如:tasklet, queue等等。这部分内容请查阅相关书籍
1. tasklet处理中断的Top-part和Bottom-part
这里直接使用了字符驱动模型,问题在于比较麻烦,尤其是驱动本身的注册,但是这种模型的驱动比较自由的。(头文件未补全,并且只是副本--真确的版本在虚拟机中,编译可能有点问题,可以私聊要完全的代码),主要参考驱动编写流程和框架。
#include #include #include #include #include #include #include /* In this program, We using Top-Bottom mechinenism to * handle the interrupt, we can use tasklet to resolve * the interrupt. */ #define DEVICE_NAME 'interruptv1' #define CLASS_NAME 'interrupts' struct key_device { cdev cdev; unsigned int count; unsigned int flags; }; static struct tasklet key_tasklet; static dev_t major; static struct class *key_class; static struct key_device *key_devp; static void interrupt_handle(unsigned long data) { printk(' } static irqreturn_t interrupt_tasklet(int irq, void *dev_id) { printk(' key_devp->count++; tasklet_schedule(&key_tasklet); return IRQ_HANDLED; } static int interrupt_open(struct inode *inode, struct file *filep) { int ret; filep->private_data =key_devp; //request a interrupt number ret = request_irq(IRQ_EINT(16), interrupt_tasklet, IRQF_TRIGGER_FALLING, DEVICE_NAME, (void *) NULL); if(ret < 0){ printk(' free_irq(IRQ_EINT(16), NULL); return -EAGAIN; } printk(' return 0; } static int interrupt_close(struct inode *inode, struct file *filep) { free_irq(IRQ_EINT(16), NULL); tasklet_kill(&key_tasklet); printk(' return 0; } static int interrupt_write(struct file *filep, char __user *buf, size_t size, loff_t *ppos) { pirntk(' return 0; } static int interrupt_read(struct file *filep, char __user *buf, size_t size, loff_t *ppos) { printk(' return 0; } DECLARE_TASKLET(key_tasklet, interrupt_handle, key_dev->count); struct file_operations interrupt_fops = { .owner = THIS_MODULE, .open = interrupt_open, .release = interrupt_close, .read = interrupt_read, .write = interrupt_write, }; static void device_setup(struct cdev *devp, int minor) { int err; dev_t devno = MKDEV(major, minor); //add a char driver to kernel cdev_init(devp, &interrupt_fops); devp->owner = THIS_MODULE; err = cdev_add(devp, devno, 1); if(err) printk(' //add device driver to file-system key_class = class_create(THIS_MODULE, CLASS_NAME); if(IS_ERR(key_class)){ printk(' return -EINVAL; } device_create(key_class, NULL, devno, NULL, DEVICE_NAME); } static int __init interrupt_init(void) { int ret; dev_t devno; if((ret = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME)) < 0){ printk(' return -EINVAL; } major = MAJOR(devno); key_devp = kmalloc(sizeof(struct key_device), GPF_KERNLE); if(!key_devp){ printk(' goto fail1; } memset(key_devp, 0, sizeof(struct key_device)); //set_irq_type(IRQ_EINT(16), IRQF_TRIGGER_FALLING); no header file device_setup(&key_devp->cdev, 0); return 0; fail1: unregister_chrdev_region(MKDEV(major, 0), 1); return -ENOMEM; } static void __exit interrupt_exit(void) { cdev_del(&key_devp->cdev); kfree(key_devp); unregister_chrdev_region(MKDEV(major, 0), 1); device_destroy(key_class, MKDEV(major, 0)); class_destroy(key_class); } module_init(interrupt_init); module_exit(interrupt_exit); MODULE_LICENSE('GPL'); MODULE_AUTHOR('weirdo'); MODULE_DESCRIPTION('This module using for smart210 interrupts'); 2. 普通中断驱动模型---miscdevice #include #include #include #include #include #include #include #define INT_NAME 'key1' #define DEVICE_NAME 'interruptv1' #define DEVICE_MINOR 12 static irqreturn_t interrupt_handle(int irq, void *dev_id) { printk(' return IRQ_HANDLED; } static int interrupt_open(struct inode *inode, struct file *filep) { int irq, ret; irq = gpio_to_irq(S5PV210_GPH2(0)); ret = request_irq(irq, interrupt_handle, IRQF_TRIGGER_FALLING, INT_NAME, 0); if(ret < 0){ printk(' return -EFAULT; } printk(' return 0; } static int interrupt_close(struct inode *inode, struct file *filep) { int irq; irq = gpio_to_irq(S5PV210_GPH2(0)); free_irq(irq, NULL); printk(' return 0; } static int interrupt_read(struct file *filep, char __user *buf, size_t size, loff_t *ppos) { printk(' return 0; } static int interrupt_write(struct file *filep, const char __user *buf, size_t size, loff_t *ppos) { printk(' return 0; } static struct file_operations interrupt_fops = { .owner = THIS_MODULE, .open = interrupt_open, .release = interrupt_close, .read = interrupt_read, .write = interrupt_write }; static struct miscdevice int_misc = { .minor = DEVICE_MINOR, .name = DEVICE_NAME, .fops = &interrupt_fops, }; static int __init interrupt_init(void) { int ret; ret = misc_register(&int_misc); if(ret != 0) { print(' retur -EFAULT; } printk(' return 0; } static void __exit interrupt_exit(void) { misc_deregister(&int_misc); } module_init(interrupt_init); module_exit(interrupt_exit); MODULE_AUTHOR('weirdo'); MODULE_LICENSE('GPL'); MODULE_DESCRIPTION('This driver write for smart210 8 keys interrupts'); 3. 驱动测试文件 由于驱动测试文件在虚拟机中,个人比较lazy,但简要叙述一些驱动中的关键点: #include <> #include <> #include <> #include <> #define DEVICE_NAME '/dev/interruptv1' int main(void) { int fd; char input; fd = open(DEVICE_NAME); if(irq){ .... } for( ; input != 'e' }
上一篇:S5PV210开发板 VGA测试
下一篇:基于S5pv210流媒体server的实现之网络摄像头
推荐阅读最新更新时间:2026-03-25 12:08
- 用于 7VIN 至 16VIN、1.5V 和 1.2V 输出的 LTM4628EV DC/DC 模块稳压器的典型应用电路
- 使用 Analog Devices 的 LTC3728LIGN 的参考设计
- DER-406 - 适用于 A19 灯的 5.76 W 高 PF 非隔离降压-升压型 TRIAC 调光 LED 驱动器
- ADR5045B 5V 输出精密微功率并联模式电压基准的典型应用
- LT3970EDDB-3.42 2.5V 降压转换器的典型应用
- MC78M08BDTG 8V 电流调节器的典型应用
- LT1021DCN8-5 精密电压基准的典型应用
- DER-282 - 100W, 扁平(11 mm), LLC DC-DC转换器
- REF193 低压差开尔文连接电压基准的典型应用电路
- LT3088EM 线性稳压器用于添加软启动的典型应用

Linux技术手册
【2025 DigiKey创意大赛】 学伴智盒 - 代码
智能机械臂
非常经典的关于LLC的杨波博士论文
XC6406PP60DL






京公网安备 11010802033920号