GPIO中断如何传递到应用程序
本帖最后由 Icefly 于 2017-12-15 18:01 编辑朋友们好,我使用rk3399的板子学习GPIO驱动,跑了官网GPIO驱动的例子(http://wiki.t-firefly.com/index.php/Firefly-RK3399/GPIO),能够在内核log里看到相关的中断信息;{:4_225:}
接着我想将该中断信息传递给上层应用程序,在应用程序里做出响应,不知道应该怎么做,新手上路请诸位多多指教。{:4_141:}
从网上了解的的信息来看,有说用异步通信的,也有说使用input框架的,都看不太明白,如果能给个示例代码那最好啦。
参考网上的例子写了个用netlink实现用户空间和内核空间通信的例子,代码大致如下
gpio-firefly.c
/** Driver for pwm demo on Firefly board.** Copyright (C) 2016, Zhongshan T-chip Intelligent Technology Co.,ltd.* Copyright 2006JC.Lin** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License version 2 as* published by the Free Software Foundation.*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/types.h>
#include <net/sock.h>
#include <linux/netlink.h>
/*
#define NETLINK_TEST 16
struct sock *nl_sk = NULL;
EXPORT_SYMBOL_GPL(nl_sk);
*/
#define NETLINK_USER 22
#define USER_MSG (NETLINK_USER+1)
#define USER_PORT 50
static struct sock *netlinkfd = NULL;
static void *netlinkdata = NULL;
static int netlinkdatalen = 0;
static struct workqueue_struct *queue=NULL;
static struct work_struct my_wq;
static void my_wq_func(struct work_struct *data);
struct firefly_gpio_info
{
//struct device *dev;
//long firefly_param;
int firefly_gpio;
int gpio_enable_value;
int firefly_irq_gpio;
int firefly_irq;
int firefly_irq_mode;
};
/*
void nl_data_ready(struct sk_buff *__skb)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
u32 pid;
int rc;
int len = NLMSG_SPACE(1200);
char str;
printk("new_link: data is ready to read.\n");
skb = skb_get(__skb);
if(skb->len >= NLMSG_SPACE(0))
{
nlh = nlmsg_hdr(skb);
printk("net_link: recv %s.\n", (char *)NLMSG_DATA(nlh));
memcpy(str, NLMSG_DATA(nlh), sizeof(str));
pid = nlh->nlmsg_pid; //pid of sending process
printk("net_link: pid is %d\n", pid);
kfree_skb(skb);
skb = alloc_skb(len, GFP_ATOMIC);
if(!skb)
{
printk(KERN_ERR "net_link: allocate failed.\n");
return;
}
nlh = nlmsg_put(skb, 0, 0, 0, 1200, 0);
NETLINK_CB(skb).pid = 0; //from kernel
memcpy(NLMSG_DATA(nlh), str, sizeof(str));
printk("net_link: going to send.\n");
rc = netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);
if(rc < 0)
{
printk(KERN_ERR "net_link: can not unicast skb (%d)\n", rc);
}
printk("net_link: send is ok.\n");
}
return;
}
static int test_netlink(void)
{
nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 0, nl_data_ready, NULL, THIS_MODULE);
if(!nl_sk)
{
printk(KERN_ERR "net_link: Cannot create netlink socket.\n");
return -EIO;
}
printk("net_link: create socket ok.\n");
return 0;
}
*/
int send_msg(int8_t *pbuf, uint16_t len)
{
struct sk_buff *nl_skb;
struct nlmsghdr *nlh;
int ret;
nl_skb = nlmsg_new(len, GFP_ATOMIC);
if(!nl_skb)
{
printk("netlink: netlink_alloc_skb error\n");
return -1;
}
nlh = nlmsg_put(nl_skb, 0, 0, USER_MSG, len, 0);
if(nlh == NULL)
{
printk("netlink: nlmsg_put() error\n");
nlmsg_free(nl_skb);
return -1;
}
memcpy(nlmsg_data(nlh), pbuf, len);
ret = netlink_unicast(netlinkfd, nl_skb, USER_PORT, MSG_DONTWAIT);
return ret;
}
static void recv_cb(struct sk_buff *skb)
{
struct nlmsghdr *nlh = NULL;
void *data = NULL;
printk("netlink: skb->len = %u\n", skb->len);
if(skb->len >= nlmsg_total_size(0))
{
nlh = nlmsg_hdr(skb);
data = NLMSG_DATA(nlh);
if(data)
{
printk("netlink: kernel receive data: %s\n", (int8_t *)data);
netlinkdata = data;
netlinkdatalen = nlmsg_len(nlh);
//send_msg(data, nlmsg_len(nlh));
}
}
}
struct netlink_kernel_cfg cfg =
{
.input = recv_cb,
};
static int test_netlink(void)
{
netlinkfd = netlink_kernel_create(&init_net, USER_MSG, &cfg);
if(!netlinkfd)
{
printk(KERN_ERR "netlink: can not create a netlink socket!\n");
return -1;
}
printk("netlink: create socket ok.\n");
return 0;
}
//static struct fasync_struct *gpio_irq_async;
static void my_wq_func(struct work_struct *data)
{
printk("Enter firefly gpio irq my_wq_func!\n");
//test_netlink();
if (netlinkdatalen > 0)
{
send_msg(netlinkdata, netlinkdatalen);
netlinkdatalen = 0;
printk("firefly netlink send_msg\n");
}
printk("Exit firefly gpio irq my_wq_func!\n");
}
static irqreturn_t firefly_gpio_irq(int irq, void *dev_id)
{
printk("Enter firefly gpio irq test program!\n");
//kill_fasync(&gpio_irq_async, SIGIO,POLL_IN);
schedule_work(&my_wq);
return IRQ_HANDLED;
}
/*
static int firefly_gpio_fasync(int fd, struct file *filp, int mode)
{
//struct scull_pipe *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &gpio_irq_async);
}*/
/*
static ssize_t gpio_firefly_attr_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct firefly_gpio_info *gpio_info = dev_get_drvdata(dev);
int len;
len = sprintf(buf, "%ld\n", gpio_info->firefly_param);
if (len < 0)
{
dev_err(dev, "firefly_gpio_infogpio_firefly_attr_show: Invalid sprintf, len= %d\n", len);
}
return len;
}
static ssize_t gpio_firefly_attr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct firefly_gpio_info *gpio_info = dev_get_drvdata(dev);
int ret;
ret = kstrtol(buf, 10, &gpio_info->firefly_param);
if (ret != 0)
{
dev_err(dev, "firefly_gpio_info gpio_firefly_attr_store: kstrtol failed, ret= %d\n", ret);
}
return count;
}
static DEVICE_ATTR(firefly_param, S_IRUGO | S_IWUSR, gpio_firefly_attr_show, gpio_firefly_attr_store);
static struct attribute *firefly_gpio_attrs[] =
{
&dev_attr_firefly_param.attr,
NULL,
};
static struct attribute_group firefly_gpio_attr_group =
{
.name = "firefly_gpio_info",
.attrs = firefly_gpio_attrs,
};
*/
static int firefly_gpio_probe(struct platform_device *pdev)
{
int ret;
int gpio;
//int error;
enum of_gpio_flags flag;
struct firefly_gpio_info *gpio_info;
struct device_node *firefly_gpio_node = pdev->dev.of_node;
printk("Firefly GPIO Test Program Probe\n");
gpio_info = devm_kzalloc(&pdev->dev,sizeof(struct firefly_gpio_info *), GFP_KERNEL);
if (!gpio_info)
{
dev_err(&pdev->dev, "devm_kzalloc failed!\n");
return -ENOMEM;
}
/*
gpio_info->dev = &pdev->dev;
platform_set_drvdata(pdev, gpio_info);
*/
gpio = of_get_named_gpio_flags(firefly_gpio_node, "firefly-gpio", 0, &flag);
if (!gpio_is_valid(gpio))
{
dev_err(&pdev->dev, "firefly-gpio: %d is invalid\n", gpio);
return -ENODEV;
}
if (gpio_request(gpio, "firefly-gpio"))
{
dev_err(&pdev->dev, "firefly-gpio: %d request failed!\n", gpio);
gpio_free(gpio);
return -ENODEV;
}
gpio_info->firefly_gpio = gpio;
gpio_info->gpio_enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1;
gpio_direction_output(gpio_info->firefly_gpio, gpio_info->gpio_enable_value);
printk("Firefly gpio putout\n");
/*
gpio = of_get_named_gpio_flags(firefly_gpio_node, "firefly-gpio1", 0, &flag);
if (!gpio_is_valid(gpio))
{
dev_err(&pdev->dev, "firefly-gpio1: %d is invalid\n", gpio);
return -ENODEV;
}
if (gpio_request(gpio, "firefly-gpio1"))
{
dev_err(&pdev->dev, "firefly-gpio1: %d request failed!\n", gpio);
gpio_free(gpio);
return -ENODEV;
}
gpio_info->firefly_gpio = gpio;
gpio_info->gpio_enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1;
gpio_direction_output(gpio_info->firefly_gpio, gpio_info->gpio_enable_value);
printk("Firefly gpio1 putout\n");
*/
gpio = of_get_named_gpio_flags(firefly_gpio_node, "firefly-irq-gpio", 0, &flag);
printk("firefly:the gpio:%d\n",gpio);
if (!gpio_is_valid(gpio))
{
dev_err(&pdev->dev, "firefly-irq-gpio: %d is invalid\n", gpio);
return -ENODEV;
}
gpio_info->firefly_irq_gpio = gpio;
gpio_info->firefly_irq_mode = flag;
gpio_info->firefly_irq = gpio_to_irq(gpio_info->firefly_irq_gpio);
if (gpio_info->firefly_irq)
{
if (gpio_request(gpio, "firefly-irq-gpio"))
{
dev_err(&pdev->dev, "firefly-irq-gpio: %d request failed!\n", gpio);
gpio_free(gpio);
return IRQ_NONE;
}
ret = request_irq(gpio_info->firefly_irq, firefly_gpio_irq, flag, "firefly-gpio", gpio_info);
if (ret != 0)
{
free_irq(gpio_info->firefly_irq, gpio_info);
dev_err(&pdev->dev, "firefly-gpio Failed to request IRQ: %d\n", ret);
}
queue = create_singlethread_workqueue("firefly-irq-gpio");
if (!queue)
{
return -1;
}
INIT_WORK(&my_wq, my_wq_func);
}
/*
error = sysfs_create_group(&pdev->dev.kobj, &firefly_gpio_attr_group);
if (error) {
dev_err(&pdev->dev, "Unable to export firefly param, error: %d\n",
error);
return error;
}
*/
test_netlink();
return 0;
}
static int firefly_gpio_remove(struct platform_device *pdev)
{
// sysfs_remove_group(&pdev->dev.kobj, &firefly_gpio_attr_group);
if (netlinkfd != NULL)
{
sock_release(netlinkfd->sk_socket);
printk(KERN_DEBUG "netlink exit\n");
}
return 0;
}
/*
struct file_operations firefly_gpio_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.fasync = firefly_gpio_fasync,
};*/
static struct of_device_id firefly_match_table[] =
{
{ .compatible = "firefly,rk3399-gpio",}, {}, };
static struct platform_driver firefly_gpio_driver =
{
.driver = {
.name = "firefly-gpio",
.owner = THIS_MODULE,
.of_match_table = firefly_match_table,
},
.probe = firefly_gpio_probe,
.remove = firefly_gpio_remove,
};
static int firefly_gpio_init(void)
{
return platform_driver_register(&firefly_gpio_driver);
}
module_init(firefly_gpio_init);
static void firefly_gpio_exit(void)
{
platform_driver_unregister(&firefly_gpio_driver);
}
module_exit(firefly_gpio_exit);
MODULE_AUTHOR("linjc <service@t-firefly.com>");
MODULE_DESCRIPTION("Firefly GPIO driver");
MODULE_ALIAS("platform:firefly-gpio");
MODULE_LICENSE("GPL");
用户空间代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/netlink.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#define NETLINK_USER 22
#define USER_MSG (NETLINK_USER+1)
#define MSG_LEN 100
#define MAX_PLOAD 100
struct _my_msg
{
struct nlmsghdr hdr;
int8_t data;
};
int main(int argc, char **argv)
{
char *data = "hello kernel";
struct sockaddr_nl local, dest_addr;
int skfd;
struct nlmsghdr *nlh = NULL;
struct _my_msg info;
int ret;
int socklen;
int recvcount = 0;
skfd = socket(AF_NETLINK, SOCK_RAW, USER_MSG);
if(skfd == -1)
{
printf("create socket error... %s\n", strerror(errno));
return -1;
}
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_pid = 50;
local.nl_groups = 0;
if(bind(skfd, (struct sockaddr *)&local, sizeof(local)) != 0)
{
printf("bind() error\n");
close(skfd);
return -1;
}
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0;
dest_addr.nl_groups = 0;
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PLOAD));
memset(nlh, 0, sizeof(struct nlmsghdr));
nlh->nlmsg_len = NLMSG_SPACE(MAX_PLOAD);
nlh->nlmsg_flags = 0;
nlh->nlmsg_type = 0;
nlh->nlmsg_seq = 0;
nlh->nlmsg_pid = local.nl_pid;
memcpy(NLMSG_DATA(nlh), data, strlen(data));
while(1)
{
ret = sendto(skfd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_nl));
if(!ret)
{
perror("sendto error1\n");
close(skfd);
exit(-1);
}
printf("wait kernel msg!\n");
// while(1)
// {
memset(&info, 0, sizeof(info));
socklen = sizeof(dest_addr);
ret = recvfrom(skfd, &info, sizeof(struct _my_msg), 0, (struct sockaddr *)&dest_addr, (socklen_t*)&socklen);
if(!ret)
{
perror("recv from kernel error\n");
close(skfd);
exit(-1);
}
printf("msg receive from kernel: %s, %d\n", info.data, recvcount++);
if (recvcount%2 == 0)
{
system("./light on");
}
else
{
system("./light off");
}
}
close(skfd);
free((void *)nlh);
return 0;
}
顶一个 mengduo 发表于 2017-12-7 16:36
顶一个
额,谢谢朋友。对于这个问题你有没有什么建议。 Icefly 发表于 2017-12-12 18:19
额,谢谢朋友。对于这个问题你有没有什么建议。
我也是新手,需求跟你差不多,目前也在研究,楼主有什么突破吗{:4_105:} mengduo 发表于 2017-12-14 14:46
我也是新手,需求跟你差不多,目前也在研究,楼主有什么突破吗
{:4_167:}握握手先,估计问的问题太基础了,所以都没人回答。最近这几天我研究了一下,我认为我想达到的目的是实现内核空间和用户空间的通信,搜了一下其方式又很多种,我本来想尝试用ioctl或者fasync,但由于找不到platform driver里file_operations,所以我又尝试了sysfs和netlink的方式,sysfs尝试失败,原因不明。。;但netlink的方式成功了,回来我把代码贴上来,看看对你有没有帮助。 必须要写内核代码吗?
Linux原生的 sys/class/gpio/gpio??/edge 机制不能用吗?
第一个想到的是用IOCTL,然后一直读,有中断来了就返回,请问博主如何编译程序,我现在写了个hello world 用aarch64-。。。。。。
这个编译器编译不过 我顶一个,赞楼主 安卓的话要往应用层传数据就用JNI,这个android.mk用ndk编so包,然后给Java native调用
页:
[1]