atomic_t v = ATOMIC_INIT(1);//定义原子变量v初始化为1②在即将访问临界资源前设定“使用中”标记,通常是:
atomic_inc(&canopen);}
printk("Using now!\n");
return -EBUSY;
atomic_inc(&canopen);//释放原子变量代码实现:
atomic.c文件
#include <linux/delay.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <linux/module.h> #include <linux/device.h> //class_create #include <mach/regs-gpio.h> //S3C2410_GPF1 #include <mach/hardware.h> #include <linux/interrupt.h> //wait_event_interruptible #include <linux/fs.h> #include <arch/arm/include/asm/atomic.h> /* 定义并初始化等待队列头 */ static DECLARE_WAIT_QUEUE_HEAD(button_waitq); //////////////////////////////////////////////////////////////////////// static atomic_t canopen = ATOMIC_INIT(1); //定义原子变量并初始化为1 //////////////////////////////////////////////////////////////////////// static struct class *buttondev_class; static struct device *buttons_device; static struct pin_desc{ unsigned int pin; unsigned int key_val; }; static struct pin_desc pins_desc[4] = { {S3C2410_GPF1,0x01}, //S3C2410_GPF1是对GPF1引脚这种“设备”的编号dev_id {S3C2410_GPF4,0x02}, {S3C2410_GPF2,0x03}, {S3C2410_GPF0,0x04}, }; static int ev_press = 0; static unsigned char key_val; int major; /* 中断处理函数 */ static irqreturn_t handle_irq(int irq, void *dev_id) { struct pin_desc *irq_pindesc = (struct pin_desc *)dev_id;// unsigned int pinval; pinval = s3c2410_gpio_getpin(irq_pindesc->pin);//获取按键值:有按键按下返回按键值0 /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */ /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */ if(pinval) { /* 松开 */ key_val = 0x80 | (irq_pindesc->key_val); } else { /* 按下 */ key_val = irq_pindesc->key_val; } ev_press = 1; /* 表示中断已经发生 */ wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */ return IRQ_HANDLED; } static int buttons_dev_open(struct inode * inode, struct file * filp) { /////////////////////////////////////////////////////////// //实现互斥:原子操作 if (!atomic_dec_and_test(&canopen)) { atomic_inc(&canopen); printk("dev is using now!\n"); return -EBUSY; } /////////////////////////////////////////////////////////// request_irq(IRQ_EINT1, handle_irq, IRQ_TYPE_EDGE_FALLING, "K1",&pins_desc[0]); request_irq(IRQ_EINT4, handle_irq, IRQ_TYPE_EDGE_FALLING, "K2",&pins_desc[1]); request_irq(IRQ_EINT2, handle_irq, IRQ_TYPE_EDGE_FALLING, "K3",&pins_desc[2]); request_irq(IRQ_EINT0, handle_irq, IRQ_TYPE_EDGE_FALLING, "K4",&pins_desc[3]); return 0; } static int buttons_dev_close(struct inode *inode, struct file *file) { ////////////////////////////////////////////////////////////// atomic_inc(&canopen);//释放原子变量 ////////////////////////////////////////////////////////////// free_irq(IRQ_EINT1,&pins_desc[0]); free_irq(IRQ_EINT4,&pins_desc[1]); free_irq(IRQ_EINT2,&pins_desc[2]); free_irq(IRQ_EINT0,&pins_desc[3]); return 0; } static ssize_t buttons_dev_read(struct file *file, char __user *user, size_t size,loff_t *ppos) { if (size != 1) return -EINVAL; wait_event_interruptible(button_waitq, ev_press);//没有按键就进入休眠 copy_to_user(user, &key_val, 1); /* 将ev_press清零 */ ev_press = 0; return 1; } /* File operations struct for character device */ static const struct file_operations buttons_dev_fops = { .owner = THIS_MODULE, .open = buttons_dev_open, .read = buttons_dev_read, .release = buttons_dev_close, }; /* 驱动入口函数 */ static int buttons_dev_init(void) { /* 主设备号设置为0表示由系统自动分配主设备号 */ major = register_chrdev(0, "buttons_dev", &buttons_dev_fops); /* 创建buttondev类 */ buttondev_class = class_create(THIS_MODULE, "buttondev"); /* 在buttondev类下创建buttons设备,供应用程序打开设备*/ buttons_device = device_create(buttondev_class, NULL, MKDEV(major, 0), NULL, "buttons");// return 0; } /* 驱动出口函数 */ static void buttons_dev_exit(void) { unregister_chrdev(major, "buttons_dev"); device_unregister(buttons_device); //卸载类下的设备 class_destroy(buttondev_class); //卸载类 } /* 模块加载和卸载函数的修饰 */ module_init(buttons_dev_init); module_exit(buttons_dev_exit); MODULE_AUTHOR("CLBIAO"); MODULE_DESCRIPTION("Just for Demon"); MODULE_LICENSE("GPL"); //遵循GPL协议测试程序:
app_atomic.c
/* 文件的编译指令是arm-linux-gcc -static -o app_irq app_atomic.c */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> //sleep #include <stdio.h> int main(int argc, char **argv) { int flag,fd; unsigned char key_val; fd = open("/dev/buttons", O_RDWR); //申请外部引脚中断服务 if (fd < 0) { printf("can't open!\n");//打开失败 return -1;//返回 } while(1) { read(fd,&key_val,1); printf("key_val = 0x%x\n",key_val); sleep(3); } return 0; }运行结果:
DECLARE_MUTEX(name);//定义一个名为name的信号量,并初始化为1②获取信号量
void down(struct semaphore * sem);//获得信号量sem,如果获取不到,这个函数会导致休眠,休眠 不可以被信号打断,因此不要在中断上下文中使用。太固执的结果!“down”往下,让我想到:在资源上插一支旗子,获取他的人就把它拿下来,其他人就呵呵了^_^
void down_interruptible(struct semaphore * sem);//进入睡眠状态的进程能被信号打断
void down_trylock(struct semaphore * sem);//尝试去获取信号量,成功返回0,失败返回非零,不会导致调用进程休眠,可用于中断上下文
int up(struct semaphore * sem);//把信号插回去,然后唤醒沉睡的人代码实现:
#include <linux/delay.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <linux/module.h> #include <linux/device.h> //class_create #include <mach/regs-gpio.h> //S3C2410_GPF1 #include <mach/hardware.h> #include <linux/interrupt.h> //wait_event_interruptible #include <linux/fs.h> #include <linux/semaphore.h> /* 定义并初始化等待队列头 */ static DECLARE_WAIT_QUEUE_HEAD(button_waitq); //////////////////////////////////////////////////////////////////////// static DECLARE_MUTEX(button_lock);//(1)获取信号量量并初始化为1 //////////////////////////////////////////////////////////////////////// static struct class *buttondev_class; static struct device *buttons_device; static struct pin_desc{ unsigned int pin; unsigned int key_val; }; static struct pin_desc pins_desc[4] = { {S3C2410_GPF1,0x01}, //S3C2410_GPF1是对GPF1引脚这种“设备”的编号dev_id {S3C2410_GPF4,0x02}, {S3C2410_GPF2,0x03}, {S3C2410_GPF0,0x04}, }; static int ev_press = 0; static unsigned char key_val; int major; /* 中断处理函数 */ static irqreturn_t handle_irq(int irq, void *dev_id) { struct pin_desc *irq_pindesc = (struct pin_desc *)dev_id;// unsigned int pinval; pinval = s3c2410_gpio_getpin(irq_pindesc->pin);//获取按键值:有按键按下返回按键值0 /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */ /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */ if(pinval) { /* 松开 */ key_val = 0x80 | (irq_pindesc->key_val); } else { /* 按下 */ key_val = irq_pindesc->key_val; } ev_press = 1; /* 表示中断已经发生 */ wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */ return IRQ_HANDLED; } static int buttons_dev_open(struct inode * inode, struct file * filp) { ///////////////////////////////////// down(&button_lock);//(2)获取信号量 //////////////////////////////////// request_irq(IRQ_EINT1, handle_irq, IRQ_TYPE_EDGE_FALLING, "K1",&pins_desc[0]); request_irq(IRQ_EINT4, handle_irq, IRQ_TYPE_EDGE_FALLING, "K2",&pins_desc[1]); request_irq(IRQ_EINT2, handle_irq, IRQ_TYPE_EDGE_FALLING, "K3",&pins_desc[2]); request_irq(IRQ_EINT0, handle_irq, IRQ_TYPE_EDGE_FALLING, "K4",&pins_desc[3]); return 0; } static int buttons_dev_close(struct inode *inode, struct file *file) { ///////////////////////////////////// up(&button_lock);//(3)释放信号量 //////////////////////////////////// free_irq(IRQ_EINT1,&pins_desc[0]); free_irq(IRQ_EINT4,&pins_desc[1]); free_irq(IRQ_EINT2,&pins_desc[2]); free_irq(IRQ_EINT0,&pins_desc[3]); return 0; } static ssize_t buttons_dev_read(struct file *file, char __user *user, size_t size,loff_t *ppos) { if (size != 1) return -EINVAL; wait_event_interruptible(button_waitq, ev_press);//没有按键就进入休眠 copy_to_user(user, &key_val, 1); /* 将ev_press清零 */ ev_press = 0; return 1; } /* File operations struct for character device */ static const struct file_operations buttons_dev_fops = { .owner = THIS_MODULE, .open = buttons_dev_open, .read = buttons_dev_read, .release = buttons_dev_close, }; /* 驱动入口函数 */ static int buttons_dev_init(void) { /* 主设备号设置为0表示由系统自动分配主设备号 */ major = register_chrdev(0, "buttons_dev", &buttons_dev_fops); /* 创建buttondev类 */ buttondev_class = class_create(THIS_MODULE, "buttondev"); /* 在buttondev类下创建buttons设备,供应用程序打开设备*/ buttons_device = device_create(buttondev_class, NULL, MKDEV(major, 0), NULL, "buttons");// return 0; } /* 驱动出口函数 */ static void buttons_dev_exit(void) { unregister_chrdev(major, "buttons_dev"); device_unregister(buttons_device); //卸载类下的设备 class_destroy(buttondev_class); //卸载类 } /* 模块加载和卸载函数的修饰 */ module_init(buttons_dev_init); module_exit(buttons_dev_exit); MODULE_AUTHOR("CLBIAO"); MODULE_DESCRIPTION("Just for Demon"); MODULE_LICENSE("GPL"); //遵循GPL协议
测试程序和前面一个一样。
运行结果:
local_irq_disable();②临界区安安心心地访问资源
local_irq_enable();二、阻塞和非阻塞
app:open("...",O_RDWR|O_NONBLOCK);
非阻塞方式例程序:nonblock.c文件
#include <linux/delay.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <linux/module.h> #include <linux/device.h> //class_create #include <mach/regs-gpio.h> //S3C2410_GPF1 #include <mach/hardware.h> #include <linux/interrupt.h> //wait_event_interruptible #include <linux/fs.h> #include <linux/semaphore.h> /* 定义并初始化等待队列头 */ static DECLARE_WAIT_QUEUE_HEAD(button_waitq); //////////////////////////////////////////////////////////////////////// static DECLARE_MUTEX(button_lock);//(1)获取信号量量并初始化为1 //////////////////////////////////////////////////////////////////////// static struct class *buttondev_class; static struct device *buttons_device; static struct pin_desc{ unsigned int pin; unsigned int key_val; }; static struct pin_desc pins_desc[4] = { {S3C2410_GPF1,0x01}, //S3C2410_GPF1是对GPF1引脚这种“设备”的编号dev_id {S3C2410_GPF4,0x02}, {S3C2410_GPF2,0x03}, {S3C2410_GPF0,0x04}, }; static int ev_press = 0; static unsigned char key_val; int major; /* 中断处理函数 */ static irqreturn_t handle_irq(int irq, void *dev_id) { struct pin_desc *irq_pindesc = (struct pin_desc *)dev_id;// unsigned int pinval; pinval = s3c2410_gpio_getpin(irq_pindesc->pin);//获取按键值:有按键按下返回按键值0 /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */ /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */ if(pinval) { /* 松开 */ key_val = 0x80 | (irq_pindesc->key_val); } else { /* 按下 */ key_val = irq_pindesc->key_val; } ev_press = 1; /* 表示中断已经发生 */ wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */ return IRQ_HANDLED; } static int buttons_dev_open(struct inode * inode, struct file * filp) { ///////////////////////////////////// if (file->f_flags & O_NONBLOCK)//判断是不是非阻塞方式 { if (down_trylock(&button_lock))//尝试获取信号量,没有就走人,不等待! return -EBUSY; } else //是阻塞方式就使用down函数,这样可以进入睡眠 { /* 获取信号量 */ down(&button_lock); } //////////////////////////////////// request_irq(IRQ_EINT1, handle_irq, IRQ_TYPE_EDGE_FALLING, "K1",&pins_desc[0]); request_irq(IRQ_EINT4, handle_irq, IRQ_TYPE_EDGE_FALLING, "K2",&pins_desc[1]); request_irq(IRQ_EINT2, handle_irq, IRQ_TYPE_EDGE_FALLING, "K3",&pins_desc[2]); request_irq(IRQ_EINT0, handle_irq, IRQ_TYPE_EDGE_FALLING, "K4",&pins_desc[3]); return 0; } static int buttons_dev_close(struct inode *inode, struct file *file) { ///////////////////////////////////// up(&button_lock);//(3)释放信号量 //////////////////////////////////// free_irq(IRQ_EINT1,&pins_desc[0]); free_irq(IRQ_EINT4,&pins_desc[1]); free_irq(IRQ_EINT2,&pins_desc[2]); free_irq(IRQ_EINT0,&pins_desc[3]); return 0; } static ssize_t buttons_dev_read(struct file *file, char __user *user, size_t size,loff_t *ppos) { if (size != 1) return -EINVAL; ///////////////////////////////////////////////////////////////// if (file->f_flags & O_NONBLOCK) //读不到按键值立马返回,不睡眠! { if (!ev_press) return -EAGAIN; } else wait_event_interruptible(button_waitq, ev_press);//没有按键就进入休眠 /////////////////////////////////////////////////////////////////// copy_to_user(user, &key_val, 1); /* 将ev_press清零 */ ev_press = 0; return 1; } /* File operations struct for character device */ static const struct file_operations buttons_dev_fops = { .owner = THIS_MODULE, .open = buttons_dev_open, .read = buttons_dev_read, .release = buttons_dev_close, }; /* 驱动入口函数 */ static int buttons_dev_init(void) { /* 主设备号设置为0表示由系统自动分配主设备号 */ major = register_chrdev(0, "buttons_dev", &buttons_dev_fops); /* 创建buttondev类 */ buttondev_class = class_create(THIS_MODULE, "buttondev"); /* 在buttondev类下创建buttons设备,供应用程序打开设备*/ buttons_device = device_create(buttondev_class, NULL, MKDEV(major, 0), NULL, "buttons");// return 0; } /* 驱动出口函数 */ static void buttons_dev_exit(void) { unregister_chrdev(major, "buttons_dev"); device_unregister(buttons_device); //卸载类下的设备 class_destroy(buttondev_class); //卸载类 } /* 模块加载和卸载函数的修饰 */ module_init(buttons_dev_init); module_exit(buttons_dev_exit); MODULE_AUTHOR("CLBIAO"); MODULE_DESCRIPTION("Just for Demon"); MODULE_LICENSE("GPL"); //遵循GPL协议
原文:http://blog.csdn.net/clb1609158506/article/details/44603809