tiny6410按键驱动(六)---异步通知

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

驱动代码如下:

#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 struct fasync_struct *sync ;           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)  {kill_fasync(&sync, SIGIO, POLL_IN);     /*发送SIGIO信号,通知应用程序读数据*/printk("kill_fasync \n");return IRQ_HANDLED;}static int myButton_open(struct inode * inode, struct file * file){/*获取信号量,如果成功,程序继续执行,否则程序进入睡眠,直到信号量被占有它的那个进程释放。释放信号量的地方在myButton_release里*//*获取信号量的三种方式*//*方式一 : *///down(&button_lock);   /*这种获取信号量的方式是不可中断的,当获取不到信号量时,进程会进入不可中断的休眠,即使执行kill也无法杀死这个休眠的进程*//*方式二 :*/if(down_interruptible(&button_lock))  {    printk("the device is busy\n");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");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;   }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;}static int button_fasync(int fd, struct file *file, int on)/*在应用程序运行的开始和结束进程时都会调用这个函数*/{    printk("button_fasync\n");return fasync_helper(fd, file, on,&sync);    }struct file_operations button_fiops={.owner    = THIS_MODULE,.open     = myButton_open,.write    = myButton_write,.read     = myButton_read,.release  = myButton_release,.fasync   = button_fasync ,};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_drv6.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>#include <signal.h>#include <fcntl.h>#include <unistd.h>int fd;char keyValue ; void sig_fun(int sig)  /*信号处理函数,这个函数里必须有个整型的参数,接收传过来的信号的值*/{printf("signal num :%d\n",sig);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; }}int main(void){int Oflags;signal(SIGIO , sig_fun);fd = open("/dev/myButton0" , O_RDWR) ;if(fd < 0){ printf("open error\n"); }fcntl(fd , F_SETOWN , getpid());  /*使用系统调用fcntl执行命令F_SETOWN ,让进程ID保存在filp->f_owner中                                   从而让内核知道应该通知哪个进程*/Oflags = fcntl(fd, F_GETFL);   /*根据我的调试,执行到这一步时,就会去调用驱动里的fasync函数,在结束这个进程的时候也会调用fasync函数*/fcntl(fd, F_SETFL, Oflags | FASYNC);while (1){sleep(1000);}  return 0;}

关于异步通知里用到的几个内核函数其实我也不怎么明白,姑且先就这样用吧。

0 0
原创粉丝点击