Linux驱动-中断实验

**

驱动程序:

**

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>

#include <linux/delay.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of_irq.h>

#define KEY_NUM     1
#define KEY0VALUE   0x01
#define KEY0INVA    0XFF
typedef struct irq_keydesc ysy;

/*key结构体*/
struct irq_keydesc{
    int gpio;       /*io编号*/
    int irqnum;     /*中断号*/
    unsigned char value;    /*键值*/
    char name[10];       /*名字*/
    irqreturn_t (*hander)(int , void *);
};
struct imx6uirq_dev{
    dev_t devid;
    int major;
    int minor;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct device_node  *nd;
    struct irq_keydesc irqkey[KEY_NUM];
    struct timer_list timer;
    atomic_t keyvalue;
    atomic_t releasekey;
};

struct imx6uirq_dev imx6uirq;
#define imx6uirq_count 1
#define imx6uirq_name "imx6uirq"

static int imx6uirq_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &imx6uirq;


    return 0;
}

static int imx6uirq_release(struct inode *inode, struct file *filp)
{
    //struct imx6uirq_dev *dev = filp->private_data;

    return 0;
}
static ssize_t imx6uirq_write(struct file *filp, const char __user *buf,
			 size_t count, loff_t *ppos)
{

    return 0;
}
ssize_t imx6uirq_read(struct file *filp, char __user *buf, size_t count , loff_t *ppos)
{
    int ret = 0;
    unsigned int keyvalue;
    unsigned int releasekey;
    struct imx6uirq_dev *dev = filp->private_data;
    keyvalue = atomic_read(&dev->keyvalue);
    releasekey = atomic_read(&dev->releasekey);
    if(releasekey) {
        if(keyvalue & 0x80) {
            keyvalue &= ~0x80;
            ret = copy_to_user(buf, &keyvalue, sizeof(keyvalue));
        } else {
            goto data_error;
        }
    } else {
        goto data_error;
    }
    atomic_set(&dev->releasekey, 0);
    return ret;
data_error:
    return -EINVAL;
    
}
static const struct file_operations imx6uirq_fops = {
    .owner = THIS_MODULE,
	.write = imx6uirq_write ,
	.open = imx6uirq_open,
    .read = imx6uirq_read,
	.release = imx6uirq_release,
};
static irqreturn_t key0_irq_hander(int irq, void *dev_id)
{   
    struct imx6uirq_dev *dev = dev_id;
    dev->timer.data = (unsigned long)dev_id;

    mod_timer(&dev->timer, jiffies + msecs_to_jiffies(15));

#if 0
    value = gpio_get_value(dev->irqkey[0].gpio);
    if(value == 0) {
        printk("key0 is press!\r\n");
    } else if(value == 1) {
        printk("key0 is release!\r\n");
    }
#endif 
    return IRQ_HANDLED;
}
static void timer_function(unsigned long arg)
{
    int value = 0;
    struct imx6uirq_dev *dev =(struct imx6uirq_dev *)arg;
    value = gpio_get_value(dev->irqkey[0].gpio);
    if(value == 0) {
        atomic_set(&imx6uirq.keyvalue, dev->irqkey[0].value);
       // printk("key0 is press!\r\n");
    } else if(value == 1) {
        atomic_set(&imx6uirq.keyvalue, 0x80 | (dev->irqkey[0].value));
        atomic_set(&imx6uirq.releasekey, 1);

       // printk("key0 is release!\r\n");
    }

}
static int key_io_init(struct imx6uirq_dev *dev)
{
    int ret = 0;
    int i =0 ;
    /*按键初始化*/
    dev->nd = of_find_node_by_path("/key");
    if(dev->nd == NULL) {
        ret =-EINVAL;
        goto fail_nd;
    }
    for(i=0; i<KEY_NUM; i++) {
        dev->irqkey[i].gpio = of_get_named_gpio(dev->nd, "key-gpios", 0);
    }
    printk("gpio num = %d\r\n", dev->irqkey[0].gpio);
    for(i=0; i<KEY_NUM; i++) {
        memset(dev->irqkey[i].name, 0, sizeof(dev->irqkey[i].name));
        sprintf(dev->irqkey[i].name, "KEY%d", i);
        gpio_request(dev->irqkey[i].gpio, dev->irqkey[i].name);
        gpio_direction_input(dev->irqkey[i].gpio);

        dev->irqkey[i].irqnum = gpio_to_irq(dev->irqkey[i].gpio);   /*获取中断号*/
 //       dev->irqkey[i].irqnum = irq_of_parse_and_map(dev->irqkey[i].gpio, i);
        printk("irq num = %d\r\n", dev->irqkey[i].irqnum);
    }
    dev->irqkey[0].hander = key0_irq_hander;
    dev->irqkey[0].value = KEY0VALUE;
    /*按键中断初始化*/

    for(i=0; i<KEY_NUM; i++) {
        ret = request_irq(dev->irqkey[i].irqnum, dev->irqkey[i].hander, 
                        IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING, dev->irqkey[i].name, &imx6uirq);
        
        if(ret) {
        printk("faile irq num = %d\r\n", dev->irqkey[i].irqnum);
        goto fail_irq_request;
      }
    }
    /*初始化定时器*/
    init_timer(&imx6uirq.timer);
    imx6uirq.timer.function = timer_function;


    return 0;
fail_irq_request:
    for(i=0; i<KEY_NUM; i++) {
        gpio_free(dev->irqkey[i].gpio);
    }
fail_nd:
    return ret;

}
static int __init imx6uirq_init(void)
{
    int ret = 0;
    imx6uirq.major = 0;
    if(imx6uirq.major) {
        imx6uirq.devid = MKDEV(imx6uirq.major,0);
        ret = register_chrdev_region(imx6uirq.devid, imx6uirq_count, imx6uirq_name);
    } else {
        ret = alloc_chrdev_region(&imx6uirq.devid, 0, imx6uirq_count, imx6uirq_name);
        imx6uirq.major = MAJOR(imx6uirq.devid);
        imx6uirq.minor = MINOR(imx6uirq.devid);
    }
    if(ret < 0) {
        goto fail_devid;
    }
    printk("major = %d,minor = %d\r\n",imx6uirq.major,imx6uirq.minor);

    imx6uirq.cdev.owner = THIS_MODULE;

    cdev_init(&imx6uirq.cdev, &imx6uirq_fops);
    ret = cdev_add(&imx6uirq.cdev, imx6uirq.devid,  imx6uirq_count);
    if(ret < 0) {
        goto fail_cdev;
    }

    imx6uirq.class = class_create (THIS_MODULE, imx6uirq_name);
    if (IS_ERR(imx6uirq.class)) {
		ret = PTR_ERR(imx6uirq.class);
		goto fail_class;
	}
    imx6uirq.device = device_create(imx6uirq.class, NULL, imx6uirq.devid, NULL,imx6uirq_name);
    if (IS_ERR(imx6uirq.device)) {
		ret = PTR_ERR(imx6uirq.device);
		goto fail_device;
	}
    ret =key_io_init(&imx6uirq);
    if(ret < 0) {
        goto fail_keyinit;
    }
    /*初始化原子变量*/
    atomic_set(&imx6uirq.keyvalue, KEY0INVA);
    atomic_set(&imx6uirq.releasekey, 0);
    return 0;
fail_keyinit:
fail_device:
    class_destroy(imx6uirq.class);
fail_class:
    cdev_del(&imx6uirq.cdev);
fail_cdev:
    unregister_chrdev_region(imx6uirq.devid, imx6uirq_count);
fail_devid:
    return ret;
}

static void __exit imx6uirq_exit(void)
{
    int i = 0;
    /*释放中断*/
    for(i=0; i<KEY_NUM; i++) {
        free_irq(imx6uirq.irqkey[i].irqnum, &imx6uirq);;
    }
    /*释放io*/
    for(i=0; i<KEY_NUM; i++) {
        gpio_free(imx6uirq.irqkey[i].gpio);
    }
    del_timer_sync(&imx6uirq.timer);
    device_destroy(imx6uirq.class, imx6uirq.devid);
    class_destroy(imx6uirq.class);
    cdev_del(&imx6uirq.cdev);
    unregister_chrdev_region(imx6uirq.devid, imx6uirq_count);
}

module_init(imx6uirq_init);
module_exit(imx6uirq_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("YSY");

应用程序:

在这里插#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>



int main(int argc,char *argv[])
{
    int fd;
    int ret = 0;
    int   retvalue;
    char *filename;
    filename = argv[1];
    unsigned char datebuf[1];
    if(argc != 2)
    {
        printf("Error usage!\r\n");
        return -1;
    }
    fd=open(filename,O_RDWR);
    if(fd<0)
    {
        printf("file %s open fialed !\r\n",filename);
        return -1;
    }
    /*循环读取*/
    while(1) {
        ret = read(fd, &retvalue, sizeof(retvalue));
        if(ret < 0) {

        } else {
            if(retvalue) {
                 printf("KEY0 Press retvalue = %d\r\n",retvalue);
             }
        }
    }
    close(fd);
    return 0;
}

**

tasklet

**
tasklet 是利用软中断来实现的另外一种下半部机制,在软中断和 tasklet 之间.

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>

#include <linux/delay.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of_irq.h>

#define KEY_NUM     1
#define KEY0VALUE   0x01
#define KEY0INVA    0XFF
/*key结构体*/
struct irq_keydesc{
    int gpio;       /*io编号*/
    int irqnum;     /*中断号*/
    unsigned char value;    /*键值*/
    char name[10];       /*名字*/
    irqreturn_t (*hander)(int , void *);
    struct tasklet_struct tasklet;

};

struct imx6uirq_dev{
    dev_t devid;
    int major;
    int minor;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct device_node  *nd;
    struct irq_keydesc irqkey[KEY_NUM];
    struct timer_list timer;
    atomic_t keyvalue;
    atomic_t releasekey;
};

struct imx6uirq_dev imx6uirq;
#define imx6uirq_count 1
#define imx6uirq_name "imx6uirq"

static int imx6uirq_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &imx6uirq;


    return 0;
}

static int imx6uirq_release(struct inode *inode, struct file *filp)
{
    //struct imx6uirq_dev *dev = filp->private_data;

    return 0;
}
static ssize_t imx6uirq_write(struct file *filp, const char __user *buf,
			 size_t count, loff_t *ppos)
{

    return 0;
}
ssize_t imx6uirq_read(struct file *filp, char __user *buf, size_t count , loff_t *ppos)
{
    int ret = 0;
    unsigned int keyvalue;
    unsigned int releasekey;
    struct imx6uirq_dev *dev = filp->private_data;
    keyvalue = atomic_read(&dev->keyvalue);
    releasekey = atomic_read(&dev->releasekey);
    if(releasekey) {
        if(keyvalue & 0x80) {
            keyvalue &= ~0x80;
            ret = copy_to_user(buf, &keyvalue, sizeof(keyvalue));
        } else {
            goto data_error;
        }
    } else {
        goto data_error;
    }
    atomic_set(&dev->releasekey, 0);
    return ret;
data_error:
    return -EINVAL;
    
}

static const struct file_operations imx6uirq_fops = {
    .owner = THIS_MODULE,
	.write = imx6uirq_write ,
	.open = imx6uirq_open,
    .read = imx6uirq_read,
	.release = imx6uirq_release,
};
static irqreturn_t key0_irq_hander(int irq, void *dev_id)
{   
    struct imx6uirq_dev *dev = dev_id;
    tasklet_schedule(&dev->irqkey[0].tasklet);
#if 0
    dev->timer.data = (unsigned long)dev_id;

    mod_timer(&dev->timer, jiffies + msecs_to_jiffies(15));

    value = gpio_get_value(dev->irqkey[0].gpio);
    if(value == 0) {
        printk("key0 is press!\r\n");
    } else if(value == 1) {
        printk("key0 is release!\r\n");
    }
#endif 
    return IRQ_HANDLED;
}
static void key_tasklet_func(unsigned long data) 
{
    struct imx6uirq_dev *dev = (struct imx6uirq_dev *)data;
    dev->timer.data = (unsigned long)data;
    mod_timer(&dev->timer, jiffies + msecs_to_jiffies(15));

}
static void timer_function(unsigned long arg)
{
    int value = 0;
    struct imx6uirq_dev *dev =(struct imx6uirq_dev *)arg;
    value = gpio_get_value(dev->irqkey[0].gpio);
    if(value == 0) {
        atomic_set(&imx6uirq.keyvalue, dev->irqkey[0].value);
       // printk("key0 is press!\r\n");
    } else if(value == 1) {
        atomic_set(&imx6uirq.keyvalue, 0x80 | (dev->irqkey[0].value));
        atomic_set(&imx6uirq.releasekey, 1);

       // printk("key0 is release!\r\n");
    }

}
static int key_io_init(struct imx6uirq_dev *dev)
{
    int ret = 0;
    int i =0 ;
    /*按键初始化*/
    dev->nd = of_find_node_by_path("/key");
    if(dev->nd == NULL) {
        ret =-EINVAL;
        goto fail_nd;
    }
    for(i=0; i<KEY_NUM; i++) {
        dev->irqkey[i].gpio = of_get_named_gpio(dev->nd, "key-gpios", 0);
    }
    printk("gpio num = %d\r\n", dev->irqkey[0].gpio);
    for(i=0; i<KEY_NUM; i++) {
        memset(dev->irqkey[i].name, 0, sizeof(dev->irqkey[i].name));
        sprintf(dev->irqkey[i].name, "KEY%d", i);
        gpio_request(dev->irqkey[i].gpio, dev->irqkey[i].name);
        gpio_direction_input(dev->irqkey[i].gpio);

        dev->irqkey[i].irqnum = gpio_to_irq(dev->irqkey[i].gpio);   /*获取中断号*/
 //       dev->irqkey[i].irqnum = irq_of_parse_and_map(dev->irqkey[i].gpio, i);
        printk("irq num = %d\r\n", dev->irqkey[i].irqnum);
    }
    dev->irqkey[0].hander = key0_irq_hander;
    dev->irqkey[0].value = KEY0VALUE;
    //dev->irqkey[0].tasklet = key_tasklet_func;
    /*按键中断初始化*/

    for(i=0; i<KEY_NUM; i++) {
        ret = request_irq(dev->irqkey[i].irqnum, dev->irqkey[i].hander, 
                        IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING, dev->irqkey[i].name, &imx6uirq);
        
        if(ret) {
        printk("faile irq num = %d\r\n", dev->irqkey[i].irqnum);
        goto fail_irq_request;
      }
      tasklet_init(&dev->irqkey[0].tasklet, key_tasklet_func, (unsigned long)dev);
    }
    /*初始化定时器*/
    init_timer(&imx6uirq.timer);
    imx6uirq.timer.function = timer_function;


    return 0;
fail_irq_request:
    for(i=0; i<KEY_NUM; i++) {
        gpio_free(dev->irqkey[i].gpio);
    }
fail_nd:
    return ret;

}
static int __init imx6uirq_init(void)
{
    int ret = 0;
    imx6uirq.major = 0;
    if(imx6uirq.major) {
        imx6uirq.devid = MKDEV(imx6uirq.major,0);
        ret = register_chrdev_region(imx6uirq.devid, imx6uirq_count, imx6uirq_name);
    } else {
        ret = alloc_chrdev_region(&imx6uirq.devid, 0, imx6uirq_count, imx6uirq_name);
        imx6uirq.major = MAJOR(imx6uirq.devid);
        imx6uirq.minor = MINOR(imx6uirq.devid);
    }
    if(ret < 0) {
        goto fail_devid;
    }
    printk("major = %d,minor = %d\r\n",imx6uirq.major,imx6uirq.minor);

    imx6uirq.cdev.owner = THIS_MODULE;

    cdev_init(&imx6uirq.cdev, &imx6uirq_fops);
    ret = cdev_add(&imx6uirq.cdev, imx6uirq.devid,  imx6uirq_count);
    if(ret < 0) {
        goto fail_cdev;
    }

    imx6uirq.class = class_create (THIS_MODULE, imx6uirq_name);
    if (IS_ERR(imx6uirq.class)) {
		ret = PTR_ERR(imx6uirq.class);
		goto fail_class;
	}
    imx6uirq.device = device_create(imx6uirq.class, NULL, imx6uirq.devid, NULL,imx6uirq_name);
    if (IS_ERR(imx6uirq.device)) {
		ret = PTR_ERR(imx6uirq.device);
		goto fail_device;
	}
    ret =key_io_init(&imx6uirq);
    if(ret < 0) {
        goto fail_keyinit;
    }
    /*初始化原子变量*/
    atomic_set(&imx6uirq.keyvalue, KEY0INVA);
    atomic_set(&imx6uirq.releasekey, 0);
    return 0;
fail_keyinit:
fail_device:
    class_destroy(imx6uirq.class);
fail_class:
    cdev_del(&imx6uirq.cdev);
fail_cdev:
    unregister_chrdev_region(imx6uirq.devid, imx6uirq_count);
fail_devid:
    return ret;
}

static void __exit imx6uirq_exit(void)
{
    int i = 0;
    /*释放中断*/
    for(i=0; i<KEY_NUM; i++) {
        free_irq(imx6uirq.irqkey[i].irqnum, &imx6uirq);;
    }
    /*释放io*/
    for(i=0; i<KEY_NUM; i++) {
        gpio_free(imx6uirq.irqkey[i].gpio);
    }
    del_timer_sync(&imx6uirq.timer);
    device_destroy(imx6uirq.class, imx6uirq.devid);
    class_destroy(imx6uirq.class);
    cdev_del(&imx6uirq.cdev);
    unregister_chrdev_region(imx6uirq.devid, imx6uirq_count);
}

module_init(imx6uirq_init);
module_exit(imx6uirq_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("YSY");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值