如何在 Android 系统上增加人体接近感应 Sensor,包含如何增加驱动、修改 Hardware、Framework,以及 APP 如何使用该 Sensor。
驱动
新建 kernel/drivers/input/sensors/mwsensor/mwsensor.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/idr.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/signal.h>
#include <linux/pm.h>
#include <linux/notifier.h>
#include <linux/fb.h>
#include <linux/input.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/kthread.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#define MW_SENSOR_NAME "mwsensor"
#define MW_SENSOR_NEAR 1
#define MW_SENSOR_FAR 2
// ioctl cmd
#define MW_SENSOR_IOC_MAGIC 'm'
#define MW_SENSOR_IOC_ENABLE _IOW(MW_SENSOR_IOC_MAGIC, 1, int)
#define MW_SENSOR_IOC_SET_RATE _IOW(MW_SENSOR_IOC_MAGIC, 2, int)
#define MW_SENSOR_IOC_MAXNR 2
struct mw_sensor_data {
struct platform_device *platform_dev;
struct miscdevice mw_sensor_device;
struct input_dev *input_dev;
struct notifier_block notifier;
int irq;
int irq_gpio;
unsigned long suspend_time;
bool is_suspended;
u32 is_delay;
u32 is_poll;
u32 delay_time;
bool enabled;
};
static inline uint32_t gettime_now(void)
{
struct timeval tv;
do_gettimeofday(&tv);
return tv.tv_sec;
}
static void mw_sensor_report_event(struct mw_sensor_data *mw_sensor, s32 data)
{
struct input_dev *input = mw_sensor->input_dev;
if (!mw_sensor->enabled) {
return;
}
input_report_rel(input, REL_MISC, data);
input_sync(input);
}
static int mw_sensor_enable(struct mw_sensor_data *mw_sensor) {
mw_sensor->enabled = true;
if (gpio_get_value(mw_sensor->irq_gpio)) {
mw_sensor_report_event(mw_sensor, MW_SENSOR_NEAR);
} else {
mw_sensor_report_event(mw_sensor, MW_SENSOR_FAR);
}
return 0;
}
static int mw_sensor_disable(struct mw_sensor_data *mw_sensor) {
mw_sensor->enabled = false;
return 0;
}
static int mw_sensor_suspend(struct mw_sensor_data *mw_sensor)
{
dev_info(&mw_sensor->platform_dev->dev, "mw_sensor_suspend\n");
mw_sensor->suspend_time = gettime_now();
mw_sensor->is_suspended = true;
//enable_irq_wake(mw_sensor->irq);
return 0;
}
static int mw_sensor_resume(struct mw_sensor_data *mw_sensor)
{
dev_info(&mw_sensor->platform_dev->dev, "mw_sensor_resume\n");
//mw_sensor->is_suspended = false;
//disable_irq_wake(mw_sensor->irq);
return 0;
}
static int mw_sensor_fb_event_notify(struct notifier_block *noti,
unsigned long event, void *data)
{
int *blank;
struct fb_event *ev_data = data;
struct mw_sensor_data *mw_sensor = container_of(noti,
struct mw_sensor_data, notifier);
if (ev_data && ev_data->data && event == FB_EVENT_BLANK && mw_sensor) {
blank = ev_data->data;
if (*blank == FB_BLANK_UNBLANK) {
mw_sensor_resume(mw_sensor);
} else if (*blank == FB_BLANK_POWERDOWN) {
mw_sensor_suspend(mw_sensor);
}
}
return NOTIFY_OK;
}
static void mw_sensor_wakeup(struct mw_sensor_data *mw_sensor) {
dev_info(&mw_sensor->platform_dev->dev, "%s, wake up\n", __func__);
input_report_key(mw_sensor->input_dev, KEY_POWER, 1);
input_sync(mw_sensor->input_dev);
input_report_key(mw_sensor->input_dev, KEY_POWER, 0);
input_sync(mw_sensor->input_dev);
}
static irqreturn_t mw_sensor_irq_handle(int irq, void *dev_id)
{
struct mw_sensor_data *mw_sensor = dev_id;
unsigned long cur_time = gettime_now();
// dts中配置是否延时,因为待机过程会产生干扰,导致微波Sensor误触发
if (!mw_sensor->is_delay || abs(cur_time - mw_sensor->suspend_time) > mw_sensor->delay_time) {
if (gpio_get_value(mw_sensor->irq_gpio)) {
if (mw_sensor->is_suspended) {
mw_sensor->is_suspended = false;
mw_sensor_wakeup(mw_sensor);
msleep(100);
mw_sensor_report_event(mw_sensor, MW_SENSOR_NEAR);
} else {
mw_sensor_report_event(mw_sensor, MW_SENSOR_NEAR);
}
} else {
mw_sensor_report_event(mw_sensor, MW_SENSOR_FAR);
}
}
return IRQ_HANDLED;
}
static void mw_sensor_free_irq(struct mw_sensor_data *mw_sensor)
{
if(mw_sensor) {
free_irq(mw_sensor->irq, mw_sensor);
}
}
static void mw_sensor_free_io_port(struct mw_sensor_data *mw_sensor)
{
if(gpio_is_valid(mw_sensor->irq_gpio)) {
gpio_free(mw_sensor->irq_gpio);
}
return;
}
static int mw_sensor_parse_dt(struct device *dev,
struct mw_sensor_data *mw_sensor)
{
int ret = 0;
struct device_node *np = dev->of_node;
mw_sensor->irq_gpio = of_get_named_gpio(np, "irq-gpios", 0);
if(!gpio_is_valid(mw_sensor->irq_gpio)) {
dev_err(dev, "No valid irq gpio");
return -1;
}
ret = of_property_read_u32(np, "mwsensor,is_delay", &mw_sensor->is_delay);
if (ret) {
mw_sensor->is_delay = 0;
}
ret = of_property_read_u32(np, "mwsensor,delay_time", &mw_sensor->delay_time);
if (ret) {
mw_sensor->delay_time = 3;
}
ret = of_property_read_u32(np, "mwsensor,is_poll",<