驱动学习之gpiolib的建立过程

1:gpiolib的学习重点

(1)gpiolib的建立过程:gpiolib和虚拟地址映射类似,也是需要一个建立

过程的,因此在学习的时候,我们需要明白gpiolib是什么时候建立的,建立函数在哪被调用的。

(2)gpiolib的使用方法:申请、使用、释放

(3)gpiolib的架构:涉及哪些目录的哪些文件

2:什么是gpiolib,为什么需要使用gpiolib

linux中从2.6.35以后就开始有gpiolib库了,gpiolib的作用是对所有的gpio实行统一管理,因为驱动在工作的时候,会出现好几个驱动共同使用同一个gpio的情况;这会造成混乱。所以内核提供了一些方法来管理gpio资源;

3:gpiolib的初始化函数

在我们的mach-smdkc110.c文件中的

smdkc110_map_io

s5pv210_gpiolib_init  这个函数是gpiolib的初始化函数

smdkc110_map_io这个函数的调用过程,在我们分析静态映射的时候已经分析了。

4:结构体struct s3c_gpio_chip

struct s3c_gpio_chip
 {
    struct gpio_chipchip;
    struct s3c_gpio_cfg*config;
    struct s3c_gpio_pm*pm;
    void __iomem*base;
    inteint_offset;
    spinlock_t lock;
    #ifdef CONFIG_PM
    u32pm_save[7];
    #endif
};

(1)这个结构体在arch/arm/palt-samsung/include/plat/gpio-core.h中

(2)一个s3c_gpio_chip结构体类型的变量就可以用来描述一个gpio端口(注意这里是一个端口,而不是一个IO口,一个端口里面可以有多个IO口(一般是一个端口有8个IO))

(3)需要struct gpio_chip结构体中的元素

const char *label;

这个元素是用来记录当前IO坐在的IO端口的名字,比如IO口GPA0.0所在的IO端口就是GPA0

(4)int base;

当前IO口所属的IO端口的编号,我们的gpiolib中 记录IO的方法是通过记录每一组IO的端口基础编号,然后通过一个IO的端口就在这个基准端口上叠加即可。

比如:

端口GPA0共有8个IO,IO口编号为0 -7,那么基准号就是0,也就是base = 0;

端口GPA1共有4个IO,IO口编号为8-11,那么基准号就是8,也就是base = 8;

5:s5pv210_gpio_4bit

(1)s5pv210_gpio_4bit是一个s3c_gpio_chip类型的结构体数组。

(2)将所有的gpio的.chip结构体中的一些元素初始化,这个数组的所有元素是与数据手册中的所有gpio是一一对应的。

(4)分析可知,这个数组就是对当前MPU中的所有的IO端口和每个端口的IO口进行了统一的描述,有了这个数组, 我们就知道当前开发板有多少个端口,有多少个IO口,以及每个IO口的编号。

6:s5pv210_gpiolib_init

__init int s5pv210_gpiolib_init(void)
{
    struct s3c_gpio_chip *chip = s5pv210_gpio_4bit;
    int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);
    int i = 0;
    for (i = 0; i < nr_chips; i++, chip++)
     {
        if (chip->config == NULL)
        chip->config = &gpio_cfg;
        if (chip->base == NULL)
        chip->base = S5PV210_BANK_BASE(i);
    }
    samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);

    return 0;
}

(1)通过上面的分析可知,s5pv210_gpiolib_init这个函数的作用是将我们开发板中所有GPIO的端口进行一个配置,并且为所有GPIO端口分配一个基准端口的虚拟地址,通过这个基准地址就能得到这组端口中所有IO口的寄存器的地址。

(2)我们之前讲过,在我们的s5pv210_gpio_4bit这个数组中绑定了开发板中所有IO口的信息,int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);得到我们s5pv210_gpio_4bit数组的元素个数,然后调用samsung_gpiolib_add_4bit_chips这个函数,将开发板中的所有信息向我们的系统进行注册,这样系统就能知道当前系统中的所以IO口的信息。

7:samsung_gpiolib_add_4bit_chips

void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip,int nr_chips)
{
    for (; nr_chips > 0; nr_chips--, chip++)
     {
        samsung_gpiolib_add_4bit(chip);   //这里的chip指针+1实际上加的是一个元素
        s3c_gpiolib_add(chip);
    }
}

(1)经过分析,发现samsung_gpiolib_add_4bit内部其实并没有做gpiolib的注册工作,而是还在做填充,填充的是每一个GPIO被设置成输入模式/输出模式的操作方法。

(2)s3c_gpiolib_add

__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
{
    struct gpio_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);
    if (ret >= 0)
    s3c_gpiolib_track(chip);
}

(1)首先我们在前面的分析可知,在samsung_gpiolib_add_4bit函数中,已经添加了我们的input和output方法,所以这里的if不会成立,并且分析函数可知,这里挂接的input和output方法是针对2bit的CON寄存器的芯片(2440)。

(2)这个函数首先是对我们的GPIO进行进一步的填充,主要是添加set和get的方法。

(3)调用gpiochip_add函数来完成真真的注册。

时间: 2024-10-28 01:55:57

驱动学习之gpiolib的建立过程的相关文章

linux驱动学习之tasklet分析

tasklet是中断处理下半部分最常用的一种方法,驱动程序一般先申请中断,在中断处理函数内完成中断上半部分的工作后调用tasklet.tasklet有如下特点: 1.tasklet只可以在一个CPU上同步地执行,不同的tasklet可以在不同地CPU上同步地执行. 2.tasklet的实现是建立在两个软件中断的基础之上的,即HI_SOFTIRQ和TASKLET_SOFTIRQ,本质上没有什么区别,只不过HI_SOFTIRQ的优先级更高一些 3.由于tasklet是在软中断上实现的,所以像软中断一

Linux驱动之平台设备驱动模型简析(驱动分离分层概念的建立)

Linux设备模型的目的:为内核建立一个统一的设备模型,从而有一个对系统结构的一般性抽象描述.换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要新添加设备或驱动提供一般性的统一接口,这使得驱动程序的开发变得更简单了,而程序员只需要去学习接口就行了. 对于整个设备总线驱动模型的样子,如下图.简单来说,bus 负责维护注册进来的devcie 与 driver,每注册进来一个device 或者 driver 都会调用 Bus->match 函数

PCM data flow - part 6: 声卡和PCM设备的建立过程

前面几章分析了Codec.Platform.Machine驱动的组成部分及其注册过程,这三者都是物理设备相关的,大家应该对音频物理链路有了一定的认知.接着分析音频驱动的中间层,由于这些并不是真正的物理设备,故我们称之为逻辑设备. PCM逻辑设备,我们又习惯称之为PCM中间层或pcm native,起着承上启下的作用:往上是与用户态接口的交互,实现音频数据在用户态和内核态之间的拷贝:往下是触发codec.platform.machine的操作函数,实现音频数据在dma_buffer<-> cpu

第十七篇:实例分析(3)--初探WDDM驱动学习笔记(十)

续: 还是记录一下, BltFuncs.cpp中的函数作用: CONVERT_32BPP_TO_16BPP 是将32bit的pixel转换成16bit的形式. 输入是DWORD 32位中, BYTE 0,1,2分别是RGB分量, 而BYTE3则是不用的 为了不减少color的范围, 所以,都是取RGB8,8,8的高RGB5, 6, 5位, 然后将这16位构成一个pixel. CONVERT_16BPP_TO_32BPP是将16bit的pixel转换成32bit的形式 输入是WORD 16BIT中

第十七篇:实例分析(4)--初探WDDM驱动学习笔记(十一)

感觉有必要把 KMDDOD_INITIALIZATION_DATA 中的这些函数指针的意思解释一下, 以便进一步的深入代码. DxgkDdiAddDevice 前面已经说过, 这个函数的主要内容是,将BASIC_DISPLAY_DRIVER实例指针存在context中, 以便后期使用, 支持多实例. DxgkDdiStartDevice 取得设备信息, 往注册表中加入内容, 从POST设备中获取FRAME BUFFER以及相关信息(DxgkCbAcquirePostDisplayOwnershi

linux 驱动学习

大端模式:低字节存高地址,高字节存低地址 小端模式:高字节存高地址,低字节存低地址 Mkfile: 1,多个源文件编译成一个ko Eg:obj-m+= hello.o Hello-objs +=test.o add.o 一设备文件 1,设备文件手动创建:如:mknod /dev/XX c 250 0 2,得到设备号:MKDEV(主号,次号): 自动创建:class_create(); Driver_create(); 生成设备文件有两种方法: 1)新:定义主次设备号----->定义设备名----

Linux驱动学习步骤(转载)

1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, lsmod, rmmod. 在驱动的init函数里打印hello world, insmod后应该能够通过dmesg看到输出. 5. 写一完整驱动, 加上read, write, ioctl, polling等各种函数的驱动实现. 在ioctl里完成从用户空间向内核空间传递结构体的实现. 6. 写一bl

linux内核驱动学习(八)----驱动分类 | 学习方法 | 硬件访问

驱动分类: 对于驱动,我们一般按两种方法进行分类:常规分类法和总线分类法. 按照常规分类法,可以分为以下三类: 1.字符设备: 以字节为最小访问单位的设备.一般通过字符设备文件来访问字符设备驱动程序.字符驱动程序则负责驱动字符设备, ,这样的驱动通常支持open.close.read.write系统调用,应用程序可以通过设备文件(比如/dev/ttySAC0等)来访问字符设备(串口).例如:串口\led\按键 2.块设备: 以块(一般512字节)为最 小传输单位的设备.大多数UNIX系统中,块设

从自我学习到深层网络——建立你的第1个深度网络分类器

自我学习就是稀疏编码器串联一个Softmax分类器,上一节看到,训练400次,准确率为98.2% 在此基础上,我们可以搭建我们的第一个深度网络:栈式自编码(2层)+Softmax分类器 简单地说,我们把稀疏自编码器的输出作为更高一层稀疏自编码器的输入. 和自我学习很像,似乎就是新加了一层,但是其实不然: 新技巧在于,我们这里有个微调的过程,让残差从最高层向输入层传递,微调整个网络权重. 这个微调对于网络性能的提高非常明显,实际上后面将会看到. 网络结构如图所示: 图1 预先加载 minFunc