先看板级定义的结构体
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
![](/qrcode.jpg)
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所起的作用,已经解释完了,其他的类似。