• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 74, 文章 - 0, 評(píng)論 - 26, 引用 - 0
            數(shù)據(jù)加載中……

            Windows CE usb驅(qū)動(dòng)程序

            上述講了堆理論,可能讀者腦袋都已經(jīng)大了,為此,我們舉個(gè)簡(jiǎn)單的例子來(lái)詳細(xì)說(shuō)明一下驅(qū)動(dòng)程序的開(kāi)發(fā)過(guò)程。

            例如我們有個(gè)USB Mouse設(shè)備,設(shè)備信息描述如下:
            Device Descriptor:
            bcdUSB: 0x0100
            bDeviceClass: 0x00
            bDeviceSubClass: 0x00
            bDeviceProtocol: 0x00
            bMaxPacketSize0: 0x08 (8)
            idVendor: 0x05E3 (Genesys Logic Inc.)
            idProduct: 0x0001
            bcdDevice: 0x0101
            iManufacturer: 0x00
            iProduct: 0x01
            iSerialNumber: 0x00
            bNumConfigurations: 0x01

            ConnectionStatus: DeviceConnected
            Current Config value: 0x01
            Device Bus Speed: Low
            Device Address: 0x02
            Open Pipes: 1

            Endpoint Descriptor:
            bEndpointAddress: 0x81
            Transfer Type: Interrupt
            wMaxPacketSize: 0x0003 (3)
            bInterval: 0x0A

            可以看出上述設(shè)備有一個(gè)中斷PIPE,包的最大值為3。可能有人問(wèn)上述的值怎么得到的,win2k 的DDK中有個(gè)usbview的例程,編譯一下,將你的USB設(shè)備插到PC機(jī)的USB口中,運(yùn)行usbview.exe即可看得相應(yīng)的設(shè)備信息。

            有了這些基本信息,就可以編寫(xiě)USB設(shè)備了,首先聲明一下,下面的代碼取自微軟的USB鼠標(biāo)樣本程序,版權(quán)歸微軟所有,此處僅僅借用來(lái)描述一下USB鼠標(biāo)驅(qū)動(dòng)的開(kāi)發(fā)過(guò)程,讀者如需要引用此代碼,需要得到微軟的同意。

            首先,必須輸出USBD要求調(diào)用的三個(gè)函數(shù),首先到設(shè)備插入到USB端口時(shí),USBD會(huì)調(diào)用USBDeviceAttach()函數(shù),相應(yīng)的代碼如下:
            extern "C" BOOL
            USBDeviceAttach(
            USB_HANDLE hDevice, // USB設(shè)備句柄
            LPCUSB_FUNCS lpUsbFuncs, // USBDI的函數(shù)集合
            LPCUSB_INTERFACE lpInterface, // 設(shè)備接口描述信息
            LPCWSTR szUniqueDriverId, // 設(shè)備ID描述字符串。
            LPBOOL fAcceptControl, // 返回TRUE,標(biāo)識(shí)我們可以控制此設(shè)備, 反之表示不能控制
            DWORD dwUnused)
            {
            *fAcceptControl = FALSE;
            // 我們的鼠標(biāo)設(shè)備有特定的描述信息,要檢測(cè)是否是我們的設(shè)備。
            if (lpInterface == NULL)
            return FALSE;
            // 打印相關(guān)的USB設(shè)備接口描述信息。
            DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: DeviceAttach, IF %u, #EP:%u, Class:%u, Sub:%u,Prot:%u\r\n"), lpInterface->Descriptor.bInterfaceNumber,lpInterface->Descriptor.bNumEndpoints, lpInterface->Descriptor.bInterfaceClass,lpInterface->Descriptor.bInterfaceSubClass,lpInterface->Descriptor.bInterfaceProtocol));
            // 初試數(shù)據(jù)USB鼠標(biāo)類(lèi),產(chǎn)生一個(gè)接受USB鼠標(biāo)數(shù)據(jù)的線(xiàn)程
            CMouse * pMouse = new CMouse(hDevice, lpUsbFuncs, lpInterface);
            if (pMouse == NULL)
            return FALSE;

            if (!pMouse->Initialize())
            {
            delete pMouse;
            return FALSE;
            }

            // 注冊(cè)一個(gè)監(jiān)控USB設(shè)備事件的回調(diào)函數(shù),用于監(jiān)控USB設(shè)備是否已經(jīng)拔掉。
            (*lpUsbFuncs->lpRegisterNotificationRoutine)(hDevice,
            USBDeviceNotifications, pMouse);

            *fAcceptControl = TRUE;
            return TRUE;
            }

            第二個(gè)函數(shù)是 USBInstallDriver()函數(shù),
            一些基本定義如下:
            const WCHAR gcszRegisterClientDriverId[] = L"RegisterClientDriverID";
            const WCHAR gcszRegisterClientSettings[] = L"RegisterClientSettings";
            const WCHAR gcszUnRegisterClientDriverId[] = L"UnRegisterClientDriverID";
            const WCHAR gcszUnRegisterClientSettings[] = L"UnRegisterClientSettings";
            const WCHAR gcszMouseDriverId[] = L"Generic_Sample_Mouse_Driver";

            函數(shù)接口如下:
            extern "C" BOOL
            USBInstallDriver(
            LPCWSTR szDriverLibFile) // @parm [IN] - Contains client driver DLL name
            {
            BOOL fRet = FALSE;
            HINSTANCE hInst = LoadLibrary(L"USBD.DLL");

            // 注冊(cè)USB設(shè)備信息
            if(hInst)
            {
            LPREGISTER_CLIENT_DRIVER_ID pRegisterId = (LPREGISTER_CLIENT_DRIVER_ID)
            GetProcAddress(hInst, gcszRegisterClientDriverId);

            LPREGISTER_CLIENT_SETTINGS pRegisterSettings =
            (LPREGISTER_CLIENT_SETTINGS) GetProcAddress(hInst,
            gcszRegisterClientSettings);

            if(pRegisterId && pRegisterSettings)
            {
            USB_DRIVER_SETTINGS DriverSettings;

            DriverSettings.dwCount = sizeof(DriverSettings);

            // 設(shè)置我們的特定的信息。
            DriverSettings.dwVendorId = USB_NO_INFO;
            DriverSettings.dwProductId = USB_NO_INFO;
            DriverSettings.dwReleaseNumber = USB_NO_INFO;

            DriverSettings.dwDeviceClass = USB_NO_INFO;
            DriverSettings.dwDeviceSubClass = USB_NO_INFO;
            DriverSettings.dwDeviceProtocol = USB_NO_INFO;

            DriverSettings.dwInterfaceClass = 0x03; // HID
            DriverSettings.dwInterfaceSubClass = 0x01; // boot device
            DriverSettings.dwInterfaceProtocol = 0x02; // mouse

            fRet = (*pRegisterId)(gcszMouseDriverId);

            if(fRet)
            {
            fRet = (*pRegisterSettings)(szDriverLibFile,
            gcszMouseDriverId, NULL, &DriverSettings);

            if(!fRet)
            {
            //BUGBUG unregister the Client Driver’s ID
            }
            }
            }
            else
            {
            RETAILMSG(1,(TEXT("!USBMouse: Error getting USBD function pointers\r\n")));
            }
            FreeLibrary(hInst);
            }
            return fRet;
            }
            上述代碼主要用于產(chǎn)生USB設(shè)備驅(qū)動(dòng)程序需要的注冊(cè)表信息,需要注意的是:USB設(shè)備驅(qū)動(dòng)程序不使用標(biāo)準(zhǔn)的注冊(cè)表函數(shù),而是使用RegisterClientDriverID()和RegisterClientSettings來(lái)注冊(cè)相應(yīng)的設(shè)備信息。

            另外一個(gè)函數(shù)是USBUninstallDriver()函數(shù),具體代碼如下:
            extern "C" BOOL
            USBUnInstallDriver()
            {
            BOOL fRet = FALSE;
            HINSTANCE hInst = LoadLibrary(L"USBD.DLL");

            if(hInst)
            {
            LPUN_REGISTER_CLIENT_DRIVER_ID pUnRegisterId =
            (LPUN_REGISTER_CLIENT_DRIVER_ID)
            GetProcAddress(hInst, gcszUnRegisterClientDriverId);

            LPUN_REGISTER_CLIENT_SETTINGS pUnRegisterSettings =
            (LPUN_REGISTER_CLIENT_SETTINGS) GetProcAddress(hInst,
            gcszUnRegisterClientSettings);

            if(pUnRegisterSettings)
            {
            USB_DRIVER_SETTINGS DriverSettings;

            DriverSettings.dwCount = sizeof(DriverSettings);
            // 必須填入與注冊(cè)時(shí)相同的信息。
            DriverSettings.dwVendorId = USB_NO_INFO;
            DriverSettings.dwProductId = USB_NO_INFO;
            DriverSettings.dwReleaseNumber = USB_NO_INFO;

            DriverSettings.dwDeviceClass = USB_NO_INFO;
            DriverSettings.dwDeviceSubClass = USB_NO_INFO;
            DriverSettings.dwDeviceProtocol = USB_NO_INFO;

            DriverSettings.dwInterfaceClass = 0x03; // HID
            DriverSettings.dwInterfaceSubClass = 0x01; // boot device
            DriverSettings.dwInterfaceProtocol = 0x02; // mouse

            fRet = (*pUnRegisterSettings)(gcszMouseDriverId, NULL,
            &DriverSettings);
            }

            if(pUnRegisterId)
            {
            BOOL fRetTemp = (*pUnRegisterId)(gcszMouseDriverId);
            fRet = fRet ? fRetTemp : fRet;
            }
            FreeLibrary(hInst);
            }
            return fRet;
            }
            此函數(shù)主要用于刪除USBInstallDriver()時(shí)創(chuàng)建的注冊(cè)表信息,同樣的它使用自己的函數(shù)接口UnRegisterClientDriverID()和UnRegisterClientSettings()來(lái)做相應(yīng)的處理。

            另外一個(gè)需要處理的注冊(cè)的監(jiān)控通知函數(shù)USBDeviceNotifications():
            extern "C" BOOL USBDeviceNotifications(LPVOID lpvNotifyParameter, DWORD dwCode,
            LPDWORD * dwInfo1, LPDWORD * dwInfo2, LPDWORD * dwInfo3,
            LPDWORD * dwInfo4)
            {
            CMouse * pMouse = (CMouse *)lpvNotifyParameter;

            switch(dwCode)
            {
            case USB_CLOSE_DEVICE:
            //刪除相關(guān)的資源。
            delete pMouse;
            return TRUE;
            }
            return FALSE;
            }


            USB鼠標(biāo)的類(lèi)的定義如下:
            class CMouse
            {
            public:
            CMouse::CMouse(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs,
            LPCUSB_INTERFACE lpInterface);
            ~CMouse();

            BOOL Initialize();
            private:
            // 傳輸完畢調(diào)用的回調(diào)函數(shù)
            static DWORD CALLBACK MouseTransferCompleteStub(LPVOID lpvNotifyParameter);
            // 中斷處理函數(shù)
            static ULONG CALLBACK CMouse::MouseThreadStub(PVOID context);
            DWORD MouseTransferComplete();
            DWORD MouseThread();

            BOOL SubmitInterrupt();
            BOOL HandleInterrupt();

            BOOL m_fClosing;
            BOOL m_fReadyForMouseEvents;

            HANDLE m_hEvent;
            HANDLE m_hThread;

            USB_HANDLE m_hDevice;
            USB_PIPE m_hInterruptPipe;
            USB_TRANSFER m_hInterruptTransfer;

            LPCUSB_FUNCS m_lpUsbFuncs;
            LPCUSB_INTERFACE m_pInterface;

            BOOL m_fPrevButton1;
            BOOL m_fPrevButton2;
            BOOL m_fPrevButton3;

            // 數(shù)據(jù)接受緩沖區(qū)。
            BYTE m_pbDataBuffer[8];
            };

            具體實(shí)現(xiàn)如下:

            // 構(gòu)造函數(shù),初始化時(shí)調(diào)用
            CMouse::CMouse(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs,
            LPCUSB_INTERFACE lpInterface)
            {
            m_fClosing = FALSE;
            m_fReadyForMouseEvents = FALSE;
            m_hEvent = NULL;
            m_hThread = NULL;

            m_hDevice = hDevice;
            m_hInterruptPipe = NULL;
            m_hInterruptTransfer = NULL;

            m_lpUsbFuncs = lpUsbFuncs;
            m_pInterface = lpInterface;

            m_fPrevButton1 = FALSE;
            m_fPrevButton2 = FALSE;
            m_fPrevButton3 = FALSE;

            memset(m_pbDataBuffer, 0, sizeof(m_pbDataBuffer));
            }

            // 析構(gòu)函數(shù),用于清除申請(qǐng)的資源。
            CMouse::~CMouse()
            {
            // 通知系統(tǒng)去關(guān)閉相關(guān)的函數(shù)接口。
            m_fClosing = TRUE;

            // Wake up the connection thread again and give it time to die.
            if (m_hEvent != NULL)
            {
            // 通知關(guān)閉數(shù)據(jù)接受線(xiàn)程。
            SetEvent(m_hEvent);

            if (m_hThread != NULL)
            {
            DWORD dwWaitReturn;

            dwWaitReturn = WaitForSingleObject(m_hThread, 1000);
            if (dwWaitReturn != WAIT_OBJECT_0)
            {
            TerminateThread(m_hThread, DWORD(-1));
            }
            CloseHandle(m_hThread);
            m_hThread = NULL;
            }
            CloseHandle(m_hEvent);
            m_hEvent = NULL;
            }

            if(m_hInterruptTransfer)
            (*m_lpUsbFuncs->lpCloseTransfer)(m_hInterruptTransfer);

            if(m_hInterruptPipe)
            (*m_lpUsbFuncs->lpClosePipe)(m_hInterruptPipe);
            }


            // 初始化USB鼠標(biāo)驅(qū)動(dòng)程序
            BOOL CMouse::Initialize()
            {
            LPCUSB_DEVICE lpDeviceInfo = (*m_lpUsbFuncs->lpGetDeviceInfo)(m_hDevice);

            // 檢測(cè)配置:USB鼠標(biāo)應(yīng)該只有一個(gè)中斷管道
            if ((m_pInterface->lpEndpoints[0].Descriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) != USB_ENDPOINT_TYPE_INTERRUPT)
            {
            RETAILMSG(1,(TEXT("!USBMouse: EP 0 wrong type (%u)!\r\n"),
            m_pInterface->lpEndpoints[0].Descriptor.bmAttributes));
            return FALSE;
            }
            DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: EP 0:MaxPacket: %u, Interval: %u\r\n"),
            m_pInterface->lpEndpoints[0].Descriptor.wMaxPacketSize,
            m_pInterface->lpEndpoints[0].Descriptor.bInterval));

            m_hInterruptPipe = (*m_lpUsbFuncs->lpOpenPipe)(m_hDevice,
            &m_pInterface->lpEndpoints[0].Descriptor);

            if (m_hInterruptPipe == NULL) {
            RETAILMSG(1,(TEXT("Mouse: Error opening interrupt pipe\r\n")));
            return (FALSE);
            }
            m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
            if (m_hEvent == NULL)
            {
            RETAILMSG(1,(TEXT("USBMouse: Error on CreateEvent for connect event\r\n")));
            return(FALSE);
            }
            // 創(chuàng)建數(shù)據(jù)接受線(xiàn)程
            m_hThread = CreateThread(0, 0, MouseThreadStub, this, 0, NULL);
            if (m_hThread == NULL)
            {
            RETAILMSG(1,(TEXT("USBMouse: Error on CreateThread\r\n")));
            return(FALSE);
            }

            return(TRUE);
            }

            // 從USB鼠標(biāo)設(shè)備中讀出數(shù)據(jù),產(chǎn)生相應(yīng)的鼠標(biāo)事件。
            BOOL CMouse::SubmitInterrupt()
            {
            if(m_hInterruptTransfer)
            (*m_lpUsbFuncs->lpCloseTransfer)(m_hInterruptTransfer);

            // 從USB鼠標(biāo)PIPE中讀數(shù)據(jù)
            m_hInterruptTransfer = (*m_lpUsbFuncs->lpIssueInterruptTransfer)
            (m_hInterruptPipe, MouseTransferCompleteStub, this,
            USB_IN_TRANSFER | USB_SHORT_TRANSFER_OK, // 表示讀數(shù)據(jù)
            min(m_pInterface->lpEndpoints[0].Descriptor.wMaxPacketSize,
            sizeof(m_pbDataBuffer)),
            m_pbDataBuffer,
            NULL);

            if (m_hInterruptTransfer == NULL)
            {
            DEBUGMSG(ZONE_ERROR,(L "!USBMouse: Error in IssueInterruptTransfer\r\n"));
            return FALSE;
            }
            else
            {
            DEBUGMSG(ZONE_TRANSFER,(L"USBMouse::SubmitInterrupt,Transfer:0x%X\r\n",
            m_hInterruptTransfer));
            }
            return TRUE;
            }

            // 處理鼠標(biāo)中斷傳輸?shù)臄?shù)據(jù)
            BOOL CMouse::HandleInterrupt()
            {
            DWORD dwError;
            DWORD dwBytes;

            DWORD dwFlags = 0;
            INT dx = (signed char)m_pbDataBuffer[1];
            INT dy = (signed char)m_pbDataBuffer[2];

            BOOL fButton1 = m_pbDataBuffer[0] & 0x01 ? TRUE : FALSE;
            BOOL fButton2 = m_pbDataBuffer[0] & 0x02 ? TRUE : FALSE;
            BOOL fButton3 = m_pbDataBuffer[0] & 0x04 ? TRUE : FALSE;

            if (!(*m_lpUsbFuncs->lpGetTransferStatus)(m_hInterruptTransfer, &dwBytes,&dwError))
            {
            DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error in GetTransferStatus(0x%X)\r\n"),
            m_hInterruptTransfer));
            return FALSE;
            }
            else
            {
            DEBUGMSG(ZONE_TRANSFER,(TEXT("USBMouse::HandleInterrupt, hTransfer 0x%X complete (%u bytes, Error:%X)\r\n"),
            m_hInterruptTransfer,dwBytes,dwError));
            }

            if (!SubmitInterrupt())
            return FALSE;

            if(dwError != USB_NO_ERROR)
            {
            DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error 0x%X in interrupt transfer\r\n"),dwError));
            return TRUE;
            }

            if(dwBytes < 3)
            {
            DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Invalid byte cnt %u from interrupt transfer\r\n"),dwBytes));
            return TRUE;
            }

            if(dx || dy)
            dwFlags |= MOUSEEVENTF_MOVE;

            if(fButton1 != m_fPrevButton1)
            {
            if(fButton1)
            dwFlags |= MOUSEEVENTF_LEFTDOWN;
            else
            dwFlags |= MOUSEEVENTF_LEFTUP;
            }

            if(fButton2 != m_fPrevButton2)
            {
            if(fButton2)
            dwFlags |= MOUSEEVENTF_RIGHTDOWN;
            else
            dwFlags |= MOUSEEVENTF_RIGHTUP;
            }

            if(fButton3 != m_fPrevButton3)
            {
            if(fButton3)
            dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
            else
            dwFlags |= MOUSEEVENTF_MIDDLEUP;
            }

            m_fPrevButton1 = fButton1;
            m_fPrevButton2 = fButton2;
            m_fPrevButton3 = fButton3;

            DEBUGMSG(ZONE_EVENTS,
            (TEXT("USBMouse event: dx:%d, dy:%d, dwFlags:0x%X (B1:%u, B2:%u, B3:%u)\r\n"),
            dx,dy,dwFlags,fButton1,fButton2,fButton3));

            // 通知系統(tǒng)產(chǎn)生鼠標(biāo)事件
            if (m_fReadyForMouseEvents)
            mouse_event(dwFlags, dx, dy, 0, 0);
            else
            m_fReadyForMouseEvents = IsAPIReady(SH_WMGR);

            return TRUE;
            }


            DWORD CALLBACK CMouse::MouseTransferCompleteStub(LPVOID lpvNotifyParameter)
            {
            CMouse * pMouse = (CMouse *)lpvNotifyParameter;
            return(pMouse->MouseTransferComplete());
            }

            // 數(shù)據(jù)傳輸完畢回調(diào)函數(shù)
            DWORD CMouse::MouseTransferComplete()
            {
            if (m_hEvent)
            SetEvent(m_hEvent);
            return 0;
            }


            ULONG CALLBACK CMouse::MouseThreadStub(PVOID context)
            {
            CMouse * pMouse = (CMouse *)context;
            return(pMouse->MouseThread());
            }

            // USB鼠標(biāo)線(xiàn)程
            DWORD CMouse::MouseThread()
            {
            DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: Worker thread started\r\n")));
            SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);

            if (SubmitInterrupt())
            {
            while (!m_fClosing)
            {
            WaitForSingleObject(m_hEvent, INFINITE);

            if (m_fClosing)
            break;

            if ((*m_lpUsbFuncs->lpIsTransferComplete)(m_hInterruptTransfer))
            {
            if (!HandleInterrupt())
            break;
            }
            else
            {
            RETAILMSG(1,(TEXT("!USBMouse: Event signalled, but transfer not complete\r\n")));
            // The only time this should happen is if we get an error on the transfer
            ASSERT(m_fClosing || (m_hInterruptTransfer == NULL));
            break;
            }
            }
            }
            RETAILMSG(1,(TEXT("USBMouse: Worker thread exiting\r\n")));
            return(0);
            }

            看 到了沒(méi)有,其實(shí)USB的驅(qū)動(dòng)程序編寫(xiě)就這么簡(jiǎn)單,類(lèi)似的其他設(shè)備,例如打印機(jī)設(shè)備,就有Bulk OUT PIPE,需要Bulk傳輸,那就需要了解一下IssueBulkTransfer()的應(yīng)用。當(dāng)然如果是開(kāi)發(fā)USB Mass Storage Disk的驅(qū)動(dòng),那就需要了解更多的協(xié)議,例如Bulk-Only Transport協(xié)議等。

            微軟的Windows CE.NET的Platform Build中已經(jīng)帶有USB Printer和USB Mass Storage Disk的驅(qū)動(dòng)的源代碼了,好好研究一下,你一定回受益非淺的。



            參考資料:
            1. 微軟出版社 <<Windows Ce Device Driver Kit>>
            2. <<Universal Serial Bus Specification 1.1>> 來(lái)自http:://www.usb.org

            posted on 2008-12-03 10:35 井泉 閱讀(1307) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            精品久久久久久久久午夜福利| 99久久精品免费看国产一区二区三区| 久久精品无码专区免费东京热| 久久超乳爆乳中文字幕| 久久水蜜桃亚洲av无码精品麻豆| 国产精品久久网| 欧美一级久久久久久久大| 精品国产青草久久久久福利| 一本色道久久88综合日韩精品| 亚洲精品无码久久毛片| 久久精品国产亚洲AV无码偷窥| 99久久99久久精品国产| 蜜臀久久99精品久久久久久小说| 欧美亚洲国产精品久久蜜芽| 久久亚洲AV无码精品色午夜麻豆| 99久久免费国产特黄| 性高湖久久久久久久久AAAAA| 久久精品国产亚洲AV香蕉| 天天影视色香欲综合久久| 久久免费精品一区二区| 久久综合88熟人妻| 精品久久亚洲中文无码| 久久精品视屏| 99久久99久久精品国产片| 久久精品中文闷骚内射| 久久久久久久97| 久久这里都是精品| 久久无码人妻精品一区二区三区| 久久99热国产这有精品| 人人狠狠综合久久88成人| 久久中文字幕人妻丝袜| 伊人久久无码精品中文字幕| 精品国产91久久久久久久a| 亚洲乱亚洲乱淫久久| 久久精品国产精品青草| 国产精品久久久久久搜索| 久久精品毛片免费观看| 久久免费的精品国产V∧| 久久综合九色综合网站| 国内精品久久久久影院日本| 色欲av伊人久久大香线蕉影院 |