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注册建立过程的更多相关文章

  1. 结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程

    结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程 目录 结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程 一. 实验准备 二. 实验过程 I 分析中断上下文的切换 ...

  2. linux设备树的建立过程

    为了阐明表示总线.设备和设备驱动程序的各个数据结构之间彼此的关联,它们的注册过程是很有必要的.顺序一定是如下:(1)注册总线---bus_register:(2)注册设备device_register ...

  3. Linux内核树的建立-基于ubuntu系统

    刚看 O'REILLY 写的<LINUX 设备驱动程序>时.作者一再强调在编写驱动程序时必须 建立内核树.先前的内核只需要有一套内核头文件就够了,但因为2.6的内核模块吆喝内核源码树中的目 ...

  4. Xilinx-Zynq Linux内核源码编译过程

    本文内容依据http://www.wiki.xilinx.com网址编写,编译所用操作系统为ubuntu 14 1.交叉编译环境的安装配置 1)http://www.wiki.xilinx.com/I ...

  5. 代码学习-Linux内核网卡收包过程(NAPI)【转】

    转自:https://blog.csdn.net/crazycoder8848/article/details/46333761 版权声明:本文没有任何版权限制,任何人可以以任何方式使用本文. htt ...

  6. Linux内核源码树建立加载hello模块

    在加载模块之前,书中说要先建立内核源码树,那么,如何建立内核源码树呢? 首先,要先知道你的OS的内核版本,用uname -r可以查得到 在/url/src/目录下可以看到对应的版本目录 如果没有可以用 ...

  7. Linux内核,文件系统移植过程中出现的一些问题与解决办法

    1.bootm地址和load address一样 此种情况下,bootm不会对uImage header后的zImage进行memory move的动作,而会直接go到entry point开始执行. ...

  8. Linux 内核设备注册

    通常的注册和注销函数在: int device_register(struct device *dev); void device_unregister(struct device *dev); 我们 ...

  9. Linux 内核总线注册

    如同我们提过的, 例子源码包含一个虚拟总线实现称为 lddbus. 这个总线建立它的 bus_type 结构, 如下: struct bus_type ldd_bus_type = { .name = ...

随机推荐

  1. Java基础教程:注解

    Java基础教程:注解 本篇文章参考的相关资料链接: 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3 注解基础与高级应用:http: ...

  2. Django:提交表单时遇到403错误:CSRF verification failed

    Django:提交表单时遇到403错误:CSRF verification failed 问题: 提交表单时遇到403错误:CSRF verification failed 解决方案: 在表单界面ht ...

  3. Makefile解析(最简单的LED)

    ①led_sp.bin: start.o led.o #led_sp.bin是由 start.o 和 led.o 生成 ②arm-linux-ld -Ttext 0x0 -o led_sp.elf $ ...

  4. SqlBulkCopy 批量导入数据 转换表字段类型

    在使用SqlBulkCopy导入数据时,要有一个跟数据库里面同样的DataTable 要赋值表名 要求每个列跟数据库中列同名,并且列的类型要赋值跟数据库中列的类型对应的NET类型 要求数据库中为Nul ...

  5. Python——列表表达式

    https://www.cnblogs.com/xuyuanyuan123/p/6718403.html

  6. HDU - 5917 水题

    题意:n个点m条边,找点集个数,点集满足有任意三个点成环,或者三个点互不相连 题解:暴力复杂度O(n^5/120*O(ok))==O(能过) //#pragma comment(linker, &qu ...

  7. Leetcode 51

    //看了一次解析后,一次AC,用一个pos记录行列.class Solution { public: vector<vector<string>> solveNQueens(i ...

  8. ActiveX开发

    转自(http://blog.csdn.net/mingojiang/article/details/8159263) 一.ActiveX基础 1.1什么是ActiveX ActiveX是COM规范的 ...

  9. 设置Shader关键字高亮(网上转)

    原文链接:http://www.cnblogs.com/cg_ghost/archive/2011/11/30/2268734.html 经过试验,在VS2012有效. 1. 创建或编辑usertyp ...

  10. hdu 3262 09 宁波 现场 C - Seat taking up is tough 暴力 难度:0

    Description Students often have problems taking up seats. When two students want the same seat, a qu ...