收到一个人体感应的需求,在设置添加一个开关
第一步,确定人体感应接口的GPIO
可知GPIO7_B5为对应GPIO
第二步,注册对应DTS
然后去驱动内注册对应的节点
很基础的东西,就不多说了,省略一万字......................(得到节点)
cat sys/devices/platform/attr/pir_pin_status
可以获取到节点状态,这里只做了读函数,不支持写GPIO值
第三步,设置里面添加
<string name="pirpin_title">pir status</string>
<string name="pirpin_title">"人体感应开关"</string>
<SwitchPreference
android:key="pirpin_mode"
android:title="@string/pirpin_title"
android:defaultValue="false" />
然后下载进去看到现象
第四步,添加环境变量(persist.sys.pir=0)
\sdk\device\rockchip\rk3288\system.prop
第五步,添加对应的按键java代码
更新一个功能,打开开关时保存一下原来的休眠时间,关闭人体功能的时候恢复原来的休眠时间
进阶难度:
Index: attr_gpio.c
===================================================================
--- attr_gpio.c (revision 84)
+++ attr_gpio.c (working copy)
@@ -34,8 +34,12 @@
#include <linux/reboot.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/switch.h>
+#include <linux/workqueue.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
@@ -46,9 +50,69 @@
.store = _store, \
}
#define DEVICE_NAME "attr"
+
+struct gpio_switch_data {
+ struct switch_dev sdev;
+ unsigned gpio;
+ const char *name_on;
+ const char *name_off;
+ const char *state_on;
+ const char *state_off;
+ int irq;
+ struct work_struct work;
+};
+static void uevent_trigger(struct switch_dev *sdev,int uevent_status) //私人上报uevent事件
+{
+ char *event = NULL;
+ char *envp[3];
+ const char *name;
+ name = uevent_status? "1" : "0";
+ event = kasprintf(GFP_KERNEL, "SWITCH_STATE=%s", name);
+ printk("%s,event--->%s\n", __func__, event);
+ envp[0] = "DEVNAME=renti";
+ envp[1] = event;
+ envp[2] = NULL;
+ kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp);
+}
+static void gpio_switch_work(struct work_struct *work)
+{
+ int state;
+ struct gpio_switch_data *data =
+ container_of(work, struct gpio_switch_data, work);
+
+ state = gpio_get_value(data->gpio);
+ printk("longmin switch_data->gpio=%d\n",state);
+// switch_set_state(&data->sdev, state);//switch类uevent上报
+ uevent_trigger(&data->sdev, state);//私人uevent上报
+}
+static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
+{
+ struct gpio_switch_data *switch_data =
+ (struct gpio_switch_data *)dev_id;
+
+ schedule_work(&switch_data->work);
+ return IRQ_HANDLED;
+}
+static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf)
+{
+ struct gpio_switch_data *switch_data =
+ container_of(sdev, struct gpio_switch_data, sdev);
+ const char *state;
+ if (switch_get_state(sdev))
+ {
+ state = switch_data->state_on;
+ }
+ else
+ {
+ state = switch_data->state_off;
+ }
+ if (state)
+ return sprintf(buf, "%s\n", state);
+ return -1;
+}
void get_attr_gpios_dt(struct device *dev){
@@ -436,6 +500,7 @@
{
//struct device *attr_dev;
struct device *attr_dev = &pdev->dev;
+int ret;
//struct device_node *np = client->attr_dev.of_node;
get_attr_gpios_dt(&pdev->dev);
device_create_file(attr_dev,&dev_attr_io_pin1);
@@ -448,6 +513,32 @@
device_create_file(attr_dev,&dev_attr_io_pin8);
device_create_file(attr_dev,&dev_attr_pir_pin_status);
+ struct gpio_switch_data *switch_data;
+ switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL);
+ if (!switch_data)
+ return -ENOMEM;
+ switch_data->sdev.name = "renti";
+ switch_data->gpio = pir_pin_status;
+ switch_data->name_on = 1;
+ switch_data->name_off = 0;
+ switch_data->state_on = 1;
+ switch_data->state_off = 0;
+ switch_data->sdev.print_state = switch_gpio_print_state;
+
+
+ ret = switch_dev_register(&switch_data->sdev);
+ ret = gpio_request(switch_data->gpio, pdev->name);
+ ret = gpio_direction_input(switch_data->gpio);
+ INIT_WORK(&switch_data->work, gpio_switch_work);
+ switch_data->irq = gpio_to_irq(switch_data->gpio);
+ if (switch_data->irq < 0) {
+ ret = switch_data->irq;
+ printk("longmin switch_data->irq=%d\n",ret);
+ }
+ ret = request_irq(switch_data->irq, gpio_irq_handler,
+ (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING), pdev->name, switch_data);
+ gpio_switch_work(&switch_data->work);
+
return 0;
}
static int attr_gpio_remove(struct platform_device *pdev)
@@ -462,6 +553,11 @@
device_remove_file(attr_dev,&dev_attr_io_pin7);
device_remove_file(attr_dev,&dev_attr_io_pin8);
device_remove_file(attr_dev,&dev_attr_pir_pin_status);
return 0;
}
给GPIO注册了一个中断,然后在中断中上报uevent事件