场景:
KEY_A 作为按键,高电平时,设备正常工作,低电平时,设备休眠。
KEY_B 作为显示灯,设备工作时为高电平,即亮灯。设备休眠时为低电平,即灭灯。
思路:创建一个线程 不断检测KEY_A ,然后根据KEY_A 电平。上报输入子系统相应的事件。
环境为 Android7.1
#include <linux/ioctl.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <linux/blkdev.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/string.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/seq_file.h>
#include <linux/kobject.h>
#include <linux/kobj_map.h>
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/backing-dev.h>
#include <linux/tty.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/async.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/proc_fs.h>
#include <linux/input/mt.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/kthread.h>
#include <asm/unaligned.h>
#include <linux/sched.h>//jiffies在此头文件中定义
static int debug = 4;
module_param(debug, int, S_IRUGO|S_IWUSR);
#define dbg_codec(level, fmt, arg...) \
do { \
if (debug >= level) \
printk(fmt , ## arg); \
} while (0)
#define DBG(fmt, ...) dbg_codec(0, fmt, ## __VA_ARGS__)
#define CLONE_KERNEL (CLONE_FS | CLONE_FILES | CLONE_SIGHAND)
struct input_dev *input_dev = NULL;
struct task_struct *practice_task_p = NULL;//内核线程
/*
0:代表当前在休眠状态
1:代表当前在工作状态
*/
int key_status = 1;
int key_status_last= 1;
int my_kernel_thread(void *arg) {
int val;
while(1) {
key_status = gpio_get_value(RK30_PIN0_PB7);
if(key_status == key_status_last)
{
//break;
}else{
/*按键为高,正常工作*/
if(key_status == 1){
gpio_direction_output(RK30_PIN0_PB4,1);
input_report_key(input_dev, KEY_WAKEUP, 1);
input_sync(input_dev);
input_report_key(input_dev, KEY_WAKEUP, 0);
input_sync(input_dev);
//msleep(1000);
/* 按键为低,休眠*/
}else if(key_status == 0){
gpio_direction_output(RK30_PIN0_PB4,0);
//KEY_SLEEP KEY_POWER
input_report_key(input_dev, KEY_POWER, 1);
input_sync(input_dev);
input_report_key(input_dev, KEY_POWER, 0);
input_sync(input_dev);
//msleep(1000);
}
}
key_status_last = key_status;
ssleep(1);
if(kthread_should_stop()) {
break;
}
}
return 0;
}
static int power_key_init(void)
{
int error = -1;
printk("---------power_key_init-----------\n");
/*
输出 RK30_PIN0_PB4
输入 RK30_PIN0_PB7
*/
//输出 RK30_PIN0_PB4
if (!gpio_is_valid(RK30_PIN0_PB4)){
DBG("%s gpio43 is unvalid \n", __func__);
}
//输入 RK30_PIN0_PB7
if (!gpio_is_valid(RK30_PIN0_PB7)){
DBG("%s gpio42 is unvalid \n", __func__);
}
if (gpio_request(RK30_PIN0_PB4, NULL)) {
DBG("%s failed to request irq-gpio, gpio_num =%d\n", __func__, 43);
}
if (gpio_request(RK30_PIN0_PB7, NULL)) {
DBG("%s failed to request irq-gpio, gpio_num =%d\n", __func__, 42);
}
gpio_direction_input(RK30_PIN0_PB7);
gpio_direction_output(RK30_PIN0_PB4,1);
//分配一个 input_dev 设备结构体,并且在 /sys/class/input/input-n 下创建设备属性文件
input_dev = input_allocate_device();
input_dev->name = "key-power";
input_dev->phys = "key-power";
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 1;
input_dev->id.product = 1;
input_dev->id.version = 1;
/*
设置支持的事件类型
*/
input_dev->evbit[0] = BIT_MASK(EV_KEY);
/*
设置支持的事件
*/
set_bit(KEY_POWER, input_dev->keybit);
set_bit(KEY_WAKEUP, input_dev->keybit);
/*
注册输入设备
*/
error = input_register_device(input_dev);
/*
创建线程,并启动线程
*/
practice_task_p = kthread_create(my_kernel_thread,NULL,"practice task");
wake_up_process(practice_task_p);
printk("---------power_key_init over-----------\n");
return 0;
}
static void power_key_exit(void)
{
input_unregister_device(input_dev);
kthread_stop(practice_task_p);
}
module_init(power_key_init);
module_exit(power_key_exit);
MODULE_LICENSE("GPL");