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 = ...
随机推荐
- 2017-2018-2 20165207实验二《Java面向对象程序设计》实验报告
2017-2018-2 20165207实验二<Java面向对象程序设计>实验报告 课程:Java程序设计 班级:1652 姓名:李天林 学号:20165207 实验日期:2018年4月1 ...
- 使用cronolog工具给tomcat进行日志切割
关于cronolog的用法查看:https://www.freebsd.org/cgi/man.cgi?query=cronolog&apropos=0&sektion=0&m ...
- HDU 3339 In Action(最短路+背包)题解
思路:最短路求出到每个点的最小代价,然后01背包,求出某一代价所能拿到的最大价值,然后搜索最后结果. 代码: #include<cstdio> #include<set> #i ...
- [kata]数值内3和5的倍数的总和求解
这个题是这样的,方法参数接受一个数值,以3,5为基数,返回小于这个参数的3,5的倍数,加上3,5本身总和. 朋友段帅说头疼,估计是天气原因吧,好起来吧,还得战斗呢.
- Tensorflow1.5.0+cuda9.0+cudnn7.0+gtx1080+ubuntu16.04
目录 Tensorflow1.5.0+cuda9.0+cudnn7.0+gtx1080+ubuntu16.04 0. 前记 1. 环境说明 2. 安装GTX1080显卡驱动 3. CUDA 9.0安装 ...
- 2012NOIP模拟试题
做的时候觉得这套题好简单,结果一看发现是2012年的模拟题,估计就是普及+的难度吧,AK无压力 总结 第一题状压我智障的调了好几分钟,因为我的最终状态写的1<<n,智障了 第三题的dfs调 ...
- BZOJ 2342: 【SHOI2011】 双倍回文
题目链接:双倍回文 回文自动机第二题.构出回文自动机,那么一个回文串是一个“双倍回文”,当且仅当代表这个串的节点\(u\)顺着\(fail\)指针往上跳,可以找到一个节点\(x\)满足\(2len_x ...
- QtWebKit_cookie
1.百度搜索“qtwebkit cookie” 2. 2.1.qtwebkit 里 cookie 信息的保存 http://blog.tianya.cn/post-227188-33378112-1. ...
- Java 字节的常用封装
一. Java 的字节 byte (字节) 是 Java 中的基本数据类型,一个 byte 包含8个 bit(位),byte 的取值范围是-128到+127. byte 跟 Java 其他基本类型的关 ...
- 51nod1347思维
1347 旋转字符串 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 收藏 关注 S[0...n-1]是一个长度为n的字符串,定义旋转函数Left(S)=S[1… ...