记录1:
字符设备设置名字在函数中
device_create(tty_class, device, dev, NULL, name);
dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
retval = device_register(dev);
与用户空间交互的结构体中设置的kobject名字就是用户需要使用的设备文件
记录2:
1. Input子系统由驱动层、输入子系统核心层和事件处理层三部分组成。驱动程序员需要开发的程序集中在驱动层,核心层和事件处理层在各平台可以通用。在驱动层主要涉及到的结构体就是input_dev结构体。input_dev是物理输入设备的基本数据结构,包括设备相关的一些信息。
struct input_dev {
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //支持事件的类别
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //具体支持的事件属性如X坐标,Y坐标事件,Z坐标事件
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)];
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 keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev,
unsigned int scancode, unsigned int keycode);
int (*getkeycode)(struct input_dev *dev,
unsigned int scancode, unsigned int *keycode);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int sync;
int abs[ABS_CNT];
int rep[REP_MAX + 1];
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 absmax[ABS_CNT];
int absmin[ABS_CNT];
int absfuzz[ABS_CNT];
int absflat[ABS_CNT];
int absres[ABS_CNT];
int (*open)(struct input_dev *dev);
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 *grab; //grab是强制为input device的handler
spinlock_t event_lock;
struct mutex mutex;
unsigned int users;
bool going_away;
struct device dev;
struct list_head h_list; //handle链表
struct list_head node; //input_dev链表
};
具体案例分析相关三个文件input.c evdev.c w55fa93_ts.c,这三个文件分别位于核心层,事件层,驱动层。
与用户空间进行交互的file_operations位于事件层。
与底层硬件进行交互的函数接口位于驱动层。
作为子系统比较通用的两个文件是input.c evdev.c,当进行子系统设备注册后进行关联。即input_register_device函数。
驱动层
触摸屏涉及到的中断有两种:触碰中断和AD转换完成中断
首先作为一个平台设备,也需要做平台驱动注册。当匹配成功则调用drv->probe函数。
1. 当insmod驱动程序后会执行w55fa93ts_init函数。这个函数所做的工作就是平台驱动进行注册,与平台设备进行匹配,如果成功则执行平台驱动的probe函数。
static int __init w55fa93ts_init(void)
{
DBG_PRINTF2("ADC: %s\n", __FUNCTION__);
#ifdef CONFIG_ADC_LIGHT_BATTERY
sys_adc = platform_device_register_simple("w55fa93-adc", -1, NULL, 0);
if (sys_adc == NULL)
printk("register adc detection module failed\n");
sysfs_create_group(&sys_adc->dev.kobj, &adc_attr_group);
#endif
return platform_driver_probe(&w55fa93ts_driver, &w55fa93ts_probe);
}
platform_driver_probe–>platform_driver_register–>driver_register–>bus_add_driver–>driver_attach(drv)–>return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)–>__driver_attach–>driver_match_device–>driver_probe_device(drv, dev)–>really_probe(dev, drv)–>drv->probe(dev)
最终到了probe函数。
w55fa93ts_probe函数工作很简单:1.取出资源如中断号 2.获取adc时钟并使能 3.分配一个input_dev结构体并填充里面成员,主要填充的对象有名字、事件、事件属性、open、close等。 4.注册中断,注册子系统
static int __devinit w55fa93ts_probe(struct platform_device *pdev)
{
int irq, result, err;
struct clk *clk;
DBG_PRINTF("ADC: %s\n", __FUNCTION__);
//outl(inl(REG_APBCLK) | ADC_CKE, REG_APBCLK);
clk = clk_get(NULL, "ADC");
clk_enable(clk);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq for device\n");
return -ENOENT;
} else {
irqnum = irq;
}
if (!request_mem_region((unsigned long)W55FA93_VA_ADC, SZ_4K, "w55fa93-ts")) {
return -EBUSY;
}
if (!(w55fa93_dev = input_allocate_device())) {
printk(KERN_ERR "w55fa93_dev: not enough memory\n");
err = -ENOMEM;
goto fail;
}
INIT_DELAYED_WORK(&ts_work, w55fa93ts_work);
w55fa93_dev->name = "W55FA93 TouchScreen";
w55fa93_dev->phys = "w55fa93/event0";
w55fa93_dev->id.bustype = BUS_HOST;
w55fa93_dev->id.vendor = 0x0005;
w55fa93_dev->id.product = 0x0001;
w55fa93_dev->id.version = 0x0100;
w55fa93_dev->open = w55fa93ts_open;
w55fa93_dev->close = w55fa93ts_close;
w55fa93_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_SYN); // 支持按键类事件,绝对坐标事件和所有事件
w55fa93_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(w55fa93_dev, ABS_X, 0, 0x400, 0, 0); //对于X轴范围是0-ox400,数据误差是0,中心平滑位置是0,AD转换出的数据最大为10位,所以不会超过0x3ff。
input_set_abs_params(w55fa93_dev, ABS_Y, 0, 0x400, 0, 0);
input_set_abs_params(w55fa93_dev, ABS_PRESSURE, 0, 1000, 0, 0); //这个是设置触摸屏是否按下的标志
result = request_irq(irq, adc_isr, IRQF_DISABLED | IRQF_SHARED, "ADC", w55fa93_dev);
//outl((1 << irqnum ), REG_AIC_MDCR);
disable_irq(irqnum);
if (result != 0)
printk("register ADC ISR failed!\n");
input_register_device(w55fa93_dev);
DBG_PRINTF("Register touch screen success\n");
return 0;
fail:
input_free_device(w55fa93_dev);
return err;
}
接下来w55fa93ts_open函数
static int w55fa93ts_open(struct input_dev *dev)
{
//int result;
//int irq;
DBG_PRINTF2("ADC: %s\n", __FUNCTION__);
spin_lock(&spin_ts_opc);
i32TsOpenCount++;
if (i32TsOpenCount != 1) {
// Ts has open,
spin_unlock(&spin_ts_opc);
return 0;
} else
spin_unlock(&spin_ts_opc);
init_timer(&ts_timer);
#ifdef CONFIG_ADC_LIGHT_BATTERY
init_timer(&ain_timer);
#endif
w55fa93_ts_pressing = 0;
ts_timer.function = timer_check_touch; /* timer handler */
#ifdef CONFIG_ADC_LIGHT_BATTERY
ain_timer.function = timer_check_ain;
mod_timer(&ain_timer, jiffies + AIN_FREQ);
#endif
#if 0
/* reset */
outl(inl(REG_APBIPRST) | ADCRST, REG_APBIPRST);
udelay(10);
outl(inl(REG_APBIPRST) & ~ADCRST, REG_APBIPRST);
udelay(10);
#endif
outl(inl(REG_AUDIO_CON) | AUDIO_RESET, REG_AUDIO_CON);
outl(inl(REG_AUDIO_CON) & ~AUDIO_RESET, REG_AUDIO_CON);
outl(0x500000, REG_AUDIO_CON);
outl(inl(REG_ADC_CON) | ADC_RST, REG_ADC_CON);
outl(inl(REG_ADC_CON) & ~ADC_RST, REG_ADC_CON);
outl(inl(REG_AGCP1) & ~0x80000000, REG_AGCP1); // Disable EDMA for ADC
//Need to modify this value if need
outl(0x1800, REG_ADC_DLY); //过多长时间后进行ad转换
#ifdef CONFIG_ADC_LIGHT_BATTERY
/* For report 1th battery */
SET_NORMAL_AIN2_WI;
SET_NORMAL_AIN2_WI_WR;
w55fa93_vol = inl(REG_ADC_XDATA);
outl( inl(REG_ADC_CON) | WT_INT | LVD_INT | ADC_INT, REG_ADC_CON);
SET_NORMAL_AIN3_WI;
SET_NORMAL_AIN3_WI_WR;
w55fa93_lux = inl(REG_ADC_XDATA);
outl( inl(REG_ADC_CON) | WT_INT | LVD_INT | ADC_INT, REG_ADC_CON);
#endif
/* waiting for trigger mode */
outl( (inl(REG_ADC_CON) | (WT_INT_EN | ADC_TSC_MODE | WT_INT | ADC_INT | ADC_CON_ADC_EN)) &
~ADC_DIV, REG_ADC_CON);
state = W55FA93_ADC_STATE_WT;
DBG_PRINTF("Open: W55FA93_ADC_STATE_WT");
outl((inl(REG_ADC_TSC) | ADC_PU_EN), REG_ADC_TSC);
__raw_writel(__raw_readl(REG_ADC_CON) & ~WT_INT, REG_ADC_CON);
__raw_writel(__raw_readl(REG_ADC_CON) | WT_INT, REG_ADC_CON);
outl((inl(REG_ADC_TSC) & ~ADC_PU_EN), REG_ADC_TSC);
//adc_enable_irq();
enable_irq(irqnum);
return 0;
}
w55fa93ts_open函数完成的主要工作是定时器的初始化和硬件初始化工作。并将状态设置为等待触摸中断模式。
w55fa93ts_close 函数完成的工作就是失能中断寄存器和删除定时器。
static void w55fa93ts_close(struct input_dev *dev)
{
DBG_PRINTF2("ADC: %s\n", __FUNCTION__);
spin_lock(&spin_ts_opc);
i32TsOpenCount--;
if (i32TsOpenCount < 0)
i32TsOpenCount = 0;
if (i32TsOpenCount != 0) {
// Ts has open,
spin_unlock(&spin_ts_opc);
return;
} else
spin_unlock(&spin_ts_opc);
spin_adc_int = SPIN_LOCK_UNLOCKED;
//outl((1 << irqnum ), REG_AIC_MDCR);
disable_irq(irqnum);
del_timer(&ts_timer);
#ifdef CONFIG_ADC_LIGHT_BATTERY
del_timer(&ain_timer);
#endif
//return 0;
}
接下来看看当触碰到触摸屏时产生中断的过程。本实验使用了工作队列,中断的处理放置在低半部的工作队列中。
static int w55fa93ts_work()
{
unsigned long reg;
unsigned char temp=0;
u32 volatile xPos, yPos,xdata[2],ydata[2];
//unsigned long flags;
DBG_PRINTF2("ADC: %s\n", __FUNCTION__);
reg = inl(REG_ADC_CON);
if ( (reg & WT_INT) && (state == W55FA93_ADC_STATE_WT) ) {
//wait for trigger
DBG_PRINTF("wait for trigger\n");
outl((inl(REG_ADC_TSC) | ADC_PU_EN), REG_ADC_TSC);
__raw_writel(__raw_readl(REG_ADC_CON) & ~WT_INT, REG_ADC_CON);
__raw_writel(__raw_readl(REG_ADC_CON) | WT_INT, REG_ADC_CON);
outl((inl(REG_ADC_TSC) & ~ADC_PU_EN), REG_ADC_TSC);
outl( inl(REG_ADC_CON) | WT_INT | LVD_INT | ADC_INT, REG_ADC_CON);
DBG_PRINTF("WT INT = 0x%x\n", inl(REG_ADC_CON));
w55fa93_ts_pressing = 1;
state = W55FA93_ADC_STATE_AUTO;
SET_AUTO_MODE; /* It will disable WT_INT_EN. Otherwise WT_INT always interrupt system */
} else if ((reg & ADC_INT) && (state == W55FA93_ADC_STATE_AUTO)) {
// auto conv end
DBG_PRINTF("auto conv end\n");
outl( inl(REG_ADC_CON) | WT_INT | LVD_INT | ADC_INT, REG_ADC_CON);
if ((inl(REG_ADC_TSC) & ADC_TSC_MAV_EN) ) {
xPos = inl(REG_TSC_MAV_X);
yPos = inl(REG_TSC_MAV_Y);
} else {
for (temp = 0; temp < 2; temp++) {
DrvADC_Conversion();
DrvADC_PollingADC();
ydata[temp] = inl(REG_ADC_YDATA) & 0xFFFF;
xdata[temp] = inl(REG_ADC_XDATA) & 0xFFFF;
}
}
//Add 2012-04-24
state = W55FA93_ADC_STATE_WT; /* Why add the statement will cause crash ???*/
SET_WT_MODE;
// udelay(2); //Wait for WT state stable (not stable)
udelay(100); //Wait for WT state stable
if ((inl(REG_ADC_TSC)&ADC_UD) == ADC_UD) { //Pen still in down state
au16XPos[Idx] = xdata[0];
au16YPos[Idx] = ydata[0];
Idx++;
au16XPos[Idx] = xdata[1];
au16YPos[Idx] = ydata[1];
Idx++;
}else{
Idx=0;
}
if(Idx>3
&&(abs(au16XPos[0]-au16XPos[3])>30
||abs(au16YPos[0]-au16YPos[3])>30
||abs(au16XPos[1]-au16XPos[2])>30
||abs(au16YPos[1]-au16YPos[2])>30))
{
Idx=0;
// printk("error position @@@\r\n");
}
if ((inl(REG_ADC_TSC)&ADC_UD) == ADC_UD&&Idx>3) { //Pen still in down state
DBG_PRINTF("Pen still in down state\n");
xPos = (au16XPos[SORT_FIFO - 4] + au16XPos[SORT_FIFO - 3] + au16XPos[SORT_FIFO - 2]+au16XPos[SORT_FIFO - 1]) >>2; //averaging
yPos = (au16YPos[SORT_FIFO - 4] + au16YPos[SORT_FIFO - 3] + au16YPos[SORT_FIFO - 2]+au16YPos[SORT_FIFO - 1]) >>2;
report_touch(xPos, yPos);
count = 0;
Idx=0;
DBG_PRINTF("X0:%d Y0:%d\r\n",au16XPos[0],au16YPos[0]);
DBG_PRINTF("X1:%d Y1:%d\r\n",au16XPos[1],au16YPos[1]);
DBG_PRINTF("X2:%d Y2:%d\r\n",au16XPos[2],au16YPos[2]);
DBG_PRINTF("X3:%d Y3:%d\r\n",au16XPos[3],au16YPos[3]);
DBG_PRINTF("X Y = %d, %d\r\n", xPos, yPos);
} else
count = count + 1;
mod_timer(&ts_timer, jiffies + INTERVAL_TIME);
}
else {
// darn, unknown status. It should be wait for trigger interrupt. Change state to AUTO mode.
DBG_PRINTF("darn, unknown status\n");
outl((inl(REG_ADC_TSC) | ADC_PU_EN), REG_ADC_TSC);
__raw_writel(__raw_readl(REG_ADC_CON) & ~WT_INT, REG_ADC_CON);
__raw_writel(__raw_readl(REG_ADC_CON) | WT_INT, REG_ADC_CON);
outl((inl(REG_ADC_TSC) & ~ADC_PU_EN), REG_ADC_TSC);
outl( inl(REG_ADC_CON) | WT_INT | LVD_INT | ADC_INT, REG_ADC_CON);
DBG_PRINTF("WT INT = 0x%x\n", inl(REG_ADC_CON));
w55fa93_ts_pressing = 1;
state = W55FA93_ADC_STATE_AUTO;
SET_AUTO_MODE; /* It will disable WT_INT_EN. Otherwise WT_INT always interrupt system */
}
enable_irq(irqnum);
}
工作队列中首先判断产生中断的原因是触摸中断或者是adc转换完成产生的中断。
第一次是触摸笔按下产生中断了,设置按下标记,并启动ad转换
第二次是ad转换完成了,将ad转换的值读出来,并将状态设置为等待触摸中断状态。通过判断标记位查看按键是否还处于按下状态,表明并非抖动引起的按键操作。上报时间并启动定时器来检验长按。
static void timer_check_touch(unsigned long dummy)
{
//DBG_PRINTF("ADC: %s\n",__FUNCTION__);
unsigned long flags;
//outl((1 << irqnum ), REG_AIC_MDCR);
adc_disable_irq();
LOCK(flags);
/*2012-04-24*/
if (state != W55FA93_ADC_STATE_WT) {
mod_timer(&ts_timer, jiffies + INTERVAL_TIME);
UNLOCK(flags);
//outl((1 << irqnum ), REG_AIC_MECR);
adc_enable_irq();
return;
}
if ( ((inl(REG_ADC_TSC)&ADC_UD) == ADC_UD) ) {
//report down/up state in WT mode. The bit is only workable in wake for trigger mode.
SET_AUTO_MODE;
state = W55FA93_ADC_STATE_AUTO;
w55fa93_ts_pressing = 1;
DBG_PRINTF("%s, ts is pressing, start this timer\n", __func__);
mod_timer(&ts_timer, jiffies + INTERVAL_TIME);
} else {
if ( (u16LastX != 0) && (u16LastY != 0) ) {
input_report_abs(w55fa93_dev, ABS_X, u16LastX);
input_report_abs(w55fa93_dev, ABS_Y, u16LastY);
input_report_key(w55fa93_dev, BTN_TOUCH, 0);
input_report_abs(w55fa93_dev, ABS_PRESSURE, 0);
input_report_abs(w55fa93_dev, ABS_PRESSURE, 0);
input_sync(w55fa93_dev);
}
Idx = 0;
count = 0;
#else
DBG_PRINTF("%s, SET_WT_MODE_I\n", __func__);
SET_WT_MODE_I;
state = W55FA93_ADC_STATE_WT;
w55fa93_ts_pressing = 0;
#endif
}
//mod_timer(&ts_timer, jiffies + INTERVAL_TIME);
UNLOCK(flags);
//outl((1 << irqnum ), REG_AIC_MECR);
adc_enable_irq();
return;
}
第三步在定时器中启动ad转换,若转换完成又回到中断函数中,并进行上报工作。
第四步若已经抬起触摸,则也启动定时器,并在定时器中上报抬起按键事件。
至此 驱动层差不多已经分析完了。
“drivers/input/input.c”核心层
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 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",
(unsigned long) atomic_inc_return(&input_no) - 1);
error = device_add(&dev->dev); //作为一个输入设备,也需要将其进行注册,并加入到设备链表
if (error)
return error;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %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);
list_for_each_entry(handler, &input_handler_list, node) //在handler链表上取出handler
input_attach_handler(dev, handler); //进行比对,如果比对成功,则调用handler->connect函数。这个函数在事件层定义。
mutex_unlock(&input_mutex);
return 0;
}
EXPORT_SYMBOL(input_register_device);
接下来看看事件层的东西,事件层有与用户空间进行交互的接口。
static const struct file_operations evdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
.unlocked_ioctl = evdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = evdev_ioctl_compat,
#endif
.fasync = evdev_fasync,
.flush = evdev_flush
};
在对事件层进行加载之后,会注册input_register_handler(&evdev_handler);这个函数的作用是将handler放置在链表上面。然后与输入设备进行比对。此函数在”drivers/input/input.c”核心层
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);
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
out:
mutex_unlock(&input_mutex);
return retval;
}
EXPORT_SYMBOL(input_register_handler);
当匹配成功后,调用evdev_connect函数。
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct evdev *evdev;
int minor;
int error;
for (minor = 0; minor < EVDEV_MINORS; minor++)
if (!evdev_table[minor])
break;
if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devices\n");
return -ENFILE;
}
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
if (!evdev)
return -ENOMEM;
INIT_LIST_HEAD(&evdev->client_list);
spin_lock_init(&evdev->client_lock);
mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait);
dev_set_name(&evdev->dev, "event%d", minor);
evdev->exist = 1;
evdev->minor = minor;
evdev->handle.dev = input_get_device(dev);
evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler;
evdev->handle.private = evdev;
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
evdev->dev.release = evdev_free;
device_initialize(&evdev->dev);
error = input_register_handle(&evdev->handle);
if (error)
goto err_free_evdev;
error = evdev_install_chrdev(evdev);
if (error)
goto err_unregister_handle;
error = device_add(&evdev->dev);
if (error)
goto err_cleanup_evdev;
return 0;
err_cleanup_evdev:
evdev_cleanup(evdev);
err_unregister_handle:
input_unregister_handle(&evdev->handle);
err_free_evdev:
put_device(&evdev->dev);
return error;
}
这个函数主要是对evdev设备的设备成员和handle成员进行填充。
并注册evdev设备,名字可以在/dev下看到event%d这个设备文件。
而后调用error = input_register_handle(&evdev->handle);函数进行handle的注册。
handle这个结构体是连接handler和input_dev的桥梁。
int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
struct input_dev *dev = handle->dev;
int error;
/*
* We take dev->mutex here to prevent race with
* input_release_device().
*/
error = mutex_lock_interruptible(&dev->mutex);
if (error)
return error;
/*
* Filters go to the head of the list, normal handlers
* to the tail.
*/
if (handler->filter)
list_add_rcu(&handle->d_node, &dev->h_list);
else
list_add_tail_rcu(&handle->d_node, &dev->h_list);
mutex_unlock(&dev->mutex);
/*
* Since we are supposed to be called from ->connect()
* which is mutually exclusive with ->disconnect()
* we can't be racing with input_unregister_handle()
* and so separate lock is not needed here.
*/
list_add_tail_rcu(&handle->h_node, &handler->h_list);
if (handler->start)
handler->start(handle);
return 0;
}
EXPORT_SYMBOL(input_register_handle);
在这个函数中主要是将其放置在各自的链表中,以便查找。
当用户打开这个设备后
static int evdev_open(struct inode *inode, struct file *file)
{
struct evdev *evdev;
struct evdev_client *client;
int i = iminor(inode) - EVDEV_MINOR_BASE;
int error;
if (i >= EVDEV_MINORS)
return -ENODEV;
error = mutex_lock_interruptible(&evdev_table_mutex);
if (error)
return error;
evdev = evdev_table[i];
if (evdev)
get_device(&evdev->dev);
mutex_unlock(&evdev_table_mutex);
if (!evdev)
return -ENODEV;
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
if (!client) {
error = -ENOMEM;
goto err_put_evdev;
}
spin_lock_init(&client->buffer_lock);
client->evdev = evdev;
evdev_attach_client(evdev, client);
error = evdev_open_device(evdev);
if (error)
goto err_free_client;
file->private_data = client;
nonseekable_open(inode, file);
return 0;
err_free_client:
evdev_detach_client(evdev, client);
kfree(client);
err_put_evdev:
put_device(&evdev->dev);
return error;
}
通过次设备号找到evdev结构体
static ssize_t evdev_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
int retval;
if (count < input_event_size())
return -EINVAL;
if (client->head == client->tail && evdev->exist &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(evdev->wait,
client->head != client->tail || !evdev->exist);
if (retval)
return retval;
if (!evdev->exist)
return -ENODEV;
while (retval + input_event_size() <= count &&
evdev_fetch_next_event(client, &event)) {
if (input_event_to_user(buffer + retval, &event))
return -EFAULT;
retval += input_event_size();
}
return retval;
}
如果如果没读到内容并设置了非阻塞O_NONBLOCK,则直接返回,否则等待有内容填充进来将其唤醒,而后拷贝至用户空间。
何时填充这个结构体呢?
input_event(dev, EV_KEY, code, !!value);这个函数是用来填充evdev结构体的
input_event–>input_handle_event(dev, type, code, value)–>input_pass_event(dev, type, code, value)–>evdev_event–>evdev_pass_event
–>wake_up_interruptible