驱动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

 
原文地址:https://www.cnblogs.com/Lwd-linux/p/6259034.html