11
#include#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IMX6UIRQ_CNT 1 #define IMX6UIRQ_NAME "noblockio" #define KEY0VALUE 0x01 #define INVAKEY 0xFF #define KEY_NUM 1 struct irq_keydesc{ int gpio; //gpio编号 unsigned int irqnum; //中断号 irqreturn_t (*irq_handler)(int, void*); //中断处理函数 }; //设备结构体 struct imx6uirq_dev{ dev_t devid; struct cdev cdev; struct class *class; struct device *device; int major; int minor; struct device_node *nd; //设备节点 atomic_t keyvalue; //有效的按键值 atomic_t releasekey; //标记是否完成一次完整的按键 struct timer_list timer; //定时器 struct irq_keydesc irq_keydesc[KEY_NUM]; //按键描述数组 wait_queue_head_t r_wait; //等待队列项头 }; struct imx6uirq_dev imx6uirq; static int imx6uirq_open(struct inode *inode, struct file *file) { file->private_data = &imx6uirq; return 0; } ssize_t imx6uirq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { unsigned char keyvalue = 0; unsigned char releasekey = 0; struct imx6uirq_dev *dev = file->private_data; int ret = 0; //定义并初始化一个等待队列项 DECLARE_WAITQUEUE(wait, current); if (atomic_read(&dev->releasekey) == 0) { //按键未按下,将等待队列项添加到等待队列头 add_wait_queue(&dev->r_wait, &wait); __set_current_state(TASK_INTERRUPTIBLE); //任务切换,进入睡眠态 schedule(); if(signal_pending(current)) { ret = -ERESTARTSYS; goto wait_error; } __set_current_state(TASK_RUNNING); //按键按下了,将等待队列项从等待队列头移除 remove_wait_queue(&dev->r_wait, &wait); } keyvalue = atomic_read(&dev->keyvalue); releasekey = atomic_read(&dev->releasekey); if (releasekey) { copy_to_user(buf, &keyvalue, sizeof(keyvalue)); atomic_set(&dev->releasekey, 0); //清除按下标志位 } else { return -EINVAL; } return 0; wait_error: set_current_state(TASK_RUNNING); remove_wait_queue(&dev->r_wait, &wait); return ret; } static imx6uirq_poll(struct file *filp, struct poll_table_struct *wait) { unsigned char keyvalue = 0; unsigned char releasekey = 0; struct imx6uirq_dev *dev = filp->private_data; int ret = 0; poll_wait(filp, &dev->r_wait, wait); if (atomic_read(&dev->releasekey) == 1) //按键按下 { ret = POLLIN | POLLRDNORM; } return ret; } static const struct file_operations imx6uirq_fops = { .owner = THIS_MODULE, .open = imx6uirq_open, .read = imx6uirq_read, .poll = imx6uirq_poll, }; //定时器回调函数 static void timer_function(unsigned long arg) { int value; struct irq_keydesc *keydesc; struct imx6uirq_dev *dev = (struct imx6uirq_dev *)arg; keydesc = &dev->irq_keydesc[0]; value = gpio_get_value(keydesc->gpio); if (value == 0) atomic_set(&dev->keyvalue, value); else { atomic_set(&dev->keyvalue, value); atomic_set(&dev->releasekey, 1); //标记按键松开 } if (atomic_read(&dev->releasekey)) { //按键按下,唤醒等待队列项中的进程 wake_up_interruptible(&dev->r_wait); } } static irqreturn_t key0_irq_handler(int irq, void *dev_id) { int value; struct imx6uirq_dev *dev = (struct imx6uirq_dev *)dev_id; dev->timer.data = (volatile long)dev_id; //启动定时器 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(10)); return IRQ_HANDLED; } static int key_io_init(void) { int ret; //通过节点名字查找节点 imx6uirq.nd = of_find_node_by_name(NULL, "gpiokey"); if (imx6uirq.nd == NULL) { printk("find %s failrn", "gpiokey"); return -EINVAL; } //通过节点获取GPIO编号 imx6uirq.irq_keydesc[0].gpio = of_get_named_gpio(imx6uirq.nd, "key-gpio", 0); if (imx6uirq.irq_keydesc[0].gpio < 0) { printk("get %s failrn", "key-gpio"); return -EINVAL; } //初始化key-gpio ret = gpio_request(imx6uirq.irq_keydesc[0].gpio, "gpio_irq"); if (ret != 0) { printk("request %s failrn", "gpio_irq"); return -EINVAL; } ret = gpio_direction_input(imx6uirq.irq_keydesc[0].gpio); if (ret < 0) { printk("set key status failrn"); return -EINVAL; } //通过节点获取中断号 imx6uirq.irq_keydesc[0].irqnum = irq_of_parse_and_map(imx6uirq.nd, 0); #if 0 //通过GPIO编号获取中断号 imx6uirq.irq_keydesc[0].irqnum = gpio_to_irq(imx6uirq.irq_keydesc[0].gpio); #endif //设置中断处理函数 imx6uirq.irq_keydesc[0].irq_handler = key0_irq_handler; //通过中断号申请中断 ret = request_irq(imx6uirq.irq_keydesc[0].irqnum, imx6uirq.irq_keydesc[0].irq_handler, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, IMX6UIRQ_NAME, &imx6uirq); if (ret < 0) { printk("request irq failrn"); return -EINVAL; } //初始化定时器 init_timer(&imx6uirq.timer); imx6uirq.timer.function = timer_function; } static int __init imx6uirq_init(void) { int ret = 0; int val = 0; //初始化等待队列头 init_waitqueue_head(&imx6uirq.r_wait); //分配设备号 if ( imx6uirq.major) { imx6uirq.devid = MKDEV( imx6uirq.major, 0); register_chrdev_region( imx6uirq.devid, IMX6UIRQ_CNT, IMX6UIRQ_NAME); } else { alloc_chrdev_region(&imx6uirq.devid, 0, IMX6UIRQ_CNT, IMX6UIRQ_NAME); imx6uirq.major = MAJOR(imx6uirq.devid); imx6uirq.minor = MINOR(imx6uirq.devid); } //初始化cdev imx6uirq.cdev.owner = THIS_MODULE; cdev_init(&imx6uirq.cdev, &imx6uirq_fops); //添加cdev cdev_add(&imx6uirq.cdev, imx6uirq.devid, IMX6UIRQ_CNT); //创建类 imx6uirq.class = class_create(THIS_MODULE, IMX6UIRQ_NAME); //创建设备 imx6uirq.device = device_create(imx6uirq.class, NULL, imx6uirq.devid, NULL, IMX6UIRQ_NAME); //按键gpio初始化 key_io_init(); return 0; } static void __exit imx6uirq_exit(void) { //删除定时器 del_timer_sync(&imx6uirq.timer); //释放中断 free_irq(imx6uirq.irq_keydesc[0].irqnum, &imx6uirq); gpio_free(imx6uirq.irq_keydesc[0].gpio); //删除设备 cdev_del(&imx6uirq.cdev); //注销设备号 unregister_chrdev_region(imx6uirq.devid, IMX6UIRQ_CNT); //删除设备的类 device_destroy(imx6uirq.class, imx6uirq.devid); //删除类 class_destroy(imx6uirq.class); printk(" dev exitn"); } module_init( imx6uirq_init); module_exit( imx6uirq_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("ZK");
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include "poll.h"
#define CLOSE_CMD 1
#define OPEN_CMD 2
#define SETPERIOD_CMD 3
int main(int argc, char *argv[])
{
int fd, ret;
char *filename;
unsigned char keyvalue;
struct pollfd fds;
if (argc != 2)
{
printf("Usage:n");
printf("n");
return -1;
}
filename = argv[1];
fd = open(filename, O_RDWR | O_NONBLOCK); //非阻塞访问
if (fd < 0)
{
printf("open file %s failn", filename);
return -1;
}
fds.fd = fd;
fds.events = POLLIN; //监视数据是否可以读取
while (1)
{
ret = poll(&fds, 1, 500); //轮训文件是否可操作,超时时间为500ms
if (ret) //文件可读
{
printf("key is enterrn");
ret = read(fd, &keyvalue, sizeof(keyvalue));
if (ret < 0)
{
}
else
{
if (keyvalue)
printf("key0 value is %d/r/n", keyvalue);
}
}
else if (ret == 0) //超时
{
}
else if (ret < 0) //错误
{
}
}
close(fd);
return ret;
}



