友坚4412开发板基于Timed_out框架的GPIO驱动分析

Timed GPIO驱动程序分析

Timed GPIO驱动程序是android系统基于linux内核新增加的一类驱动程序,这类驱动程序主要是运用了内核定时器,与内核定时器进行绑定,使得控制GPIO口的高低电平与时间打上关系,既可以实现在一定的时间实现GPIO口为高或者低电平。Timed GPIO驱动被实现为平台设备驱动,Timed GPIO驱动源码位于如下目录:\kernel\drivers\staging\android

Timed GPIO驱动程序主要包括如下几个文件:

Timed_gpio.c

Timed_gpio.h

Timed_output.c

Timed_output.h

Timed_gpio.c文件为具体的驱动程序,Timed_output.c为向sys文件系统注册类的框架代码,

下面将具体分析每一个文件的作用及实现的具体功能。

首先分析注册类的框架代码 :Timed_output.c   Timed_output.h

Timed_output.h文件分析:

struct timed_output_dev {

const char *name;

void  (*enable)(struct timed_output_dev *sdev, int timeout);

int  (*get_time)(struct timed_output_dev *sdev);

struct device *dev;

int  index;

int  state;

};

extern int timed_output_dev_register(struct timed_output_dev *dev);

extern void timed_output_dev_unregister(struct timed_output_dev *dev);

Timed_output.h文件主要定义了一个结构体timed_output_dev设备结构体,该结构体表示一个具体的设备,

Name:代表Time GPIO设备的名字,enable:为一个函数指针,主要用于设置定时器的过期时间,

Enable:用于获取离过期还剩余的时间。Index:为设备索引号,代表同一名字的设备的数量,state带表当前设备的状态值。

timed_output_dev_register,timed_output_dev_unregister这两个函数声明用于timed_output设备的注册和卸载。

Timed_output.c文件分析:

该文件主要用于向系统注册timed_output驱动程序框架,其中主要实现了Timed_output.h文件中定义的结构体及函数。

timed_output框架注册函数的实现,这个函数用于将驱动程序注册到kernel中,后面分析Timed GPIO驱动的具体实现时会调用此函数向系统注册Timed GPIO驱动。

int timed_output_dev_register(struct timed_output_dev *tdev)

{

int ret;

if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time)

return -EINVAL;

ret = create_timed_output_class(); 调用此函数在sys/class下生成timed_output类

if (ret < 0)

return ret;

tdev->index = atomic_inc_return(&device_count);

tdev->dev = device_create(timed_output_class, NULL,

MKDEV(0, tdev->index), NULL, tdev->name);

if (IS_ERR(tdev->dev))

return PTR_ERR(tdev->dev);

ret = device_create_file(tdev->dev, &dev_attr_enable);

if (ret < 0)

goto err_create_file;

dev_set_drvdata(tdev->dev, tdev);

tdev->state = 0;

return 0;

err_create_file:

device_destroy(timed_output_class, MKDEV(0, tdev->index));

printk(KERN_ERR "timed_output: Failed to register driver %s\n",

tdev->name);

return ret;

}

此函数用于在sys/class下面创建类,类的名字为timed_output

static int create_timed_output_class(void)

{

if (!timed_output_class) {

timed_output_class = class_create(THIS_MODULE, "timed_output");

if (IS_ERR(timed_output_class))

return PTR_ERR(timed_output_class);

atomic_set(&device_count, 0);

}

return 0;

}

其中下面两个函数最为关键,是内核空间和用户空间的传值过程的具体实现函数,

enable_show函数调用get_time函数并将返回的剩余时间写入buf并传递到用户空间。

static ssize_t enable_show(struct device *dev, struct device_attribute *attr,

char *buf)

{

struct timed_output_dev *tdev = dev_get_drvdata(dev);

int remaining = tdev->get_time(tdev);

return sprintf(buf, "%d\n", remaining);

}

enable_store函数用于将用户空间传递来的buf值写入内核空间。

static ssize_t enable_store(

struct device *dev, struct device_attribute *attr,

const char *buf, size_t size)

{

struct timed_output_dev *tdev = dev_get_drvdata(dev);

int value;

if (sscanf(buf, "%d", &value) != 1)

return -EINVAL;

tdev->enable(tdev, value);

return size;

}

Timed_gpio.h文件分析:

#ifndef _LINUX_TIMED_GPIO_H

#define _LINUX_TIMED_GPIO_H

#define TIMED_GPIO_NAME "timed-gpio" //Time_GPIO驱动的名字,将显示在/sys/class/ timed_output目录下

struct timed_gpio {

const char *name; //GPIO的名字

unsigned  gpio; //具体的GPIO管脚

int  max_timeout;//最大的超时时间

u8   active_low; //IO口电平状态表示位

};

timed_gpio结构体仅用于定义单个的GPIO的相关信息

gpio_platform_data结构体用于定义一组GPIO的相关信息

struct timed_gpio_platform_data {

int   num_gpios;

struct timed_gpio *gpios;

};

#endif

下面将分析具体的Timed_gpio驱动程序

timed_gpio_driver定义如下:

该函数指明了具体的初始化函数(pore)和移除函数(remove)以及驱动的名字额模块。

static struct platform_driver timed_gpio_driver = {

.probe  = timed_gpio_probe,

.remove  = timed_gpio_remove,

.driver  = {

.name  = TIMED_GPIO_NAME,

.owner  = THIS_MODULE,

},

};

调用platform_driver_register函数向kernel注册平台驱动

static int __init timed_gpio_init(void)

{

return platform_driver_register(&timed_gpio_driver);

}

timed_gpio探测函数

static int timed_gpio_probe(struct platform_device *pdev)

{

struct timed_gpio_platform_data *pdata = pdev->dev.platform_data;

struct timed_gpio *cur_gpio;

struct timed_gpio_data *gpio_data, *gpio_dat;

int i, j, ret = 0;

if (!pdata)

return -EBUSY; //为pdata->num_gpios个GPIO分配内存空间

gpio_data = kzalloc(sizeof(struct timed_gpio_data) * pdata->num_gpios,

GFP_KERNEL);

if (!gpio_data)

return -ENOMEM;

for (i = 0; i < pdata->num_gpios; i++) {

cur_gpio = &pdata->gpios[i];

gpio_dat = &gpio_data[i];

hrtimer_init(&gpio_dat->timer, CLOCK_MONOTONIC,//初始化定时器

HRTIMER_MODE_REL);

gpio_dat->timer.function = gpio_timer_func;//定时器回调函数

spin_lock_init(&gpio_dat->lock);

gpio_dat->dev.name = cur_gpio->name;

gpio_dat->dev.get_time = gpio_get_time;

gpio_dat->dev.enable = gpio_enable;

ret = gpio_request(cur_gpio->gpio, cur_gpio->name);//申请GPIO

if (ret >= 0) {

ret = timed_output_dev_register(&gpio_dat->dev);//调用timed_output框架注册函数

if (ret < 0)

gpio_free(cur_gpio->gpio);

}

if (ret < 0) {

for (j = 0; j < i; j++) {

timed_output_dev_unregister(&gpio_data[i].dev);

gpio_free(gpio_data[i].gpio);

}

kfree(gpio_data);

return ret;

}

gpio_dat->gpio = cur_gpio->gpio;

gpio_dat->max_timeout = cur_gpio->max_timeout;

gpio_dat->active_low = cur_gpio->active_low;

gpio_direction_output(gpio_dat->gpio, gpio_dat->active_low);//初始化GPIO的输出值

}

platform_set_drvdata(pdev, gpio_data);

return 0;

}

初始化过程:

1. 首先调用kzalloc函数为 GPIO分配内存空间

2. 调用hrtimer_init函数初始化化内核定时器

3. 设置GPIO的enable函数为gpio_enable

4. 设置GPIO的get_time函数为gpio_get_time

5. 调用timed_output_dev_register函数注册设备驱动。

6. 初始化timed_gpio_data结构体

7. 调用gpio_direction_output函数设置GPIO的初始值。

GPIO驱动移除函数,调用timed_output_dev_unregister卸载驱动程序

static int timed_gpio_remove(struct platform_device *pdev)

{

struct timed_gpio_platform_data *pdata = pdev->dev.platform_data;

struct timed_gpio_data *gpio_data = platform_get_drvdata(pdev);

int i;

for (i = 0; i < pdata->num_gpios; i++) {

timed_output_dev_unregister(&gpio_data[i].dev);

gpio_free(gpio_data[i].gpio);

}

kfree(gpio_data);

return 0;

}

功能回调函数gpio_timer_func分析:定时器超时后将执行此函数,此函数根据active_low的值来设置GPIO的高低电平。

static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer)

{

struct timed_gpio_data *data =

container_of(timer, struct timed_gpio_data, timer);

gpio_direction_output(data->gpio, data->active_low ? 1 : 0);

return HRTIMER_NORESTART;

}

gpio_enable函数为关键函数接受用户空间传过来的value值用于在一定时间里控制GPIO

static void gpio_enable(struct timed_output_dev *dev, int value)

{

struct timed_gpio_data *data =

container_of(dev, struct timed_gpio_data, dev);

unsigned long flags;

spin_lock_irqsave(&data->lock, flags);

/* cancel previous timer and set GPIO according to value */

hrtimer_cancel(&data->timer);

gpio_direction_output(data->gpio, data->active_low ? !value : !!value);

if (value > 0) {

if (value > data->max_timeout)

value = data->max_timeout;

//启动定时器函数

hrtimer_start(&data->timer,

ktime_set(value / 1000, (value % 1000) * 1000000),

HRTIMER_MODE_REL);

}

spin_unlock_irqrestore(&data->lock, flags);

}

到这里相信大家对Time GPIO驱动已经用了深刻的印象和认识。下面将用一幅图来说明整个Time GPIO驱动的调用过程。以总结回顾前面的分析。

读者可以根据我的分析结合源代码具体了解每一步的调用过程。

注:以上整个过程实现了并创建了设备节点/sys/class/timed_output/timed-gpio

时间: 2024-10-16 05:00:54

友坚4412开发板基于Timed_out框架的GPIO驱动分析的相关文章

友坚4412开发板怎样在source insight中使汇编代码高亮显示?

友坚4412开发板怎样在source insight中使汇编代码高亮显示?4412开发板 做ARM嵌入式开发时,有时得整汇编代码,但在SIS里建立PROJECT并ADD TREE的时候,根据默认设置并不会把该TREE里面所有汇编文件都包含进来,默认只加了.inc和.asm后缀的, .s后缀的没有.而且用SIS打开.s的文件时,一片黑白没有色彩, 感觉回到DOS的EDIT时代里了. 解决方法是在Options->Document Options里面,点左上的Document Type下拉菜单,选择

4412开发板三星cortex-A9四核开发板友坚科技

UT4412BV03开发板介绍 4412开发板三星cortex-A9四核开发板友坚科技 友坚恒天科技urbetter.net专注于三星平台产品的研发,是三星在中国最具实力的方案公司.公司主打的三星平板电脑方案销量,连续多年稳居第一.公司定位于中高端产品的研发,具有多年的嵌入式产品研发经验:基于三星 A15-Exynos 5250.A9-Exynos 4412.A8-S5PV210.ARM11-S3C6410.ARM9-S3C2416等处理器,开发了系列化的产品,为客户提供了全面的产品选择及专业化

【嵌入式4412开发板学习教程】Uboot教程之uboot基础概念和框架

[4412开发板教程]Uboot教程之uboot基础概念和框架 正在学习uboot,教程讲解的很详细,先上个笔记,视频上传到网盘后再补上...... 知识点: 1.操作系统分层的概念 Windows:bios→内核模式→用户模式→用户程序 linux:bootloader→内核→文件系统→用户程序 2.bootboader种类介绍 U-boot是最通用的bootboader.(210,4412等等) vivi 针对三星的ARM来定制2440上有用到 3.4412休眠问题 它可以直接跳过uboot

基于讯为4412开发板的Android开发流程

讯为4412开发板  使用三星2410芯片,基于arm9架构,由于自己电脑硬件的局限,只能跑Android4.0.3系统. 1.Uboot这个直接使用官方镜像烧写就可以了,一般情况不用去重复烧写. 略. 烧写命令:fastboot.exe flash bootloader u-boot-iTOP-4412.bin 2.linux Kernel 1)设备驱动 --字符设备驱动 --杂项设备驱动 --I2C设备驱动(两种模式 a,linux内部i2c体系 包括两部分:i2c设备驱动与i2c总线驱动,

4412开发板支持GPS高强度信号

三星Exynos 4412开发板支持GPS高强度信号,GPS信号强度可达50dbm 2012年,三星正式推出了自家的首款四核移动处理器Exynos 4412. 这款新Exynos A9 四核处理器,拥有4枚主频为1.4-1.6 GHz的Cortex-A9通用处理核心,拥有32/32 KB I/D Cache, 1 MB L2 Cache, 并且集成ARM Mali 400 MP图形处理核心,而且三星公司已将这颗图形处理器主频由此前的266MHz提升至400MHz: 采用32nm HKMG(高K金

4412开发板疯狂大促销,团购火热进行中

特大喜讯:九鼎创展全新四核x4412开发板正值上市推广期,特拿出100套开发板进行团购疯狂大促销,仅此100套,卖完即恢复原价.团购QQ群:16073601 团购优惠价: x4412开发板+7寸高清电容屏[1024*600]=699元 x4412开发板+7寸高清电容屏[1024*600]+优质红外遥控器[提供源码]=699元 x4412开发板+7寸高清电容屏[1024*600]+优质红外遥控器[提供源码]+USB WIFI=699元 x4412开发板+7寸高清电容屏[1024*600]+优质红外

[学习开发板怎么选]迅为4412开发板帮你入门嵌入式

丰富选配模块 入门视频教程(购买后提供完整版高清教程)部分视频观看地址: [视频教程]iTOP-4412开发板之学习方法--致初学者 http://v.youku.com/v_show/id_XNzQ5MDA4NzM2.html [视频教程]三星Exynos 4412处理器开发要点 http://v.youku.com/v_show/id_XNjIwODA0MTY4.html [视频教程]iTOP-4412开发板之如何扩展不同型号LCD屏 http://v.youku.com/v_show/id

4412开发板免费视频教程

4412开发板参数: CPU Exynos4412,四核Cortex-A9,主频为1.4GHz-1.6GHz 内存 1GB 双通道 DDR3(2GB 可选) 存储 4GB EMMC(16GB 可选) 电源管理 低功耗动态三星S5M8767电源管理,最优架构! 工作电压 2.65V--5.5V (推荐4.0V) 系统支持 Linux-QT5.7/Android 4.0.3 /Android 4.4/Ubuntu12.04操作系统 USB HOST 板载USB3503,引出高性能HSIC,实现2路U

嵌入式开发-迅为4412开发板QT鼠标和触摸的问题解决方案

迅为4412开发板-QT鼠标和触摸的问题解决方案: 一. 背景 在使用迅为提供的QT4.7的时候,鼠标可以正常使用,有触摸但是触摸会出现问题.尤其是在左右滑动qt界面的时候,总是会出现往左滑动,画面急速往右走,然而往右滑动,画面急速的往左走. 在使用迅为提供的Qtopia4的时候,只能用触摸不能用鼠标. 二.解决办法 ① QT4.7系统 打开/bin/qt4 找到这句话: export QWS_MOUSE_PROTO='MouseMan:/dev/input/mice Tslib:/dev/in