嵌入式Linux驱动学习之路(十四)按键驱动-同步、互斥、阻塞
目的:同一个时刻,只能有一个应用程序打开我们的驱动程序。
①原子操作:
v = ATOMIC_INIT( i ) 定义原子变量v并初始化为i
atomic_read(v) 返回原子变量的值
atomic_set(v,i) 设置原子变量的值
atomic_inc_and_test(v) 自加后和测试是否为0 为0则返回true
atomic_dec_and_test(v) 自减后和测试是否为0 为0则返回true
atomic_inc(v) 自加
#atomic_dec(v) 自减
驱动代码:
#include <linux/sched.h> #include <linux/signal.h> #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/random.h> #include <linux/poll.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/wait.h> #include <linux/mutex.h> #include <linux/io.h> #include <asm/irq.h> #include <linux/irq.h> #include <linux/fs.h> #include <asm/arch/regs-gpio.h> #include <linux/interrupt.h> #include <linux/poll.h> static struct class *key_class; //创建类 static struct class_device *key_class_devs; //创建类对应的设备 struct pin_desc{ unsigned int pin; unsigned int key_val; }; struct pin_desc pins_desc[4] = { {S3C2410_GPF0,0X01}, {S3C2410_GPF2,0X02}, {S3C2410_GPG3,0X03}, {S3C2410_GPG11,0X04}, }; unsigned char keyvals=0; static volatile int ev_press = 0; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); static struct fasync_struct *key_async_queue; atomic_t canopen = ATOMIC_INIT(1); static irqreturn_t keys_irq(int irq, void *dev_id) { struct pin_desc *pindesc = (struct pin_desc *)dev_id; unsigned int pinval; pinval = s3c2410_gpio_getpin(pindesc->pin); if(pinval) { keyvals = pindesc->key_val|0x80; } else { keyvals = pindesc->key_val; } ev_press = 1; wake_up_interruptible(&button_waitq); kill_fasync (&key_async_queue, SIGIO, POLL_IN); return IRQ_HANDLED; } int key_open(struct inode *inode, struct file *fp) { if(!atomic_dec_and_test(&canopen)) //if --canopen==0 return ture /*自减后和0相比 如果等于0 则返回true*/ { atomic_inc(&canopen); return -EBUSY; } request_irq( IRQ_EINT0, keys_irq, IRQT_BOTHEDGE, "key2", &pins_desc[0]); request_irq( IRQ_EINT2, keys_irq, IRQT_BOTHEDGE, "key3", &pins_desc[1]); request_irq( IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "key4", &pins_desc[2]); request_irq( IRQ_EINT19, keys_irq, IRQT_BOTHEDGE, "key5", &pins_desc[3]); return 0; } ssize_t key_read(struct file *fp, char __user *buff, size_t count, loff_t *offp){ if(count != 1) { return -EINVAL; } wait_event_interruptible(button_waitq,ev_press); copy_to_user(buff,&keyvals,1); ev_press = 0; return 0; } ssize_t key_write(struct file *fp, const char __user *buf, size_t count, loff_t *ppos){ } int key_close(struct inode *inode, struct file *file) { atomic_inc(&canopen); free_irq(IRQ_EINT0,&pins_desc[0]); free_irq(IRQ_EINT2,&pins_desc[1]); free_irq(IRQ_EINT11,&pins_desc[2]); free_irq(IRQ_EINT19,&pins_desc[3]); } static unsigned int key_poll(struct file *file, struct poll_table_struct *wait) { unsigned int mask = 0; poll_wait(file, &button_waitq,wait); if(ev_press) mask |= POLLIN|POLLRDNORM; return mask; } static int key_fsync (int fd, struct file *filp, int on) { printk("ok\n"); return fasync_helper (fd, filp, on, &key_async_queue); } struct file_operations led_fops={ .owner = THIS_MODULE, .open = key_open, .write = key_write, .read = key_read, .release = key_close, .poll = key_poll, .fasync = key_fsync, }; int major; static int key_init(void) { major = register_chrdev( 0,"key_drv", &led_fops ); key_class = class_create(THIS_MODULE,"key_class"); key_class_devs = class_device_create(key_class,NULL,MKDEV(major,0),NULL,"my_keys"); printk("key install Module\n"); return 0; } static void key_exit(void) { unregister_chrdev( major, "key_drv" ); class_device_unregister(key_class_devs); class_destroy(key_class); printk("key Module exit\n"); } module_init(key_init); module_exit(key_exit); MODULE_LICENSE("GPL");
信号量:
#include <linux/sched.h> #include <linux/signal.h> #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/random.h> #include <linux/poll.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/wait.h> #include <linux/mutex.h> #include <linux/io.h> #include <asm/irq.h> #include <linux/irq.h> #include <linux/fs.h> #include <asm/arch/regs-gpio.h> #include <linux/interrupt.h> #include <linux/poll.h> static struct class *key_class; //创建类 static struct class_device *key_class_devs; //创建类对应的设备 struct pin_desc{ unsigned int pin; unsigned int key_val; }; struct pin_desc pins_desc[4] = { {S3C2410_GPF0,0X01}, {S3C2410_GPF2,0X02}, {S3C2410_GPG3,0X03}, {S3C2410_GPG11,0X04}, }; unsigned char keyvals=0; static volatile int ev_press = 0; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); static struct fasync_struct *key_async_queue; static DECLARE_MUTEX(canopen); //定义互斥锁 static irqreturn_t keys_irq(int irq, void *dev_id) { struct pin_desc *pindesc = (struct pin_desc *)dev_id; unsigned int pinval; pinval = s3c2410_gpio_getpin(pindesc->pin); if(pinval) { keyvals = pindesc->key_val|0x80; } else { keyvals = pindesc->key_val; } ev_press = 1; wake_up_interruptible(&button_waitq); kill_fasync (&key_async_queue, SIGIO, POLL_IN); return IRQ_HANDLED; } int key_open(struct inode *inode, struct file *fp) { /*获取信号量*/ down(&canopen); //如果设备已经被打开,那么程序将会一直停在这里知道信号量被释放。 request_irq( IRQ_EINT0, keys_irq, IRQT_BOTHEDGE, "key2", &pins_desc[0]); request_irq( IRQ_EINT2, keys_irq, IRQT_BOTHEDGE, "key3", &pins_desc[1]); request_irq( IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "key4", &pins_desc[2]); request_irq( IRQ_EINT19, keys_irq, IRQT_BOTHEDGE, "key5", &pins_desc[3]); return 0; } ssize_t key_read(struct file *fp, char __user *buff, size_t count, loff_t *offp){ if(count != 1) { return -EINVAL; } wait_event_interruptible(button_waitq,ev_press); copy_to_user(buff,&keyvals,1); ev_press = 0; return 0; } ssize_t key_write(struct file *fp, const char __user *buf, size_t count, loff_t *ppos){ } int key_close(struct inode *inode, struct file *file) { free_irq(IRQ_EINT0,&pins_desc[0]); free_irq(IRQ_EINT2,&pins_desc[1]); free_irq(IRQ_EINT11,&pins_desc[2]); free_irq(IRQ_EINT19,&pins_desc[3]); up(&canopen); } static unsigned int key_poll(struct file *file, struct poll_table_struct *wait) { unsigned int mask = 0; poll_wait(file, &button_waitq,wait); if(ev_press) mask |= POLLIN|POLLRDNORM; return mask; } static int key_fsync (int fd, struct file *filp, int on) { printk("ok\n"); return fasync_helper (fd, filp, on, &key_async_queue); } struct file_operations led_fops={ .owner = THIS_MODULE, .open = key_open, .write = key_write, .read = key_read, .release = key_close, .poll = key_poll, .fasync = key_fsync, }; int major; static int key_init(void) { major = register_chrdev( 0,"key_drv", &led_fops ); key_class = class_create(THIS_MODULE,"key_class"); key_class_devs = class_device_create(key_class,NULL,MKDEV(major,0),NULL,"my_keys"); printk("key install Module\n"); return 0; } static void key_exit(void) { unregister_chrdev( major, "key_drv" ); class_device_unregister(key_class_devs); class_destroy(key_class); printk("key Module exit\n"); } module_init(key_init); module_exit(key_exit); MODULE_LICENSE("GPL");
阻塞:分为阻塞和非阻塞
如何分辨阻塞和非阻塞呢?则需要在打开设备文件的时候传入一个参数
#include <linux/sched.h> #include <linux/signal.h> #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/random.h> #include <linux/poll.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/wait.h> #include <linux/mutex.h> #include <linux/io.h> #include <asm/irq.h> #include <linux/irq.h> #include <linux/fs.h> #include <asm/arch/regs-gpio.h> #include <linux/interrupt.h> #include <linux/poll.h> static struct class *key_class; //创建类 static struct class_device *key_class_devs; //创建类对应的设备 struct pin_desc{ unsigned int pin; unsigned int key_val; }; struct pin_desc pins_desc[4] = { {S3C2410_GPF0,0X01}, {S3C2410_GPF2,0X02}, {S3C2410_GPG3,0X03}, {S3C2410_GPG11,0X04}, }; unsigned char keyvals=0; static volatile int ev_press = 0; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); static struct fasync_struct *key_async_queue; static DECLARE_MUTEX(canopen); //定义互斥锁 static irqreturn_t keys_irq(int irq, void *dev_id) { struct pin_desc *pindesc = (struct pin_desc *)dev_id; unsigned int pinval; pinval = s3c2410_gpio_getpin(pindesc->pin); if(pinval) { keyvals = pindesc->key_val|0x80; } else { keyvals = pindesc->key_val; } ev_press = 1; wake_up_interruptible(&button_waitq); kill_fasync (&key_async_queue, SIGIO, POLL_IN); return IRQ_HANDLED; } int key_open(struct inode *inode, struct file *fp) { /*获取信号量*/ if( fp->f_flags & O_NONBLOCK ) { if(down_trylock(&canopen)) return -EBUSY; } else { down(&canopen); } request_irq( IRQ_EINT0, keys_irq, IRQT_BOTHEDGE, "key2", &pins_desc[0]); request_irq( IRQ_EINT2, keys_irq, IRQT_BOTHEDGE, "key3", &pins_desc[1]); request_irq( IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "key4", &pins_desc[2]); request_irq( IRQ_EINT19, keys_irq, IRQT_BOTHEDGE, "key5", &pins_desc[3]); return 0; } ssize_t key_read(struct file *fp, char __user *buff, size_t count, loff_t *offp){ if(fp->f_flags & O_NONBLOCK ) { if(!ev_press) return -EAGAIN; } else { wait_event_interruptible(button_waitq,ev_press); } if(count != 1) { return -EINVAL; } copy_to_user(buff,&keyvals,1); ev_press = 0; return 0; } ssize_t key_write(struct file *fp, const char __user *buf, size_t count, loff_t *ppos){ } int key_close(struct inode *inode, struct file *file) { free_irq(IRQ_EINT0,&pins_desc[0]); free_irq(IRQ_EINT2,&pins_desc[1]); free_irq(IRQ_EINT11,&pins_desc[2]); free_irq(IRQ_EINT19,&pins_desc[3]); up(&canopen); } static unsigned int key_poll(struct file *file, struct poll_table_struct *wait) { unsigned int mask = 0; poll_wait(file, &button_waitq,wait); if(ev_press) mask |= POLLIN|POLLRDNORM; return mask; } static int key_fsync (int fd, struct file *filp, int on) { printk("ok\n"); return fasync_helper (fd, filp, on, &key_async_queue); } struct file_operations led_fops={ .owner = THIS_MODULE, .open = key_open, .write = key_write, .read = key_read, .release = key_close, .poll = key_poll, .fasync = key_fsync, }; int major; static int key_init(void) { major = register_chrdev( 0,"key_drv", &led_fops ); key_class = class_create(THIS_MODULE,"key_class"); key_class_devs = class_device_create(key_class,NULL,MKDEV(major,0),NULL,"my_keys"); printk("key install Module\n"); return 0; } static void key_exit(void) { unregister_chrdev( major, "key_drv" ); class_device_unregister(key_class_devs); class_destroy(key_class); printk("key Module exit\n"); } module_init(key_init); module_exit(key_exit); MODULE_LICENSE("GPL");
阻塞测试文件:
#include <stdio.h> #include <signal.h> #include <fcntl.h> #include <unistd.h> int fd; static char key_val; int main( int argc, char **argv ) { int oflags; fd = open("/dev/my_keys",O_RDWR|O_NONBLOCK); /* O_NONBLOCK为非阻塞*/ if(fd<0) { printf("open failed\n"); return 0; } while(1) { read(fd,&key_val,1); printf("key_val:%d\n",key_val); sleep(1); } return 0; }
完
u-boot下载地址: ftp://ftp.denx.de/pub/u-boot/
linux内核下载地址: https://www.kernel.org/pub/linux/kernel
linux内核下载地址: https://www.kernel.org/pub/linux/kernel