字符设备驱动(1)代码分析---之gpio_get_value()

在中断处理函数中,调用gpio_get_value/gpio_set_value()函数来获取/设置gpio端口的值,在这里简单分析一下内核的实现流程。

tmp = gpio_get_value(S5PV210_GPH2(0));
#define gpio_get_value    __gpio_get_value
int __gpio_get_value(unsigned gpio)
{
    struct gpio_chip    *chip;
    int value;
    chip = gpio_to_chip(gpio);

    ##
        {
         .base    = (S5P_VA_GPIO + 0xC40),
         .config    = &gpio_cfg_noint,
         .irq_base = IRQ_EINT(16),
            .chip    = {
            .base    = S5PV210_GPH2(0),
            .ngpio    = S5PV210_GPIO_H2_NR,
            .label    = "GPH2",
            .to_irq = samsung_gpiolib_to_irq,
        },
    ##

    value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
    //offset = gpio - chip->base
    trace_gpio_value(gpio, 1, value);
    return value;

    ##
/****************************************************
    chip->get()函数的内核实现
****************************************************/
    //drivers/gpio/gpio-plat-samsung.c
    void __init samsung_gpiolib_add_4bit_chips
            (structs 3c_gpio_chip *chip,int nr_chips)
    {
        for (; nr_chips > 0; nr_chips--, chip++) {
            samsung_gpiolib_add_4bit(chip);
            s3c_gpiolib_add(chip);
        }
    }

    void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
    {
        chip->chip.direction_input = samsung_gpiolib_4bit_input;
        chip->chip.direction_output = samsung_gpiolib_4bit_output;
        chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
    }

    //arch/arm/plat_samsung/gpio.c
    __init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
    {
        struct gpio_chip *gc = &chip->chip;
        int ret;
        ....
        ....

        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;
        //至此完善后的结构体gc变为:

  gc = {
         .base    = (S5P_VA_GPIO + 0xC40),
         .config    = &gpio_cfg_noint,
         .irq_base = IRQ_EINT(16),
         .pm = __gpio_pm(&s3c_gpio_pm_4bit),
            .chip    = {
            .base    = S5PV210_GPH2(0),
            .ngpio    = S5PV210_GPIO_H2_NR,
            .label    = "GPH2",
            .to_irq = samsung_gpiolib_to_irq,
            .direction_input = samsung_gpiolib_4bit_input,
            .direction_output = samsung_gpiolib_4bit_output,
            .set = s3c_gpiolib_set,
            .get = s3c_gpiolib_get,
            },

gc

        ###

//samsung_gpiolib_4bit_input具体实现函数

 static int samsung_gpiolib_4bit_input(struct gpio_chip *chip,
                      unsigned int offset)
            {
                struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
                void __iomem *base = ourchip->base;
                unsigned long con;

                con = __raw_readl(base + GPIOCON_OFF);
                con &= ~(0xf << con_4bit_shift(offset));
                __raw_writel(con, base + GPIOCON_OFF);

                gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);

                return 0;
            }

samsung_gpiolib_4bit_input

static int samsung_gpiolib_4bit_output(struct gpio_chip *chip,
                                   unsigned int offset, int value)
            {
                struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
                void __iomem *base = ourchip->base;
                unsigned long con;
                unsigned long dat;

                con = __raw_readl(base + GPIOCON_OFF);
                con &= ~(0xf << con_4bit_shift(offset));
                con |= 0x1 << con_4bit_shift(offset);

                dat = __raw_readl(base + GPIODAT_OFF);

                if (value)
                    dat |= 1 << offset;
                else
                    dat &= ~(1 << offset);
                //有点小疑问:为啥要写两次数据???
                __raw_writel(dat, base + GPIODAT_OFF);
                __raw_writel(con, base + GPIOCON_OFF);
                __raw_writel(dat, base + GPIODAT_OFF);

                gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);

                return 0;
            }

samsung_gpiolib_4bit_output

    //s3c_gpiolib_set、s3c_gpiolib_get的具体实现函数

static void s3c_gpiolib_set(struct gpio_chip *chip,
                unsigned offset, int value)
            {
                struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
                void __iomem *base = ourchip->base;
                unsigned long flags;
                unsigned long dat;

                s3c_gpio_lock(ourchip, flags);

                dat = __raw_readl(base + 0x04);
                //将需要设定的位清零
                dat &= ~(1 << offset);
                //如果设定的值是1,则将相应位置1
                if (value)
                    dat |= 1 << offset;
                __raw_writel(dat, base + 0x04);

                s3c_gpio_unlock(ourchip, flags);
            }

s3c_gpiolib_set

static int s3c_gpiolib_get(struct gpio_chip *chip, unsigned offset)
            {
                struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
                unsigned long val;

                val = __raw_readl(ourchip->base + 0x04);
                //将需要获取的位右移至最低位
                val >>= offset;
                //获取最低位的值并返回
                val &= 1;
                return val;
            }

s3c_gpiolib_get




        ###

        ....
    }
    ##

}

原文地址:https://www.cnblogs.com/embeded-linux/p/11094088.html

时间: 2024-10-15 16:35:47

字符设备驱动(1)代码分析---之gpio_get_value()的相关文章

Linux内核分析(五)----字符设备驱动实现

原文:Linux内核分析(五)----字符设备驱动实现 Linux内核分析(五) 昨天我们对linux内核的子系统进行简单的认识,今天我们正式进入驱动的开发,我们今后的学习为了避免大家没有硬件的缺陷,我们都会以虚拟的设备为例进行学习,所以大家不必害怕没有硬件的问题. 今天我们会分析到以下内容: 1.      字符设备驱动基础 2.      简单字符设备驱动实现 3.      驱动测试 l  字符设备基础 1.       字符设备描述结构 在linux2.6内核中,使用cdev结构体描述一

LCD驱动分析(一)字符设备驱动框架分析

LCD驱动也是字符设备驱动,也遵循字符设备驱动的流程: a. 分配主设备号 b. 构建file_operations结构体中的open,write,read...等函数 c. 调用register_chrdev()函数注册字符设备 d. 调用class_register()注册类 e. 调用device_create()创建设备,linux会在sysfs目录下自动创建字符设备. 以上的步骤同样适用于分析输入子系统,只不过上面的各个步骤可能分散在不同的文件与函数中完成. 1.linux/drive

LDD3 字符设备驱动简单分析

最近在看LDD3,理解了一下,为了加深自己的印象,自己梳理一下.我用的CentOS release 6.6 (Final)系统. 一.编写编译内核模块的Makefile 以下是我用的Makefile ifneq ($(KERNELRELEASE),) # 第一次被调用时,KERNELRELEASE为空,所以不会被执行 obj-m := scull.o else # 将内核编译用的Makefile路径赋值给KERNELRELEASE KERNELRELEASE ?= /lib/modules/`u

linux字符设备驱动

一.字符设备.字符设备驱动与用户空间访问该设备的程序三者之间的关系. 如图,在Linux内核中使用cdev结构体来描述字符设备,通过其成员dev_t来定义设备号(分为主.次设备号)以确定字符设备的唯一性.通过其成员file_operations来定义字符设备驱动提供给VFS的接口函数,如常见的open().read().write()等. 在Linux字符设备驱动中,模块加载函数通过register_chrdev_region( ) 或alloc_chrdev_region( )来静态或者动态获

字符设备驱动模型

1.设备描述结构cdev驱动模型种类繁多,这就需要我从众多的模型中提取出他们的一些共性:a.驱动初始化a.1 分配设备描述结构a.2 初始化设备描述结构a.3 注册设备描述结构a.4 硬件初始化b.实现设备操作c.驱动注销 ------------------------------------------------------------------ 设备描述结构:在任何一种驱动模型中,设备都会用的内核中的一种结构来描述,我们的字符设备在内核中使用struct cdev 来来描述.struc

Linux字符设备驱动剖析

一.先看看设备应用程序 1.很简单,open设备文件,read.write.ioctl,最后close退出.如下: intmain(int argc ,char *argv[]){ unsigned char val[1] = 1; int fd =open("/dev/LED",O_RDWR);//打开设备 write(fd,val,1);//写入设备,这里代表LED全亮 close(fd);//关闭设备 return 0; } 二./dev目录与文件系统 2./dev是根文件系统下

字符设备驱动、平台设备驱动、设备驱动模型、sysfs的关系

Linux驱动开发的童鞋们来膜拜吧:-)  学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关联的分析.对于开发者而言,能够熟悉某一点并分享出来已很难得,但对于专注传授技术和经验给

深入浅出~Linux设备驱动之字符设备驱动

一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的字符设备有鼠标.键盘.串口.控制台和LED设备等. 块设备:是指可以从设备的任意位置读取一定长度数据的设备.块设备包括硬盘.磁盘.U盘和SD卡等. 每一个字符设备或块设备都在/dev目录下对应一个设备文件.linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备和块设备

Linux应用程序访问字符设备驱动详细过程解析

下面先通过一个编写好的内核驱动模块来体验以下字符设备驱动 可以暂时先忽略下面的代码实现! memdev.c #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/uaccess.h> int dev1_registers[5]; int dev2_registers[5]; stru

linux字符设备驱动程序源码分析

本文主要分析linux-2.6.28内核版本的字符设备抽象层源码文件char_dev.c.该文件代码量不大,但其为linux应用程序访问实际字符型硬件设备搭建了桥梁,进一步限定了linux字符设备驱动的设计框架. void __init chrdev_init(void) {  cdev_map = kobj_map_init(base_probe, &chrdevs_lock);  bdi_init(&directly_mappable_cdev_bdi); } 该函数在系统初始化启动时