日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

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

linux

7.Linux 输入子系统分析

發布時間:2025/7/14 linux 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 7.Linux 输入子系统分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 為什么要引入輸入子系統?

在前面我們寫了一些簡單的字符設備的驅動程序,我們是怎么樣打開一個設備并操作的呢?

一般都是在執行應用程序時,open一個特定的設備文件,如:/dev/buttons

1 ..... 2 int main(int argc, char **argv) 3 { 4 unsigned char key_val; 5 int ret; 6 fd = open("/dev/buttons", O_RDWR); //默認為阻塞操作 7 if (fd < 0) 8 { 9 printf("can't open!\n"); 10 return -1; 11 } 12 ......

但是實際上,一般的應用程序不會去打開這樣設備文件“/dev/buttons”。一般打開的都是系統原有的文件,如“?dev/tty*?”?,還有可能是不需要打開什么tty,
而是直接“scanf()”就去獲得了按鍵的輸入。

以前我們寫一些輸入設備(鍵盤、鼠標等)的驅動都是采用字符設備、混雜設備處理的。問題由此而來,Linux開源社區的大神們看到了這大量輸入設備如此分散不堪,有木有可以實現一種機制,可以對分散的、不同類別的輸入設備進行統一的驅動,所以才出現了輸入子系統。

?輸入子系統引入的好處:

(1)統一了物理形態各異的相似的輸入設備的處理功能。例如,各種鼠標,不論PS/2、USB、還是藍牙,都被同樣處理。

(2)提供了用于分發輸入報告給用戶應用程序的簡單的事件(event)接口。你的驅動不必創建、管理/dev節點以及相關的訪問方法。因此它能夠很方便的調用輸入API以發送鼠標移動、鍵盤按鍵,或觸摸事件給用戶空間。X windows這樣的應用程序能夠無縫地運行于輸入子系統提供的event接口之上。

(3)抽取出了輸入驅動的通用部分,簡化了驅動,并提供了一致性。例如,輸入子系統提供了一個底層驅動(成為serio)的集合,支持對串口和鍵盤控制器等硬件輸入的訪問
  詳見《精通Linux設備驅動程序開發》


?

?

1.Linux輸入子系統框架

linux輸入子系統(linux input subsystem)從上到下由三層實現,分別為:

  輸入子系統事件處理層(EventHandler)

  輸入子系統核心層(InputCore)

  輸入子系統設備驅動層(input driver)

1.輸入子系統設備驅動層:主要實現對硬件設備的讀寫訪問,中斷設置,并把硬件產生的事件轉換為核心層定義的規范提交給事件處理層。

2.核心層:承上啟下。為驅動層提供輸入設備注冊與操作接口,如:input_register_device;通知事件處理層對事件進行處理;在/Proc下產生相應的設備信息。

    設備驅動層只要關心如何驅動硬件并獲得硬件數據(例如按下的按鍵數據),然后調用核心層提供的接口,核心層會自動把數據提交給事件處理層。

3.事件處理層:是用戶編程的接口(設備節點),并處理驅動層提交的數據處理。

    (Linux中在用戶空間將所有的設備都當做文件來處理,由于在一般的驅動程序中都有提供fops接口,以及在/dev下生成相應的設備文件nod,這些操作在輸入子系統中由事件處理層完成)

?

輸入子系統中有兩個類型的驅動,當我們要為一個輸入設備(如觸摸屏)的編寫驅動的時候,我們是要編寫兩個驅動:輸入設備驅動和輸入事件驅動?

? ? ? ?答案是否定的。在子系統中,事件驅動是標準的,對所有的輸入類都是可以用的,所以你更可能的是實現輸入設備驅動而不是輸入事件驅動。你的設備可以利用一個已經存在的,合適的輸入事件驅動通過輸入核心和用戶應用程序接口。

輸入設備都各有不同,那么輸入子系統也就只能實現他們的共性,差異性則由設備驅動來實現。差異性又體現在哪里?

最直觀體現在設備功能上的不同。對于驅動編寫者來說,在設備驅動中就只要使用輸入子系統提供的工具(也就是函數)來完成這些“差異”就行了,其他的則是輸入子系統的工作。這個思想不僅存在于輸入子系統,其他子系統也是一樣(比如:usb子系統、video子系統等)

?先分析核心層的代碼 Input.c

?以下轉載自Linux之輸入子系統分析(詳解)

Input.c

?在最后有一下兩段:

subsys_initcall(input_init); //修飾入口函數 module_exit(input_exit); //修飾出口函數

可知,子系統是作為一個模塊存在的。

1.先來分析入口函數input_init

1 static int __init input_init(void) 2 { 3 int err; 4 5 err = class_register(&input_class); //注冊類,放在/sys/class 6 if (err) { 7 printk(KERN_ERR "input: unable to register input_dev class\n"); 8 return err; 9 } 10 11 err = input_proc_init(); //在/proc下建立相關文件 12 if (err) 13 goto fail1; 14 15 err = register_chrdev(INPUT_MAJOR, "input", &input_fops); //注冊驅動 16 if (err) { 17 printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); 18 goto fail2; 19 } 20 21 return 0; 22 23 fail2: input_proc_exit(); 24 fail1: class_unregister(&input_class); 25 return err; 26 }

?

(1)上面第5行,class_register(&input_class),是在/sys/class中創建一個input類,input_class類結構如下:

struct class input_class = {.name = "input",.release = input_dev_release,.uevent = input_dev_uevent, };

如下圖,我們啟動內核,再啟動一個input子系統的驅動后,也可以看到創建了個"input"類 :

疑問:為什么在此只創建了類,卻沒有使用class_dev_create()函數在類下面創建驅動設備?

  當注冊了input子系統的驅動后,才會有設備驅動,此處代碼沒有驅動。以下會詳細解釋。

(2)上面第15行通過register_chrdev創建驅動設備,其中變量INPUT_MAJOR =13,所以創建了一個主設備為13的"input"設備。

然后我們來看看它的操作結構體input_fops,如下

static const struct file_operations input_fops = {.owner = THIS_MODULE,.open = input_open_file, };

只有一個.open函數,比如當我們掛載一個新的input驅動,則內核便會調用該.open函數,接下來分析該.open函數

?

2.進入input_open_file函數(drivers/input/input.c)

?

1 static int input_open_file(struct inode *inode, struct file *file) 2 { 3 struct input_handler *handler = input_table[iminor(inode) >> 5]; // (1) 4 const struct file_operations *old_fops, *new_fops = NULL; 5 int err; 6 7 if (!handler || !(new_fops = fops_get(handler->fops))) //(2) 8 return -ENODEV; 9 10 if (!new_fops->open) { 11 fops_put(new_fops); 12 return -ENODEV; 13 } 14 15 old_fops = file->f_op; 16 file->f_op = new_fops; //(3) 17 18 err = new_fops->open(inode, file); //(4) 19 if (err) { 20 fops_put(file->f_op); 21 file->f_op = fops_get(old_fops); 22 } 23 24 fops_put(old_fops); 25 26 return err; 27 }

(1)第3行中,其中iminor (inode)函數調用了MINOR(inode->i_rdev);讀取子設備號,然后將子設備除以32,找到新掛載的input驅動的數組號,然后放在input_handler 驅動處理函數handler中?

(2)第7行中,若handler有值,說明掛載有這個驅動,就將handler結構體里的成員file_operations * fops賦到新的file_operations *old_fops里面

(3)第16行中, 再將新的file_operations *old_fops賦到file-> file_operations ?*f_op里, 此時input子系統的file_operations就等于新掛載的input驅動的file_operations結構體,實現一個偷天換日的效果.

(4)第18行中,然后調用新掛載的input驅動的*old_fops里面的成員.open函數

?

3.上面代碼的input_table[]數組在初始時是沒有值的,

所以我們來看看input_table數組里面的數據又是在哪個函數里被賦值

?在input.c函數(drivers/input/input.c)中搜索input_table,找到它在input_register_handler()函數中被賦值,代碼如下:

int input_register_handler(struct input_handler *handler) { ... ... input_table[handler->minor >> 5] = handler; //input_table[]被賦值 ... ... list_add_tail(&handler->node, &input_handler_list); //然后將這個input_handler放到input_handler_list鏈表中 ... ...

 list_for_each_entry(dev, &input_dev_list, node)?//對于每一個input_dev,調用input_attach_handler
   input_attach_handler(dev, handler);  //根據input_handler的id_table判斷能否支持這個input_dev

}

就是將驅動處理程序input_handler注冊到input_table[]中,然后放在input_handler_list鏈表中,后面會講這個鏈表

?

?4.繼續來搜索input_register_handler,看看這個函數被誰來調用

?如下圖所示,有evdev.c(事件設備),tsdev.c(觸摸屏設備),joydev.c(joystick操作桿設備),keyboard.c(鍵盤設備),mousedev.c(鼠標設備)?這5個內核自帶的設備處理函數注冊到input子系統中

以evdev.c為例,它在evdev_ini()函數中注冊:

static int __init evdev_init(void) {return input_register_handler(&evdev_handler); //注冊 }

?

5.我們來看看這個evdev_handler變量是什么結構體,:

1 static struct input_handler evdev_handler = { 2 .event = evdev_event, 3 .connect = evdev_connect, //(4) 4 .disconnect = evdev_disconnect, 5 .fops = &evdev_fops, //(1) 6 .minor = EVDEV_MINOR_BASE, //(2) 7 .name = "evdev", 8 .id_table = evdev_ids, //(3) 9 };

就是我們之前看的input_handler驅動處理結構體

(1)?第5行中.fops:文件操作結構體,其中evdev_fops函數就是自己的寫的操作函數,然后賦到.fops中

(2)第6行中 .minor:用來存放次設備號

其中EVDEV_MINOR_BASE=64, 然后調用input_register_handler(&evdev_handler)后,由于EVDEV_MINOR_BASE/32=2,所以存到input_table[2]中

?所以當open打開這個input設備,就會進入 input_open_file()函數,執行evdev_handler-> evdev_fops -> .open函數,如下所示:

1 static const struct file_operations evdev_fops = { 2 .owner = THIS_MODULE, 3 .read = evdev_read, 4 .write = evdev_write, 5 .poll = evdev_poll, 6 .open = evdev_open, 7 .release = evdev_release, 8 .unlocked_ioctl = evdev_ioctl, 9 #ifdef CONFIG_COMPAT 10 .compat_ioctl = evdev_ioctl_compat, 11 #endif 12 .fasync = evdev_fasync, 13 .flush = evdev_flush 14 };

(3)第8行中.id_table :?表示能支持哪些輸入設備,比如某個驅動設備的input_dev->的id和某個input_handler的id_table相匹配,就會調用.connect連接函數,如下圖

(4)第3行中.connect:連接函數,將設備input_dev和某個input_handler建立連接,如下圖

6.我們先來看看上圖的input_register_device()函數,如何創建驅動設備的

?搜索input_register_device,發現內核自己就已經注冊了很多驅動設備

 6.1然后進入input_register_device()函數,代碼如下:

1 int input_register_device(struct input_dev *dev) //*dev:要注冊的驅動設備 2 { 3 ... ... 4 list_add_tail(&dev->node, &input_dev_list); //(1)放入鏈表中 5 ... ... 6 list_for_each_entry(handler, &input_handler_list, node) //(2) 7   input_attach_handler(dev, handler); 8 ... ... 9 }

(1)第4行中,將要注冊的input_dev驅動設備放在input_dev_list鏈表中

(2)第6行中,其中input_handler_list在前面講過,就是存放每個input_handle驅動處理結構體,

然后list_for_each_entry()函數會將每個input_handle從鏈表中取出,放到handler中

最后會調用input_attach_handler()函數,將每個input_handle的id_table進行判斷,若兩者支持便進行連接。

  6.2然后我們在回過頭來看注冊input_handler的input_register_handler()函數,如下圖所示

?在input.c中

1 int input_register_handler(struct input_handler *handler) 2 { 3 struct input_dev *dev; 4 5 INIT_LIST_HEAD(&handler->h_list); 6 7 if (handler->fops != NULL) { 8 if (input_table[handler->minor >> 5]) 9 return -EBUSY; 10 11 input_table[handler->minor >> 5] = handler; //放入數組 12 } 13 14 list_add_tail(&handler->node, &input_handler_list); //放入鏈表 15      16 list_for_each_entry(dev, &input_dev_list, node)  //對于每一個input_dev,調用input_attach_handler 17 input_attach_handler(dev, handler); 18 19 input_wakeup_procfs_readers(); 20 return 0;

所以,不管新添加input_dev還是input_handler,都會進入input_attach_handler()判斷兩者id是否有支持, 若兩者支持便進行連接

?

  6.3我們來看看input_attach_handler()如何實現匹配兩者id的:

1 static int input_attach_handler(struct input_dev *dev, struct input_handler *handler) 2 { 3 ... ... 4 id = input_match_device(handler->id_table, dev); //匹配兩者 5 6 if (!id) //若不匹配,return退出 7 return -ENODEV; 8 9 error = handler->connect(handler, dev, id); //調用input_handler ->connect函數建立連接 10 ... ... 11 12 }

根據input_handler的id_table判斷能否支持這個input_dev
如果能支持,則調用input_handler的connect函數建立“連接”

7.以evdev.c(事件驅動) 的evdev_handler->connect函數來分析是怎樣建立連接的,如下:

1 static struct input_handler evdev_handler = { 2 .event = evdev_event, 3 .connect = evdev_connect, 4 .disconnect = evdev_disconnect, 5 .fops = &evdev_fops, 6 .minor = EVDEV_MINOR_BASE, 7 .name = "evdev", 8 .id_table = evdev_ids, 9 };

?

  7.1?evdev_handler的.connect函數是evdev_connect(),代碼如下:

1 static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) 2 { 3 ... ... 4 for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); //查找驅動設備的子設備號 5 if (minor == EVDEV_MINORS) { // EVDEV_MINORS=32,所以該事件下的驅動設備最多存32個, 6 printk(KERN_ERR "evdev: no more free evdev devices\n"); 7 return -ENFILE; //沒找到驅動設備 8 } 9 ... ... 10 evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); //分配一個input_handle全局結構體(沒有r) 11 ... ... 12 evdev->handle.dev = dev; //指向參數input_dev驅動設備 13 evdev->handle.name = evdev->name; 14 evdev->handle.handler = handler; //指向參數 input_handler驅動處理結構體 15 evdev->handle.private = evdev; 16 sprintf(evdev->name, "event%d", minor); //(1)保存驅動設備名字, event%d 17 ... ... 18 devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), //(2) 將主設備號和次設備號轉換成dev_t類型 19 cdev = class_device_create(&input_class, &dev->cdev, devt,dev->cdev.dev, evdev->name); 20 // (3)在input類下創建驅動設備 21 22 ... ... 23 error = input_register_handle(&evdev->handle); //(4)注冊這個input_handle結構體 24 25 ... ... 26 }

(1) 第16行中,是在保存驅動設備名字,名為event%d, 比如下圖(鍵盤驅動)event1: 因為沒有設置子設備號,默認從小到大排列,其中event0是表示這個input子系統,所以這個鍵盤驅動名字就是event1

(2)第18行中,是在保存驅動設備的主次設備號,其中主設備號INPUT_MAJOR=13,因為EVDEV_MINOR_BASE=64,所以此設備號=64+驅動程序本事子設備號, 比如下圖(鍵盤驅動)event1: ?主次設備號就是13,65

(3)在之前在2小結里就分析了input_class類結構,所以第19行中,會在/sys/class/input類下創建驅動設備event%d,比如下圖(鍵盤驅動)event1:

(4)最終會進入input_register_handle()函數來注冊,代碼在下面

? 

 7.2?input_register_handle()函數如下:

1 int input_register_handle(struct input_handle *handle) 2 { 3 struct input_handler *handler = handle->handler; //handler= input_handler驅動處理結構體 4 5 list_add_tail(&handle->d_node, &handle->dev->h_list); //(1) 6 list_add_tail(&handle->h_node, &handler->h_list); // (2) 7 8 if (handler->start) 9 handler->start(handle); 10 return 0; 11 }

(1)在第5行中,?因為handle->dev指向input_dev驅動設備,所以就是將handle->d_node放入到input_dev驅動設備的h_list鏈表中,

即input_dev驅動設備的h_list鏈表就指向handle->d_node

(2) 在第6行中,?同樣, input_handler驅動處理結構體的h_list也指向了handle->h_node

最終如下圖所示:

兩者的.h_list都指向了同一個handle結構體,然后通過.h_list 來找到handle的成員.dev和handler,便能找到對方,便建立了連接

?

8.建立了連接后,又如何讀取evdev.c(事件驅動) 的evdev_handler->.fops->.read函數?

事件驅動的.read函數是evdev_read()函數,我們來分析下:

1 static ssize_t evdev_read(struct file *file, char __user * buffer, size_t count, loff_t *ppos) 2 { 3 ... ... 4 /*判斷應用層要讀取的數據是否正確*/ 5 if (count < evdev_event_size()) 6 return -EINVAL; 7 8 /*在非阻塞操作情況下,若client->head == client->tail|| evdev->exist時(沒有數據),則return返回*/ 9 if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK)) 10 return -EAGAIN; 11 12 /*若client->head == client->tail|| evdev->exist時(沒有數據),等待中斷進入睡眠狀態 */ 13 retval = wait_event_interruptible(evdev->wait,client->head != client->tail || !evdev->exist); 14 15 ... ... //上傳數據 16 17 }

?

9.若read函數進入了休眠狀態,又是誰來喚醒?

?我們搜索這個evdev->wait這個等待隊列變量,找到evdev_event函數里喚醒:

static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { ... ...wake_up_interruptible(&evdev->wait); //有事件觸發,便喚醒等待中斷 }

其中evdev_event()是evdev.c(事件驅動) 的evdev_handler->.event成員,如下所示:

1 static struct input_handler evdev_handler = { 2 .event = evdev_event, 3 .connect = evdev_connect, 4 .disconnect = evdev_disconnect, 5 .fops = &evdev_fops, 6 .minor = EVDEV_MINOR_BASE, 7 .name = "evdev", 8 .id_table = evdev_ids, 9 };

當有事件發生了,比如對于按鍵驅動,當有按鍵按下時,就會進入.event函數中處理事件

?

?10.分析下,是調用evdev_event()這個.event事件驅動函數

?猜測:硬件相關的代碼(input_dev那層)--中斷處理函數

?來看看內核 gpio_keys_isr()函數代碼例子就知道了 (driver/input/keyboard/gpio_key.c)

1 static irqreturn_t gpio_keys_isr(int irq, void *dev_id) 2 { 3 /*獲取按鍵值,賦到state里*/ 4 ... ... 5 6 /*上報事件*/ 7 input_event(input, type, button->code, !!state); 8 input_sync(input); //同步信號通知,表示事件發送完畢 9 }

顯然就是通過input_event()來調用.event事件函數,我們來看看:

1 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 2 { 3 struct input_handle *handle; 4 ... ... 5 6 /* 通過input_dev ->h_list鏈表找到input_handle驅動處理結構體*/ 7 list_for_each_entry(handle, &dev->h_list, d_node) 8 if (handle->open) //如果input_handle之前open 過,那么這個就是我們的驅動處理結構體 9 handle->handler->event(handle, type, code, value); //調用evdev_event()的.event事件函數 10 11 }

若之前驅動input_dev和處理input_handler已經通過input_handler 的.connect函數建立起了連接,那么就調用evdev_event()的.event事件函數,如下圖所示:

?

?

?11.本節總結分析:

1.注冊輸入子系統,進入input_init():

1)創建主設備號為13的"input"字符設備

err = register_chrdev(INPUT_MAJOR, "input", &input_fops);

?

2.open打開驅動,進入input_open_file():

1)更新設備的file_oprations

file->f_op=fops_get(handler->fops);

2)執行file_oprations->open函數

err = new_fops->open(inode, file);

?

3.注冊input_handler,進入input_register_handler():

1)添加到input_table[]處理數組中

input_table[handler->minor >> 5] = handler;

?2)添加到input_handler_list鏈表中

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

3)判斷input_dev的id,是否有支持這個驅動的設備

list_for_each_entry(dev, &input_dev_list, node) //遍歷查找input_dev_list鏈表里所有input_dev input_attach_handler(dev, handler); //判斷兩者id,若兩者支持便進行連接。

?

4.注冊input_dev,進入input_register_device():

1)放在input_dev_list鏈表中

list_add_tail(&dev->node, &input_dev_list);

2)判斷input_handler的id,是否有支持這個設備的驅動

list_for_each_entry(handler, &input_handler_list, node) //遍歷查找input_handler_list鏈表里所有input_handler input_attach_handler(dev, handler); //判斷兩者id,若兩者支持便進行連接。

?

5.判斷input_handlerinput_devid,進入input_attach_handler():

?1)匹配兩者id,

input_match_device(handler->id_table, dev); //匹配input_handler和dev的id,不成功退出函數

2)匹配成功調用input_handler ->connect

handler->connect(handler, dev, id); //建立連接

?

6.建立input_handlerinput_dev的連接,進入input_handler->connect():

?1)創建全局結構體,通過input_handle結構體連接雙方

evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); //創建兩者連接的input_handle全局結構體 list_add_tail(&handle->d_node, &handle->dev->h_list); //連接input_dev->h_list list_add_tail(&handle->h_node, &handler->h_list); // 連接input_handle->h_list

?

7.有事件發生時,比如按鍵中斷,在中斷函數中需要進入input_event()上報事件:

?1)找到驅動處理結構體,然后執行input_handler->event()

list_for_each_entry(handle, &dev->h_list, d_node) // 通過input_dev ->h_list鏈表找到input_handle驅動處理結構體 if (handle->open) //如果input_handle之前open 過,那么這個就是我們的驅動處理結構體(有可能一個驅動設備在不同情況下有不同的驅動處理方式)handle->handler->event(handle, type, code, value); //調用evdev_event()的.event事件函數

?

轉載于:https://www.cnblogs.com/y4247464/p/10126481.html

總結

以上是生活随笔為你收集整理的7.Linux 输入子系统分析的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 杨幂一区二区国产精品 | 99久久国产热无码精品免费 | 欧美一区2区三区4区公司 | 国产精品1区2区 | av永久免费在线观看 | 91婷婷色 | 先锋av在线资源 | 女人高潮被爽到呻吟在线观看 | 亚洲一区二区精品在线观看 | 国产一区二区三区 | 成人免费无码大片a毛片抽搐色欲 | 美日韩一级 | 亚洲欧洲视频在线观看 | 国产午夜手机精彩视频 | 无码精品在线观看 | 日本一区二区高清免费 | 色哟哟免费在线观看 | 激情草逼 | 成人黄色一区二区 | 天堂资源网 | 国产在线高清 | 国产精品黄视频 | 国产精品自拍99 | 中文字幕乱码人妻无码久久95 | 尤物视频在线播放 | av不卡免费在线观看 | 婷婷在线免费 | 人人草人人 | 秋霞成人av| 狠狠干香蕉| a黄色片 | 免费在线视频一区 | 四季av在线一区二区三区 | 欧美成人一区二区 | 在线免费看污片 | 日韩欧美亚洲精品 | 国产 中文 字幕 日韩 在线 | 欧美人与性动交α欧美精品 | 影音先锋在线视频 | 黄色大片中文字幕 | 成人一区二区av | 亚洲视频欧美 | 国产午夜一级 | 日本在线www | 91免费成人| 久草免费看 | 六月婷婷综合网 | 久草91| 欧美做受69 | 色婷婷综合在线 | 一级黄色大毛片 | 九色福利视频 | 日韩欧美少妇 | 99re这里只有精品在线 | 亚洲一区二区在线免费 | 亚洲剧情av| 日韩精品一区二区三区不卡 | 葵司免费一区二区三区四区五区 | 国产在线高清 | 欧美国产激情 | 午夜a级片 | 欧美入口 | 丰满熟女人妻一区二区三区 | aaaaaa毛片 | 视频一区亚洲 | 成人18视频 | 久久久久久久久网站 | 老色批永久免费网站www | 日本a免费| 欧美aaa一级片| 欧美一级淫片免费 | 熟女少妇a性色生活片毛片 亚洲伊人成人网 | 亚洲视频日韩 | 两个人看的www视频免费完整版 | 黄色动漫免费在线观看 | 国产无遮挡一区二区三区毛片日本 | www.brazzers.com| 日韩一区二区三区av | 丁香六月色婷婷 | 欧美精品aa| 日本免费一区二区三区四区 | 正在播放木下凛凛88av | 一区二区三区四区亚洲 | 91亚洲一区 | 一级特黄aa大片欧美 | 国产欧美一级片 | 在线国产视频 | 国产精品无码久久久久高潮 | 日本韩国免费观看 | 欧美精品欧美极品欧美激情 | 无码黑人精品一区二区 | 国产av无码专区亚洲精品 | 国产第113页 | 久久依人 | 日本不卡高清视频 | 亚洲午夜剧场 | 久久久久久国产精品三级玉女聊斋 | 亚洲第一视频 | 欧美黑人疯狂性受xxxxx喷水 |