中断

来源:互联网 发布:汉王全屏幕软件下载 编辑:程序博客网 时间:2024/05/18 16:35

驱动层

#include <linux/kernel.h>#include <linux/module.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/kdev_t.h>#include <linux/device.h>#include <linux/io.h>#include <linux/uaccess.h>#include <linux/export.h>#include <linux/types.h>#include <linux/gpio.h>#include <linux/interrupt.h>#define GPM4CON 0x110002E0volatile unsigned long *baseaddr = 0;#define rGPM4CON (*((volatile unsigned long *)(baseaddr + 0)))#define rGPM4DAT (*((volatile unsigned long *)(baseaddr + 1)))#define MYKEY_MAJOR 0#define MYKEY_NAME "mykey"#define MYKEY_DRVNUM 1#define MYKEY_NUM 4dev_t mykey_devt;       //设备号int mykey_major;struct class *mykey_class;      //设备结构体struct cdev *mykey;             //设备驱动核心结构char led_status[MYKEY_NUM]={-1,-1,-1,-1};struct mykey{    long gpio;    int num;    char name[10];    int irq;};struct mykey mykeys[4]={{EXYNOS4_GPX3(2),0,"KEY0"},{EXYNOS4_GPX3(3),1,"KEY1"},{EXYNOS4_GPX3(4),2,"KEY2"},{EXYNOS4_GPX3(5),3,"KEY3"},};char key_status[4]={1,1,1,1};loff_t key_lseek (struct file *fp, loff_t off, int whence){    loff_t newoff=0;    switch(whence)    {        case SEEK_SET:            newoff=off;            break;        case SEEK_CUR:            newoff = fp->f_pos+off;            break;        case SEEK_END:            newoff = 4 + off;        default:            return -EINVAL;    }    if(newoff<0)        newoff = 0;    else if(newoff>4)        newoff = 4;    fp->f_pos=newoff;    return newoff;}ssize_t key_read (struct file *fp, char __user *buf, size_t size, loff_t *off){ /*   int i=0;    unsigned long ret;    if(*off>4)        return -EINVAL;    if(*off+size>4)        size = 4-*off;    for(i=0;i<MYKEY_NUM;i++)        key_status[i]= !(rGPM4DAT&(0x1<<i));    ret = copy_to_user(buf,&key_status[*off],size);    *off = *off+size;    printk("key_read is calkey\n");    return 0;*/     if(copy_to_user(buf,key_status,4))     {         return -EINVAL;     }     //printk("mykey_read is called\n");     return 0;   }  ssize_t key_write (struct file *fp, const char __user *buf, size_t size, loff_t *off){    int i;    unsigned long temp;    if(*off>4)        return -EINVAL;    if(*off + size >4)        size = 4 - *off;    temp = copy_from_user(&key_status[*off],buf,size);    for(i=0;i<MYKEY_NUM;i++)    {        if(key_status[i] == 0)            rGPM4DAT |= (0x1<<i);        else if(key_status[i] == 1)            rGPM4DAT &= ~(0x1<<i);        else            return -EINVAL;    }    *off = *off + size;    printk("key_write is calkey \n");    return 0;}   int key_open (struct inode *node, struct file *fp){    int i=0;    fp->private_data =(void *) MINOR(node->i_rdev);    rGPM4CON &= ~(0xffff);    rGPM4CON |= (0x1111);    for(i=0;i<MYKEY_NUM;i++)    {        key_status[i] = !(rGPM4DAT&(0x1<<i));    }    printk("key_open is calkey \n");    return 0;}int key_close (struct inode *node, struct file *fp){    printk("key_close is calkey \n");    return 0;}long key_ioctl(struct file *fp, unsigned int cmd, unsigned long arg){    int i=0;    if(_IOC_TYPE(cmd) != 'x')        return -EINVAL;    switch (_IOC_DIR(cmd))    {        case _IOC_READ:            for(i=0;i<MYKEY_NUM;i++)            {                key_status[i] =! (rGPM4DAT&(0x1<<i));            }            if(copy_to_user((long*)arg,key_status,4))                return -EINVAL;            break;        case  _IOC_WRITE:            if(_IOC_NR(cmd)==0)                rGPM4DAT |= (0x1<<arg);            else if(_IOC_NR(cmd) == 1)                rGPM4DAT &= ~(0x1<<arg);            else                return -EINVAL;            break;        case (_IOC_WRITE|_IOC_READ):        {            for(i=0;i<MYKEY_NUM;i++)                key_status[i]=! (rGPM4DAT&(0x1<<i));            switch (_IOC_NR(cmd))            {                case 0:                    rGPM4DAT |= (0x1<<*((int *)arg));                    break;                case 1:                    rGPM4DAT &= ~(0x1<<*((int *)arg));                    break;                default :                    return -EINVAL;                    break;            }            if(copy_to_user((long*)arg,key_status,MYKEY_NUM))                return -EINVAL;            break;        }        case _IOC_NONE:            break;        default:            break;    }    return 0;}struct file_operations key_fops={    .owner=THIS_MODULE,    .open =key_open,    .release = key_close,    .read=key_read,    .write = key_write,    .unlocked_ioctl = key_ioctl,    .llseek = key_lseek,};irqreturn_t mykey_handler(int irq,void *dev){    struct mykey *tmp = (struct mykey *)dev;    key_status[tmp->num] = gpio_get_value(tmp->gpio);    if(key_status[tmp->num])        rGPM4DAT &= ~(0x1<<tmp->num);    else        rGPM4DAT |= (0x1<<tmp->num);    return IRQ_HANDLED;}static int __init mykey_init(void){    int i=0;#if MYKEY_MAJOR    mykey_major = MYKEY_MAJOR;    mykey_devt = MKDEV(mykey_major,0);    if(register_chrdev_region(mykey_devt,MYKEY_DRVNUM,MYKEY_NAME))#else    if(alloc_chrdev_region(&mykey_devt,0,MYKEY_DRVNUM,MYKEY_NAME))#endif    {        printk("注册失败\n");        return -EBUSY;    }    mykey = cdev_alloc();    cdev_init(mykey,&key_fops);    if(cdev_add(mykey,mykey_devt,MYKEY_DRVNUM))        {        printk("注册成功\n");        return -EBUSY;    }    printk("注册成功\n");    mykey_class = class_create(THIS_MODULE,MYKEY_NAME);    device_create(mykey_class,NULL,mykey_devt,NULL,"%s",MYKEY_NAME);   baseaddr = ioremap(GPM4CON, 8);    for(i=0;i<MYKEY_NUM;i++)    {    //获取中断号        mykeys[i].irq = gpio_to_irq(mykeys[i].gpio);    ///注册中断        if(request_irq(mykeys[i].irq, mykey_handler,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING|IRQF_SHARED,mykeys[i].name,(void*)&mykeys[i]))            goto REQUTEST_IRQ_FAILLED;    }    return 0;REQUTEST_IRQ_FAILLED:    for(--i;i>=0;i--)    {    //使能中断        disable_irq(mykeys[i].irq);    //注销中断        free_irq(mykeys[i].irq,(void *)&mykeys[i]);    }    return -EINVAL;}static void __exit mykey_exit(void){    int i;    iounmap(baseaddr);    for(i=0;i<MYKEY_NUM;i++)    {        disable_irq(mykeys[i].irq);        free_irq(mykeys[i].irq,(void *)&mykeys[i]);    }    device_destroy(mykey_class, mykey_devt);    class_destroy(mykey_class);    cdev_del(mykey);    unregister_chrdev_region(mykey_devt,MYKEY_DRVNUM);    printk("注销成功\n");}module_init(mykey_init);module_exit(mykey_exit);MODULE_LICENSE("GPL");

应用层

#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>char key_oldstatus[4]={-1,-1,-1,-1};char key_newstatus[4]={-1,-1,-1,-1};void print(int fd){    int i=0;    read(fd,key_newstatus,4);    for(i=0;i<4;i++)    {        if(key_oldstatus[i] !=key_newstatus[i])        {            printf("key%d:%s\n",i,key_newstatus[i]?"up":"down");            key_oldstatus[i] = key_newstatus[i];        }    }}int main(int argc,char *argv[]){    int fd = open(argv[1],O_RDWR);    if(fd == -1)    {        printf("打开失败\n");        return 0;    }    read(fd,key_oldstatus,4);    while(1)        print(fd);    close(fd);    return 0;}
原创粉丝点击