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. Bootstrap fileinput v3.0(ssm版)

    说明在上一个版本即Bootstrap fileinput v2.0(ssm版)的基础上,增加了多处都需要上传的需求 核心代码ArticleController.java package com.isd ...

  2. Educational Codeforces Round 56 Solution

    A. Dice Rolling 签到. #include <bits/stdc++.h> using namespace std; int t, n; int main() { scanf ...

  3. python: 随机选择

    想从一个序列中随机抽取若干元素,或者想生成几个随机数. random 模块有大量的函数用来产生随机数和随机选择元素.比如,要想从一个序列中随机的抽取一个元素,可以使用random.choice() : ...

  4. Linux 笔记 #04# Installing Tomcat 8 on Debian

    失败一 ※ 失败二  ※ 失败三 ※ 完 1- 确认机型: root@iZwz:~# lsb_release -a LSB Version: core-2.0-amd64:core-2.0-noarc ...

  5. Linux内核分析06

    进程的描述和进程的创建 一,进程的描述 进程控制块PCB——task_struct (进程描述符),为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息. struc ...

  6. (转载)Ubuntu 16.04+1080Ti机器学习基本环境配置

    转载自:https://blog.csdn.net/mahonesun/article/details/80808930 一.设置网络 机器有两张网卡,将当前正在使用的"有线连接1" ...

  7. HDU 1503 Advanced Fruits(LCS+记录路径)

    http://acm.hdu.edu.cn/showproblem.php?pid=1503 题意: 给出两个串,现在要确定一个尽量短的串,使得该串的子串包含了题目所给的两个串. 思路: 这道题目就是 ...

  8. spark 累加历史 + 统计全部 + 行转列

    spark 累加历史主要用到了窗口函数,而进行全部统计,则需要用到rollup函数 1  应用场景: 1.我们需要统计用户的总使用时长(累加历史) 2.前台展现页面需要对多个维度进行查询,如:产品.地 ...

  9. H5 canvas控制坦克移动2

    接着上一篇(http://www.cnblogs.com/zhouhuan/p/H5_tankgame2.html),这篇主要修复两个bug,第一,玩家按下方向键时,坦克的炮筒应该指向相应的方向,并向 ...

  10. Java中HashMap的put与get方法原理

    直接上代码 注: 代码来自于 Java 9 put方法 public V put(K key, V value) { return putVal(hash(key), key, value, fals ...