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

USB系列之二:讀取USB設備的描述符

在前面的文章中,我們已經給出了USB協議的鏈接地址,從這篇文章起,我們會涉及到許多USB 1.1的內容,我們的指導思想是先從熟悉USB 1.1協議入手,先使用現成的HCD和USBD,直接面對客戶端驅動編程,盡快看到成果,使讀者對USB的開發充滿信心,進而去研究USBD和HCD的編程方法。請讀者自行閱讀協議,文章中有關協議的詳細情況,由于會涉及非常多的文字,恕不能過多解釋。
1、USB系統主機端的軟件結構
    一般來說,教科書或者協議上都會把USB主機端的軟件說成有三層,第一層叫主機控制器驅動程序HCD(Host Controller Driver),第二層叫USB驅動程序USBD(USB Driver),第三層叫客戶端驅動程序(Client Driver);實際上,我們實際看到的東西,往往HCD和USBD是由一個程序完成的,比如windows就提供了HCD和USBD,如果你自己開發了一個USB設備,只需要在HCD和USBD上面開發一個客戶端驅動程序即可;linux也是同樣,linux內核已經提供了HCD和USBD;所以在windows和linux下我們基本上沒有開發HCD和USBD的必要,而且linux還提供源代碼;但DOS就不一樣了,DOS本身對USB沒有任何支持,所以要想在DOS下徹底玩轉USB,需要研究HCD、USBD和客戶端驅動程序。
2、DOSUSB介紹
    很顯然,HCD和USBD更加底層一些,需要理解的東西也更多一些;如果我們能夠繞過HCD和USBD,直接從客戶端驅動程序入手,將會容易許多。幸運的是我們可以找到一個免費的DOS下的USB驅動程序,叫DOSUSB,該驅動程序實現了大部分的HCD和USBD的功能,使我們進行USB編程的好幫手。
    DOSUSB目前還沒有實現EHIC的驅動,也就是說還不支持USB2.0,這也是我們從USB 1.1開始的原因之一,另一方面,由于USB2.0是兼容USB1.1的,所以,即便你在USB2.0的設備下,仍然可以使用USB1.1的驅動程序,只不過不能實現480MB/秒的傳送速度而已。
    下面我們介紹一下DOSUSB。DOSUSB的官方網站如下:
    http://www.usbdos.net

    可以從其官方網站上下載DOGUSB的最新版本,當前版本是1.1.1。或者在下面在下面網址下載這個版本的DOSUSB。

    http://blog.hengch.com/software/dosusb/dosusb.zip

    DOSUSB可以在非商業領域免費使用,如果肯花費費用,可以購買到源代碼,從其官方網站的論壇上看到,在2006年9月作者開出的源代碼的價格是1000歐元。

    DOSUSB的安裝十分簡便,只需要解壓縮到某一個目錄下即可,比如放在c:\dosusb目錄下,請自行閱讀DOSUSB自帶的文檔,使用也非常簡單,在DOS提示符下鍵入dosusb執行即可。

    c:\dosusb>dosusb

    缺省情況下,DOSUSB使用int 65h作為其驅動的調用軟中斷,如果和你的系統有沖突,在運行dosusb時可以加參數/I,請自行閱讀DOSUSB的文檔。

    DOSUSB通過一個叫做URB(USB Request Block)的數據結構與客戶端驅動程序進行通訊,這一點和linux非常相似,估計作者參考了linux下的源代碼,在DOSUSB文檔里給出了這個結構的定義,如下:
    struct {
      BYTE  transaction_type;   // 設置事務(控制傳輸)(2Dh),輸入事務(69h)輸出事務(E1h)
      BYTE  chain_end_flag;     // 備用
      BYTE  dev_add;            // 設備地址
      BYTE  end_point;          // 端點號
      BYTE  error_code;         // 錯誤嗎
      BYTE  status;             // 設備狀態
      WORD  transaction_flags;  // 備用
      WORD  buffer_off;         // 接收/發送緩沖區偏移地址
      WORD  buffer_seg;         // 接收/發送緩沖區段地址
      WORD  buffer_length;      // 接收/發送緩沖區長度
      WORD  actual_length;      // 接收/發送時每個包的最大長度
      WORD  setup_buffer_off;   // setup_request結構的偏移地址
      WORD  setup_buffer_seg;   // setup_request結構的段地址
      WORD  start_frame;        // 備用
      WORD  nr_of_packets;      // >0時會啟動實時傳輸
      WORD  int_interval;       // 備用
      WORD  error_count;        // 重試的次數
      WORD  timeout;            // 備用
      WORD  next_urb_off;       // 備用
      WORD  next_urb_seg;       // 備用
    } urb                       // 32字節
    之所以列出這個結構,是因為我們將使用這個結構與USBD進行交互。關于結構中字段的定義,在DOSUSB的文檔中有詳細的說明。除備用字段不需要填以外,error_code和status由DOSUSB返回,故填0即可,后面還會介紹更詳細的填寫方法。

    在DOSUSB的發行包中,有一個sample目錄,里面有很多例子,但大多是使用power basic寫的,不過仍然有很好的參考價值。

3、USB 1.1協議中的一些內容

    USB協議為USB設備定義了一套描述設備功能和屬性的固有結構的描述符,包括標準描述符(設備描述符、培植描述符、接口描述符、端點描述符和字符串描述符),還有費標準描述符,如類描述符等。按照協議,設備描述符下可以有若干個配置描述符,每個配置描述符可以有若干個接口描述符,每個接口描述符下又可以有若干個端點描述符,字符串描述符主要用于描述一些文字信息,比如廠家名稱,產品名稱等。這篇文章的目的就是要讀出這些描述符。

    實際上,所謂描述符就是一個數據結構,不管是什么描述符,其前兩個字節的含義都是一樣的,第一個字節是描述符的長度,第二個字節是描述符的類型。

  • 設備描述符(Device Descriptor):

    struct {
      BYTE    bLength;            // 描述符的長度,以字節為單位
      BYTE    bDescriptorType;    // 設備描述符類型,0x01
      WORD    bcdUSB;             // 設備支持的USB協議版本,BCD碼
      BYTE    bDeviceClass;       // 設備類代碼(由USB-IF分配)
      BYTE    bDeviceSubClass;    // 子類代碼
      BYTE    bDeviceProtocol;    // 協議碼
      BYTE    bMaxPacketSize0;    // 端點0的最大包長度(僅為8,16,32,64)
      WORD    idVendor;           // 廠商ID(由USB-IF分配)
      WORD    idProduct;          // 產品ID(由制造商定義)
      WORD    bcdDevice;          // 設備發行號(BCD碼)
      BYTE    iManufacture;       // 描述廠商信息的字符串描述符的索引值
      BYTE    iProduct;           // 描述產品信息的字符串描述符的索引值
      BYTE    iSerialNumber;      // 描述設備序列號信息的字符串描述符的索引值
      BYTE    bNumConfigurations; // 可能的配置描述符的數目
    } device_descriptor

  • 配置描述符(Configuration Descriptor)

    struct {
      BYTE    bLength;             // 描述符的長度,以字節為單位
      BYTE    bDescriptorType;     // 配置描述符類型,0x02
      WORD    wTotalLength;        // 配置信息的總長
      BYTE    bNumInterfaces;      // 該配置所支持的接口數目
      BYTE    bConfigurationValue; // 被SetCongiguration()請求用做參數來選定該配置
      BYTE    bConfiguration;      // 描述該配置的字符串描述符的索引值
      BYTE    bmAttributes;        // 配置特性
      BYTE    MaxPower;            // 該配置下的總線電源耗費量,以2mA為一個單位 
    }configuration_descriptor;

    bmAttributes :b7:備用,b6:自供電,b5:遠程喚醒,b4--b0:備用

    另外,在讀取配置描述符時可以把該配置下的所有描述符全部讀出,這些描述符的總長度就是wTotalLength字段的值,讀出所有描述符后,在一個一個地拆分。

  • 接口描述符(Interface Descriptor):

    struct {
      BYTE    bLength;            // 描述符的長度,以字節為單位
      BYTE    bDescriptorType;    // 接口描述符類型,0x04
      BYTE    bInterfaceNumber;   // 接口號,從0開始
      BYTE    bAlternateSetting;  // 可選設置的索引值.
      BYTE    bNumEndpoints;      // 此接口的端點數量。 
      BYTE    bInterfaceClass;    // 接口類編碼(由USB-IF分配)
      BYTE    bInterfaceSubClass; // 接口子類編碼(由USB-IF分配)
      BYTE    bInterfaceProtocol; // 協議碼(由USB-IF分配)
      BYTE    iInterface;         // 描述該接口的字符串描述符的索引值
    }interface_descriptor;

    bInterfaceClass:USB協議根據功能將不同的接口劃分成不同的類,如下:

    1:音頻類,2:CDC控制類,3:人機接口類(HID),5:物理類,6:圖像類,7:打印機類,8:大數據存儲類,9:集線器類,10:CDC數據類,11:智能卡類,13:安全類,220:診斷設備類,224:無線控制類,254:特定應用類,255廠商定義的設備。

  •  端點描述符(Endpoint Descriptor):

    struct {
      BYTE    bLength;            // 描述符的長度,以字節為單位
      BYTE    bDescriptorType;    // 端點描述符類型,0x05
      BYTE    bEndpointAddress;   // 端點地址
      BYTE    bmAttributes;       // 在bconfigurationValue所指的配置下的端點特性.
      WORD    wMaxPacketSize;     // 接收/發送的最大數據報長度. 
      BYTE    bInterval;          // 周期數據傳輸端點的時間間隙.
    }endpoint_descriptor;

    bmAttributes:bit 1:0--傳送類型,00=控制傳輸,01=實時傳輸,10=批量傳輸,11=中斷傳輸;所有其他位均保留。

  • 字符串描述符(String Descriptor):

    struct {
      BYTE    bLength;            // 描述符的長度,以字節為單位
      BYTE    bDescriptorType;    // 字符串描述符類型,0x03
      char    bString[];          // UNICODE編碼的字符串
    }string_descriptor;

  • USB命令請求(USB DEVICE REQUEST)

    為了更好地協調USB主機與設備之間的數據通信,USB規范定義了一套命令請求,用于完成主機對總線上所有USB設備的統一控制,USB命令請求由統一的格式,其結構如下:

    struct {
      BYTE  bmRequestType;  // 請求類型
      BYTE  bRequest;       // 命令請求的編碼
      WORD  wValue;         // 命令不同,含義不同
      WORD  wIndex;         // 命令不同,含義不同 
      WORD  wLength;        // 如果有數據階段,此字段為數據字節數

    }
 setup_request;

    后面我們向設備發出指令就全靠這個結構了。作為我們本文要用到的讀取USB設備描述符的命令請求,該結構各字段的填法如下。

    bmRequestType : b7--數據傳輸方向,0=主機到設備,1=設備到主機;b6:5--命令的類型,0=標準命令,1=類命令,2=廠商提供的命令,3=保留;b4:0--接收對象,0=設備,1=接口,2=端點,3=其他。我們發出的得到描述符的命令,數據傳輸方向為設備到主機,標準命令,接收對象為設備,所以該字段填0x80。

    bRequest : 標準命令的編碼如下,GET_STATUS=0;CLEAR_FEATURE=1;SET_FEATURE=3;SET_ADDRESS=5;GET_DESCRIPTOR=6;SET_DESCRIPTOR=7;GET_CONFIGURATION=8;SET_CONFIGURATION=9;GET_INTERFACE=10;SET_INTERFACE=11;SYNCH_FRAME=12。我們的命令是GET_DESCRIPTOR,所以應該填6。

    wValue : 高字節表示描述符的類型,0x01=設備描述符,0x02=配置描述符,0x03=字符串描述符,0x04=接口描述符,0x05=端點描述符,0x29=集線器類描述符,0x21=人機接口類描述符,0xFF=廠商定義的描述符。

    低字節表示表示描述符的索引值。所以,當讀取設備描述符時,該字段值為0x100,當讀取配置描述符是,應為0x03yy,其中yy為描述符的索引值。

    wIndex : 當讀取字符串描述符時,填0x0409,表示希望獲得英文字符串,其他情況下填0。

    wLength : 數據長度,一般應該填寫,描述符的第一個字節,bLength。由于我們在讀描述符時,并不知道其實際長度,通常的做法是先讀取8個字節,然后根據第一個字節bLength的值在重新讀取一次完整的描述符;注意,當讀取配置描述符的錢8個字節后,應該使用wTotalLength字段的值作為長度讀取與該配置有關的所有描述符。

4、讀取設備描述符的范例程序

    按照我們文章的習慣,幾乎每篇文章都有一個范例程序,本文也不例外,本文的范例程序請在下面地址下載:

    http://blog.hengch.com/source/usbview.zip

    程序用C++寫成,在DJGPP下編譯通過,所以是32位保護模式下的代碼,要注意的是,DOSUSB是實模式下的驅動,所以在申請內存塊時要申請1M以內實模式可以讀取的內存,否則,在使用int 65h調用DOSUSB時一定會出現問題。

    有4個頭文件,public.h中定義了一些方便使用的數據類型,比如BYTE為char,WORD為short int等等,可以不必太關注;x86int.h中定義了調用DOS中斷所需的函數和數據結構,直到怎么使用就可以了;dosmem.h中定義了一個DOS_MEM類,主要是為了在保護模式下申請和使用DOS內存塊更為方便,也是知道其中的方法,能夠明白程序中的意義就可以了;usb.h定義了與USB協議有關的所有常數,這些常數與前面介紹的各種數據結構一一對應,由于我們是在保護模式下使用DOS內存,所以把一個內存塊映射到一個數據結構上有一些麻煩,讀取各個字段主要靠在usb.h中定義的這些常數。

    主要程序在usbview.cc中,主要思路如下:

  • USB設備的地址從1--127,所以我們從1--127做一個循環,逐一讀取USB設備描述符,直到出現“非法地址”為止。
  • 每一個USB設備的設備描述符只有一個,所以我們從讀取某個地址下的設備描述符開始。
  • 開始我們并不知道設備描述符的長度,即便我們知道其長度為18個字符,但我們仍然不知道端點0允許的包長度(設備描述符中bMaxPacketSize0字段),但我們知道包長度的最小值是8,所以我們先讀取8個字節的設備描述符。
  • 在我們得到8個字符的設備描述符后,我們就可以得到該描述符的長度和端點0的包長度,在后面發出的所有命令中,始終要把這個值填在URB結構的actual_length字段中。
  • buffer用于存放USBD返回的描述符,在使用前建議初始化一下,全部清0。
  • 要向設備發出命令請求(Request),需要先填setup_request結構,前面講過,bmRequestType=0x80,bRequest=6,這兩個字段的填法始終不變;我們現在讀取設備描述符,所以wValue=0x100,wIndex=0,wLength在首次調用時填8,第二次調用時填返回的bLength字段(應該是18)。
  • 準備好buffer和setup_request后,我們要填URB一邊與DOSUSB交互;讀取描述符是一個控制傳輸,所以transaction=0x2D(后面一直是0x2D);dev_add填上面提到的循環變量;end_point=0,因為我們總對端點0(見USB協議);buffer_off和buffer_seg分別填buffer的便宜地址和段地址;setup_buffer_off和setup_buffer_seg分別填前面setup_request結構的偏移地址和段地址;buffer_length同setup_request結構中的wLength,也可以把值設在wLength和buferr的最大長度之間,如果buffer的最大長度小于wLength,我們只能填buffer的最大長度,但這種情況下我們將得不到完整的描述符;actual_length在第一次調用時填8,以后一直填返回的bMaxPacketsize0字段;其他字段均為0。
  • 讓DS:DX指向剛剛填完的URB結構,調用軟中斷65h,DOSUSB將為你處理下面的事情。
  • 如果正常,error_code應該返回0,如果非0,含義如下:
    1--非法的設備地址;2--內部錯誤;3--非法的transation_type字段;4--非法的buffer長度。
  • 如果正常,status字段應該為0,該字段是是USB控制器返回的狀態字節,不同的控制器(OHCI或UHCI)會返回不同的值。
  • 當我們得到設備描述符后,如果設備描述符中的iManufacturer字段不為0,我們可以根據這個所引值得到相應的字符串描述符,從而顯示出廠家信息,要注意的是字符串描述符是UNICODE編碼,對于ASCII而言,它是一個ASSCII碼跟一個ASCII 0組成;同理我們可以得到產品信息和序列號信息。
  • 當我們得到了設備的設備描述符后,我們就可以知道這個設備上有多少個配置(設備描述符中的bNumConfigurations),進而通過一個循環得到所有的配置描述符及其配置下的所有描述符。
  • 讀取配置描述符的方法與讀取設備描述符大同小異,也是先讀取8個字節,然后根據返回的內容再讀取所有的描述符內容,要注意的是,實際上,我們不能單獨得到接口描述符和端點描述符,唯一的辦法是把一個配置下的描述符全部讀出來,所以setup_request結構中的wLength字段一定要與配置描述符中返回的wTotalLength值一致才行。
  • 剩下的事情就是如何顯示我們得到的描述符,我想這對每一位讀者而言都不是什么困難的事。

posted on 2010-11-24 14:06 wrh 閱讀(2932) 評論(0)  編輯 收藏 引用

導航

<2011年8月>
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

統計

常用鏈接

留言簿(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>
            久久阴道视频| 欧美网站在线观看| 欧美在线免费视屏| 亚洲精品免费一区二区三区| 在线国产精品一区| 18成人免费观看视频| 国产有码在线一区二区视频| 国产精品美女www爽爽爽视频| 欧美日韩视频在线一区二区| 欧美激情1区2区| 欧美日韩亚洲系列| 欧美涩涩网站| 国产欧美丝祙| 亚洲国产精品ⅴa在线观看| 99国产精品自拍| 正在播放欧美一区| 亚洲欧美综合另类中字| 久久xxxx| 欧美电影在线观看| 一区二区三区四区精品| 亚洲午夜电影| 久久久久看片| 欧美激情综合| 国产一区二区三区久久精品| 91久久综合| 久久精品理论片| 蜜桃精品久久久久久久免费影院| 亚洲国产精品一区二区第四页av| 亚洲天堂成人在线视频| 麻豆av一区二区三区| 国产精品久久中文| 亚洲精品美女久久久久| 欧美在线关看| 夜夜嗨av一区二区三区免费区| 性做久久久久久久久| 免费在线观看精品| 国产伦精品一区二区三区视频黑人 | 亚洲高清资源| 亚洲欧美日韩一区二区三区在线观看| 久久婷婷一区| 国产精品毛片大码女人| 亚洲乱码久久| 久久久国产视频91| 久久久久久久一区| 国产日本欧美一区二区三区| av成人手机在线| 午夜久久久久| 亚洲第一主播视频| 欧美一区二区三区四区高清| 欧美三级视频| 亚洲高清三级视频| 久久免费国产| 亚洲尤物精选| 国产精品久久久久av免费| 亚洲国产精品高清久久久| 美女日韩欧美| 性欧美长视频| 在线播放日韩| 欧美大片在线观看| 久久精品一区二区三区中文字幕 | 国产精品久久激情| 一二美女精品欧洲| 亚洲国产美国国产综合一区二区| 久久久国产精品一区二区三区| 国产精品久久久久久久久免费樱桃| 日韩亚洲欧美在线观看| 亚洲精品1234| 欧美日韩在线电影| 亚洲综合欧美日韩| 亚洲一区精彩视频| 国产在线观看91精品一区| 久久婷婷蜜乳一本欲蜜臀| 久久久午夜视频| 亚洲欧洲一区二区天堂久久| 亚洲电影免费在线| 欧美涩涩网站| 久久久久久电影| 美女脱光内衣内裤视频久久影院| 亚洲三级电影全部在线观看高清| 最新国产拍偷乱拍精品| 国产精品久久国产三级国电话系列| 亚洲综合精品| 久久精品日韩| 99riav国产精品| 99re6这里只有精品| 国产日韩欧美一区二区| 久久综合导航| 欧美激情亚洲另类| 亚洲欧美不卡| 久久久人成影片一区二区三区| 日韩视频一区二区在线观看 | 久久精品欧美日韩精品| 日韩视频精品在线观看| 亚洲欧美国产77777| 亚洲成人影音| 亚洲欧美日韩在线| 欧美性猛交视频| 久久久久成人精品| 欧美激情在线免费观看| 欧美综合国产精品久久丁香| 快she精品国产999| 午夜欧美大片免费观看| 暖暖成人免费视频| 久久精品五月婷婷| 欧美日韩三级一区二区| 老司机精品导航| 国产精品色婷婷| 日韩一级片网址| 亚洲国产精品成人va在线观看| 亚洲网址在线| 9i看片成人免费高清| 久久九九有精品国产23| 亚洲欧洲av一区二区三区久久| 欧美大片在线观看| 美女国产一区| 国内成人在线| 午夜精品久久久久久久99樱桃 | 欧美一级视频| 欧美日韩在线影院| 亚洲日本激情| 亚洲卡通欧美制服中文| 裸体一区二区| 亚洲国产成人在线播放| 一区在线播放视频| 欧美一区午夜精品| 香蕉av777xxx色综合一区| 欧美久久视频| 91久久香蕉国产日韩欧美9色| 原创国产精品91| 久久久青草青青国产亚洲免观| 久久久精品国产99久久精品芒果| 国产精品一区二区在线观看| 在线一区视频| 亚洲欧美日韩国产一区二区| 国产精品高潮呻吟视频| 99亚洲精品| 亚洲欧美视频在线| 国产伦精品一区二区三区高清| 亚洲一区二区三区乱码aⅴ| 亚洲视频观看| 国产乱码精品一区二区三区五月婷| 亚洲深夜福利| 久久不射电影网| 狠狠色伊人亚洲综合成人| 久久综合伊人77777麻豆| 亚洲高清毛片| 一本色道久久88精品综合| 欧美性一区二区| 午夜老司机精品| 美国十次了思思久久精品导航| 亚洲激情六月丁香| 欧美日韩国产综合视频在线观看| 夜夜爽99久久国产综合精品女不卡| 亚洲一区二区欧美日韩| 国产伦精品一区二区三区照片91 | 久久夜精品va视频免费观看| 国产小视频国产精品| 久久久久久网站| 欧美国产日韩一区| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 日韩一级免费| 国产精品hd| 欧美一区二区三区视频在线观看| 麻豆成人综合网| 一区二区欧美在线| 国产婷婷精品| 欧美电影资源| 亚洲男女自偷自拍图片另类| 久久综合色8888| a91a精品视频在线观看| 国产精品一二三| 免费亚洲一区二区| 亚洲中字在线| 亚洲高清成人| 久久久久久久久久久成人| 亚洲免费观看在线观看| 国产一区二区三区四区三区四| 欧美96在线丨欧| 午夜亚洲影视| 99re热这里只有精品视频| 久久综合综合久久综合| 亚洲一区美女视频在线观看免费| 激情成人亚洲| 国产精品国产三级国产专播品爱网| 欧美在线视频导航| 一区二区毛片| 亚洲国产精品久久久久秋霞不卡 | 国产综合久久久久久鬼色| 欧美另类亚洲| 欧美/亚洲一区| 久久成人精品无人区| 一本久久综合亚洲鲁鲁五月天| 嫩草影视亚洲| 久久精品日韩欧美| 亚洲女同在线| 亚洲综合成人在线| 亚洲一区二区3| 9l国产精品久久久久麻豆| 最近中文字幕日韩精品 | 欧美一级欧美一级在线播放|