3519AGPIO按键驱动及测试程序


原文链接: 3519AGPIO按键驱动及测试程序

3519AGPIO按键驱动及测试程序3519A文档 外围设备驱动 操作指南.pdf 中介绍了linux下内核态GPIO操作的方法,修改完善后得到下边的代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
// 00 01 02 04 06 07 08 0510 0903 900901
// vup vdow up dow lef rig ok menu back PTT
unsigned int gpio_key_chip []={ 3, 3, 1, 1, 1, 1, 4, 3, 3, 1};
unsigned int gpio_key_offset[]={ 6, 7, 0, 1, 2, 3, 4, 4, 5, 7};
unsigned int gpio_key_num []={ 30, 31, 8, 9, 10, 11, 36, 28, 29, 15};
unsigned int gpio_irq_num []={ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
static DECLARE_WAIT_QUEUE_HEAD(gpio_queue);
static volatile int gpio_data = 0;
static int gpio_dev_id = 0;
spinlock_t irq_lock;

static irqreturn_t gpio_key_irq(int irq,void * dev_id){

int i = 0;
int value = -1;
for(i = 0;i < sizeof(gpio_irq_num) / sizeof(int);++i){
    if(gpio_irq_num[i] == irq && irq != -1){
        value = gpio_get_value(gpio_key_num[i]);
        if(value != -1){
            gpio_data = gpio_key_num[i] + (value == 0 ? 0x1000 : 0x2000);
        }
        break;
    }
}
printk("func[%s %d] irq:%d value:%d data:%x\n",__FUNCTION__,__LINE__,irq,value,gpio_data);
wake_up_interruptible(&gpio_queue);
return IRQ_HANDLED;

}

static int gpio_key_read(struct file * file,char __user * buff,size_t count,loff_t * offp){

int size = -1;
int data = gpio_data;
if(!gpio_data){
    if(file->f_flags & O_NONBLOCK){
        return -EAGAIN;
    }else{
        wait_event_interruptible(gpio_queue,gpio_data);
    }
}
if(copy_to_user(buff,&data,sizeof(gpio_data)) == 0){
    size = sizeof(gpio_data);
}
printk("func[%s %d] size:%d data:%x\n",__FUNCTION__,__LINE__,size,gpio_data);
gpio_data = 0;
return size;

}

static unsigned int gpio_key_poll(struct file * file,struct poll_table_struct * wait){

unsigned int mask = 0;
poll_wait(file,&gpio_queue,wait);
if(gpio_data){
    mask |= POLLIN | POLLRDNORM;
}
return mask;

}

static int gpio_key_open(struct inode * inode,struct file * file){

int i = 0;
int irq_num;
printk("\nfunc[%s %d]\n",__FUNCTION__,__LINE__);
for(i = 0;i < sizeof(gpio_key_num) / sizeof(int);++i){
    if(gpio_request(gpio_key_num[i],NULL)){
        printk("func[%s %d] request gpio%d_%d failed.\n",__FUNCTION__,__LINE__,gpio_key_chip[i],gpio_key_offset[i]);
        continue;
    }
    if(gpio_direction_input(gpio_key_num[i])){
        printk("func[%s %d] gpio%d_%d set_input failed.\n",__FUNCTION__,__LINE__,gpio_key_chip[i],gpio_key_offset[i]);
        gpio_free(gpio_key_num[i]);
        continue;
    }
    irq_num = gpio_to_irq(gpio_key_num[i]);
    if(request_irq(irq_num,gpio_key_irq,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED,"gpio_key_irq",&gpio_dev_id)){
        printk("func[%s %d] gpio%d_%d request_irq:%d failed.\n",__FUNCTION__,__LINE__,gpio_key_chip[i],gpio_key_offset[i],irq_num);
        gpio_free(gpio_key_num[i]);
        continue;
    }
    gpio_irq_num[i] = irq_num;
    printk("func[%s %d] gpio%d_%d request_irq:%d success.\n",__FUNCTION__,__LINE__,gpio_key_chip[i],gpio_key_offset[i],irq_num);
}
return 0;

}

static int gpio_key_close(struct inode * inode,struct file * file){

int i = 0;
for(i = 0;i < sizeof(gpio_key_num) / sizeof(int);++i){
    unsigned long flags = 0;
    spin_lock_irqsave(&irq_lock,flags);
    free_irq(gpio_to_irq(gpio_key_num[i]),&gpio_dev_id);
    spin_unlock_irqrestore(&irq_lock,flags);
    printk("func[%s %d] free gpio%d_%d\n",__FUNCTION__,__LINE__,gpio_key_chip[i],gpio_key_offset[i]);

    gpio_free(gpio_key_num[i]);
    gpio_irq_num[i] = -1;
}
printk("func[%s %d]\n\n",__FUNCTION__,__LINE__);

return 0;

}

static struct file_operations dev_fops = {

.owner = THIS_MODULE,
.open = gpio_key_open,
.release = gpio_key_close,
.read = gpio_key_read,
.poll = gpio_key_poll

};

static struct miscdevice dev_misc = {

.minor = MISC_DYNAMIC_MINOR,
.name = "gpio_irq",
.fops = &dev_fops

};

static int __init gpio_key_init(void){

if(misc_register(&dev_misc)){
    printk("func[%s %d] init failed.\n",__FUNCTION__,__LINE__);
    return -1;
}
printk("func[%s %d] init success.\n",__FUNCTION__,__LINE__);
spin_lock_init(&irq_lock);
return 0;

}

static void __exit gpio_key_exit(void){

misc_deregister(&dev_misc);
printk("func[%s %d]\n",__FUNCTION__,__LINE__);

}

module_init(gpio_key_init);
module_exit(gpio_key_exit);

MODULE_DESCRIPTION("gpio key driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("yang");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
Makefile

obj-m := button.o
export ARCH=arm
export CROSS_COMPILE=arm-himix200-linux-
###KERDIR := /home/work/Hisi/Hi3536C/Hi3536CV100_SDK_V2.0.4.0/package/osdrv/opensource/kernel/linux-3.18.y
###KERDIR := /home/work/Hisi/Hi3536CV100_SDK_V2.0.4.0/osdrv/opensource/kernel/linux-3.18.y
KERDIR := /home/work/Hisi/Hi3519AV100_SDK_V2.0.1.0/osdrv/opensource/kernel/linux-4.9.y-smp/
CURDIR := $(shell pwd)
all:

    make -C $(KERDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-himix200-linux-

clean:

    rm -f *.ko *.o *.mod.o *.mod.c *.symvers

1
2
3
4
5
6
7
8
9
10
11
测试程序:使用poll异步读写驱动映射文件

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
int main(int argc, char *argv[]){
    char buf[32] = {0};
    int code[] = { 30+0x1000, 31+0x1000, 8+0x1000, 9+0x1000, 10+0x1000,
                         11+0x1000, 36+0x1000, 28+0x1000, 29+0x1000, 15+0x1000,
                         30+0x2000, 31+0x2000, 8+0x2000, 9+0x2000, 10+0x2000,
                         11+0x2000, 36+0x2000, 28+0x2000, 29+0x2000, 15+0x2000};
    char * key[] = {"vup press","vdown press","up press","down press","left press",
                    "right press","ok press","menu press","back press","PTT press",
                    "vup release","vdown release","up release","down release","left release",
                    "right release","ok release","menu release","back release","PTT release"};
    struct pollfd * pollfd = (struct pollfd *)malloc(sizeof(struct pollfd));
    if(pollfd){
        pollfd->fd = open("/dev/gpio_irq",O_RDONLY);
        if(pollfd->fd >= 0){
            pollfd->events = POLLIN;
            while(1){
                if(poll(pollfd,1,-1) > 0 && pollfd->revents & POLLIN){
                    int count = read(pollfd->fd,buf,32);
                    if(count == sizeof(int)){
                        int i = 0;
                        for(i = 0;i < sizeof(code) / sizeof(int);++i){
                            if(code[i] == *(int *)buf){
                                break;
                            }
                        }
                        if(i < sizeof(code) / sizeof(int)){
                            printf("key %s ,buf:%x\n",key[i],*(int *)buf);
                        }else{
                            printf("key not find, count:%d buf:%x\n",count,*(int *)buf);
                        }
                    }else{
                        printf("read count:%d buf:%x size > 4\n",count,buf);
                    }
                }
            }
            close(pollfd->fd);
        }else{
            printf("pollfd open failed.fd:%d\n",pollfd->fd);
        }
        free(pollfd);
    }else{
        printf("pollfd malloc failed.\n");
    }
    printf("exit.\n");
    return 0;
}

使用gcc交叉编译即可:

arm-himix200-linux-gcc test.c -o test
————————————————
版权声明:本文为CSDN博主「yangyang031213」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yangyang031213/article/details/103729771

`