日韩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)设备的生命线(十一)的全部內容,希望文章能夠幫你解決所遇到的問題。

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

亚洲精品国产精品国自产观看 | 免费观看十分钟 | 在线观看黄a | 国产精品久久久久久久久婷婷 | 在线观看一区二区视频 | 丁香综合激情 | 国产精品白丝jk白祙 | 99国产在线视频 | 五月婷丁香 | zzijzzij亚洲日本少妇熟睡 | 一级黄色片在线播放 | 激情五月激情综合网 | 中文字幕在线观看网站 | 国内精品久久久久久 | 免费成人在线网站 | 国产一区二区三区免费在线观看 | 色婷婷狠狠干 | 午夜一级免费电影 | 日韩 精品 一区 国产 麻豆 | 一区二区在线影院 | 亚洲理论在线观看电影 | 日日狠狠| 成人免费影院 | 国产精品久久久久久久久久久久午夜片 | 麻豆国产在线视频 | 五月天综合婷婷 | 日韩网站在线 | 久久不卡国产精品一区二区 | 亚洲第一区在线播放 | 欧美一级艳片视频免费观看 | 亚洲精品视频大全 | 99久久99久久精品国产片果冰 | 中文字幕在线播放日韩 | 91精品一区在线观看 | 99热99热 | 三级黄色a | 91亚洲激情 | 国产精品99久久久久久久久久久久 | 狠狠天天 | 日韩中文字幕一区 | 狠狠色丁香婷婷综合 | 91一区啪爱嗯打偷拍欧美 | 中文在线免费一区三区 | 91精品爽啪蜜夜国产在线播放 | 五月婷婷视频在线 | 国产资源精品在线观看 | 视频在线观看亚洲 | 亚洲最新在线视频 | 在线视频日韩欧美 | 国产精品自在线拍国产 | 九九九免费视频 | 99爱在线 | 成人试看120秒 | 国产专区在线视频 | 国产精品久久一 | 日韩在线短视频 | 成人av免费在线看 | 99久久久久久久久 | 香蕉视频网址 | 五月开心激情网 | 国产成人久久久77777 | 中文字幕视频免费观看 | 免费观看av | 特黄特色特刺激视频免费播放 | 激情五月在线观看 | 国产精品久久久精品 | 午夜视频在线观看一区二区 | 99色在线观看 | 国产一区二区三区免费视频 | 国产欧美高清 | 亚洲成人精品av | 午夜影视剧场 | 国产一区二区网址 | 久久精品官网 | 国产精品久久一区二区三区不卡 | 欧美视频日韩视频 | 国语精品免费视频 | 日韩精品免费在线视频 | 国产精品精品久久久久久 | 天天操天天操天天操天天操天天操 | 天天躁日日躁狠狠躁 | 精品久久久久_ | 97视频成人| 国产亚洲精品精品精品 | 久久福利影视 | 国产成人一区二区三区在线观看 | 免费在线黄 | www.玖玖玖 | 国产一在线精品一区在线观看 | 韩国一区在线 | 国产精品96久久久久久吹潮 | 99久久日韩精品视频免费在线观看 | 国产成人三级在线 | 黄色软件视频大全免费下载 | 欧美精品久久天天躁 | 在线观看亚洲国产精品 | 欧美日本一二三 | 国产免费观看高清完整版 | 狠狠躁日日躁狂躁夜夜躁av | 天堂av影院 | 天天色天天操天天爽 | 97av色| 久久乱码卡一卡2卡三卡四 五月婷婷久 | 免费看日韩 | 在线观看免费av网 | 91天堂影院 | 国产真实精品久久二三区 | 天天干天天做天天爱 | 久久久三级视频 | 亚洲高清视频在线观看 | 国产v在线 | 热久久影视 | 日韩欧美一区二区在线播放 | 久久免费在线观看 | 9999精品 | 亚洲三级黄色 | 在线导航av | 江苏妇搡bbbb搡bbbb | 成人精品电影 | 综合网天天色 | 国产日产在线观看 | 99精品在线播放 | 久久激情视频免费观看 | 成人国产亚洲 | 免费看的黄色片 | 一 级 黄 色 片免费看的 | 国产精品99久久久久久有的能看 | 超碰人人91 | 日韩免费一级a毛片在线播放一级 | 特级西西人体444是什么意思 | 韩国三级av在线 | 婷婷成人亚洲综合国产xv88 | 亚洲精品视频二区 | 依人成人综合网 | 2020天天干夜夜爽 | 国产污视频在线观看 | 成人a免费视频 | 国产一区二区精品 | 日韩视| 黄色大片av | 日韩视频在线观看视频 | 中文字幕免费高清在线 | av一本久道久久波多野结衣 | 欧美性生活小视频 | 成人久久18免费 | 韩日电影在线免费看 | 午夜精品一区二区三区在线观看 | 国产永久免费高清在线观看视频 | 精品国产伦一区二区三区 | 美女视频免费一区二区 | 狠狠狠狠干 | 免费看日韩 | 亚洲精品电影在线 | 国产精品久久久久永久免费 | 美腿丝袜av | 精品黄色视 | 中文字幕av在线免费 | 久久综合网色—综合色88 | 91精品国产自产在线观看 | 日韩av免费在线电影 | 国产成人福利在线观看 | 国产一区在线观看免费 | 91tv国产成人福利 | 日韩国产欧美在线视频 | 日韩经典一区二区三区 | 最新av免费在线 | 天天摸夜夜操 | 成年人看片网站 | 在线观看日本高清mv视频 | 亚洲精品伦理在线 | 91av在线免费播放 | 米奇四色影视 | 69热国产视频 | 中文字幕av免费观看 | 久久激情五月丁香伊人 | 日韩成人精品 | 一区二区男女 | 免费高清在线观看成人 | www.午夜视频 | 久久精品视频免费观看 | 一区久久久 | 成年人视频在线免费播放 | 黄色资源在线观看 | 免费a v视频 | 久草精品视频在线看网站免费 | 国产精品99久久免费黑人 | 在线看不卡av | 成人黄色在线 | 国产一区在线观看免费 | 亚洲一级黄色av | 丁香婷婷网 | 特级黄色视频毛片 | 国产手机视频在线观看 | 夜夜操网 | 中国精品一区二区 | 午夜视频在线观看一区 | 麻豆视频观看 | 国产一区二区午夜 | 福利视频午夜 | 99久久精品免费看国产一区二区三区 | 激情五月六月婷婷 | 日本久久成人中文字幕电影 | 狠狠激情中文字幕 | 国产精品成人自产拍在线观看 | 久久久免费精品 | 久久久一本精品99久久精品 | 国产成人a亚洲精品 | 在线观看国产www | 一本一道波多野毛片中文在线 | 亚洲日韩精品欧美一区二区 | 久久a v电影 | 肉色欧美久久久久久久免费看 | 日日夜夜中文字幕 | 伊人激情网 | 日韩一区二区三免费高清在线观看 | 98超碰在线 | 国产亚洲人成网站在线观看 | 国产婷婷精品 | 国产精品久久久久久一区二区三区 | 久久精品国亚洲 | 中文视频在线播放 | 在线观看视频黄色 | 国产在线国偷精品产拍 | 夜色资源网 | 人人爽人人爽人人片av | 久久8精品 | 中文字幕在线观看资源 | 国产精品一区二区免费看 | 高清一区二区 | 一区二区三区免费播放 | 成人一区二区在线观看 | 亚洲一区美女视频在线观看免费 | av一区二区三区在线播放 | 国产精品成人一区二区三区吃奶 | 久久电影中文字幕视频 | 香蕉视频啪啪 | 97看片吧 | 人人玩人人爽 | 亚洲精品国偷拍自产在线观看蜜桃 | 天天操天天干天天 | 91正在播放| 草久视频在线 | 亚洲精品在线看 | 久久公开视频 | 88av网站| 欧美一二三区在线观看 | 国产99久久精品一区二区300 | 中文一二区 | 亚洲精品美女久久久久 | 久久精品国产精品亚洲精品 | 日日干夜夜爱 | 美女视频黄免费的 | 美女网站视频一区 | 91高清不卡| 91中文字幕一区 | 玖玖视频在线 | 成人sm另类专区 | 天天在线免费视频 | 国产精选视频 | 成人三级视频 | 在线免费观看av网站 | 欧美成人69av | 在线色视频小说 | 四虎永久免费在线观看 | 黄色av大片 | 色婷婷激婷婷情综天天 | 伊人狠狠干 | 亚洲 中文字幕av | 成年人在线观看网站 | 欧美精品免费在线 | 日日夜夜精品免费 | 国产视频九色蝌蚪 | 97**国产露脸精品国产 | 激情av网址 | 亚洲精品国产精品久久99 | 91麻豆精品国产91 | 黄av免费| 五月宗合网 | 国产九色在线播放九色 | 激情五月视频 | 欧美午夜a | 成人精品久久 | 久久99精品一区二区三区三区 | 亚州激情视频 | 亚洲乱码精品 | 欧美巨大荫蒂茸毛毛人妖 | 国产久视频 | 久草a视频| www.色五月.com | japanesefreesexvideo高潮 | 欧美精品黑人性xxxx | 亚洲码国产日韩欧美高潮在线播放 | www.五月激情.com | 免费的国产精品 | 久久手机视频 | 欧美午夜精品久久久久 | 五月婷婷综合激情网 | 日韩电影中文字幕 | 国内精品免费久久影院 | 色国产在线 | 人人网av| 久久久久国产精品视频 | 91av视频免费在线观看 | 国产手机在线精品 | 日日夜夜精品免费观看 | 99高清视频有精品视频 | 久久精品欧美日韩精品 | 国产精品久久久影视 | 日本三级在线观看中文字 | 2019av在线视频| 亚洲一区精品二人人爽久久 | 亚洲精品合集 | 日韩欧美精品在线视频 | 国产精品精 | 日免费视频| 国内精品久久久久久久影视简单 | 精品视频成人 | 精品在线视频一区二区三区 | 久久精品毛片 | 中文字幕在线观看你懂的 | 91中文字幕视频 | 日韩电影在线观看一区二区三区 | 国产精品专区在线 | 伊甸园av在线 | 久久电影国产免费久久电影 | 天天躁日日躁狠狠 | 日日夜夜爱 | 在线观看视频国产一区 | 91九色自拍 | 精品久久一二三区 | 欧美日韩不卡一区二区三区 | 久草视频免费看 | 色综合婷婷| 天天爱av导航| 四虎免费在线观看 | 久久精品一区二区三区视频 | 日韩精品视频免费专区在线播放 | 亚洲免费av电影 | 五月婷婷导航 | 欧美一区二区在线 | 亚洲精品乱码久久久久久蜜桃不爽 | 日韩av在线不卡 | 狠狠狠色丁香综合久久天下网 | 美女久久久久久久 | 亚洲精品女人久久久 | 91av精品 | 天天干天天操人体 | 手机av片 | 天天操比 | 久草剧场 | 中文字幕免费观看视频 | 国产精品福利小视频 | 黄色免费视频在线观看 | 成人av影院在线观看 | 免费看黄电影 | 成人久久亚洲 | 91激情视频在线 | 精品欧美乱码久久久久久 | 69视频在线| 久久久精品国产一区二区三区 | 久久久精品亚洲 | 久久久久久久影院 | 国产成人一区二区三区在线观看 | 91在线视频免费播放 | 91av视频免费在线观看 | 亚洲一区免费在线 | 国产精品久久久av久久久 | 999色视频| 欧美一性一交一乱 | 天天做天天爱天天综合网 | 毛片区 | 国产香蕉久久精品综合网 | 波多野结衣视频在线 | 中文字幕视频一区二区 | 97色在线| 四虎在线永久免费观看 | 免费视频一二三区 | 成年人黄色在线观看 | 日本久久综合网 | 国产在线精品播放 | 婷婷色伊人 | 色丁香婷婷| 日韩av资源站 | 国内精品小视频 | 欧美精品网站 | 日本久久久久久久久 | 有码中文在线 | 97视频免费在线 | 高清不卡一区二区三区 | 超碰97在线人人 | 久久精品视频国产 | 午夜.dj高清免费观看视频 | 久久国产精品第一页 | 日韩在线视频二区 | 精品一区电影国产 | 亚洲国产片 | 国产91电影在线观看 | 久久久久国产精品视频 | 国产精品久久久久久久久久不蜜月 | 激情五月婷婷激情 | 欧美大片www| 九九激情视频 | 一级欧美黄 | 三级在线视频播放 | 在线观看国产区 | 国产日产精品久久久久快鸭 | 不卡的av| 99精品视频99 | 美女免费黄视频网站 | av解说在线观看 | 亚洲黄色小说网址 | 色婷在线 | 久久久国产精品久久久 | 午夜av影院| 99久久久久免费精品国产 | 国产裸体无遮挡 | 狠狠躁日日躁狂躁夜夜躁av | 国产精久久久 | 久久中文精品视频 | 99精品视频在线免费观看 | 国产精品久久久av | 久久久精品在线观看 | 黄色毛片一级片 | 一区二区电影网 | 91 在线视频 | 国产高清视频色在线www | 国产永久免费高清在线观看视频 | 久草视频播放 | 亚洲国产中文字幕在线视频综合 | 日韩在线观看第一页 | 精品国产免费人成在线观看 | 99精品视频在线观看免费 | 成人久久毛片 | 久久精品视频国产 | 欧美一二三视频 | 天天激情站 | 欧美日韩高清国产 | 婷婷色综合 | 免费久久久久久 | 国内精品视频在线播放 | 久久成人国产精品一区二区 | 99视频精品全国免费 | a视频免费看 | 四虎成人精品永久免费av | av永久网址| 久久亚洲综合国产精品99麻豆的功能介绍 | 狠狠色噜噜狠狠狠狠2021天天 | 日本中文乱码卡一卡二新区 | 极品国产91在线网站 | 国产日韩欧美在线一区 | 日韩欧美xxxx | 国产破处精品 | 精品一区精品二区 | 国产精品涩涩屋www在线观看 | 中文字幕一区二区在线播放 | 天天摸天天操天天舔 | 99精品免费在线 | 国产成人精品日本亚洲999 | 久久综合免费视频 | 91一区啪爱嗯打偷拍欧美 | 欧美日韩后 | 国产精品一区二区吃奶在线观看 | 婷婷亚洲综合 | 综合久久五月天 | 国产九色91 | 中文字幕在线观看网址 | 97成人免费 | 黄色软件大全网站 | 亚洲国产中文在线 | 国产精品资源在线观看 | 国产成人三级一区二区在线观看一 | 在线视频精品播放 | av在线电影网站 | 久久男人免费视频 | 黄色成人免费电影 | 日韩在线视频观看 | 免费看黄色小说的网站 | 国内精品一区二区 | 免费看的视频 | 久久视频 | www.五月婷婷.com | 91精品国产99久久久久 | 日本性xxxxx 亚洲精品午夜久久久 | 日韩欧美大片免费观看 | 亚洲1区 在线 | 在线有码中文字幕 | 国产精品一区二区三区四区在线观看 | 日韩久久网站 | 狠狠干在线 | 麻豆视频免费看 | 亚洲区另类春色综合小说 | 日韩一区二区三区在线看 | 国产又粗又硬又长又爽的视频 | 99国内精品久久久久久久 | 一区二区三区手机在线观看 | 五月天天在线 | 在线视频电影 | 亚洲精品国 | 国产精品免费视频久久久 | 久久久久女人精品毛片九一 | 亚洲精品999 | 精品久久网 | 久久久久久久久久久久影院 | 欧美激情视频一二区 | 最近在线中文字幕 | 91av视频在线观看免费 | av中文字幕av | 日韩免费专区 | 91在线播 | 五月婷婷在线综合 | 久久精品久久久精品美女 | 亚洲国产精品va在线看黑人 | 国产成人精品久久久久 | 久久国产精品99久久人人澡 | 日韩影视在线 | 综合色站| 91视频最新网址 | 中文字幕在线观看第一区 | 日本精品视频一区 | 91女人18片女毛片60分钟 | 五月婷激情 | 日本久久久久久久久久 | 国精产品999国精产品视频 | 欧美一级黄色片 | 亚洲国产成人久久 | 久久亚洲综合国产精品99麻豆的功能介绍 | 久久天堂亚洲 | 天堂va在线高清一区 | 丝袜足交在线 | 日韩在线视频在线观看 | 狠狠地操| 日韩欧美xxxx | 久久精品香蕉视频 | a黄色片在线观看 | 高清在线观看av | 就要干b | 亚洲第一色| 一区中文字幕电影 | 色94色欧美| 91视频免费看网站 | 国产成人黄色在线 | 成人网大片 | 久久新视频| 国产视频1区2区 | 欧美一区二区日韩一区二区 | 色婷婷狠狠五月综合天色拍 | 成人视屏免费看 | 国产精品毛片久久 | 日韩精品视频一二三 | 91精品国产91久久久久 | 成人黄色电影在线观看 | 欧美日韩精品区 | 激情婷婷在线观看 | 91福利视频久久久久 | 69国产盗摄一区二区三区五区 | 欧美日韩视频一区二区三区 | 精品国产区在线 | 亚洲电影图片小说 | 伊人热| 西西大胆免费视频 | www.久久99| 亚洲影视九九影院在线观看 | 欧美孕妇视频 | 人人干人人干人人干 | 综合色婷婷 | 日韩在线在线 | 国产成人精品一区二区在线观看 | 国产一区二区不卡视频 | 伊人av综合 | 色多多视频在线观看 | 久久精品首页 | 久草免费看 | 韩国av电影网| 99爱爱| 天堂资源在线观看视频 | 久久在视频 | 九九爱免费视频 | 久久免费视频这里只有精品 | 日韩av有码在线 | 久草影视在线 | 国产高清视频在线观看 | 久久久午夜精品理论片中文字幕 | 国产福利一区二区三区视频 | 亚洲激情在线 | 91九色免费视频 | 欧美日韩一区久久 | 欧美一区二区三区免费观看 | 五月婷婷综合在线视频 | 免费一级片视频 | 色综合久久综合网 | 夜夜骑日日 | 经典三级一区 | 欧美激情视频三区 | 最近高清中文字幕在线国语5 | 久久国内精品视频 | 精品少妇一区二区三区在线 | 永久免费毛片在线观看 | 久久艹久久| 日韩国产精品久久久久久亚洲 | 亚洲伦理一区 | 在线色视频小说 | 亚洲黄色三级 | 日韩电影久久 | 在线免费av网| 久久综合狠狠综合 | 成人在线视 | 久久三级毛片 | 99麻豆久久久国产精品免费 | 国产91影院| 日韩免费 | 久久国产精品小视频 | 一本一本久久a久久 | 久久99精品久久久久久 | 成人亚洲综合 | 一级黄网| 精品久久精品久久 | 精品国产伦一区二区三区 | 久草久草久草久草 | 成人午夜av电影 | 天天操天天爽天天干 | 91在线免费观看国产 | 99免在线观看免费视频高清 | 国产精品在线看 | 九九交易行官网 | 一区二区三区视频网站 | 超碰最新网址 | 国产99在线播放 | 超碰97人人干 | 激情五月视频 | 天堂v中文 | 精品视频免费观看 | 色诱亚洲精品久久久久久 | 日韩中文字幕在线不卡 | 国产一性一爱一乱一交 | 亚洲一级片av | 国产亚洲精品v | 99r精品视频在线观看 | 伊人天天狠天天添日日拍 | 国产精品影音先锋 | 亚洲欧美偷拍另类 | 美女视频一区二区 | 免费国产亚洲视频 | 丁香婷婷综合激情五月色 | 91九色视频国产 | 久久精品国产精品亚洲 | 亚洲高清在线视频 | 免费日韩 精品中文字幕视频在线 | 成 人 黄 色 免费播放 | 奇米7777狠狠狠琪琪视频 | 99精品国产成人一区二区 | 国产99爱 | 免费观看mv大片高清 | 中文字幕在线高清 | 久精品视频 | 久久www免费人成看片高清 | 成年人视频免费在线播放 | 最近最新中文字幕视频 | 久久99久久99精品免观看粉嫩 | 国产91在线看 | 色婷婷激情电影 | 超级碰视频 | 亚洲精欧美一区二区精品 | 国产一级视频 | 东方av免费在线观看 | 国产热re99久久6国产精品 | 成人一区二区三区在线观看 | 久久国产精品精品国产色婷婷 | 国产午夜精品一区二区三区 | 亚洲欧美激情精品一区二区 | 色网免费观看 | 精品播放 | 中文在线中文a | 国产精品久久久久免费a∨ 欧美一级性生活片 | 亚洲第一av在线播放 | 免费电影播放 | 天天干天天射天天插 | 日韩免费福利 | 手机成人在线 | 天天综合狠狠精品 | 激情网五月婷婷 | 精品福利在线视频 | 青草视频在线播放 | 日日草夜夜操 | 欧美激情第八页 | 在线观看免费成人av | 日本精品视频免费 | 蜜桃视频精品 | 国产精品久久久久久久久费观看 | 日本爱爱免费视频 | 在线看国产日韩 | 久草视频中文在线 | 久久a v电影 | 日韩精品偷拍 | 久久久久福利视频 | 欧洲亚洲激情 | 激情欧美一区二区三区免费看 | 免费h漫在线观看 | 久久影视中文字幕 | 毛片视频电影 | 国产一区欧美在线 | 在线观看视频国产一区 | 日韩高清精品一区二区 | 日日夜夜精品 | 国产1区2| av在线成人 | 精品成人免费 | 98精品国产自产在线观看 | 国产99精品| 国产成人久久精品77777 | 91激情视频在线播放 | 中日韩在线视频 | 欧美激情精品久久 | 久久福利剧场 | 亚洲视频在线免费看 | 麻豆91小视频 | 国产精品成人国产乱一区 | 中文字幕黄色网 | 91精品在线麻豆 | 日日操天天操夜夜操 | 久草视频在线资源站 | 免费亚洲视频 | 亚洲精品高清一区二区三区四区 | 国内精品久久久久久中文字幕 | 91爱爱中文字幕 | 免费久久视频 | 91丨九色丨国产在线观看 | 免费a级毛片在线看 | 国产精品在线看 | 日韩在线观看一区 | 婷婷六月丁香激情 | 911香蕉视频 | 91精品在线观看入口 | 亚洲国产欧美一区二区三区丁香婷 | 亚洲免费视频在线观看 | 麻豆精品视频在线 | 欧美色图视频一区 | 人人干天天射 | 欧美一级性生活视频 | 伊甸园永久入口www 99热 精品在线 | 91精品导航 | 欧美黄色特级片 | 天天综合网在线 | 狠狠色丁香九九婷婷综合五月 | 精品超碰 | 一级黄色片在线播放 | 国产亚洲婷婷 | 91香蕉视频色版 | 日本精品一区二区 | 久久草 | 国产第一页精品 | 亚洲精品日韩av | 久久综合中文字幕 | 久久久久久激情 | 国产三级av在线 | 99精品欧美一区二区蜜桃免费 | 国产日韩高清在线 | 91精品人成在线观看 | 91欧美国产 | 国产精品高清在线 | 久久久久www | www.色com | 久久久精品国产一区二区 | 亚洲精品短视频 | 婷婷九月丁香 | 国产精品手机在线观看 | 久久大片 | 六月婷婷色 | 精品在线观看一区二区 | 69精品| 日韩在线观看精品 | 91传媒免费在线观看 | 精品国偷自产国产一区 | 在线国产日韩 | 日日夜夜婷婷 | 成人毛片在线观看视频 | 成人午夜久久 | 欧美精品一级视频 | 国产视频资源 | 激情婷婷丁香 | 国产精品成人av电影 | 日本中文不卡 | 99久久精品费精品 | 91麻豆操 | 丝袜制服天堂 | 在线观看黄色的网站 | 日韩精品一区二区三区在线播放 | 欧美久久久影院 | 91九色视频导航 | 黄色大片日本免费大片 | 日本精品一区二区三区在线观看 | 日韩电影在线观看一区二区三区 | 黄色av一级 | 午夜丰满寂寞少妇精品 | 国内精品久久久久影院优 | 久久久久97国产 | 亚洲精品一区二区久 | 国产精品久久久久久久久软件 | 狠狠色噜噜狠狠 | 色婷婷av国产精品 | 亚洲精品一区二区久 | 亚洲精品美女 | 手机色在线| 婷色在线| 免费观看黄 | 色综合天天色综合 | 麻花豆传媒mv在线观看网站 | 黄色网址av | 国产又粗又猛又爽又黄的视频先 | 日韩欧美一区二区三区免费观看 | 色综合久久五月天 | 在线视频黄| 五月亚洲| 欧美精品久久久久久久久久久 | 91成年人网站 | 精品久久久久久一区二区里番 | 亚洲美女免费精品视频在线观看 | 免费在线成人av电影 | 色干干| 玖玖在线视频观看 | 久久国产精品久久w女人spa | 伊人永久在线 | 精品国产亚洲一区二区麻豆 | 69国产盗摄一区二区三区五区 | 国产在线观看高清视频 | 在线香蕉视频 | 久久国精品 | 色综合久久久久 | 伊人电影天堂 | 国产成人精品一区二区三区免费 | 久久精品视频播放 | 国产黄免费看 | 日本字幕网 | 中国成人一区 | 黄色av电影在线 | 国产日韩精品一区二区在线观看播放 | 天天激情在线 | 天堂在线一区二区三区 | 99久久精 | 免费色网站 | 中文字幕av最新 | 麻豆一区在线观看 | 成人国产在线 | 久久99久久99免费视频 | 九九免费精品 | 国产精品video| 日韩最新理论电影 | 天天干,天天干 | 国内精品久久久久久久久久久久 | 精品国产一二三 | 激情婷婷| 国产黄色特级片 | 国产九九热 | 九九热视频在线 | 97在线免费观看 | 日韩色高清 | 欧美精品一区二区免费 | 日韩av黄 | 精品国产_亚洲人成在线 | 精品99久久久久久 | 欧美日本啪啪无遮挡网站 | 五月婷婷六月丁香在线观看 | av在线亚洲天堂 | 欧美一区二区日韩一区二区 | 久久夜色精品国产欧美乱极品 | 久久私人影院 | 中文字幕在线国产 | 国产xxxxx在线观看 | 欧美一区二区三区在线播放 | 免费观看久久久 | 黄色三级网站 | 亚洲成a人片77777潘金莲 | 国产免费资源 | 国产精品com | 在线国产视频观看 | 欧亚日韩精品一区二区在线 | 日韩视频一区二区在线 | 天堂av观看| 波多野结衣电影一区二区 | 欧美老女人xx | 天堂在线免费视频 | 免费看三级黄色片 | 国产视频精品视频 | 日韩激情小视频 | 激情婷婷av| 狠狠色综合欧美激情 | 美女网站黄在线观看 | 久久精品一 | 精品免费一区 | 五月综合色婷婷 | 青春草免费视频 | 在线欧美最极品的av | 天天干天天摸天天操 | 亚洲欧美国产日韩在线观看 | 西西444www高清大胆 | 日韩久久精品一区二区三区 | 国产精品对白一区二区三区 | 午夜精品久久久久久久久久久 | 久久久久久久久久久久亚洲 | 91网址在线看 | 国产午夜在线观看视频 | 久久久免费国产 | 亚洲精品久久久久久中文传媒 | 九色91av| 天天做天天爱天天综合网 | 久久一级片 | 91在线porny国产在线看 | 久久不射影院 | 久久久久久久福利 | .国产精品成人自产拍在线观看6 | 亚洲区另类春色综合小说校园片 | 久久无码av一区二区三区电影网 | 在线免费观看黄色小说 | 欧美一级片免费观看 | 午夜精品福利影院 | 在线观看免费版高清版 | 久久精品高清 | 69av久久 | 国产精品视频内 | 97超碰人 | 最新日韩在线 | 欧洲亚洲国产视频 | 黄色片网站av | 人人澡人人干 | 亚洲视频六区 | 成人午夜免费剧场 | www.超碰97.com| 久久精品精品 | 午夜精品一二区 | 91视频最新网址 | 91视频免费看 | 国内精品中文字幕 | 欧美一二区视频 | 亚洲电影久久久 | 午夜国产福利在线 | 午夜精品99久久免费 | 国产一区二区在线播放视频 | 日韩高清av| 高清久久久久久 | 日韩中文在线观看 | 国产精品久久av | 国产日韩中文字幕在线 | 久久97久久| 久草免费在线 | 日韩av电影免费在线观看 | 免费a视频在线 | 91免费在线看片 | 日韩伦理片一区二区三区 | 久久精品在线视频 | 国产精在线 | 2019免费中文字幕 | 精品三级av | 国产精品久久久久久久久蜜臀 | 一级欧美一级日韩 | 黄色小说在线观看视频 | 伊人资源视频在线 | 97日日碰人人模人人澡分享吧 | 色综合天天在线 | 夜夜狠狠 | 国产一区视频导航 | 国产精品欧美精品 | 久久看片 | 久久综合久久八八 | www免费在线观看 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 97精产国品一二三产区在线 | 黄色录像av | 天天操夜夜操夜夜操 | 久久综合加勒比 | 国产成人综合精品 | 久久97久久97精品免视看 | 在线欧美日韩 | 97视频中文字幕 | 色婷婷免费 | 91欧美在线 | 亚洲网站在线 | 日韩亚洲在线观看 | 五月天婷婷在线播放 | 97视频人人澡人人爽 | 一区在线观看 | 久久婷婷五月综合色丁香 | 国产视频在线观看一区 | 色天天综合网 | 久久久久久久久久久黄色 | 久久字幕网| 婷婷视频 | 一区二区三区四区五区在线 | 国产999在线观看 | 亚洲精品成人av在线 | 久久综合久久综合这里只有精品 | 久久久精品欧美 | 日韩黄色在线电影 | 久久精品国产免费看久久精品 | 国产一区91| 久久免费观看少妇a级毛片 久久久久成人免费 | 日本精品久久久一区二区三区 | 久久伊人精品天天 | 人人干网 | 久久国产精品精品国产色婷婷 |