在按键驱动中增加异步通知的例子

来源:互联网 发布:卖家淘宝退款流程图 编辑:程序博客网 时间:2024/04/29 21:20


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

  //misc_key_async.c  1 #include<stdio.h>  2 #include<stdlib.h>  3 #include<unistd.h>  4 #include<fcntl.h>  5 #include<signal.h>  6 #include<sys/stat.h>  7   8 //#define DEBUG  9  10 #ifdef DEBUG 11 #define MAX_LEN 100 12 #endif 13  14 /*接受到异步读信号后的动作*/ 15 void input_handler(int signum) 16 { 17 #ifdef DEBUG 18     char data[MAX_LEN]; 19     int len; 20     /*读取并输出SIDIN_FILENO 上的输入*/ 21     len = read(fd, &data, MAX_LEN); 22     data[len] = '\0'; 23     printf("input available:%s", data); 24  25 #endif 26     printf("receive a signal from globalfifo, signalnum:%d\n",signum); 27 } 28  29 int main(void) 30 { 31     int fd,oflags; 32     fd = open("/dev/button_by_hui", O_RDWR, S_IRUSR | S_IWUSR); 33     if(fd != -1){ 34         /*启动信号驱动机制*/         /*设置信号处理函数*/ 35         signal(SIGIO, input_handler);/*让input_handler()函数处理SIGIO信号*/ 36         fcntl(fd, F_SETOWN, getpid()); /*通过F_SETOWN IO控制命令设置设备文件拥有者为本进程*/ 37         oflags = fcntl(fd, F_GETFL);/*F_GETFL 命令 取得fd设备文件状态标志*/ 38         fcntl(fd, F_SETFL, oflags | FASYNC); /*F_SETFL 命令设置设备文件支持FASYNC(异步通知模式)*/ 39         while(1){ 40             sleep(100); 41         } 42     }else{ 43         printf("device open failure\n"); 44     } 45 }








原创粉丝点击