Android 驱动 (一) GPIO
USB UART等各种总线上(或是虚拟总线),每块开发板都有自己的原理图和走线方式,这些硬件相关内容又是BSPproject师们在调试驱动时绕不开的。
思来想去,因为涉及面过于繁杂。加之本人能力又有限。还是认为站在BSP的角度上去分析,首先简介基础的背景知识。搞懂驱动程序的意思之后,而后再着手优化移植驱动,用这样的比較有用的方式慢慢地模块看似比較难的驱动程序。
处理器: SUN4I A10
IO ports,也就是通用IO口。嵌入式系统中经常有数量众多。可是结构却比較简单的外部设备/电路。对这些设备/电路有的须要CPU为之提供控制手段,有的则须要被CPU用作输入信号。
并且,很多这种设备/电路仅仅要求一位。即仅仅要有开/关两种状态就够了。比方灯亮与灭。
对这些设备/电路的控制。使用传统的串行口或并行口都不合适。
所以在微控制器芯片上一般都会提供一个“通用可编程IO接口”,即GPIO。
接口至少有两个寄存器,即“通用IO控制寄存器”与“通用IO数据寄存器”。
数据寄存器的各位都直接引到芯片外部,而对这样的寄存器中每一位的作用,即每一位的信号流通方向,则能够通过控制寄存器中相应位独立的加以设置。这样。有无GPIO接口也就成为微控制器差别于微处理器的一个特征。
static int __init sun4i_gpio_init(void) {
int err;
int i;
int sun4i_gpio_used = 0;
struct sun4i_gpio_data *gpio_i;
/* include /linux/sysfs.h
-------------------------------------
struct attribute {
const char *name;
struct module *owner;
mode_t mode;
}; struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
}; 这2个都是sys文件系统的中的结构体。关键点在device_attribute 中的show 和 store,事实上就是对设备的读和写
*/
struct device_attribute *attr_i;
char pin[16];
pr_info("sun4i gpio driver init\n");
/*
用来获取sys_config1.fex主键gpio_para中的子键gpio_used的值,假设gpio_used的值为0,则表示该驱动已经通过配置关闭了,这样就是实现了用配置来控制打开和关闭驱动
这里我们知道了假设我们要添加单独控制的gpio。我们仅仅须要在sys_config1.fex文件里,加入gpio_para的主键和名为gpio_used的子键
*/
err = script_parser_fetch("gpio_para", "gpio_used", &sun4i_gpio_used, sizeof(sun4i_gpio_used)/sizeof(int));
if(err) {
pr_err("%s script_parser_fetch \"gpio_para\" \"gpio_used\" error\n", __FUNCTION__);
goto exit;
}
if(!sun4i_gpio_used) {
pr_err("%s sun4i_gpio is not used in config\n", __FUNCTION__);
err = -1;
goto exit;
}
/*
用来获取sys_config1.fex主键gpio_para中的子键gpio_num的值,非常显然子键gpio_num的值。用来定义配置中一共同拥有多少个gpio
*/
err = script_parser_fetch("gpio_para", "gpio_num", &sun4i_gpio_num, sizeof(sun4i_gpio_num)/sizeof(int));
if(err) {
pr_err("%s script_parser_fetch \"gpio_para\" \"gpio_num\" error\n", __FUNCTION__);
goto exit;
}
sun4i_gpio_dbg("sun4i_gpio_num:%d\n", sun4i_gpio_num);
if(!sun4i_gpio_num) {
pr_err("%s sun4i_gpio_num is none\n", __FUNCTION__);
err = -1;
goto exit;
} /*
注冊一个杂项设备,主设备号是10,此设备号由系统来定义
*/
err = misc_register(&sun4i_gpio_dev);
if(err) {
pr_err("%s register sun4i_gpio as misc device error\n", __FUNCTION__);
goto exit;
} /*
依据gpio的个数。对每一个gpio结构体申请一块内存,用来保存从sys_config1.fex文件里读取到的每一个gpio的属性
*/
psun4i_gpio = kzalloc(sizeof(struct sun4i_gpio_data) * sun4i_gpio_num, GFP_KERNEL);
/*
依照gpio的个数,对每一个gpio申请一个设备属性,每一个设备属性将用来对sys文件系统中的gpio的读写
*/
pattr = kzalloc(sizeof(struct device_attribute) * sun4i_gpio_num, GFP_KERNEL);
if(!psun4i_gpio || !pattr) {
pr_err("%s kzalloc failed\n", __FUNCTION__);
err = -ENOMEM;
goto exit;
}
gpio_i = psun4i_gpio;
attr_i = pattr;
/*
循环对每一个gpio的在sys_config1.fex文件的值进行读取,并将解析出来的值保存到gpio_i中
*/
for(i = 0; i < sun4i_gpio_num; i++) {
/*
由此能够看出,子键相似于gpio_pin_1 gpio_pin_2 gpio_pin_3 ......这样的方式来命名的
*/
sprintf(pin, "gpio_pin_%d", i+1);
sun4i_gpio_dbg("pin:%s\n", pin); err = script_parser_fetch("gpio_para", pin,
(int *)&gpio_i->info, sizeof(script_gpio_set_t));
if(err) {
pr_err("%s script_parser_fetch \"gpio_para\" \"%s\" error\n", __FUNCTION__, pin);
break;
} /*
************************************************************************************************************
* 这是 CSP_GPIO_Request_EX函数的说明 * CSP_GPIO_Request_EX
*
* 函数名称:
*
* 參数说明: main_name 传进的主键名称,匹配模块(驱动名称)
*
* sub_name 传进的子键名称,假设是空,表示所有,否则寻找到匹配的单独GPIO
*
* 返回值 :0 : err
* other: success
*
* 说明 :临时没有做冲突检查
*
*
************************************************************************************************************
*/ gpio_i->gpio_handler = gpio_request_ex("gpio_para", pin);
sun4i_gpio_dbg("gpio handler: %d", gpio_i->gpio_handler);
if(!gpio_i->gpio_handler) {
pr_err("%s can not get \"gpio_para\" \"%s\" gpio handler,\
already used by others? ", __FUNCTION__, pin);
break;
}
sun4i_gpio_dbg("%s: port:%d, portnum:%d\n", pin, gpio_i->info.port,
gpio_i->info.port_num);
/* Turn the name to pa1, pb2 etc... */
sprintf(gpio_i->name, "p%c%d", 'a'+gpio_i->info.port-1, gpio_i->info.port_num);
sun4i_gpio_dbg("psun4i_gpio->name%s\n", gpio_i->name);
/* Add attributes to the group */
/*
这里将属性初始化到sys文件系统。并对device_attribute 结构体的成员赋值,这样事实上就是定义了读写IO的函数
sun4i_gpio_enable_show就是读出IO的data,而sun4i_gpio_enable_store就是往IO中写入值
*/
sysfs_attr_init(&attr_i->attr);
attr_i->attr.name = gpio_i->name;
attr_i->attr.mode = S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH;
attr_i->show = sun4i_gpio_enable_show;
attr_i->store = sun4i_gpio_enable_store;
sun4i_gpio_attributes[i] = &attr_i->attr;
gpio_i++;
attr_i++;
}
sysfs_create_group(&sun4i_gpio_dev.this_device->kobj,
&sun4i_gpio_attribute_group);
exit:
return err;
}
static void __exit sun4i_gpio_exit(void) {
sun4i_gpio_dbg("bye, sun4i_gpio exit\n");
sysfs_remove_group(&sun4i_gpio_dev.this_device->kobj,
&sun4i_gpio_attribute_group);
misc_deregister(&sun4i_gpio_dev);
kfree(psun4i_gpio);
kfree(pattr);
} struct sun4i_gpio_data,这个结构体事实上就用来描写叙述一个gpio struct sun4i_gpio_data {
int status; //当前状态,事实上就是gpio的值。0或者1
unsigned gpio_handler; //用来标识这个gpio,相当于一个唯一的id
script_gpio_set_t info;
char name[8]; //8个字节的字符串用来描写叙述名字 比如"PI09"
} script_gpio_set_t 结构体。才是真正用来描写叙述单个的gpio
typedef struct
{
char gpio_name[32];
int port;
int port_num;
int mul_sel;
int pull;
int drv_level;
int data;
} script_gpio_set_t;
gpio_name ="gpio_pin_1 "
port ='I'
port_num =09
(五) sysconfig1.fex 配置系统》一文中,我们以前简单分析过sysconfig1.fex和描写叙述GPIO的形式
描写叙述gpio的形式:Port:port+组内序号<功能分配><内部电阻状态><驱动能力><输出电平状态>
相应的,mul_sel就是功能分配,是Multifunction select的缩写,这个决定了属于什么功能,因为我们这里是输出功能,所以默认值为1
sysfs
终于sysfs使我们认识到一个全新的对象模型非常有利于系统,于是kobject应运而生。
从kernel在2.6引入sysfs開始,sysfs总是不可或缺的内核的一部分了。
直接来控制GPIO了,而不须要通过程序
假设採用sysfs的方式,我们的应用程序仅仅须要读写一个文件就可以操作GPIO了
static int sun4i_gpio_open(struct inode *inode, struct file *file) {
pr_info("sun4i_gpio open\n");
return 0;
}
ssize_t sun4i_gpio_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) {
pr_info("sun4i_gpio write\n");
return 0;
} static const struct file_operations sun4i_gpio_fops = {
.open = sun4i_gpio_open,
.write = sun4i_gpio_write,
.release = sun4i_gpio_release
};
ugly gpio driver" ^_^
Android 驱动 (一) GPIO的更多相关文章
- Android(Linux)控制GPIO方法二
前文<Android(Linux)控制GPIO的方法及实时性分析>主要使用Linux shell命令控制GPIO,该方法可在调试过程中快速确定GPIO硬件是否有问题,即对应的GPIO是否受 ...
- Android驱动开发5-8章读书笔记
Android驱动开发读书笔记 第五章 S5PV210是一款32位处理器,具有 ...
- 初入android驱动开发之字符设备(四-中断)
上一篇讲到android驱动开发中,应用是怎样去操作底层硬件的整个流程,实现了按键控制led的亮灭.当然,这是一个非常easy的实例,只是略微演变一下,就能够得到广泛的应用. 如开发扫描头,应用透过监 ...
- Android驱动开发前的准备
最近看了一些Android驱动开发前需要知道的资料,收获很多,接下来就谈谈我自己的一些心得体会. Android在近几年时间发展迅速,已经成为智能手机操作系统的老大.不过,因为Android原生的代码 ...
- Android驱动开发之Hello实例
Android驱动开发之Hello实例: 驱动部分 modified: kernel/arch/arm/configs/msm8909-1gb_w100_hd720p-perf_defconf ...
- android驱动[置顶] 我的DIY Android之旅--驱动并控制你的Android开发板蜂鸣器
改章节个人在深圳游玩的时候突然想到的...这几周就有想写几篇关于android驱动的博客,所以回家到之后就奋笔疾书的写出来发布了 这些天一直在想Android驱动框架层的实现,本文借助老罗教师的博客和 ...
- 如何做更好的Android驱动project师
随着智能手机的飞跃发展,特别是Android智能机的爆炸性发展,Android驱动project师是越来越受欢迎的一个职位,并且是一个非常值得人期待的职位,由于可能你參与研发的一款手机就能改变 ...
- 迅为iTOP-4418/6818开发板-驱动-实现GPIO扩展
实现 GPIO 扩展,先弄清楚“复用”的概念,将调用这些 GPIO 的驱动去掉配置,重新编译,加到自己的驱动中,就可以实现扩展的 GPIO 的输入和输出.另外必须要先看文档“迅为iTOP-4418开发 ...
- 通过linux核映射驱动访问GPIO
1. HPS GPIO原理 1.功能方块图 linux内核是通过Linux内核memory-mapped device驱动访问GPIO控制器的寄存器而控制HPS端用户的LED和KEY的.memory- ...
- 初入android驱动开发之字符设备(一)
大学毕业,初入公司,招进去的是android驱动开发工程师的岗位,那时候刚进去,首先学到的就是如何搭建kernel.android的编译环境,然后就是了解如何刷设备以及一些最基本的工具.如adb.fa ...
随机推荐
- TI 77GHZ雷达开发套件 RDP-DC100
RDP-DC100用户使用手册 目录 1. 硬件说明... 3 1.1. 官方处理板的修 ...
- Computed Properties vs Property Requirements - protocol
In addition to stored properties, classes, structures, and enumerations can define computed properti ...
- MFC窗体大小变化
对话框的大小变化后,假若对话框上的控件大小不变化,看起来会比较难看.下面就介绍怎么让对话框上的控件随着对话框的大小的变化自动调整. 首先明确的是Windows有一个WM_SIZE消息响应函数,这个函数 ...
- CAD实现文档坐标到视区坐标的转换(com接口Delphi语言)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...
- vue基础---条件渲染
(1)v-if条件渲染 v-if 指令用于条件性地渲染一块内容.这块内容只会在指令的表达式返回 truthy 值的时候被渲染. 可以用 v-else 添加一个“else 块”: ①表达式 <di ...
- 18SVN进行版本控制
SVN进行版本控制 SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS.CVS,它采用了分支管理系统,它的设计目标就是取代CVS. SVN Website.
- CodeForces 【20C】Dijkstra?
解题思路 heap+Dijkstra就能过.注意边是双向边,要用long long. 附上代码 #include <iostream> #include <queue> #in ...
- [Luogu] P1993 小K的农场
题目描述 小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述: 农场a比农场b至少多种植了c个单位的作 ...
- UVA - 1618 Weak Key(RMQ算法)
题目: 给出k个互不相同的证书组成的序列Ni,判断是否存在4个证书Np.Nq.Nr.Ns(1≤p<q<r<s≤k)使得Nq>Ns>Np>Nr或者Nq<Ns&l ...
- application对象的使用
application对象的使用 制作人:全心全意 application对象用于保存所有应用程序中的公有数据.它在服务器启动时自动创建,在服务器停止时销毁.当application对象没有被销毁时, ...