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的更多相关文章

  1. Linux 下wifi 驱动开发(三)—— SDIO接口WiFi驱动浅析

    SDIO-Wifi模块是基于SDIO接口的符合wifi无线网络标准的嵌入式模块,内置无线网络协议IEEE802.11协议栈以及TCP/IP协议栈.可以实现用户主平台数据通过SDIO口到无线网络之间的转 ...

  2. Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析

    源: Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析

  3. 基于335X平台Linux交换芯片驱动开发

    基于335X平台Linux交换芯片驱动开发   一.软硬件平台资料 1.开发板:创龙AM3359核心板,网口采用RMII形式. 2.Kernel版本:4.4.12,采用FDT 3.交换芯片MARVEL ...

  4. 转: 嵌入式linux下usb驱动开发方法--看完少走弯路【转】

    转自:http://blog.csdn.net/jimmy_1986/article/details/5838297 嵌入式linux下的usb属于所有驱动中相当复杂的一个子系统,要想将她彻底征服,至 ...

  5. Android HAL层与Linux Kernel层驱动开发简介

    近日稍微对Android中的驱动开发做了一些简要的了解. HAL:Hardware Abstract Layer 硬件抽象层,由于Linux Kernel需要遵循GPL开源协议,硬件厂商为了保护自己硬 ...

  6. Linux 字符设备驱动开发基础(二)—— 编写简单 PWM 设备驱动【转】

    本文转载自:https://blog.csdn.net/zqixiao_09/article/details/50858776 版权声明:本文为博主原创文章,未经博主允许不得转载.    https: ...

  7. Linux SD卡驱动开发(四) —— SD 控制器之真正的硬件操作

    前面对SD卡控制器有了一个主要的介绍.事实上SD控制器层更过的意义是为core层提供一种操作SD卡硬件的一种方法.当然不同的控制器对硬件控制的方法不尽同样,可是他们终于都能像core层提交一个统一的封 ...

  8. linux内核中驱动开发常见的相似多态

    #include<stdio.h> #include<stdlib.h> struct test { char name[20]; void (*func)(char *); ...

  9. (57)Linux驱动开发之三Linux字符设备驱动

    1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...

随机推荐

  1. SQL Server 使用 OUTPUT做数据操作记录

    OUTPUT 子句 可以在数据进行增删改的时候,可以返回受影响的行.先准备一张表 create table #t ( id int identity primary key ,name ) ) go ...

  2. 正则表达式 (python 2)

    Python提供re模块,包含所有正则表达式的功能.由于Python的字符串本身也用\转义,所以要特别注意: s = 'ABC\\-001' # Python的字符串# 对应的正则表达式字符串变成:# ...

  3. 解决yii2.0里url重写引用js路径问题(@web/的用法)

    在实际项目中,为了seo优化,使用了伪静态,开启了url重写

  4. sql2005 和 mysql 定时备份批处理

    保存为sqlbak.bat  目录我直接放winrar 的根目录了 或者拷贝一个winrar.exe 具体目录随意. 然后添加计划任务个人的话建议一周或者一天 虚拟主机等 建议每周或者每月 @echo ...

  5. 关于数据库插入sql操作速度的影响

    大概看了以下,适当多线程数据库连接操作比单线程效率高 多个sql语句组合后调用数据库连接执行比单个sql循环执行效率高的多 下面是几个参考资料,有空的时候详细整理一下 https://blog.csd ...

  6. Django 模型中FileField字段

    FileField¶ class FileField([upload_to=None, max_length=100, **options])¶ 一个上传文件的字段. 注意 FileField字段不支 ...

  7. 牛客网多校训练第一场 B - Symmetric Matrix(dp)

    链接: https://www.nowcoder.com/acm/contest/139/B 题意: 求满足以下条件的n*n矩阵A的数量模m:A(i,j) ∈ {0,1,2}, 1≤i,j≤n.A(i ...

  8. ResNet 修改

    https://github.com/tornadomeet/ResNet apache 开源项目 修改如下: 训练模块 import argparse,logging,os import mxnet ...

  9. C/C++心得-理解指针

    上一篇笔者用自己那不是怎么好理解的逻辑介绍了内存和C中的基本数据类型,现在笔者再根据自己重新所学来说说C语言中的指针. 理解指针才能真正的算C语言入门.也许是我大学期间太关注前端UE,也许是当初开始学 ...

  10. oracle 通配符及regexp_count函数说明

    通配符 通配符描述示例      %:匹配包含零个或更多字符的任意字符串.WHERE title LIKE '%computer%' 将查找处于书名任意位置的包含单词 computer 的所有书名.  ...