【Linux Device Driver】—(2)—Concurrency and Race Conditions——代码

来源:互联网 发布:苹果文字识别软件 编辑:程序博客网 时间:2024/06/05 07:55

做了做这个信号量的实验,不过用到了异步通知,也就是通过内核来通知应用程序(具体就是按键按下后,内核通知应用程序可以进行读操作)!


在《Linux Device Driver》这本书里我查过了,在下章节会介绍到,但是也懒得改代码了,所以就这样贴出来吧,马上也就要写一下异步通知这个很实用的动动。。

这里我用的是互斥锁,还可以设置 O_NONBLOCK 位。

1、驱动程序

①、tiny6410_button_sem.c

 

#include <linux/io.h>#include <linux/platform_device.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/poll.h>#include <linux/cdev.h>#include <mach/regs-gpio.h>#include <mach/gpio-bank-n.h>#include <mach/gpio-bank-l.h>#include <mach/map.h>MODULE_LICENSE("GPL");static int major;static dev_t devno;static struct cdev cdev;static struct class *tiny6410_class;static struct device *tiny6410_device;static struct fasync_struct *tiny6410_button_fasync;static volatile char key_value;static DEFINE_SEMAPHORE(button_semlock);typedef struct {int irq;/* 中断号 */int num;/* 对应的按键编码 */char *name;/* 对应的按键名称 */} button_irq;button_irq button_irqs[] = {{IRQ_EINT(0), 0, "KEY1"},{IRQ_EINT(1), 1, "KEY2"},{IRQ_EINT(2), 2, "KEY3"},{IRQ_EINT(3), 3, "KEY4"},{IRQ_EINT(4), 4, "KEY5"},{IRQ_EINT(5), 5, "KEY6"},{IRQ_EINT(19), 6, "KEY7"},{IRQ_EINT(20), 7, "KEY8"},};static irqreturn_t button_interrupt(int irq,void *dev_id){button_irq *button_irqs_tmp = (struct button_irq *)dev_id;int down;int number;unsigned tmp;number = button_irqs_tmp->num;switch(number) {case 0: case 1: case 2: case 3: case 4: case 5:tmp = readl(S3C64XX_GPNDAT);down = !(tmp & (1<<number));break;case 6: case 7:tmp = readl(S3C64XX_GPLDAT);down = !(tmp & (1 << (number + 5)));break;default:down = 0;}if (down == !(key_value & (1<<number))) {key_value = down ? (key_value | (1<<number)) : (key_value & ~(1<<number));kill_fasync (&tiny6410_button_fasync, SIGIO, POLL_IN);    }    return IRQ_RETVAL(IRQ_HANDLED);}static void button_request_irq(void){int i;for(i=0; i<8; i++) {request_irq(button_irqs[i].irq, button_interrupt,IRQ_TYPE_EDGE_BOTH, button_irqs[i].name, (void *)(&button_irqs[i]));}}static void button_free_irq(void){int i;for(i=0; i<8; i++) {free_irq(button_irqs[i].irq, (void *)(&button_irqs[i]));}}static int button_open(struct inode *inode, struct file *filp){if(filp->f_flags & O_NONBLOCK) {if(down_trylock(&button_semlock)) {return -EBUSY;}}else {down(&button_semlock);}button_request_irq();return 0;}static int button_release(struct inode *inode, struct file *filp){up(&button_semlock);button_free_irq();return 0;}static ssize_t button_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos){unsigned long err;err = copy_to_user(buf, &key_value, sizeof(key_value));return err ? -EFAULT : min(sizeof(key_value), size);}static int button_fasync(int fd, struct file *filp, int on){printk("Call button_fasync!\n");return fasync_helper(fd, filp, on, &tiny6410_button_fasync);}static const struct file_operations button_fops ={.owner = THIS_MODULE,.open  = button_open,.release = button_release,.read  = button_read,.fasync = button_fasync,};static int __init button_sem_init(void){alloc_chrdev_region(&devno, 0, 1, "tiny6410_button_sem");major = MAJOR(devno);/* 初始化cdev */cdev_init(&cdev, &button_fops);cdev.owner = THIS_MODULE;/* 注册cdev */cdev_add(&cdev, MKDEV(major, 0), 1);tiny6410_class = class_create(THIS_MODULE, "tiny6410_sem_class");tiny6410_device = device_create(tiny6410_class, NULL, MKDEV(major, 0), NULL, "tiny6410_button_sem");return 0;}static void __exit button_sem_exit(void){device_destroy(tiny6410_class, devno);class_destroy(tiny6410_class);/* 注销cdev */cdev_del(&cdev);unregister_chrdev_region(MKDEV(major, 0), 1);;}module_init(button_sem_init);moudle_exit(button_sem_exit);


 2、测试程序

①、tiny6410_button_sem_app.c

#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <poll.h>#include <signal.h>#include <sys/types.h>#include <unistd.h>#include <fcntl.h>/* tiny6410_button_sem_app.c  */  int fd;void button_fasync_signal(int signum){int i;int key_value, last_key_value;read(fd, &key_value, sizeof(key_value));for (i=0; i<8; i++) {if ((key_value & (1<<i)) != (last_key_value & (1<<i))) {printf("KEY%d: %s (key_value = 0x%x)\n",i+1, (key_value & (1<<i)) ? "DOWN" : "UP", key_value);}}last_key_value = key_value;}int main(int argc, char **argv){unsigned char key_val;int ret;int oflags;signal(SIGIO, button_fasync_signal);fd = open("/dev/tiny6410_button_sem", O_RDWR | O_NONBLOCK);if (fd < 0) {printf("can't open!\n");}fcntl(fd, F_SETOWN, getpid());/* Save process ID in filp -> f_owner,告诉内核我要发给谁 */oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, (oflags | FASYNC));/* 改变fasync 标志,最终会调用到驱动的fasync > fasync_helper;用来初始化/ 释放fasync_struct */while (1) {sleep(1000);}return 0;}


3、测试结果

 

当时由于没有记录。。。。所以就这样吧。。呵呵。。

原创粉丝点击