日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux--内核Uevent事件机制 与 Input子系统【转】

發布時間:2024/4/14 linux 69 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux--内核Uevent事件机制 与 Input子系统【转】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

閱讀目錄

  • Uevent在kernel中的位置
  • Uevent的內部邏輯解析

轉自:http://blog.csdn.net/lxl584685501/article/details/46379453

?

[-]

  • 一Uevent機制
  • Uevent在kernel中的位置
  • Uevent的內部邏輯解析
  • 二Input子系統?
  • 從應用層的角度出發看input子系統
  • 輸入設備上報事件的處理過程
  • 通過設備節點讀取輸入事件
  • 通過設備節點寫入輸入事件
  • 總結
  • 一、Uevent機制

    1.前提摘要

    (1)Sysfs文件系統?

    ??????? 內核設備模型主要的模塊和用戶之間能看到的相關部分就是sysfs文件系統了。內核在啟動的時候會注冊sysfs文件系統,并且在啟動系統的初期。通過mount命令掛載sysfs文件系統到/sys掛載點。

    ?????? Mount?-t?sysfs?sysfs?/sys

    ?

    ?????????? 那么sysfs文件系統的作用是什么呢。概括的說有三點:

    ??????????????????? 1)、建立系統中總線、驅動、設備三者之間的橋梁

    ??????????????????? 2)、像用戶空間展示內核中各種設備的拓撲圖

    ??????????????????? 3)、提供給用戶空間對設備獲取信息和操作的接口,部分取代ioctl功能。

    ?

    (2)Kobject:Sysfs文件系統中最基本的結構就是kobject,kobject可以代表一個設備,一條總線等。在sys目錄下直觀的以一個目錄表示出來。

    ?

    (3)Uevent機制

    ???? 上面的分析其實只是對Linux設備模型做了一些基礎性的了解。也就是一個穿針引線的作用,如果要細致了解,需要仔細閱讀代碼。有了上面對于sysfs的基礎。接下來我們來比較詳細的了解一下uevent機制。

    ???????? 什么是uevent機制。這個得從熱插拔設備開始說起。最簡單的一個例子就是U盤了。當我們在計算機上插上一個U盤的時候,系統的USB?hub會檢測到U盤設備接入,并且完成設備枚舉過程(從設備上讀出相應的設備信息),并在內核中創建相應的設備結構體。但是,usb設備千奇百態,內核不可能預先將所有usb設備驅動都增加到內存中來。也就是當插入U盤設備的時候,內核中不一定存在對應這個設備的usb驅動。這個時候USB驅動也許以模塊的形式保存在硬盤上。載入驅動必然只能從用戶態來進行,那這時候應該怎么辦呢?

    ????????? 看到這里的時候,有人一定會想,人工敲入命令載入驅動,呵呵。這必然是一種方法,但是是一種很古老的方法。Linux對類似的情況設計了一種uevent的機制。當有新的設備加入的時候,將設備的信息發送消息到用戶態。而用戶態有一個udev的進程監聽這個信息。當收到信息后做一定的解析,根據解析到的結果和用戶程序的配置做一些處理,也包括加載驅動程序。

    ?

    2.具體介紹(http://www.wowotech.net/linux_kenrel/uevent.html)

    ????????? Uevent是Kobject的一部分,用于在Kobject狀態發生改變時,例如增加、移除等,通知用戶空間程序。

    用戶空間程序收到這樣的事件后,會做相應的處理。

    ????????? 該機制通常是用來支持熱拔插設備的,例如U盤插入后,USB相關的驅動軟件會動態創建用于表示該U盤的device結構(相應的也包括其中的kobject),并告知用戶空間程序,為該U盤動態的創建/dev/目錄下的設備節點,

    更進一步,可以通知其它的應用程序,將該U盤設備mount到系統中,從而動態的支持該設備。

    回到頂部

    Uevent在kernel中的位置

    ??????????????

    ?

    ??????? 由此可知,Uevent的機制是比較簡單的,設備模型中任何設備有事件需要上報時,會觸發Uevent提供的接口。Uevent模塊準備好上報事件的格式后。

    ??????? 可以通過兩個途徑把事件上報到用戶空間:一種是通過kmod模塊,直接調用用戶空間的可執行文件;

    另一種是通過netlink通信機制,將事件從內核空間傳遞給用戶空間。

    ??????? 注1:有關kmod和netlink,會在其它文章中描述,因此本文就不再詳細說明了。

    回到頂部

    Uevent的內部邏輯解析

    ??????? Uevent的代碼比較簡單,主要涉及kobject.h和kobject_uevent.c兩個文件,如下:

    • include/linux/kobject.h
    • lib/kobject_uevent.c

    ??????? 前面有提到過,在利用Kmod向用戶空間上報event事件時,會直接執行用戶空間的可執行文件。而在Linux系統,可執行文件的執行,依賴于環境變量,因此kobj_uevent_env用于組織此次事件上報時的環境變量。

    ?

    ??? ? ?? 說明:怎么指定處理uevent的用戶空間程序(簡稱uevent helper)?

    ??? 上面介紹kobject_uevent_env的內部動作時,有提到,Uevent模塊通過Kmod上報Uevent時,會通過call_usermodehelper函數,調用用戶空間的可執行文件(或者腳本,簡稱uevent helper )處理該event。而該uevent helper的路徑保存在uevent_helper數組中。

    ?????? 可以在編譯內核時,通過CONFIG_UEVENT_HELPER_PATH配置項,靜態指定uevent helper。但這種方式會為每個event fork一個進程,隨著內核支持的設備數量的增多,這種方式在系統啟動時將會是致命的(可以導致內存溢出等)。因此只有在早期的內核版本中會使用這種方式,現在內核不再推薦使用該方式。因此內核編譯時,需要把該配置項留空。

    ????? 在系統啟動后,大部分的設備已經ready,可以根據需要,重新指定一個uevent helper,以便檢測系統運行過程中的熱拔插事件。這可以通過把helper的路徑寫入到"/sys/kernel/uevent_helper”文件中實現。實際上,內核通過sysfs文件系統的形式,將uevent_helper數組開放到用戶空間,供用戶空間程序修改訪問,具體可參考"./kernel/ksysfs.c”中相應的代碼,這里不再詳細描述。


    3.實例分析(http://blog.csdn.net/sunweizhong1024/article/details/7928530headphone_event 上報事件的分析

    ???? 本文章講解插入headphone的時候,向上層上報event函數的整個過程

    #ifdef?CONFIG_I_LOVE_PBJ30

    void?headphone_event(int?state)

    {

    ???????switch_set_state(&wired_switch_dev, state);

    }

    EXPORT_SYMBOL_GPL(headphone_event);

    #endif

    ?

    headphone_event 函數會調用switch_set_state函數進行上報事件

    ?

    接下來會調用kobject_uevent_env函數進行上報事件。

    ?

    最終調用add_uevent_var()將用戶空間需要的參數添加到環境變量中去,如

    retval = add_uevent_var(env,"ACTION=%s", action_string);

    ???????if?(retval)

    ??????????????goto?exit;

    ???????retval = add_uevent_var(env,"DEVPATH=%s", devpath);

    ???????if?(retval)

    ??????????????goto?exit;

    ???????retval = add_uevent_var(env,"SUBSYSTEM=%s", subsystem);

    ???????if?(retval)

    ??????????????goto?exit;

    ?

    4.實例分析2

    ???? Uevent?是內核通知Android有狀態變化的一種方法,比如USB線插入、拔出,電池電量變化等等。其本質是內核發送(可以通過socket)一個字符串,應用層(android)接收并解釋該字符串,獲取相應信息。

    ???? (一)、Kernel側:UEVENT的發起在Kernel端,主要是通過函數

    ???????????? intkobject_uevent_env(struct kobject*kobj, enum kobject_action action,char*envp_ext[])

    該函數的主要功能是根據參數組合一個字符串并發送。一個典型的字符串如下:change@/devices/platform/msm-battery/power_supply/usb纮ACTION=change纮DEVPATH=/devices/platform/msm-battery/power_supply/usb纮SUBSYSTEM=power_supply纮POWER_SUPPLY_NAME=usb纮POWER_SUPPLY_ONLINE=0纮SEQNUM=1486纮

    上面這塊來自網上,這段內容是否有問題,待考究。

    下面看這個函數: int kobject_uevent_env(structkobject *kobj, enum kobject_action action,char *envp_ext[])

    static const char *kobject_actions[] ={

    [KOBJ_ADD] = "add",

    [KOBJ_REMOVE] = "remove",

    [KOBJ_CHANGE] = "change",

    [KOBJ_MOVE] = "move",

    [KOBJ_ONLINE] = "online",

    [KOBJ_OFFLINE] = "offline",

    };

    //以上為kobject標準的動作,調用時需要傳入相應的enum值

    ?

    ?

    ///以下是獲取subsystem信息

    if (uevent_ops&&uevent_ops->name)

    subsystem =uevent_ops->name(kset, kobj);

    else

    subsystem =kobject_name(&kset->kobj);

    if (!subsystem) {

    pr_debug("kobject: '%s' (%p):%s: unset subsystem caused the "

    "event to drop!\n",kobject_name(kobj), kobj,

    __func__);

    return 0;

    }

    ?

    ?

    //下面準備要傳遞的信息數據

    retval =?add_uevent_var(env, "ACTION=%s",action_string);

    if (retval)

    goto exit;

    retval =?add_uevent_var(env, "DEVPATH=%s",devpath);

    if (retval)

    goto exit;

    retval =?add_uevent_var(env, "SUBSYSTEM=%s",subsystem);

    if (retval)

    goto exit;

    //envp_ext[i]是傳進來的參數,為該event時攜帶的一些自定義的信息

    if (envp_ext) {

    for (i = 0; envp_ext[i]; i++){

    retval =?add_uevent_var(env, "%s", envp_ext[i]);

    if (retval)

    goto exit;

    ?

    ?

    //下面通過網絡socket將數據發送出去

    mutex_lock(&uevent_sock_mutex);

    list_for_each_entry(ue_sk,&uevent_sock_list, list) {

    struct sock *uevent_sock =ue_sk->sk;

    struct sk_buff*skb;

    size_t len;

    ?

    NETLINK_CB(skb).dst_group =1;//下面開始發送數據

    retval =netlink_broadcast_filtered(uevent_sock, skb,

    0, 1, GFP_KERNEL,

    kobj_bcast_filter,

    kobj);

    }

    ?

    (二)、Android側:

    private finalUEventObserver?mUEventObserver = newUEventObserver(){

    @Override

    public void onUEvent(UEventObserver.UEventevent) {

    if(DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());

    ?

    String state =event.get("USB_STATE");

    String accessory =event.get("ACCESSORY");

    ?

    //Added for USB Develpment debug, more logfor more debuging help

    if(DEBUG) Log.w(TAG, "mUEventObserver:onUEvent: state = " + state);

    //Added for USB Develpment debug, more logfor more debuging help

    ?

    if(state != null) {

    mHandler.updateState(state);

    }else if ("START".equals(accessory)) {

    if(DEBUG) Slog.d(TAG, "got accessory start");

    setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY,false);

    }

    }

    };

    ?

    /在類初始化時會調用下面的動作,啟動監聽動作。

    mUEventObserver.startObserving(USB_STATE_MATCH);

    ?

    //最終會調用到UEventObserver的addObserver:

    privateArrayList<Object> mObservers = newArrayList<Object>();

    public voidaddObserver(String match, UEventObserver observer) {

    synchronized(mObservers){

    mObservers.add(match);

    mObservers.add(observer);

    }

    }

    private static final String?USB_STATE_MATCH?=

    "DEVPATH=/devices/virtual/android_usb/android0";

    ?

    ?

    該函數最終會將”DEVPATH=/devices/virtual/android_usb/android0”增加到匹配序列中,當kernel發送具有該字符串的數據時,就返回匹配成功,然后調用mUEventObserver的onUEvent函數;

    UeventObserver.Java

    private static class UEventThread extendsThread {

    ?

    privateArrayList<Object> mObservers = newArrayList<Object>();

    ?

    UEventThread() {

    super("UEventObserver");

    }

    ?

    public void run() {

    native_setup();

    ?

    byte[] buffer = new byte[1024];

    int len;

    while (true) {

    len = next_event(buffer);

    if(len > 0) {

    String bufferStr = new String(buffer, 0,len); // easier to search a String

    synchronized (mObservers) {

    for (int i = 0; i <mObservers.size(); i += 2) {

    if(bufferStr.indexOf((String)mObservers.get(i)) != -1) {

    ((UEventObserver)mObservers.get(i+1))

    .onUEvent(newUEvent(bufferStr));

    }

    }

    ?

    ?

    二、Input子系統??

    refer: http://www.cnblogs.com/myblesh/articles/2367648.html

    ????????? http://blog.csdn.NET/bingqingsuimeng/article/details/7950543

    ?

    //1.? Input 子系統--概述

    ???????Android、X windows、qt等眾多應用對于linux系統中鍵盤、鼠標、觸摸屏等輸入設備的支持都通過、或越來越傾向于標準的input輸入子系統。

    ??????? 因為input子系統已經完成了字符驅動的文件操作接口,所以編寫驅動的核心工作是完成input系統留出的接口,工作量不大。但如果你想更靈活的應用它,就需要好好的分析下input子系統了。


    ?

    ?

    1. 輸入子系統由驅動層、輸入子系統核心、事件處理層三部分組成:
    ?? 一個輸入事件,如鼠標移動、鍵盤按下等通過Driver->Inputcore->Event handler->userspace的順序到達用戶控件的應用程序。
    2. input子系統仍然是字符設備驅動程序,但是代碼量減少很多,input子系統只需要完成兩個工作:初始化和事件報告。

    3. (1)上報的大致過程:設備驅動層->核心層->事件處理層->應用層

    ?? (2)具體調用的函數(以evdev為例):
    ??? ??? ?input_event()->input_handle_event() ->input_pass_event() ->handle->handler->event(handle,type, code, value)
    ?? ??? ?->evdev_event() ->evdev_pass_event() ,
    ?? ??? ?然后通過client->buffer[client->head++]= *event賦值給上層client(是struct evdev_client)

    //2.??Input 子系統之一--框架結構(初始化)
    1. 第一層
    ===============================================================================
    用戶空間訪問? <User space>? 設備節點訪問(略)
    @@@@@@xx_test.c


    2. 第二層
    ===============================================================================
    事件處理層<Event Handler>
    /*主要是和用戶空間交互。
    (Linux中在用戶空間將所有的設備都當初文件來處理,由于在一般的驅動程序中都有提供fops接口,以及在/dev下生成相應的設備文件nod,這些操作在輸入子系統中由事件處理層完成)*/
    @@@@@@evdev.c等。(以evdev_handler為例)
    (1)===>>module_init(evdev_init);? module_exit(evdev_exit);
    (2)===>>static int __init evdev_init(void)
    {
    ?? ?return input_register_handler(&evdev_handler);///
    ?? ??? ??? ??? ??? ?/*static struct input_handler evdev_handler = {
    ?? ??? ??? ??? ??? ??? ?.event?? ??? ?= evdev_event,
    ?? ??? ??? ??? ??? ??? ?.connect?? ?= evdev_connect,
    ?? ??? ??? ??? ??? ??? ?.disconnect?? ?= evdev_disconnect,
    ?? ??? ??? ??? ??? ??? ?.fops?? ??? ?= &evdev_fops,?? evdev的文件操作方法
    ?? ??? ??? ??? ??? ??? ?.minor?? ??? ?= EVDEV_MINOR_BASE,
    ?? ??? ??? ??? ??? ??? ?.name?? ??? ?= "evdev",
    ?? ??? ??? ??? ??? ??? ?.id_table?? ?= evdev_ids,*/
    };




    }

    (3)===>>int input_register_handler(struct input_handler *handler)//注冊一個新的event handler
    {
    ?? ?struct input_dev *dev;
    ?? ?

    ?? ?list_add_tail(&handler->node, &input_handler_list);

    ?? ?list_for_each_entry(dev, &input_dev_list, node);
    ?? ??? ?
    ??????? input_attach_handler(dev, handler);將這個新的event handler 與其兼容的input dev綁定在一起

    ?? ?
    }

    (4)===>>static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
    {
    ?? ?

    ?? ?id = input_match_device(handler, dev);//匹配規則:Input_dev和input_handler匹配后調用input_handler的connect。
    ?? ?
    ?? ?error = handler->connect(handler, dev, id);//
    ?? ?
    }
    (5)===>>創建新的evdev字符設備節點
    static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
    ?? ??? ??? ? const struct input_device_id *id)
    {
    ?? ?struct evdev *evdev;
    ?? ?int minor;
    ?? ?

    ?? ?for (minor = 0; minor < EVDEV_MINORS; minor++)//尋找未使用的minor
    ?? ??? ?if (!evdev_table[minor])
    ?? ??? ??? ?break;

    ?? ?dev_set_name(&evdev->dev, "event%d", minor);
    ?? ?evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);//創建字符設備節點event%d
    ?? ?
    ?? ?
    }

    3. 第三層
    ===============================================================================
    核心層<Input Core>
    /*承上啟下。為驅動層提供輸入設備注冊與操作接口,如:input_register_device;通知事件處理層對事件進行處理;在/Proc下產生相應的設備信息*/
    @@@@@@input.c
    (1)===>>subsys_initcall(input_init); module_exit(input_exit);
    (2)===>>static int __init input_init(void)
    {
    ?? ?
    ??????? //創建 sysfs 系統文件/proc/bus/input:devices && handlers
    ?? ?err = class_register(&input_class);///? struct class input_class = {
    ?? ????????????????????????????????????????????? .name?? ??? ?= "input",
    ?? ????????????????????????????????????????????? .devnode?? ?= input_devnode,//kasprintf(GFP_KERNEL, "input/%s", dev_name(dev));
    ?????????????????????? ?
    ??????????????????????????? };
    ?? ?//創建proc系統文件/proc/bus/input:devices && handlers
    ?? ?err = input_proc_init();
    ?? ?if (err)
    ?? ??? ?goto fail1;


    ?????? //注冊字符設備的文件操作input_fops
    ?? ?err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
    ?? ??? ??? ??? ??? ??? ?static const struct file_operations input_fops = {
    ?? ??? ??? ??? ??? ??? ??? ?.owner = THIS_MODULE,
    ?? ??? ??? ??? ??? ??? ??? ?.open = input_open_file,///
    ?? ??? ??? ??? ??? ??? ??? ?.llseek = noop_llseek,}
    }


    (3)===>>static int input_open_file(struct inode *inode, struct file *file)
    {
    ?? ?struct input_handler *handler;
    ?? ?
    ?? ?/* No load-on-demand here? */
    ?? ?handler = input_table[iminor(inode) >> 5];
    ?? ?if (handler)
    ?? ??? ?new_fops = fops_get(handler->fops);

    ?? ?
    ?? ?file->f_op = new_fops;/根據傳入的inode節點(即:event handler),設置相應的文件操作方法

    ?? ?err = new_fops->open(inode, file);打開文件操作方法
    ?? ?
    }



    4. 第四層
    ===============================================================================
    設備驅動層<Input driver>(略)
    /*將底層的硬件輸入轉化為統一事件形式,想輸入核心(Input Core)匯報。*/
    /*實現設備驅動核心工作是:向系統報告按鍵、觸摸屏等輸入事件(event,通過input_event結構描述),不再需要關心文件操作接口。
    ? 驅動報告事件經過inputCore和Eventhandler到達用戶空間。*/
    @@@@@@mtk_tpd.c? &&? ft5206_driver.c

    ===============================================================================

    ?

    /3.??? Input 子系統之二--使用方式1:來自驅動層(硬件出發,如觸屏等)向上層匯報事件
    1. 在第四層:Input driver中需要建立一個input設備以供使用(分配、注冊、注銷input設備)
    @@@mtk_tpd.c


    /* global variable definitions */----------必加內容1
    struct tpd_device? *tpd = 0;


    static int tpd_probe(struct platform_device *pdev)?
    {

    if((tpd=(struct tpd_device*)kmalloc(sizeof(struct tpd_device), GFP_KERNEL))==NULL) return -ENOMEM;
    ??? memset(tpd, 0, sizeof(struct tpd_device));

    /* allocate input device */
    if((tpd->dev=input_allocate_device())==NULL) { kfree(tpd); return -ENOMEM; }----------必加內容2

    /*設置input設備支持的事件類型、事件碼、事件值的范圍、input_id等信息*/
    /*一個設備可以支持一個或多個事件類型。每個事件類型下面還需要設置具體的觸發事件碼。比如:EV_KEY事件,需要定義其支持哪些按鍵事件碼。*/
    /*事件類型(包括EV_RST,EV_REL,EV_MSC,EV_KEY,EV_ABS,EV_REP等)
    ? 而當事件類型為EV_KEY時,按鍵類型keybit包括BTN_LEFT,BTN_0,BTN_1,BTN_MIDDLE等
    */
    ?? ?set_bit(ABS_MT_TRACKING_ID, tpd->dev->absbit);
    ?? ??? ?set_bit(ABS_MT_TOUCH_MAJOR, tpd->dev->absbit);
    ?? ??? ?set_bit(ABS_MT_TOUCH_MINOR, tpd->dev->absbit);
    ?? ??? ?set_bit(ABS_MT_POSITION_X, tpd->dev->absbit);
    ?? ??? ?set_bit(ABS_MT_POSITION_Y, tpd->dev->absbit);

    ?? ?input_set_abs_params(tpd->dev, ABS_MT_POSITION_X, 0, TPD_RES_X, 0, 0);
    ?? ?input_set_abs_params(tpd->dev, ABS_MT_POSITION_Y, 0, TPD_RES_Y, 0, 0);
    ?? ?input_set_abs_params(tpd->dev, ABS_MT_TOUCH_MAJOR, 0, 100, 0, 0);
    ?? ?input_set_abs_params(tpd->dev, ABS_MT_TOUCH_MINOR, 0, 100, 0, 0); ?? ?

    ?if(input_register_device(tpd->dev))----------必加內容3
    ??????? TPD_DMESG("input_register_device failed.(tpd)\n");
    ?else
    ?? ??? ??? ?tpd_register_flag = 1;

    ?

    ?

    ????????? 初始化函數定義了input設備struct tpd_device? *tpd結構體,它用于描述一個輸入子系統設備。

    ?????? 任何驅動設備如果想標明自己是輸入設備,都應該通過初始化這樣的結構體,并且調用input_allocate_device()函數進行注冊。這個函數的功能是為新添加的輸入設備分配內存,如果成功,將返回input_dev *的指針結構,因此在寫驅動的時候應該接受返回值,作為驅動層獲得了一個新的輸入設備操作的接口。通過input_allocate_device()函數,我們設備驅動現在持有的input_dev里面就被賦予了input的“形象”,但是還需要我們去充實一下“內在”,因此,設備驅動程序,還需要為自己的設備增加自己的特性,才能創造獨有的設備“形象”。

    ??????input_allocate_device這部分完成了輸入設備的初始化工作。但是這僅是初始化自己的“特點”,還需要通知輸入子系統有這樣一個新設備誕生了,這就需要調用輸入子系統的注冊函數input_register_device(tpd來完成。input_register_device()用于注冊一個輸入設備。那么注冊過程是怎樣的呢?這是一個重點,在下面的代碼中進行注釋分析:

    ?????

    1 int input_register_device(struct input_dev *dev) 2 { 3 /* 用于記錄輸入設備名稱的索引值 */ 4 static atomic_t input_no = ATOMIC_INIT(0); 5 /* 輸入事件的處理接口指針,用于和設備的事件類型進行匹配 */ 6 struct input_handler *handler; 7 const char *path; 8 int error; 9 10 /* 默認所有的輸入設備都支持EV_SYN同步事件 */ 11 set_bit(EV_SYN, dev->evbit); 12 13 /* 14 * 如果設備驅動沒有指定重復按鍵(連擊),系統默認提供以下的支持 15 * 其中init_timer為連擊產生的定時器,時間到調用input_repeat_key函數 16 * 上報,REP_DELAY用于設置重復按鍵的鍵值,REP_PERIOD設置延時時間 17 */ 18 init_timer(&dev->timer); 19 if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) { 20 dev->timer.data = (long) dev; 21 dev->timer.function = input_repeat_key; 22 dev->rep[REP_DELAY] = 250; 23 dev->rep[REP_PERIOD] = 33; 24 } 25 26 /* 如果設備驅動沒有設置自己的獲取鍵值的函數,系統默認 */ 27 if (!dev->getkeycode) 28 dev->getkeycode = input_default_getkeycode; 29 30 /* 如果設備驅動沒有指定按鍵重置函數,系統默認 */ 31 if (!dev->setkeycode) 32 dev->setkeycode = input_default_setkeycode; 33 34 /* 重要,把設備掛到全局的input子系統設備鏈表input_dev_list上 */ 35 list_add_tail(&dev->node, &input_dev_list); 36 37 /* 動態獲取input設備的ID號,名稱為input*,其中后面的“*”動態獲得,唯一的 */ 38 snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), 39 "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); 40 41 /* 如果這個值沒有設置,系統把輸入設備掛入設備鏈表 */ 42 if (!dev->cdev.dev) 43 dev->cdev.dev = dev->dev.parent; 44 45 /* 在/sys目錄下創建設備目錄和文件 */ 46 error = class_device_add(&dev->cdev); 47 if (error) 48 return error; 49 50 /* 獲取并打印設備的絕對路徑名稱 */ 51 path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); 52 printk(KERN_INFO "input: %s as %s\n", 53 dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); 54 kfree(path); 55 56 /* 核心重點,input設備在增加到input_dev_list鏈表上之后,會查找 57 * input_handler_list事件處理鏈表上的handler進行匹配,這里的匹配 58 * 方式與設備模型的device和driver匹配過程很相似,所有的input 59 * 都掛在input_dev_list上,所有類型的事件都掛在input_handler_list 60 * 上,進行“匹配相親”*/ 61 list_for_each_entry(handler, &input_handler_list, node) 62 input_attach_handler(dev, handler); 63 64 input_wakeup_procfs_readers(); 65 66 return 0; 67 } 上面的代碼主要的功能有以下幾個功能,也是設備驅動注冊為輸入設備委托內核做的事情:
    • 進一步初始化輸入設備,例如連擊事件;
    • 注冊輸入設備到input類中;
    • 把輸入設備掛到輸入設備鏈表input_dev_list中;
    • 查找并匹配輸入設備對應的事件處理層,通過input_handler_list鏈表

    ?  我們需要再分析下這個匹配的過程,但是需要注意的是下面分析的代碼是我們暫時無法分析的,因為那樣會使得情況變得更加復雜,當我們從應用層往下分析的時候一切都會明白。input_attach_handler匹配過程如下:

    ?View Code

      先來看下input_match_device()函數,看一下這個匹配的條件是什么,如何匹配的過程是怎樣的,匹配的結果會是什么?

    ?View Code

      既然證明是合適的,接下來就應該登記注冊,并公證了。還記得handler->connect(handler, dev, id)函數吧。

      當input_match_device()找到最合適的事件處理層驅動時,便執行handler->connect函數進行公證了,看下面這部分代碼(假如說找到了evdev類型的驅動,在input/evdev.c中):

    ?View Code

      通過上述代碼的執行,最終,輸入設備在input_register_handle()的關聯下與已經匹配上的handler結合

    ?

      

    以上是輸入設備驅動注冊的全過程,牽涉的代碼比較多,需要從宏觀上理順。

      縱觀整個過程:

      輸入設備驅動最終的目的就是能夠與事件處理層的事件驅動相互匹配,但是在drivers/input目錄下有evdev.c事件驅動、mousedev.c事件驅動、joydev.c事件驅動等等,我們的輸入設備產生的事件應該最終上報給誰,然后讓事件驅動再去處理呢?

      知道了這么個原因再看上面代碼就會明白,其實evdev.c、mousedev.c等根據硬件輸入設備的處理方式的不同抽象出了不同的事件處理接口幫助上層去調用,而我們寫的設備驅動程序只不過是完成了硬件寄存器中數據的讀寫,但提交給用戶的事件必須是經過事件處理層的封裝和同步才能夠完成的,事件處理層提供給用戶一個統一的界面來操作。

      由于以上的這些原因,才有了上述代碼的關聯過程,看一下整個關聯注冊的過程:

    ???????????????????????????????????????????????

    ?

    ?

    通過上圖我們可以看到input輸入設備匹配關聯的關鍵過程以及涉及到的關鍵函數和數據。

      以上主要是從input設備驅動程序的角度去看輸入子系統的注冊過程和三層之間的關聯。


    ?

    ?

    ?

    2. 在第四層:在發生輸入事件時,向子系統報告事件
    @@@ft5206_driver.c

    static? void tpd_down(int x, int y, int p,int finger_id) {
    ?? ?// input_report_abs(tpd->dev, ABS_PRESSURE, p);
    ?? ? input_report_key(tpd->dev, BTN_TOUCH, 1);
    ?? ? input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, 1);
    ?? ? input_report_abs(tpd->dev, ABS_MT_POSITION_X, x);
    ?? ? input_report_abs(tpd->dev, ABS_MT_POSITION_Y, y);
    ?? ??
    ?? ? input_report_abs(tpd->dev, ABS_MT_TRACKING_ID, finger_id);
    ?? ??
    ?? ? //printk("D[%4d %4d %4d] ", x, y, p);
    ?? ? input_mt_sync(tpd->dev);
    }



    ??? 用于報告EV_KEY、EV_REL、EV_ABS等事件的函數有:

    ??? void input_report_key(struct input_dev *dev, unsigned int code, int value)

    ??? void input_report_rel(struct input_dev *dev, unsigned int code, int value)

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


    @@@第三層:input.c
    ??? 注意:如果你覺得麻煩,你也可以只記住1個函數(因為上述函數都是通過它實現的):input core中的如下函數:
    ??? void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);


    ??? 最終調用到如下函數:
    /*
    ?* Pass event first through all filters and then, if event has not been
    ?* filtered out, through all open handles. This function is called with
    ?* dev->event_lock held and interrupts disabled.
    ?*/
    static void input_pass_event(struct input_dev *dev,
    ?? ??? ??? ????? unsigned int type, unsigned int code, int value)
    {
    ?? ?struct input_handler *handler;
    ?? ?struct input_handle *handle;

    ?? ?rcu_read_lock();

    ?? ?handle = rcu_dereference(dev->grab);
    ?? ?if (handle)
    ?? ??? ?handle->handler->event(handle, type, code, value);
    ?? ?else {
    ?? ??? ?bool filtered = false;

    ?? ??? ?list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
    ?? ??? ??? ?if (!handle->open)
    ?? ??? ??? ??? ?continue;

    ?? ??? ??? ?handler = handle->handler;
    ?? ??? ??? ?if (!handler->filter) {
    ?? ??? ??? ??? ?if (filtered)
    ?? ??? ??? ??? ??? ?break;

    ?? ??? ??? ??? ?handler->event(handle, type, code, value);///

    ?? ??? ??? ?} else if (handler->filter(handle, type, code, value))
    ?? ??? ??? ??? ?filtered = true;
    ?? ??? ?}
    ?? ?}

    ?? ?rcu_read_unlock();
    }






    @@@第二層:evdev.c
    static struct input_handler evdev_handler = {
    ?? ?.event?? ??? ?= evdev_event,///
    ?? ?.connect?? ?= evdev_connect,
    ?? ?.disconnect?? ?= evdev_disconnect,
    ?? ?.fops?? ??? ?= &evdev_fops,
    ?? ?.minor?? ??? ?= EVDEV_MINOR_BASE,
    ?? ?.name?? ??? ?= "evdev",
    ?? ?.id_table?? ?= evdev_ids,
    };
    /*
    ?* Pass incoming event to all connected clients.
    ?*/
    static void evdev_event(struct input_handle *handle,
    ?? ??? ??? ?unsigned int type, unsigned int code, int value)
    {


    ??????? rcu_read_lock();

    ?? ?client = rcu_dereference(evdev->grab);///得到上層的client

    ?? ?if (client)
    ?? ??? ?evdev_pass_event(client, &event, time_mono, time_real);
    ?? ?else
    ?? ??? ?list_for_each_entry_rcu(client, &evdev->client_list, node);
    ?? ??? ?evdev_pass_event(client, &event, time_mono, time_real);

    ?? ?rcu_read_unlock();


    }


    static void evdev_pass_event(struct evdev_client *client,
    ?? ??? ??? ????? struct input_event *event,
    ?? ??? ??? ????? ktime_t mono, ktime_t real)
    {
    ?? ?event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
    ?? ??? ??? ??? ??? ?mono : real);

    ?? ?/* Interrupts are disabled, just acquire the lock. */
    ?? ?spin_lock(&client->buffer_lock);

    ?? ?client->buffer[client->head++] = *event;將事件賦值給上層client(是struct evdev_client)

    }


    /4.??? Input 子系統之二--使用方式2:來自用戶空間? 對? 設備節點的訪問(/dev/input/event%d)

    (1)關于設備節點的查詢方式

    讀取并顯示/dev/input/eventX事件

    $getevent -l

    ????????????????????????????????

    ?

    查看設備的major:/proc/devices/*? &&? 訪問設備節點:/dev/*

    ????? /proc/devices/中的設備是通過insmod加載到內核的,它可產生一個major(主設備號)供mknod作為 參數。?

    ????? 這個文件列出字符和塊設備的主設備號,以及分配到這些設備號的設備名稱。

    ?

    ?????? /dev/* 是通過mknod加上去的(使用major),格式:mknod device1 c/b major minor 如:mknod /dev/ttyS0 c 4 64,用戶通過此設備名來訪問你的驅動。

    ?????? /*在每一行都可以看到設備文件、設備編號(主、次);
    ??? ?? 對于每種硬件設備,系統內核有相應的設備驅動程序負責對它的處理。而在Unix 中,使用設備文件的方式來表示硬件設備,每種設備驅動程序都被抽象 為設備文件的形式,這樣就給應用程序一個一致的文件界面,方便應用程序和操作系統之間的通信。?
    ?????? 習慣上,所有的設備文件 都放置在/dev?目錄下*/

    ?

    查看input設備節點(1):/dev/input/*

    ( /dev/input目錄下的事件都是在驅動中調用input_register_device(struct input_dev *dev)產生的。

    ?? 每個event將上報指定的事件,如G-Sensor、觸摸屏、Mouse、按鍵等。)

    查看input設備節點(2):與/dev/input/*的event對應的相關設備信息:/proc/bus/input/devices



    ?

    (2)下面將從應用層的角度分析事件的接受過程和處理過程以及三層之間是如何配合處理輸入事件的。

    從應用層的角度出發看input子系統

    ??????? 以上部分已經借助input子系統把input設備驅動層與事件驅動層進行了關聯,以s3c2440_ts.c(輸入設備層驅動)和evdev.c(事件處理層驅動)為例,來分析這一過程。

    ??????? 由于s3c2440_ts.c中上報的事件類型為按鍵、絕對值坐標,而evdev事件驅動程序是全匹配的,因此早在s3c2440_ts.c注冊的過程中,就會創建設備節點/dev/input/event0(假設內核中沒有其他的event類型的輸入設備,這里就是event0)

      我們知道,應用層使用設備的第一步,是open(“/dev/event0”),因此這里event0的主設備號成為關鍵,因為主設備號將表明你是什么設備,我們ls -l查看/dev/event0發現:

    crw-r-----1 root root 13, 64 2012-07-26 14:32 /dev/input/event0

      由此可見主設備是13,輸入命令cat? /proc/devices查看主設備為13的是input設備,因此可以確定當我們執行open函數打開event0設備的時候,會調用input設備的open驅動函數,這個函數在input.c中,為了說明這一問題,需要從input驅動注冊過程開始,還是input.c文件:

    ?View Code

    ?

      可以看到,輸入設備初始化的過程首先建立了input類,初始化input在proc下的節點,然后注冊input設備,設備名稱為input,操作接口是input_fops,主設備號是INPUT_MAJOR=13。

      由以上可知,只要是主設備號為13的設備驅動程序,都是用input_fops接口,即當event0設備使用open函數打開時,會調用到input_fops接口中的open驅動函數,這個結構體的初始化為:



      可以看到,只實現了一個open功能字段,再看input_open_file的實現:

      以上代碼的功能為找到對應事件驅動層的fops,即進行fops的接口轉換,指向對應設備的事件處理接口。

      其中input_table[iminor(inode)]>>5的input_table是一個全局的input_handler類型的數組,iminor(inode)取得次設備號,并且右移5位索引input_table表中對應的位置,為什么這樣做呢?這是因為這個表格中填寫的就是事件處理的指針,待會分析。

      繼續查看下面的代碼。if中將判斷是否為空并且事件處理層中的fops有沒有初始化,如果沒有就不能進行接口轉換,報出設備不存在的錯誤,如果設備存在則把input設備的f_op驅動接口指向input_table表中存在的接口,并調用其open函數。

      那么這個input_table里面到底存放了什么呢?我們還是拿觸摸屏驅動來講解。由于觸摸屏驅動已經完成了和evdev.c事件處理層的匹配,且次設備號為64,設備名稱為/dev/event0,這是我們通過分析驅動注冊中獲得的內容,既然input核心設備注冊了,s3c2440觸摸屏驅動也注冊了,那會不會evdev設備也會注冊了呢?答案是肯定的,要想知道input_table里面放了什么,必須要去查看evdev設備的注冊過程,打開input/evdev.c查看它的注冊過程:

    ?View Code

      由以上的內容可以知道evdev_handler也被作為一個設備來操作,但是它屬于input handler事件處理設備,然而我們在evdev_handler結構體的.fops字段又發現它的驅動接口為字符設備類型,在input中,如果input_table匹配到了evdev_handler,將會把file->f_op=&evdev_fops,那么如果使用read、write等函數操作,將會調用到evdev_fops中的read、write。

      為了進一步查看input_table表中的內容是如何填充的,還需要查看這個注冊的過程:

    ?View Code

    ?

      當然這個注冊過程并不是只有這么一句話,看到這條語句,相信應該知道什么意思了。

      在input的open函數執行之前,即我們的open代碼打開之前,input_table中的字段已經被事件處理層填充了。

      由于evdev的次設備號在初始化的時候就設置成了64,因此這里相當于:

    ?View Code

      回到input_open_file函數查看new_fops->open(inode, file)便知道了調用的是:

    ?View Code

      

      在分析open函數之前,解釋一下為什么要右移5位?

      這說明一個問題,次設備號的低5位被忽略,這說明evdev的最大支持的輸入設備驅動個數為2^5次方等于32個,你可能會看到你的/dev目錄下面有event0、event1、event2等設備,他們的次設備號分別為64、65、66等等。但最大是64+32-1,因此input_table為這些輸入設備增加的一個統一接口,通過上層打開設備時,只要次設備號在64+32-1之間的設備都會重新定位到evdev_handler中,即event*設備打開后執行的底層函數將被重新定義到evdev_handler中。

      相信上面的問題已經描述清楚,如果還是不明白,最起碼應該知道的是,input設備中的open函數只是一個接口,通過次設備號才找到了真正的事件處理接口。接下來要看新的open接口的實現了,evdev_handler-> fops->open實現如下:

    ?View Code

      上面截取了片段,并沒有執行到open函數,open進行自減操作,表示沒有調用過open,這個值主要是為了close中判斷open為0時釋放資源使用。

      不僅如此,我們在觸摸屏驅動中也沒有定義read、write,那當觸摸屏上報事件時,是如何處理的呢?

      我們需要先到觸摸屏驅動程序中找到上報事件的函數再做進一步分析。

    ?


    ?

    輸入設備上報事件的處理過程

    ?

      觸摸屏驅動程序上報事件的函數為:

    ?View Code

    ?

    ?

      然而他們其實是input_event函數的封裝,調用的都是input_event函數,這一函數在input.c中實現如下:

    ?View Code

      代碼被做了精簡,其中就是在匹配上報的事件,并根據事件的類型調用驅動程序中相應的函數來完成,但是由于我們并沒有定義過這些函數,因此執行最后的handle_handler_event函數,由事件處理層evdev_event函數來完成事件的保存工作,具體過程如下:

    ?View Code

      這里列舉了關鍵代碼,即上報的事件被保存到了client_buffer中,其中client_buffer是一個循環緩沖區,client->head表示當前數據的位置,因此每次都寫到client->head的位置,而讀數據時需要到client_tail中讀取。因為在open的時候,client已經被鏈入到了evdev->client_list中,因此通過可以通過list_for_each_entry重evdev->client_list中找到對應的client。

      事件的上報都會把數據保存到client->buffer中,以便上層通過read和write進行讀去和寫入。

    ?


    ?

    通過設備節點讀取輸入事件

    ??????? 事件的上報都會把數據保存到client->buffer中,以便上層通過read和write進行讀去和寫入。?

      還是以觸摸屏驅動程序和evdev事件處理層驅動來分析:

    ?View Code

    ?

      這里如果沒有數據,進程會睡眠,那由誰來喚醒呢?細心的話可以發現,當設備驅動層調用input_event上報事件調用相應的event函數進行事件寫入時,是會喚醒阻塞等待的進程的。

    ?


    ?

    通過設備節點寫入輸入事件

    ?????? 事件的上報都會把數據保存到client->buffer中,以便上層通過read和write進行讀去和寫入。

      寫入過程:

    ?View Code

      上述代碼中的event是input_event數組,包含了事件的類型、鍵值,通過input_inject_event把數據寫入循環數組client->buffer中,input_inject_event調用的是input_event函數。

    ?


    ?

    總結

    ?

      對input子系統的整個過程做了分析,并從兩個角度進行考慮.

      對于寫輸入設備驅動程序的來說,需要掌握的是設備應該上報事件的類型,這樣才能匹配到對應的事件層驅動幫助你保存對應的數據.

      而對于設備上層開發者來說,應該先使用cat /proc/bus/input/devices查看你操作的設備類型和處理接口,以幫助你更好的對設備操作。
















    本文轉自張昺華-sky博客園博客,原文鏈接:http://www.cnblogs.com/sky-heaven/p/6394267.html,如需轉載請自行聯系原作者

    總結

    以上是生活随笔為你收集整理的Linux--内核Uevent事件机制 与 Input子系统【转】的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    日日夜精品| 永久中文字幕 | 日韩高清精品免费观看 | av中文字幕网址 | 日韩丝袜在线 | 99精品一区二区 | 国产成人免费在线 | 午夜精品一区二区三区四区 | 欧美日韩一区二区三区在线观看视频 | 亚洲资源在线 | 天天综合精品 | 97超级碰碰碰碰久久久久 | 欧美一二三视频 | 粉嫩一区二区三区粉嫩91 | 超碰人在线 | 国产中文字幕网 | 久久一线| 三级黄色免费 | 9ⅰ精品久久久久久久久中文字幕 | 亚洲 欧美 国产 va在线影院 | 麻豆传媒在线视频 | 最近中文字幕完整视频高清1 | av在线电影免费观看 | 看片的网址 | 日韩三级久久 | 啪啪免费观看网站 | 中文字幕亚洲精品在线观看 | 日韩黄色一级电影 | 国产免费大片 | 99在线精品观看 | 国内精品亚洲 | 激情婷婷| 日本中文乱码卡一卡二新区 | 日韩精品短视频 | 亚洲欧美日韩精品一区二区 | 日韩一区二区三区高清免费看看 | 国产精品国产精品 | 中文字幕网站 | 免费看片网页 | 在线观看一二三区 | 日韩欧美xxx| 欧美老女人xx | 国产在线播放一区二区 | 在线国产日韩 | 狠狠色2019综合网 | 成年人毛片在线观看 | 久久久久久久久免费视频 | www成人av| 日韩资源在线 | 又粗又长又大又爽又黄少妇毛片 | 日日躁你夜夜躁你av蜜 | 久久av免费电影 | 97在线公开视频 | www免费视频com━ | 黄色av影视| 99精品视频一区 | 亚洲人成人在线 | 男女精品久久 | 亚洲一区美女视频在线观看免费 | 在线观看色网 | 亚洲成成品网站 | 国产经典 欧美精品 | 天天艹 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 亚洲涩综合 | 人人澡人摸人人添学生av | 久久久久北条麻妃免费看 | 国产高清视频免费观看 | 久久久久久久久久网 | 天天插综合网 | 成人久久| 综合在线观看色 | 国产精品va最新国产精品视频 | 精品av网站 | 色老板在线视频 | 麻豆久久久久久久 | 99视频在线免费看 | 国产精品专区h在线观看 | 91精品日韩 | 美女网站视频免费黄 | 亚洲爱视频 | 天天操天天摸天天干 | 草久久影院 | 一级国产视频 | 玖玖在线资源 | 国产精品久久久久久久久久久久午夜 | 99久久精品日本一区二区免费 | 免费在线观看成人av | 欧美日本啪啪无遮挡网站 | 亚洲日日射 | 三级黄色片在线观看 | 最近高清中文字幕 | 亚洲天堂精品 | 成人精品一区二区三区电影免费 | 日韩黄色免费在线观看 | 91国内在线 | 四川bbb搡bbb爽爽视频 | 午夜黄色一级片 | 国产青春久久久国产毛片 | 91久久丝袜国产露脸动漫 | 色视频网站在线观看一=区 a视频免费在线观看 | 在线小视频你懂的 | 日韩av有码在线 | 韩国一区二区av | 久久精品九色 | 国产免费一区二区三区最新6 | 在线观看完整版免费 | 欧美日韩国产二区 | 国产午夜在线观看 | 久久久久欧美精品 | 国产精品mm| 182午夜在线观看 | 国产精品久久久久一区 | 久久久久免费看 | 成人国产精品一区 | 婷五月天激情 | 久久久国际精品 | 青春草免费视频 | 欧美三人交 | 久久五月激情 | 国产一级高清 | 国产五月| 一区二区不卡视频在线观看 | 国产麻豆精品传媒av国产下载 | 中文字幕在线观看国产 | 欧美日本高清视频 | 欧美久久久久久久久中文字幕 | 91在线免费观看网站 | www激情久久 | 国产群p | 精品国产乱码久久久久久1区2匹 | 日韩av三区| 黄色一二级片 | www国产精品com | 亚洲狠狠婷婷综合久久久 | 亚洲涩综合 | 精品国产精品久久 | 国产1级视频 | 在线观看视频国产 | 久久久久久综合 | 成人黄色在线看 | av在线成人 | 国产精品免费看久久久8精臀av | 国产精品成人在线 | 国产亚洲精品成人 | 在线欧美小视频 | 欧美日韩久久不卡 | 91成人国产 | 超碰97国产| 麻豆一区在线观看 | 久久久免费| 91在线日本 | 少妇bbw搡bbbb搡bbb | 国产成人三级一区二区在线观看一 | 在线观看一区二区精品 | 亚洲 欧美日韩 国产 中文 | 狠狠色丁香婷婷综合视频 | 夜夜爽www | 免费中文字幕视频 | 国产黄免费看 | 亚洲免费成人av电影 | 欧美一级性生活 | 不卡的av电影在线观看 | 久久精品资源 | 91精品成人久久 | 色婷婷福利 | 久久午夜免费视频 | 久久久国产精品一区二区中文 | 91精品国产一区二区三区 | 亚洲激情精品 | 久久久久久久久久电影 | 亚洲精品五月天 | 少妇视频在线播放 | 婷婷综合影院 | 久久久亚洲影院 | 成人网页在线免费观看 | 久久五月激情 | 精品视频免费 | 久久久久久久久久久免费视频 | 高清av不卡 | 欧美疯狂性受xxxxx另类 | 亚洲午夜在线视频 | 九九电影在线 | av在线一 | 欧美激情视频久久 | 日韩免费三区 | 99热这里只有精品久久 | 久久久久久久久福利 | 97碰碰视频 | 日日射av | 99久久99久久免费精品蜜臀 | 亚洲最新在线视频 | 免费在线精品视频 | 99国产情侣在线播放 | 99电影456麻豆 | 五月天六月色 | 日韩午夜av电影 | 丝袜+亚洲+另类+欧美+变态 | 成年人黄色免费网站 | 五月天亚洲综合小说网 | 特黄免费av | 久久久色| 成人黄大片 | 欧美国产日韩一区二区 | 去看片| 天天爱天天射天天干天天 | 伊人网站| 九九视频网站 | 91porny九色91啦中文 | 二区中文字幕 | 国产一区二区综合 | 密桃av在线 | 国产夫妻自拍av | 欧美日韩国内在线 | 最新在线你懂的 | 西西444www大胆高清图片 | 97人人模人人爽人人喊中文字 | 天天干天天干天天射 | 欧美精品网站 | 青草视频网 | 国产中文字幕视频在线观看 | 国产99久久久久久免费看 | 91精品蜜桃 | 国产一区欧美日韩 | 麻豆激情电影 | 欧美不卡视频在线 | 欧美日韩精品在线 | 中文字幕av日韩 | 国产成人久久精品亚洲 | 日韩性色 | 天海冀一区二区三区 | 国产性天天综合网 | 国产 中文 日韩 欧美 | 91九色在线视频 | 日韩精品高清不卡 | 国产精彩视频一区二区 | 精品国产乱码久久久久 | 99精品美女 | 97超碰人人澡人人爱 | 欧美日本在线观看视频 | 亚洲最新av在线网址 | 99视频在线免费 | 五月婷婷综合在线视频 | 欧美成人久久 | 91香蕉国产在线观看软件 | 国产高清99| 成人高清在线观看 | 91精品专区| 97在线视| 香蕉国产91 | 99国产精品免费网站 | 天天射天天做 | 人人爽人人| 精品福利在线观看 | 天天干一干 | 国产欧美精品一区aⅴ影院 99视频国产精品免费观看 | 啪啪av在线 | 中文亚洲欧美日韩 | 中文av网| 中文有码在线视频 | 欧美一二三专区 | 国产一区二区不卡视频 | 日韩三级av | 久久电影色 | 亚洲成色 | 国产精品久久99综合免费观看尤物 | 亚洲美女精品 | 国产成人一区二区在线观看 | 亚洲艳情| 国产成人高清av | 亚洲精品欧洲精品 | 黄色福利网站 | 在线观看免费一级片 | 国产欧美三级 | 91插插插免费视频 | 九九免费观看视频 | 久久你懂得 | 99精品国产99久久久久久福利 | 91男人影院 | 精品久久久久久亚洲 | 操操碰| 99精品在线观看 | 日韩av一区二区在线播放 | 久久这里只有精品首页 | 国产一区二区免费看 | 国产在线精品国自产拍影院 | 麻豆精品视频 | 欧美久久久一区二区三区 | 亚洲综合精品视频 | 亚洲精品高清视频在线观看 | 国产传媒中文字幕 | 日韩三级不卡 | 天天干天天干天天干 | 久久综合久久鬼 | 国产99久久精品一区二区300 | 欧美性猛片, | 欧美性大战久久久久 | 夜夜操狠狠干 | 99久久免费看 | 91在线看片 | 69精品久久久 | 国产一级高清视频 | 免费看黄的 | 欧美一级片免费在线观看 | 探花视频免费观看 | 精品a视频 | 91av短视频| 99热9| 亚洲综合视频在线 | 精品国产一区二区三区久久影院 | 丁香六月中文字幕 | 一区二区三区日韩在线 | 91大神免费视频 | 国产成人a亚洲精品 | 亚洲视频 中文字幕 | 不卡av在线免费观看 | 精品国产aⅴ麻豆 | 波多野结衣一区二区 | 久久伊人操 | 最近高清中文在线字幕在线观看 | 日韩美视频| 成+人+色综合 | 中文字幕av最新 | 婷婷在线免费 | 国产精品女同一区二区三区久久夜 | 国产成人三级 | 国产精品第54页 | 丁香花在线视频观看免费 | 麻豆传媒视频在线免费观看 | 在线视频日韩欧美 | 九九在线视频 | www视频在线观看 | 中文字幕高清在线播放 | 久久久久久久久毛片 | 在线观看网站av | 日本黄色大片免费看 | 色视频 在线 | 青青河边草免费直播 | 激情亚洲综合在线 | 三级在线视频观看 | 国产精品小视频网站 | 久保带人| 亚洲色影爱久久精品 | 国产一级视频在线免费观看 | 成人教育av | 亚洲成人欧美 | 国产精品一区二 | 99精品免费| 日韩精品久久久 | 91精品国产入口 | 国产精品网红直播 | www在线免费观看 | 国产精品6999成人免费视频 | 欧美孕交vivoestv另类 | 天天做天天干 | 国产色小视频 | 国产视频黄 | 精品播放 | 一区 二区 精品 | 日韩中文字幕免费视频 | 日韩欧美在线播放 | 精品免费视频123区 午夜久久成人 | 久久99久久99精品免费看小说 | 亚洲黄色免费在线看 | 久久这里只有精品视频首页 | 亚洲精品美女视频 | 日韩电影在线视频 | 久久久久久久久毛片 | 成人久久18免费网站麻豆 | 99看视频在线观看 | 成人av av在线 | 亚洲精品男人天堂 | 在线看片a| 在线观看精品一区 | 激情网站五月天 | 国产一区二区视频在线 | 久草国产在线观看 | 亚洲精品久久久久久久蜜桃 | 97超视频免费观看 | 精品国内自产拍在线观看视频 | 欧美男男激情videos | 韩国av一区二区三区在线观看 | 国产男男gay做爰 | av一级在线 | 国产精品久久久久久69 | 午夜免费久久看 | 久久不射影院 | 天天操天天操天天爽 | 日韩免费视频一区二区 | 亚洲国产免费av | 91av国产视频| 日本中文字幕久久 | 午夜av免费看 | 久香蕉| 免费日韩三级 | 日韩免费观看高清 | av免费在线看网站 | 欧美精品xx| 国产精品一区二区av影院萌芽 | 欧美精品久久久久久久久久久 | 二区视频在线观看 | 麻豆免费视频观看 | 日韩欧美有码在线 | 最新日韩在线观看视频 | 国产精品久久毛片 | 国产少妇在线观看 | 午夜精品一区二区三区在线播放 | 日日添夜夜添 | 成人av免费在线看 | av在线超碰 | 日韩伦理一区二区三区av在线 | 99久久婷婷国产精品综合 | 成人午夜影院在线观看 | 国产精品99久久久久久小说 | 亚洲国产精品一区二区久久,亚洲午夜 | 91久久国产综合精品女同国语 | 国产福利一区二区三区在线观看 | 成人一级片免费看 | 天天射天天射 | 最新中文字幕在线观看视频 | 五月婷婷中文 | 精品国产伦一区二区三区免费 | 久久久精品影视 | 日韩av电影中文字幕在线观看 | 精品国产诱惑 | 成人av资源网 | 久久ww | 欧美综合色在线图区 | 久久99精品国产99久久 | 久久激情婷婷 | 亚洲综合在线五月天 | 国产一区麻豆 | 国产精品久久久久久久免费大片 | 成人午夜电影网站 | 日韩免费在线一区 | 日韩av区| 91传媒免费在线观看 | 国产a国产 | 黄色精品久久久 | 亚洲电影黄色 | 在线观看久久久久久 | 麻豆国产精品视频 | 在线 精品 国产 | 久久人人爽人人片 | 亚洲日韩精品欧美一区二区 | 久久99精品久久久久久清纯直播 | 色吊丝在线永久观看最新版本 | 激情欧美一区二区三区 | 成人免费观看大片 | 国产中文字幕大全 | 激情综合网五月激情 | 国产精品美女久久久久久久 | 国产原创中文在线 | 久久a v视频| 精品久久久久久久久久久久久久久久 | 天堂av高清 | 久久精品99国产精品日本 | 久久久穴| 国内精品久久久精品电影院 | 黄色成年片| 欧美日韩一区二区在线观看 | 久久成人毛片 | 人人澡人人添人人爽一区二区 | 精品国产欧美 | 91免费看黄色 | 91传媒在线观看 | 日韩成人精品一区二区三区 | av成人黄色| 久久久久久久久久福利 | 日本爱爱免费 | avove黑丝| 亚洲草视频 | 人人澡超碰碰 | 久久伦理 | 亚洲禁18久人片 | 国产精品一二三 | 精品欧美在线视频 | 国产成人一区二区三区影院在线 | 亚洲国内精品 | 久久系列 | 午夜10000| 亚洲理论在线观看电影 | 国产美女视频黄a视频免费 久久综合九色欧美综合狠狠 | 狠狠干天天色 | 久久久久久久久久久免费av | 国产探花视频在线播放 | 国产成人精品一区二区三区免费 | 久久久久久高潮国产精品视 | 久色婷婷| 五月色丁香 | 免费在线一区二区 | 亚洲成人精品 | 亚洲永久字幕 | 天天综合精品 | 欧美精品成人在线 | 在线国产精品一区 | 成片人卡1卡2卡3手机免费看 | a黄色影院 | 999视频在线观看 | 88av色| 在线视频黄| 国产一区二区三区视频在线 | av一区二区三区在线 | 日本黄色特级片 | 波多野结衣视频一区二区三区 | av不卡中文字幕 | 亚洲视频网站在线观看 | 中文字幕免费久久 | 美女视频一区二区 | 亚洲精品中文在线 | 日本中文一级片 | 久久久久久综合网天天 | 美女露久久 | 国产免费av一区二区三区 | 午夜婷婷网 | 久久久久免费 | 91视频3p| 国产视频午夜 | 黄色精品国产 | a级国产乱理论片在线观看 特级毛片在线观看 | 免费一级日韩欧美性大片 | 中文资源在线播放 | 久久久资源网 | 少妇bbbb| 日本黄色免费电影网站 | 91九色蝌蚪视频网站 | 亚洲国产精品久久久久婷婷884 | 美女av电影 | 久久久久亚洲国产精品 | 中国黄色一级大片 | 亚洲一二三久久 | 日韩免费三区 | 国产精品永久免费 | 六月天综合网 | 久草在线免费在线观看 | 黄网在线免费观看 | 国产视频在线观看一区 | 91精品国产九九九久久久亚洲 | 天天草天天干天天射 | 丁香伊人网 | av在线电影播放 | 91精品久久久久久久久久久久久 | 国产精品久久久久婷婷 | 美女视频永久黄网站免费观看国产 | 香蕉视频在线网站 | 免费视频久久久 | 综合网在线视频 | 亚洲va欧洲va国产va不卡 | 午夜精品福利一区二区 | 亚洲激情网站免费观看 | 久久久精品影视 | 国产中文字幕一区 | 午夜私人影院 | 亚洲高清在线 | 在线日韩av| 色综合咪咪久久网 | 国产字幕av| 视频在线一区二区三区 | 亚洲一级黄色 | 香蕉影院在线 | 中文字幕日本电影 | 欧美在线99| 88av色| 一区二区视频电影在线观看 | www在线免费观看 | 午夜精品视频福利 | 欧美在线视频一区二区 | 亚洲精品午夜久久久 | 综合在线观看色 | 亚洲视频一区二区三区在线观看 | 国产成人a v电影 | 久久精品久久久久 | 亚洲成av人片在线观看 | 中文字幕高清免费日韩视频在线 | 亚洲国产免费看 | 国产精品乱看 | 国产不卡在线观看 | 久久理论片 | 高清不卡一区二区三区 | 在线三级av| av在线短片 | 国产精品99久久久久久大便 | 麻豆视频大全 | 国产国语在线 | 一级黄色片毛片 | 精品日韩中文字幕 | 中文字幕日本特黄aa毛片 | 97电影网站 | 亚洲h在线播放在线观看h | 色久av| 成人av高清在线观看 | 黄在线免费观看 | 日韩精品1区2区 | 国产精品永久免费视频 | 精品亚洲一区二区 | 又色又爽的网站 | 欧美va电影| 国产毛片久久 | 亚洲第一香蕉视频 | 久久久精品网 | 欧美精品久久久久性色 | 国产视频一区二区在线观看 | 91网址在线 | 99国产免费网址 | 91精品婷婷国产综合久久蝌蚪 | 欧美精品久久天天躁 | 天天操夜夜摸 | 中文字幕大全 | 欧美成人va| 高清不卡一区二区在线 | 亚洲劲爆av| 国产精华国产精品 | 亚洲精品国精品久久99热 | 久久超碰免费 | 亚洲五月综合 | 国产四虎在线 | 激情欧美丁香 | a√天堂资源 | 国产成人av一区二区三区在线观看 | 91精品老司机久久一区啪 | 日韩高清www | 亚洲国产黄色 | 欧美日韩不卡在线观看 | 久久九九免费 | 久久久久久视频 | 亚洲成人xxx | 一二区av | 一级黄色在线视频 | 99久久影院 | 粉嫩高清一区二区三区 | 热久久这里只有精品 | 93久久精品日日躁夜夜躁欧美 | 91.麻豆视频 | 九九精品毛片 | 成人免费看电影 | 久久99精品国产一区二区三区 | 丁香在线视频 | 最新日韩视频在线观看 | 国产伦理精品一区二区 | 日韩精品免费一线在线观看 | 在线看国产一区 | 黄色国产大片 | 精品国产_亚洲人成在线 | 精品国产美女在线 | 黄色精品网站 | 99久久精品免费看国产四区 | 欧美日韩国产精品一区 | 日韩欧美精选 | 就要干b | 国产精品无av码在线观看 | 国产一级视频在线免费观看 | 在线观看视频一区二区三区 | 九九免费在线看完整版 | 久久免费在线观看 | 久久夜靖品 | 最新亚洲视频 | 精品国产一区二区三区四区在线观看 | 91在线精品播放 | 视频一区二区在线 | 亚洲在线看 | 国产精品毛片一区 | 六月丁香婷 | 久久一级电影 | 免费看片在线观看 | 在线天堂日本 | 国产精品久久久久免费观看 | 午夜电影中文字幕 | 综合久久一本 | 激情五月激情综合网 | 亚洲激情 欧美激情 | 国产精品一级在线 | 黄色网址中文字幕 | 国产精品岛国久久久久久久久红粉 | 国产中文字幕视频在线 | 麻豆小视频在线观看 | 三级av中文字幕 | 精品一区 在线 | 亚洲人人网| 久久亚洲区 | 国产免费一区二区三区最新 | 天天看天天干 | 国产精品网站一区二区三区 | 免费a视频在线 | www在线免费观看 | 玖玖999 | 精品国产诱惑 | 人人插人人费 | 天天在线免费视频 | 91成年视频 | 91在线一区 | 97在线观看免费高清完整版在线观看 | 国产成人精品久久久 | 涩涩成人在线 | 日韩中文字幕免费在线观看 | 五月婷婷六月丁香 | 亚洲精品一区二区在线观看 | 国产人成免费视频 | 日韩在线视频精品 | 免费高清在线观看成人 | 免费看的黄色录像 | 99热只有精品在线观看 | 九九免费在线看完整版 | 亚洲国产精品va在线 | 亚洲黄色在线免费观看 | 久久综合九色99 | 国产精品免费观看久久 | 免费网站看v片在线a | 麻豆国产精品一区二区三区 | 视频一区在线免费观看 | 久久大片网站 | 视频成人永久免费视频 | 精品成人a区在线观看 | 亚洲手机av | 夜夜天天干 | 五月激情姐姐 | 亚洲欧美日本国产 | 欧美一区二区在线看 | 日日躁夜夜躁xxxxaaaa | 国产韩国精品一区二区三区 | 中文国产成人精品久久一 | 免费在线h | 久久久久国产精品一区 | 国产精品片 | 亚洲免费永久精品国产 | 中文字幕国语官网在线视频 | 手机av观看| 91久久久久久久一区二区 | 国产九九热 | 国产精品国产亚洲精品看不卡15 | 精品播放| 狠狠黄| 国产欧美日韩一区 | 天天插日日插 | 狠狠插狠狠干 | 日韩videos高潮hd | 久久精品免视看 | 久99久精品视频免费观看 | 成人app在线免费观看 | 日本中文在线播放 | 国产区精品在线 | 久久免费国产精品1 | 九九热免费精品视频 | 国产欧美日韩精品一区二区免费 | 四虎成人精品永久免费av九九 | 91在线视频 | 成人av高清 | 国产美女精品 | 久久婷婷精品 | 一级片视频免费观看 | 日韩欧美视频二区 | 玖玖在线精品 | 亚洲丝袜中文 | av丝袜在线| 色88久久 | 不卡的av在线| 99精品视频一区 | 天天综合导航 | 欧美性视频网站 | 久久69av | 久久国产午夜精品理论片最新版本 | 亚洲国产精品一区二区久久,亚洲午夜 | 成人午夜性影院 | 99产精品成人啪免费网站 | 1000部18岁以下禁看视频 | 好看的国产精品视频 | 黄色a三级| 人人干免费 | 成人久久18免费网站图片 | 精品免费视频. | 丁香激情综合国产 | 91理论电影 | 三级视频国产 | 国产一级片网站 | 国产偷v国产偷∨精品视频 在线草 | 婷婷久月| 美女视频黄是免费的 | 欧美性做爰猛烈叫床潮 | 久久久久女人精品毛片 | 欧美日韩亚洲国产一区 | 精品91在线 | 激情综合五月天 | 韩国精品视频在线观看 | 亚洲视频aaa| 91麻豆免费看| 在线视频手机国产 | 国产精品成人一区二区三区吃奶 | 91在线产啪 | av福利资源 | 国产小视频网站 | 免费福利小视频 | 日本精品va在线观看 | 亚洲精品ww | 成年人电影毛片 | 99热手机在线 | 狂野欧美激情性xxxx欧美 | 成人a视频 | 久久成人高清 | 婷婷深爱激情 | 久草热视频| 欧美一区在线看 | 久久少妇免费视频 | 国产一区高清在线观看 | 欧美成人精品在线 | 一区二区三区四区不卡 | 韩国av三级| 黄色毛片观看 | 国产手机视频在线观看 | 久久亚洲人 | 久久成人精品电影 | 国产在线v | av中文在线影视 | 亚洲精品va| 久久亚洲福利视频 | 九九视频在线观看视频6 | 亚洲在线视频免费 | 在线免费观看黄 | 免费看十八岁美女 | 亚洲国产免费 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 国产精品久久久久毛片大屁完整版 | 视频三区在线 | 一级片黄色片网站 | 久久香蕉国产精品麻豆粉嫩av | 国产小视频在线观看免费 | www.av免费| 国产精品久久久区三区天天噜 | 在线观看日韩一区 | 久久久久久久国产精品视频 | 91一区啪爱嗯打偷拍欧美 | 在线观看成人一级片 | 久久综合色婷婷 | 国产在线a不卡 | 日韩在线观看网站 | 中文永久字幕 | 久久久精品国产免费观看同学 | 欧美一级大片在线观看 | 人成午夜视频 | 97超碰资源站 | 六月婷婷色 | 欧美精品一区二区免费 | 亚洲免费视频在线观看 | 操操操人人 | 亚洲四虎在线 | 国产精品99久久久久久武松影视 | 激情欧美在线观看 | 欧美激情综合网 | 久草在线中文888 | 少妇激情久久 | 免费看黄色毛片 | 欧美日韩中文字幕在线视频 | 2022久久国产露脸精品国产 | 成年人国产在线观看 | 91在线网址 | 园产精品久久久久久久7电影 | 亚洲人精品午夜 | 超碰国产在线观看 | 黄色一级片视频 | 日韩欧美高清不卡 | 99精品免费久久久久久久久 | 高潮久久久久久 | 午夜精品一区二区三区免费视频 | 国产精品欧美日韩在线观看 | 久久免费视频网站 | 国产不卡免费 | 日韩在线电影一区 | 色a在线观看 | 欧美做受高潮电影o | 黄色软件视频大全免费下载 | 成年人在线免费看视频 | 色视频在线观看 | 人人玩人人爽 | 夜夜夜夜夜夜操 | 国产精品69av | 国产福利在线 | 久久国产精品第一页 | 午夜精品一区二区三区在线观看 | 中文高清av | 五月色婷 | 国产精品理论片在线观看 | 久久精视频| 国内精品视频一区二区三区八戒 | 久久精品国产免费看久久精品 | 日韩视频一二三区 | 4438全国亚洲精品观看视频 | 九九久久电影 | 香蕉视频网址 | 综合网av | 一区二区三区av在线 | a级国产乱理伦片在线播放 久久久久国产精品一区 | 五月婷婷视频在线 | 亚洲精品一区中文字幕乱码 | 国产一级免费观看视频 | 日本在线中文在线 | 欧洲精品久久久久毛片完整版 | 国产永久免费 | 日韩69av| 亚州av网站大全 | 天天射天 | 日韩免费观看av | 久草久热 | 黄色av电影免费观看 | 成人小视频在线观看免费 | av在线成人 | 不卡中文字幕av | 日韩av成人在线 | 综合黄色网 | 午夜天使 | 九九在线精品视频 | 国产视频一二三 | 日本中文字幕一二区观 | 精品自拍sae8—视频 | 深夜国产福利 | 1000部18岁以下禁看视频 | 伊人狠狠操 | av在线不卡观看 | 精油按摩av | 色爱区综合激月婷婷 | 99精品在线视频播放 | 天天综合日日夜夜 | 亚洲成av人片在线观看www | 91免费观看 | 91高清完整版在线观看 | 亚洲久草网 | www.少妇| 国产精品久久久久久久av电影 | 亚洲精品国产麻豆 | 久草视频首页 | 亚洲婷婷伊人 | 69国产成人综合久久精品欧美 | 激情五月播播久久久精品 | 黄a在线看 | 精品成人在线 | 天天插天天操天天干 | 免费黄色激情视频 | 久久乱码卡一卡2卡三卡四 五月婷婷久 | 日韩精品免费一区二区在线观看 | 天天爱天天 | 丁香免费视频 | 久久人91精品久久久久久不卡 | 国产 亚洲 欧美 在线 | 日韩欧美国产视频 | 免费观看版| 午夜久久久久久久 | 精品日韩在线一区 | 视频二区在线 | 狠狠色伊人亚洲综合网站野外 | 亚洲涩涩涩涩涩涩 | 波多野结衣电影一区二区 | 人人爽人人澡 | 欧美了一区在线观看 | 久久国产亚洲精品 | 欧美小视频在线 | 久久麻豆精品 | 91综合视频在线观看 | 日韩欧美一区视频 | 天天综合人人 | 天天激情综合网 | 黄色aaa毛片 | 国产午夜精品理论片在线 | 日韩久久久久久久久久久久 | 久草在线手机观看 | 天天操夜夜爱 | 久久视屏网| 国产成视频在线观看 | 射综合网 | 久草成人在线 | 青青啪 | 狠狠色丁香婷婷综合久久片 | 国产精品久久久久久久久久久杏吧 | 久草精品电影 | 日韩精品一区二区三区第95 | 天天射天天操天天色 | 欧美成人h版在线观看 | 在线天堂亚洲 | 黄色在线观看www | 国产成人99av超碰超爽 | 97精品久久 | 国产精成人品免费观看 | 色婷婷 亚洲 | 国产精品美女久久久久久网站 | 成人久久精品视频 | 色婷婷综合久色 | 久久国产女人 | 久久久久久久久久久网 | 久久成人免费视频 | 欧美色操 | 波多野结衣视频一区二区 | 天天干天天做 | 精品一区二区精品 | 国产精品99久久久久久宅男 | 午夜精品久久久久久久99无限制 | 九九视频网 | 91av手机在线 | 国产精品成久久久久三级 | 久久精品福利视频 | 久久久久成 | 久久国内视频 | 亚洲一区网 |