这是2.6.15以前某个版本,2.6.15已经略有不同,但总体思想还是差不多
输入子系统大致实现方法:
底层驱动层(input_dev)-----<通过结构体input_handle关联>-----输入事件处理层类接口(input_handler)-----<输入核心层input.c>-----应用层
-----------------------------------------------------
struct input_handle { //用于关联底层驱动层input_dev和事件处理层input_handler
void *private;
int open;
struct input_dev *dev;
struct input_handler *handler;
struct input_handle *dnext;
struct input_handle *hnext;
};
-----------------------------------------------------
void input_register_device(struct input_dev *dev)
{
struct input_handler *handler = input_handler;
struct input_handle *handle;
/*
* Initialize repeat timer to default values.
*/
init_timer(&dev->timer);
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = HZ/4;
dev->rep[REP_PERIOD] = HZ/33;
/*
* Add the device.
*/
if (input_number >= INPUT_DEVICES) {
printk(KERN_WARNING "input: ran out of input device numbers!\n");
dev->number = input_number;
} else {
dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES);
set_bit(dev->number, input_devices); //编号此输入设备
} //input_devices[8],8*32(BITS_PER_LONG)=256b,256 minor for each major
dev->next = input_dev; //插入到单链表首
input_dev = dev;
input_number++;
/*
* Notify handlers.
*/
while (handler) { //故应先通过input_register_handler注册handler到单链表中,即输入子系统的第二层:事件处理层
//事件处理层是类通用的,如endev,tsdev,mousedev等
//且某个具体的驱动层设备可以关联多个事件处理层接口,生成多个节点
//用户程序根据打开的节点判断调用某一类事件处理层接口,进而关联驱动层
if ((handle = handler->connect(handler, dev)))
input_link_handle(handle);
-------------------------------
static void input_link_handle(struct input_handle *handle)
{
handle->dnext = handle->dev->handle;
handle->hnext = handle->handler->handle;
handle->dev->handle = handle;
handle->handler->handle = handle;
}
-------------------------------
handler = handler->next;
}
}
------------------------------------------------
以endev为例:
static struct input_handler evdev_handler = {
event: evdev_event,
connect: evdev_connect,
disconnect: evdev_disconnect,
fops: &evdev_fops,
minor: EVDEV_MINOR_BASE,
};
static struct file_operations evdev_fops = {
owner: THIS_MODULE,
read: evdev_read,
write: evdev_write,
poll: evdev_poll,
open: evdev_open,
release: evdev_release,
ioctl: evdev_ioctl,
fasync: evdev_fasync,
};
-------------------------------------
void input_register_handler(struct input_handler *handler)
{
struct input_dev *dev = input_dev;
struct input_handle *handle;
/*
* Add minors if needed.
*/
if (handler->fops != NULL)
input_table[handler->minor >> 5] = handler;
/*
* Add the handler.
*/
handler->next = input_handler; //插入到单链表首
input_handler = handler;
/*
* Notify it about all existing devices.
*/
while (dev) {
if ((handle = handler->connect(handler, dev)))
input_link_handle(handle);
dev = dev->next;
}
}
----------------------------------------
static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev)
{
struct evdev *evdev;
int minor;
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); //evdev_table记录endev的个数
if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devices\n");
return NULL;
}
if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL))) //申请一个新的endev
return NULL;
memset(evdev, 0, sizeof(struct evdev));
init_waitqueue_head(&evdev->wait);
evdev->minor = minor;
evdev_table[minor] = evdev; //添加到evdev_table
evdev->handle.dev = dev; //实现驱动层和事件处理层的关联
evdev->handle.handler = handler;
evdev->handle.private = evdev;
evdev->exist = 1;
evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);
// printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number);
return &evdev->handle;
}
------------------------------------------
devfs_handle_t input_register_minor(char *name, int minor, int minor_base)
{
char devfs_name[16];
sprintf(devfs_name, name, minor); //创建设备节点:INPUT_MAJOR=13,
//minor_base+minor:
// EVDEV_MINOR_BASE(64)+(0-31);
// MOUSEDEV_MINOR_BASE(32)+(0-31);
// JOYDEV_MINOR_BASE(0)+(0-31);
// TSDEV_MINOR_BASE(128)+(0-31);
//input_devfs_handle=devfs_mk_dir(NULL, "input", NULL);
//在/dev/input/下可看到相关的input设备节点
return devfs_register(input_devfs_handle, devfs_name, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base,
S_IFCHR | S_IRUGO | S_IWUSR, &input_fops, NULL);
}
-----------------------------------------
static int __init input_init(void)
{
if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) {
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
return -EBUSY;
}
input_devfs_handle = devfs_mk_dir(NULL, "input", NULL);
return 0;
}
----------------------------------------
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct input_handle *handle = dev->handle;
/*
* Filter non-events, and bad input values out.
*/
if (type > EV_MAX || !test_bit(type, dev->evbit))
return;
switch (type) {
case EV_KEY:
if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
return;
if (value == 2) break;
change_bit(code, dev->key);
if (test_bit(EV_REP, dev->evbit) && dev->timer.function) {
if (value) {
mod_timer(&dev->timer, jiffies + dev->rep[REP_DELAY]);
dev->repeat_key = code;
break;
}
if (dev->repeat_key == code)
del_timer(&dev->timer);
}
break;
case EV_ABS:
if (code > ABS_MAX || !test_bit(code, dev->absbit))
return;
if (dev->absfuzz[code]) {
if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
(value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
return;
if ((value > dev->abs[code] - dev->absfuzz[code]) &&
(value < dev->abs[code] + dev->absfuzz[code]))
value = (dev->abs[code] * 3 + value) >> 2;
if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
(value < dev->abs[code] + (dev->absfuzz[code] << 1)))
value = (dev->abs[code] + value) >> 1;
}
if (dev->abs[code] == value)
return;
dev->abs[code] = value;
break;
case EV_REL:
if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
return;
break;
case EV_MSC:
if (code > MSC_MAX || !test_bit(code, dev->mscbit))
return;
break;
case EV_LED:
if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
return;
change_bit(code, dev->led);
if (dev->event) dev->event(dev, type, code, value);
break;
case EV_SND:
if (code > SND_MAX || !test_bit(code, dev->sndbit) || !!test_bit(code, dev->snd) == value)
return;
change_bit(code, dev->snd);
if (dev->event) dev->event(dev, type, code, value);
break;
case EV_REP:
if (code > REP_MAX || dev->rep[code] == value) return;
dev->rep[code] = value;
if (dev->event) dev->event(dev, type, code, value);
break;
case EV_FF:
if (dev->event) dev->event(dev, type, code, value);
break;
}
/*
* Distribute the event to handler modules.
*/
while (handle) {
//遍历每个打开的handle
if (handle->open)
//when open a input device,record it once time
//in function input_open_device,handle->open++;
handle->handler->event(handle, type, code, value);
handle = handle->dnext;
}
}
-----------------------------------
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_list *list = evdev->list;
while (list) {
do_gettimeofday(&list->buffer[list->head].time);
list->buffer[list->head].type = type;
list->buffer[list->head].code = code;
list->buffer[list->head].value = value;
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN);
list = list->next;
}
wake_up_interruptible(&evdev->wait); //填充数据结构,并唤醒相关的等待进程。
}
-----------------------------------
至于何时打开:
static struct file_operations input_fops = {
owner: THIS_MODULE,
open: input_open_file,
};
-----------------------------------
static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5]; //LINUX最多8类事件处理层接口,各32个节点
//打开某个设备时,根据节点大小选择事件处理层接口
struct file_operations *old_fops, *new_fops = NULL;
int err;
/* No load-on-demand here? */
if (!handler || !(new_fops = fops_get(handler->fops))) //得到相应的事件处理层接口的操作接口
return -ENODEV;
/*
* That's _really_ odd. Usually NULL ->open means "nothing special",
* not "no device". Oh, well...
*/
if (!new_fops->open) {
fops_put(new_fops);
return -ENODEV;
}
old_fops = file->f_op;
file->f_op = new_fops;
lock_kernel();
err = new_fops->open(inode, file); //进一步调用
unlock_kernel();
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
return err;
}
---------------------------------------
static int evdev_open(struct inode * inode, struct file * file)
{
struct evdev_list *list;
int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE;
if (i >= EVDEV_MINORS || !evdev_table[i])
return -ENODEV;
if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
return -ENOMEM;
memset(list, 0, sizeof(struct evdev_list));
list->evdev = evdev_table[i]; //得到底层驱动层
list->next = evdev_table[i]->list;
evdev_table[i]->list = list;
file->private_data = list;
if (!list->evdev->open++) //若未打开,则调用input_open_device并标识为打开
if (list->evdev->exist)
input_open_device(&list->evdev->handle);
return 0;
}
--------------------------------------
int input_open_device(struct input_handle *handle)
{
handle->open++; //打开handle实现
if (handle->dev->open)
return handle->dev->open(handle->dev); //驱动层若有open,进一步实现
return 0;
}