按键驱动程序(混杂字符设备)







   //misc_key.c
  1 #include <linux/module.h>
  2 #include <linux/kernel.h>
  3 #include <linux/fs.h>
  4 #include <linux/init.h>
  5 #include <linux/delay.h>
  6 #include <linux/poll.h>
  7 #include <linux/irq.h>  // #define S3C_EINT(x) ((x) + S3C_IRQ_EINT_BASE)   #define IRQ_EINT(x) S3C_EINT(x)
  8 #include <asm/irq.h>
  9 #include <asm/io.h>
 10 #include <linux/interrupt.h>
 11 #include <asm/uaccess.h>
 12 #include <mach/hardware.h>
 13 #include <linux/platform_device.h>
 14 #include <linux/cdev.h>
 15 #include <linux/miscdevice.h>
 16 #include <mach/map.h>
 17 #include <mach/regs-clock.h>
 18 #include <mach/regs-gpio.h>
 19 #include <plat/gpio-cfg.h>
 20 #include <mach/gpio-bank-n.h>
 21 #include <mach/gpio-bank-l.h>  //#define S3C64XX_GPLDAT (S3C64XX_GPL_BASE + 0x08)
 22 
 23 #define DEVICE_NAME "button_by_hui"
 24 
 25 struct button_irq_desc{
 26     int irq;
 27     int number;
 28     char *name;
 29 };
 30 
 31 static struct button_irq_desc button_irqs[] = {
 32     {IRQ_EINT(0),  0, "KEY0"},
 33     {IRQ_EINT(1),  1, "KEY1"},
 34     {IRQ_EINT(2),  2, "KEY2"},
 35     {IRQ_EINT(3),  3, "KEY3"},
 36     {IRQ_EINT(4),  4, "KEY4"},
 37     {IRQ_EINT(5),  5, "KEY5"},
 38     {IRQ_EINT(19), 6, "KEY6"},
 39     {IRQ_EINT(20), 7, "KEY7"},
 40 };
 41 static volatile char key_values[] = {'0', '0', '0', '0', '0', '0', '0', '0'};
 42 
 43 static DECLARE_WAIT_QUEUE_HEAD(button_waitq); /*定义一个新的等待队列的头*/
 44 static volatile int ev_press = 0;             /*判断是否有按键按下的标志位*/
 45 
 46 static irqreturn_t buttons_interrupt(int irq, void *dev_id) /*中断处理函数*/
 47 {                                                   /*(void *)&button_irqs[i]申请中断时传进来的参数*/
 48     struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
 49     int down;
 50     int number;
 51     unsigned tmp;
 52     udelay(0);
 53     number = button_irqs->number;
 54     switch(number) {
 55         case 0: case 1: case 2: case 3: case 4: case 5:
 56             tmp = readl(S3C64XX_GPNDAT);  // 
 57             down = !(tmp & (1<<number));
 58             break;
 59         case 6: case 7:
 60             tmp = readl(S3C64XX_GPLDAT); /*(返回)从映射的I/O空间读取32位4字节的数值 */ 
 61             down = !(tmp & (1 << (number + 5)));
 62             break;
 63         default:
 64             down = 0;
 65     }
 66     if (down != (key_values[number] & 1)) {
 67         key_values[number] = '0' + down;
 68         ev_press = 1;
 69         wake_up_interruptible(&button_waitq);   /*唤醒阻塞(睡眠)的等待队列*/
 70     }
 71     /*  //means that we did have a valid interrupt and handled it
 72      *  #define IRQ_RETVAL(x) ((x) != IRQ_NONE )   //这个宏只是返回0或非0
 73      */
 74     return IRQ_RETVAL(IRQ_HANDLED);
 75 }
 76 
 77 static int s3c64xx_buttons_open(struct inode *inode, struct file *file)
 78 {
 79     int i;
 80     int err = 0;
 81     for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
 82         if (button_irqs[i].irq < 0) {
 83             continue;
 84         }                 /*中断号            处理函数           双延触发*/
 85         err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,    /*申请中断*/
 86                 button_irqs[i].name, (void *)&button_irqs[i]);
 87                 /*在proc/interrupts中显示中断拥有者   void *dev_id*/
 88         if (err)
 89             break;
 90     }
 91     if (err) {  /*出错处理 把之前分配的中断释放掉*/
 92         i--;
 93         for (; i >= 0; i--) {
 94             if (button_irqs[i].irq < 0){
 95                 continue;
 96             }
 97             disable_irq(button_irqs[i].irq);
 98             free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
 99         }
100         return -EBUSY;
101     }
102     ev_press = 1;
103     return 0;
104 }
105 
106 static int s3c64xx_buttons_close(struct inode *inode, struct file *file)
107 {
108     int i;
109     for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
110         if (button_irqs[i].irq < 0) {
111             continue;
112         }
113         free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
114     }
115     return 0;
116 }
117 
118 static int s3c64xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
119 {
120     unsigned long err;
121     if (!ev_press) {
122         if (filp->f_flags & O_NONBLOCK)
123             return -EAGAIN;
124         else{
125             /*这个宏:使调用进程在等待队上睡眠,一直到修改了给定条件为止*/
126             wait_event_interruptible(button_waitq, ev_press);  /*直到ev_press 为 1*/
127         }
128     }
129     ev_press = 0;
130     err = copy_to_user((void *)buff, (const void *)(&key_values), min(sizeof(key_values), count));
131     return err ? -EFAULT : min(sizeof(key_values), count);
132 }
133 
134 static unsigned int s3c64xx_buttons_poll( struct file *file, struct poll_table_struct *wait)
135 {
136     unsigned int mask = 0;
137     poll_wait(file, &button_waitq, wait);
138     if (ev_press)
139         mask |= POLLIN | POLLRDNORM;       ev_press = 0;
140     return mask;
141 }
142 
143 static struct file_operations dev_fops = {
144     .owner   = THIS_MODULE,
145     .open    = s3c64xx_buttons_open,
146     .release = s3c64xx_buttons_close,
147     .read    = s3c64xx_buttons_read,
148     .poll    = s3c64xx_buttons_poll,
149 };
150 
151 static struct miscdevice misc = { /*杂项字符设备结构体*/
152     .minor = MISC_DYNAMIC_MINOR,  /*次设备号 表示自动分配*/
153     .name  = DEVICE_NAME,         /*设备名*/
154     .fops  = &dev_fops,           /*设备操作*/
155 };
156 
157 static int __init dev_init(void)
158 {
159     int ret;
160     ret = misc_register(&misc);             /*注册一个混杂设备 在加载模块时会自动创建设备文件, 为主设备号为10的字符设备*/
161     printk(DEVICE_NAME"\tinitialized\n");   /*无需mknod指令创建设备文件。因为misc_register()会调用class_device_create()或者device_create()*/
162     return ret;
163 }
164 
165 static void __exit dev_exit(void)
166 {
167     misc_deregister(&misc);                 /*注销混杂设备 自动删除设备文件*/
168 }
169 
170 module_init(dev_init);
171 module_exit(dev_exit);
172 MODULE_LICENSE("GPL");
173 MODULE_AUTHOR("FriendlyARM Inc.");

测试程序:

  //button_test.c
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <sys/ioctl.h>
  5 #include <sys/types.h>
  6 #include <sys/stat.h>
  7 #include <fcntl.h>
  8 #include <sys/select.h>
  9 #include <sys/time.h>
 10 #include <errno.h>
 11 
 12 int main(void)
 13 {
 14     int buttons_fd;
 15     char buttons[6] = {'0', '0', '0', '0', '0', '0'};
 16 
 17     buttons_fd = open("/dev/button_by_hui", 0);
 18     if(buttons_fd < 0){
 19         perror("open device buttons");
 20         exit(1);
 21     }
 22 
 23     printf("open /dev/button_by_hui ok\n please puton one key\n");
 24 
 25     for(;;){
 26         char current_buttons[6];
 27         int count_of_changed_key;
 28         int i;
 29         if(read(buttons_fd, current_buttons, sizeof current_buttons) != sizeof current_buttons){
 30             perror("read buttons:");
 31             exit(1);
 32         }
 33 
 34         for(i = 0, count_of_changed_key = 0; i < sizeof buttons / sizeof buttons[0]; i++){
 35             if(buttons[i] != current_buttons[i]){
 36                 buttons[i] = current_buttons[i];
 37                 printf("%s key%d is %s", count_of_changed_key ? "," : "" ,   i+1,  buttons[i] == '0' ?  "up" : "down" );
 38                 count_of_changed_key++;
 39             }
 40         }
 41 
 42         if(count_of_changed_key){
 43             printf("\n");
 44         }
 45     }
 46 
 47     close(buttons_fd);
 48     return 0;
 49 }


轮询操作:(也可以在驱动中增加异步通知 这样应用程序调用时就更加强大了 如,按键按下灯亮的操作)

  1 /*测试程序:该程序用于监控 key 的是否可读(按下)状态*/
  2 #include<stdio.h>
  3 #include<sys/select.h>
  4 #include<fcntl.h>
  5 
  6 int main(void)
  7 {
  8     int fd;
  9     fd_set rfds; /*读文件描述符集*/
 10     
 11     /*以非阻塞的方式打开 设备文件*/
 12     fd = open("/dev/button_by_hui", O_RDONLY | O_NONBLOCK);
 13     if(fd != -1){
 14         while(1){
 15             FD_ZERO(&rfds); /*清除一个文件描述符集*/
 16             FD_SET(fd, &rfds); /*将一个文件描述符 加入 文件描述符集中*/
 17             
 18 /*最高文件描述符+1 要监控的 读    写     异常  等待超时返回*/
 19             select(fd + 1, &rfds, NULL, NULL, NULL); /*该函数最终调用poll*/
 20             
 21             /*数据可获得*/
 22             if(FD_ISSET(fd, &rfds))
 23                 printf("Poll monitor:button can be read\n");
 24         }       
 25     }else{
 26         printf("Device open failure\n");
 27     }   
 28     return 0;
 29 }   



评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值