gpio子系统之2440
来源:互联网 发布:淘宝搞笑收货人名字 编辑:程序博客网 时间:2024/06/06 05:30
先看板级定义的结构体
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所起的作用,已经解释完了,其他的类似。
- gpio子系统之2440
- GPIO子系统
- Linux内核驱动之GPIO子系统
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- Linux内核驱动之GPIO子系统-GPIO的使用
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- Linux内核驱动之GPIO子系统GPIO的使用
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- Linux内核驱动之GPIO子系统-GPIO的使用
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- Linux内核驱动之GPIO子系统-GPIO的使用
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- Linux内核驱动之GPIO子系统(一)GPIO的使用
- Suggestion: add 'tools:replace="android:value"' to <meta-data> element 报错解决方案
- 【转载】MyBatis学习
- 关于Label中文字的居中
- ThinkPHP5 整合微信扫码支付
- poj-3744
- gpio子系统之2440
- 网络营销实战课-文案实操1
- rpm包创建以及yum仓库的创建应用简单版
- python 区分对象和字典
- JavaScript 严格模式(use strict)
- Web前端初学总结
- 详解Oracle临时表的几种用法及意义
- RTNETLINK answers: File exists
- node web框架之express简单认识