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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Linux那些事儿 之 戏说USB(28)设备的生命线(十一)

發布時間:2023/11/27 生活经验 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux那些事儿 之 戏说USB(28)设备的生命线(十一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

現在已經使用GET_DESCRIPTOR請求取到了包含一個配置里所有相關描述符內容的一堆數據,這些數據是raw的,即原始的,所有數據不管是配置描述符、接口描述符還是端點描述符都彼此的擠在一起,所以得想辦法將它們給分開,丁是丁卯是卯的,于是usb_parse_configuration()登上了歷史舞臺,顯然它們兩個不管是誰想簡短幾句就搞定是不可能的,不過也沒什么可怕的,咱寫不會,看還不會么?

drivers/usb/core/config.c

static int usb_parse_configuration(struct usb_device *dev, int cfgidx,struct usb_host_config *config, unsigned char *buffer, int size)
{struct device *ddev = &dev->dev;unsigned char *buffer0 = buffer;int cfgno;int nintf, nintf_orig;int i, j, n;struct usb_interface_cache *intfc;unsigned char *buffer2;int size2;struct usb_descriptor_header *header;int len, retval;u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];unsigned iad_num = 0;memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);if (config->desc.bDescriptorType != USB_DT_CONFIG ||config->desc.bLength < USB_DT_CONFIG_SIZE ||config->desc.bLength > size) {dev_err(ddev, "invalid descriptor for config index %d: ""type = 0x%X, length = %d\n", cfgidx,config->desc.bDescriptorType, config->desc.bLength);return -EINVAL;}cfgno = config->desc.bConfigurationValue;buffer += config->desc.bLength;size -= config->desc.bLength;nintf = nintf_orig = config->desc.bNumInterfaces;if (nintf > USB_MAXINTERFACES) {dev_warn(ddev, "config %d has too many interfaces: %d, ""using maximum allowed: %d\n",cfgno, nintf, USB_MAXINTERFACES);nintf = USB_MAXINTERFACES;}/* Go through the descriptors, checking their length and counting the* number of altsettings for each interface */n = 0;for ((buffer2 = buffer, size2 = size);size2 > 0;(buffer2 += header->bLength, size2 -= header->bLength)) {if (size2 < sizeof(struct usb_descriptor_header)) {dev_warn(ddev, "config %d descriptor has %d excess ""byte%s, ignoring\n",cfgno, size2, plural(size2));break;}header = (struct usb_descriptor_header *) buffer2;if ((header->bLength > size2) || (header->bLength < 2)) {dev_warn(ddev, "config %d has an invalid descriptor ""of length %d, skipping remainder of the config\n",cfgno, header->bLength);break;}if (header->bDescriptorType == USB_DT_INTERFACE) {struct usb_interface_descriptor *d;int inum;d = (struct usb_interface_descriptor *) header;if (d->bLength < USB_DT_INTERFACE_SIZE) {dev_warn(ddev, "config %d has an invalid ""interface descriptor of length %d, ""skipping\n", cfgno, d->bLength);continue;}inum = d->bInterfaceNumber;if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) &&n >= nintf_orig) {dev_warn(ddev, "config %d has more interface ""descriptors, than it declares in ""bNumInterfaces, ignoring interface ""number: %d\n", cfgno, inum);continue;}if (inum >= nintf_orig)dev_warn(ddev, "config %d has an invalid ""interface number: %d but max is %d\n",cfgno, inum, nintf_orig - 1);/* Have we already encountered this interface?* Count its altsettings */for (i = 0; i < n; ++i) {if (inums[i] == inum)break;}if (i < n) {if (nalts[i] < 255)++nalts[i];} else if (n < USB_MAXINTERFACES) {inums[n] = inum;nalts[n] = 1;++n;}} else if (header->bDescriptorType ==USB_DT_INTERFACE_ASSOCIATION) {if (iad_num == USB_MAXIADS) {dev_warn(ddev, "found more Interface ""Association Descriptors ""than allocated for in ""configuration %d\n", cfgno);} else {config->intf_assoc[iad_num] =(struct usb_interface_assoc_descriptor*)header;iad_num++;}} else if (header->bDescriptorType == USB_DT_DEVICE ||header->bDescriptorType == USB_DT_CONFIG)dev_warn(ddev, "config %d contains an unexpected ""descriptor of type 0x%X, skipping\n",cfgno, header->bDescriptorType);}	/* for ((buffer2 = buffer, size2 = size); ...) */size = buffer2 - buffer;config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0);if (n != nintf)dev_warn(ddev, "config %d has %d interface%s, different from ""the descriptor's value: %d\n",cfgno, n, plural(n), nintf_orig);else if (n == 0)dev_warn(ddev, "config %d has no interfaces?\n", cfgno);config->desc.bNumInterfaces = nintf = n;/* Check for missing interface numbers */for (i = 0; i < nintf; ++i) {for (j = 0; j < nintf; ++j) {if (inums[j] == i)break;}if (j >= nintf)dev_warn(ddev, "config %d has no interface number ""%d\n", cfgno, i);}/* Allocate the usb_interface_caches and altsetting arrays */for (i = 0; i < nintf; ++i) {j = nalts[i];if (j > USB_MAXALTSETTING) {dev_warn(ddev, "too many alternate settings for ""config %d interface %d: %d, ""using maximum allowed: %d\n",cfgno, inums[i], j, USB_MAXALTSETTING);nalts[i] = j = USB_MAXALTSETTING;}len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL);if (!intfc)return -ENOMEM;kref_init(&intfc->ref);}/* FIXME: parse the BOS descriptor *//* Skip over any Class Specific or Vendor Specific descriptors;* find the first interface descriptor */config->extra = buffer;i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,USB_DT_INTERFACE, &n);config->extralen = i;if (n > 0)dev_dbg(ddev, "skipped %d descriptor%s after %s\n",n, plural(n), "configuration");buffer += i;size -= i;/* Parse all the interface/altsetting descriptors */while (size > 0) {retval = usb_parse_interface(ddev, cfgno, config,buffer, size, inums, nalts);if (retval < 0)return retval;buffer += retval;size -= retval;}/* Check for missing altsettings */for (i = 0; i < nintf; ++i) {intfc = config->intf_cache[i];for (j = 0; j < intfc->num_altsetting; ++j) {for (n = 0; n < intfc->num_altsetting; ++n) {if (intfc->altsetting[n].desc.bAlternateSetting == j)break;}if (n >= intfc->num_altsetting)dev_warn(ddev, "config %d interface %d has no ""altsetting %d\n", cfgno, inums[i], j);}}return 0;
}
代碼太生猛了,還是先說點理論墊墊底兒,其實前面也說到過的,使用GET_DESCRIPTOR請求時,得到的數據并不是雜亂無序的,而是有規可循的,一般來說,配置描述符后面跟的是第一個接口的接口描述符,接著是這個接口里第一個端點的端點描述符,如果有class-和vendor-specific描述符的話,會緊跟在對應的標準描述符后面,不管接口有多少端點有多少都是按照這個規律順序排列。當然有些廠商會特立獨行一些,非要先返回第二個接口然后再返回第一個接口,但配置描述符后面總歸先是接口描述符再是端點描述符。
5行,buffer里保存的就是GET_DESCRIPTOR請求獲得的那堆數據,要解析這些數據,不可避免的要對buffer指針進行操作,這里先將它備份一下。
17行,config是參數里傳遞過來的,是設備struct usb_device結構體里的struct usb_host_config結構體數組config中的一員。不出意外的話buffer的前USB_DT_CONFIG_SIZE個字節對應的就是配置描述符,那么這里的意思就很明顯了。然后做些檢驗,看看這USB_DT_CONFIG_SIZE字節的內容究竟是不是正如我們所期待的那樣是個配置描述符,如果不是,那buffer里的數據問題可就大了,沒什么利用價值了,還是返回吧,不必要再接著解析了。
28行,buffer的前USB_DT_CONFIG_SIZE個字節已經理清了,接下來該解析剩下的數據了,buffer需要緊跟形勢的發展,位置和長度都要做相應的修正。
31行,獲得這個配置所擁有的接口數目,不能簡單一賦值就完事兒了,得知道系統里對這個數目是有個USB_MAXINTERFACES這樣的限制的,如果數目比這個限制還大,就改為USB_MAXINTERFACES。
42~124行,這函數真是酷到家了,連里面一個循環都這么長這么酷,不過別看它cool,完成的事情卻很單一,就是統計記錄一下這個配置里每個接口所擁有的設置數目。提醒你一下,千萬別被寫代碼的哥們兒給迷惑了,這個循環里使用的是buffer2和size2, buffer和size的兩個替身,buffer和size就停在42行享受陽光海灘。
46行,這里遇到一個新的結構struct usb_descriptor_header,在include/uapi/linux/usb/ch9.h里定義
struct usb_descriptor_header {__u8  bLength;__u8  bDescriptorType;
} __attribute__ ((packed));
這個結構比俺還單純,就包括了兩個成員,你研究一下所有的那些標準描述符,會興奮的發現它們的前兩個字節都是一樣的,一個表示描述符的長度,一個表示描述符的類型。那么為什么要專門搞這么一個結構?試想一下,有塊數據緩沖區,讓你判斷一下里面保存的是哪個描述符,或者是其它什么東西,你怎么做?你當然可以直接將它的前兩個字節內容讀出來,判斷判斷bDescriptorType,再判斷判斷bLength,不過這樣的代碼就好像你自己畫的一副抽象畫,太藝術化了,過個若干年自己都不知道啥意思,更別說別人了。53行做了個很好的示范,把buffer2指針轉化為struct usb_descriptor_header的結構體指針,然后就可以使用‘->’來取出bLength和bDescriptorType,這樣寫的人順心看的人舒心,你好我好大家好。
那么46行就表示如果GET_DESCRIPTOR請求返回的數據里除了包括一個配置描述符外,連兩個字節都沒有,那就說明這個配置在進行裸體行為藝術,能看不能用。
61行,如果這是個接口描述符就說明這個配置的某個接口擁有一個設置,是沒有什么所謂的設置描述符的,一個接口描述符就代表了存在一個設置,接口描述里的bInterfaceNumber會指出這個設置隸屬于哪個接口。那么這里除了是接口描述符還有可能是什么?還有可能是class-和vendor-specific描述符。
65行,既然覺得這是個接口描述符,就把這個指針轉化為struct usb_interface_descriptor結構體指針,你可別被C里的這種指針游戲給轉暈了,一個地址如果代碼不給它賦予什么意義,它除了表示一個地址外就什么都不是。同樣一個地址,上面轉化為struct usb_descriptor_header結構體指針和這里轉化為struct usb_interface_descriptor結構體指針,它就不再僅僅是一個地址,而是代表了不同的含義。
66行,仍然不忘保持革命斗爭警惕性。bDescriptorType等于USB_DT_INTERFACE并不說明它就一定是接口描述符了,它的bLength還必須要等于USB_DT_INTERFACE_SIZE。bLength和bDescriptorType一起才能決定一個描述符。
91~102這幾行是用來考驗咱們的耐心和勇氣的。首先要明白n、inums和nalts這幾個枯燥的東東是表示什么的,n記錄的是接口的數目,數組inums里的每一項都表示一個接口號,數組nalts里的每一項記錄的是每個接口擁有的設置數目,inums和nalts兩個數組里的元素是一一對應的,inums[0]就對應nalts[0],inums[1]就對應nalts[1]。其次還要謹記一個殘酷的事實,發送GET_DESCRIPTOR請求時,設備并不一定會按照接口1,接口2這樣的順序循規蹈矩的返回數據,雖說協議里是這么要求的,但都在江湖行走誰能沒點個性。
125行,buffer的最后邊兒可能會有些垃圾數據,為了去除這些洋垃圾,這里需要將size和配置描述符里的那個wTotalLength修正一下。
128行,經過上面那個超酷的循環之后,如果統計得到的接口數目和配置描述符里的bNumInterfaces不符,或者干脆就沒有發現配置里有什么接口,就警告一下。
137行,又一個for循環,目的是看看是不是遺漏了哪個接口號,比如說配置6個接口,為什么是6那,因為俺的幸運數字是6,呵呵,每個接口號都應該對應數組inums里的一項,如果在inums里面沒有發現這個接口號,比如2吧,那2這個接口號就神秘失蹤了,你找不到接口2。這個當然也屬于違章駕駛,需要警告一下,開票罰600,不開票罰200,你自己選。
148行,再一個for循環,struct usb_interface_caches做嘛用的早就說過了,USB_MAXALTSETTING的定義在config.c里
#define USB_MAXALTSETTING		128	/* Hard limit */
一個接口最多可以有128個設置,足夠了。158行根據每個接口擁有的設置數目為對應的intf_cache數組項申請內存。
169行,配置描述符后面緊跟的不一定就是接口描述符,還可能是class-和vendor-specific描述符,如果有的話。不管有沒有,先把buffer的地址賦給extra,如果沒有擴展的描述符,則170行返回的i就等于0,extralen也就為0。
170行,調用find_next_descriptor()在buffer里尋找配置描述符后面跟著的第一個接口描述符。它也在config.c里定義,進去看看
static int find_next_descriptor(unsigned char *buffer, int size,int dt1, int dt2, int *num_skipped)
{struct usb_descriptor_header *h;int n = 0;unsigned char *buffer0 = buffer;/* Find the next descriptor of type dt1 or dt2 */while (size > 0) {h = (struct usb_descriptor_header *) buffer;if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2)break;buffer += h->bLength;size -= h->bLength;++n;}/* Store the number of descriptors skipped and return the* number of bytes skipped */if (num_skipped)*num_skipped = n;return buffer - buffer0;
}
這個函數需要傳遞兩個描述符類型的參數,11行已經清清楚楚的表明它是腳踩兩只船的,一個多情的種。它不是專一的去尋找一種描述符,而是去尋找兩種描述符,比如你指定dt1為USB_DT_INTERFACE,dt2為USB_DT_ENDPOINT時,只要能夠找到接口描述符或端點描述符中的一個,這個函數就返回。usb_parse_configuration函數的170行只需要尋找下一個接口描述符,所以dt1和dt2都設置為USB_DT_INTERFACE。
這個函數結束后,num_skipped里記錄的是搜索過程中忽略的dt1和dt2之外其它描述符的數目,返回值表示搜索結束時buffer的位置比搜索開始時前進的字節數。其它沒什么好講的。還是回到usb_parse_configuration函數。
176行,根據find_next_descriptor的結果修正buffer和size。你可能因為受過很多面試的摧殘,或者代碼里錯過很多次,對C里的按引用傳遞和按值傳遞已經爛熟于心,看到find_next_descriptor()那里傳遞的是buffer,一個指針,條件反射的覺得它里面對buffer的修改必定影響了外面的buffer,所以認為buffer已經指向了尋找到的接口描述符。但是你的這種如意算盤此時并不能如意,find_next_descriptor里修改的只是參數里buffer的值,并沒有修改它指向的內容,對于地址本身來說仍然只能算是按值傳遞,怎么修改都影響不到函數外邊,所以這里的176行仍然要對buffer的位置進行修正。
180行,事不過三,三個for循環之后輪到了一個while循環,如果size大于0,就說明配置描述符后面找到了一個接口描述符,根據這個接口描述符的長度,已經可以解析出一個完整的接口描述符了,但是仍然沒到樂觀的時候,這個接口描述符后面還會跟著一群端點描述符,再然后還會有其它的接口描述符。所以我們又迎來了另一個變態函數usb_parse_interface,先不管這個它長什么樣子,畢竟usb_parse_configuration()就快到頭兒了,暫時只需要知道它返回的時候,buffer的位置已經在下一個接口描述符那里了,還是那個理兒,對buffer地址本身來說是按值傳遞的,所以186行要對這個位置和長度進行下調整以適應新形勢。那么這個while循環的意思就很明顯了,對buffer一段一段的解析,直到再也找不到接口描述符了。
191行,最后這個for循環沒啥實質性的內容,就是找一下每個接口是不是有哪個設置編號給漏過去了,只要有耐心,你就能看得懂。咱們接下來還是看config.c里的那個usb_parse_interface()
static int usb_parse_interface(struct device *ddev, int cfgno,struct usb_host_config *config, unsigned char *buffer, int size,u8 inums[], u8 nalts[])
{unsigned char *buffer0 = buffer;struct usb_interface_descriptor	*d;int inum, asnum;struct usb_interface_cache *intfc;struct usb_host_interface *alt;int i, n;int len, retval;int num_ep, num_ep_orig;d = (struct usb_interface_descriptor *) buffer;buffer += d->bLength;size -= d->bLength;if (d->bLength < USB_DT_INTERFACE_SIZE)goto skip_to_next_interface_descriptor;/* Which interface entry is this? */intfc = NULL;inum = d->bInterfaceNumber;for (i = 0; i < config->desc.bNumInterfaces; ++i) {if (inums[i] == inum) {intfc = config->intf_cache[i];break;}}if (!intfc || intfc->num_altsetting >= nalts[i])goto skip_to_next_interface_descriptor;/* Check for duplicate altsetting entries */asnum = d->bAlternateSetting;for ((i = 0, alt = &intfc->altsetting[0]);i < intfc->num_altsetting;(++i, ++alt)) {if (alt->desc.bAlternateSetting == asnum) {dev_warn(ddev, "Duplicate descriptor for config %d ""interface %d altsetting %d, skipping\n",cfgno, inum, asnum);goto skip_to_next_interface_descriptor;}}++intfc->num_altsetting;memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE);/* Skip over any Class Specific or Vendor Specific descriptors;* find the first endpoint or interface descriptor */alt->extra = buffer;i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,USB_DT_INTERFACE, &n);alt->extralen = i;if (n > 0)dev_dbg(ddev, "skipped %d descriptor%s after %s\n",n, plural(n), "interface");buffer += i;size -= i;/* Allocate space for the right(?) number of endpoints */num_ep = num_ep_orig = alt->desc.bNumEndpoints;alt->desc.bNumEndpoints = 0;		/* Use as a counter */if (num_ep > USB_MAXENDPOINTS) {dev_warn(ddev, "too many endpoints for config %d interface %d ""altsetting %d: %d, using maximum allowed: %d\n",cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS);num_ep = USB_MAXENDPOINTS;}if (num_ep > 0) {/* Can't allocate 0 bytes */len = sizeof(struct usb_host_endpoint) * num_ep;alt->endpoint = kzalloc(len, GFP_KERNEL);if (!alt->endpoint)return -ENOMEM;}/* Parse all the endpoint descriptors */n = 0;while (size > 0) {if (((struct usb_descriptor_header *) buffer)->bDescriptorType== USB_DT_INTERFACE)break;retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt,num_ep, buffer, size);if (retval < 0)return retval;++n;buffer += retval;size -= retval;}if (n != num_ep_orig)dev_warn(ddev, "config %d interface %d altsetting %d has %d ""endpoint descriptor%s, different from the interface ""descriptor's value: %d\n",cfgno, inum, asnum, n, plural(n), num_ep_orig);return buffer - buffer0;skip_to_next_interface_descriptor:i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,USB_DT_INTERFACE, NULL);return buffer - buffer0 + i;
}
14行,傳遞過來的buffer里開頭兒那部分只能是一個接口描述符,沒有什么可質疑的,所以這里將地址轉化為struct usb_interface_descriptor結構體指針,然后調整buffer的位置和size。
18行,只能是并不說明它就是,只有bLength等于USB_DT_INTERFACE_SIZE才說明開頭兒的USB_DT_INTERFACE_SIZE字節確實是個接口描述符。否則就沒必要再對這些數據進行什么處理了,直接跳到最后吧。先看看這個函數的最后都發生了什么,從新的位置開始再次調用find_next_descriptor()在buffer里尋找下一個接口描述符。
22行,因為數組inums并不一定是按照接口的順序來保存接口號的,inums[1]對應的可能是接口1也可能是接口0,所以這里要用for循環來尋找這個接口對應著inums里的哪一項,從而根據在數組里的位置獲得接口對應的struct usb_interface_cache結構體。usb_parse_configuration()已經告訴了我們,同一個接口在inums和intf_cache這兩個數組里的位置是一樣的。
34行,獲得這個接口描述符對應的設置編號,然后根據這個編號從接口的cache里搜索看這個設置是不是已經遇到過了,如果已經遇到過,就沒必要再對這個接口描述符進行處理,直接跳到最后,否則意味著發現了一個新的設置,要將它添加到cache里,并cache里的設置數目num_altsetting加1。要記住,設置是用struct usb_host_interface結構來表示的,一個接口描述符就對應一個設置。
51行,這段代碼好熟悉啊。現在buffer開頭兒的那個接口描述符已經理清了,要解析它后面的那些數據了。先把位置賦給這個剛解析出來的接口描述符的extra,然后再從這個位置開始去尋找下一個距離最近的一個接口描述符或端點描述符。如果這個接口描述符后面還跟有class-或vendor-specific描述符,則find_next_descriptor的返回值會大于0,buffer的位置和size也要進行相應的調整,來指向新找到的接口描述符或端點描述符。
這里find_next_descriptor的dt1參數和dt2參數就不再一樣了,因為如果一個接口只用到端點0,它的接口描述符后邊兒是不會跟有端點描述符的。
62行,獲得這個設置使用的端點數目,然后將相應接口描述符里的bNumEndpoints置0,為什么?你要往下看。USB_MAXENDPOINTS在include/linux/usb.h里定義
#define USB_MAXENDPOINTS	30
為什么這個最大上限為30?前面也提到過,如果你不想頻繁的驀然回首那就簡單認為是協議里這么規定的好了。然后根據端點數為接口描述符里的endpoint數組申請內存。
81行,走到這里,buffer開頭兒的那個接口描述符已經理清了,而且也找到了下一個接口描述符或端點描述符的位置,該從這個新的位置開始解析了,于是又遇到了一個似曾相識的while循環。82行先判斷一下前面找到的是接口描述符還是端點描述符,如果是接口描述符就中斷這個while循環,返回與下一個接口描述符的距離。否則說明在buffer當前的位置上待著的是一個端點描述符,因此就要迎來另一個函數usb_parse_endpoint對面緊接著的數據進行解析。usb_parse_endpoint()返回的時候,buffer的位置已經在下一個端點描述符那里了,91行調整buffer的位置長度,這個while循環的也很明顯了,對buffer一段一段的解析,直到遇到下一個接口描述符或者已經走到buffer結尾。現在看看config.c里定義的usb_parse_endpoint函數
static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,int asnum, struct usb_host_interface *ifp, int num_ep,unsigned char *buffer, int size)
{unsigned char *buffer0 = buffer;struct usb_endpoint_descriptor *d;struct usb_host_endpoint *endpoint;int n, i, j, retval;d = (struct usb_endpoint_descriptor *) buffer;buffer += d->bLength;size -= d->bLength;if (d->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE)n = USB_DT_ENDPOINT_AUDIO_SIZE;else if (d->bLength >= USB_DT_ENDPOINT_SIZE)n = USB_DT_ENDPOINT_SIZE;else {dev_warn(ddev, "config %d interface %d altsetting %d has an ""invalid endpoint descriptor of length %d, skipping\n",cfgno, inum, asnum, d->bLength);goto skip_to_next_endpoint_or_interface_descriptor;}i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK;if (i >= 16 || i == 0) {dev_warn(ddev, "config %d interface %d altsetting %d has an ""invalid endpoint with address 0x%X, skipping\n",cfgno, inum, asnum, d->bEndpointAddress);goto skip_to_next_endpoint_or_interface_descriptor;}/* Only store as many endpoints as we have room for */if (ifp->desc.bNumEndpoints >= num_ep)goto skip_to_next_endpoint_or_interface_descriptor;endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];++ifp->desc.bNumEndpoints;memcpy(&endpoint->desc, d, n);INIT_LIST_HEAD(&endpoint->urb_list);/* Fix up bInterval values outside the legal range. Use 32 ms if no* proper value can be guessed. */i = 0;		/* i = min, j = max, n = default */j = 255;if (usb_endpoint_xfer_int(d)) {i = 1;switch (to_usb_device(ddev)->speed) {case USB_SPEED_SUPER:case USB_SPEED_HIGH:/* Many device manufacturers are using full-speed* bInterval values in high-speed interrupt endpoint* descriptors. Try to fix those and fall back to a* 32 ms default value otherwise. */n = fls(d->bInterval*8);if (n == 0)n = 9;	/* 32 ms = 2^(9-1) uframes */j = 16;/** Adjust bInterval for quirked devices.* This quirk fixes bIntervals reported in* linear microframes.*/if (to_usb_device(ddev)->quirks &USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL) {n = clamp(fls(d->bInterval), i, j);i = j = n;}break;default:		/* USB_SPEED_FULL or _LOW *//* For low-speed, 10 ms is the official minimum.* But some "overclocked" devices might want faster* polling so we'll allow it. */n = 32;break;}} else if (usb_endpoint_xfer_isoc(d)) {i = 1;j = 16;switch (to_usb_device(ddev)->speed) {case USB_SPEED_HIGH:n = 9;		/* 32 ms = 2^(9-1) uframes */break;default:		/* USB_SPEED_FULL */n = 6;		/* 32 ms = 2^(6-1) frames */break;}}if (d->bInterval < i || d->bInterval > j) {dev_warn(ddev, "config %d interface %d altsetting %d ""endpoint 0x%X has an invalid bInterval %d, ""changing to %d\n",cfgno, inum, asnum,d->bEndpointAddress, d->bInterval, n);endpoint->desc.bInterval = n;}/* Some buggy low-speed devices have Bulk endpoints, which is* explicitly forbidden by the USB spec.  In an attempt to make* them usable, we will try treating them as Interrupt endpoints.*/if (to_usb_device(ddev)->speed == USB_SPEED_LOW &&usb_endpoint_xfer_bulk(d)) {dev_warn(ddev, "config %d interface %d altsetting %d ""endpoint 0x%X is Bulk; changing to Interrupt\n",cfgno, inum, asnum, d->bEndpointAddress);endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;endpoint->desc.bInterval = 1;if (usb_endpoint_maxp(&endpoint->desc) > 8)endpoint->desc.wMaxPacketSize = cpu_to_le16(8);}/** Some buggy high speed devices have bulk endpoints using* maxpacket sizes other than 512.  High speed HCDs may not* be able to handle that particular bug, so let's warn...*/if (to_usb_device(ddev)->speed == USB_SPEED_HIGH&& usb_endpoint_xfer_bulk(d)) {unsigned maxp;maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;if (maxp != 512)dev_warn(ddev, "config %d interface %d altsetting %d ""bulk endpoint 0x%X has invalid maxpacket %d\n",cfgno, inum, asnum, d->bEndpointAddress,maxp);}/* Parse a possible SuperSpeed endpoint companion descriptor */if (to_usb_device(ddev)->speed == USB_SPEED_SUPER)usb_parse_ss_endpoint_companion(ddev, cfgno,inum, asnum, endpoint, buffer, size);/* Skip over any Class Specific or Vendor Specific descriptors;* find the next endpoint or interface descriptor */endpoint->extra = buffer;i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,USB_DT_INTERFACE, &n);endpoint->extralen = i;retval = buffer - buffer0 + i;if (n > 0)dev_dbg(ddev, "skipped %d descriptor%s after %s\n",n, plural(n), "endpoint");return retval;skip_to_next_endpoint_or_interface_descriptor:i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,USB_DT_INTERFACE, NULL);return buffer - buffer0 + i;
}
一個一個變態的函數看過來,到現在都已經麻木了。但是遇到這種函數,你誰都不能罵,對linus,對Greg,對Alan,你有的只能是崇敬。
10行,buffer開頭兒只能是一個端點描述符,所以這里將地址轉化為struct usb_endpoint_descriptor結構體指針,然后調整buffer的位置和size。
14行,這里要明白的是端點描述符與配置描述符、接口描述符不一樣,它是可能有兩種大小的。
25行,得到端點號。這里的端點號不能為0,因為端點0是沒有描述符的,也不能大于16,為什么?同樣如果你不想驀然回首,就當成協議里規定的吧。
34行,要知道這個bNumEndpoints在usb_parse_interface()的63行是被賦為0了的。
37行,要知道這個endpoint數組在usb_parse_interface()的74行也是已經申請好內存了的。從這里你應該明白bNumEndpoints是被當成了一個計數器,發現一個端點描述符,它就加1,并把找到的端點描述符copy到設置的endpoint數組里。
41行,初始化端點的urb隊列urb_list。
43~98行,這堆代碼的目的是處理端點的bInterval,你要想不被它們給忽悠了,得明白幾個問題。第一個就是,i,j,n分別表示什么。45~90這么多行就為了給它們選擇一個合適的值,i和j限定了bInterval的一個范圍,bInterval如果在這里邊兒,它就是合法的,如果超出了這個范圍,它就是非法的,就要修理修理它,像97行做的那樣將n賦給它,那么n表示的就是bInterval的一個默認值。i和j的默認值分別為0和255,也就是說合法的范圍默認是0~255,對于批量端點和控制端點,bInterval對你我來說并沒有太大的用處,不過協議里還是規定了,這個范圍只能為0~255。對于中斷端點和等時端點,bInterval表演的舞臺就很大了,對這個范圍也要做一些調整。
第二個問題就是如何判斷端點是中斷的還是等時的。這涉及到兩個函數usb_endpoint_xfer_int和usb_endpoint_xfer_isoc,它們都在include/uapi/linux/usb/ch9.h里定義
static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
{return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==USB_ENDPOINT_XFER_INT);
}
static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
{return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==USB_ENDPOINT_XFER_ISOC);
}
這倆函數so直白,一點都不含蓄,你根本不用去猜它們的心思就能明明白白了。一桌麻將還差兩個,另外兩個就是usb_endpoint_xfer_bulk和usb_endpoint_xfer_control,用來判斷批量端點和控制端點的。
第三個問題是to_usb_device。usb_parse_endpoint()的參數是struct device結構體,要獲得設備的速度就需要使用to_usb_device將它轉化為struct usb_device結構體,這是個include/linux/usb.h里定義的宏
#define	to_usb_device(d) container_of(d, struct usb_device, dev)
OK,接著繼續看usb_parse_endpoint的139行,現在你對這幾行玩的把戲應該很明白了。這里接著在buffer里尋找下一個端點描述符或者接口描述符。

經過usb_parse_configuration、usb_parse_interface和usb_parse_endpoint這三個函數一步一營的層層推進,通過GET_DESCRIPTOR請求所獲得那堆數據現在已經解析的清清白白。現在,設備的各個配置信息已經了然于胸,那接下來設備的那條生命線該怎么去走?它已經可以進入Configured狀態了么?事情沒這么簡單,光是獲得設備各個配置信息沒用,要進入Configured狀態,你還得有選擇有目的有步驟有計劃的去配置設備,那怎么去有選擇有目的有步驟有計劃?這好像就不是core能夠答復的問題了,畢竟它并不知道你希望你的設備采用哪種配置,只有你的設備的驅動才知道,所以接下來設備要做的是去在設備模型的茫茫人海中尋找屬于自己的驅動。
做為一個負責任的男人,絕對不能忘記的是設備的那個struct usb_device結構體在出生的時候就帶有usb_bus_type和usb_device_type這樣的胎記,Linux設備模型根據總線類型usb_bus_type將設備添加到usb總線的那條有名的設備鏈表里,然后去輪詢usb總線的另外一條有名的驅動鏈表,針對每個找到的驅動去調用usb總線的match函數,也就是usb_device_match(),去為設備尋找另一個匹配的半圓。match函數會根據設備的自身條件和類型usb_device_type安排設備走設備那條路,從而匹配到那個對所有usb_device_type類型的設備都來者不拒的花心大蘿卜,usb世界里唯一的那個usb設備驅動(不是usb接口驅動)struct device_driver結構體對象usb_generic_driver。

總結

以上是生活随笔為你收集整理的Linux那些事儿 之 戏说USB(28)设备的生命线(十一)的全部內容,希望文章能夠幫你解決所遇到的問題。

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

在线视频久久 | 激情www | 国产黄色精品视频 | 日韩精品最新在线观看 | 91爱爱免费观看 | 欧美日韩一区二区三区在线免费观看 | 亚色视频在线观看 | 韩国一区在线 | 亚洲国产69 | 91成人黄色 | 国产精品视频在线观看 | 国产精品一区二 | 美女国产免费 | 欧美韩国在线 | 国产精品亚洲片在线播放 | 国产123区在线观看 国产精品麻豆91 | 久草线| 九七视频在线观看 | 成人午夜久久 | 粉嫩高清一区二区三区 | 久久精品电影网 | 久草久| 午夜精品视频在线 | 久久视频这里有精品 | 天干啦夜天干天干在线线 | 中文一区二区三区在线观看 | 日韩经典一区二区三区 | 久久99婷婷 | 久久亚洲日本 | 日本精品视频在线播放 | 日本久草电影 | 不卡国产视频 | 欧美色就是色 | 天堂av在线7 | 欧美日韩国产色综合一二三四 | 91精品视频免费观看 | 色婷婷国产在线 | 99热国产在线 | 五月天天在线 | 中文字幕日本特黄aa毛片 | 久久精品国产亚洲aⅴ | 久久图| 天天艹日日干 | 日韩久久久 | 处女av在线| av电影在线播放 | 亚洲国产剧情av | 亚洲三级国产 | 丁香婷婷深情五月亚洲 | 成人国产亚洲 | 中文字幕婷婷 | 人人澡视频 | 国产精品久久久久久吹潮天美传媒 | 亚洲国产成人久久综合 | 欧美日韩一区二区在线观看 | 国产精品va在线播放 | 中文字幕免费高 | 国产精品网址在线观看 | 亚洲免费在线 | 久久精品伊人 | 婷婷丁香av | 日韩毛片在线一区二区毛片 | 91天堂在线观看 | 日本中文字幕在线播放 | 超碰在线97观看 | 91精品视频免费看 | 中文字幕成人在线 | 亚洲男男gaygayxxxgv | 成人黄色国产 | 在线观看日韩av | 午夜精品婷婷 | 婷婷丁香五 | 国产精品久久久久久久久费观看 | 国产又粗又猛又黄视频 | 免费观看全黄做爰大片国产 | 天天射天天射天天射 | 亚洲精品男人天堂 | 欧美日韩视频在线播放 | 亚洲午夜久久久久久久久电影网 | 国产中文 | 天天操夜夜操夜夜操 | 亚洲一区二区三区精品在线观看 | 免费网站v | 99久久精| 中文字幕综合在线 | 午夜国产福利在线 | 欧美精品久久人人躁人人爽 | 亚洲最大成人网4388xx | 国产精品视频不卡 | 精品欧美一区二区三区久久久 | 国产精品9区 | 97狠狠干 | 日韩在线第一区 | 九色免费视频 | av中文字幕剧情 | 天天色影院 | 天天操天天谢 | 在线国产精品一区 | 成人午夜毛片 | 91精品国产成人观看 | 国产打女人屁股调教97 | 国产不卡一区二区视频 | 亚洲视频分类 | 亚洲欧美怡红院 | 久操操 | 欧美 亚洲 另类 激情 另类 | 国产中文在线观看 | 国产精品九九久久久久久久 | 91在线小视频 | 日本最新一区二区三区 | 国产你懂的在线 | 色是在线视频 | 日本中文在线播放 | 亚洲综合欧美日韩狠狠色 | 国产欧美最新羞羞视频在线观看 | 97超碰在线资源 | 99久久婷婷国产综合亚洲 | 在线看的毛片 | 色香蕉网 | 黄色av电影一级片 | 国产精品久久久久久久久久久免费看 | 日韩中文字幕免费视频 | 在线v| 成人午夜电影网 | 日韩免费电影一区二区 | 午夜美女视频 | 天天看天天干 | 亚洲激情久久 | 欧美午夜性生活 | 国产视频二区三区 | 国产精品一区二区三区免费看 | 国产精品日韩欧美一区二区 | 免费视频 三区 | 日韩av一区二区三区四区 | 国产一区二区免费看 | 碰超在线| 97国产大学生情侣酒店的特点 | 五月开心婷婷 | 99久久久国产精品美女 | 日韩特黄av | 精品国产免费一区二区三区五区 | 五月天久久精品 | 在线看v片成人 | 亚洲免费在线看 | 成年人电影免费看 | 久久91久久久久麻豆精品 | 久久伊99综合婷婷久久伊 | 日韩精品免费在线 | 夜夜视频欧洲 | 久久夜色精品亚洲噜噜国4 午夜视频在线观看欧美 | 在线观影网站 | 91麻豆视频 | 国产一级片直播 | 中文字幕乱码日本亚洲一区二区 | 在线精品视频免费播放 | 久久ww | 国内精品在线观看视频 | 成人精品在线 | 成人毛片一区二区三区 | 国产精品久久久久久久免费观看 | 久草网在线视频 | 亚洲成人av在线电影 | 久久开心激情 | 中文字幕五区 | 久久公开视频 | 狠狠色噜噜狠狠 | 久久午夜免费观看 | 亚洲乱码在线 | 国产香蕉97碰碰碰视频在线观看 | 2021久久| 麻豆国产精品视频 | 色999精品 | 黄色av高清 | 超碰av在线| a在线免费 | 精品夜夜嗨av一区二区三区 | 伊在线视频 | 国产成人高清av | 91成人网在线播放 | 日日日日| 久久精品屋 | 999久久久欧美日韩黑人 | 色就是色综合 | 综合天天色 | 九九九视频在线 | 激情影音先锋 | 天堂av在线免费 | 日韩精品亚洲专区在线观看 | 国产玖玖精品视频 | av黄色在线观看 | 婷婷综合网 | 婷婷av电影 | 日韩免费电影网站 | 色婷婷婷 | 日本中文字幕网 | 成人av在线看 | 欧美一级免费黄色片 | 中文字幕在线观看91 | 国产91影院| 久久久久久久久久久久亚洲 | 国产精品专区在线 | 国产成人精品av在线观 | 成年人免费电影在线观看 | 国产夫妻性生活自拍 | 米奇狠狠狠888| 久久综合九色综合网站 | 国产精品99久久久久久久久久久久 | 国产在线成人 | 国产无套精品久久久久久 | 91日本在线播放 | 女人18片 | 免费福利小视频 | av再线观看 | 婷婷丁香国产 | 日韩天堂在线观看 | 久久人人爽爽人人爽人人片av | 成年免费在线视频 | 成人资源在线观看 | 国产日韩欧美在线播放 | 国产精品日韩 | 日韩在线视频网 | 精品在线观 | 在线观看成人福利 | 国产精品成人免费一区久久羞羞 | 久艹在线免费观看 | 天天综合久久综合 | 日本色小说视频 | 99精品亚洲 | 99色婷婷| 中文字幕一区二区三区视频 | 国产亚洲高清视频 | 天天草天天草 | 国产精品久久久久久久久久久久久久 | 亚洲欧洲国产精品 | 日韩av一区二区在线播放 | 国产精品久久久久久999 | .国产精品成人自产拍在线观看6 | 综合激情 | 亚洲精品免费在线观看视频 | 久久草网站 | 日韩免费视频 | 精品视频成人 | 国产vs久久| 91精品国产九九九久久久亚洲 | 91香蕉视频在线下载 | 中文字幕高清免费日韩视频在线 | 国产日本高清 | 欧美激情精品久久久久久 | 久久婷婷国产色一区二区三区 | 国产午夜不卡 | 黄色小说视频在线 | 国产精品乱码高清在线看 | 中文伊人 | 婷婷国产在线观看 | 一 级 黄 色 片免费看的 | 一个色综合网站 | 色噜噜噜噜| 国产精品久久久久久爽爽爽 | 久久国产精品99国产精 | 欧美日韩一区二区三区免费视频 | 国产v在线| 色综合 久久精品 | 免费在线一区二区 | 国产欧美高清 | av免费成人 | 婷婷视频在线观看 | 俺要去色综合狠狠 | 午夜国产福利视频 | 亚洲成人二区 | 亚洲精品免费在线 | 久草视频免费播放 | 91大神免费视频 | 在线观看国产区 | 日批视频 | 天天操人人要 | 日韩在线视频网 | av电影免费在线看 | 精品你懂的 | 天天躁日日躁狠狠躁av中文 | 色在线免费 | 超碰在线观看97 | 欧美精品一区二区三区四区在线 | 欧美另类v | 免费国产在线精品 | 国产精品色| 99国产精品久久久久久久久久 | 日韩大片免费观看 | 久久草视频 | 国产精品久久99综合免费观看尤物 | 一级片免费观看视频 | 欧美另类一二三四区 | 国产视频2区 | 天天爱天天 | 99资源网| 在线观看视频你懂得 | 免费试看一区 | 黄色毛片一级 | 久久免费试看 | 波多野结衣一区二区三区中文字幕 | 久热这里有精品 | 91精品国产麻豆 | 国产亚洲精品福利 | 高清不卡免费视频 | 伊人黄| 97人人模人人爽人人少妇 | 欧美日韩国产精品一区二区三区 | 国产 中文 日韩 欧美 | 久久久久久久久久久久久久av | 六月丁香在线观看 | 香蕉视频国产在线观看 | 国产精品久久久久久久久久免费 | 国产高清 不卡 | 精品久久久久久久久久国产 | 91免费视频网站在线观看 | 成人黄色大片 | 亚洲精品午夜视频 | 最新av在线网站 | 精品久久久久久国产91 | 天天插天天干天天操 | 天天操天| 涩涩网站免费 | 国产精品一区二区白浆 | 九九在线免费视频 | 久久精品视频网站 | 怡春院av | 亚洲精品88欧美一区二区 | 黄色www| 三级a毛片 | 又色又爽的网站 | 免费观看全黄做爰大片国产 | 干干夜夜 | 97在线观看视频免费 | 在线国产中文字幕 | 天天射日 | 在线观看av黄色 | a精品视频| 国产精品免费人成网站 | 婷婷在线综合 | 亚洲永久av | 深夜免费福利 | 欧美一级黄大片 | 国产精品成人一区二区 | 黄色的视频 | 黄色在线视频网址 | 欧美日韩一区二区免费在线观看 | 久久 国产一区 | 精品亚洲免费 | 婷婷色五 | 亚洲国产日韩欧美在线 | 懂色av懂色av粉嫩av分享吧 | 久久精品国产精品 | 99久久精品日本一区二区免费 | 国产成人精品免高潮在线观看 | 91精品国产99久久久久 | 丁香婷婷久久 | 婷婷伊人综合亚洲综合网 | 免费av免费观看 | 日韩一区在线播放 | 麻豆传媒视频在线免费观看 | 四虎影视成人永久免费观看亚洲欧美 | 美腿丝袜一区二区三区 | 最近高清中文字幕在线国语5 | 麻豆一区二区三区视频 | 中文av在线播放 | 婷婷午夜天 | 在线最新av | 国内精品视频在线 | 久久午夜色播影院免费高清 | 中文字幕欧美日韩va免费视频 | 日韩电影久久 | 精品久久一区二区三区 | 免费看国产一级片 | 久久久久女人精品毛片九一 | 99c视频高清免费观看 | 96亚洲精品久久 | 国产黄视频在线观看 | 五月网婷婷 | 久久免费试看 | 尤物97国产精品久久精品国产 | 91视频 - v11av | 在线亚洲成人 | 国产精品视频免费 | 99热精品在线观看 | 久久精品看片 | 热久久99这里有精品 | 国产成人精品久久久久蜜臀 | 欧美另类xxxxx | 麻豆视传媒官网免费观看 | 99re久久资源最新地址 | 国产精品成人在线 | 国产精品99久久久久 | 国产极品尤物在线 | 丁香九月婷婷综合 | 国产精品一区二区视频 | 国产黄av | 精品一区二区在线免费观看 | 国产精品毛片久久 | 久久久久久久久久久久国产精品 | 在线观看 亚洲 | 国产二区视频在线观看 | 99精品欧美一区二区三区 | 99精品在线免费观看 | 波多野结衣亚洲一区二区 | av在线网站观看 | 日本在线观看中文字幕 | 一区二区精品在线观看 | 天天干 天天摸 天天操 | 国产精品一区二区麻豆 | 亚洲黄色网络 | 国色天香永久免费 | 综合久久网| 欧美激情综合色综合啪啪五月 | 五月天婷婷在线播放 | 国产精品1区2区3区 久久免费视频7 | 免费成人看片 | 天堂av在线7 | 久久久精品国产免费观看一区二区 | 久久五月婷婷丁香社区 | 欧美少妇xxxxxx| 五月天激情视频在线观看 | 激情婷婷在线 | 人成午夜视频 | 四虎永久国产精品 | 国产婷婷 | 丁香婷婷久久 | 丁香综合激情 | 亚洲无吗天堂 | 91看片在线播放 | 91丨九色丨国产在线观看 | 91麻豆精品国产91久久久久 | 久久这里只精品 | a午夜在线| 麻豆国产在线视频 | 午夜精品福利一区二区三区蜜桃 | 日韩欧美在线观看一区二区 | 啪啪小视频网站 | 天堂va在线高清一区 | 日韩精品在线观看视频 | 九九久久久久久久久激情 | 国产毛片久久 | 999国产在线 | www.久久久精品 | 成人午夜电影网站 | 日本久久久久久 | 91毛片在线观看 | 337p日本欧洲亚洲大胆裸体艺术 | 狠狠狠狠狠狠 | 91视视频在线直接观看在线看网页在线看 | 日韩在线电影一区 | 成年人视频免费在线 | 免费的国产精品 | 中文字幕在线一二 | 国产成人精品网站 | 婷婷日 | 久久久精品国产一区二区三区 | 午夜狠狠干 | 免费欧美 | 日本在线中文在线 | 免费观看黄 | 五月天堂色 | 亚洲国产天堂av | 免费av试看 | 天天干天天干天天干 | 97超碰在线久草超碰在线观看 | 国产精品中文字幕av | 青春草免费视频 | 国产精品久久久久aaaa九色 | 人人爱夜夜操 | 99久久99久久 | 精品人人爽| 丝袜av网站| 91在线观看视频 | 韩国精品在线 | 丁香久久综合 | 天天操人人要 | 干亚洲少妇 | 伊人丁香| 久久久香蕉视频 | 黄色小说18 | 91自拍视频在线观看 | 婷婷色网址 | 久久一区二区免费视频 | 2020天天干夜夜爽 | 中文字幕在线不卡国产视频 | 毛片久久久 | 日韩簧片在线观看 | 色偷偷88欧美精品久久久 | 丰满少妇麻豆av | 天天躁日日躁狠狠躁av中文 | 成人毛片在线观看 | 国产综合小视频 | 免费在线观看成人小视频 | 一区二区精品在线视频 | 丁香花中文在线免费观看 | 日韩电影在线观看中文字幕 | 9797在线看片亚洲精品 | 国产精品永久 | 婷婷色狠狠 | 欧美日韩观看 | 69国产在线观看 | 日韩视频www | 91精品视频免费在线观看 | 一区二区三区韩国免费中文网站 | www黄色com| 日韩免费视频线观看 | 91精品在线免费观看视频 | 九色激情网 | 欧美日韩精品区 | 黄色片网站大全 | 99久久99视频 | av成人免费 | 深夜免费福利视频 | 国内精品久久久久久久97牛牛 | 干狠狠| 国产视频2 | 中文字幕色在线 | 国产亚洲精品久久久久秋 | 中文字幕av免费在线观看 | 国产精品精品久久久 | 最新中文字幕 | 免费福利视频网站 | av噜噜噜在线播放 | 欧美在线视频不卡 | 欧美一级在线观看视频 | 国产在线97 | 日韩区欧美久久久无人区 | 亚洲 欧洲 国产 日本 综合 | 亚洲好视频 | 久久久人人人 | 韩国av电影在线观看 | 国产精品永久久久久久久久久 | 中文字幕欲求不满 | 久久免费国产精品 | www日韩精品 | 成年人视频免费在线 | 夜夜高潮夜夜爽国产伦精品 | 在线观看国产麻豆 | 婷婷六月中文字幕 | www.久久视频 | 久久精品国产99国产 | 又污又黄的网站 | 天天天色综合 | 国内精品久久久久久 | 91中文视频 | 人人看黄色 | 日韩网站在线看片你懂的 | 亚洲专区路线二 | 色综久久 | 色婷久久 | 欧美日韩亚洲在线观看 | 国产日韩视频在线观看 | 99久久精品免费 | 天天干,天天操,天天射 | 9999在线视频 | 青青草国产在线 | 国产一二区视频 | 激情五月在线视频 | 不卡中文字幕在线 | 国产精品理论片 | 天天综合网 天天 | 久草视频中文 | 五月婷婷视频在线观看 | 99草视频| 久久久久久久久影视 | 97国产一区二区 | 在线成人欧美 | 国产一区二区免费看 | av大片免费在线观看 | 国产网站av| 国产无套精品久久久久久 | 91污污 | 久久精品久久99精品久久 | 一区二区三区电影在线播 | 久久久国产一区二区三区四区小说 | av免费电影在线 | 91在线免费视频 | 日韩av电影中文字幕在线观看 | aaaaaa毛片| 精品久久电影 | 天天操综| 四虎国产精品成人免费4hu | 日韩视 | 99热只有精品在线观看 | 激情欧美丁香 | 亚州av免费 | 免费在线观看av的网站 | 中文字幕文字幕一区二区 | 欧美性高跟鞋xxxxhd | 久久久久久久久久久网 | 深爱婷婷 | 欧美成人区 | 色视频网站免费观看 | 日韩r级电影在线观看 | 激情综合五月天 | 在线电影播放 | 久久久在线 | 久久久av免费 | 亚洲视频第一页 | 亚洲最快最全在线视频 | 国产一区在线视频播放 | 黄色小网站免费看 | 欧美亚洲另类在线视频 | 香蕉在线视频观看 | 国产日韩高清在线 | 久草视频一区 | 色婷婷av一区 | 福利网在线| 黄色avwww| 欧美了一区在线观看 | 精品国产一区二区三区av性色 | 日韩中文字幕在线看 | 亚洲人xxx | 成人av一二三区 | 91最新网址 | 亚洲综合色站 | 五月开心婷婷网 | 亚洲欧洲精品一区二区精品久久久 | 日本视频不卡 | 激情综合啪啪 | 97超碰人人爱 | 国产精品一区在线播放 | 久久日本视频 | 日韩免费视频一区二区 | 国产视频中文字幕在线观看 | 美女视频黄,久久 | 国产专区欧美专区 | 中文字幕精品一区 | 亚洲国产一区二区精品专区 | 在线天堂日本 | 就要色综合 | 日韩网站免费观看 | 黄色国产成人 | 日韩三级视频在线观看 | 一区二区视频电影在线观看 | 亚洲视屏在线播放 | 欧美成年黄网站色视频 | 欧美高清视频不卡网 | 国产 一区二区三区 在线 | av片一区二区| 国产精品欧美一区二区 | 福利视频 | 色婷婷伊人 | 国产97在线播放 | 色全色在线资源网 | 黄色福利网站 | 91av色 | 成年人在线播放视频 | 美女视频黄免费网站 | 91在线影院| 天天人人 | 久久久这里有精品 | 久久免费福利视频 | 美女视频黄免费 | 国产毛片久久 | 日本成人中文字幕在线观看 | 五月婷婷丁香色 | 嫩嫩影院理论片 | 久久精视频| 久久小视频 | 西西4444www大胆艺术 | 欧美日韩综合在线 | 玖玖玖影院 | 丁香5月婷婷 | 欧美精选一区二区三区 | 午夜av电影| 黄色av一区二区三区 | 日本精品视频免费观看 | 香蕉影院在线播放 | 久久艹欧美| 国产精品va | 欧洲激情综合 | 97小视频| 国产精品欧美激情在线观看 | 欧美一级片在线 | 91在线日本 | 成人免费 在线播放 | 天天色成人 | 中文字幕国产视频 | 免费裸体视频网 | 中文字幕五区 | 黄色91在线观看 | 久久免费看av | 国产精品视频资源 | 国产综合片 | 国产高清不卡 | 亚洲三级网 | 亚洲国产精品人久久电影 | 亚洲www天堂com| 日韩动漫免费观看高清完整版在线观看 | 久久tv视频 | 国产99黄| 欧美巨乳波霸 | 99久久精品国产系列 | 91免费在线看片 | 久久综合狠狠综合久久综合88 | 国产99色| 91视频在线免费看 | 日韩啪啪小视频 | 在线观看的av | 在线观看国产日韩欧美 | 日本中文字幕在线一区 | 国产成人61精品免费看片 | 在线观看黄 | 午夜黄色影院 | 久久久久久久久久影视 | 日韩a在线播放 | 国产一区久久久 | 狠狠躁18三区二区一区ai明星 | 久爱精品在线 | 玖玖在线观看视频 | 一区免费视频 | 蜜臀av夜夜澡人人爽人人 | 精品夜夜嗨av一区二区三区 | 超碰97国产在线 | 奇米影视777四色米奇影院 | 亚洲成人黄色av | 日本三级中文字幕在线观看 | 国产麻豆电影在线观看 | 99精品欧美一区二区三区黑人哦 | 91在线操 | 国产成人精品女人久久久 | 天天射天天干天天操 | 亚洲精品2区 | 国产一级a毛片视频爆浆 | 伊人天堂av| 国产色道 | 欧美二区三区91 | 久久欧洲视频 | 伊人五月天.com| www.国产在线视频 | 亚洲日本成人网 | 综合久久久久久 | wwwwww色 | 日本最新中文字幕 | 亚洲精品国产精品国自产在线 | www99精品 | 久久久久成人精品 | 天天操天天干天天玩 | 一区二区理论片 | 久久成人欧美 | 亚洲视频axxx| 免费观看一级特黄欧美大片 | 久久久精选 | 一区二区三区在线免费观看视频 | 免费看的黄色录像 | 免费av的网站| 欧美成人免费在线 | 午夜精品久久久久久久99无限制 | 成人黄色av网站 | 色在线高清 | 久久在线精品视频 | av在线免费播放网站 | 久久国产精品精品国产色婷婷 | 国产在线色视频 | 日韩欧美一级二级 | 天天爽天天爽天天爽 | 国产精品高清免费在线观看 | 麻豆影视网站 | 激情五月在线观看 | 国产精品国产精品 | 欧美日韩视频一区二区三区 | 一级做a爱片性色毛片www | 精品成人a区在线观看 | 天天干天天射天天爽 | 草久在线观看视频 | 日韩乱码在线 | 国产男女无遮挡猛进猛出在线观看 | 草久视频在线观看 | 亚洲色图色 | 开心激情五月婷婷 | 亚洲精品视频在线看 | 午夜影院一级片 | 日韩在线观看 | 亚洲高清在线视频 | 成年人免费av网站 | 香蕉精品视频在线观看 | 免费av免费观看 | 国产 视频 久久 | 成人av在线直播 | 玖玖视频在线 | 国产成人亚洲在线观看 | 五月婷香蕉久色在线看 | 欧美久久综合 | 五月婷亚洲 | 国产中文字幕视频在线观看 | 狠狠色噜噜狠狠狠 | 国产精品午夜在线观看 | 久久免费视频99 | 欧美-第1页-屁屁影院 | 91最新在线观看 | 亚洲精品88欧美一区二区 | 日韩精品你懂的 | 精品高清美女精品国产区 | 美女视频黄频 | 婷婷五月在线视频 | 九九视频免费在线观看 | 中文字幕一区二区在线观看 | 在线观看91精品国产网站 | 日韩欧美99 | 日韩欧美高清 | 黄色a在线 | 九色精品 | 久久69精品 | 中文字幕电影高清在线观看 | 久草在线手机视频 | 日本女人逼 | 91精品国产综合久久婷婷香蕉 | 日韩在线观看电影 | 亚洲高清在线视频 | 91在线免费看片 | 天天操天天操天天操天天操天天操天天操 | 久久黄视频 | 黄色片亚洲 | 六月丁香综合网 | 精品五月天 | 婷婷九九| 91视频最新网址 | 国产无套视频 | 亚洲精品在线观看不卡 | 久久激情小视频 | 日韩在线精品视频 | 97视频在线观看网址 | 最新av在线网址 | www久久com | 伊人手机在线 | 波多野结衣在线播放视频 | 久久激情婷婷 | 久久理论视频 | 97中文字幕 | 视频一区二区视频 | 人人插人人插 | 欧美老女人xx | 国产成人免费av电影 | 日日夜夜天天久久 | 国产特级毛片aaaaaa毛片 | 日韩高清一二区 | 中文字幕人成不卡一区 | 97av在线视频免费播放 | 国产 日韩 欧美 自拍 | 亚洲精品tv| 久久九九影院 | 国产精品爽爽爽 | 免费精品国产 | 日韩电影在线观看一区二区三区 | 91麻豆精品国产自产在线 | 精品一区91| 国产v视频 | 国产精品亚 | 美女一二三区 | 四虎www. | 国产一级一片免费播放放 | www.夜夜操 | 麻豆91在线观看 | 久久资源总站 | 久久久这里有精品 | 黄色三级av | 久久这里只有精品23 | 中文字幕色网站 | 99爱视频 | 综合久久五月天 | 欧美男同网站 | 亚洲久草网 | 福利一区视频 | 国产精品99久久久 | 国产99久久久久久免费看 | 久久在线免费 | 狠狠狠色丁香综合久久天下网 | 欧美日本在线观看视频 | 亚洲二区精品 | 欧美在线观看视频一区二区三区 | 亚洲人成精品久久久久 | 国产视频资源 | 丁香婷婷网 | 国产剧情在线一区 | 国产精品久久久久久久免费观看 | 视频91| 日韩电影在线观看一区 | 国产精品国产三级国产aⅴ入口 | 操操操人人人 | 久久婷婷五月综合色丁香 | 人人插人人 | 色偷偷888欧美精品久久久 | 91亚洲精| 国产精品网在线观看 | 99精品久久久久久久久久综合 | 国产成人免费精品 | 天天干天天干天天 | 久久久久成人精品免费播放动漫 | 亚洲精品一区二区久 | 国产高清免费视频 | 久久视频精品在线 | 日本中文字幕系列 | 免费观看v片在线观看 | 欧美日韩91| 精品国产1区2区 | 午夜视频一区二区 | 久久久免费看 | 国产夫妻性生活自拍 | 免费av福利 | 精品国产一区二区三区久久久 | 欧美特一级片 | 欧美在线视频一区二区三区 | 欧日韩在线视频 | 中文字幕在线专区 | 黄色视屏在线免费观看 | 欧美性一级观看 | 国产香蕉视频在线观看 | 亚洲伦理电影在线 | 国产亚洲综合精品 | 1000部国产精品成人观看 | 国产 精品 资源 | 97日日 | 18网站在线观看 | 日日夜夜精品网站 | 国产精品久久电影网 | 天天色 天天 | 亚洲精品乱码久久久久 | 97精品国产97久久久久久 | 欧美性色黄大片在线观看 | 久久桃花网 | 久久免费视频5 | 色哟哟国产精品 | 在线激情影院一区 | 免费一级片在线观看 | a久久久久久 | 日韩一区在线播放 | 亚洲一区日韩精品 | 日韩久久午夜一级啪啪 | 99色亚洲| 日本少妇视频 | 午夜精品视频在线 | 欧美综合在线观看 | 成人免费在线播放视频 | 91高清在线看 | 国产精品久久久久aaaa九色 | 日日夜夜免费精品视频 | 日韩av有码在线 | 国产精品一区二区精品视频免费看 | 国产精品手机看片 | 久久综合狠狠综合久久激情 | 激情文学综合丁香 | 午夜视频在线观看一区二区三区 | 亚州国产精品 | 亚洲欧美日韩不卡 | 欧美最猛性xxxxx亚洲精品 | 国产一区91| 在线免费色 | 国产区av在线| 欧美热久久 | av在线看网站 | 亚洲一区二区三区四区在线视频 | 亚洲精品av在线 | 欧美日韩久 | 日韩精品视频免费在线观看 | 在线精品观看国产 | 国产精品久久久久久模特 | 国产一级黄色av | 日日夜夜精品免费 | 欧美成人91 | 九九久久国产精品 | 久草9视频| av在线电影网站 | 成 人 免费 黄 色 视频 | 国产精品午夜在线观看 | 西西444www大胆高清图片 | 国产亚洲精品久久久网站好莱 | 99免费观看视频 | av福利在线看 | 欧美激情精品久久久 | 六月婷色 | 波多野结衣在线观看一区 | 国产在线视频资源 | 久久理论片 | 亚洲一级片av | 在线观看视频亚洲 | 五月婷婷一级片 | 人人干天天干 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 黄色av网站在线观看 | www.黄色片.com | 久久99久久99精品免观看粉嫩 | av成人免费在线观看 | 亚洲第一中文字幕 | 一区二区在线影院 | 天天色天天射综合网 | 成人av免费在线 | 日本老少交| 99久久久久免费精品国产 | 久久国产精品色婷婷 | 国产成人精品一区二三区 | 欧美热久久 | 国产网红在线 | 在线观看中文字幕dvd播放 | 丁香婷婷综合激情 | 天天综合导航 | 婷婷色婷婷 | av在线播放网址 | 国产精品丝袜在线 |