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

PDF全文下載地址:http://download.csdn.net/source/2320280
http://bbs.driverdevelop.com/read.php?tid-120461.html

《USB 軟件結(jié)構(gòu) 》

 

軟件結(jié)構(gòu)比硬件來(lái)的復(fù)雜很多。因?yàn)樗嗽S多從表面上看不到的層次。比如總線驅(qū)動(dòng)、功能驅(qū)動(dòng)、過(guò)濾驅(qū)動(dòng)等。套用社會(huì)學(xué)的話,這體現(xiàn)了功能應(yīng)用中的分工和統(tǒng)籌。下面我們逐層來(lái)看它們。

  總線驅(qū)動(dòng)
總線驅(qū)動(dòng)位于驅(qū)動(dòng)棧的最低層,處理復(fù)雜的任務(wù),必須資源分配,子設(shè)備管理。作為下層驅(qū)動(dòng),負(fù)責(zé)處理上層驅(qū)動(dòng)發(fā)下來(lái)的請(qǐng)求。 USB 設(shè)備中的總線驅(qū)動(dòng)主要有兩類(lèi):控制器驅(qū)動(dòng)、 HUB 驅(qū)動(dòng);另外還有一個(gè)端口驅(qū)動(dòng)。

1 ) 控制器驅(qū)動(dòng): Ushohci.sys 、 Usbuhci.sys 、 Usbehci.sys 。

首先解釋一下 HCI ,它是主機(jī)控制接口( Host Control Interface )的縮寫(xiě)。前后一共有三種 HCI 協(xié)議出現(xiàn): USB 1.1 時(shí)代,有 OHCI (開(kāi)發(fā) HCI )協(xié)議和 UHCI (通用 HCI )協(xié)議; USB2.0 時(shí)代,有 EHCI (擴(kuò)展 HCI )協(xié)議。三個(gè)協(xié)議分別對(duì)應(yīng)了上面的三個(gè)驅(qū)動(dòng)程序。因?yàn)?USB 是向后兼容的,所以 UsbEHC.sys 中也包含了 UsbOhci 和 UsbUhci 的功能。請(qǐng)看下圖。

 


圖 1 總線設(shè)備 

上圖中設(shè)備 1 、 3 是控制器設(shè),從名稱上就可以區(qū)別它們的不同: Universal Host Controller 和 Enhanced Host Controller 。所以設(shè)備 1 的驅(qū)動(dòng)程序是 USBUhci.sys ,設(shè)備 3 的驅(qū)動(dòng)程序是 USBEhci.sys 。

這說(shuō)明同一臺(tái)主機(jī)特別是筆記本電腦中, 1.1 和 2.0 的控制器并存,像筆記本電腦中的鍵盤(pán)通過(guò)內(nèi)置 USB 接口與系統(tǒng)連接,其數(shù)據(jù)吞吐量小,只需要 1.1 的控制器就能滿足;而暴露在外供用戶使用的接口則需要 2.0 。

2) Hub 驅(qū)動(dòng): UsbHub.sys 。 Hub 驅(qū)動(dòng)是所有 USB 設(shè)備的父驅(qū)動(dòng)。下圖描繪了這一景況:


圖2


上圖中看到, Hub 驅(qū)動(dòng)的子設(shè)備要不是獨(dú)立設(shè)備,如左側(cè)圖;要么是一個(gè)含有多個(gè)子設(shè)備的父設(shè)備,如右側(cè)圖。 Hub 驅(qū)動(dòng)只為直系子設(shè)備創(chuàng)建唯一的物理設(shè)備對(duì)象。上圖中, Hub 驅(qū)動(dòng)為設(shè)備 1 和設(shè)備 2 創(chuàng)建物理設(shè)備對(duì)象,但并不為設(shè)備 2 的子設(shè)備創(chuàng)建物理設(shè)備對(duì)象。

3 ) Port 驅(qū)動(dòng): UsbPort.sys 。這是個(gè)框架驅(qū)動(dòng),比較復(fù)雜,很少人會(huì)用到。而上面的 Ushohci.sys 、 Usbuhci.sys 、 Usbehci.sys 其實(shí)都是他的微端口驅(qū)動(dòng)。對(duì)于這么偏門(mén)的框架,不提也罷。

  系統(tǒng)類(lèi)驅(qū)動(dòng)
所以出現(xiàn)類(lèi)驅(qū)動(dòng),體現(xiàn)了 USB 總線在應(yīng)用上的繁榮景象。只有用得多了,才有被歸類(lèi)的可能。就像人類(lèi)社會(huì)中有幾百個(gè)國(guó)家,幾千個(gè)民族,正是體現(xiàn)了人類(lèi)這個(gè)團(tuán)體的多樣性與繁榮。只有在“多”的基礎(chǔ)上,分類(lèi)才是有必要的;少數(shù)人的小群體,再怎么獨(dú)立特行,也都不足以被分類(lèi),甚至定義為“ XX 民族”。

USB 設(shè)備包含很多的通用的功能類(lèi),比如: USB 集線器設(shè)備, USB HID 設(shè)備, USB 音頻設(shè)備, USB MIDI 設(shè)備, USB 存儲(chǔ)設(shè)備。為了讓開(kāi)發(fā)工作變得更加簡(jiǎn)單, Windows 操作系統(tǒng)為他們提供了系統(tǒng)驅(qū)動(dòng)程序。

大部分時(shí)候,系統(tǒng)類(lèi)驅(qū)動(dòng)就是功能驅(qū)動(dòng)。下表是系統(tǒng)提供的 USB 類(lèi)驅(qū)動(dòng)。

 

USB 類(lèi)名稱
 類(lèi)代碼
 驅(qū)動(dòng)名稱
 系統(tǒng)支持
 
藍(lán)牙設(shè)備
 0xE0
 Bthusb.sys
 Vista 、 XP
 
USB 芯片智能卡接口設(shè)備
(CCID)
 0x0B
 Usbccid.sys
 2K 、 XP 、 2K3 、 Vista 、 2K8
 
Hub 設(shè)備
 0x09
 Usbhub.sys
 2K 、 XP 、 2K3 、 Vista 、 2K8
 
HID 設(shè)備
 0x03
 Hidusb.sys
 2K 、 XP 、 2K3 、 Vista 、 2K8
 
USB 大容量存儲(chǔ)設(shè)備
 0x08
 Usbstor.sys
 2K 、 XP 、 2K3 、 Vista 、 2K8
 
打印設(shè)備
 0x07
 Usbprint.sys
 2K 、 XP 、 2K3 、 Vista 、 2K8
 
掃描設(shè)備
 0x06
 WpdUsb.sys Usbscan.sys
 2K 、 XP 、 2K3 、 Vista 、 2K8
 
媒體傳輸設(shè)備 (MTP)
 0x06
 WpdUsb.sys
 XP 、 2K3 、 Vista 、 2K8
 
音頻設(shè)備
 0x01
 Usbaudio.sys
 2K 、 XP 、 2K3 、 Vista 、 2K8
 
Modem 設(shè)備 (CDC)
 0x02
 Usbser.sys
 2K 、 XP 、 2K3 、 Vista 、 2K8
 
視頻設(shè)備 (UVC)
 0x0E
 Usbvideo.sys
 XP 、 Vista
 

 

表 1   系統(tǒng)提供的 USB 類(lèi)驅(qū)動(dòng)

 

功能驅(qū)動(dòng)
 

不是所有的 USB 設(shè)備都有類(lèi)驅(qū)動(dòng),但功能驅(qū)動(dòng)卻是它們唯一的身份證。沒(méi)有功能驅(qū)動(dòng),設(shè)備就不足以在系統(tǒng)中存在。它的作用是為設(shè)備創(chuàng)造一個(gè)獨(dú)一無(wú)二的內(nèi)核設(shè)備對(duì)象( DEVICE_OBJCET ),并因此而在需要的時(shí)候,系統(tǒng)能夠通過(guò)此內(nèi)核設(shè)備對(duì)象找到它。

如果要讓用戶層也能夠知道并使用 USB 設(shè)備,功能驅(qū)動(dòng)更加不可少。它為設(shè)備在用戶程序可見(jiàn)的名字空間中,為它起一個(gè)別名,這個(gè)別名可以是一個(gè)符號(hào)鏈接,也可以是一個(gè)由 GUID 定義的設(shè)備 Interface 。通過(guò)對(duì)這個(gè)別名進(jìn)行操作,也就是對(duì)設(shè)備本身進(jìn)行操作。

OK ,上面的話說(shuō)得太滿了,有例外的!唯一的例外是以 RAW 模式驅(qū)動(dòng)的設(shè)備。這種設(shè)備直接由總線驅(qū)動(dòng)來(lái)驅(qū)動(dòng)其工作,不需要功能驅(qū)動(dòng)。這種例子真的不多見(jiàn),也許只有很很底層的控制器設(shè)備、 Hub 設(shè)備之類(lèi),才會(huì)這樣做。對(duì)于 RAW 模式驅(qū)動(dòng)的設(shè)備,當(dāng)收到 IRP_MN_QUERY_CAPABILITIES 查詢請(qǐng)求的時(shí)候,在返回的 DEVICE_CAPABILITIES 結(jié)構(gòu)體中,必須將 RawDeviceOK 位設(shè)置為 TRUE 。

建議讀者在需要的時(shí)候使用 WinOBJ.exe 工具查看系統(tǒng)空間中的設(shè)備與別名。

 

父驅(qū)動(dòng)與混合設(shè)備
 

通過(guò)一定的設(shè)置, USB 設(shè)備中的每個(gè)接口可以擁有不同的 Class 和 Protocol 定義,從而實(shí)現(xiàn):一個(gè)設(shè)備,多個(gè)功能。這種設(shè)備被稱為混合設(shè)備。混合設(shè)備的前提是擁有多個(gè)接口,對(duì)單接口設(shè)備談 “ 混合 ” 是沒(méi)有意義的。

滿足了如下兩個(gè)條件的多接口 USB 設(shè)備,被系統(tǒng)認(rèn)為是混合設(shè)備:

1.         設(shè)備描述符中,設(shè)備類(lèi)的值為 0 : (bDeviceClass , bDeviceSubClass, bDeviceProtocol ) = (0, 0, 0);

2.         只有唯一的配置描述符,即設(shè)備描述符中: (bNumConfigurations ) = (1)

 

從 WinXP SP2 以后,還支持另外一種混合設(shè)備的判別方式,稱作: Interface Association Descriptor ( IAD )。其實(shí) IAD 描述符是用來(lái)組織 “ 接口組( Interfaces Group ) ” 的。配置描述符中可以有多個(gè) IAD 存在,如果將某兩個(gè)接口將組成接口組,那么首先這兩個(gè)接口必須是緊挨著的,其次,必須有一個(gè) IAD 描述符位于這兩個(gè)接口描述符的前面,也必須是緊挨著的, IAD 描述符中的 bFirstInterface 用來(lái)描述接口組中的第一個(gè)接口 ID , bInterfaceCount 用來(lái)描述接口組中包含多少個(gè)接口。這樣接口集合 : [bFirstInterface, bFirstInterface+bInterfaceCount) 為一個(gè)接口組。

當(dāng)然,能夠用上 IAD 的設(shè)備,一定是有多接口存在了,否則就是多此一舉了。 IAD 描述符的識(shí)別和實(shí)現(xiàn)是通用父驅(qū)動(dòng)完成的,所以有 IAD 支持的設(shè)備,都被認(rèn)作混合設(shè)備。而識(shí)別設(shè)備是否有 IAD 支持,是通過(guò)設(shè)備描述符中的如下值判斷的:

(bDeviceClass, bDeviceSubClass, bDeviceProtocol) = (0xEF, 0x02, 0x01)

IAD 普及率不是很廣,一個(gè)原因就是 XP sp2 以后的操作系統(tǒng)版本才對(duì)它支持,這樣如果把設(shè)備插入到 Win 2000 甚至 XP SP1 上,都不能被正確識(shí)別。這樣,廠商可能必須為不同的系統(tǒng)寫(xiě)兩套驅(qū)動(dòng)程序。

我們下面來(lái)說(shuō)說(shuō)當(dāng)一個(gè)多接口混合設(shè)備插入電腦后,系統(tǒng)是如何識(shí)別它,并為它加載驅(qū)動(dòng)的。這里大家要注意到一點(diǎn),就是系統(tǒng)是如何把一個(gè)設(shè)備,通過(guò)多接口,識(shí)別為多個(gè)物理設(shè)備的。

一開(kāi)始,系統(tǒng) PNP 管理器安裝常規(guī),讀取并分析 USB 設(shè)備描述符,然后為它分配如下設(shè)備 ID :

 

USB\VID_vvvv&PID_pppp

USB\VID_vvvv&PID_pppp&REV_rrrr

(vvvv, pppp, rrrr: 4 位 16 進(jìn)制數(shù),分別代表了廠商 ID ,產(chǎn)品 ID , USB 版本。對(duì)應(yīng)于設(shè)備描述符中的這些值: idVendor/ idProduct/ bcdDevice)

 

和兼容 ID :

 

USB\COMPOSITE

 

PNP 管理器首先按照常規(guī),根據(jù)上述的設(shè)備 ID 為設(shè)備尋找合適的驅(qū)動(dòng)程序:根據(jù)設(shè)備 ID 到注冊(cè)表的設(shè)備安裝信息庫(kù)(對(duì)應(yīng)于 Enum 和 Class 兩個(gè)鍵)中進(jìn)行搜索,如果找到了安裝記錄,就根據(jù)記錄中的信息加載驅(qū)動(dòng)程序。

問(wèn)題是如果找不到合法的記錄怎么辦?這時(shí)候就用的著兼容 ID 了,兼容 ID “ USB\COMPOSITE ”是在系統(tǒng)中有注冊(cè)記錄的,并且就對(duì)應(yīng)著通用父設(shè)備驅(qū)動(dòng)( USBCCGP.sys) 。于是,系統(tǒng)為混合設(shè)備加載通用父設(shè)備驅(qū)動(dòng)。讀者可到目錄 Windows\Inf 下查看 usb.inf 文件,此文件中包含了通用父設(shè)備驅(qū)動(dòng)的安裝信息。

通用父設(shè)備驅(qū)動(dòng)通過(guò)分析配置描述符,完成兩個(gè)動(dòng)作:首先為每個(gè) USB 接口分配一個(gè)的設(shè)備 ID 和兼容 ID ;然后為每個(gè) USB 接口創(chuàng)建一個(gè)物理設(shè)備對(duì)象( Physical Device Object )。設(shè)備 ID 形式如下:

 

USB\VID_vvvv&PID_pppp&MI_mm

USB\VID_vvvv&PID_pppp&REV_rrrr&MI_mm

(mm: 兩個(gè) 16 位數(shù)字表示的接口號(hào) )

 

根據(jù)接口描述符中的 clsss 類(lèi)型,分配兼容 ID ,其形式如下:

 

USB\CLASS_cc

USB\CLASS_cc&SUBCLASS_ss

USB\CLASS_cc&SUBCLASS_ss&PROT_pp

(cc/ ss / pp: 兩位 16 進(jìn)制數(shù)。分別對(duì)應(yīng)于接口描述符中的: bInterfaceClass/ bInterfaceSubClass/ bInterfaceProtocol)

 

通用父設(shè)備驅(qū)動(dòng)為每個(gè)接口創(chuàng)建了物理設(shè)備對(duì)象后,將接口的設(shè)備 ID 、兼容 ID 信息提交給 PNP 管理器, PNP 管理器就有責(zé)任為這些“虛假的”物理設(shè)備安裝驅(qū)動(dòng)。仍然重復(fù)上面的過(guò)程:根據(jù)每個(gè)接口的設(shè)備 ID 和兼容 ID 在注冊(cè)表的設(shè)備安裝信息庫(kù)中搜索,試圖找到相關(guān)的安裝記錄,如果找到了,就為接口加載相應(yīng)的驅(qū)動(dòng)程序。如果找不到,系統(tǒng)就會(huì)彈出“發(fā)現(xiàn)新設(shè)備”的對(duì)話框,啟動(dòng)驅(qū)動(dòng)安裝向?qū)А4藭r(shí)用戶需為這些接口手動(dòng)安裝驅(qū)動(dòng)。

所以,對(duì)于多接口的混合設(shè)備( composite device ),其設(shè)備驅(qū)動(dòng)的安裝分為兩個(gè)過(guò)程,先嘗試安裝混合驅(qū)動(dòng),如果找不到,就默認(rèn)安裝通用父設(shè)備驅(qū)動(dòng);接下來(lái)通用父設(shè)備驅(qū)動(dòng)為每個(gè)接口分配設(shè)備 ID ,并要求系統(tǒng)為每個(gè)接口啟動(dòng) PNP 過(guò)程。

最后,那么來(lái)說(shuō),在 USB 混合設(shè)備中,一定是 X 個(gè)接口對(duì)應(yīng)于 X 個(gè)功能設(shè)備(有一個(gè)物理設(shè)備對(duì)象)嗎?一般情況下是這樣的,但也有例外,這就是接口組:在符合一定條件的情況下,多個(gè)接口中的某些接口可以被組合為一個(gè)接口組,一個(gè)接口組代表一個(gè)功能,父設(shè)備驅(qū)動(dòng)只為之創(chuàng)建一個(gè)物理設(shè)備對(duì)象。

接口組的詳情,大家看后面的章節(jié)內(nèi)容。

 

過(guò)濾驅(qū)動(dòng)
 

過(guò)濾驅(qū)動(dòng)無(wú)處不在。在很多時(shí)候,它被稱作 Hook ,是一種 Hack 手段;很多時(shí)候它又是必不可少的,這種技術(shù)甚至被操作系統(tǒng)自己使用。沒(méi)有哪一個(gè)殺防毒軟件不使用過(guò)濾驅(qū)動(dòng),我們?cè)谑褂镁W(wǎng)上銀行的時(shí)候,會(huì)用到一些安全控件,基本上都借助了過(guò)濾驅(qū)動(dòng)的技術(shù)。

過(guò)濾驅(qū)動(dòng)可以位于任何一層驅(qū)動(dòng)的上面,或下面。過(guò)濾的對(duì)象也包括已經(jīng)存在于系統(tǒng)中的其他的過(guò)濾驅(qū)動(dòng)。當(dāng)它位于某層驅(qū)動(dòng)( D 驅(qū)動(dòng))上面的時(shí)候,所有目標(biāo)發(fā)往 D 驅(qū)動(dòng)的請(qǐng)求,都首先被它截取;當(dāng)它位于某層驅(qū)動(dòng)下面的時(shí)候,所有和 D 驅(qū)動(dòng)相關(guān)的從更底層驅(qū)動(dòng)反饋回來(lái)的的“完成消息”都預(yù)先被過(guò)濾驅(qū)動(dòng)截取。這正是它威力強(qiáng)大的原因所在。對(duì)于被過(guò)濾的驅(qū)動(dòng)來(lái)說(shuō),過(guò)濾驅(qū)動(dòng)簡(jiǎn)直就是它的先知了。

但使用過(guò)濾驅(qū)動(dòng),要很慎重。很容易把系統(tǒng)搞得很不穩(wěn)定。讀者在寫(xiě)過(guò)濾驅(qū)動(dòng)的時(shí)候,要明白這樣一件事:你想過(guò)濾誰(shuí),得先了解誰(shuí);好像你追求一個(gè)人,要先認(rèn)識(shí)這個(gè)人。否則死機(jī)藍(lán)屏都會(huì)與你不期而遇。

 

USB 驅(qū)動(dòng)棧、設(shè)備棧
 

請(qǐng)大家不要把這里的“棧”理解成“程序堆棧”的那個(gè)棧,朋友們要回到這個(gè)字最簡(jiǎn)單的本意來(lái)理解它,而不是想象成一個(gè)數(shù)據(jù)結(jié)構(gòu)。就看成草垛柴堆一樣。

驅(qū)動(dòng)棧、設(shè)備棧本質(zhì)上是并行概念。驅(qū)動(dòng)之間的聯(lián)系是通過(guò)設(shè)備對(duì)象進(jìn)行的,所以驅(qū)動(dòng)之間是間接聯(lián)系的,驅(qū)動(dòng)棧多少也就只是概念上的,他用來(lái)表示一個(gè)設(shè)備能夠在系統(tǒng)中識(shí)別、運(yùn)行,從上到下中共需要哪些驅(qū)動(dòng)程序支持。

設(shè)備棧則是由據(jù)可查的。系統(tǒng)中每個(gè) DevNode 就表現(xiàn)一個(gè)設(shè)備棧。可以這樣理解,多個(gè)設(shè)備棧,串聯(lián)成了驅(qū)動(dòng)棧。

使用 WinDBG 的 !devnode 命令,可以列舉系統(tǒng)中的設(shè)備樹(shù)。下圖截取了 CY001 相關(guān)片段。

 


圖 3 CY001 DevNode 片段 

上圖中紅色框標(biāo)出的三個(gè) DevNode ,正好對(duì)應(yīng)于三個(gè)內(nèi)核驅(qū)動(dòng),建立了 CY001 的驅(qū)動(dòng)棧。從上到下分別是控制器驅(qū)動(dòng) (usbEHCI) ,集線器驅(qū)動(dòng) (usbHUB) ,和功能驅(qū)動(dòng) (CY001) 。下圖以 CY001 為例,更加清晰詳細(xì)地描繪了驅(qū)動(dòng)棧、設(shè)備棧的面貌。


圖 4 CY001 的驅(qū)動(dòng)棧和設(shè)備棧 

上圖是單接口 CY001 設(shè)備的驅(qū)動(dòng)棧、設(shè)備棧全圖。也適用于所有其他的單接口 USB 設(shè)備。如果是多接口混合設(shè)備,就要多一個(gè)通用父驅(qū)動(dòng),稍微復(fù)雜一點(diǎn)。

最上面是可能存在的過(guò)濾驅(qū)動(dòng),因?yàn)橹皇?#8220;可能存在”,所以都用虛框表示。其實(shí)過(guò)濾驅(qū)動(dòng)可以存在于設(shè)備棧的任何一個(gè)位置,而不僅僅是最上層。筆者不可能盡皆畫(huà)全,以上層過(guò)濾為例,能說(shuō)明問(wèn)題也就可以了。

過(guò)濾驅(qū)動(dòng)生成的過(guò)濾設(shè)備對(duì)象,掛載到 CY001 驅(qū)動(dòng)生成的功能設(shè)備對(duì)象上;這樣所有發(fā)送給 CY001 功能設(shè)備對(duì)象的請(qǐng)求,過(guò)濾設(shè)備對(duì)象總是先得到。根集線器生成了 CY001 驅(qū)動(dòng)的物理設(shè)備對(duì)象。三個(gè)設(shè)備連在一起,就是 CY001 驅(qū)動(dòng)程序的設(shè)備棧。

但還沒(méi)有完,根集線器驅(qū)動(dòng)并不是最底層驅(qū)動(dòng),他必須得到控制器驅(qū)動(dòng)的支持,于是加上可能存在的過(guò)濾驅(qū)動(dòng),由此形成中間的那條設(shè)備棧。

仍舊未結(jié)束,控制器驅(qū)動(dòng)也不是直接和系統(tǒng)交互的,而是通過(guò)更底層的系統(tǒng)總線如 PCI 、 ACPI 進(jìn)行的。這樣,右側(cè)的第三條設(shè)備棧也形成了。

由此也可以看出設(shè)備棧、驅(qū)動(dòng)棧之間的關(guān)系了。驅(qū)動(dòng)棧是形而上的,設(shè)備棧是形而下的。


本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/changpei/archive/2010/05/06/5562542.aspx

posted @ 2010-11-30 10:36 wrh 閱讀(1795) | 評(píng)論 (0)編輯 收藏

在MFC類(lèi)庫(kù)提供了CWnd::OnCtlColor函數(shù),在工作框架的子窗口被重畫(huà)時(shí)將調(diào)用該成員函數(shù).因此可以重載WM_CTLCOLOR消息的響應(yīng)函數(shù).此函數(shù)的原型:
  
afx_msg HBRUSH OnCtlColor(CDC *pDC,CWnd *pWnd,UINT nCtlColor);
           參數(shù)nCtlColor用于指定控件的類(lèi)型,可以是:
           .CTLCOLOR_BTN                按鈕控件
           .CTLCOLOR_DLG                對(duì)話框
           .CTLCOLOR_EDIT               編輯框
           .CTLCOLOR_LISTBOX            列表控件
           .CTLCOLOR_MSGBOX             消息控件
           .CTLCOLOR_SCROLLBAR 滾動(dòng)條控件
           .CTLCOLOR_STATIC             靜態(tài)控件
[程序?qū)崿F(xiàn)]
           假設(shè)你已有了名為My的對(duì)話框工程.你有了一個(gè)STATIC的控件,ID為IDC_STATIC1.
  
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
           {
        HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
  
        // TODO: Change any attributes of the DC here
           if (nCtlColor==CTLCOLOR_STATIC)

              {
                    pDC->SetTextColor(RGB(255,0,0));
  
//字體顏色
                    pDC->SetBkColor(RGB(0, 0, 255));   //字體背景色  

                }
       
// TODO: Return a different brush if the default is not desired
        return hbr;
           }


如果要指定某個(gè)特定控件可以這樣寫(xiě):ID為IDC_STATIC1

if (pWnd->GetDlgCtrlID()==IDC_STATIC1)
{
       pDC->SetTextColor(
RGB(255,0,0));  //設(shè)置字體顏色
       pDC->SetBkMode(TRANSPARENT); //設(shè)置字體背景為透明
// TODO: Return a different brush if the default is not desired
  return (HBRUSH)::GetStockObject(BLACK_BRUSH);  // 設(shè)置背景色
}
else
return hbr;

【注】

BLACK_BRUSH:黑色

WHITE_BRUSH:白色

GRAY_BRUSH:灰色

NULL_BRUSH:透明

HOLLOW_BRUSH :透明











1.為對(duì)話框類(lèi)添加WM_CTLCOLOR的響應(yīng)函數(shù)afx_msg HBRUSH OnCtlColor(CDC*pDC,CWnd*pWnd,UINT nCtlColor){...}

2.定義一個(gè)m_brush(CBrush類(lèi)型)的成員變量和一個(gè)m_font(CFont類(lèi)型)成員變量,在構(gòu)造函數(shù)中初始化,例如:m_brush.CreateSolidBrush(RGB(0,0,255));m_font.CreatePointFont(200,"華文行楷");

3.改變背景顏色和文本顏色和字體:在OnCtlColor()添加代碼:

if(pWnd->GetDlgCtrlID()==IDC_LINE_STYLE/*控件ID*/)

{

pDC->SetTextColor(RGB(255,0,0));

pDC->SetBkMode(TRANSPARENT);//設(shè)置文本背景色為透明

pDC->SelectObject(&m_font);//設(shè)置字體

return m_brush;//設(shè)置控件背景顏色

}

//對(duì)于按鈕來(lái)說(shuō)上面的方法無(wú)效


posted @ 2010-11-29 11:24 wrh 閱讀(2515) | 評(píng)論 (0)編輯 收藏

VC通用控件自適應(yīng)屏幕類(lèi)

此為我程序中的一個(gè)類(lèi),本用于WinCE,但在桌面系統(tǒng)上也同樣適用!

使用方法(在WM_INITDIALOG或WM_CREATE消息中加入):

CWindowAnchor::BeginControlBound(hwnd)

 

手動(dòng)調(diào)整控件位置:

CWindowAnchor::AddControl(hwnd,IDC_STATIC1,&WindowAnchorInfo(WAT_LEFT|WAT_TOP,2,8,4,10));
CWindowAnchor::AddControl(hwnd,IDC_STATIC1,
&WindowAnchorInfo(WAT_LEFT|WAT_TOP|WAT_RIGHT,2,20,4,10));
CWindowAnchor::AddControl(hwnd,IDC_STATIC1,
&WindowAnchorInfo(WAT_LEFT|WAT_TOP,2,8,40,10));


自動(dòng)調(diào)整控件位置(跟據(jù)設(shè)計(jì)時(shí)資源文件中控件的大小及位置):

CWindowAnchor::AddControl(hwnd,IDC_STATIC1,&WindowAnchorInfo(WAT_LEFT|WAT_TOP));
CWindowAnchor::AddControl(hwnd,IDC_STATIC1,
&WindowAnchorInfo(WAT_LEFT|WAT_TOP|WAT_RIGHT));

 

響應(yīng)WM_SIZE消息:

case WM_SIZE:
    
return HANDLE_WM_SIZE(hwndDlg,wParam,lParam,CWindowAnchor::OnSize);

 

響應(yīng)WM_DESTROY消息:

CWindowAnchor::EndControlBound(hwnd);

 

 

代碼:

#pragma once
#include 
<map>

#if defined (_MSC_VER)
    
#pragma warning(disable: 4786)
#endif

/*用于WindowAnchorInfo結(jié)構(gòu)的停靠類(lèi)型*/
typedef 
enum WindowAnchorType
{
    WAT_TOP
=0x0001,
    WAT_LEFT
=0x0002,
    WAT_RIGHT
=0x0004,
    WAT_BOTTOM
=0x0008
};

/*控件定位描述信息*/
typedef 
struct WindowAnchorInfo{
    DWORD dwAnchor; 
//WAT_*
    RECT rcOriginalRect; //控件的原始邊距,如果為空則自動(dòng)獲取(僅適用于WM_INIT中)
    
    WindowAnchorInfo(DWORD pAnchor
=WAT_TOP|WAT_LEFT,LONG pLeft=0,LONG pTop=0,LONG pRight=0,LONG pBottom=0)
    {
        dwAnchor
=pAnchor;
        rcOriginalRect.left
=pLeft;
        rcOriginalRect.top
=pTop;
        rcOriginalRect.right
=pRight;
        rcOriginalRect.bottom
=pBottom;
    };
};

typedef std::map
<HWND,WindowAnchorInfo> ControlHashtable;

typedef 
struct{
    INT nWidth; 
//對(duì)話框?qū)挾?/span>
    INT nHeight; //對(duì)話框高度
    INT nMinHeight; //對(duì)話框最小高度
    ControlHashtable mapControls; //對(duì)話框所有子控件
}WindowAnchorDialog;

/*
 * 對(duì)話框子控件定位
 * 2009.03.29 By Frank
*/
static class CWindowAnchor
{
private:
    
static BOOL _ReSize(HWND hwndDlg, const WindowAnchorDialog *wad, HWND hwndCtrl, const WindowAnchorInfo *wai);

public:
    
/*
     * 開(kāi)始調(diào)整(此調(diào)用中會(huì)獲取當(dāng)前對(duì)話框的大小,如果在設(shè)計(jì)后要調(diào)整對(duì)話框大小,請(qǐng)先調(diào)用此方法)
     * hwndDlg:對(duì)話框句柄
    
*/
    
static BOOL BeginControlBound(HWND hwndDlg);

    
/*
     * 結(jié)束調(diào)整
     * hwndDlg:對(duì)話框句柄
    
*/
    
static BOOL EndControlBound(HWND hwndDlg);

    
/*
     * 添加一個(gè)控件到調(diào)整列表
     * hWndInsertAfter:HWND_BOTTOM |HWND_NOTOPMOST | HWND_TOP | HWND_TOPMOST |-2不改變 | Is Hwnd
    
*/
    
static BOOL AddControl(HWND hwndDlg, INT nCtrlID, WindowAnchorInfo *wai, HWND hWndInsertAfter=(HWND)-2);

    
/*
     * 調(diào)整一個(gè)指定控件的大小
    
*/
    
static BOOL ReSize(HWND hwndDlg, HWND hwndCtrl);

    
/*
     * 響應(yīng)WM_SIZE消息
    
*/
    
static BOOL OnSize(HWND hwndDlg, UINT state, int cx, int cy);

    
/*相應(yīng)WM_VSCROLL消息*/
    
static BOOL OnVScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos);
};

 

下載地址:單擊下載

posted @ 2010-11-29 11:14 wrh 閱讀(823) | 評(píng)論 (0)編輯 收藏

1.首先在初始化函數(shù)中,F(xiàn)ormView在OnInitialUpdate(),Dialog在OnInitDialog()中初始化控件的大小。

view plaincopy to clipboardprint?
01.//開(kāi)始初始化控件大小  
02. m_IsInitialed = false;  
03. 
04. CRect m_ClientRect;  
05. this->GetClientRect(&m_ClientRect);  
06. CSize m_Forsize;  
07. m_Forsize = GetTotalSize();//在資源編輯器中定好大小后,程序運(yùn)行時(shí)大小(不管最大化和最小化,該大小均為同一個(gè)值),客戶區(qū)大于或等于顯示的大小  
08. double m_x = (double)m_ClientRect.Width() / m_Forsize.cx;//寬度方向發(fā)大倍數(shù)  
09. double m_y = (double)m_ClientRect.Height() / m_Forsize.cy;//高度方向發(fā)大倍數(shù)  
10. 
11. //調(diào)整控件的大小  
12. CWnd *pWnd = NULL;   
13. pWnd = GetWindow(GW_CHILD);  
14. while(pWnd)//判斷是否為空,因?yàn)閷?duì)話框創(chuàng)建時(shí)會(huì)調(diào)用此函數(shù),而當(dāng)時(shí)控件還未創(chuàng)建  
15. {  
16.  CRect rect;   //獲取控件變化前大小  
17.  pWnd->GetWindowRect(&rect);  
18.  ScreenToClient(&rect);//將控件大小轉(zhuǎn)換為在對(duì)話框中的區(qū)域坐標(biāo)  
19.  m_ControlRect.insert(pair<int, CRect>(pWnd->GetDlgCtrlID(), rect));//保存控件的初始大小,以便在OnSize函數(shù)中繼續(xù)使用  
20.  int width = rect.Width();  
21.  int height = rect.Height();  
22. 
23.  WCHAR szBuf[256];  
24.  GetClassName(pWnd->m_hWnd,szBuf,256);           
25.  if( _tcsicmp(szBuf,_T("Edit")) == 0)     
26.  {   
27.   //Edit只是位置變化,大小沒(méi)有變  
28.   rect.top = m_y * rect.top;  
29.   rect.left = m_x * rect.left;  
30.   rect.bottom = rect.top + height;  
31.   rect.right = rect.left + width;  
32.  }  
33.  else 
34.  {  
35.   //其它控件位置和大小均變化  
36.   rect.top = m_y * rect.top;  
37.   rect.left = m_x * rect.left;  
38.   rect.bottom = m_y * rect.bottom;  
39.   rect.right = m_x * rect.right;  
40.  }  
41. 
42.  pWnd->MoveWindow(&rect);//設(shè)置控件大小  
43.  pWnd = pWnd->GetWindow(GW_HWNDNEXT);  
44. }  
45.   
46. //控件初始化結(jié)束  
47. m_IsInitialed = true; 
//開(kāi)始初始化控件大小
 m_IsInitialed = false;

 CRect m_ClientRect;
 this->GetClientRect(&m_ClientRect);
 CSize m_Forsize;
 m_Forsize = GetTotalSize();//在資源編輯器中定好大小后,程序運(yùn)行時(shí)大小(不管最大化和最小化,該大小均為同一個(gè)值),客戶區(qū)大于或等于顯示的大小
 double m_x = (double)m_ClientRect.Width() / m_Forsize.cx;//寬度方向發(fā)大倍數(shù)
 double m_y = (double)m_ClientRect.Height() / m_Forsize.cy;//高度方向發(fā)大倍數(shù)

 //調(diào)整控件的大小
 CWnd *pWnd = NULL;
 pWnd = GetWindow(GW_CHILD);
 while(pWnd)//判斷是否為空,因?yàn)閷?duì)話框創(chuàng)建時(shí)會(huì)調(diào)用此函數(shù),而當(dāng)時(shí)控件還未創(chuàng)建
 {
  CRect rect;   //獲取控件變化前大小
  pWnd->GetWindowRect(&rect);
  ScreenToClient(&rect);//將控件大小轉(zhuǎn)換為在對(duì)話框中的區(qū)域坐標(biāo)
  m_ControlRect.insert(pair<int, CRect>(pWnd->GetDlgCtrlID(), rect));//保存控件的初始大小,以便在OnSize函數(shù)中繼續(xù)使用
  int width = rect.Width();
  int height = rect.Height();

  WCHAR szBuf[256];
  GetClassName(pWnd->m_hWnd,szBuf,256);        
  if( _tcsicmp(szBuf,_T("Edit")) == 0)  
  {
   //Edit只是位置變化,大小沒(méi)有變
   rect.top = m_y * rect.top;
   rect.left = m_x * rect.left;
   rect.bottom = rect.top + height;
   rect.right = rect.left + width;
  }
  else
  {
   //其它控件位置和大小均變化
   rect.top = m_y * rect.top;
   rect.left = m_x * rect.left;
   rect.bottom = m_y * rect.bottom;
   rect.right = m_x * rect.right;
  }

  pWnd->MoveWindow(&rect);//設(shè)置控件大小
  pWnd = pWnd->GetWindow(GW_HWNDNEXT);
 }
 
 //控件初始化結(jié)束
 m_IsInitialed = true;
 

2.如果界面在運(yùn)行時(shí)大小可以改變,則在OnSize函數(shù)中加入如下代碼

view plaincopy to clipboardprint?
01.// TODO: 在此處添加消息處理程序代碼  
02.    CFormView::ShowScrollBar(SB_BOTH, false);//設(shè)置沒(méi)有滾動(dòng)條,視情況而定。  
03.         //在界面不是最小化并且已經(jīng)初始化完畢  
04.    if (!IsIconic() && m_IsInitialed)  
05.    {  
06.        CSize m_Forsize;  
07.        m_Forsize = GetTotalSize();  
08.        double m_x = (double)cx / m_Forsize.cx;  
09.        double m_y = (double)cy / m_Forsize.cy;  
10. 
11.                //讀取控件的初始大小  
12.        map<int, CRect>::iterator pos = m_ControlRect.begin();  
13.        for (; pos != m_ControlRect.end(); ++pos)  
14.        {  
15.            CRect rect = pos->second;  
16.            int width = rect.Width();  
17.            int height = rect.Height();  
18. 
19.            WCHAR szBuf[256];  
20.            GetClassName(GetDlgItem(pos->first)->m_hWnd,szBuf,256);                     
21.            if( _tcsicmp(szBuf,_T("Edit")) == 0)     
22.            {   
23.                rect.top = m_y * rect.top;  
24.                rect.left = m_x * rect.left;  
25.                rect.bottom = rect.top + height;  
26.                rect.right = rect.left + width;  
27.            }  
28.            else 
29.            {  
30.                rect.top = m_y * rect.top;  
31.                rect.left = m_x * rect.left;  
32.                rect.bottom = m_y * rect.bottom;  
33.                rect.right = m_x * rect.right;  
34.            }  
35.            GetDlgItem(pos->first)->MoveWindow(rect);  
36.        }  
37.    } 
// TODO: 在此處添加消息處理程序代碼
 CFormView::ShowScrollBar(SB_BOTH, false);//設(shè)置沒(méi)有滾動(dòng)條,視情況而定。
         //在界面不是最小化并且已經(jīng)初始化完畢
 if (!IsIconic() && m_IsInitialed)
 {
  CSize m_Forsize;
  m_Forsize = GetTotalSize();
  double m_x = (double)cx / m_Forsize.cx;
  double m_y = (double)cy / m_Forsize.cy;

                //讀取控件的初始大小
  map<int, CRect>::iterator pos = m_ControlRect.begin();
  for (; pos != m_ControlRect.end(); ++pos)
  {
   CRect rect = pos->second;
   int width = rect.Width();
   int height = rect.Height();

   WCHAR szBuf[256];
   GetClassName(GetDlgItem(pos->first)->m_hWnd,szBuf,256);         
   if( _tcsicmp(szBuf,_T("Edit")) == 0)  
   {
    rect.top = m_y * rect.top;
    rect.left = m_x * rect.left;
    rect.bottom = rect.top + height;
    rect.right = rect.left + width;
   }
   else
   {
    rect.top = m_y * rect.top;
    rect.left = m_x * rect.left;
    rect.bottom = m_y * rect.bottom;
    rect.right = m_x * rect.right;
   }
   GetDlgItem(pos->first)->MoveWindow(rect);
  }
 }

或在OnShowWindow()函數(shù)中加入也可以(特別是在對(duì)話框作為tabpage時(shí))

 

本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/ybw20041910/archive/2010/06/19/5679730.aspx

posted @ 2010-11-29 11:06 wrh 閱讀(1687) | 評(píng)論 (0)編輯 收藏

1.

重載OnCtlColor    (CDC*    pDC,    CWnd*    pWnd,    UINT    nCtlColor),即WM_CTLCOLOR消息。  
   ----    ①在CExampleDlgDlg的頭文件中,添加一CBrush的成員變量:    
   class    CExampleDlgDlg    :    public    CDialog  
   {...  
   protected:  
   CBrush    m_brush;    
   ...  
   };  
   ----    ②在OnInitDialog()函數(shù)中添加如下代碼:    
   BOOL    CExampleDlgDlg::OnInitDialog()    
   {  
   ...  
   //    TODO:    Add    extra    initialization    here  
   m_brush.CreateSolidBrush(RGB(0,    255,    0));    //    生成一綠色刷子    
   ...  
   }    
   ----    ③利用ClassWizard重載OnCtlColor(…),即WM_CTLCOLOR消息:    
   HBRUSH    CExampleDlgDlg::OnCtlColor  
   (CDC*    pDC,    CWnd*    pWnd,    UINT    nCtlColor)    
   {  
   /*  
   **    這里不必編寫(xiě)任何代碼!  
   **下行代碼要注釋掉  
   **    HBRUSH    hbr    =    CDialog::OnCtlColor(pDC,    pWnd,    nCtlColor);  
   */  
   return    m_brush;        //返加綠色刷子  
   }

2.

   修改對(duì)話框的OnPaint,在else中添加如下代碼  
           CPaintDC    dc(this);  
           CRect    rect;    
           GetClientRect(rect);    
           dc.FillSolidRect(rect,    RGB(0,0,0));    
           CDialog::OnPaint();

3.

在對(duì)話框的應(yīng)用類(lèi)(App)的.cpp的Initinstance()中加入代碼:  
                   //加在int    nResponse=dlg.DoModal();  
                   前一個(gè)RGB設(shè)置背景色,第二個(gè)設(shè)置字體顏色  
   SetDialogBkColor(RGB(0,0,255),RGB(0,255,0));

4.

1.在對(duì)話框類(lèi)中添加成員變量:  
   public:  
           CBrush          m_brushBlue;  
   
   2.在對(duì)話框類(lèi)的OnInitDialog()中添加代碼:  
   m_brushBlue.CreateSolidBrush(RGB(0,0,255));  
   
   3.用ClassWizard在對(duì)話框類(lèi)中添加成員函數(shù)OnCtlCollor(),并在其中添加代碼:  
   if(nCtlColor==CTLCOLOR_DLG)  
   return    m_brushBlue;


本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/mfreesky/archive/2007/08/27/1760222.aspx

posted @ 2010-11-29 10:55 wrh 閱讀(1536) | 評(píng)論 (0)編輯 收藏
=============獲取設(shè)備描述符
bRequestType:80
bRequest    :06
wValue      :0100
wIndex      :0000
wLength     :0040 期望長(zhǎng)度64字節(jié)

usb bus Reset總線復(fù)位我的usb設(shè)備
=============發(fā)出為我的usb設(shè)備設(shè)置地址指令,我的usb地址被設(shè)置為0x04
bRequestType:00
bRequest    :05
wValue      :0004
wIndex      :0000
wLength     :0000

=============獲取配置描述符
bRequestType:80
bRequest    :06
wValue      :0200
wIndex      :0000
wLength     :0009 期望長(zhǎng)度9字節(jié)

=============嘗試讀取配置描述符0xff長(zhǎng)度
bRequestType:80
bRequest    :06
wValue      :0200
wIndex      :0000
wLength     :00ff

=============嘗試讀取配置描述符0x12長(zhǎng)度,不會(huì)超時(shí)
bRequestType:80
bRequest    :06
wValue      :0200
wIndex      :0000
wLength     :0012

=============嘗試讀取配置描述符0x09長(zhǎng)度,正好
bRequestType:80
bRequest    :06
wValue      :0200
wIndex      :0000
wLength     :0009

=============讀取配置描述符總長(zhǎng)度0x22
bRequestType:80
bRequest    :06
wValue      :0200
wIndex      :0000
wLength     :0022

=============設(shè)置配置,將配置生效,使能cpu上的endpoint端點(diǎn)
bRequestType:00
bRequest    :09
wValue      :0001 將配置數(shù)值設(shè)置為1
wIndex      :0000
wLength     :0000

=============
bRequestType:00
bRequest    :09
wValue      :0001
wIndex      :0000
wLength     :0000

=============
bRequestType:81 讀取接口
bRequest    :06 讀取接口描述符
wValue      :2200 讀取報(bào)告描述符
wIndex      :0000
wLength     :0072

=============
bRequestType:81
bRequest    :06
wValue      :2200
wIndex      :0000
wLength     :0072

============= 讀取配置描述符
bRequestType:80
bRequest    :06
wValue      :0200
wIndex      :0000
wLength     :0022

posted @ 2010-11-26 13:29 wrh 閱讀(281) | 評(píng)論 (0)編輯 收藏
     摘要: 一、USB命令   在USB規(guī)范里,對(duì)命令一詞提供的單詞為“Request”,但這里為了更好的理解主機(jī)與設(shè)備之間的主從關(guān)系,將它定義成“命令”。   所有的USB設(shè)備都要求對(duì)主機(jī)發(fā)給自己的控制命令作出響應(yīng),USB規(guī)范定義了11個(gè)標(biāo)準(zhǔn)命令,它們分別是:C...  閱讀全文
posted @ 2010-11-24 14:39 wrh 閱讀(1053) | 評(píng)論 (0)編輯 收藏

在《USB系列之三》中,我們實(shí)現(xiàn)了一系列的SCSI命令,在這個(gè)系列中,我們要實(shí)現(xiàn)向U盤(pán)上寫(xiě)扇區(qū)的命令,所以,本文相對(duì)比較容易,更多地是給出一個(gè)實(shí)現(xiàn)的源程序。

    在《USB系列之三》中,我們實(shí)現(xiàn)的SCSI命令有:INQUIRY、READ CAPACITY(10)、TEST UNIT READY、REQUEST SENSE、READ(10);都是一些讀出的命令,所以不會(huì)破壞U盤(pán)的內(nèi)容,在文檔SBC-2的第29頁(yè)有一個(gè)SCSI命令的表,在這個(gè)表中列出了所有的命令,其TYPE為“M”的都是SCSI設(shè)備必須實(shí)現(xiàn)的命令,這些命令有:

Num

Command Name

Operation Code

 Type

 Reference

 1

 FORMAT UNIT

 04h

 M

 SBC-2

 2

 INQUIRY

 12h

 M

 SPC-3

 3

 READ(6)

 08h

 M

 SBC-2

 4

 READ(10)

 28h

 M

 SBC-2

 5

 READ(16)

 88h

 M

 SBC-2

 6

 READ CAPACITY(10)

 25h

 M

 SBC-2

 7

 READ CAPACITY(16)

 9Eh/10h

 M

 SBC-2

 8

 REQUEST SENSE

 03h

 M

 SPC-3

 9

 SEND DIAGNOSTIC

 1Dh

 M

 SPC-3

 10

 TEST UNIT READY

 00h

 M

 SPC-3

 11

 WRITE(10)

 2Ah

 O

 SBC-2

    這里面最后的一個(gè)命令并不是SBC-2中要求強(qiáng)制實(shí)現(xiàn)的,而是可選的,但如果我們不去實(shí)現(xiàn),U盤(pán)的操作將失色很多;我們不打算去實(shí)現(xiàn)序號(hào)為1、3、5、7和9的命令,READ(6)、READ(16)和READ(10)十分相似,只是LBA的長(zhǎng)度不同而已,如果需要實(shí)現(xiàn),參考READ(10)就可以了,F(xiàn)ORMAT和SEND DIAGNOSTIC兩個(gè)命令對(duì)使用芯片的U盤(pán)來(lái)說(shuō)沒(méi)有什么意義,當(dāng)然對(duì)硬盤(pán)是有意義的,所以在本文中,我們只需要實(shí)現(xiàn)一個(gè)很重要的WRTE(10),向U盤(pán)上寫(xiě)數(shù)據(jù),我們需要準(zhǔn)備一張沒(méi)有有用數(shù)據(jù)的U盤(pán),因?yàn)槲覀円淖兤渲械膬?nèi)容。

    WRITE(10)源代碼下載地址:

    http://blog.hengch.com/source/usb-write.zip

    程序中,我們向《USB系列三》中的程序一樣,先reset,然后得到最大的LUN,這個(gè)步驟不是必須的,然后我們向device發(fā)出WRITE(10)命令,注意,這是一個(gè)OUT事務(wù),所以,CBW_FLAGS=0X00而不是像以前一樣是0X80,發(fā)出WRITE(10)命令后,我們還要向device發(fā)送要寫(xiě)入的數(shù)據(jù),每次64個(gè)字節(jié),一個(gè)扇區(qū)512字節(jié)需要啟動(dòng)8個(gè)OUT事務(wù),這個(gè)工作又函數(shù)putData完成,每次發(fā)送的64個(gè)字節(jié)我們分別寫(xiě)入了0--63,程序中,我們把這些數(shù)據(jù)寫(xiě)入到了LBA=100的扇區(qū)中,寫(xiě)入后,我們?cè)谑褂迷凇禪SB系列之三》中介紹過(guò)的READ(10)命令把相同的扇區(qū)讀出來(lái),我們會(huì)看到我們所希望的結(jié)果,由于在讀之前,我們已經(jīng)把buffer全部清為0了,所以我們有把握相信,我們讀到的數(shù)據(jù)是真實(shí)的。

    到這里,我們已經(jīng)把控制U盤(pán)的主要命令都介紹完了,利用DOSUSB,我們已經(jīng)有可能為U盤(pán)編寫(xiě)一個(gè)簡(jiǎn)單的驅(qū)動(dòng)程序,但可能我們還不知道DOS下的驅(qū)動(dòng)程序該如何寫(xiě),從下一篇文章開(kāi)始,我們將暫時(shí)放下USB系列文章,介紹一下DOS下驅(qū)動(dòng)程序的寫(xiě)法。

posted @ 2010-11-24 14:10 wrh 閱讀(1234) | 評(píng)論 (0)編輯 收藏

U盤(pán)是我們最常使用的一種USB設(shè)備,本文繼續(xù)使用DOSUSB做驅(qū)動(dòng),試圖以讀取扇區(qū)的方式讀取你的U盤(pán)。
    本文可能涉及的協(xié)議可能會(huì)比較多。
一、了解你的U盤(pán)
    首先我們用上一篇文章介紹的程序usbview.exe去看一下你的U盤(pán),我在本文中用于測(cè)試的U盤(pán)情況如下:
    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

    各種描述符的含義在以前的文章中介紹過(guò)了,或者去翻閱USB的specification,這里就不多說(shuō)了,我們從接口描述符開(kāi)始就一些關(guān)鍵點(diǎn)進(jìn)行一下說(shuō)明。
    首先看接口描述符,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盤(pán)可能還會(huì)有第三個(gè)端點(diǎn),比如支持中斷傳輸?shù)腢盤(pán)還會(huì)有一個(gè)Interrupt端點(diǎn),不過(guò)這都沒(méi)有關(guān)系。
    我大概看了我手頭有的5個(gè)U盤(pán),都支持批量傳輸,且支持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,不過(guò)這個(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盤(pán)、攝像頭、打印機(jī)等,而本文將只針對(duì)我們經(jīng)常使用的USB設(shè)備----U盤(pán),如果你打算嘗試本文所介紹的內(nèi)容,請(qǐng)準(zhǔn)備好一個(gè)U盤(pán),什么樣子的都行,或者是一個(gè)USB讀卡器,不過(guò)要記得插一張卡進(jìn)去,實(shí)際上本文所載范例就是使用一個(gè)USB的CF卡讀卡器完成的,不用擔(dān)心損害你的U盤(pán)中的數(shù)據(jù),本文不會(huì)對(duì)U盤(pán)進(jìn)行任何寫(xiě)操作,僅僅做一些讀操作。

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

     不用為規(guī)范發(fā)愁,實(shí)際上,前兩個(gè)規(guī)范都很短,其中第一個(gè)對(duì)實(shí)際編程沒(méi)有什么作用,但最好看一下;第二個(gè)規(guī)范連目錄一共22頁(yè),其中13頁(yè)以前的內(nèi)容可以跳過(guò)(很多和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ī)范中并沒(méi)有定義第二部分的內(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è)字母倒過(guò)來(lái),這是因?yàn)镃BW的字符順序是little endian(這個(gè)東東在以前有關(guān)網(wǎng)絡(luò)編程的文章中介紹過(guò)),而我們PC機(jī)中的字符順序是big endian,所以要顛倒一下,總之寫(xiě)dCBWSignature = 0X43425355就OK了;dCBWTag僅僅是一個(gè)標(biāo)志,你可以填任何值,這里要先說(shuō)一下CSW(Command Status Wrapper),我們每發(fā)出一個(gè)命令,設(shè)備都會(huì)返回一個(gè)CSW(這個(gè)東東下面很快就要介紹了),以說(shuō)明命令的執(zhí)行狀態(tài),這個(gè)結(jié)構(gòu)中也有Signature和Tag這兩個(gè)字段,其中Tag字段和發(fā)出命令時(shí)CBW中的Tag字段相同,這樣就可以區(qū)分這個(gè)CSW是和那個(gè)CBW對(duì)應(yīng)的了,至于Signature,下面再說(shuō)。

    下一個(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)說(shuō):我們發(fā)送INQIURY命令到設(shè)備,按照SPC-3第144頁(yè)的說(shuō)明,該命令返回的數(shù)據(jù)至少為36個(gè)字節(jié),所以,此時(shí)這個(gè)字節(jié)應(yīng)該填36;再如:我們讀取U盤(pán)的一個(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盤(pán)都不支持多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è)要說(shuō)的數(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)如下:

     前面說(shuō)過(guò),在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中,批量傳輸沒(méi)有那么簡(jiǎn)單,批量傳輸分為輸出事務(wù)和輸入事務(wù),我們應(yīng)該注意到,前面在看U盤(pán)的描述表時(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)該閱讀過(guò)DOSUSB的說(shuō)明,并且對(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)說(shuō)明如何啟動(dòng)一個(gè)傳輸,我們以SCSI INQUIRY命令為了,關(guān)于這個(gè)命令的定義在SPC-3的第142頁(yè)--157頁(yè)有說(shuō)明,篇幅很長(zhǎng),但絕大多數(shù)篇幅用來(lái)解釋返回?cái)?shù)據(jù)的含義,我們可以暫時(shí)不去理會(huì)。首先我們要填寫(xiě)CBW結(jié)構(gòu),CBW結(jié)構(gòu)的第一部分的填寫(xiě)前面已經(jīng)說(shuō)的很明白了,第二部分的定義在SPC-3的第142頁(yè),共有6個(gè)字節(jié),我們要按照定義填寫(xiě)好,實(shí)際上只要填兩個(gè)字段,一個(gè)是OPERATION CODE = 0X12,第二個(gè)就是ALLOCATION CODE = 36,表示需要返回36個(gè)字節(jié)的內(nèi)容;CBW填好后,我們開(kāi)始填寫(xiě)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)介紹過(guò)了,填完以后調(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ì)容易一些,只要填寫(xiě)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)描述符表中寫(xiě)明包的最大長(zhǎng)度為64,其它字段按常規(guī)填寫(xiě),調(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盤(pán)上讀出一個(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)介紹過(guò)了,程序無(wú)非就是實(shí)現(xiàn)這些概念,幾乎所有的代碼都是圍繞著填寫(xiě)數(shù)據(jù)結(jié)構(gòu)和顯示返回結(jié)果的,所以代碼本身并不難,更重要的是理解數(shù)據(jù)結(jié)構(gòu)中個(gè)字段的含義,這可能不得不閱讀一些規(guī)范,我想我不可能比規(guī)范說(shuō)的更嚴(yán)謹(jǐn)更完整。要注意的是,你使用的U盤(pán)不可能和我的完全一致,一般情況下有可能有變化的是:設(shè)備地址devAddr、輸出端點(diǎn)地址outEndpoint和輸入端點(diǎn)地址inEndpoint,所以在編譯程序之前一定要使用《USB系列之二》中的方法仔細(xì)查看一下你的U盤(pán)的各種描述符表,如果這些值和我的U盤(pán)不同,請(qǐng)?jiān)谥鞒绦蜷_(kāi)始的地方,更改這幾個(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è)谔顚?xiě)LBA和讀取最大LBA時(shí)都做了相應(yīng)的轉(zhuǎn)換。

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

    Enjoy it.

posted @ 2010-11-24 14:09 wrh 閱讀(1421) | 評(píng)論 (1)編輯 收藏
 USB現(xiàn)在已經(jīng)成為PC機(jī)必不可少的接口之一,幾乎所有的設(shè)備都可以接在USB設(shè)備上,USB鍵盤(pán)、鼠標(biāo)、打印機(jī)、攝像頭,還有常用的U盤(pán)等等,從本篇文章開(kāi)始,將集中篇幅介紹一下在DOS中使用USB設(shè)備的方法,具體會(huì)有幾篇暫不好定,寫(xiě)到哪里算哪里吧,三、四篇總是少不了的。
    本文介紹如何使用我以前文章中介紹過(guò)的知識(shí)在你的機(jī)器中找到USB設(shè)備,并判定設(shè)備類(lèi)型。
    一個(gè)USB系統(tǒng)一般由一個(gè)USB主機(jī)(HOST)、一個(gè)或多個(gè)USB集線器(HUB,但不是局域網(wǎng)里的集線器)和一個(gè)或多個(gè)USB設(shè)備節(jié)點(diǎn)(NODE)組成,一個(gè)系統(tǒng)中只有一個(gè)HOST,我們PC機(jī)里的USB實(shí)際上就是HOST和HUB兩部分,你的PC機(jī)可能會(huì)有4個(gè)USB口,其實(shí)是一個(gè)HOST,一個(gè)HUB,HUB為你提供了4個(gè)端口,我們插在USB口上的器件,一般是USB設(shè)備,比如U盤(pán),USB打印機(jī)等,當(dāng)然我們也可以插一個(gè)集線器上去,使你的一個(gè)USB口擴(kuò)展成多個(gè)。
    實(shí)際上我們說(shuō)在DOS下使用USB,就是對(duì)USB系統(tǒng)中的HOST進(jìn)行編程管理,根據(jù)USB的規(guī)范,HOST將對(duì)連接在上面的HUB和USB設(shè)備進(jìn)行管理,不用我們操心。HOST器件目前有三個(gè)規(guī)范,OHCI(Open Host Controller Interface)、UHCI(Universal Host Controller Interface)支持USB1.1,EHCI(Enhanced Host Controller Interface)支持USB2.0,以后的文章中,我們將側(cè)重介紹OHCI和EHCI。
    學(xué)習(xí)USB編程,讀規(guī)范是少不了的,以下是一些應(yīng)該閱讀的規(guī)范下載:
    OHCI規(guī)范:
http://blog.hengch.com/specification/usb_ohci_r10a.pdf
    EHCI規(guī)范:http://blog.hengch.com/specification/usb_ehci_r10.pdf
    USB規(guī)范1.1:http://blog.hengch.com/specification/usb_spec11.pdf
    USB規(guī)范2.0:http://blog.hengch.com/specification/usb_spec20.pdf
    本文介紹的內(nèi)容不需要學(xué)習(xí)規(guī)范。

    下面進(jìn)入正題,列出你的USB設(shè)備,USB的HOST是掛接在PCI總線上的,所以通過(guò)PCI設(shè)備的遍歷就可以找到你的機(jī)器上的所有USB設(shè)備,在以前介紹PCI的配置空間時(shí),曾經(jīng)介紹過(guò)在配置空間中有一個(gè)占三個(gè)字節(jié)的分類(lèi)代碼字段(如果不知道,請(qǐng)參閱我以前的博文
《遍歷PCI設(shè)備》),在偏移為0x0B的字節(jié)叫基本分類(lèi)代碼,在偏移為0x0A的字節(jié)叫子分類(lèi)代碼,在偏移為0x09的字節(jié)叫編程接口代碼,對(duì)于USB設(shè)備類(lèi)說(shuō),基本分類(lèi)代碼為0x0C,子分類(lèi)代碼為0x03,對(duì)于符合不同規(guī)范的HOST器件而言,編程接口代碼是不同的,UHCI的編程接口代碼是0x00,OHCI的編程接口代碼是0x10,EHCI的編程接口代碼是0x20,我想了解這些就足夠了。
    下面列出USB設(shè)備的源程序。
#include <stdio.h>
#include <stdlib.h>
#include <dpmi.h>

typedef unsigned long      UDWORD;
typedef short int          WORD;
typedef unsigned short int UWORD;
typedef unsigned char      UBYTE;

typedef union {
  struct {
    UDWORD edi;
    UDWORD esi;
    UDWORD ebp;
    UDWORD res;
    UDWORD ebx;
    UDWORD edx;
    UDWORD ecx;
    UDWORD eax;
  } d;
  struct {
    UWORD di, di_hi;
    UWORD si, si_hi;
    UWORD bp, bp_hi;
    UWORD res, res_hi;
    UWORD bx, bx_hi;
    UWORD dx, dx_hi;
    UWORD cx, cx_hi;
    UWORD ax, ax_hi;
    UWORD flags;
    UWORD es;
    UWORD ds;
    UWORD fs;
    UWORD gs;
    UWORD ip;
    UWORD cs;
    UWORD sp;
    UWORD ss;
  } x;
  struct {
    UBYTE edi[4];
    UBYTE esi[4];
    UBYTE ebp[4];
    UBYTE res[4];
    UBYTE bl, bh, ebx_b2, ebx_b3;
    UBYTE dl, dh, edx_b2, edx_b3;
    UBYTE cl, ch, ecx_b2, ecx_b3;
    UBYTE al, ah, eax_b2, eax_b3;
  } h;
} X86_REGS;
/*************************************************************
 * Excute soft interrupt in real mode
 *************************************************************/
int x86_int(int int_num, X86_REGS *x86_reg) {
  __dpmi_regs d_regs;
  int return_value;

  d_regs.d.edi = x86_reg->d.edi;
  d_regs.d.esi = x86_reg->d.esi;
  d_regs.d.ebp = x86_reg->d.ebp;
  d_regs.d.res = x86_reg->d.res;
  d_regs.d.ebx = x86_reg->d.ebx;
  d_regs.d.ecx = x86_reg->d.ecx;
  d_regs.d.edx = x86_reg->d.edx;
  d_regs.d.eax = x86_reg->d.eax;
  d_regs.x.flags = x86_reg->x.flags;
  d_regs.x.es = x86_reg->x.es;
  d_regs.x.ds = x86_reg->x.ds;
  d_regs.x.fs = x86_reg->x.fs;
  d_regs.x.gs = x86_reg->x.gs;
  d_regs.x.ip = x86_reg->x.ip;
  d_regs.x.cs = x86_reg->x.cs;
  d_regs.x.sp = x86_reg->x.sp;
  d_regs.x.ss = x86_reg->x.ss;

  return_value = __dpmi_int(int_num, &d_regs);

  x86_reg->d.edi = d_regs.d.edi;
  x86_reg->d.esi = d_regs.d.esi;
  x86_reg->d.ebp = d_regs.d.ebp;
  x86_reg->d.res = d_regs.d.res;
  x86_reg->d.ebx = d_regs.d.ebx;
  x86_reg->d.ecx = d_regs.d.ecx;
  x86_reg->d.edx = d_regs.d.edx;
  x86_reg->d.eax = d_regs.d.eax;
  x86_reg->x.flags = d_regs.x.flags;
  x86_reg->x.es = d_regs.x.es;
  x86_reg->x.ds = d_regs.x.ds;
  x86_reg->x.fs = d_regs.x.fs;
  x86_reg->x.gs = d_regs.x.gs;
  x86_reg->x.ip = d_regs.x.ip;
  x86_reg->x.cs = d_regs.x.cs;
  x86_reg->x.sp = d_regs.x.sp;
  x86_reg->x.ss = d_regs.x.ss;

  return return_value;
}
/**********************************
 * Read Configuration WORD if PCI
 **********************************/
UWORD ReadConfigWORD(WORD pciAddr, int reg) {
  X86_REGS inregs;

  inregs.x.ax = 0xB109;    // Read Configuration word
  inregs.x.bx = pciAddr;
  inregs.x.di = reg;       // Register number
  x86_int(0x1A, &inregs);

  return inregs.d.ecx;     // the value
}
// main program
int main(void) {
  UWORD pciAddr;
  UWORD subClass;
  int ehciCount = 0, ohciCount = 0, uhciCount = 0;

  for (pciAddr = 0; pciAddr < 0xffff; pciAddr++) {
    if (ReadConfigWORD(pciAddr, 0) != 0xFFFF) {
      // Read Class Code
      if (ReadConfigWORD(pciAddr, 0x000a ) == 0x0c03) {  // Usb Host Controller
        // Read SubClass Code
        subClass = ReadConfigWORD(pciAddr, 0x0008);
        if ((subClass & 0xff00) == 0x2000) {  // uhci
          ehciCount++;
        } else if ((subClass & 0xff00) == 0x1000) {  // ohci
          ohciCount++;
        } else if ((subClass & 0xff00) == 0x00) {    // uhci
          uhciCount++;
        }
      }
    }
  }
  printf("There are %d ohci device(s).\n", ohciCount);
  printf("There are %d ehci device(s).\n", ehciCount);
  printf("There are %d uhci device(s).\n", uhciCount);
}

    程序非常簡(jiǎn)單,所有概念在以前的博文中均有過(guò)介紹,其中的子程序大多是以前程序范例中使用過(guò)的,所以在這里就不做更多的解釋了,程序中,我們僅僅列出了設(shè)備的數(shù)量,但很顯然,用這種方法,我們可以從配置空間里讀出基地址等信息,這些在以后的文章中會(huì)用到。
posted @ 2010-11-24 14:07 wrh 閱讀(775) | 評(píng)論 (0)編輯 收藏
僅列出標(biāo)題
共25頁(yè): First 2 3 4 5 6 7 8 9 10 Last 

導(dǎo)航

<2014年3月>
2324252627281
2345678
9101112131415
16171819202122
23242526272829
303112345

統(tǒng)計(jì)

常用鏈接

留言簿(19)

隨筆檔案

文章檔案

收藏夾

搜索

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲第一精品久久忘忧草社区| 亚洲欧美日韩精品综合在线观看| 亚洲精品免费看| 在线不卡a资源高清| 国内精品久久久久久| 亚洲精品在线电影| 亚洲黄网站在线观看| 亚洲激情av在线| 日韩亚洲欧美精品| 亚洲已满18点击进入久久| 亚洲欧美伊人| 久久人人爽爽爽人久久久| 欧美高清在线| 国产精品夫妻自拍| 国产在线高清精品| 亚洲精品久久视频| 亚洲欧美卡通另类91av| 久久久精品动漫| 欧美国产日韩一区二区在线观看| 亚洲日本乱码在线观看| 亚洲一区国产视频| 久久久久久久高潮| 欧美色道久久88综合亚洲精品| 国产精品亚洲综合天堂夜夜 | 欧美大成色www永久网站婷| 亚洲国产综合91精品麻豆| 亚洲午夜精品国产| 蜜臀av在线播放一区二区三区| 欧美婷婷在线| 亚洲国产天堂久久综合网| 性欧美超级视频| 亚洲高清久久| 日韩视频在线永久播放| 中文国产一区| 久久久久免费视频| 国产精品五月天| 在线亚洲电影| 欧美不卡视频| 欧美亚洲自偷自偷| 欧美天堂亚洲电影院在线播放| 136国产福利精品导航网址| 午夜精品久久久久久99热| 亚洲国产高清高潮精品美女| 久久爱www久久做| 国产精品视频不卡| 亚洲无人区一区| 亚洲三级电影全部在线观看高清| 久久久人人人| 黄色一区二区在线观看| 久久精品国产一区二区三区免费看 | 蜜臀av性久久久久蜜臀aⅴ四虎 | 欧美日韩国产高清| 亚洲国产美女| 久久亚洲一区二区| 午夜久久tv| 国产精品视频导航| 欧美一级免费视频| 亚洲一区二区免费视频| 欧美天天视频| 亚洲欧美日韩一区在线| 亚洲一卡久久| 国产欧美精品一区aⅴ影院| 免费精品视频| 极品中文字幕一区| 久久综合久久88| 久久久无码精品亚洲日韩按摩| 国色天香一区二区| 欧美99久久| 欧美激情综合五月色丁香| 亚洲人午夜精品免费| 欧美国产日韩二区| 欧美日韩精品久久久| 99ri日韩精品视频| 9久re热视频在线精品| 国产精品久久久免费| 欧美一区二区三区久久精品| 午夜精品一区二区三区在线视| 韩日成人av| 亚洲第一黄网| 欧美视频在线不卡| 久久久一区二区三区| 裸体素人女欧美日韩| 亚洲国产日韩一区| 亚洲免费成人av| 国产欧美日本一区二区三区| 久久在线精品| 欧美日韩大片| 国产精品嫩草久久久久| 国产一区二区日韩| 欧美成年人在线观看| 开心色5月久久精品| 久久久久久精| 中国女人久久久| 午夜日本精品| 亚洲激情欧美| 一二三四社区欧美黄| 国产一区自拍视频| 亚洲国产老妈| 国产精品一二| 亚洲电影在线| 国产亚洲激情在线| 亚洲国产精品123| 国产精品永久| 亚洲国产精品久久久久秋霞影院| 国产精品v亚洲精品v日韩精品 | 欧美丝袜第一区| 久久亚洲国产成人| 欧美日韩精品系列| 久久字幕精品一区| 国产精品卡一卡二| 亚洲国产精品免费| 在线精品国产欧美| 亚洲欧美激情一区| 国产精品99久久不卡二区| 久久婷婷国产综合国色天香| 亚洲欧美综合国产精品一区| 久久亚洲一区二区| 国产精品久久久久国产精品日日| 欧美成人日本| 狠狠色丁香婷婷综合久久片| 中文在线资源观看网站视频免费不卡| 亚洲国产欧美一区二区三区久久| 欧美一区二区三区免费看| 一区二区三区 在线观看视频| 老司机一区二区三区| 久久视频在线免费观看| 国产欧美日韩在线视频| 中文日韩在线| 亚洲男人天堂2024| 欧美日韩亚洲一区二| 亚洲国产中文字幕在线观看| 亚洲黄色免费电影| 久久在线视频在线| 久久综合网hezyo| 韩国亚洲精品| 久久久999精品免费| 久久天天躁狠狠躁夜夜爽蜜月| 国产午夜精品久久久久久免费视| 中文在线不卡| 亚洲欧美日韩久久精品| 国产精品久久久| 亚洲一区二区毛片| 久久精品国产亚洲a| 国产亚洲精品久久久| 欧美在线观看一区二区| 久久精品亚洲国产奇米99| 国产综合香蕉五月婷在线| 欧美伊人久久久久久久久影院| 欧美一区二区三区的| 国产一区91精品张津瑜| 香蕉亚洲视频| 亚洲一区激情| 性欧美长视频| 国精品一区二区| 久久精品人人做人人爽电影蜜月| 蜜桃伊人久久| av成人福利| 国产精品视频免费| 久久国产精品久久久久久电车 | 久久久精品免费视频| 韩国久久久久| 美女精品一区| 一区二区三区四区五区精品视频 | 亚洲国产精品成人久久综合一区| 亚洲精品美女久久7777777| 欧美精品在线观看播放| 亚洲夜间福利| 嫩草影视亚洲| 亚洲午夜精品久久| 国产日产欧美精品| 久久蜜桃香蕉精品一区二区三区| 亚洲国产天堂久久综合网| 亚洲一区bb| 欲香欲色天天天综合和网| 欧美国产日本| 欧美一区二区三区精品 | 最新日韩中文字幕| 欧美一区国产二区| 亚洲精品午夜| 国产日韩在线播放| 欧美极品在线观看| 久久国产精品72免费观看| 亚洲三级电影在线观看| 久久9热精品视频| 一区二区高清在线观看| 激情五月婷婷综合| 国产精品每日更新| 欧美国产日韩亚洲一区| 午夜精品久久久久久| 亚洲美女视频| 欧美黄色精品| 久久久天天操| 亚欧成人精品| aa级大片欧美三级| 亚洲国产精品电影在线观看| 国产女主播一区二区三区| 欧美日韩一区二区在线| 免费永久网站黄欧美| 久久九九久精品国产免费直播 | 亚洲午夜精品网|