安卓系统的time device驱动编写过程

前言:

time device是Android系统中的一个定时设备驱动,对Android移动设备提供了定时控制的功能。time device分为timed output和timed gpio 两类。本篇blog蒋健基于dragonBoard410c的定时设备驱动开发基础知识和教大家怎么去定时控制一个GPIO口的高低电平。


一、Timed Output驱动架构

在Android系统中,timed output通常用于实现Vibrator驱动程序。Timed output驱动是基于sys文件系统实现的,能够对设备进行定时控制功能,目前支持设备有vibrator和led设备。timed output驱动会注册sys/class/timed_output/目录,每一个注册实现的timed outpput设备如vibrator和led将会在sys/class/timed_output/目录中新建一个和设备同名的子目录。在子目录中更有一个名为enable的子文件。通过对此文件的读写实现对设备的控制和显示功能。

在Android系统中,有如下连个实现timed output驱动的文件。

drivers/staging/android/timed_output.c

drivers/staging/android/timed_output.h


其中:timed_output.h的实现代码如下:

文件timed_output.h中定义了结构体timed_output_dev,使设备设置定时器功能,并手机返回定时器的剩余时间。


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.c代码实现如下:


static struct class *timed_output_class;
static atomic_t device_count;


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);
}

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;
}

static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);

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;
}

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();
        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));
        pr_err("failed to register driver %s\n",
                        tdev->name);

        return ret;
}
EXPORT_SYMBOL_GPL(timed_output_dev_register);

void timed_output_dev_unregister(struct timed_output_dev *tdev)
{
        tdev->enable(tdev, 0);
        device_remove_file(tdev->dev, &dev_attr_enable);
        dev_set_drvdata(tdev->dev, NULL);
        device_destroy(timed_output_class, MKDEV(0, tdev->index));
}
EXPORT_SYMBOL_GPL(timed_output_dev_unregister);

static int __init timed_output_init(void)
{
        return create_timed_output_class();
}

static void __exit timed_output_exit(void)
{
        class_destroy(timed_output_class);
}

module_init(timed_output_init);
module_exit(timed_output_exit);

MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
MODULE_DESCRIPTION("timed output class driver");
MODULE_LICENSE("GPL");


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

初始化过程:
1. 首先调用kzalloc函数为 GPIO分配内存空间
2. 调用hrtimer_init函数初始化化内核定时器
3. 设置GPIOenable函数为gpio_enable
4. 设置GPIOget_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.dev);
gpio_free(gpio_data.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);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值