gpio子系统之2440

先看板级定义的结构体

struct s3c_gpio_chip s3c24xx_gpios[] = {
        [0] = {
                .base   = S3C2410_GPACON,
                .pm     = __gpio_pm(&s3c_gpio_pm_1bit),
                .config = &s3c24xx_gpiocfg_banka,
                .chip   = {
                        .base                   = S3C2410_GPA(0),
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOA",
                        .ngpio                  = 24,
                        .direction_input        = s3c24xx_gpiolib_banka_input,
                        .direction_output       = s3c24xx_gpiolib_banka_output,
                },
        },
        [1] = {
                .base   = S3C2410_GPBCON,
                .pm     = __gpio_pm(&s3c_gpio_pm_2bit),
                .chip   = {
                        .base                   = S3C2410_GPB(0),                   //32
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOB",
                        .ngpio                  = 16,
                },
        },
。。。。。。。。。。。。。。
        }, {
                .base   = S3C2443_GPMCON,
                .pm     = __gpio_pm(&s3c_gpio_pm_2bit),
                .chip   = {
                        .base                   = S3C2410_GPM(0),
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOM",
                        .ngpio                  = 2,
                },
        },
};

与平台相关的结构体s3c_gpio_chip,在板级配置端初始化了基地址和每个gpio控制器所管理的gpio数量等等。
在分析函数之前先来看一看S3C2410_GPA(0)
参考:http://blog.csdn.net/tang_jin_chan/article/details/12389069

.base           = S3C2410_GPA(0)  
#define S3C2410_GPA(_nr)    (S3C2410_GPIO_A_START + (_nr))  
enum s3c_gpio_number {  
    S3C2410_GPIO_A_START = 0,  
    S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),  
    S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),  
    S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),  
    S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),  
    S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),  
    S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),  
    S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),  
};  
#define S3C2410_GPIO_NEXT(__gpio) \  
    ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)  

#if CONFIG_S3C_GPIO_SPACE != 0  
#error CONFIG_S3C_GPIO_SPACE cannot be zero at the moment  
#endif   

这里的CONFIG_S3C_GPIO_SPAC是内核配置选项
CONFIG_S3C_GPIO_SPACE = 0

由此可以推知:
S3C2410_GPIO_A_START = 0
S3C2410_GPIO_B_START = S3C2410_GPIO_A_START + S3C2410_GPIO_A_NR + 0 + 0 = 0 + S3C2410_GPIO_A_NR + 0 + 0
其中,
、# define S3C2410_GPIO_A_NR (32)
所以,
S3C2410_GPIO_B_START = 0 + 32 + 0 + 0 = 32
因此,
对于gpio_chip_GPIOA:
.base = S3C2410_GPA(0) = S3C2410_GPIO_A_START + 0 = 0 + 0 = 0
对于gpio_chip_GPIOB:
.base = S3C2410_GPB(0) = S3C2410_GPIO_B_START + 0 = 32 + 0 = 32

这个.base在后面gpio_desc[id]数组填充时做参考。

下面分析具体函数。

static __init int s3c24xx_gpiolib_init(void)
{
        struct s3c_gpio_chip *chip = s3c24xx_gpios;
        int gpn;

        for (gpn = 0; gpn < ARRAY_SIZE(s3c24xx_gpios); gpn++, chip++) {   //ARRAY_SIZE(s3c24xx_gpios)表示控制器的数量
                if (!chip->config)
                        chip->config = &s3c24xx_gpiocfg_default;  //做配置各个控制器上的gpio引脚使用

                s3c_gpiolib_add(chip);               //注册
        }

        return 0;
}

调用 s3c_gpiolib_add函数

int gpiochip_add(struct gpio_chip *chip)
{
        unsigned long   flags;
        int             status = 0;
        unsigned        id;
        int             base = chip->base;

        if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))       //检验是否超过规定的引脚数量
                        && base >= 0) {
                status = -EINVAL;
                goto fail;
        }

        spin_lock_irqsave(&gpio_lock, flags);

        if (base < 0) {
                base = gpiochip_find_base(chip->ngpio);           //动态分配空闲gpio引脚,并将最后找到的gpio号定为base
                if (base < 0) {
                        status = base;
                        goto unlock;
                }
                chip->base = base;
        }

        /* these GPIO numbers must not be managed by another gpio_chip */
        for (id = base; id < base + chip->ngpio; id++) {               
                if (gpio_desc[id].chip != NULL) {                        //判断是否已经将chip赋值了
                        status = -EBUSY;
                        break;
                }
        }
        if (status == 0) {
                for (id = base; id < base + chip->ngpio; id++) {
                        gpio_desc[id].chip = chip;                        //将chip赋值,每一组gpio口使用的chip一样。

                        /* REVISIT:  most hardware initializes GPIOs as
                         * inputs (often with pullups enabled) so power
                         * usage is minimized.  Linux code should set the
                         * gpio direction first thing; but until it does,
                         * we may expose the wrong direction in sysfs.
                         */
                        gpio_desc[id].flags = !chip->direction_input
                                ? (1 << FLAG_IS_OUT)                        //对flag赋值
                                : 0;
                }
        }

unlock:
        spin_unlock_irqrestore(&gpio_lock, flags);
        if (status == 0)
                status = gpiochip_export(chip);                    //在/sys/class/下创建控制器gpiochip%d节点
fail:
        /* failures here can mean systems won't boot... */
        if (status)
                pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
                        chip->base, chip->base + chip->ngpio - 1,
                        chip->label ? : "generic");
        return status;
}
EXPORT_SYMBOL_GPL(gpiochip_add);
看看gpiochip_export这个函数

static int gpiochip_export(struct gpio_chip *chip)
{
        int             status;
        struct device   *dev;

        /* Many systems register gpio chips for SOC support very early,
         * before driver model support is available.  In those cases we
         * export this later, in gpiolib_sysfs_init() ... here we just
         * verify that _some_ field of gpio_class got initialized.
         */
        if (!gpio_class.p)
                return 0;

        /* use chip->base for the ID; it's already known to be unique */
        mutex_lock(&sysfs_lock);
        dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip,
                                "gpiochip%d", chip->base);                         //在/sys/class下创建gpiochip节点
        if (!IS_ERR(dev)) {
                status = sysfs_create_group(&dev->kobj,                        //在上面创建的节点下创建一些attr属性文件
                                &gpiochip_attr_group);
        } else
                status = PTR_ERR(dev);
        chip->exported = (status == 0);
        mutex_unlock(&sysfs_lock);

        if (status) {
                unsigned long   flags;
                unsigned        gpio;

                spin_lock_irqsave(&gpio_lock, flags);
                gpio = chip->base;
                while (gpio_desc[gpio].chip == chip)
                        gpio_desc[gpio++].chip = NULL;
                spin_unlock_irqrestore(&gpio_lock, flags);

                pr_debug("%s: chip %s status %d\n", __func__,
                                chip->label, status);
        }

        return status;
}

int sysfs_create_group(struct kobject *kobj,
                       const struct attribute_group *grp)
{
        return internal_create_group(kobj, 0, grp);
}


static int internal_create_group(struct kobject *kobj, int update,
                                 const struct attribute_group *grp)
{
        struct sysfs_dirent *sd;
        int error;

        BUG_ON(!kobj || (!update && !kobj->sd));

        /* Updates may happen before the object has been instantiated */
        if (unlikely(update && !kobj->sd))
                return -EINVAL;

        if (grp->name) {                                     //没有名字 ,所以执行下面的
                error = sysfs_create_subdir(kobj, grp->name, &sd);
                if (error)
                        return error;
        } else
                sd = kobj->sd;
        sysfs_get(sd);                                              //原子量计数
        error = create_files(sd, kobj, grp, update);                 //创建文件,里面把属性组的数据一个一个提取出来进行文件的创建。
        if (error) {
                if (grp->name)
                        sysfs_remove_subdir(sd);
        }
        sysfs_put(sd);
        return error;
}

在应用层除了gpiochip0,还有export等文件,如果需要导出gpio端口到用户空间,可以直接 echo 19 > export
撤销GPIO的导出 ,可以 echo 19 > unexport
可是这两个文件是哪里来的呢?drivers/gpio/gpiolib.c文件下有如下定义。
static struct class_attribute gpio_class_attrs[] = { //属性定义
__ATTR(export, 0200, NULL, export_store),
__ATTR(unexport, 0200, NULL, unexport_store),
__ATTR_NULL,
};

static struct class gpio_class = {
.name = “gpio”,
.owner = THIS_MODULE,

    .class_attrs =  gpio_class_attrs,

};

在gpiolib_sysfs_init函数中有status = class_register(&gpio_class)–》 __class_register–》add_class_attrs

static int add_class_attrs(struct class *cls)
{
        int i;
        int error = 0;

        if (cls->class_attrs) {
                for (i = 0; attr_name(cls->class_attrs[i]); i++) {
                        error = class_create_file(cls, &cls->class_attrs[i]);        //在类下创建文件节点
                        if (error)
                                goto error;
                }
        }
done:
        return error;
error:
        while (--i >= 0)
                class_remove_file(cls, &cls->class_attrs[i]);
        goto done;
}

参考:http://blog.csdn.net/mirkerson/article/details/8464290
既然在/sys/class/gpio/下有了export节点,怎么用呢?
如echo 19 > export
19这个数字存放在下面函数的buf中。

static ssize_t export_store(struct class *class,
                                struct class_attribute *attr,
                                const char *buf, size_t len)
{
        long    gpio;
        int     status;

        status = strict_strtol(buf, 0, &gpio);           //将buf中的数据格式转换后给gpio
        if (status < 0)
                goto done;

        /* No extra locking here; FLAG_SYSFS just signifies that the
         * request and export were done by on behalf of userspace, so
         * they may be undone on its behalf too.
         */

        status = gpio_request(gpio, "sysfs");         //申请这个引脚
        if (status < 0)
                goto done;

        status = gpio_export(gpio, true);               //下面看这个函数  
        if (status < 0)
                gpio_free(gpio);
        else
                set_bit(FLAG_SYSFS, &gpio_desc[gpio].flags);

done:
        if (status)
                pr_debug("%s: status %d\n", __func__, status);
        return status ? : len;
}

int gpio_export(unsigned gpio, bool direction_may_change)
{
        unsigned long           flags;
        struct gpio_desc        *desc;
        int                     status = -EINVAL;
        const char              *ioname = NULL;

        /* can't export until sysfs is available ... */
        if (!gpio_class.p) {
                pr_debug("%s: called too early!\n", __func__);
                return -ENOENT;
        }

        if (!gpio_is_valid(gpio))                           // 判断是否有效,即在规定引脚范围里面
                goto done;

        mutex_lock(&sysfs_lock);

        spin_lock_irqsave(&gpio_lock, flags);
        desc = &gpio_desc[gpio];                                   //从数组中取出gpio描述符
        if (test_bit(FLAG_REQUESTED, &desc->flags)                              // 判断是否已经被使用
                        && !test_bit(FLAG_EXPORT, &desc->flags)) {
                status = 0;
                if (!desc->chip->direction_input
                                || !desc->chip->direction_output)
                        direction_may_change = false;
        }
        spin_unlock_irqrestore(&gpio_lock, flags);

        if (desc->chip->names && desc->chip->names[gpio - desc->chip->base])
                ioname = desc->chip->names[gpio - desc->chip->base];          //没有定义,不被调用

        if (status == 0) {
                struct device   *dev;

                dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),           // 在类下创建设备gpio
                                desc, ioname ? ioname : "gpio%u", gpio);
                if (!IS_ERR(dev)) {
                        status = sysfs_create_group(&dev->kobj,                         // 在设备gpio下创建属性文件
                                                &gpio_attr_group);

                        if (!status && direction_may_change)    
                                status = device_create_file(dev,                           //  在设备gpio下创建属性文件
                                                &dev_attr_direction);

                        if (!status && gpio_to_irq(gpio) >= 0
                                        && (direction_may_change
                                                || !test_bit(FLAG_IS_OUT,
                                                        &desc->flags)))
                                status = device_create_file(dev,                       // 在设备gpio下创建属性文件
                                                &dev_attr_edge);

                        if (status != 0)
                                device_unregister(dev);
                } else
                        status = PTR_ERR(dev);
                if (status == 0)
                        set_bit(FLAG_EXPORT, &desc->flags);
        }

        mutex_unlock(&sysfs_lock);

done:
        if (status)
                pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);

        return status;
}
EXPORT_SYMBOL_GPL(gpio_export);
至此export所起的作用,已经解释完了,其他的类似。

猜你喜欢

转载自blog.csdn.net/qq_28219531/article/details/77453722
今日推荐