3519A文档 外围设备驱动 操作指南.pdf 中介绍了linux下内核态GPIO操作的方法,修改完善后得到下边的代码:
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
// 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");
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
测试程序:使用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