字符设备驱动之按键中断(阻塞机制)——FS2410
2012-04-15 21:40
501 查看
一、开发环境
1、硬件平台:FS2410
2、主机:Ubuntu 10.10
3、内核版本:Linux 2.6.35
4、交叉编译工具链:arm-none-linux-gnueabi-
二、详细代码
按键驱动程序(button_drv.c):
应用程序测试代码(button_test.c):
Makefile:
在虚拟机中输入:
$make
$arm-none-linux-gnueabi-gcc button_test.c -o button
$sudo cp button_drv.ko button /source/rootfs/app
在开发板的上输入:
#insmod button_drv.ko
#mknod /dev/button c 249 0
#./button
1、硬件平台:FS2410
2、主机:Ubuntu 10.10
3、内核版本:Linux 2.6.35
4、交叉编译工具链:arm-none-linux-gnueabi-
二、详细代码
按键驱动程序(button_drv.c):
#include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/sched.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/mm.h> #include <linux/kdev_t.h> #include <linux/cdev.h> #include <linux/interrupt.h> #include <linux/ioport.h> #include <asm/irq.h> #include <linux/irq.h> #include <linux/device.h> #include <asm/io.h> #include <asm/uaccess.h> #include <mach/regs-irq.h> #define GPFCON 0x56000050 #define GPFDAT 0x56000054 #define GPGCON 0x56000060 #define GPECON 0x56000040 #define GPEDAT 0x56000044 #define EXTINT0 0x56000088 #define EXTINT2 0x56000090 #define SRCPND 0x4A000000 #define INTPND 0x4A000010 static volatile unsigned int *gpfcon; static volatile unsigned int *gpfdat; static volatile unsigned int *gpgcon; static volatile unsigned int *gpecon; static volatile unsigned int *gpedat; static volatile unsigned int *extint0; static volatile unsigned int *extint2; static volatile unsigned int *srcpnd; static volatile unsigned int *intpnd; struct tasklet_struct button_tasklet; void button_do_tasklet(unsigned long ); DECLARE_TASKLET(button_tasklet, button_do_tasklet, 0); static int button_major = 249; struct button_dev { struct cdev cdev; char key_value; wait_queue_head_t r_wait; }; struct button_dev dev; void wait(volatile long long max) { while(max--); } void ioremap_gpio(void) { gpfcon = ioremap(GPFCON, 0x4); gpfdat = ioremap(GPFDAT, 0x4); gpgcon = ioremap(GPGCON, 0x4); gpecon = ioremap(GPECON, 0x4); gpedat = ioremap(GPEDAT, 0x4); extint0 = ioremap(EXTINT0, 0x4); extint2 = ioremap(EXTINT2, 0x4); srcpnd = ioremap(SRCPND, 0x4); intpnd = ioremap(INTPND, 0x4); return ; } void init_gpio(void) { ioremap_gpio(); writel(readl(gpecon) & ~(3 << 22), gpecon); writel(readl(gpecon) | (1 << 22), gpecon); writel(readl(gpedat) & ~(1 << 11), gpedat); writel(readl(gpgcon) & ~(3 << 22), gpgcon); writel(readl(gpgcon) | (2 << 22), gpgcon); writel(readl(gpfcon) & ~(0xff << 8), gpfcon); writel(readl(gpfcon) | (0x55 << 8), gpfcon); set_irq_type(IRQ_EINT19, IRQ_TYPE_EDGE_FALLING); writel(readl(extint2) & ~(7 << 12), extint2); writel(readl(extint2) | (1 << 13), extint2); return ; } void iounmap_gpio(void) { iounmap(gpfcon); iounmap(gpfdat); iounmap(gpgcon); iounmap(gpecon); iounmap(gpedat); iounmap(extint0); iounmap(extint2); iounmap(srcpnd); iounmap(intpnd); return ; } void button_do_tasklet(unsigned long arg) { wait(200000); if((readl(gpfdat) & (1 << 4)) == 0) writel(readl(gpfdat) | (1 << 4), gpfdat); else writel(readl(gpfdat) & ~(1 << 4), gpfdat); dev.key_value = 1; wake_up_interruptible(&dev.r_wait); return ; } static irqreturn_t button_interrupt(int irq, void *dev_id) { *srcpnd = *srcpnd; *intpnd = *intpnd; tasklet_schedule(&button_tasklet); return IRQ_HANDLED; } static int button_open(struct inode *inode, struct file *filp) { init_gpio(); writel(readl(gpfdat) & ~(0xf << 4), gpfdat); return 0; } static int button_release(struct inode *inode, struct file *filp) { iounmap_gpio(); return 0; } static ssize_t button_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) { int ret; if(filp->f_flags & O_NONBLOCK) { ret = -EAGAIN; return ret; } wait_event_interruptible(dev.r_wait, dev.key_value != 0); if(copy_to_user(buf, &dev.key_value, size)) return -EFAULT; dev.key_value = 0; ret = size; return ret; } static ssize_t button_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos) { return 0; } static int button_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) { return 0; } static struct file_operations button_fops = { .owner = THIS_MODULE, .read = button_read, .write = button_write, .open = button_open, .release = button_release, .ioctl = button_ioctl, }; static void button_setup_cdev(struct cdev *dev, int index) { int err; int devno = MKDEV(button_major, index); cdev_init(dev, &button_fops); dev->owner = THIS_MODULE; err = cdev_add(dev, devno, 1); if(err) printk("Error %d adding key %d", err, index); return ; } static int __init button_init(void) { int result; int devno = MKDEV(button_major, 0); if(button_major) result = register_chrdev_region(devno, 1, "button"); else { result = alloc_chrdev_region(&devno, 0, 1, "button"); button_major = MAJOR(devno); } if(result < 0) return result; result = request_irq(IRQ_EINT19, button_interrupt, IRQF_DISABLED, "key", NULL); button_setup_cdev(&dev.cdev, 0); init_waitqueue_head(&dev.r_wait); return 0; } static void __exit button_exit(void) { cdev_del(&dev.cdev); unregister_chrdev_region(MKDEV(button_major, 0), 1); free_irq(IRQ_EINT19, NULL); return; } module_init(button_init); module_exit(button_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("yhr");
应用程序测试代码(button_test.c):
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> int main(void) { int dev_fd; char buf; if((dev_fd = open("/dev/button", O_RDWR)) < 0) { perror("failed to open button"); exit(-1); } while(1) { read(dev_fd, &buf, 1); printf("read : %d\n", buf); } close(dev_fd); return 0; }
Makefile:
ifeq ($(KERNELRELEASE),) # set your object kernel dir KERNELDIR = /home/linux/linux-2.6.35 PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules* .PHONY: modules modules_install clean else obj-m := button_drv.o endif
在虚拟机中输入:
$make
$arm-none-linux-gnueabi-gcc button_test.c -o button
$sudo cp button_drv.ko button /source/rootfs/app
在开发板的上输入:
#insmod button_drv.ko
#mknod /dev/button c 249 0
#./button
相关文章推荐
- 字符设备驱动之按键中断(POLL机制)——FS2410
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-查询+中断+引入poll机制的按键驱动程序
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-按键驱动程序之异步通知机制+原子操作+互斥信号量+阻塞与非阻塞+定时器去抖
- 字符设备驱动-----按键驱动(中断+poll机制)
- 字符设备驱动之按键中断——FS2410
- 嵌入式linux:字符设备驱动-----按键驱动(中断+poll机制)
- 字符设备驱动-----按键驱动(中断+poll机制)
- 高级字符设备驱动--中断下半部机制之tasklet(一)
- 驱动之字符设备----按键中断
- 高级字符设备驱动--中断下半部机制之workqueue(二)
- 基于platform总线的中断(按键)字符设备驱动设计
- 字符设备驱动程序之中断方式的按键驱动
- 字符设备驱动笔记——中断方式按键驱动之代码(六)
- 基于platform总线的中断(按键)字符设备驱动设计
- 字符设备驱动之按键处理二(中断处理的按键驱动程序)
- 高级字符设备驱动--中断下半部机制之workqueue(二)
- Linux设备驱动开发基础---字符设备驱动程序开发之基于中断的按键驱动
- 字符设备驱动--中断方式下的按键驱动
- 字符设备驱动程序按键驱动---中断方式
- 字符设备驱动之按键扫描——FS2410