tiny6410按键驱动(五)---同步互斥阻塞

来源:互联网 发布:faker哭了知乎 编辑:程序博客网 时间:2024/06/05 05:56

驱动代码如下:

#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.oKDIR :=/home/lijunliang/windows-files/linux-tiny6410all :make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=armclean :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;}


0 0
原创粉丝点击