天天看點

[轉]2.6核心輸入子系統分析-續

上文介紹了input_dev 、input_handle、input_handler三者是如何聯系起來了,現在繼續介紹如何通過它們來傳遞資訊。

在開始之前還是先引用一位大俠的文章:

引:

現在看使用者擷取觸摸屏輸入的一個流程(以tsdev為例/drivers/input/tsdev.c):
static struct file_operations tsdev_fops = {
        .owner =        THIS_MODULE,
        .open =         tsdev_open,
        .release =      tsdev_release,
        .read =         tsdev_read,
        .poll =         tsdev_poll,
        .fasync =       tsdev_fasync,
        .ioctl =        tsdev_ioctl,
};
假設所有初始化早已完成,使用者open該裝置後,使用read系統調用進入核心,系統
轉移控制到tsdev_read,使用wait_event_interruptible等待事件。

此時驅動層得到使用者輸入,于是調用input_report_abs,input_report_abs隻是
input_event的簡單包裝:
static inline void input_report_abs(struct input_dev *dev, 
                                     unsigned int code, int value)
{
        input_event(dev, EV_ABS, code, value);
}

void input_event(struct input_dev *dev, unsigned int type, 
                                  unsigned int code, int value)
{
    ...
    switch (type) {
        ...
        case EV_ABS:
            ...
            break;
        ...
    }
    ...

    if (dev->grab)
        dev->grab->handler->event(dev->grab, type, code, value);
    else
        list_for_each_entry(handle, &dev->h_list, d_node)
            if (handle->open)
                handle->handler->event(handle, type, code, value);
}
前面的處理關系具體裝置,見最後對handler函數的調用,就是從input_dev的h_list鍊
上的input_handle獲得每一個相關input_handler,并調用其中的event函數,對tsdev
來說:
static struct input_handler tsdev_handler = {
        .event =        tsdev_event,
        .connect =      tsdev_connect,
        .disconnect =   tsdev_disconnect,
        .fops =         &tsdev_fops,
        .minor =        TSDEV_MINOR_BASE,
        .name =         "tsdev",
        .id_table =     tsdev_ids,
};
即調用tsdev_event函數,接着看:
static void tsdev_event(struct input_handle *handle, unsigned int type,
                        unsigned int code, int value)
{
    ...
    switch (type) {
        case EV_ABS:
            break;
    ...
    list_for_each_entry(list, &tsdev->list, node) {
        int x, y, tmp;
        do_gettimeofday(&time);
        list->event[list->head].millisecs = time.tv_usec / 100;
        list->event[list->head].pressure = tsdev->pressure;

        x = tsdev->x;
        y = tsdev->y;
        /* Calibration */
        if (!list->raw) {
            x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
            y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
            if (tsdev->cal.xyswap) {
                tmp = x; x = y; y = tmp;
            }
        }

        list->event[list->head].x = x;
        list->event[list->head].y = y;
        list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
        kill_fasync(&list->fasync, SIGIO, POLL_IN);
    }
    wake_up_interruptible(&tsdev->wait);
}
它填充資料,并喚醒等待着的請求。于是前面等待着的read請求就可繼續了,
回到tsdev_read中,copy_to_user拷貝資料,最後傳回使用者層。


一個簡單流程就結束了。      

注:

    原文請看以下網址:

http://bbs.ustc.edu.cn/cgi/bbstcon?board=Kernel&file=M.1179398612.A

看了以上的内容,相信你對2.6核心的輸入子系統的消息傳遞過程應該有個大概的了解了,現在我就如何通過input_dev 、input_handle、input_handler這三者傳遞資訊進行詳細的分析:

################

從<tsdev.c>開始

################

static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,

                          loff_t * ppos)

{

        struct tsdev_list *list = file->private_data;

        int retval = 0;

        if (list->head == list->tail && list->tsdev->exist && (file->f_flags & O_NONBLOCK))

                return -EAGAIN;

        retval = wait_event_interruptible(list->tsdev->wait,

                        list->head != list->tail || !list->tsdev->exist);

        if (retval)

                return retval;

        if (!list->tsdev->exist)

                return -ENODEV;

        while (list->head != list->tail &&

               retval + sizeof (struct ts_event) <= count) {

                if (copy_to_user (buffer + retval, list->event + list->tail,

                                  sizeof (struct ts_event)))

                        return -EFAULT;

                list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);//更新讀指針

                retval += sizeof (struct ts_event);//更新讀位元組數

        }

        return retval;

}

#################

<s3c2410-ts.c>

#################

        input_report_abs(&ts.dev, ABS_X, ts.xp);

        input_report_abs(&ts.dev, ABS_Y, ts.yp);

        input_report_key(&ts.dev, BTN_TOUCH, 1);

        input_report_abs(&ts.dev, ABS_PRESSURE, 1);

        input_sync(&ts.dev);

###########################

<input.h>

###########################

static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)

{

        input_event(dev, EV_ABS, code, value);

}

##########################

<input.c>

##########################

void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

{

struct input_handle *handle;

........................................................................................................

        switch (type) {

                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;

...............................................................................................................

        if (type != EV_SYN)

                dev->sync = 0;

        if (dev->grab)

                dev->grab->handler->event(dev->grab, type, code, value);

        else

                list_for_each_entry(handle, &dev->h_list, d_node)//通過input_dev找出與其聯系的input_handle

                        if (handle->open)//相應的接口裝置(比如tsdev)被打開(通過調用tsdev.c的tsdev_open函數進而調用input_open_device

                         函數增加handle->open的計數值)

                                handle->handler->event(handle, type, code, value);//調用該接口裝置的event函數對資料進行處理

}

################

在<tsdev.c>結束

################

static void tsdev_event(struct input_handle *handle, unsigned int type,

                        unsigned int code, int value)

{

        struct tsdev *tsdev = handle->private;

        struct tsdev_list *list;

        struct timeval time;

        switch (type) {

        case EV_ABS:

                switch (code) {

                case ABS_X:

                        tsdev->x = value;//記錄x坐标值

                        break;

                case ABS_Y:

                        tsdev->y = value;//記錄y坐标值

                        break;

                case ABS_PRESSURE:

                        if (value > handle->dev->absmax[ABS_PRESSURE])

                                value = handle->dev->absmax[ABS_PRESSURE];

                        value -= handle->dev->absmin[ABS_PRESSURE];

                        if (value < 0)

                                value = 0;

                        tsdev->pressure = value;//記錄觸摸屏的按壓狀态

                        break;

                }

                break;

...................................................................................................

        if (type != EV_SYN || code != SYN_REPORT)//鍵值的傳遞以EV_SYN為結束标志(通過input_sync函數),等到資料都填充好tsdev結構後再統一發送出去,否則直接傳回,繼續填充另一個資料

                return;

        list_for_each_entry(list, &tsdev->list, node) {    //通過tsdev擷取struct tsdev_list結構(在tsdev_open函數中定義):

                                //list_add_tail(&list->node, &tsdev_table[i]->list);

                int x, y, tmp;

                do_gettimeofday(&time);            //填充事件的時間

                list->event[list->head].millisecs = time.tv_usec / 100;

                list->event[list->head].pressure = tsdev->pressure;//填充觸摸屏的狀态

                x = tsdev->x;

                y = tsdev->y;

                if (!list->raw) {

                        x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;

                        y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;

                        if (tsdev->cal.xyswap) {

                                tmp = x; x = y; y = tmp;

                        }

                }

                list->event[list->head].x = x;        //填充x坐标值

                list->event[list->head].y = y;        //填充y坐标值

                list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);//更新寫指針

                kill_fasync(&list->fasync, SIGIO, POLL_IN);

        }

        wake_up_interruptible(&tsdev->wait);//喚醒睡眠在tsdev->wait下等待資料都程序讀取資料。至此,資料傳遞過程結束,開始新一輪的資料傳遞。

}