青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Windows主機端與自定義USB HID設備通信詳解

  Windows主機端與自定義USB HID設備通信詳解 收藏

Windows主機端與自定義USB HID設備通信詳解

 

說明:

-          以下結論都是基于 Windows XP 系統所得出的,不保證在其他系統的適用性。

-          在此討論的是 HID 自定義設備,對于標準設備,譬如 USB 鼠標和鍵盤,由于操作系統對其獨占,許多操作未必能正確執行。

 

1 .   所使用的典型 Windows API

CreateFile

ReadFile

WriteFile

以下函數是 DDK 的內容:

HidD_SetFeature

HidD_GetFeature

HidD_SetOutputReport

HidD_GetInputReport

其中, CreateFile 用于打開設備; ReadFile 、 HidD_GetFeature 、 HidD_GetInputReport 用于設備到主機方向的數據通信; WriteFile 、 HidD_SetFeature 、 HidD_SetOutputReport 用于主機到設備方向的數據通信。鑒于實際應用,后文主要討論 CreateFile , WriteFile , ReadFile , HidD_SetFeature 四個函數,明白了這四個函數,其它的可以類推之。

 

2 .   幾個常見錯誤

       當使用以上 API 時,如果操作失敗,調用 GetLastError() 會得到以下常見錯誤:

       6 :          句柄無效

       23 :        數據錯誤(循環冗余碼檢查)

       87 :        參數錯誤

       1784 :     用戶提供的 buffer 無效

       后文將會詳細說明這些錯誤情況。

 

3.         主機端設備枚舉程序流程

 

 

4.         函數使用說明

CreateFile(devDetail->DevicePath,                                         // 設備路徑

               GENERIC_READ | GENERIC_WRITE,                    // 訪問方式

               FILE_SHARE_READ | FILE_SHARE_WRITE,         // 共享模式

               NULL,

               OPEN_EXISTING,                                           // 文件不存在時,返回失敗

               FILE_FLAG_OVERLAPPED,                                 // 以重疊(異步)模式打開

               NULL);

 

在這里, CreateFile 用于打開 HID 設備,其中設備路徑通過函數 SetupDiGetInterfaceDeviceDetail 取得。 CreateFile 有以下幾點需要注意:

 

-     訪問方式: 如果是系統獨占設備,例如鼠標、鍵盤等等,應將此參數設置為 0 ,否則后續函數操作將失敗(譬如 HidD_GetAttributes );也就是說,不能對獨占設備進行除了查詢以外的任何操作,所以能夠使用的函數也是很有限的,下文的一些函數并不一定適合這些設備。在此順便列出 MSDN 上關于此參數的說明:

If this parameter is zero, the application can query file and device attributes without accessing the device. This is useful if an application wants to determine the size of a floppy disk drive and the formats it supports without requiring a floppy in the drive. It can also be used to test for the file's or directory's existence without opening it for read or write access 。

-          重疊(異步)模式:此參數并不會在此處表現出明顯的意義,它主要是對后續的 WriteFile , ReadFile 有影響。如果這里設置為重疊(異步)模式,那么在使用 WriteFile , ReadFile 時也應該使用重疊(異步)模式,反之亦然。這首先要求 WriteFile , ReadFile 的最后一個參數不能為空( NULL )。否則,便會返回 87 (參數錯誤)錯誤號。當然, 87 號錯誤并不代表就是此參數不正確,更多的信息將在具體講述這兩個函數時指出。此參數為 0 時,代表同步模式,即 WriteFile , ReadFile 操作會在數據處理完成之后才返回,否則阻塞在函數內部。

 

ReadFile(hDev,                                 // 設備句柄,即 CreateFile 的返回值

              recvBuffer,                          // 用于接收數據的 buffer

              IN_REPORT_LEN,              // 要讀取數據的長度

              &recvBytes,                         // 實際收到的數據的字節數

              &ol);                                  // 異步模式

 

在這里, ReadFile 用于讀取 HID 設備通過中斷 IN 傳輸發來的輸入報告 。有以下幾點要注意:

 

1 、 ReadFile 的調用不會引起設備的任何反應,即 HID 設備與主機之間的中斷 IN 傳輸不與 ReadFile 打交道。實際上主機會在最大間隔時間(由設備的端點描述符來指定)內輪詢設備,發出中斷 IN 傳輸的請求。“讀取”即意味著從某個 buffer 里面取回數據,實際上這個 buffer 就是 HID 設備驅動中的 buffer 。這個 buffer 的大小可以通過 HidD_SetNumInputBuffers 來改變。在 XP 上缺省值是 32 (個報告)。

 

2 、讀取的數據對象是輸入報告,也即通過中斷輸入管道傳入的數據。所以,如果設備不支持中斷 IN 傳輸,那么是無法使用此函數來得到預期結果的。實際上這種情況不可能在 HID 中出現,因為協議指明了至少要有一個中斷 IN 端點。

 

3 、 IN_REPORT_LEN 代表要讀取的數據的長度(實際的數據正文 + 一個 byte 的報告 ID ),這里是一個常數,主要是因為設備固件的信息我是完全知道的,當然知道要讀取多少數據(也就是報告的長度);不過也可以通過另外的函數( HidD_GetPreparsedData )來事先取得報告的長度,這里不做詳細討論。因為很難想象在不了解固件信息的情況下來做自定義設備的 HID 通信,在實際應用中一般來說就是固件與 PC 程序匹配著來開發。此參數如果設置過大,不會有實質性的錯誤,在 recvBytes 參數中會輸出實際讀到的長度;如果設置過小,即小于報告的長度,會返回 1784 號錯誤(用戶提供的 buffer 無效)。

 

4 、關于異步模式。前面已經提過,此參數的設置必須與 CreateFile 時的設置相對應,否則會返回 87 號錯誤(參數錯誤)。如果不需要異步模式,此參數需置為 NULL 。在這種情況下, ReadFile 會一直等待直到數據讀取成功,所以會阻塞住程序的當前過程。

 

       WriteFile(hDev,                                 // 設備句柄,即 CreateFile 的返回值

                     reportBuf,                           // 存有待發送數據的 buffer

                     OUT_REPORT_LEN,           // 待發送數據的長度

                     &sendBytes,                        // 實際收到的數據的字節數

                     &ol);                                  // 異步模式

 

       在這里, WriteFile 用于傳輸一個輸出報告 給 HID 設備。有以下幾點要注意:

 

1、  與 ReadFile 不同, WriteFile 函數被調用后,雖然也是經過驅動程序,但是最終會反映到設備中。也就是說,調用 WriteFile 后,設備會接收到輸出報告的請求。如果設備使用了中斷 OUT 傳輸,則 WriteFile 會通過中斷 OUT 管道來進行傳輸;否則會使用 SetReport 請求通過控制管道來傳輸。

 

2、  OUT_REPORT_LEN 代表要寫入的數據長度(實際的數據正文 + 一個 byte 的報告 ID )。如果大于實際報告的長度,則使用實際報告長度;如果小于實際報告長度,會返回 1784 號錯誤(用戶提供的 buffer 無效)。

 

3、  reportBuf [0] 必須存有待發送報告的 ID ,并且此報告 ID 指示的必須是輸出報告,否則會返回 87 號錯誤(參數錯誤)。這種情況可能容易被程序員忽略,結果不知錯誤號所反映的是什么,網上也經常有類似疑問的帖子。順便指出,輸入報告、輸入報告、特征報告這些報告類型,是反映在 HID 設備的報告描述符中。后文將做舉例討論。

 

4、  關于異步模式。前面已經提過,此參數的設置必須與 CreateFile 時的設置相對應,否則會返回 87 號錯誤(參數錯誤)。如果不需要異步模式,此參數需置為 NULL 。在這種情況下, WriteFile 會一直等待直到數據讀取成功,所以會阻塞住程序的當前過程。

 

HidD_SetFeature(hDev,                                    // 設備句柄,即 CreateFile 的返回值

                     reportBuf,                                   // 存有待發送數據的 buffer

                     FEATURE_REPORT_LEN);        //buffer 的長度

HidD_SetOutputReport(hDev,                            // 設備句柄,即 CreateFile 的返回值

                     reportBuf,                                   // 存有待發送數據的 buffer

                     OUT_REPORT_LEN);                //buffer 的長度

 

HidD_SetFeature 發送一個特征報告 給設備, HidD_ SetOutputReport 發送一個輸出報告 給設備。注意以下幾點:

 

1、  跟 WriteFile 類似,必須在 reportBuf [0] 中指明要發送的報告的 ID ,并且和各自適合的類型相對應。也就是說, HidD_SetFeature 只能發送特征報告,因此報告 ID 必須是特征報告的 ID ; HidD_SetOutputReport 只能發送輸出報告,因此報告 ID 只能是輸出報告的 ID 。

2、  這兩個函數最常返回的錯誤代碼是 23 (數據錯誤)。包括但不僅限于以下情況:

- 報告 ID 與固件描述的不符。

- 傳入的 buffer 長度少于固件描述的報告的長度。

據有關資料反映(非官方文檔),只要是驅動程序對請求無反應,都會產生此錯誤。

 

5.         常見錯誤匯總

- HID ReadFile

  - Error Code 6 (handle is invalid)

    傳入的句柄無效

  - Error Code 87 ( 參數錯誤 )

    很可能是 createfile 時聲明了異步方式,但是讀取時按同步讀取。

  - Error Code 1784 ( 用戶提供的 buffer 無效 ):

    傳參時傳入的“讀取 buffer 長度”與實際的報告長度不符。

 

- HID WriteFile

  - Error Code 6 (handle is invalid)

    傳入的句柄無效

  - Error Code 87 (參數錯誤)

    - CreateFile 時聲明的同步 / 異步方式與實際調用 WriteFile 時傳入的不同。

    - 報告 ID 與固件中定義的不一致( buffer 的首字節是報告 ID )

  - Error Code 1784 ( 用戶提供的 buffer 無效 )

    傳參時傳入的“寫入 buffer 長度”與實際的報告長度不符。

 

- HidD_SetFeature

- HidD_SetOutputReport

  - Error Code 1 (incorrect function)

    不支持此函數,很可能是設備的報告描述符中未定義這樣的報告類型(輸入、輸出、特征)

  - Error Code 6 (handle is invalid)

    傳入的句柄無效

  - Error Code 23 (數據錯誤(循環冗余碼檢查))

    - 報告 ID 與固件中定義的不相符( buffer 的首字節是報告 ID )

    - 傳入的 buffer 長度少于固件定義的報告長度(報告正文 +1byte, 1byte 為報告 ID )

    - 據相關資料反映(非官方文檔),只要是驅動程序不接受此請求(對請求無反應),都會產生此錯誤

 

6.         報告描述符及數據通信程序示例

報告描述符(由于是匯編代碼,所以不必留意其語法,僅需注意表中的每個數據都占 1 個字節):

 

_ReportDescriptor:                              // 報告描述符

       .dw 0x06,  0x00, 0xff               // 用法頁

    .dw 0x09,  0x01                     // 用法 ( 供應商用法 1)

    .dw 0xa1,  0x01                      // 集合開始

    .dw 0x85,  0x01                         // 報告 ID(1)

    .dw 0x09,  0x01                  // 用法 ( 供應商用法 1)  

    .dw 0x15,  0x00                 // 邏輯最小值 (0)

    .dw 0x26,  0xff, 0x0                     // 邏輯最大值 (255)

    .dw 0x75,  0x08               // 報告大小 (8)

    .dw 0x95,  0x07                        // 報告計數 (7)

    .dw 0x81,  0x06                // 輸入 (數據,變量,相對值)

 

    .dw 0x09,  0x01                     // 用法 ( 供應商用法 1)  

    .dw 0x85,  0x03                         // 報告 ID ( 3 )

    .dw 0xb1,   0x06                         // 特征 (數據,變量,相對值)

 

       .dw 0x09,  0x01                    // 用法 ( 供應商用法 1)

    .dw 0x85,  0x02                         // 報告 ID ( 2 )

    .dw 0xb1,  0x06                         // 特征 (數據,變量,相對值)

 

     .dw 0x09,  0x01                     // 用法 ( 供應商用法 1)  

    .dw 0x85,  0x04                         // 報告 ID ( 4 )

    .dw 0x91,   0x06                         // 輸出 (數據,變量,相對值)

    .dw   0xc0                    // 結合結束

_ReportDescriptor_End:

 

這個報告描述符,定義了 4 個不同的報告:輸入報告 1 ,特征報告 2 ,特征報告 3 ,輸出報告 4 (數字代表其報告 ID )。為了簡化,每個報告都是 7 個字節(加上報告 ID 就是 8 個字節)。下面用一個簡單的示例來描述 PC 端與 USB HID 設備進行通信的一般方法。

 

view plaincopy to clipboardprint?
#define     USB_VID       0xFC0   
#define     USB_PID       0x420   
HANDLE OpenMyHIDDevice(int overlapped);   
void HIDSampleFunc()   
{   
    HANDLE       hDev;   
    BYTE         recvDataBuf[8];   
    BYTE         reportBuf[8];   
    DWORD        bytes;   
    hDev = OpenMyHIDDevice(0);                                // 打開設備,不使用重疊(異步)方式 ;   
    if (hDev == INVALID_HANDLE_VALUE)   
        return;   
    reportBuf[0] = 4;                                         // 輸出報告的報告 ID 是 4   
    memset(reportBuf, 0, 8);   
    reportBuf[1] = 1;   
    if (!WriteFile(hDev, reportBuf, 8, &bytes, NULL))         // 寫入數據到設備   
         return;   
    ReadFile(hDev, recvDatatBuf, 8, &bytes, NULL);            // 讀取設備發給主機的數據   
}   
    
HANDLE OpenMyHIDDevice(int overlapped)   
{   
    HANDLE hidHandle;   
    GUID hidGuid;   
    HidD_GetHidGuid(&hidGuid);   
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&hidGuid,   
                                            NULL,   
                                            NULL,   
                                            (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));   
    if (hDevInfo == INVALID_HANDLE_VALUE)   
    {   
        return INVALID_HANDLE_VALUE;   
    }   
    SP_DEVICE_INTERFACE_DATA devInfoData;   
    devInfoData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);   
    int deviceNo = 0;   
    SetLastError(NO_ERROR);   
    while (GetLastError() != ERROR_NO_MORE_ITEMS)   
    {   
        if (SetupDiEnumInterfaceDevice (hDevInfo,   
                                        0,   
                                       &hidGuid,   
                                       deviceNo,   
                                       &devInfoData))   
        {   
            ULONG  requiredLength = 0;   
            SetupDiGetInterfaceDeviceDetail(hDevInfo,   
                                            &devInfoData,   
                                            NULL,   
                                            0,   
                                            &requiredLength,   
                                             NULL);  
            PSP_INTERFACE_DEVICE_DETAIL_DATA devDetail = (SP_INTERFACE_DEVICE_DETAIL_DATA*) malloc (requiredLength);   
            devDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);   
            if(!SetupDiGetInterfaceDeviceDetail(hDevInfo,   
                                                 &devInfoData,   
                                                 devDetail,   
                                                 requiredLength,   
                                                 NULL,   
                                                 NULL))   
            {   
                free(devDetail);   
                SetupDiDestroyDeviceInfoList(hDevInfo);   
                return INVALID_HANDLE_VALUE;   
            }   
            if (overlapped)   
            {   
                hidHandle = CreateFile(devDetail->DevicePath,   
                                       GENERIC_READ | GENERIC_WRITE,   
                                       FILE_SHARE_READ | FILE_SHARE_WRITE,   
                                       NULL,   
                                       OPEN_EXISTING,           
                                       FILE_FLAG_OVERLAPPED,   
                                       NULL);   
            }   
            else   
            {   
                hidHandle = CreateFile(devDetail->DevicePath,   
                                       GENERIC_READ | GENERIC_WRITE,   
                                       FILE_SHARE_READ | FILE_SHARE_WRITE,   
                                       NULL,   
                                       OPEN_EXISTING,           
                                       0,   
                                       NULL);   
            }   
            free(devDetail);   
            if (hidHandle==INVALID_HANDLE_VALUE)   
            {   
                SetupDiDestroyDeviceInfoList(hDevInfo);   
                free(devDetail);   
                return INVALID_HANDLE_VALUE;   
            }   
            _HIDD_ATTRIBUTES hidAttributes;   
            if(!HidD_GetAttributes(hidHandle, &hidAttributes))   
            {   
                CloseHandle(hidHandle);   
                SetupDiDestroyDeviceInfoList(hDevInfo);   
                return INVALID_HANDLE_VALUE;   
            }   
            if (USB_VID == hidAttributes.VendorID   
                && USB_PID  == hidAttributes.ProductID)   
            {   
                break;   
            }   
            else   
            {   
                CloseHandle(hidHandle);   
                ++deviceNo;   
            }   
        }   
    }   
    SetupDiDestroyDeviceInfoList(hDevInfo);   
    return hidHandle;   
}


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/kevinyujm/archive/2009/06/12/4264506.aspx

posted on 2010-11-18 09:12 wrh 閱讀(6445) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


導航

<2025年11月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

統計

常用鏈接

留言簿(19)

隨筆檔案

文章檔案

收藏夾

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            美女视频一区免费观看| 在线亚洲精品| 欧美护士18xxxxhd| 欧美jjzz| 麻豆成人在线播放| 欧美中文字幕在线| 香蕉成人久久| 久久久国产精彩视频美女艺术照福利| 亚洲综合999| 久久九九国产| 老司机一区二区| 欧美激情五月| 亚洲视频 欧洲视频| 午夜精品一区二区三区在线播放| 亚洲欧美久久久| 久久久最新网址| 欧美日韩亚洲一区二| 国产欧美亚洲视频| 亚洲肉体裸体xxxx137| 亚洲综合精品| 欧美成人午夜激情在线| 亚洲毛片在线| 久久久国产精品一区二区三区| 欧美大尺度在线| 国产亚洲精品久久久久婷婷瑜伽| 亚洲精品日韩在线观看| 欧美在线免费视屏| 最近中文字幕日韩精品 | 香蕉久久夜色精品| 久久精品人人爽| 亚洲精品午夜精品| 久久精品av麻豆的观看方式| 欧美日韩一区二区精品| 伊伊综合在线| 午夜精品影院| 欧美激情1区2区| 久久aⅴ国产欧美74aaa| 欧美日韩精品是欧美日韩精品| 欧美夫妇交换俱乐部在线观看| 最新亚洲视频| 久久久爽爽爽美女图片| 在线视频你懂得一区| 欧美va天堂在线| 在线成人h网| 国产美女一区| 亚洲视频免费在线观看| 欧美激情一区二区三区高清视频 | 一区二区高清| 欧美成人免费在线视频| 在线播放中文字幕一区| 久久久999精品免费| 亚洲综合电影一区二区三区| 久久久噜噜噜| 久久精品综合网| 午夜精品一区二区三区在线播放| 欧美视频日韩视频| 亚洲午夜羞羞片| 亚洲国产精品久久| 免费视频亚洲| 亚洲精品久久久久中文字幕欢迎你 | 亚洲伊人网站| 亚洲伦伦在线| 亚洲日本欧美在线| 欧美极品在线播放| 亚洲剧情一区二区| 亚洲破处大片| 欧美日韩mv| 亚洲无线观看| 亚洲网站在线看| 国产欧美在线| 麻豆91精品91久久久的内涵| 久久久久网址| 午夜精品亚洲| 欧美在线三区| 亚洲国产日韩欧美| 亚洲日本无吗高清不卡| 欧美视频在线免费| 欧美一二三区精品| 久久精品成人| 亚洲人永久免费| 一本色道久久综合| 国产欧美日韩综合一区在线播放 | 亚洲一区二区三区四区中文| 欧美视频在线观看视频极品 | 在线天堂一区av电影| 亚洲午夜久久久久久久久电影院 | 亚洲精品一区在线| 国产精品―色哟哟| 久久综合色播五月| 欧美精品aa| 欧美与黑人午夜性猛交久久久| 国产在线拍偷自揄拍精品| 中文欧美在线视频| 欧美一激情一区二区三区| 亚洲韩国青草视频| 亚洲一区二区黄色| 亚洲黄色尤物视频| 午夜一区二区三区不卡视频| 亚洲国内自拍| 亚洲欧美日韩国产一区| 影音先锋中文字幕一区| 免费欧美电影| 国产精品免费看| 欧美国产综合视频| 国产视频亚洲| 99亚洲视频| 在线日韩av永久免费观看| 亚洲天堂成人在线视频| 久久婷婷麻豆| 在线精品视频在线观看高清| 国产欧美日韩亚洲精品| 欧美福利一区二区| 亚洲欧美一区二区三区极速播放| 野花国产精品入口| 国内外成人免费激情在线视频| 亚洲天堂网在线观看| 亚洲黄一区二区三区| 久久国产直播| 亚洲黄页一区| 亚洲精品乱码久久久久久日本蜜臀 | 欧美激情一区二区三区蜜桃视频| 亚洲丝袜av一区| 国产麻豆日韩欧美久久| 欧美在线观看视频在线| 欧美77777| 欧美亚洲在线观看| 欧美日韩一区三区| 亚洲级视频在线观看免费1级| 国产精品爽黄69| 99精品国产热久久91蜜凸| 亚洲精品三级| 欧美国产综合视频| 亚洲国产欧美一区二区三区久久| 激情欧美一区二区三区在线观看| 亚洲一区二区三区在线观看视频| av成人国产| 欧美日韩国语| 在线一区二区日韩| 亚洲欧美偷拍卡通变态| 国产精品美女久久久浪潮软件| 99热在这里有精品免费| 亚洲私人影院在线观看| 欧美日韩亚洲视频| 亚洲视频免费看| 欧美一区二区在线看| 国产欧美一级| 久久亚洲二区| 亚洲国产婷婷综合在线精品| 亚洲人成在线观看| 欧美激情第9页| 99精品国产高清一区二区 | 亚洲在线日韩| 欧美一区二区视频观看视频| 国产精品九九久久久久久久| 亚洲一区免费| 久久在线播放| 日韩午夜av电影| 国产精品高潮呻吟久久av无限| 亚洲女优在线| 免费成人黄色av| 日韩视频一区二区在线观看| 欧美性大战久久久久| 好吊一区二区三区| 久久艳片www.17c.com| 亚洲精品韩国| 久久成人精品无人区| 在线观看日韩av电影| 欧美第一黄色网| 亚洲制服av| 欧美激情国产日韩精品一区18| 国产精品99久久久久久久久| 国产欧美日韩综合精品二区| 久久这里只有| 一本久道久久综合狠狠爱| 欧美在线三级| 亚洲美洲欧洲综合国产一区| 国产精品久久久久久久久婷婷| 久久久久国产免费免费| 99在线热播精品免费99热| 久久一区中文字幕| 亚洲一区二区三区午夜| 亚洲国产精品va| 国产欧美日韩亚洲| 欧美日本一区二区高清播放视频| 性8sex亚洲区入口| 亚洲日韩视频| 欧美不卡视频一区| 欧美一区在线视频| 亚洲无毛电影| 亚洲精选中文字幕| 一色屋精品亚洲香蕉网站| 国产精品美女一区二区| 欧美电影免费观看大全| 久久久99免费视频| 亚洲一区二区精品| 99国产精品久久久久久久久久| 亚洲第一免费播放区| 久久久精品动漫| 性色av一区二区三区红粉影视| 日韩一区二区精品葵司在线|