Linux内核gpiolib注册建立过程
1、相关的数据结构
struct s3c_gpio_chip { // 这个结构体是三星在移植gpiolib时封装的一个结构体 用来描述一组gpio端口信息
struct gpio_chip chip;
struct s3c_gpio_cfg *config; // 三星封装的用来配置一个gpio端口的结构体 主要是上下拉模式配置
struct s3c_gpio_pm *pm; // 这个是电源管理相关的数据结构
void __iomem *base; // gpio相关寄存器的虚拟基地址
int eint_offset;
spinlock_t lock;
#ifdef CONFIG_PM
u32 pm_save[];
#endif
};
struct gpio_chip { // 内核提供的用来描述一组gpio端口信息的结构体
const char *label; // 一个标号 也就是gpio端口的名字
struct device *dev; // device指针指向这个gpio端口设备
struct module *owner;
int (*request)(struct gpio_chip *chip, // 请求gpio 申请
unsigned offset);
void (*free)(struct gpio_chip *chip, // 释放
unsigned offset);
int (*direction_input)(struct gpio_chip *chip, // 用于将gpio配置为输入模式
unsigned offset);
int (*get)(struct gpio_chip *chip, // 获取gpio电平状态
unsigned offset);
int (*direction_output)(struct gpio_chip *chip, // 用于将gpio配置为输出模式
unsigned offset, int value);
int (*set_debounce)(struct gpio_chip *chip, // 用于消抖
unsigned offset, unsigned debounce);
void (*set)(struct gpio_chip *chip, // 设置gpio的电平
unsigned offset, int value);
int (*to_irq)(struct gpio_chip *chip, // 如果该gpio是一个外部中断源,则使用这个函数来获取对应的中断号
unsigned offset);
void (*dbg_show)(struct seq_file *s,
struct gpio_chip *chip);
int base; // 这组gpio端口的 基准编号 (这个编号是内核设计的)
u16 ngpio; // 这组端口的gpio数量
const char *const *names;
unsigned can_sleep:;
unsigned exported:;
};
struct s3c_gpio_cfg {
unsigned int cfg_eint; // 用于外部中断源时的一个配置值
s3c_gpio_pull_t (*get_pull)(struct s3c_gpio_chip *chip, unsigned offs); // 读取下拉状态时gpio的电流
int (*set_pull)(struct s3c_gpio_chip *chip, unsigned offs, // 设置下拉状态gpio电流
s3c_gpio_pull_t pull);
int (*set_pin)(struct s3c_gpio_chip *chip, unsigned offs,
s3c_gpio_pull_t level);
unsigned (*get_config)(struct s3c_gpio_chip *chip, unsigned offs); // 获取gpio的当前配置
int (*set_config)(struct s3c_gpio_chip *chip, unsigned offs, // 设置gpio的当前配置
unsigned config);
};
2、函数调用关系图
smdkc110_map_io
s5pv210_gpiolib_init
samsung_gpiolib_add_4bit_chips
samsung_gpiolib_add_4bit
s3c_gpiolib_add
gpiochip_add // 这个函数就是内核的gpiolib驱动框架提供的用来注册gpiolib的函数
3、函数详解
smdkc110_map_io:
static void __init smdkc110_map_io(void)
{
s5p_init_io(NULL, , S5P_VA_CHIPID); // 静态物理地址到虚拟地址的映射初始化
s3c24xx_init_clocks(); // 系统时钟初始化
s5pv210_gpiolib_init(); // gpiolib管理器初始化
s3c24xx_init_uarts(smdkc110_uartcfgs, ARRAY_SIZE(smdkc110_uartcfgs));
s5p_reserve_bootmem(smdkc110_media_devs, ARRAY_SIZE(smdkc110_media_devs));
#ifdef CONFIG_MTD_ONENAND
s5pc110_device_onenand.name = "s5pc110-onenand";
#endif
#ifdef CONFIG_MTD_NAND
s3c_device_nand.name = "s5pv210-nand";
#endif
s5p_device_rtc.name = "smdkc110-rtc";
}
s5pv210_gpiolib_init:
__init int s5pv210_gpiolib_init(void)
{
struct s3c_gpio_chip *chip = s5pv210_gpio_4bit; // 4bit表示的是一个gpio使用4位来配置描述 s5pv210_gpio_4bit是一个struct s3c_gpio_chip数组,是三星移植时写好的
int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit); // 获取端口数量(注意一组端口和一个具体的gpio)
int i = ; for (i = ; i < nr_chips; i++, chip++) {
if (chip->config == NULL) // 如果我们的gpio端口没有 配置方法 则使用 gpio_cfg 进行默认配置
chip->config = &gpio_cfg;
if (chip->base == NULL) // 如果我们的gpio端口结构体中没有填充 基准编号 则使用下面进行填充
chip->base = S5PV210_BANK_BASE(i);
} samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips); // 添加gpiolib return ;
}
samsung_gpiolib_add_4bit_chips:
void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip,
int nr_chips)
{
for (; nr_chips > ; nr_chips--, chip++) { // 对于每一个gpio端口组都调用下面的两个函数
samsung_gpiolib_add_4bit(chip); // 给gpio端口配置输入输出模式配置方法
s3c_gpiolib_add(chip); // 最终是通过这个函数去添加gpiolib
}
} void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
{
chip->chip.direction_input = samsung_gpiolib_4bit_input; // 给gpio端口加入配置gpio为输入模式的方法
chip->chip.direction_output = samsung_gpiolib_4bit_output; // 给gpio端口加入配置gpio为输出模式的方法
chip->pm = __gpio_pm(&s3c_gpio_pm_4bit); // 电源管理相关
}
s3c_gpiolib_add:
__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
{
struct gpio_chip *gc = &chip->chip; // 使用gc指针指向 chip->chip
int ret; BUG_ON(!chip->base);
BUG_ON(!gc->label);
BUG_ON(!gc->ngpio); spin_lock_init(&chip->lock); // 如果我们的结构体中还没有加入相应的方法 则在下面加入方法
if (!gc->direction_input)
gc->direction_input = s3c_gpiolib_input;
if (!gc->direction_output)
gc->direction_output = s3c_gpiolib_output;
if (!gc->set)
gc->set = s3c_gpiolib_set;
if (!gc->get)
gc->get = s3c_gpiolib_get; #ifdef CONFIG_PM // 电源管理相关
if (chip->pm != NULL) {
if (!chip->pm->save || !chip->pm->resume)
printk(KERN_ERR "gpio: %s has missing PM functions\n",
gc->label);
} else
printk(KERN_ERR "gpio: %s has no PM function\n", gc->label);
#endif /* gpiochip_add() prints own failure message on error. */
ret = gpiochip_add(gc); // 最终又是通过这个函数去注册我们的gpiolib管理器 这个函数就是内核gpiolib驱动框架提供的了
if (ret >= )
s3c_gpiolib_track(chip);
}

总结:
其实我们的gpiolib虽然说是一个gpio的管理者,同样他也是一个设备,在/sys目录下是能够去通过设备的属性方法对具体的gpio进行设置的,三星在移植gpiolib时是使用内核
提供的gpiolib驱动框架来实现的。
其实这个注册就是将我们的封装了一个GPIO端口的所有信息的chip结构体变量挂接到内核gpiolib模块定义的一个gpio_desc数组中的某一个格子中。
Linux内核gpiolib注册建立过程的更多相关文章
- 结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程
结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程 目录 结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程 一. 实验准备 二. 实验过程 I 分析中断上下文的切换 ...
- linux设备树的建立过程
为了阐明表示总线.设备和设备驱动程序的各个数据结构之间彼此的关联,它们的注册过程是很有必要的.顺序一定是如下:(1)注册总线---bus_register:(2)注册设备device_register ...
- Linux内核树的建立-基于ubuntu系统
刚看 O'REILLY 写的<LINUX 设备驱动程序>时.作者一再强调在编写驱动程序时必须 建立内核树.先前的内核只需要有一套内核头文件就够了,但因为2.6的内核模块吆喝内核源码树中的目 ...
- Xilinx-Zynq Linux内核源码编译过程
本文内容依据http://www.wiki.xilinx.com网址编写,编译所用操作系统为ubuntu 14 1.交叉编译环境的安装配置 1)http://www.wiki.xilinx.com/I ...
- 代码学习-Linux内核网卡收包过程(NAPI)【转】
转自:https://blog.csdn.net/crazycoder8848/article/details/46333761 版权声明:本文没有任何版权限制,任何人可以以任何方式使用本文. htt ...
- Linux内核源码树建立加载hello模块
在加载模块之前,书中说要先建立内核源码树,那么,如何建立内核源码树呢? 首先,要先知道你的OS的内核版本,用uname -r可以查得到 在/url/src/目录下可以看到对应的版本目录 如果没有可以用 ...
- Linux内核,文件系统移植过程中出现的一些问题与解决办法
1.bootm地址和load address一样 此种情况下,bootm不会对uImage header后的zImage进行memory move的动作,而会直接go到entry point开始执行. ...
- Linux 内核设备注册
通常的注册和注销函数在: int device_register(struct device *dev); void device_unregister(struct device *dev); 我们 ...
- Linux 内核总线注册
如同我们提过的, 例子源码包含一个虚拟总线实现称为 lddbus. 这个总线建立它的 bus_type 结构, 如下: struct bus_type ldd_bus_type = { .name = ...
随机推荐
- 文件下载—SSH框架文件下载
1.准备下载的api组件 <dependency> <groupId>commons-io</groupId> <artifactId>commons- ...
- 2018-2019 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2018) Solution
A. Numbers Unsolved. B. Broken Watch Solved. 题意: 一个圆盘上,有等分的n块区域,有三根指针,当三根指针分别位于两块区域的交界处时 指针的三点相连会形成一 ...
- 能否通过六面照片构建3D模型?比如人脸,全身的多角度照片,生成3D模型。?
https://www.zhihu.com/question/36412840 9023 添加评论 分享 邀请回答举报 收起 已关注写回答 9 个回答 默认排序 叛逆者 计算机图形学 ...
- SQL Server2008创建数据库语法
use mastergo if exists(select * from sys.databases where name='MySchool') drop database MySchool -- ...
- 20145204 《Java程序设计》第7周学习总结
20145204 <Java程序设计>第7周学习总结 教材学习内容总结 时间 GMT.UT.TAI 格林威治标准时间(GMT)的正午是太阳抵达天空最高点之时,因为地球公转轨道为椭圆且速度不 ...
- RC 522模块在LINUX平台调试笔记
硬件平台: 1 主控:SMDK Exynos4412 POP S5M8767A 2 RFID模块:君盾集团提供的RC522模块 3 通信接口:SPI 软件平台:Android ICS & ke ...
- git如何在自动生成补丁时指定补丁名的起始编号
答:使用选项--start-number,用法如下: git format-patch 1f43be --start-number=2 这样就可以生成起始编号为2的补丁名,类似0002-me.patc ...
- atcoder ARC092 D - Two Sequences 二分 & 二进制
今天生日捏,嘻嘻~ 题意:给定A B数组长度为n 求所有 (1<=i,j <=n ) a[i]+b[j] 的异或和. n <=200000 ai bi <=228 这题比赛没 ...
- SQL语句主要的分类
SQL语言的命令通常分为四类1.数据定义语言(DDL) 创建.修改或删除数据库中各种对象,包括表.视图.索引等. 命令:CREATE TABLE , CREATE VIEW, CREATE INDEX ...
- callee 与 caller
arguments.callee 在函数内部指向函数本身 1.函数调用 function sum (num){ if(num <= 1){ return 1; }else{ return num ...