一、linux驱动开发-7.3-非阻塞IO实验

本文档展示了Linux内核中中断处理的实现,包括关键结构体定义、中断处理函数、设备驱动注册及中断处理流程。同时,提供了用户空间通过字符设备接口读取中断事件的示例代码,涉及到了中断请求、等待队列、定时器和设备文件操作等概念。
摘要由CSDN通过智能技术生成

11

#include <linux/types.h>

#include <linux/kernel.h>

#include <linux/delay.h>

#include <linux/ide.h>

#include <linux/init.h>

#include <linux/module.h>

#include <linux/errno.h>

#include <linux/gpio.h>

#include <linux/cdev.h>

#include <linux/device.h>

#include <linux/of.h>

#include <linux/of_address.h>

#include <linux/of_gpio.h>

#include <linux/semaphore.h>

#include <linux/timer.h>

#include <linux/of_irq.h>

#include <linux/irq.h>

#include <asm/mach/map.h>

#include <asm/uaccess.h>

#include <asm/io.h>

#include <linux/string.h>

#include <linux/wait.h>

#include <linux/poll.h>



#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 fail\r\n", "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 fail\r\n", "key-gpio");

		return -EINVAL;

	}

	//初始化key-gpio

	ret = gpio_request(imx6uirq.irq_keydesc[0].gpio, "gpio_irq");

	if (ret != 0)

	{

		printk("request %s fail\r\n", "gpio_irq");

		return -EINVAL;

	}

	ret = gpio_direction_input(imx6uirq.irq_keydesc[0].gpio);

	if (ret < 0)

	{

		printk("set key status fail\r\n");

		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 fail\r\n");

		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 exit\n");

}



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 fail\n", filename);
        return -1;
    }

    fds.fd = fd;
    fds.events = POLLIN;    //监视数据是否可以读取

    while (1)
    {
        ret = poll(&fds, 1, 500);    //轮训文件是否可操作,超时时间为500ms
        if (ret)    //文件可读
        {
            printf("key is enter\r\n");
            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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值