sunbeyond 发表于 2014-11-5 10:16:10

Cubiebaord Linux 按键设备驱动(中断)

本帖最后由 sunbeyond 于 2014-11-7 22:06 编辑

Cubiebaord 按键设备驱动(中断)
根据按键原理。本例子让 PI11 口 pin 脚接地模拟按键按下。只需要有根电线就行不要真正的按键。

说明:
gpio_request(unsigned gpio, const char *label)第一个参数 gpio 标号是如何获取。是根据
script.fex 中的 gpio_para 中子键 gpio_pin_1,gpio_pin_2,gpio_pin_3....对应的顺序 GPIO 标号依次是
1,2,3。

1 首先修改 scipt.fex 配置,这里以 PI11 作为按键中断口。对应的 gpio 标号原理跟上面讲的一样。
可知此处对应的标号也为 1。

gpio_used = 1
gpio_num = 2
gpio_pin_1 = port:PI11<0><1><default><default> ------》 PH11 对应 GPIO 标号 num = 1
gpio_pin_2 = port:PH21<1><default><default><1>
2 驱动代码:(红色部分为 GPIO 中断使用重点)button_drv.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <asm/io.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <mach/irqs.h>
#include <plat/sys_config.h>
#include <mach/system.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/atomic.h>
#include <linux/kthread.h>
//分配 cdev
struct cdev btn_cdev;
wait_queue_head_t btn_wq; //分配等待队列头
Copyright © Cubietech Limited. All right reservedWebsite: http://cubieboard.org
E-mail: s upport@cubiete ch.com
//主设备号
static int major;
//设备类
static struct class *cls;
//按键操作标志
static int is_press; // 1:按键操作 0:无按键操作
static unsigned char key_val;
//按按键按下次数
int press_num = 1;
//GPIO 标号,非常重要,通过 script.fex 中的 gpio_para 配置顺序。从上往下对应的 gpio 标号依次是
1,2,3......
int num = 1;
//中断号
int irq ;
static int button_open(struct inode *inode,
struct file *file)
{
return 0;
}
static int button_close(struct inode *inode,
struct file *file)
{
return 0;
}
static ssize_t button_read(struct file *file,
char __user *buf,
size_t count,
loff_t *ppos)
{
/*.判断按键是否有操作,如果有,进行读取
键值,然后上报给用户,如果没有操作,
进程休眠
*/
wait_event_interruptible(btn_wq, is_press != 0);
is_press = 0;
/*3.上报键值*/
copy_to_user(buf, &key_val, sizeof(key_val));
return count;
}
//设备的操作集合
static struct file_operations btn_fops = {
.owner = THIS_MODULE,
.open = button_open,
Copyright © Cubietech Limited. All right reservedWebsite: http://cubieboard.org
E-mail: s upport@cubiete ch.com
.release = button_close,
.read = button_read
};
static irqreturn_t button_isr(int irq,
void *dev_id)
{
unsigned long status;
/*1. 获取按键状态*/
status = gpio_get_value(num);
/*2. 更新按键键值 key_val*/
if (status == 1) {
//松开
key_val = 0x50;
} else if (status == 0)
//按下
key_val = 0x51;
/*3. 唤醒休眠的进程*/
wake_up_interruptible(&btn_wq);
is_press = 1;
return IRQ_HANDLED;
}
static int button_init(void)
{
dev_t dev_id;
/*1.申请设备号*/
if (major) {
dev_id = MKDEV(major, 0);
register_chrdev_region(dev_id, 1, "button");
} else {
alloc_chrdev_region(&dev_id, 0, 1, "button");
major = MAJOR(dev_id);
}
/*2.分配初始化 cdev*/
/*2.2 初始化 cdev*/
cdev_init(&btn_cdev, &btn_fops);
//初始化等待队列头
init_waitqueue_head(&btn_wq);
/*3.注册 cdev*/
cdev_add(&btn_cdev, dev_id, 1);
/*4.自动创建设备节点*/
Copyright © Cubietech Limited. All right reservedWebsite: http://cubieboard.org
E-mail: s upport@cubiete ch.com
cls = class_create(THIS_MODULE, "button");
device_create(cls, NULL, dev_id, NULL, "button");
/*5.申请 GPIO 资源*/
if (gpio_request(num,"gpio_pin")){
printk("request gpio error\n");
}
/*6.获取中断号*/
irq = gpio_to_irq(num);
/*7 注册中断*/
int error = request_irq(irq,button_isr,IRQF_TRIGGER_FALLING|
IRQF_TRIGGER_RISING,"key_1",&press_num);
if(error){
printk("request irq error\n");
}
return 0;
}
static void button_exit(void)
{
dev_t dev_id = MKDEV(major, 0);
/*释放中断*/
/*释放 GPIO 资源*/
free_irq(irq, &press_num);
gpio_free(num);
/*删除设备节点*/
device_destroy(cls, dev_id);
class_destroy(cls);
/*删除 cdev*/
cdev_del(&btn_cdev);
/*释放设备号*/
unregister_chrdev_region(dev_id, 1);
}
module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");

测试代码:button_test.c 测试代码: button_test.c
#include
#include
#include
#include
<stdio.h>
<sys/types.h>
<sys/stat.h>
<fcntl.h>
int main(int argc, char *argv[])
{
int fd;
unsigned char key_val;
fd = open("/dev/button", O_RDWR);
if (fd < 0) {
printf("open failed.\n");
return -1;
}
while(1) {
read(fd, &key_val, sizeof(key_val));
printf("key_val = %#x\n", key_val);
}
close(fd);
return 0;
}
3 加载驱动,运行测试代码:
$ insmod button_drv.ko
根据按键原理。可让 PI11 口 pin 脚接地模拟按键按下。
$ ./button_test (有按键按下返回 0x51,松开按键返回 0x50)

hades 发表于 2014-11-11 11:20:45

:lol:lol:lol:lol:lol先顶顶,,回来有空了尝试一下,,,收藏了,,,thank you for your share

sunbeyond 发表于 2014-11-11 12:13:18

hades 发表于 2014-11-11 11:20 static/image/common/back.gif
先顶顶,,回来有空了尝试一下,,,收藏了,,,thank you for your share...

恩 有什么问题反馈一下

simon_zhangss 发表于 2015-10-14 10:33:54

LZ,你好!我参照论坛的教程构建的debian系统。现在想做基于gpio的中断驱动。自己做的驱动在gpio toirq 这一步失败,获取的irq为-22。看到你的帖子,复制粘贴,修改.fex的gpiopara,编译没问题,加载驱动的时候同样在gpio to irq这一步获得的irq为-22.
“root@CubieBoard2:~# insmod button_drv.ko
GPIO<1> request the irq is -22
[   48.781065] GPIO<1> request the irq is -22
request irq error
[   48.787647] request irq error
root@CubieBoard2:~# ”
现在的使用的debian下面并没有gpio-sunxi.ko驱动,这个驱动与我编译的驱动有没有关联?

sunbeyond 发表于 2015-10-15 09:27:21

simon_zhangss 发表于 2015-10-14 10:33 static/image/common/back.gif
LZ,你好!我参照论坛的教程构建的debian系统。现在想做基于gpio的中断驱动。自己做的驱动在gpio toirq 这 ...

gpio-sunxi.ko 获取.fex 的参数。 你要先加载gpio-sunxi.ko模块。    应该是有的可能驱动选上把。

sunbeyond 发表于 2015-10-15 09:27:23

simon_zhangss 发表于 2015-10-14 10:33 static/image/common/back.gif
LZ,你好!我参照论坛的教程构建的debian系统。现在想做基于gpio的中断驱动。自己做的驱动在gpio toirq 这 ...

gpio-sunxi.ko 获取.fex 的参数。 你要先加载gpio-sunxi.ko模块。    应该是有的可能驱动选上把。

sunbeyond 发表于 2015-10-15 09:27:27

simon_zhangss 发表于 2015-10-14 10:33 static/image/common/back.gif
LZ,你好!我参照论坛的教程构建的debian系统。现在想做基于gpio的中断驱动。自己做的驱动在gpio toirq 这 ...

gpio-sunxi.ko 获取.fex 的参数。 你要先加载gpio-sunxi.ko模块。    应该是有的可能驱动选上把。

simon_zhangss 发表于 2015-10-15 10:25:14

本帖最后由 simon_zhangss 于 2015-10-15 10:28 编辑

sunbeyond 发表于 2015-10-15 09:27 http://forum.cubietech.com/static/image/common/back.gif
gpio-sunxi.ko 获取.fex 的参数。 你要先加载gpio-sunxi.ko模块。    应该是有的可能驱动选上把。 ...

现在使用的内核是3.4.43.昨天后面有尝试加载gpio-sunxi.ko模块。下面是打印信息:

打印信息第二行显示:GPIO irq support disabled in this platform。
#define EINT_NUM gpio_eint_count
不明白,然后在gpio_sunxi.c中搜索打印信息,
      /* configure EINTs for the detected SoC */
      sunxi_gpio_eint_probe();

      /* This needs additional system irq numbers (NR_IRQ=NR_IRQ+EINT_NUM) */
      if (EINT_NUM > 0) {
                sunxi_chip->irq_base = irq_alloc_descs(-1, 0, EINT_NUM, 0);
                if (sunxi_chip->irq_base < 0) {
                        pr_err("Couldn't allocate virq numbers. GPIO irq support disabled\n");
                        err = sunxi_chip->irq_base;
                }
      } else
                pr_info("GPIO irq support disabled in this platform\n");
进入_devinit sunxi_gpio_eint_probe(),仅有
if (sunxi_is_a10())
{
gpio_eint_list = a10;
gpio_eint_count = 32;
}
else if (sunxi_is_a13())
{
gpio_eint_list = a13;
gpio_eint_count = 32;
}
else
{
gpio_eint_list = none;
gpio_eint_count = 0;
}
这意思是不支持a20?

sunbeyond 发表于 2015-10-15 20:02:33

simon_zhangss 发表于 2015-10-15 10:25 static/image/common/back.gif
现在使用的内核是3.4.43.昨天后面有尝试加载gpio-sunxi.ko模块。下面是打印信息:

打印信息第二行显示: ...

你这内核源码哪里下载的啊? 感觉不是cubie官方的。官方放的都是3.4.79

https://github.com/cubieboard/linux-sdk-kernel-source

sunbeyond 发表于 2015-10-15 20:02:39

simon_zhangss 发表于 2015-10-15 10:25 static/image/common/back.gif
现在使用的内核是3.4.43.昨天后面有尝试加载gpio-sunxi.ko模块。下面是打印信息:

打印信息第二行显示: ...

你这内核源码哪里下载的啊? 感觉不是cubie官方的。官方放的都是3.4.79

https://github.com/cubieboard/linux-sdk-kernel-source
页: [1] 2
查看完整版本: Cubiebaord Linux 按键设备驱动(中断)