为了种树,我也是拼了

       蚂蚁森林有个行走赚绿色能量的方法,但奈何我的手机不支持运动传感器,Android
本身已支持计步器传感器,如果写个计步器的驱动,那应该就可以显示步数了。刚开始想
参考计步传感器的驱动来写,但发现都没有真实的计步传感器,更别提参考了。网上搜

索发现了一篇文档(lm80-p0436-9_sensors_porting_guide.pdf),感觉这个有希望。

驱动如下

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sensors.h>
#include <linux/input.h>
#define POLL_DEFAULT_INTERVAL_MS 500
static unsigned long step_count;
struct sensors_classdev step_counter_cdev ={
    .name = "simulated_step_counter",
    .vendor = "www",
    .version = 1,
    .type = SENSOR_TYPE_STEP_COUNTER,
    .sensors_enable = NULL,
    .sensors_poll_delay = NULL,
};

struct step_counter {
    atomic_t delay;
    struct workqueue_struct *data_wq;
    struct delayed_work dwork;
    struct sensors_classdev cdev;
    struct mutex enable_lock;
    struct mutex step_count_lock;
    struct input_dev *idev;
};

static int step_counter_set_enable(struct sensors_classdev *sensors_cdev,unsigned int enable)
{
    struct step_counter *virtual_step_counter = container_of(sensors_cdev,struct step_counter, cdev);
    mutex_lock(&virtual_step_counter->enable_lock);
    if (enable)
    {
        queue_delayed_work(virtual_step_counter->data_wq,&virtual_step_counter->dwork,
        msecs_to_jiffies(atomic_read(&virtual_step_counter->delay)));
    } else
    {
        cancel_delayed_work_sync(&virtual_step_counter->dwork);
    }
    mutex_unlock(&virtual_step_counter->enable_lock);
    return 0;

}
static ssize_t step_count_show(struct device *dev,struct device_attribute *attr, char *buf)
{
    return sprintf(buf, "%lu\n", step_count);
}

static ssize_t step_count_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{
    unsigned long data;
    int ret;
    struct step_counter *virtual_step_counter=dev_get_drvdata(dev);
    ret = kstrtoul(buf, 10, &data);
    if (ret)
        return ret;
    mutex_lock(&virtual_step_counter->step_count_lock);
    step_count=data;
    mutex_unlock(&virtual_step_counter->step_count_lock);
    return count;
}
static DEVICE_ATTR(step_count, S_IRUSR|S_IRGRP|S_IWUSR,step_count_show,step_count_store);

int step_counter_poll_delay(struct sensors_classdev *sensors_cdev,unsigned int delay_msec)
{
    struct step_counter *virtual_step_counter = container_of(sensors_cdev,struct step_counter, cdev);
    atomic_set(&virtual_step_counter->delay,delay_msec);
    return 0;    
}

static void step_counter_poll(struct work_struct *work)
{
    struct step_counter *virtual_step_counter = container_of((struct delayed_work  *)work,struct step_counter, dwork);
    input_report_abs(virtual_step_counter->idev, ABS_MISC, step_count);
    mutex_lock(&virtual_step_counter->step_count_lock);
    step_count=step_count+1;
    mutex_unlock(&virtual_step_counter->step_count_lock);
    input_sync(virtual_step_counter->idev);
    queue_delayed_work(virtual_step_counter->data_wq,&virtual_step_counter->dwork,
            msecs_to_jiffies(atomic_read(&virtual_step_counter->delay)));
}

static struct input_dev *step_counter_init_input(struct device *dev)
{
    int status;
    struct input_dev *input = NULL;

    input = devm_input_allocate_device(dev);
    if (!input)
        return NULL;
    input->name = "step_counter";
    input_set_capability(input, EV_ABS, ABS_MISC);
    status = input_register_device(input);
    if (status) {
        dev_err(dev,"error registering input device\n");
        return NULL;
    }
    return input;
}

static int step_counter_probe(struct platform_device *pdev)
{
    int ret;
    struct step_counter *virtual_step_counter;
    printk("step_counter_probe start\n");
    virtual_step_counter = devm_kzalloc(&pdev->dev, sizeof(struct step_counter),GFP_KERNEL);
    if (!virtual_step_counter) {
        dev_err(&pdev->dev, "memory allocation failed.\n");
        goto out;
    }
    INIT_DELAYED_WORK(&virtual_step_counter->dwork, step_counter_poll);
    virtual_step_counter->data_wq =create_freezable_workqueue("step_counter_data_work");
    if (!virtual_step_counter->data_wq) {
            dev_err(&pdev->dev, "Cannot create workqueue.\n");
            goto out_create_workqueue;
        }
    atomic_set(&virtual_step_counter->delay, POLL_DEFAULT_INTERVAL_MS);
    virtual_step_counter->idev=step_counter_init_input(&pdev->dev);
    if(!virtual_step_counter->idev){
        dev_err(&pdev->dev, "init input device failed\n");
        ret = -ENODEV;
        goto out_register_input;
    }
    virtual_step_counter->cdev=step_counter_cdev;
    virtual_step_counter->cdev.sensors_enable=step_counter_set_enable;
    virtual_step_counter->cdev.sensors_poll_delay=step_counter_poll_delay;
    ret=sensors_classdev_register(&virtual_step_counter->idev->dev,&virtual_step_counter->cdev);
    if (ret) {
        dev_err(&pdev->dev, "sensors class register failed.\n");
        goto out_register_classdev;
    }
    mutex_init(&virtual_step_counter->enable_lock);
    mutex_init(&virtual_step_counter->step_count_lock);
    dev_set_drvdata(&pdev->dev, virtual_step_counter);
    ret = device_create_file(&pdev->dev, &dev_attr_step_count);
    printk("step_counter_probe ok\n");
    return 0;

out_register_classdev:
    input_unregister_device(virtual_step_counter->idev);    
out_create_workqueue:
out_register_input:    
    destroy_workqueue(virtual_step_counter->data_wq);
out:
    printk("step_counter_probe fail\n");
    return ret;
}    
 
static int step_counter_remove(struct platform_device *pdev)
{
    return 0;
}

static struct platform_device step_counter_devices =
{
    .name            = "simulated_step_counter",
    .id             = 0,
};

static struct platform_driver step_counter_driver =
{
    .probe  = step_counter_probe,
    .remove = step_counter_remove,
    .driver = {
            .name = "simulated_step_counter",
            .owner = THIS_MODULE,
    },
};

static int sensor_init(void)
{
    platform_device_register(&step_counter_devices);
    platform_driver_register(&step_counter_driver);
    return 0;
}

static void __exit sensor_exit(void)
{
    platform_device_unregister(&step_counter_devices);
    platform_driver_unregister(&step_counter_driver);
}

module_init(sensor_init);
module_exit(sensor_exit);
MODULE_LICENSE("GPL");
                    驱动工作了,并有相关的数据上传了,但上层APP说不支持计步传感器,查找相关
代码在hardware/qcom/sensors/sensors.h加上SENSOR_TYPE_STEP_COUNTER,并将压力传
感器bmp180的相关hal代码进行改造,计步器正常工作了。用其他APP读数,汇报的值跟APP
读到的值一致,但蚂蚁森林上的读数比较久才跟新下,应该跟其内部的实现有关。

相关修改如下




      见证成果的时候到了。





猜你喜欢

转载自blog.csdn.net/mike8825/article/details/79231772