字符设备驱动之Buttons-循环缓冲队列+非阻塞访问
2011-09-14 17:16
357 查看
buttons.c
buttons_test.c
#include <linux/fs.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/ioport.h> #include <linux/pci.h> #include <asm/uaccess.h> #include <asm/io.h> #include <asm/irq.h> #include <linux/interrupt.h> #include <asm/mach/irq.h> #include <asm/arch/regs-gpio.h> static int major = 0; static struct class *cls; /* gpecon 0x56000040 */ /* gpfcon 0x56000050 */ /* gpgcon 0x56000060 */ static volatile unsigned long *gpecon; static volatile unsigned long *gpedat; static volatile unsigned long *gpfcon; static volatile unsigned long *gpfdat; static volatile unsigned long *gpgcon; static volatile unsigned long *gpgdat; struct key_desc { int irq; int pin; char *name; char key_val; }; struct key_desc key_desc[] = { {IRQ_EINT0, S3C2410_GPF0, "K10", 1}, /* 松开: 1, 按下: 0x81 */ {IRQ_EINT2, S3C2410_GPF2, "K7", 2}, /* 松开: 2, 按下: 0x82 */ {IRQ_EINT11, S3C2410_GPG3, "K4", 3}, /* 松开: 3, 按下: 0x83 */ {IRQ_EINT19, S3C2410_GPG11, "K1", 4}, /* 松开: 4, 按下: 0x84 */ }; volatile char key = 0; static wait_queue_head_t button_waitq; #define BUF_LEN 10 static char key_buf[BUF_LEN]; static volatile int r = 0, w = 0; static int isEmpty(void) { return (r == w); } static int isFull(void) { return (r == ((w+1)%BUF_LEN)); } static int putData(char val) { if (isFull()) { return -1; } else { key_buf[w] = val; w = (w+1)%BUF_LEN; return 0; } } static int getData(char *p) { if (isEmpty()) { return -1; } else { *p = key_buf[r]; r = (r+1)%BUF_LEN; return 0; } } static irqreturn_t buttons_irq(int irq, void *dev_id) { struct key_desc *kd = (struct key_desc *)dev_id; int up; char key; /* 确定按键: 哪个按键,按下还是松开 */ up = s3c2410_gpio_getpin(kd->pin); // gpfdat, gpgdat if (up) { key = kd->key_val; } else { key = kd->key_val | 0x80; } // printk("key = 0x%x\n", key); putData(key); /* 唤醒应用程序 */ wake_up_interruptible(&button_waitq); //printk("buttons_irq current %s , pid = %d \n", current->comm, current->pid); return IRQ_HANDLED; } int buttons_open(struct inode *inode, struct file *file) { int i; /* 注册中断 */ for (i = 0; i < 4; i++) { request_irq(key_desc[i].irq, buttons_irq, IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, key_desc[i].name, &key_desc[i]); } /* 设置GPIO为中断引脚 * 设置触发方式 * 使能中断 */ /* 设置KSCAN0(GPE11)为输出引脚,输出0 */ *gpecon &= ~(0x3 << 22); *gpecon |= (1 << 22); *gpedat &= ~(1<<11); return 0; } ssize_t buttons_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { /* 如果没有按键发生, 休眠 */ /* key 等于 0, 才会休眠 * key 非0, 不会休眠 */ // command //printk("current %s , pid = %d before sleep\n", current->comm, current->pid); char key; if (isEmpty() && (file->f_flags & O_NONBLOCK)) return -EAGAIN; wait_event_interruptible(button_waitq, !isEmpty()); //printk("current %s , pid = %d after sleep\n", current->comm, current->pid); /* 被唤醒后, 把按键值返回给用户程序 */ getData(&key); copy_to_user(buf, &key, 1); /* 发生了中断, key=xxx */ //key = 0; return 1; } int buttons_close(struct inode *inode, struct file *file) { int i; for (i = 0; i < 4; i++) { free_irq(key_desc[i].irq, &key_desc[i]); } return 0; } static const struct file_operations buttons_fops = { .owner = THIS_MODULE, .read = buttons_read, .open = buttons_open, /* 设置引脚,申请资源 */ .release = buttons_close, }; int buttons_init(void) { int i; major = register_chrdev(0, "buttons", &buttons_fops); /* sysfs ==> 挂接到/sys */ cls = class_create(THIS_MODULE, "buttons_class"); class_device_create(cls, NULL, MKDEV(major, 0), NULL, "buttons"); // mdev会根据/sys下的这些内容创建/dev/buttons gpecon = ioremap(0x56000040, 4096); gpedat = gpecon + 1; gpfcon = gpecon + 4; gpfdat = gpfcon + 1; gpgcon = gpecon + 8; gpgdat = gpgcon + 1; init_waitqueue_head(&button_waitq); return 0; } void buttons_exit(void) { unregister_chrdev(major, "buttons"); class_device_destroy(cls, MKDEV(major, 0)); class_destroy(cls); iounmap(gpecon); } module_init(buttons_init); module_exit(buttons_exit); MODULE_LICENSE("GPL"); |
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> /* button_test [nonblock] */ int main(int argc, char **argv) { char buf[4]; int fd; int ret; if (argc == 2)/*阻塞、非阻塞访问,由应用程序决定*/ fd = open("/dev/buttons", O_RDONLY | O_NONBLOCK); else fd = open("/dev/buttons", O_RDONLY); if (fd < 0) { printf("can't open /dev/buttons\n"); return -1; } while (1) { ret = read(fd, buf, 1); if (ret == -1) printf("no data\n"); else printf("key = 0x%x\n", buf[0]); } return 0; } |
相关文章推荐
- 字符设备驱动之Buttons-循环缓冲队列
- 字符设备驱动之循环缓冲队列+读写等待
- Linux驱动开发-11、设备阻塞访问-等待队列
- 字符设备驱动之Buttons-等待队列
- 字符设备驱动之Buttons-中断上下部(工作队列-workqueue)
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-按键驱动程序之异步通知机制+原子操作+互斥信号量+阻塞与非阻塞+定时器去抖
- linux高级字符设备驱动之 二 内核等待队列
- Linux应用程序访问字符设备驱动详细过程解析
- Linux 设备驱动--- 阻塞型字符设备驱动 --- O_NONBLOCK --- 非阻塞标志【转】
- Linux应用程序访问字符设备驱动详细过程【转】
- Linux 设备驱动--- 阻塞型字符设备驱动 --- O_NONBLOCK --- 非阻塞标志
- Linux应用程序访问字符设备驱动详细过程解析
- 如何应用条件变量实现eCos字符设备驱动的阻塞读
- 字符驱动之四阻塞IO(等待队列)
- arm 驱动基础:字符设备驱动程序之同步互斥阻塞
- 字符设备驱动--异步通知、同步互斥阻塞
- 字符设备驱动同步之互斥阻塞
- linux字符设备驱动-同步互斥阻塞笔记
- 字符设备驱动之Buttons-异步通知(fasync)
- Linux_设备驱动阻塞/非阻塞IO_等待队列