Linux GPIO键盘驱动开发记录_OMAPL138
Linux GPIO键盘驱动开发记录_OMAPL138
Linux基本配置完毕了,这几天开始着手Linux驱动的开发,从一个最简单的键盘驱动开始,逐步的了解开发驱动的过程有哪些。看了一下Linux3.3内核文件下的driver目录,点开里面的C文件,感觉底层的Linux驱动机制还是很复杂的,还需要一段漫长时间的学习。现在开发的也不能说是叫做驱动,也只能说是驱动的应用,我们学习驱动也从应用逐步开始,往里面深入吧。
0.开发准备
- 内核源文件(当时我们编译内核时候的目录,很重要,编译驱动的时候需要依赖这些内核源文件)
- Makefile文件(编译驱动的Makefile文件)
- 驱动源程序
- 应用程序(有main函数的)
1.键盘的接线图

我们主要使用USER0和USER1 KEY,两个按键,完成Linux GPIO键盘驱动开发。从图中可以看出GPIO0_6和GPIO6_1主要采集键盘按下的信息。
2. key.c驱动文件

驱动结构可以看上图,主要是在注册Linux内核设备,我们使用platform_device进行内核注册。我们从思维到图上看,从后往前的顺序进行一个一个定义。
2.1 gpio_key_buttons结构体
Linux提供的标准结构体,在#include <linux/gpio_key.h>头文件中。这里面就要定义按键的行为信息和指定GPIO口,这个是和上面的硬件原理图打交道的一个结构体。以下是和这个结构体有关的定义。
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <mach/da8xx.h> // 板子的头文件
#define OMAPL138_KEYS_BEBOUNCE 10
#define OMAPL138_GPIO_KEYS_POLL_MS 200
#define OMAPL138_USER_KEY0 GPIO_TO_PIN( 0,6 )
#define OMAPL138_USER_KEY1 GPIO_TO_PIN( 6,1 )
static const short omapl138_user_key_pins[] = {
DA850_GPIO0_6, DA850_GPIO6_1, -1
};
static struct gpio_keys_button omapl138_user_keys[] = {
[0] = {
.type = EV_KEY,
.active_low = 1,
.wakeup = 0,
.debounce_interval = OMAPL138_KEYS_BEBOUNCE,
.code = KEY_PROG1,
.desc = "user_key0",
.gpio = OMAPL138_USER_KEY0
},
[1] = {
.type = EV_KEY,
.active_low = 1,
.wakeup = 0,
.debounce_interval = OMAPL138_KEYS_BEBOUNCE,
.code = KEY_PROG2,
.desc = "user_key1",
.gpio = OMAPL138_USER_KEY1
}
};
在其他的平台可能GPIO口的定义不同,我用的是OMAPL138,使用的内核文件是OMAPL138提供的,他的里面定义了da8xx.h定义了相关GPIO的宏定义,你需要找到你自己平台GPIO结构体的定义,修改这个宏定义即可。这个结构提十分具备可读性,一看就能看懂了,其中的.code就是我们写应用程序的时候,按键读出来的值,就可以判断了。
2.2 gpio_keys_platform_data结构体
platform_data结构体顾名思义,基本上就是和我们整个驱动开发数据相关的。
static struct gpio_keys_platform_data omapl138_user_keys_pdata = {
.buttons = omapl138_user_keys,
.nbuttons = ARRAY_SIZE( omapl138_user_keys )
};
里面的成员,.buttons就是刚才我们定义gpio_keys_button数组,.nbuttons就是长度,我们使用宏函数ARRAY_SIZE完成取值。
2.3 platform_device结构体
思维导图在向前,我们就需要定义platform_device结构体了,这个结构体就是要和Linux内核打交道的结构提了。里面有设备名称.name,.id,dev。
static void omapl138_user_keys_release( struct device *dev ) {
}
static struct platform_device omapl138_user_keys_device = {
// you can find mount root by command "dmesg | grep gpio-keys ";
// cat /proc/bus/input/devices look the where the device is.
.name = "gpio-keys",
.id = 1,
.dev = {
.platform_data = &omapl138_user_keys_pdata,
.release = omapl138_user_keys_release,
},
};
.name中当驱动程序向linux注册后通过dmesg | grep gpio-keys命令就可以看到这个名字,在内核调试输出中可以看到。.id设备挂载节点的id,同样的设备id不能重复。.dev给定data和release函数(可以为空)。
2.4 初始化函数和退出函数
最后就是初始化函数和退出函数,最终要的就是resigster这个函数了。向内核注册设备。
static int __init omapl138_user_keys_init( void )
{
int reg;
reg = platform_device_register( &omapl138_user_keys_device );
if( reg ) {
pr_warning( "Could not register baseboard GPIO tronlong keys!" );
}else {
printk( KERN_INFO "User keys register successful!" );
}
return reg;
}
static void __exit omapl138_user_keys_exit( void )
{
platform_device_unregister( &omapl138_user_keys_device );
printk( KERN_INFO "user keys unregister ! \n" );
}
module_init( omapl138_user_keys_init );
module_exit( omapl138_user_keys_exit );
MODULE_DESCRIPTION( "user keys platform driver," );
MODULE_AUTHOR("Carlos Wei");
MODULE_LICENSE( "GPL" );
当我们使用insmod name.ko的时候,自动调用module_init()里面写入的函数了,当我们rmmod name.ko的时候,自动调用module_exit()里面写入的函数。
3 编译内核或者以模块形式加载
我们可以把这个驱动程序静态编译到内核代码树中也可以以模块的形式加载到内核中,我建议一开始开发的时候使用模块的形式加入到内核中,等着编译成熟之后,在编译到内核里面。
3.1 编译
制定内核源码文件的路径,写好Makefile文件,编译后上传到目标板的任意路径。
3.1.1 Makefile文件
ifneq ($(KERNELRELEASE),)
obj-m := key.o
else
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-arago-linux-gnueabi-
clean:
rm -rf *.ko *.o *.mod.o *.mod.c *.symvers modul* .button.* .tmp_versions
KDIR=/usr/src/linux-headers-3.3.0-omapl138
endif
这里比较重要的:
- KDIR=? 这个位置就是你Linux源码文件的路径,(内核事先编译一定要正确)
- CROSS_COMPILE= 这个指定交叉编译器,我的交叉编译器名字比较怪异arm-arago-linux-gnueabi-
3.1.2 Make一下生成key.ko

编译完成之后,通过ls命令,查看生成了key.ko文件。
通过scp或者ftp把key.ko文件传输到目标板子上。
3.2 加载驱动与查看挂载节点
1) insmod key.ko

2) 通过dmesg查看内核输出是否成功

3)通过cat /proc/bus/input/devices命令查看挂在详情

重点是event1,一会儿我们编辑应用程序需要打开/dev/input/event1这个设备节点进行对GPIO键盘操作。
4)测试键盘输入
在没有编写应用程序的时候,我们也可以通过简单的方法对GPIO键盘进行一个简单的测试。GPIO挂载节点是Handlers = event1 则输入:
cat /dev/input/event1
然后我们按键盘,如果当我们点击键盘的时候 终端输出乱码则代表我们的驱动是编写成功的。
5) 解挂驱动
如果我们不需要驱动了,则需要进行解挂驱动:
rmmod key.ko
也可以通过dmesg命令查看内核输出日志。
4 应用程序开发
建立文件:key_app.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <time.h>
#include <fcntl.h>
#include <linux/input.h>
int main( int argc, char **argv )
{
int key_state;
int fd;
int ret;
int code;
struct input_event buf;
fd = open( "/dev/input/event1", O_RDONLY );
if( fd < 0 ) {
printf( "Open GPIO_keys failed!!\n" );
return -1;
}
printf( "Open GPIO keys successful! \n" );
while( 1 ) {
ret = read( fd, &buf, sizeof( struct input_event ) );
if( ret <= 0 ) {
printf( "read failed! \n" );
return -1;
}
code = buf.code;
key_state = buf.value;
printf("wait...... \n");
switch( code ) {
case KEY_PROG1:
code = '1';
printf( "KEY1 state = %d\n", key_state );
break;
case KEY_PROG2:
code = '2';
printf( "KEY2 state = %d\n", key_state );
break;
}
}
printf("key test finished.\n");
close(fd);
return 0;
}
一个非常简单的程序,就是输出案件之。我们编译它:
arm-arago-linux-gnueabi-gcc key_app.c -o key_app.o
生成的key_app.o文件放入目标板的Linux目录,然后运行即可。
5 调试结果

通过按键就可以输出这些值,意味着我们的驱动开发成功了。
附录:源程序
链接: https://pan.baidu.com/s/1pNcEBEj 密码: xpsq
版权声明:
1. 本文为MULTIBEANS团队研发跟随文章,未经允许不得转载。
2· 文中涉及的内容若有侵权行为,请与本人联系,本人会及时删除。
3· 尊重成果,本文将用的参考文献全部给出,向无私的工程师,爱好者致敬。
Linux GPIO键盘驱动开发记录_OMAPL138的更多相关文章
- Linux 下wifi 驱动开发(三)—— SDIO接口WiFi驱动浅析
SDIO-Wifi模块是基于SDIO接口的符合wifi无线网络标准的嵌入式模块,内置无线网络协议IEEE802.11协议栈以及TCP/IP协议栈.可以实现用户主平台数据通过SDIO口到无线网络之间的转 ...
- Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析
源: Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析
- 基于335X平台Linux交换芯片驱动开发
基于335X平台Linux交换芯片驱动开发 一.软硬件平台资料 1.开发板:创龙AM3359核心板,网口采用RMII形式. 2.Kernel版本:4.4.12,采用FDT 3.交换芯片MARVEL ...
- 转: 嵌入式linux下usb驱动开发方法--看完少走弯路【转】
转自:http://blog.csdn.net/jimmy_1986/article/details/5838297 嵌入式linux下的usb属于所有驱动中相当复杂的一个子系统,要想将她彻底征服,至 ...
- Android HAL层与Linux Kernel层驱动开发简介
近日稍微对Android中的驱动开发做了一些简要的了解. HAL:Hardware Abstract Layer 硬件抽象层,由于Linux Kernel需要遵循GPL开源协议,硬件厂商为了保护自己硬 ...
- Linux 字符设备驱动开发基础(二)—— 编写简单 PWM 设备驱动【转】
本文转载自:https://blog.csdn.net/zqixiao_09/article/details/50858776 版权声明:本文为博主原创文章,未经博主允许不得转载. https: ...
- Linux SD卡驱动开发(四) —— SD 控制器之真正的硬件操作
前面对SD卡控制器有了一个主要的介绍.事实上SD控制器层更过的意义是为core层提供一种操作SD卡硬件的一种方法.当然不同的控制器对硬件控制的方法不尽同样,可是他们终于都能像core层提交一个统一的封 ...
- linux内核中驱动开发常见的相似多态
#include<stdio.h> #include<stdlib.h> struct test { char name[20]; void (*func)(char *); ...
- (57)Linux驱动开发之三Linux字符设备驱动
1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...
随机推荐
- VS配置Qt
https://blog.csdn.net/qq_35488967/article/details/71516640
- MyEcplise使用---使用 MyEclipse 反转引擎生成数据库
使用 MyEclipse 反转引擎,生成数据库 步骤: 1. 新建 Database 连接 2. 新建web项目 temp 添加myeclipse hibernate 能力 3. Hibernate ...
- Hadoop学习---Eclipse中hadoop环境的搭建
在eclipse中建立hadoop环境的支持 1.需要下载安装eclipse 2.需要hadoop-eclipse-plugin-2.6.0.jar插件,插件的终极解决方案是https://githu ...
- 小程序——微信小程序初学踩过的坑
微信小程序初学踩过的坑 一.前言 最近因为某些需要和个人兴趣打算开发一下微信小程序,经过在官方网站上的基本了解,我大体知道了微信小程序开发的大致过程,其实最本质的就是MVVM,借用了很多模式上 ...
- Kubernetes pod里一个特殊的容器:pause-amd64
大家在使用Docker容器或者Kubernetes时,遇到过这个容器么?gcr.io/google_containers/pause-amd64 docker ps的命令返回的结果: [root@k8 ...
- 百度地图隐藏LOGO显示
在引入地图的页面加入下列样式即可隐藏百度地图左下角的LOGO <style type="text/css"> .anchorBL{display:none;} ...
- github基本概念
github: 托管项目代码. 仓库(repository):用来存放项目的代码,每个项目对应一个仓库,多个项目则有多个仓库. 收藏(star):收藏项目的人数.收藏别人的项目方便下次查看. 复制克隆 ...
- BZOJ1879:[SDOI2009]Bill的挑战(状压DP)
Description Input 本题包含多组数据. 第一行:一个整数T,表示数据的个数. 对于每组数据: 第一行:两个整数,N和K(含义如题目表述). 接下来N行:每行一个字符串. T ≤ ...
- luogu P4135 作诗
嘟嘟嘟 郑重声明:我的前几到分块题写法上都有点小毛病,以这篇为主! 这道题感觉也是分块的基本套路,只不过卡常,得开氧气. 维护俩:sum[i][j]表示前 i 块中,数字 j 出现了多少次,ans[i ...
- STM32的备份寄存器和控制状态寄存器
STM32的备份寄存器和控制状态寄存器 1 备份寄存器用于RTC时钟 RTC时钟可以在掉电以后继续计数,保证时间的延续,但是重新上电以后需要配置,保证之前的计数不会被清除,可以借助备份寄存器实现,备份 ...