input device的初始化解释
3, 初始化input device
struct input_dev {//表示的是一个具体的输入设备,描述设备能够产生什么数据
const char *name; // sysfs中给用户看的信息
const char *phys;
const char *uniq;
struct input_id id;
//evbit实际是一个位表,描述输入设备能够产生什么类型数据
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; // EV_KEY,EV_ABS, EV_REL
//表示能够产生哪种按键
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//KEY_POWER… 能够表示768bit,直接用24个long来表示
// KEY_CNT == 768 BITS_TO_LONGS== nr/32 = 768/32==24
//表示能够产生哪种相对坐标数据
unsigned long relbit[BITS_TO_LONGS(REL_CNT)];// REL_X
//表示能够产生哪种绝对坐标数据
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //ABS_X
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
struct device dev; // 继承device对象
struct list_head h_list;
struct list_head node; //表示节点
}
不同输入设备能够产生不同的数据:
1,按键/keyboard: 产生键值,实际是一个数字
#define KEY_VOLUMEDOWN 114
#define KEY_VOLUMEUP 115
#define KEY_POWER 116 /* SC System Power Down /
2,ts/gsensor:产生坐标,绝对坐标, 有一个明确坐标系,并且原点(0,0),最大值(800,480)
#define ABS_X 0x00
#define ABS_Y 0x01
#define ABS_PRESSURE 0x18
#define ABS_MT_TOUCH_MAJOR 0x30 / Major axis of touching ellipse /
#define ABS_MT_TOUCH_MINOR 0x31 / Minor axis (omit if circular) /
#define ABS_MT_WIDTH_MAJOR 0x32 / Major axis of approaching ellipse /
#define ABS_MT_WIDTH_MINOR 0x33 / Minor axis (omit if circular) /
#define ABS_MT_ORIENTATION 0x34 / Ellipse orientation /
#define ABS_MT_POSITION_X 0x35 / Center X touch position /
#define ABS_MT_POSITION_Y 0x36 / Center Y touch position */
3,mouse:产生坐标,相对坐标,坐标值是相对于之前一个点坐标
#define REL_X 0x00
#define REL_Y 0x01
#define REL_WHEEL 0x08
如何表示不同数据类型:
#define EV_SYN 0x00 //表示同步数据类型
#define EV_KEY 0x01 //表示按键数据类型
#define EV_REL 0x02 //表示相对坐标数据类型
#define EV_ABS 0x03 //表示绝对坐标数据类型
#define EV_MSC 0x04 //表示杂项
#define EV_SW 0x05 //开关
#define EV_LED 0x11 //led指示数据
#define EV_SND 0x12 //声音数据
添加input device的信息
在init函数中添加设备信息
//添加设备信息--/sys/class/input/eventx/device/
inputdev->name = "simple input key";
inputdev->phys = "key/input/input0";
inputdev->uniq = "simple key0 for 4412";
inputdev->id.bustype = BUS_HOST;
inputdev->id.vendor =0x1234 ;
inputdev->id.product = 0x8888;
inputdev->id.version = 0x0001;
设置位表和上报数据的另一种方式
另外一种设置bit的方法
inputdev->keybit[BIT_WORD(KEY_POWER)] |= BIT_MASK(KEY_POWER);// 116%32
inputdev->keybit[116/32] |= 1 << 116%32;// 116%32
上报数据的时候:
方法1:通用方法
void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)
方法2:封装:
input_report_key(struct input_dev * dev, unsigned int code, int value)
|
input_event(dev, EV_KEY, code, !!value); //上报按键的时候一定0或者1
设备树中定义按键信息的子节点
4, 驱动多个按键
一个按键有多个与其相关的元素:
a, 中断号码
b, 按键的状态–gpio的数据寄存器获取到
c, 按键的值–code
在设备树文件中设置这几个元素:
key_int_node{
compatible = "test_key";
#address-cells = <1>;
#size-cells = <1>;
key_int@0 {
key_name = "key2_power_eint";
key_code = <116>;
gpio = <&gpx1 1 0>;
reg = <0x11000C20 0x18>;
interrupt-parent = <&gpx1>;
interrupts = <1 0>;
};
key_int@1 {
key_name = "key3_vup_eint";
key_code = <115>;
gpio = <&gpx1 2 0>;
reg = <0x11000C20 0x18>;
interrupt-parent = <&gpx1>;
interrupts = <2 0>;
};
key_int@2 {
key_name = "key4_vdown_eint";
key_code = <114>;
gpio = <&gpx3 2 0>;
reg = <0x11000C60 0x18>;
interrupt-parent = <&gpx3>;
interrupts = <2 0>;
};
};
make dtbs
更新设备树文件:
cp -raf arch/arm/boot/dts/exynos4412-fs4412.dtb /tftpboot/
初始化所有的按键并驱动起来
在代码中也会设计这几个元素
在代码中获取节点:
of_get_next_child(const struct device_node * node, struct device_node * prev)
参数1:表示节点
参数2:之前的节点,如果是第一个节点,设置成NULL
// 通过节点去获取到中断号码
irqno = irq_of_parse_and_map(cnp, 0);
//获取key name
of_property_read_string(cnp, "key_name", &key_name);
//获取key code
of_property_read_u32(cnp, "key_code", &code);
gpionum = of_get_named_gpio(cnp, "gpio", 0);
printk("name = %s, code = %d, gpionum = %d,irqno = %d\n",
key_name, code, gpionum,irqno);
//设计一个对象出来
struct key_desc{
char *name;
int irqno;
int key_code;
int gpionum;
void *reg_base;
struct device_node *cnp;// 可以随时去获取节点各个信息
};
完整代码
simple_input_allkey.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <asm/io.h>
#define KEY_NUMS 3
//设计一个对象出来
struct key_desc{
char *name;
int irqno;
int key_code;
int gpionum;
void *reg_base;
struct device_node *cnp;// 可以随时去获取节点各个信息
};
struct key_desc all_key[KEY_NUMS];
struct input_dev *inputdev;
void get_all_child_from_node(void)
{
// 获取到设备树中到节点
struct device_node *np = of_find_node_by_path("/key_int_node");
if(np){
printk("find node ok\n");
}else{
printk("find node failed\n");
}
struct device_node *cnp;
struct device_node *prev = NULL;
int i = 0;
do{
//获取到子节点
cnp = of_get_next_child(np, prev);
if(cnp != NULL){
all_key[i++].cnp = cnp;//将当前的节点记录下来
printk("get child node ok!\n");
}else{
printk("get child node failed\n");
}
prev = cnp; //把当前的设置位prev
}while(of_get_next_child(np, prev) != NULL);
}
irqreturn_t input_key_irq_handler(int irqno, void *devid)
{
printk("-------%s-------------\n", __FUNCTION__);
//区分不同的按键
struct key_desc *pdesc = (struct key_desc *)devid;
int gpionum = of_get_named_gpio(pdesc->cnp, "gpio", 0);
//直接通过gpio获取按键状态
int value = gpio_get_value(gpionum);
if(value){//抬起
input_report_key(inputdev, pdesc->key_code, 0);
input_sync(inputdev);//上报数据结束
}else{
input_report_key(inputdev, pdesc->key_code, 1);
input_sync(inputdev);//上报数据结束
}
return IRQ_HANDLED;
}
static int __init simple_input_init(void)
{
//编写输入子系统代码
/*
1,分配一个input device对象
2, 初始化input device对象
3,注册input device对象
*/
int ret;
inputdev = input_allocate_device();
if(inputdev == NULL)
{
printk(KERN_ERR "input_allocate_device error\n");
return -ENOMEM;
}
get_all_child_from_node();
//添加设备信息--/sys/class/input/eventx/device/
inputdev->name = "simple input key";
inputdev->phys = "key/input/input0";
inputdev->uniq = "simple key0 for 4412";
inputdev->id.bustype = BUS_HOST;
inputdev->id.vendor =0x1234 ;
inputdev->id.product = 0x8888;
inputdev->id.version = 0x0001;
//当前设备能够产生按键数据--将某个bit置1
__set_bit(EV_KEY, inputdev->evbit);
//表示当前设备能够产生power按键
//__set_bit(KEY_POWER, inputdev->keybit);
//另外一种设置bit的方式
int i;
int code;
int irqno;
char *key_name;
for(i=0; i<KEY_NUMS; i++)
{
//设置keybit,支持哪些按键
// 按键值从设备设备树
struct device_node *cnp = all_key[i].cnp;
of_property_read_u32(cnp,"key_code", &code);
__set_bit(code, inputdev->keybit);
all_key[i].key_code = code; //先记录下来
irqno = irq_of_parse_and_map(cnp, 0);
all_key[i].irqno = irqno;//先记录下来
of_property_read_string(cnp, "key_name", &key_name);
all_key[i].name = key_name;
printk("name = %s, code = %d,irqno = %d\n",
key_name, code,irqno);
int irqflags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING;
ret = request_irq(irqno, input_key_irq_handler, irqflags,
key_name, &all_key[i]);
if(ret != 0)
{
printk("request_irq error\n");
goto err_0;
}
}
ret = input_register_device(inputdev);
if(ret != 0)
{
printk(KERN_ERR "input_register_device error\n");
goto err_0;
}
return 0;
err_1:
input_unregister_device(inputdev);
err_0:
input_free_device(inputdev);
return ret;
}
static void __exit simple_input_exit(void)
{
int i;
for(i=0; i<KEY_NUMS; i++)
free_irq(all_key[i].irqno, &all_key[i]);
input_unregister_device(inputdev);
input_free_device(inputdev);
}
module_init(simple_input_init);
module_exit(simple_input_exit);
MODULE_LICENSE("GPL");
Makefile
ROOTFS_DIR = /opt/4412/rootfs
MODULE_NAME = simple_input_allkey
ifeq ($(KERNELRELEASE), )
KERNEL_DIR = /home/linux/linux-3.14.10
CUR_DIR = $(shell pwd)
all :
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
clean :
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
install:
cp -raf *.ko $(ROOTFS_DIR)/drv_module
else
obj-m += $(MODULE_NAME).o
endif