zoukankan      html  css  js  c++  java
  • 驱动02.按键

    一.以查询方式实现

    1.写出驱动框架
      1.1 仿照其他程序加一些必要的头文件
      1.2 构造一个结构体file_operations
      1.3 根据file_operations的所选项写出所需的函数,并构建出来
      1.4 入口函数、出口函数的注册和卸载
      1.5 修饰入口函数和出口函数
      1.6 给sysfs提供更多的信息,并有udev机制自动创建/dev/xxx设备节点
    2.硬件操作
      2.1 sch原理图
      2.2 2440手册
      2.3 编程:物理地址到虚拟地址的映射

      1 /*
      2   *以查询的方式实现按键驱动程序
      3   */
      4 
      5 #include <linux/module.h>
      6 #include <linux/kernel.h>
      7 #include <linux/fs.h>
      8 #include <linux/init.h>
      9 #include <linux/delay.h>
     10 #include <asm/uaccess.h>
     11 #include <asm/irq.h>
     12 #include <asm/io.h>
     13 #include <asm/arch/regs-gpio.h>
     14 #include <asm/hardware.h>
     15 
     16 
     17 static struct class *g_ptSeconddrvCls;
     18 static struct class_device *g_ptSeconddrvClsDev;
     19 
     20 volatile unsigned long *gpfcon;
     21 volatile unsigned long *gpfdat;
     22 
     23 volatile unsigned long *gpgcon;
     24 volatile unsigned long *gpgdat;
     25 
     26 static int seconddrv_open(struct inode *inode, struct file *file)
     27 {
     28     /* 配置GPF0,2为输入引脚 */
     29     *gpfcon &= ~((0x3<<(0*2)) | (0x3<<(2*2)));
     30 
     31     /* 配置GPG3,11为输入引脚 */
     32     *gpgcon &= ~((0x3<<(3*2)) | (0x3<<(11*2)));
     33 
     34     return 0;
     35 }
     36 
     37 static ssize_t seconddrv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
     38 {
     39     /* 返回4个引脚的电平 */
     40     unsigned char key_vals[4];
     41     int regval;
     42 
     43     if (size != sizeof(key_vals))
     44         return -EINVAL;
     45 
     46     /* 读GPF0,2 */
     47     regval = *gpfdat;
     48     key_vals[0] = (regval & (1<<0)) ? 1 : 0;
     49     key_vals[1] = (regval & (1<<2)) ? 1 : 0;
     50     
     51 
     52     /* 读GPG3,11 */
     53     regval = *gpgdat;
     54     key_vals[2] = (regval & (1<<3)) ? 1 : 0;
     55     key_vals[3] = (regval & (1<<11)) ? 1 : 0;
     56 
     57     copy_to_user(buf, key_vals, sizeof(key_vals));
     58     
     59     return sizeof(key_vals);
     60 }
     61 
     62 static struct file_operations seconddrv_fops = {
     63     .owner = THIS_MODULE,
     64     .open   = seconddrv_open,     
     65     .read   =    seconddrv_read,
     66 };
     67 
     68 
     69 int g_iMajor;
     70 static int seconddrv_init(void)
     71 {
     72     g_iMajor = register_chrdev(0, "second_drv", &seconddrv_fops);
     73 
     74     g_ptSeconddrvCls = class_create(THIS_MODULE, "second_drv");
     75 
     76     g_ptSeconddrvClsDev = class_device_create(g_ptSeconddrvCls, NULL, MKDEV(g_iMajor, 0), NULL, "buttons"); /* /dev/buttons */
     77 
     78     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
     79     gpfdat = gpfcon + 1;
     80 
     81     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
     82     gpgdat = gpgcon + 1;
     83 
     84     return 0;
     85 }
     86 
     87 static int seconddrv_exit(void)
     88 {
     89     unregister_chrdev(g_iMajor, "second_drv");
     90     class_device_unregister(g_ptSeconddrvClsDev);
     91     class_destroy(g_ptSeconddrvCls);
     92     iounmap(gpfcon);
     93     iounmap(gpgcon);
     94     return 0;
     95 }
     96 
     97 module_init(seconddrv_init);
     98 
     99 module_exit(seconddrv_exit);
    100 MODULE_LICENSE("GPL");
    查询方式的按键驱动程序
     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 
     6 /* 2nddrvtest 
     7   */
     8 int main(int argc, char **argv)
     9 {
    10     int fd;
    11     unsigned char key_vals[4];
    12     int cnt = 0;
    13     
    14     fd = open("/dev/buttons", O_RDWR);
    15     if (fd < 0)
    16     {
    17         printf("can't open!
    ");
    18     }
    19 
    20     while (1)
    21     {
    22         read(fd, key_vals, sizeof(key_vals));
    23         if (!key_vals[0] || !key_vals[1] || !key_vals[2] || !key_vals[3])
    24         {
    25             printf("%04d key pressed: %d %d %d %d
    ", cnt++, key_vals[0], key_vals[1], key_vals[2], key_vals[3]);
    26         }
    27     }
    28     
    29     return 0;
    30 }
    测试程序

     二、使用中断方式实现按键驱动程序

    使用查询方式实现时,程序一直占用CPU资源,CPU利用率低。

    改进的办法:使用中断的方式实现

    1.linux中断异常体系分析

      1.1 异常向量的设置trap_init()
        trap_init被用来设置各种异常的处理向量,trap_init函数将异常向量复制到0xffff0000处
        trap_init
            memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
                vector_irq
                    vector_stub(宏)//计算返回地址,保存一些寄存器
                        __irq_usr     //根据被中断的工作模式进入相应的某个跳转分支->进入管理模式
                            usr_entry(宏)//保存一些寄存器的值
                                .maro irq_handler(宏)
                                    asm_do_IRQ //异常处理函数
      1.2 异常处理函数asm_do_IRQ
      asm_do_IRQ
          定义了一个结构体数组desc[NR_IRQS]
              irq_enter
              desc_handle_irq:desc->handle_irq
            
      1.3 结构数组desc[NR_IRQS]的构建    
      s3c24xx_init_irq
          set_irq_chip    //chip=s3c_irq_eint0t4,可设置触发方式,使能中断,禁止中断等底层芯片相关的操作
          set_irq_flags
          set_irq_handler(irqno, handle_edge_irq)//handle_irq=handle_edge_irq
              __set_irq_handler
                  desc_handle_irq
      

      中断处理函数handle_edge_irq
        handle_edge_irq
            desc->chip->ack(irq)//清中断
            handle_IRQ_event//取出action链表中的成员,执行action->handler
      1.4 用户注册中断处理函数的过程request_irq
      request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)
              //用户通过request_irq向内核注册中断处理函数:a.分配了irqaction结构b.调用setup_irq函数
          setup_irq(irq,action)//将新建的irqaction结构链入irq_desc[irq]结构的action链表中P405
          desc->chip->settype//定义引脚为中断引脚
          desc->chip->startup/enable//引脚使能
      1.5 free_irq(irq,dev_id)//卸载中断服务程序
          a.出链
          b.禁止中断

      1.6 总结:handle_irq是这个中断的处理函数入口,发生中断时,总入口函数asm_do_IRQ函数将根据中断号调用相应irq_desc数组项的handle_irq。handle_irq使用chip结构体中的函数来清除、屏蔽或者重新enable中断,还一一调用用户在action链表中注册的中断处理函数。

    2.编写代码

      1 /*
      2   *用中断方式实现按键驱动程序
      3   */
      4 
      5 #include <linux/module.h>
      6 #include <linux/kernel.h>
      7 #include <linux/fs.h>
      8 #include <linux/init.h>
      9 #include <linux/delay.h>
     10 #include <linux/irq.h>
     11 #include <asm/uaccess.h>
     12 #include <asm/irq.h>
     13 #include <asm/io.h>
     14 #include <asm/arch/regs-gpio.h>
     15 #include <asm/hardware.h>
     16 
     17 
     18 static struct class *g_ptThirddrvCls;
     19 static struct class_device *g_ptThirddrvClsDev;
     20 
     21 volatile unsigned long *gpfcon;
     22 volatile unsigned long *gpfdat;
     23 
     24 volatile unsigned long *gpgcon;
     25 volatile unsigned long *gpgdat;
     26 
     27 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
     28 
     29 /* 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 */
     30 static volatile int ev_press = 0;
     31 
     32 struct pin_desc{
     33     unsigned int pin;
     34     unsigned int key_val;
     35 };
     36 
     37 static unsigned char key_val;
     38 
     39 struct pin_desc pins_desc[4] = {
     40     {S3C2410_GPF0, 0x01},
     41     {S3C2410_GPF2, 0x02},
     42     {S3C2410_GPG3, 0x03},
     43     {S3C2410_GPG11, 0x04},
     44 };
     45 
     46 
     47 /*
     48   * 确定按键值
     49   */
     50 static irqreturn_t buttons_irq(int irq, void *dev_id)
     51 {
     52     struct pin_desc * pindesc = (struct pin_desc *)dev_id;
     53     unsigned int pinval;
     54     
     55     pinval = s3c2410_gpio_getpin(pindesc->pin);
     56 
     57     if (pinval)
     58     {
     59         /* 松开 */
     60         key_val = 0x80 | pindesc->key_val;
     61     }
     62     else
     63     {
     64         /* 按下 */
     65         key_val = pindesc->key_val;
     66     }
     67 
     68     ev_press = 1;                  /* 表示中断发生了 */
     69     wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
     70 
     71     
     72     return IRQ_RETVAL(IRQ_HANDLED);
     73 }
     74 
     75 static int thirddrv_open(struct inode *inode, struct file *file)
     76 {
     77     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
     78     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
     79     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
     80     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);    
     81 
     82     return 0;
     83 }
     84 
     85 static ssize_t thirddrv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
     86 {
     87     
     88     if (size != 1)
     89         return -EINVAL;
     90 
     91     /* 如果没有按键动作, 休眠 */
     92     wait_event_interruptible(button_waitq, ev_press);
     93 
     94     /* 如果有按键动作, 返回键值 */
     95     copy_to_user(buf, &key_val, 1);
     96     ev_press = 0;
     97     
     98     return 1;
     99 }
    100 
    101 static int thirddrv_close (struct inode * inode, struct file * file)
    102 {
    103     free_irq(IRQ_EINT0,&pins_desc[0]);
    104     free_irq(IRQ_EINT2,&pins_desc[1]);
    105     free_irq(IRQ_EINT11,&pins_desc[2]);
    106     free_irq(IRQ_EINT19,&pins_desc[3]);
    107 
    108     return 0;
    109 }
    110 
    111 static struct file_operations thirddrv_fops = {
    112     .owner = THIS_MODULE,
    113     .open   = thirddrv_open,     
    114     .read   =    thirddrv_read,
    115     .release = thirddrv_close,
    116 };
    117 
    118 
    119 int g_iMajor;
    120 static int thirddrv_init(void)
    121 {
    122     g_iMajor = register_chrdev(0, "third_drv", &thirddrv_fops);
    123 
    124     g_ptThirddrvCls = class_create(THIS_MODULE, "third_drv");
    125 
    126     g_ptThirddrvClsDev = class_device_create(g_ptThirddrvCls, NULL, MKDEV(g_iMajor, 0), NULL, "buttons"); /* /dev/buttons */
    127 
    128     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    129     gpfdat = gpfcon + 1;
    130 
    131     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    132     gpgdat = gpgcon + 1;
    133 
    134     return 0;
    135 }
    136 
    137 static int thirddrv_exit(void)
    138 {
    139     unregister_chrdev(g_iMajor, "third_drv");
    140     class_device_unregister(g_ptThirddrvClsDev);
    141     class_destroy(g_ptThirddrvCls);
    142     iounmap(gpfcon);
    143     iounmap(gpgcon);
    144     return 0;
    145 }
    146 
    147 module_init(thirddrv_init);
    148 
    149 module_exit(thirddrv_exit);
    150 MODULE_LICENSE("GPL");
    驱动程序
     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 #include <unistd.h>
     6 
     7 /* thirddrvtest 
     8   */
     9 int main(int argc, char **argv)
    10 {
    11     int fd;
    12     unsigned char key_val;
    13     
    14     fd = open("/dev/buttons", O_RDWR);
    15     if (fd < 0)
    16     {
    17         printf("can't open!
    ");
    18     }
    19 
    20     while (1)
    21     {
    22         //read(fd, &key_val, 1);
    23         //printf("key_val = 0x%x
    ", key_val);
    24         sleep(5);
    25     }
    26     
    27     return 0;
    28 }
    测试程序

    三、在上述基础上添加poll机制

      虽然我们实现了中断式的按键驱动,但是我们发觉,测试程序是一个无限的循环。在实际应用中并不存在这样的情况,所以我们要进一步优化——poll机制。

    1.poll机制的分析

    1.1 函数原型

    int poll(struct pollfd *fds,nfds_t nfds, int timeout)
    //Poll机制会判断fds中的文件是否可读,如果可读则会立即返回,返回的值就是可读fd的数量,如果不可读,那么就进程就会
    休眠timeout这么长的时间,然后再来判断是否有文件可读,如果有,返回fd的数量,如果没有,则返回0.  
    1.2 poll机制在内核实现分析:
    应用程序调用poll
        sys_poll
            do_sys_poll
                poll_initwait(&table)//table->pt->qproc = qproc = __pollwait
                do_poll(nfds, head, &table, timeout)
                    for (;;) {
                    if (do_pollfd(pfd, pt)) {     //return mask;mask=file->f_op->poll(file,pwait)
                        count++;
                        pt = NULL;
                        }
                    if (count || !*timeout || signal_pending(current))
                            break;//break的条件是:count非0,超时,有信号在等待处理
                        __timeout = schedule_timeout(__timeout)//休眠
                        }
    1.3 总结
    ①poll > sys_poll > do_sys_poll >poll_initwait,poll_initwait函数注册一下回调函数__pollwait,它就是我们的驱动程序执行poll_wait时,真正被调用的函数。
    ②接下来执行file->f_op->poll,即我们驱动程序里自己实现的poll函数它会调用poll_wait把自己挂入某个队列,这个队列也是我们的驱动自己定义的;它还判断一下设备是否就绪。
    ③如果设备未就绪,do_sys_poll里会让进程休眠一定时间,这个时间是应用提供的“超时时间”
    ④进程被唤醒的条件有2:一是上面说的“一定时间”到了,二是被驱动程序唤醒。驱动程序发现条件就绪时,就把“某个队列”上挂着的进程唤醒,这个队列,就是前面通过poll_wait把本进程挂过去的队列。
    ⑤如果驱动程序没有去唤醒进程,那么schedule_timeout(__timeout)超时后,会重复2、3动作1
    次,然后返回。

     2.写代码
    ①在测试程序中加入以下代码
    while (1)
        {
            ret = poll(fds, 1, 5000);
            if (ret == 0)
            {
                printf("time out ");
            }
    int main()
    {
        int ret;
        struct pollfd fds[1]
    }
    ②在file_operations中增加一行
    .poll    =  forth_drv_poll
    ③写函数forth_drv_poll
    forth_drv_poll
        poll_wait
            p->qproc(file,wait_address,p)//相当于调用了__pollwait(file,&button_waitq,p)
                                            //把当前进程挂到button_waitq队列里去
    ④在增加如下代码
    if (ev_press)
            mask |= POLLIN | POLLRDNORM;

      1 /*
      2   *使用poll 机制实现按键驱动程序
      3   */
      4 
      5 #include <linux/module.h>
      6 #include <linux/kernel.h>
      7 #include <linux/fs.h>
      8 #include <linux/init.h>
      9 #include <linux/delay.h>
     10 #include <linux/irq.h>
     11 #include <asm/uaccess.h>
     12 #include <asm/irq.h>
     13 #include <asm/io.h>
     14 #include <asm/arch/regs-gpio.h>
     15 #include <asm/hardware.h>
     16 
     17 
     18 static struct class *g_ptForthdrvCls;
     19 static struct class_device *g_ptForthdrvClsDev;
     20 
     21 volatile unsigned long *gpfcon;
     22 volatile unsigned long *gpfdat;
     23 
     24 volatile unsigned long *gpgcon;
     25 volatile unsigned long *gpgdat;
     26 
     27 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
     28 
     29 /* 中断事件标志, 中断服务程序将它置1,forth_drv_read将它清0 */
     30 static volatile int ev_press = 0;
     31 
     32 struct pin_desc{
     33     unsigned int pin;
     34     unsigned int key_val;
     35 };
     36 
     37 static unsigned char key_val;
     38 
     39 struct pin_desc pins_desc[4] = {
     40     {S3C2410_GPF0, 0x01},
     41     {S3C2410_GPF2, 0x02},
     42     {S3C2410_GPG3, 0x03},
     43     {S3C2410_GPG11, 0x04},
     44 };
     45 
     46 
     47 /*
     48   * 确定按键值
     49   */
     50 static irqreturn_t buttons_irq(int irq, void *dev_id)
     51 {
     52     struct pin_desc * pindesc = (struct pin_desc *)dev_id;
     53     unsigned int pinval;
     54     
     55     pinval = s3c2410_gpio_getpin(pindesc->pin);
     56 
     57     if (pinval)
     58     {
     59         /* 松开 */
     60         key_val = 0x80 | pindesc->key_val;
     61     }
     62     else
     63     {
     64         /* 按下 */
     65         key_val = pindesc->key_val;
     66     }
     67 
     68     ev_press = 1;                  /* 表示中断发生了 */
     69     wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
     70 
     71     
     72     return IRQ_RETVAL(IRQ_HANDLED);
     73 }
     74 
     75 static int forthdrv_open(struct inode *inode, struct file *file)
     76 {
     77     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
     78     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
     79     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
     80     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);    
     81 
     82     return 0;
     83 }
     84 
     85 static ssize_t forthdrv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
     86 {
     87     
     88     if (size != 1)
     89         return -EINVAL;
     90 
     91     /* 如果没有按键动作, 休眠 */
     92     wait_event_interruptible(button_waitq, ev_press);
     93 
     94     /* 如果有按键动作, 返回键值 */
     95     copy_to_user(buf, &key_val, 1);
     96     ev_press = 0;
     97     
     98     return 1;
     99 }
    100 
    101 static int forthdrv_close (struct inode * inode, struct file * file)
    102 {
    103     free_irq(IRQ_EINT0,&pins_desc[0]);
    104     free_irq(IRQ_EINT2,&pins_desc[1]);
    105     free_irq(IRQ_EINT11,&pins_desc[2]);
    106     free_irq(IRQ_EINT19,&pins_desc[3]);
    107 
    108     return 0;
    109 }
    110 
    111 static unsigned int forthdrv_poll(struct file *file, struct poll_table_struct *wait)
    112 {
    113     unsigned int mask = 0;
    114     poll_wait(file, &button_waitq, wait); 
    115 
    116     if (ev_press)
    117         mask |= POLLIN | POLLRDNORM;
    118 
    119     return mask;
    120 }
    121 
    122 static struct file_operations forthdrv_fops = {
    123     .owner   = THIS_MODULE,
    124     .open    = forthdrv_open,     
    125     .read     = forthdrv_read,
    126     .release = forthdrv_close,
    127     .poll      = forthdrv_poll,
    128 };
    129 
    130 
    131 int g_iMajor;
    132 static int forthdrv_init(void)
    133 {
    134     g_iMajor = register_chrdev(0, "forth_drv", &forthdrv_fops);
    135 
    136     g_ptForthdrvCls = class_create(THIS_MODULE, "forth_drv");
    137 
    138     g_ptForthdrvClsDev = class_device_create(g_ptForthdrvCls, NULL, MKDEV(g_iMajor, 0), NULL, "buttons"); /* /dev/buttons */
    139 
    140     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    141     gpfdat = gpfcon + 1;
    142 
    143     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    144     gpgdat = gpgcon + 1;
    145 
    146     return 0;
    147 }
    148 
    149 static int forthdrv_exit(void)
    150 {
    151     unregister_chrdev(g_iMajor, "forth_drv");
    152     class_device_unregister(g_ptForthdrvClsDev);
    153     class_destroy(g_ptForthdrvCls);
    154     iounmap(gpfcon);
    155     iounmap(gpgcon);
    156     return 0;
    157 }
    158 
    159 module_init(forthdrv_init);
    160 
    161 module_exit(forthdrv_exit);
    162 MODULE_LICENSE("GPL");
    使用poll机制实现按键驱动程序
     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 #include <poll.h>
     6 /* forthdrvtest 
     7   */
     8 int main(int argc, char **argv)
     9 {
    10     int fd;
    11     unsigned char key_val;
    12     int ret;
    13 
    14     struct pollfd fds[1];
    15     
    16     fd = open("/dev/buttons", O_RDWR);
    17     if (fd < 0)
    18     {
    19         printf("can't open!
    ");
    20     }
    21 
    22     fds[0].fd     = fd;
    23     fds[0].events = POLLIN;
    24     while (1)
    25     {
    26         ret = poll(fds, 1, 5000);
    27         if (ret == 0)
    28         {
    29             printf("time out
    ");
    30         }
    31         else
    32         {
    33             read(fd, &key_val, 1);
    34             printf("key_val = 0x%x
    ", key_val);
    35         }
    36     }
    37     return 0;
    38 }
    测试程序

    四、异步通知机制

    之前的的驱动都是应用程序主动去读取驱动程序传来的数据;有没有一直机制,就是一旦有数据,驱动程序主动通知应用程序,让应用程序来获取数据。这种机制就是异步通知。

    1.异步通知的简介

    异步通知是file_operations中的一个设备方法,定义为
    int (*fsync) (struct file *, struct dentry *, int datasync)

    1.1 四个要点

    要点:
    注册信号处理函数:由应用程序注册信号处理函数
    谁发信号?——驱动
    发给谁?——应用程序的进程ID(如何获取应用程序的进程ID?——fasync_helper函数)
    怎么发?——kill_fasync函数(在中断服务程序实现)

    1.2 总结

    为了使设备支持异步通知机制,驱动程序中涉及以下3项工作:
    ①支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。(不过此项工作已由内核完成,设备驱动无须处理
    ②支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。
       驱动中应该实现fasync()函数。
    ③在设备资源可获得时,调用kill_fasync()函数激发相应的信号

    应用程序:
    fcntl(fd, F_SETOWN, getpid());  // 告诉内核,发给谁

    Oflags = fcntl(fd, F_GETFL);   
    fcntl(fd, F_SETFL, Oflags | FASYNC);  // 改变fasync标记,最终会调用到驱动的faync > fasync_helper:初始化/释放fasync_struct

     

      1 /*
      2   *异步通知机制实现按键驱动程序
      3   */
      4 
      5 #include <linux/module.h>
      6 #include <linux/kernel.h>
      7 #include <linux/fs.h>
      8 #include <linux/init.h>
      9 #include <linux/delay.h>
     10 #include <linux/irq.h>
     11 #include <asm/uaccess.h>
     12 #include <asm/irq.h>
     13 #include <asm/io.h>
     14 #include <asm/arch/regs-gpio.h>
     15 #include <asm/hardware.h>
     16 #include <linux/poll.h>
     17 
     18 
     19 static struct class *g_ptFifthdrvCls;
     20 static struct class_device *g_ptFifthdrvClsDev;
     21 
     22 volatile unsigned long *gpfcon;
     23 volatile unsigned long *gpfdat;
     24 
     25 volatile unsigned long *gpgcon;
     26 volatile unsigned long *gpgdat;
     27 
     28 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
     29 
     30 /* 中断事件标志, 中断服务程序将它置1,forth_drv_read将它清0 */
     31 static volatile int ev_press = 0;
     32 static struct fasync_struct *fifthdrv_async;
     33 
     34 struct pin_desc{
     35     unsigned int pin;
     36     unsigned int key_val;
     37 };
     38 
     39 static unsigned char key_val;
     40 
     41 struct pin_desc pins_desc[4] = {
     42     {S3C2410_GPF0, 0x01},
     43     {S3C2410_GPF2, 0x02},
     44     {S3C2410_GPG3, 0x03},
     45     {S3C2410_GPG11, 0x04},
     46 };
     47 
     48 
     49 /*
     50   * 确定按键值
     51   */
     52 static irqreturn_t buttons_irq(int irq, void *dev_id)
     53 {
     54     struct pin_desc * pindesc = (struct pin_desc *)dev_id;
     55     unsigned int pinval;
     56     
     57     pinval = s3c2410_gpio_getpin(pindesc->pin);
     58 
     59     if (pinval)
     60     {
     61         /* 松开 */
     62         key_val = 0x80 | pindesc->key_val;
     63     }
     64     else
     65     {
     66         /* 按下 */
     67         key_val = pindesc->key_val;
     68     }
     69 
     70     ev_press = 1;                  /* 表示中断发生了 */
     71     wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
     72 
     73     kill_fasync(&fifthdrv_async,SIGIO, POLL_IN);
     74     return IRQ_RETVAL(IRQ_HANDLED);
     75 }
     76 
     77 static int fifthdrv_open(struct inode *inode, struct file *file)
     78 {
     79     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
     80     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
     81     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
     82     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);    
     83 
     84     return 0;
     85 }
     86 
     87 static ssize_t fifthdrv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
     88 {
     89     
     90     if (size != 1)
     91         return -EINVAL;
     92 
     93     /* 如果没有按键动作, 休眠 */
     94     wait_event_interruptible(button_waitq, ev_press);
     95     
     96     /* 如果有按键动作, 返回键值 */
     97     copy_to_user(buf, &key_val, 1);
     98     ev_press = 0;
     99     
    100     return 1;
    101 }
    102 
    103 static int fifthdrv_close (struct inode * inode, struct file * file)
    104 {
    105     free_irq(IRQ_EINT0,&pins_desc[0]);
    106     free_irq(IRQ_EINT2,&pins_desc[1]);
    107     free_irq(IRQ_EINT11,&pins_desc[2]);
    108     free_irq(IRQ_EINT19,&pins_desc[3]);
    109 
    110     return 0;
    111 }
    112 
    113 static unsigned int fifthdrv_poll(struct file *file, struct poll_table_struct *wait)
    114 {
    115     unsigned int mask = 0;
    116     poll_wait(file, &button_waitq, wait); 
    117 
    118     if (ev_press)
    119         mask |= POLLIN | POLLRDNORM;
    120 
    121     return mask;
    122 }
    123 
    124 static int fifthdrv_fasync(int fd, struct file *file, int on)
    125 {    
    126     printk("driver: fifthdrv_fasync
    ");
    127     return fasync_helper(fd, file, on, &fifthdrv_async);
    128 }
    129 
    130 
    131 static struct file_operations fifthdrv_fops = {
    132     .owner   = THIS_MODULE,
    133     .open    = fifthdrv_open,     
    134     .read     = fifthdrv_read,
    135     .release = fifthdrv_close,
    136     .poll      = fifthdrv_poll,
    137     .fasync  = fifthdrv_fasync,
    138 };
    139 
    140 
    141 int g_iMajor;
    142 static int fifthdrv_init(void)
    143 {
    144     g_iMajor = register_chrdev(0, "fifth_drv", &fifthdrv_fops);
    145 
    146     g_ptFifthdrvCls = class_create(THIS_MODULE, "fifth_drv");
    147 
    148     g_ptFifthdrvClsDev = class_device_create(g_ptFifthdrvCls, NULL, MKDEV(g_iMajor, 0), NULL, "buttons"); /* /dev/buttons */
    149 
    150     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    151     gpfdat = gpfcon + 1;
    152 
    153     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    154     gpgdat = gpgcon + 1;
    155 
    156     return 0;
    157 }
    158 
    159 static int fifthdrv_exit(void)
    160 {
    161     unregister_chrdev(g_iMajor, "fifth_drv");
    162     class_device_unregister(g_ptFifthdrvClsDev);
    163     class_destroy(g_ptFifthdrvCls);
    164     iounmap(gpfcon);
    165     iounmap(gpgcon);
    166     return 0;
    167 }
    168 
    169 module_init(fifthdrv_init);
    170 
    171 module_exit(fifthdrv_exit);
    172 MODULE_LICENSE("GPL");
    异步通知机制
     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 #include <poll.h>
     6 #include <signal.h>
     7 #include <sys/types.h>
     8 #include <unistd.h>
     9 #include <fcntl.h>
    10 
    11 
    12 /* fifthdrvtest 
    13   */
    14 int fd;
    15 
    16 void my_signal_fun(int signum)
    17 {
    18     unsigned char key_val;
    19     read(fd, &key_val, 1);
    20     printf("key_val: 0x%x
    ", key_val);
    21 }
    22 
    23 int main(int argc, char **argv)
    24 {
    25     unsigned char key_val;
    26     int ret;
    27     int Oflags;
    28 
    29     signal(SIGIO, my_signal_fun);
    30     
    31     fd = open("/dev/buttons", O_RDWR);
    32     if (fd < 0)
    33     {
    34         printf("can't open!
    ");
    35     }
    36 
    37     fcntl(fd, F_SETOWN, getpid());
    38     
    39     Oflags = fcntl(fd, F_GETFL); 
    40     
    41     fcntl(fd, F_SETFL, Oflags | FASYNC);
    42 
    43 
    44     while (1)
    45     {
    46         sleep(1000);
    47     }
    48     
    49     return 0;
    50 }
    测试程序

     五、同步,互斥,阻塞

    linux内核是多线程的内核,当有多个应用程序来访问同一个驱动程序时必将出错,这是系统所不允许的。所以,同一时刻只能有一个应用程序打开驱动程序。

    实现原理:

    static int canopen = 1;
    在open函数内添加如下代码
    if(--canopen != 0){
        canopen++;
        return -EBUSY;
    }

    在close函数内添加如下代码
    canopen++;

    但是,linux是多任务系统,进行某一操作的同时有可能被切换,从而导致两进程都打开了设备。

    解决方案:

    1.把上述步骤设置为原子操作。

    open函数:
    static atomic_t canopen = ATOMIC_INIT(1);
    if(!atomic_desc_and_test(&canopen)){
        atomic_inc(canopen);
        return -EBUSY;
        }

    close函数:
    atomic_inc(canopen);

    2.使用信号量实现。

    定义信号量init_MUTEX(button_lock)
    获得信号量down(&button_lock)
    释放信号量up(&button_lock)

    3.阻塞

    open函数添加以下代码:

    if (file->f_flags & O_NONBLOCK)
        {
            if (down_trylock(&button_lock))
                    return -EBUSY;
        }
        else
        {
            /* 获取信号量 */
            down(&button_lock);
        }
    在read函数添加以下代码:

       if (file->f_flags & O_NONBLOCK)
        {
            if (!ev_press)
                return -EAGAIN;
        }
        else
        {
            /* 如果没有按键动作, 休眠 */
            wait_event_interruptible(button_waitq, ev_press);
        }

    测试方法:

    当多次执行./sixth_test &时,S即睡眠状态,D即僵死状态

      1 /*
      2   *阻塞方式实现按键驱动程序
      3   */
      4 
      5 #include <linux/module.h>
      6 #include <linux/kernel.h>
      7 #include <linux/fs.h>
      8 #include <linux/init.h>
      9 #include <linux/delay.h>
     10 #include <linux/irq.h>
     11 #include <asm/uaccess.h>
     12 #include <asm/irq.h>
     13 #include <asm/io.h>
     14 #include <asm/arch/regs-gpio.h>
     15 #include <asm/hardware.h>
     16 #include <linux/poll.h>
     17 
     18 
     19 static struct class *g_ptFifthdrvCls;
     20 static struct class_device *g_ptFifthdrvClsDev;
     21 
     22 volatile unsigned long *gpfcon;
     23 volatile unsigned long *gpfdat;
     24 
     25 volatile unsigned long *gpgcon;
     26 volatile unsigned long *gpgdat;
     27 
     28 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
     29 
     30 /* 中断事件标志, 中断服务程序将它置1,forth_drv_read将它清0 */
     31 static volatile int ev_press = 0;
     32 static struct fasync_struct *fifthdrv_async;
     33 
     34 struct pin_desc{
     35     unsigned int pin;
     36     unsigned int key_val;
     37 };
     38 
     39 static unsigned char key_val;
     40 
     41 struct pin_desc pins_desc[4] = {
     42     {S3C2410_GPF0, 0x01},
     43     {S3C2410_GPF2, 0x02},
     44     {S3C2410_GPG3, 0x03},
     45     {S3C2410_GPG11, 0x04},
     46 };
     47 
     48 static DECLARE_MUTEX(button_lock);  
     49 /*
     50   * 确定按键值
     51   */
     52 static irqreturn_t buttons_irq(int irq, void *dev_id)
     53 {
     54     struct pin_desc * pindesc = (struct pin_desc *)dev_id;
     55     unsigned int pinval;
     56     
     57     pinval = s3c2410_gpio_getpin(pindesc->pin);
     58 
     59     if (pinval)
     60     {
     61         /* 松开 */
     62         key_val = 0x80 | pindesc->key_val;
     63     }
     64     else
     65     {
     66         /* 按下 */
     67         key_val = pindesc->key_val;
     68     }
     69 
     70     ev_press = 1;                  /* 表示中断发生了 */
     71     wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
     72 
     73     kill_fasync(&fifthdrv_async,SIGIO, POLL_IN);
     74     return IRQ_RETVAL(IRQ_HANDLED);
     75 }
     76 
     77 static int fifthdrv_open(struct inode *inode, struct file *file)
     78 {
     79 
     80 #if 0    
     81     if (!atomic_dec_and_test(&canopen))
     82     {
     83         atomic_inc(&canopen);
     84         return -EBUSY;
     85     }
     86 #endif        
     87 
     88     if (file->f_flags & O_NONBLOCK)
     89     {
     90         if (down_trylock(&button_lock))
     91             return -EBUSY;
     92     }
     93     else
     94     {
     95         /* 获取信号量 */
     96         down(&button_lock);
     97     }
     98     
     99     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
    100     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
    101     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
    102     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);    
    103 
    104     return 0;
    105 }
    106 
    107 static ssize_t fifthdrv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
    108 {
    109     
    110     if (size != 1)
    111         return -EINVAL;
    112 
    113     if (file->f_flags & O_NONBLOCK)
    114     {
    115         if (!ev_press)
    116             return -EAGAIN;
    117     }
    118     else
    119     {
    120         /* 如果没有按键动作, 休眠 */
    121         wait_event_interruptible(button_waitq, ev_press);
    122     }
    123 
    124     /* 如果有按键动作, 返回键值 */
    125     copy_to_user(buf, &key_val, 1);
    126     ev_press = 0;
    127     
    128     return 1;
    129 }
    130 
    131 static int fifthdrv_close (struct inode * inode, struct file * file)
    132 {
    133     free_irq(IRQ_EINT0,&pins_desc[0]);
    134     free_irq(IRQ_EINT2,&pins_desc[1]);
    135     free_irq(IRQ_EINT11,&pins_desc[2]);
    136     free_irq(IRQ_EINT19,&pins_desc[3]);
    137     up(&button_lock);
    138     return 0;
    139 }
    140 
    141 static unsigned int fifthdrv_poll(struct file *file, struct poll_table_struct *wait)
    142 {
    143     unsigned int mask = 0;
    144     poll_wait(file, &button_waitq, wait); 
    145 
    146     if (ev_press)
    147         mask |= POLLIN | POLLRDNORM;
    148 
    149     return mask;
    150 }
    151 
    152 static int fifthdrv_fasync(int fd, struct file *file, int on)
    153 {    
    154     printk("driver: fifthdrv_fasync
    ");
    155     return fasync_helper(fd, file, on, &fifthdrv_async);
    156 }
    157 
    158 
    159 static struct file_operations fifthdrv_fops = {
    160     .owner   = THIS_MODULE,
    161     .open    = fifthdrv_open,     
    162     .read     = fifthdrv_read,
    163     .release = fifthdrv_close,
    164     .poll      = fifthdrv_poll,
    165     .fasync  = fifthdrv_fasync,
    166 };
    167 
    168 
    169 int g_iMajor;
    170 static int fifthdrv_init(void)
    171 {
    172     g_iMajor = register_chrdev(0, "fifth_drv", &fifthdrv_fops);
    173 
    174     g_ptFifthdrvCls = class_create(THIS_MODULE, "fifth_drv");
    175 
    176     g_ptFifthdrvClsDev = class_device_create(g_ptFifthdrvCls, NULL, MKDEV(g_iMajor, 0), NULL, "buttons"); /* /dev/buttons */
    177 
    178     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    179     gpfdat = gpfcon + 1;
    180 
    181     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    182     gpgdat = gpgcon + 1;
    183 
    184     return 0;
    185 }
    186 
    187 static int fifthdrv_exit(void)
    188 {
    189     unregister_chrdev(g_iMajor, "fifth_drv");
    190     class_device_unregister(g_ptFifthdrvClsDev);
    191     class_destroy(g_ptFifthdrvCls);
    192     iounmap(gpfcon);
    193     iounmap(gpgcon);
    194     return 0;
    195 }
    196 
    197 module_init(fifthdrv_init);
    198 
    199 module_exit(fifthdrv_exit);
    200 MODULE_LICENSE("GPL");
    信号量+阻塞方式
     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 #include <poll.h>
     6 #include <signal.h>
     7 #include <sys/types.h>
     8 #include <unistd.h>
     9 #include <fcntl.h>
    10 
    11 
    12 /* sixthdrvtest 
    13   */
    14 int fd;
    15 
    16 void my_signal_fun(int signum)
    17 {
    18     unsigned char key_val;
    19     read(fd, &key_val, 1);
    20     printf("key_val: 0x%x
    ", key_val);
    21 }
    22 
    23 int main(int argc, char **argv)
    24 {
    25     unsigned char key_val;
    26     int ret;
    27     int Oflags;
    28 
    29     //signal(SIGIO, my_signal_fun);
    30     
    31     fd = open("/dev/buttons", O_RDWR | O_NONBLOCK);
    32     if (fd < 0)
    33     {
    34         printf("can't open!
    ");
    35         return -1;
    36     }
    37 
    38     //fcntl(fd, F_SETOWN, getpid());
    39     
    40     //Oflags = fcntl(fd, F_GETFL); 
    41     
    42     //fcntl(fd, F_SETFL, Oflags | FASYNC);
    43 
    44 
    45     while (1)
    46     {
    47         ret = read(fd, &key_val, 1);
    48         printf("key_val: 0x%x, ret = %d
    ", key_val, ret);
    49         sleep(5);
    50     }
    51     
    52     return 0;
    53 }
    测试程序

    最后科普一下,异步通知和阻塞的区别:

    阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
    阻塞调用是指调用结果返回之前,当前线程会被挂起(休眠)。调用线程只有在得到结果之后才会返回。
    非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

    异步关注的是消息通信机制,当一个异步过程调用发出后,调用者不会立刻得到结果,
    而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用(主动通知调用者)。

    异步通知是相对与同步通知来说的。
    这里阻塞与非阻塞与是否同步异步无关

    比如:你问朋友问题,如果你是阻塞式调用,你会一直把自己“挂起”,直到得到问题有没有解决的结果,
    如果是非阻塞式调用,你不管朋友有没有告诉你,你先去忙其他事,当然你也要偶尔看一下朋友有没有返回结果。

    异步通知:朋友看到你问的问题,直接告诉你他想一下,(此时没有返回结果给你),当他想到了,会主动通知你

    六、定时器防抖动

    1.按键去抖动的方法
        a.硬件电路去抖动
        b.软件延时去抖动,有两种方式,其中一种是什么事都不做,死循环;另一种是利用定时器延时。

    本程序采用的的定时器延时的方式。

    2.定时器延时的两个要素:超时时间,处理函数。

    3.定时器相关的处理函数
        a.初始化定时器init_timer
        b.处理函数timer_list.function
        c.向内核注册一个定时器结构体add_timer
        d.修改定时器时间并启动定时器mod_timer
        
    4.mod_timer(&timer, jiffies+HZ/100)的定时时间为10ms,为什么?
     HZ为100,所以HZ/100 = 1,变成了jiffies+1,而jiffies的单位为10ms,所以每次定时的时间自然就为10ms了。
     

      1 /*
      2   *定时器去抖动
      3   */
      4 
      5 #include <linux/module.h>
      6 #include <linux/kernel.h>
      7 #include <linux/fs.h>
      8 #include <linux/init.h>
      9 #include <linux/delay.h>
     10 #include <linux/irq.h>
     11 #include <asm/uaccess.h>
     12 #include <asm/irq.h>
     13 #include <asm/io.h>
     14 #include <asm/arch/regs-gpio.h>
     15 #include <asm/hardware.h>
     16 #include <linux/poll.h>
     17 
     18 
     19 static struct timer_list timer;
     20 
     21 static struct pin_desc *irq_pd;
     22 
     23 static struct class *g_pbuttonsdrvCls;
     24 static struct class_device *g_pbuttonsdrvClsDev;
     25 
     26 volatile unsigned long *gpfcon;
     27 volatile unsigned long *gpfdat;
     28 
     29 volatile unsigned long *gpgcon;
     30 volatile unsigned long *gpgdat;
     31 
     32 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
     33 
     34 /* 中断事件标志, 中断服务程序将它置1,forth_drv_read将它清0 */
     35 static volatile int ev_press = 0;
     36 static struct fasync_struct *buttonsdrv_async;
     37 
     38 struct pin_desc{
     39     unsigned int pin;
     40     unsigned int key_val;
     41 };
     42 
     43 static unsigned char key_val;
     44 
     45 struct pin_desc pins_desc[4] = {
     46     {S3C2410_GPF0, 0x01},
     47     {S3C2410_GPF2, 0x02},
     48     {S3C2410_GPG3, 0x03},
     49     {S3C2410_GPG11, 0x04},
     50 };
     51 
     52 static DECLARE_MUTEX(button_lock);  
     53 /*
     54   * 确定按键值
     55   */
     56 static irqreturn_t buttons_irq(int irq, void *dev_id)
     57 {
     58     /* 10ms后启动定时器 */
     59     irq_pd = (struct pin_desc *)dev_id;
     60     mod_timer(&timer, jiffies+HZ/100);
     61     return IRQ_RETVAL(IRQ_HANDLED);
     62 }
     63 
     64 static int buttonsdrv_open(struct inode *inode, struct file *file)
     65 {
     66 
     67 #if 0    
     68     if (!atomic_dec_and_test(&canopen))
     69     {
     70         atomic_inc(&canopen);
     71         return -EBUSY;
     72     }
     73 #endif        
     74 
     75     if (file->f_flags & O_NONBLOCK)
     76     {
     77         if (down_trylock(&button_lock))
     78             return -EBUSY;
     79     }
     80     else
     81     {
     82         /* 获取信号量 */
     83         down(&button_lock);
     84     }
     85     
     86     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
     87     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
     88     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
     89     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);    
     90 
     91     return 0;
     92 }
     93 
     94 static ssize_t buttonsdrv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
     95 {
     96     
     97     if (size != 1)
     98         return -EINVAL;
     99 
    100     if (file->f_flags & O_NONBLOCK)
    101     {
    102         if (!ev_press)
    103             return -EAGAIN;
    104     }
    105     else
    106     {
    107         /* 如果没有按键动作, 休眠 */
    108         wait_event_interruptible(button_waitq, ev_press);
    109     }
    110 
    111     /* 如果有按键动作, 返回键值 */
    112     copy_to_user(buf, &key_val, 1);
    113     ev_press = 0;
    114     
    115     return 1;
    116 }
    117 
    118 static int buttonsdrv_close (struct inode * inode, struct file * file)
    119 {
    120     free_irq(IRQ_EINT0,&pins_desc[0]);
    121     free_irq(IRQ_EINT2,&pins_desc[1]);
    122     free_irq(IRQ_EINT11,&pins_desc[2]);
    123     free_irq(IRQ_EINT19,&pins_desc[3]);
    124     up(&button_lock);
    125     return 0;
    126 }
    127 
    128 static unsigned int buttonsdrv_poll(struct file *file, struct poll_table_struct *wait)
    129 {
    130     unsigned int mask = 0;
    131     poll_wait(file, &button_waitq, wait); 
    132 
    133     if (ev_press)
    134         mask |= POLLIN | POLLRDNORM;
    135 
    136     return mask;
    137 }
    138 
    139 static int buttonsdrv_fasync(int fd, struct file *file, int on)
    140 {    
    141     printk("driver: buttonsdrv_fasync
    ");
    142     return fasync_helper(fd, file, on, &buttonsdrv_async);
    143 }
    144 
    145 
    146 static void buttons_timer_func(unsigned long data)
    147 {
    148     struct pin_desc * pindesc = irq_pd;
    149     unsigned int pinval;
    150     
    151     pinval = s3c2410_gpio_getpin(pindesc->pin);
    152 
    153     if (pinval)
    154     {
    155         /* 松开 */
    156         key_val = 0x80 | pindesc->key_val;
    157     }
    158     else
    159     {
    160         /* 按下 */
    161         key_val = pindesc->key_val;
    162     }
    163 
    164     ev_press = 1;                  /* 表示中断发生了 */
    165     wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
    166 
    167     kill_fasync(&buttonsdrv_async,SIGIO, POLL_IN);
    168 //    return IRQ_RETVAL(IRQ_HANDLED);
    169 }
    170 
    171 static struct file_operations buttonsdrv_fops = {
    172     .owner   = THIS_MODULE,
    173     .open    = buttonsdrv_open,     
    174     .read     = buttonsdrv_read,
    175     .release = buttonsdrv_close,
    176     .poll      = buttonsdrv_poll,
    177     .fasync  = buttonsdrv_fasync,
    178 };
    179 
    180 
    181 int g_iMajor;
    182 static int buttonsdrv_init(void)
    183 {
    184 
    185     init_timer(&timer);
    186 //    timer.expires = jiffies + media_tbl[dev->if_port].wait;
    187     timer.function = &buttons_timer_func;    /* timer handler */
    188     add_timer(&timer);
    189 
    190     
    191     g_iMajor = register_chrdev(0, "buttons_drv", &buttonsdrv_fops);
    192 
    193     g_pbuttonsdrvCls = class_create(THIS_MODULE, "buttons_drv");
    194 
    195     g_pbuttonsdrvClsDev = class_device_create(g_pbuttonsdrvCls, NULL, MKDEV(g_iMajor, 0), NULL, "buttons"); /* /dev/buttons */
    196 
    197     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    198     gpfdat = gpfcon + 1;
    199 
    200     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    201     gpgdat = gpgcon + 1;
    202 
    203     return 0;
    204 }
    205 
    206 static int buttonsdrv_exit(void)
    207 {
    208     unregister_chrdev(g_iMajor, "buttons_drv");
    209     class_device_unregister(g_pbuttonsdrvClsDev);
    210     class_destroy(g_pbuttonsdrvCls);
    211     iounmap(gpfcon);
    212     iounmap(gpgcon);
    213     return 0;
    214 }
    215 
    216 module_init(buttonsdrv_init);
    217 
    218 module_exit(buttonsdrv_exit);
    219 MODULE_LICENSE("GPL");
    定时器防抖动
     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 #include <poll.h>
     6 #include <signal.h>
     7 #include <sys/types.h>
     8 #include <unistd.h>
     9 #include <fcntl.h>
    10 
    11 
    12 /* sixthdrvtest 
    13   */
    14 int fd;
    15 
    16 void my_signal_fun(int signum)
    17 {
    18     unsigned char key_val;
    19     read(fd, &key_val, 1);
    20     printf("key_val: 0x%x
    ", key_val);
    21 }
    22 
    23 int main(int argc, char **argv)
    24 {
    25     unsigned char key_val;
    26     int ret;
    27     int Oflags;
    28 
    29     //signal(SIGIO, my_signal_fun);
    30     
    31     fd = open("/dev/input/event0", O_RDWR);
    32     if (fd < 0)
    33     {
    34         printf("can't open!
    ");
    35         return -1;
    36     }
    37 
    38     //fcntl(fd, F_SETOWN, getpid());
    39     
    40     //Oflags = fcntl(fd, F_GETFL); 
    41     
    42     //fcntl(fd, F_SETFL, Oflags | FASYNC);
    43 
    44 
    45     while (1)
    46     {
    47         ret = read(fd, &key_val, 1);
    48         printf("key_val: 0x%x, ret = %d
    ", key_val, ret);
    49         //sleep(5);
    50     }
    51     
    52     return 0;
    53 }
    测试程序

    修改于2017-01-08 21:05:56

     
  • 相关阅读:
    使用Mutex实现程序单实例运行(c#)
    KMP(转载来自Matrix67原创)
    【转载】搞ACM的你伤不起(转载,不过这个神作实在是太经典了)
    POJ 3125 Printer Queue【打印队列】
    弱校ACM奋斗史
    POJ 2063 Investment
    程序员的艺术:排序算法舞蹈【视频】
    POJ 2063 Investment【经典完全背包】
    快速幂模板
    搞ACM的你伤不起(转载,不过这个神作实在是太经典了)
  • 原文地址:https://www.cnblogs.com/Lwd-linux/p/6259034.html
Copyright © 2011-2022 走看看