原文地址:http://blog.csdn.net/gdt_a20/article/details/7342816
摘要:
input子系统是kernel中比较简单的一个子系统,主要用来管理输入设备(触摸屏,键盘等等),个人感
觉可以作为driver的起点,输入设备不明思议,要提供输入信息,input子系统将这些信息当作事件,进行区分,实
时的上传!input中不是那么规矩,并没有抽象出来总线的概念(硬件上不存在),而是用一个结构struct input_handle充当了总线
的结构,struct input_handle挂接了操作结构以及设备,input设备用struct input_dev结构来表示,操作函数用struct input_handler
来表示,注意这里input_handle和input_handler很相似,存在全局的input设备链表input_dev_list,用于连接所有input devices,
存在全局的input操作链表input_handler_list,用于挂接所有handler.
主要涉及目录:drivers/input
struct input_dev
一、相关数据结构
1.input device
-
struct input_dev {
-
const char *name; //名字
-
const char *phys; //物理地址
-
const char *uniq; //设备特殊标识码
-
struct input_id id; //设备id
-
-
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; //设备属性相关位图
-
-
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //支持的事件
-
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //key,button位图
-
unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //相对坐标
-
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //绝对坐标
-
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; //杂项事件支持
-
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; //led相关
-
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; //音响效果相关
-
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
-
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
-
-
unsigned int hint_events_per_packet;
-
-
unsigned int keycodemax; //键码表大小
-
unsigned int keycodesize;
-
void *keycode; //按键扫描码
-
-
int (*setkeycode)(struct input_dev *dev, //老式扫描方法
-
const struct input_keymap_entry *ke,
-
unsigned int *old_keycode);
-
int (*getkeycode)(struct input_dev *dev,
-
struct input_keymap_entry *ke);
-
-
struct ff_device *ff;
-
-
unsigned int repeat_key;
-
struct timer_list timer; //定时器
-
-
int rep[REP_CNT];
-
-
struct input_mt_slot *mt;
-
int mtsize;
-
int slot;
-
int trkid;
-
-
struct input_absinfo *absinfo;
-
-
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
-
unsigned long led[BITS_TO_LONGS(LED_CNT)];
-
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
-
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
-
-
int (*open)(struct input_dev *dev); //open回调函数
-
void (*close)(struct input_dev *dev);
-
int (*flush)(struct input_dev *dev, struct file *file);
-
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
-
-
struct input_handle __rcu *grab;
-
-
spinlock_t event_lock;
-
struct mutex mutex;
-
-
unsigned int users;
-
bool going_away;
-
-
bool sync;
-
-
struct device dev; //devices 模型
-
-
struct list_head h_list; //连接相应的handle
-
struct list_head node; //挂接到全局input_dev_list
-
};
2.操作函数结构input_handler
-
struct input_handler {
-
-
void *private; //私有属性结构
-
-
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
-
bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
-
bool (*match)(struct input_handler *handler, struct input_dev *dev);
-
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
-
void (*disconnect)(struct input_handle *handle);
-
void (*start)(struct input_handle *handle);
-
-
const struct file_operations *fops;
-
int minor;
-
const char *name; //名字
-
-
const struct input_device_id *id_table; //支持的devices,id表
-
-
struct list_head h_list; //用于连接到对应的handle的
-
struct list_head node; //用于连接到全局的input_handler_list链表
-
};
3.bus的充当者总体管理结构
-
struct input_handle {
-
-
void *private; //私有数据结构
-
-
int open; //open计数
-
const char *name; //名字
-
-
struct input_dev *dev; //连接设备
-
struct input_handler *handler; //连接driver的操作函数
-
-
struct list_head d_node; //设备挂接点
-
struct list_head h_node; //handle挂接点
-
};
二、相关的操作函数
1.关心一下核心文件input.c,input子系统的初始化:
-
static int __init input_init(void)
-
{
-
int err;
-
-
err = class_register(&input_class); //注册input类,出现在sys/class下
-
if (err) {
-
pr_err("unable to register input_dev class\n");
-
return err;
-
}
-
-
err = input_proc_init(); //在proc下添加相关信息(bus/input)
-
if (err)
-
goto fail1;
-
-
err = register_chrdev(INPUT_MAJOR, "input", &input_fops); //注册成字符设备,设备号13
-
if (err) {
-
pr_err("unable to register char major %d", INPUT_MAJOR);
-
goto fail2;
-
}
-
-
return 0;
-
-
fail2: input_proc_exit();
-
fail1: class_unregister(&input_class);
-
return err;
-
}
貌似戛然而止了,^.^!,
2.向input子系统添加设备的函数,
-
int input_register_device(struct input_dev *dev)
-
{
-
static atomic_t input_no = ATOMIC_INIT(0);
-
struct input_handler *handler;
-
const char *path;
-
int error;
-
-
/* Every input device generates EV_SYN/SYN_REPORT events. */
-
__set_bit(EV_SYN, dev->evbit);
-
-
/* KEY_RESERVED is not supposed to be transmitted to userspace. */
-
__clear_bit(KEY_RESERVED, dev->keybit);
-
-
/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
-
input_cleanse_bitmasks(dev);
-
-
if (!dev->hint_events_per_packet)
-
dev->hint_events_per_packet =
-
input_estimate_events_per_packet(dev);
-
-
/*
-
* If delay and period are pre-set by the driver, then autorepeating
-
* is handled by the driver itself and we don't do it in input.c.
-
*/
-
init_timer(&dev->timer);
-
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
-
dev->timer.data = (long) dev;
-
dev->timer.function = input_repeat_key;
-
dev->rep[REP_DELAY] = 250;
-
dev->rep[REP_PERIOD] = 33;
-
}
-
-
if (!dev->getkeycode)
-
dev->getkeycode = input_default_getkeycode; //如果没有设置,设置成默认值
-
-
if (!dev->setkeycode)
-
dev->setkeycode = input_default_setkeycode;
-
-
dev_set_name(&dev->dev, "input%ld", //name
-
(unsigned long) atomic_inc_return(&input_no) - 1);
-
-
error = device_add(&dev->dev); //标准设备的加入,这个,,加哪去了,没bus的野设备??
-
if (error) //直接扔到系统全局总设备链表了
-
return error;
-
-
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
-
pr_info("%s as %s\n",
-
dev->name ? dev->name : "Unspecified device",
-
path ? path : "N/A");
-
kfree(path);
-
-
error = mutex_lock_interruptible(&input_mutex);
-
if (error) {
-
device_del(&dev->dev);
-
return error;
-
}
-
-
list_add_tail(&dev->node, &input_dev_list); //加入全局input device链表
-
-
list_for_each_entry(handler, &input_handler_list, node) //遍历handler链表,匹配合适的handler
-
input_attach_handler(dev, handler);
-
-
input_wakeup_procfs_readers();
-
-
mutex_unlock(&input_mutex);
-
-
return 0;
-
}
继续跟一下input_attach_handler函数,
-
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
-
{
-
const struct input_device_id *id;
-
int error;
-
-
id = input_match_device(handler, dev); //具体的匹配函数
-
if (!id)
-
return -ENODEV;
-
-
error = handler->connect(handler, dev, id); //匹配后调用connect函数
-
if (error && error != -ENODEV)
-
pr_err("failed to attach handler %s to device %s, error: %d\n",
-
handler->name, kobject_name(&dev->dev.kobj), error);
-
-
return error;
-
}
还有个函数
-
static const struct input_device_id *input_match_device(struct input_handler *handler,
-
struct input_dev *dev)
-
{
-
const struct input_device_id *id;
-
int i;
-
-
for (id = handler->id_table; id->flags || id->driver_info; id++) {
-
-
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
-
if (id->bustype != dev->id.bustype)
-
continue;
-
-
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
-
if (id->vendor != dev->id.vendor)
-
continue;
-
-
if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
-
if (id->product != dev->id.product)
-
continue;
-
-
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
-
if (id->version != dev->id.version)
-
continue;
-
-
MATCH_BIT(evbit, EV_MAX);
-
MATCH_BIT(keybit, KEY_MAX);
-
MATCH_BIT(relbit, REL_MAX);
-
MATCH_BIT(absbit, ABS_MAX);
-
MATCH_BIT(mscbit, MSC_MAX);
-
MATCH_BIT(ledbit, LED_MAX);
-
MATCH_BIT(sndbit, SND_MAX);
-
MATCH_BIT(ffbit, FF_MAX);
-
MATCH_BIT(swbit, SW_MAX);
-
-
if (!handler->match || handler->match(handler, dev)) //不光是调用match函数,上面的匹配也很严格,厂商
-
return id; //版本一个也不能少
-
}
-
-
return NULL;
-
}
3.handler的注册
同样handler也要有注册的
-
int input_register_handler(struct input_handler *handler)
-
{
-
struct input_dev *dev;
-
int retval;
-
-
retval = mutex_lock_interruptible(&input_mutex);
-
if (retval)
-
return retval;
-
-
INIT_LIST_HEAD(&handler->h_list);
-
-
if (handler->fops != NULL) {
-
if (input_table[handler->minor >> 5]) {
-
retval = -EBUSY;
-
goto out;
-
}
-
input_table[handler->minor >> 5] = handler;
-
}
-
-
list_add_tail(&handler->node, &input_handler_list); //加入全局handler链表
-
-
list_for_each_entry(dev, &input_dev_list, node) //遍历devices链表,匹配
-
input_attach_handler(dev, handler);
-
-
input_wakeup_procfs_readers();
-
-
out:
-
mutex_unlock(&input_mutex);
-
return retval;
-
}
三、input deivce实例
这个东东还是找个例子看起来比较方便,
翻一翻touchscreen下s3c2410_ts.c,
直接进入主题看probe
-
"code" class="cpp">static int __devinit s3c2410ts_probe(struct platform_device *pdev)
-
{
-
struct s3c2410_ts_mach_info *info;
-
struct device *dev = &pdev->dev;
-
struct input_dev *input_dev;
-
struct resource *res;
-
int ret = -EINVAL;
-
-
/* Initialise input stuff */
-
memset(&ts, 0, sizeof(struct s3c2410ts));
-
-
ts.dev = dev;
-
-
info = pdev->dev.platform_data;
-
if (!info) {
-
dev_err(dev, "no platform data, cannot attach\n");
-
return -EINVAL;
-
}
-
-
dev_dbg(dev, "initialising touchscreen\n");
-
-
ts.clock = clk_get(dev, "adc"); //申请clock
-
if (IS_ERR(ts.clock)) {
-
dev_err(dev, "cannot get adc clock source\n");
-
return -ENOENT;
-
}
-
-
clk_enable(ts.clock); //使能clock
-
dev_dbg(dev, "got and enabled clocks\n");
-
-
ts.irq_tc = ret = platform_get_irq(pdev, 0); //中断号
-
if (ret < 0) {
-
dev_err(dev, "no resource for interrupt\n");
-
goto err_clk;
-
}
-
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //相关寄存器地址
-
if (!res) {
-
dev_err(dev, "no resource for registers\n");
-
ret = -ENOENT;
-
goto err_clk;
-
}
-
-
ts.io = ioremap(res->start, resource_size(res)); //进行映射
-
if (ts.io == NULL) {
-
dev_err(dev, "cannot map registers\n");
-
ret = -ENOMEM;
-
goto err_clk;
-
}
-
-
/* inititalise the gpio */
-
if (info->cfg_gpio)
-
info->cfg_gpio(to_platform_device(ts.dev)); //相关gpio配置
-
-
ts.client = s3c_adc_register(pdev, s3c24xx_ts_select, //注意这里adc核心相关,select会启动timer上报adc事件
-
s3c24xx_ts_conversion, 1);
-
if (IS_ERR(ts.client)) {
-
dev_err(dev, "failed to register adc client\n");
-
ret = PTR_ERR(ts.client);
-
goto err_iomap;
-
}
-
-
/* Initialise registers */
-
if ((info->delay & 0xffff) > 0)
-
writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
-
-
writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
-
-
input_dev = input_allocate_device(); //这里重点,分配了一个input device设备
-
if (!input_dev) {
-
dev_err(dev, "Unable to allocate the input device !!\n");
-
ret = -ENOMEM;
-
goto err_iomap;
-
}
-
-
ts.input = input_dev;
-
ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-
ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0);
-
input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0);
-
-
ts.input->name = "S3C24XX TouchScreen";
-
ts.input->id.bustype = BUS_HOST;
-
ts.input->id.vendor = 0xDEAD;
-
ts.input->id.product = 0xBEEF;
-
ts.input->id.version = 0x0102;
-
-
ts.shift = info->oversampling_shift;
-
ts.features = platform_get_device_id(pdev)->driver_data;
-
-
ret = request_irq(ts.irq_tc, stylus_irq, 0, //申请中断,input设备大多都是使用中断的,pen down up事件
-
"s3c2410_ts_pen", ts.input);
-
if (ret) {
-
dev_err(dev, "cannot get TC interrupt\n");
-
goto err_inputdev;
-
}
-
-
dev_info(dev, "driver attached, registering input device\n");
-
-
/* All went ok, so register to the input system */
-
ret = input_register_device(ts.input); //这里注册input device
-
if (ret < 0) {
-
dev_err(dev, "failed to register input device\n");
-
ret = -EIO;
-
goto err_tcirq;
-
}
-
-
return 0;
-
-
err_tcirq:
-
free_irq(ts.irq_tc, ts.input);
-
err_inputdev:
-
input_free_device(ts.input);
-
err_iomap:
-
iounmap(ts.io);
-
err_clk:
-
del_timer_sync(&touch_timer);
-
clk_put(ts.clock);
-
return ret;
-
}
-
-
-
-
看一下 input_allocate_device函数,
-
-
"code"
class="cpp">struct input_dev *input_allocate_device(void)
-
{
-
struct input_dev *dev;
-
-
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
-
if (dev) {
-
dev->dev.type = &input_dev_type; //初始化成input类型
-
dev->dev.class = &input_class;
-
device_initialize(&dev->dev);
-
mutex_init(&dev->mutex);
-
spin_lock_init(&dev->event_lock);
-
INIT_LIST_HEAD(&dev->h_list);
-
INIT_LIST_HEAD(&dev->node);
-
-
__module_get(THIS_MODULE);
-
}
-
-
return dev;
-
}irq用于判断pen down up,启动adc上报坐标事件.
-
-
-
未完待续....
-
-
-
Thanks
-
-
-
-
-
-
-
-
-
阅读(1040) | 评论(0) | 转发(0) |