tiny6410按键驱动(五)---同步互斥阻塞
2014-12-24 20:55
363 查看
驱动代码如下:
Makefile文件如下:
测试程序如下:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/poll.h> #include <linux/irq.h> #include <asm/irq.h> #include <asm/io.h> #include <linux/interrupt.h> #include <asm/uaccess.h> #include <mach/hardware.h> #include <linux/platform_device.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #include <mach/map.h> #include <mach/regs-clock.h> #include <mach/regs-gpio.h> #include <plat/gpio-cfg.h> #include <mach/gpio-bank-n.h> #include <mach/gpio-bank-l.h> #include<linux/timer.h> #include <linux/semaphore.h> static unsigned button_major; static dev_t button_id; /*设备号*/ static struct cdev button_cdev; static struct class *button_class; static struct device *button_device; static volatile char ev_press; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); /*生成一个等待队列头wait_queue_head_t,名字为button_waitq*/ static DEFINE_SEMAPHORE(button_lock) ; /*这个宏定义一个互斥体,并将其初始化为1*/ struct buttons_irq_decs{ int irq; char *name; }; static struct buttons_irq_decs button_irqs[] = { {IRQ_EINT( 0),"K1"}, {IRQ_EINT( 1),"K2"}, {IRQ_EINT( 2),"K3"}, {IRQ_EINT( 3),"K4"}, }; static irqreturn_t buttons_irq(int irq, void *dev_id) { struct buttons_irq_decs *irq_desc = (struct buttons_irq_decs*)dev_id ; printk("%s\n" ,irq_desc->name); ev_press = 1; wake_up_interruptible(&button_waitq);/*唤醒睡眠的进程*/ return IRQ_HANDLED; } static int myButton_open(struct inode * inode, struct file * file) { /*获取信号量,如果成功,程序继续执行,否则程序进入睡眠,直到信号量被占有它的那个进程释放。释放信号量的地方在myButton_release里*/ /*获取信号量的三种方式*/ /*方式一 : */ //down(&button_lock); /*这种获取信号量的方式是不可中断的,当获取不到信号量时,进程会进入不可中断的休眠,即使执行kill也无法杀死这个休眠的进程*/ /*方式二 :*/ if(down_interruptible(&button_lock)) return -ERESTARTSYS; /*这种获取信号量的方式是可中断的,获取到信号是返回值是0,无法获取信号量时返回非零值,这种获取信号量的方式一定要判断返回值*/ /*方式三 :*/ /*if(down_trylock(&button_lock)) { return -ERESTARTSYS; } */ /*这种方式永远不会进入休眠,如果信号量不能获得时,立即返回一个非0值,但我在用这种方式时,当进程无法获得信号量时,进程一直在 这里休眠,即使后来信号量被其他的进程释放,依旧还是在此处休眠,除非杀死进程,重新运行进程,才可以获得信号量*/ int i; char err; for(i=0 ; i<sizeof(button_irqs)/sizeof(button_irqs[0]) ;i++) { err = request_irq(button_irqs[i].irq , &buttons_irq ,IRQ_TYPE_EDGE_BOTH ,button_irqs[i].name ,&button_irqs[i] ); /*IRQ_TYPE_EDGE_BOTH表示双边沿触发,即按键按下和松开都会触发中断*/ if(err) { printk("button_irqs[i] request faild\n"); continue; } } printk("myButton_open end\n"); return 0; } static int myButton_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_pos) { return 0; } static int myButton_read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) { if(bytes != 1) { printk("you can read just one char from the decive\n"); return -1; } //printk("myButton_read start\n"); wait_event_interruptible(button_waitq ,ev_press); char value; value = readl(S3C64XX_GPNDAT)&(0xf); /*GPN0~3对应于按键K1~K4*/ if(copy_to_user(userbuf, &value, bytes)) /*成功时返回0,失败时返回没有成功拷贝的字符个数*/ { printk("copy_to_user error\n"); return -1; } ev_press =0 ; //printk("myButton_read end\n"); return 0; } static int myButton_release(struct inode *inode, struct file *file) { int i; for(i=0 ; i<sizeof(button_irqs)/sizeof(button_irqs[0]) ;i++) { free_irq(button_irqs[i].irq, &button_irqs[i]); } printk("myButton_release\n"); up(&button_lock); /*释放信号量*/ return 0; } /*(应用程序)poll->sys_poll->do_sys_poll->do_poll->do_pollfd->f_op->poll(驱动)*/ static unsigned myButton_poll(struct file *file, struct poll_table_struct *wait) { unsigned mask = 0; poll_wait(file, &button_waitq, wait); /*将当前的设备加入到等待队列中,不会立即休眠,poll_wait的作用, poll_wait的作用只是为了让驱动程序能找到要唤醒的进程*/ if (ev_press) mask |= POLLIN | POLLRDNORM; /*POLLIN :设备可以无阻塞地读取;POLLRDNORM:数据已就绪,可以读取*/ return mask; } struct file_operations button_fiops= { .owner = THIS_MODULE, .open = myButton_open, .write = myButton_write, .read = myButton_read, .release = myButton_release, .poll = myButton_poll, }; static int myButton_init(void) { if(button_major) { button_id = MKDEV(button_major,0); register_chrdev_region(button_id, 2, "myButton_drv"); } else { alloc_chrdev_region(&button_id, 0, 2,"myButton_drv" ); button_major = MAJOR(button_id); } cdev_init(&button_cdev, &button_fiops); cdev_add(&button_cdev, button_id, 2); /*添加2个设备*/ button_class = class_create(THIS_MODULE, "myButton"); button_device = device_create(button_class, NULL, MKDEV(button_major , 0), NULL, "myButton0"); /*创建设备节点/dev/myButton0*/ button_device = device_create(button_class, NULL, MKDEV(button_major , 1), NULL, "myButton1"); /*创建设备节点/dev/myButton1*/ printk("myButton init succeed\n"); return 0; } static void myButton_exit(void) { device_destroy(button_class, MKDEV(button_major , 0)); device_destroy(button_class, MKDEV(button_major , 1)); class_destroy(button_class); cdev_del(&button_cdev); unregister_chrdev_region(button_id, 2); printk("myButton exit succeed\n"); } module_init(myButton_init); module_exit(myButton_exit); MODULE_LICENSE("GPL");
Makefile文件如下:
obj-m := mybutton_drv5.o KDIR :=/home/lijunliang/windows-files/linux-tiny6410 all : make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm clean : rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order
测试程序如下:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <poll.h> int main(void) { int fd; int ret; char keyValue ; struct pollfd fds[1]; fd = open("/dev/myButton0" , O_RDWR); if(fd < 0) {printf("open file error\n");} fds[0].fd = fd ; fds[0].events = POLLIN ; while(1) { ret = poll(fds , 1 ,5000 ); /*函数原型 :int poll(struct pollfd *fds ,nfds_t nfds ,int timeout); Poll机制会判断fds中的文件是否可读,如果可读则会立即返回,返回的值就是可读fd的数量, 如果不可读,那么就进程就会休眠timeout这么长的时间,然后再来判断是否有文件可读,如果有,返回fd的数量,如果没有,则返回0. */ if(0 == ret) { printf("timeOut ...\n"); } else { read(fd ,&keyValue ,1); switch(keyValue) { case 0xe: printf("K1 按下\n"); break; case 0xd: printf("K2 按下\n"); break; case 0xb: printf("K3 按下\n"); break; case 0x7: printf("K4 按下\n"); break; default : break; } } } //printf("%x\n",userbuffer0[0]); return 0; }
相关文章推荐
- 按键驱动的恩恩怨怨之同步互斥阻塞
- 嵌入式linux按键驱动,同步互斥阻塞,linux进程六大状态
- 嵌入式Linux驱动学习之路(十四)按键驱动-同步、互斥、阻塞
- linux字符驱动之同步互斥阻塞按键驱动
- linux字符驱动之同步互斥按键驱动
- linux字符驱动之同步互斥按键驱动
- 4412驱动-sixth_drv 同步互斥按键驱动
- 字符设备驱动同步之互斥阻塞
- 驱动中的同步互斥阻塞之原子量
- 字符设备驱动程序之按键——同步互斥阻塞
- Linux字符设备驱动之同步互斥阻塞
- arm 驱动基础:字符设备驱动程序之同步互斥阻塞
- linux字符驱动之同步互斥按键驱动
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-按键驱动程序之异步通知机制+原子操作+互斥信号量+阻塞与非阻塞+定时器去抖
- 字符设备驱动--异步通知、同步互斥阻塞
- 字符设备驱动-同步互斥阻塞
- linux字符设备驱动-同步互斥阻塞笔记
- 韦东山第12.7课-字符驱动之同步互斥阻塞、原子操作、信号量、阻塞
- 字符设备驱动程序之按键——同步互斥阻塞
- 并发,同步,异步,互斥,阻塞,非阻塞的理解