• <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>

            USB系列之三:從你的U盤里讀出更多的內(nèi)容

            U盤是我們最常使用的一種USB設(shè)備,本文繼續(xù)使用DOSUSB做驅(qū)動(dòng),試圖以讀取扇區(qū)的方式讀取你的U盤。
                本文可能涉及的協(xié)議可能會(huì)比較多。
            一、了解你的U盤
                首先我們用上一篇文章介紹的程序usbview.exe去看一下你的U盤,我在本文中用于測(cè)試的U盤情況如下:
                Device Descriptor: (設(shè)備描述符)
                USB Address:             1
                Length:                  18
                Descriptor Type:         1
                USB Specification nr.:   0x0110
                Calss Code:              Class code specified by interface
                Subclass Code:           0x00
                Protocol Code:           0x00
                MAX Packet Size:         0x08
                Vendor ID:               0x058f
                Product ID:              0x9321
                Device Code:             0x0100
                Manufacture Index:       1
                Product Index:           2
                Serial Number Index:     0
                Number of Configuration: 1

                String Descriptor: (字符串描述符)
                Manufacturer: Alcor Micro
                Product: Mass Storage Device

                Configuration Descriptor: (配置描述符)
                Length:               9
                Descriptor Type:      2
                Total Length:         32
                Number of Interfaces: 1
                Configuration Value:  1
                Configuration Index:  0
                Attributes:           Bus Powered
                Max Power:            50mA

                Interface Descriptor: (接口描述符)
                Length:               9
                Descriptor Type:      4
                Interface Number:     0
                Alternate Setting:    0
                Number of Endpoints:  2
                Interface Class:      Mass Storage Device
                Interface Sub Class:  6
                Interface Protocol:   80
                Interface Index:      0

                Endpoint Descriptor: (端點(diǎn)描述符)
                Length:               7
                Descriptor Type:      5
                Endpoint Address:     
            1 OUT endpoint
                Attributes:           Bulk
                Max Packet Size:      64
                Interval:             0

                Endpoint Descriptor: (端點(diǎn)描述符)
                Length:               7
                Descriptor Type:      5
                Endpoint Address:     
            2 IN endpoint
                Attributes:           Bulk
                Max Packet Size:      64
                Interval:             0

                各種描述符的含義在以前的文章中介紹過了,或者去翻閱USB的specification,這里就不多說了,我們從接口描述符開始就一些關(guān)鍵點(diǎn)進(jìn)行一下說明。
                首先看接口描述符,Interface Class = 8,表明是Mass Storage Device;Sub Class = 6,表明執(zhí)行SCSI命令;Interface Protocol = 0x80,表明支持Bulk傳輸;另外,Number of Endpoints = 2,表明有兩個(gè)端點(diǎn)。
                兩個(gè)端點(diǎn)描述符要注意的是,Endpoint Address = 1的是OUT端點(diǎn),Endpoint Address = 2的是IN端點(diǎn),有些可能會(huì)不一樣;有些U盤可能還會(huì)有第三個(gè)端點(diǎn),比如支持中斷傳輸?shù)腢盤還會(huì)有一個(gè)Interrupt端點(diǎn),不過這都沒有關(guān)系。
                我大概看了我手頭有的5個(gè)U盤,都支持批量傳輸,且支持SCSI命令,所以,這可能是一個(gè)比較典型的例子,我們就以它為例。

            二、CBW(Command Block Wrapper)和CSW(Command Status Wrapper)

                在《USB系列之一》中,我們安裝了一個(gè)DOSUSB,在《USB系列之二》中,我們利用USBDOS讀取了所有的描述表,掌握這些內(nèi)容需要了解USB協(xié)議1.1(USB Specification Revision 1.1)即可,當(dāng)然還要了解USBDOS,不過這個(gè)比較簡(jiǎn)單。

                在系列一和系列二中,我們已經(jīng)對(duì)DOSUSB的一個(gè)數(shù)據(jù)結(jié)構(gòu)URB有所了解,本文中還要大量用到,我們還接觸了一個(gè)結(jié)構(gòu)叫device_request,這個(gè)結(jié)構(gòu)是在USB協(xié)議中定義的,用于向設(shè)備發(fā)送命令(Request),本文也會(huì)用到。

                與前面不同的是,前面的兩個(gè)系列可以針對(duì)任何USB設(shè)備,比如U盤、攝像頭、打印機(jī)等,而本文將只針對(duì)我們經(jīng)常使用的USB設(shè)備----U盤,如果你打算嘗試本文所介紹的內(nèi)容,請(qǐng)準(zhǔn)備好一個(gè)U盤,什么樣子的都行,或者是一個(gè)USB讀卡器,不過要記得插一張卡進(jìn)去,實(shí)際上本文所載范例就是使用一個(gè)USB的CF卡讀卡器完成的,不用擔(dān)心損害你的U盤中的數(shù)據(jù),本文不會(huì)對(duì)U盤進(jìn)行任何寫操作,僅僅做一些讀操作。

                這個(gè)系列中我們需要針對(duì)U盤讀更多的規(guī)范,如下:

                 不用為規(guī)范發(fā)愁,實(shí)際上,前兩個(gè)規(guī)范都很短,其中第一個(gè)對(duì)實(shí)際編程沒有什么作用,但最好看一下;第二個(gè)規(guī)范連目錄一共22頁(yè),其中13頁(yè)以前的內(nèi)容可以跳過(很多和USB Specification中相同),第三個(gè)規(guī)范主要看第6章,第四個(gè)規(guī)范主要看第5章,后兩個(gè)規(guī)范在編程時(shí)需要經(jīng)常翻閱,以便了解你正在實(shí)現(xiàn)的SCSI命令的具體格式和參數(shù)。

                本節(jié)我們主要介紹兩個(gè)新的數(shù)據(jù)結(jié)構(gòu),這兩個(gè)結(jié)構(gòu)都是在第二個(gè)規(guī)范中定義的。

                第一個(gè)數(shù)據(jù)結(jié)構(gòu)叫CBW(Command Block Wrapper)


                這個(gè)結(jié)構(gòu)將承載具體的與設(shè)備有關(guān)的命令發(fā)送到設(shè)備上去,這個(gè)結(jié)構(gòu)分成兩部分,第一部分從byte[0]--byte[14]共15個(gè)字節(jié),第而部分從byte[15]--byte[30]共16個(gè)字節(jié),整個(gè)數(shù)據(jù)結(jié)構(gòu)為31個(gè)字節(jié)。規(guī)范中并沒有定義第二部分的內(nèi)容,這是因?yàn)榈诙糠殖休d的具體的命令,既與命令集(SCSI命令集)有關(guān),也與具體的命令有關(guān),我們使用SCSI命令集,所以后16個(gè)字節(jié)的內(nèi)容在前面提到的后面兩個(gè)規(guī)范中有定義。

                比如我們要向設(shè)備發(fā)出一個(gè)SCSI命令I(lǐng)NQUIRY(我們姑且先不要管命令的含義),那么這個(gè)命令的結(jié)構(gòu)在SPC-3的第142頁(yè)有定義,如下:


                對(duì)于SCSI INQUIRY這條命令而言,CBW的第二部分的定義就是上面的這六個(gè)字節(jié),不同的命令,定義也會(huì)不同。

                好,我們回到CSW的結(jié)構(gòu)上來(lái),根據(jù)規(guī)范,dCBWSignature的值必須是0X43425355,其實(shí)就是USBC這幾個(gè)字母倒過來(lái),這是因?yàn)镃BW的字符順序是little endian(這個(gè)東東在以前有關(guān)網(wǎng)絡(luò)編程的文章中介紹過),而我們PC機(jī)中的字符順序是big endian,所以要顛倒一下,總之寫dCBWSignature = 0X43425355就OK了;dCBWTag僅僅是一個(gè)標(biāo)志,你可以填任何值,這里要先說一下CSW(Command Status Wrapper),我們每發(fā)出一個(gè)命令,設(shè)備都會(huì)返回一個(gè)CSW(這個(gè)東東下面很快就要介紹了),以說明命令的執(zhí)行狀態(tài),這個(gè)結(jié)構(gòu)中也有Signature和Tag這兩個(gè)字段,其中Tag字段和發(fā)出命令時(shí)CBW中的Tag字段相同,這樣就可以區(qū)分這個(gè)CSW是和那個(gè)CBW對(duì)應(yīng)的了,至于Signature,下面再說。

                下一個(gè)字段是dCBWDataTransferLength,表示的是當(dāng)這個(gè)命令發(fā)出后,我們希望設(shè)備返回?cái)?shù)據(jù)的字符數(shù)或者我們要向設(shè)備傳輸?shù)淖址麛?shù),本文僅涉及從設(shè)備返回?cái)?shù)據(jù),不涉及向設(shè)備傳輸數(shù)據(jù);舉例來(lái)說:我們發(fā)送INQIURY命令到設(shè)備,按照SPC-3第144頁(yè)的說明,該命令返回的數(shù)據(jù)至少為36個(gè)字節(jié),所以,此時(shí)這個(gè)字節(jié)應(yīng)該填36;再如:我們讀取U盤的一個(gè)扇區(qū),如果扇區(qū)的長(zhǎng)度是512個(gè)字節(jié),那么這個(gè)字段就要填512。

                再下來(lái)是bmCBWFlags字段,這個(gè)字段只有bit 7有意義,為0表示要向設(shè)備傳輸數(shù)據(jù),為1表示要從設(shè)備獲得數(shù)據(jù)。

                bCBWLUN字段總是填0,因?yàn)榻^大多數(shù)的U盤都不支持多LUN(Logical Unit Number),只有一個(gè)邏輯單元自然好嗎就是0了。

                bCBWCBLength字段是只CBW第二部分的長(zhǎng)度,像前面舉例的INQUIRY命令,長(zhǎng)度為6個(gè)字節(jié),則這個(gè)字段就應(yīng)該填6,再如:READ(10)命令的長(zhǎng)度是10個(gè)字節(jié)(SBC-2第42頁(yè)有定義),這個(gè)字段當(dāng)然要填10了。

                第二個(gè)要說的數(shù)據(jù)結(jié)構(gòu)是CSW,當(dāng)host向device發(fā)送一個(gè)CBW后,接著就可以從device收到數(shù)據(jù)(或者發(fā)數(shù)據(jù)到device),當(dāng)接受完所需的的數(shù)據(jù)后,就可以從device獲得一個(gè)CSW(Command Status Wrapper),CSW的結(jié)構(gòu)如下:

                 前面說過,在CBW中的dCBWSignature的值恒為:0x43425355,得到的CSW中的dCSWSignature的值為:0x53425355,dCSWTag與dCBWTag中的一致。

                在得到的CSW中,恒定有13個(gè)字節(jié),bCSWStatus的定義如下:

             

            三、發(fā)送命令和接收數(shù)據(jù)

                我們知道USB協(xié)議中定義了三種傳輸方式,控制傳輸、批量傳輸、中斷傳輸和實(shí)時(shí)傳輸,在《USB系列二》中我們一直都在使用控制傳輸,我們應(yīng)該比較熟悉了,本文中將涉及批量傳輸。

                我們?cè)谑褂每刂苽鬏敃r(shí),我們?cè)O(shè)置好URB啟動(dòng)傳輸事務(wù),相應(yīng)的結(jié)果將返回到制定得buffer中,批量傳輸沒有那么簡(jiǎn)單,批量傳輸分為輸出事務(wù)和輸入事務(wù),我們應(yīng)該注意到,前面在看U盤的描述表時(shí),在端點(diǎn)這一級(jí)有兩個(gè)端點(diǎn),一個(gè)叫OUT端點(diǎn),一個(gè)叫IN端點(diǎn),當(dāng)我們啟動(dòng)一個(gè)輸出事務(wù)時(shí),一定要發(fā)送給OUT端點(diǎn),當(dāng)我們啟動(dòng)一個(gè)輸入事務(wù)時(shí),一定要發(fā)送到輸入端點(diǎn)。下面我們簡(jiǎn)單描述一下如何啟動(dòng)批量傳輸事務(wù)。

                在使用控制傳輸時(shí),我們應(yīng)該閱讀過DOSUSB的說明,并且對(duì)URB結(jié)構(gòu)比較熟悉,URB中有一個(gè)字段叫transation_type,當(dāng)這個(gè)值為0x2d時(shí)為控制傳輸;當(dāng)為0x69時(shí)為批量傳輸?shù)腎N事務(wù);當(dāng)為0xe1時(shí)為批量傳輸?shù)腛UT事務(wù);當(dāng)我們啟動(dòng)一個(gè)傳輸時(shí),一定要正確地設(shè)置這個(gè)值。

                我們以一個(gè)具體的例子來(lái)說明如何啟動(dòng)一個(gè)傳輸,我們以SCSI INQUIRY命令為了,關(guān)于這個(gè)命令的定義在SPC-3的第142頁(yè)--157頁(yè)有說明,篇幅很長(zhǎng),但絕大多數(shù)篇幅用來(lái)解釋返回?cái)?shù)據(jù)的含義,我們可以暫時(shí)不去理會(huì)。首先我們要填寫CBW結(jié)構(gòu),CBW結(jié)構(gòu)的第一部分的填寫前面已經(jīng)說的很明白了,第二部分的定義在SPC-3的第142頁(yè),共有6個(gè)字節(jié),我們要按照定義填寫好,實(shí)際上只要填兩個(gè)字段,一個(gè)是OPERATION CODE = 0X12,第二個(gè)就是ALLOCATION CODE = 36,表示需要返回36個(gè)字節(jié)的內(nèi)容;CBW填好后,我們開始填寫URB,首先把CBW的偏移和段地址放到URB的buffer_off和buffer_seg中,把transation_type=0xe1,表示一個(gè)輸出事務(wù),注意把end_point字段一定要放OUT endpoint的地址,從前面的描述符表中看,應(yīng)該是1(2是IN endpoint的地址,你的機(jī)器可能不同),其它字段的填法在《USB系列二》中已經(jīng)介紹過了,填完以后調(diào)用DOSUSB,這樣,一個(gè)承載著INQUIRY命令的輸出事務(wù)就發(fā)送到由URB中dev_add和end_point兩個(gè)字段指定的端點(diǎn)上去了。

                接下來(lái)我們要接收device返回的執(zhí)行INQUIRY命令的結(jié)果,這要啟動(dòng)一個(gè)輸入事務(wù),相對(duì)容易一些,只要填寫URB就可以了,把transation_type=0x69,把end_point填上OUT endpoint的地址,本例中為2,buffer_off和buffer_seg指向緩沖區(qū)buffer,把buffer_length和actual_length均填為64,因?yàn)榍懊娑它c(diǎn)描述符表中寫明包的最大長(zhǎng)度為64,其它字段按常規(guī)填寫,調(diào)用DOSUSB,在buffer中就可以得到返回的內(nèi)容,按照SPC-3中對(duì)返回內(nèi)容的解釋即可了解設(shè)備的一些情況。

                接收晚數(shù)據(jù)后,不要忘了接收CSW,方法也是啟動(dòng)一個(gè)輸入事務(wù),與接收數(shù)據(jù)完全相同,然后根據(jù)CSW的結(jié)構(gòu)解釋其含義。至此一個(gè)命令執(zhí)行完畢。

            四、范例

                在本文的范例中,我們實(shí)現(xiàn)了如下內(nèi)容:

            • 實(shí)現(xiàn)了Bulk-Only Mass Storage Reset
            • 實(shí)現(xiàn)了Get Max LUN
            • 實(shí)現(xiàn)了SCSI INQUIRY Command
            • 實(shí)現(xiàn)了SCSI READ CAPACITY (10) Command
            • 實(shí)現(xiàn)了SCSI REQUEST SENSE Command
            • 實(shí)現(xiàn)了SCSI TEST UNIT READY Command
            • 實(shí)現(xiàn)了SCSI READ (10) Command

                最后的一個(gè)命令,我將從你的U盤上讀出一個(gè)扇區(qū)。

                最前面的兩個(gè)命令,請(qǐng)翻閱《Universal Serial Bus Mass Storage Class - Bulk-Only Transport》第7頁(yè);INQUIRY、REQUEST SENSE、TEST UNIT READY三個(gè)命令請(qǐng)翻閱SPC-3的第142、221和232頁(yè);READ CAPACITY(10)和READ(10)命令,請(qǐng)翻閱SBC-2的第42和44頁(yè)。

                源代碼請(qǐng)?jiān)谙旅婢W(wǎng)址下載:

                http://blog.hengch.com/source/reader.rar

                各種概念在前面已經(jīng)介紹過了,程序無(wú)非就是實(shí)現(xiàn)這些概念,幾乎所有的代碼都是圍繞著填寫數(shù)據(jù)結(jié)構(gòu)和顯示返回結(jié)果的,所以代碼本身并不難,更重要的是理解數(shù)據(jù)結(jié)構(gòu)中個(gè)字段的含義,這可能不得不閱讀一些規(guī)范,我想我不可能比規(guī)范說的更嚴(yán)謹(jǐn)更完整。要注意的是,你使用的U盤不可能和我的完全一致,一般情況下有可能有變化的是:設(shè)備地址devAddr、輸出端點(diǎn)地址outEndpoint和輸入端點(diǎn)地址inEndpoint,所以在編譯程序之前一定要使用《USB系列之二》中的方法仔細(xì)查看一下你的U盤的各種描述符表,如果這些值和我的U盤不同,請(qǐng)?jiān)谥鞒绦蜷_始的地方,更改這幾個(gè)變量;另外,在主程序6th step中,scsiRead10(0),傳遞給scsiRead10的參數(shù)為0,含義是從LBA(Logical Block Address)為0的地方讀取一個(gè)扇區(qū),如果你向讀取其它扇區(qū),可以更改這個(gè)值,其最大值我們?cè)趯?shí)現(xiàn) READ CAPACITY時(shí)已經(jīng)讀出了,可以參考;此外,注意CBW的字符順序是little endian,所以我們?cè)谔顚慙BA和讀取最大LBA時(shí)都做了相應(yīng)的轉(zhuǎn)換。

                好了,應(yīng)該沒有什么了!

                Enjoy it.

            posted on 2010-11-24 14:09 wrh 閱讀(1399) 評(píng)論(1)  編輯 收藏 引用

            評(píng)論

            # re: USB系列之三:從你的U盤里讀出更多的內(nèi)容 2012-07-17 17:53 王飛

            請(qǐng)教個(gè)問題,傳輸數(shù)據(jù)塊時(shí),可傳輸數(shù)據(jù)塊大小是由什么決定的呢?   回復(fù)  更多評(píng)論   


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


            導(dǎo)航

            <2012年1月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            2930311234

            統(tǒng)計(jì)

            常用鏈接

            留言簿(19)

            隨筆檔案

            文章檔案

            收藏夾

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            国产精品热久久无码av| 精品久久久久久无码中文字幕 | 久久天天躁狠狠躁夜夜avapp| 婷婷综合久久中文字幕蜜桃三电影| 久久精品亚洲一区二区三区浴池| 久久久久久人妻无码| 97精品国产97久久久久久免费| 久久久精品久久久久久| 亚洲AV无一区二区三区久久| 国产成人久久激情91| 亚洲国产日韩综合久久精品| 久久精品人人做人人妻人人玩| 国産精品久久久久久久| 亚洲AV成人无码久久精品老人| 久久精品国产一区二区| 久久婷婷五月综合色高清| 精品久久久久久无码中文野结衣| 久久综合给合久久狠狠狠97色| 久久人妻少妇嫩草AV蜜桃| 国产午夜免费高清久久影院| 久久亚洲AV成人无码| 久久精品国产精品亚洲艾草网美妙| 香蕉久久av一区二区三区| 久久青青草原精品国产软件| 久久国产精品国产自线拍免费| 亚洲精品国产字幕久久不卡| 亚洲国产一成久久精品国产成人综合 | 久久青青草原综合伊人| 亚洲AV无码成人网站久久精品大| 久久亚洲国产精品五月天婷| 国产精品久久久久久影院| 欧美午夜精品久久久久免费视| 色欲综合久久躁天天躁| 久久久亚洲精品蜜桃臀| 国产A级毛片久久久精品毛片| 久久国产精品99久久久久久老狼 | 婷婷久久综合九色综合九七| 大蕉久久伊人中文字幕| 成人精品一区二区久久久| 91精品国产高清久久久久久91| 婷婷综合久久狠狠色99h|