新聞中心
探究 linux 塊設備驅動

成都創(chuàng)新互聯(lián)公司-專業(yè)網站定制、快速模板網站建設、高性價比昂仁網站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式昂仁網站制作公司更省心,省錢,快速模板網站建設找我們,業(yè)務覆蓋昂仁地區(qū)。費用合理售后完善,10多年實體公司更值得信賴。
Linux 操作系統(tǒng)的成功離不開豐富的驅動程序的支持,它們?yōu)橛布O備提供了底層的控制和操作。塊設備驅動是其中的一類,通常會加載到內核中實現對硬盤等塊設備進行管理。
本文將從以下幾個方面介紹 Linux 塊設備驅動:
一、塊設備的定義和特點
二、塊設備驅動的實現方式
三、塊設備驅動的常見操作
四、常見問題及解決方案
一、塊設備的定義和特點
塊設備是一種存儲器設備,使用一個固定長度的塊(通常為512字節(jié))來讀取和寫入數據。塊設備的特點包括:
1. 數據以固定長度的塊為單位進行讀取和寫入,而不是按字節(jié)操作。
2. 支持一些高級操作,例如磁盤分區(qū)、文件系統(tǒng)和文件。
3. 可以隨機訪問,即可以識別和操作不同塊的數據,而不是按照線性方式讀取。
二、塊設備驅動的實現方式
Linux 提供了多種實現塊設備驅動的方式,如:
1. 虛擬塊設備驅動:創(chuàng)建虛擬設備并向上層內核暴露其接口。
2. 硬件塊設備驅動:與硬件設備一起工作的驅動程序。
3. USB 塊設備驅動:與 USB 存儲器設備一起工作的驅動程序。
4. SCSI 塊設備驅動:與 SCSI 硬盤驅動器一起工作的驅動程序。
三、塊設備驅動的常見操作
塊設備驅動提供以下常見操作:
1. 寫:在塊設備上寫入數據。
2. 讀:從塊設備上讀取數據。
3. 文件系統(tǒng)操作:為塊設備創(chuàng)建文件系統(tǒng),格式化設備,配置磁盤分區(qū)等。
4. 磁盤管理:管理硬盤的分區(qū)、格式化等。
5. 分頁和映射:與虛擬內存管理器一起工作,將磁盤塊映射到分頁上。
6. 塊設備的電源管理。
四、常見問題及解決方案
塊設備驅動常見的問題及解決方案如下:
1. 性能問題:可能由于設備緩存、磁盤扇區(qū)大小和文件系統(tǒng)的組織方式等因素,導致性能下降。解決方案可能包括調整系統(tǒng)的 IO 調度程序和設置緩存策略。
2. 安全問題:由于塊設備通常包含重要的數據,因此必須實施必要的安全措施,例如加密、將訪問限制為特定用戶或組,并限制對設備的物理訪問。
3. 塊設備硬件故障問題:由于硬盤容易受到震動和磁場等干擾,因此可能會導致數據損壞。解決方案包括使用 RD 技術和定期備份數據。
本文主要討論了 Linux 塊設備驅動的定義、特點、實現方式、常見操作,以及其可能遇到的常見問題及解決方案。了解塊設備驅動和如何編寫一個驅動程序,對于 Linux 內核的開發(fā)和系統(tǒng)管理員都十分重要。
成都網站建設公司-創(chuàng)新互聯(lián),建站經驗豐富以策略為先導10多年以來專注數字化網站建設,提供企業(yè)網站建設,高端網站設計,響應式網站制作,設計師量身打造品牌風格,熱線:028-86922220LINUX設備驅動程序如何與硬件通信
LINUX設備驅動程序是怎么樣和硬件通信的?下面將由我?guī)Т蠹襾斫獯疬@個啟信祥疑問吧,希望對大家有所收獲!
LINUX設備驅動程序與硬件設備之間的通信
設備驅動程序是軟件概念和硬件電路之間的一個抽象層,因此兩方面都要討論。到目前為止,我們已經討論詳細討論了軟件概念上的一些細節(jié),現在討論另一方面,介紹驅動程序在Linux上如何在保持可移植性的前提下訪問I/O端口和I/O內存。
我們在需要示例的場合會使用簡單的數字I/O端口來講解I/O指令,并使用普通的幀緩沖區(qū)顯存來講解內存映射I/O。
I/O端口和I/O內存
計算機對每種外設都是通過讀寫它的寄存悄搏器進行控制的。大部分外設都有幾個寄存器,不管是在內存地址空間還是在I/O地址空間,這些寄存器的訪問地址都是連續(xù)的。
I/O端口就是I/O端口,設備會把寄存器映射到I/O端口,不管處理器是否具有獨立的I/O端口地址空間。即使沒有在訪問外設時也要模擬成讀寫I/O端口。
I/O內存是設備把寄存器映射到某個內存地址區(qū)段(如PCI設備)。這種I/O內存通常是首先方案,它不需要特殊的處理器指令,而且CPU核心訪問內存更有效率。
I/O寄存器和常規(guī)內存
盡管硬件寄存器和內存非常相似,但程序員在訪問I/O寄存器的時候必須注意避免由于CPU或編譯器不恰當的優(yōu)化而改變預期的I/O動作。
I/O寄存器和RAM最主要的區(qū)別就是I/O操作具有邊際效應,而內存操作則沒有:由坦橘于內存沒有邊際效應,所以可以用多種 方法 進行優(yōu)化,如使用高速緩存保存數值、重新排序讀/寫指令等。
編譯器能夠將數值緩存在CPU寄存器中而不寫入內存,即使儲存數據,讀寫操作也都能在高速緩存中進行而不用訪問物理RAM。無論是在編譯器一級或是硬件一級,指令的重新排序都有可能發(fā)生:一個指令序列如果以不同于程序文本中的次序運行常常能執(zhí)行得更快。
在對常規(guī)內存進行這些優(yōu)化的時候,優(yōu)化過程是透明的,而且效果良好,但是對I/O操作來說這些優(yōu)化很可能造成致命的錯誤,這是因為受到邊際效應的干擾,而這卻是驅動程序訪問I/O寄存器的主要目的。處理器無法預料某些 其它 進程(在另一個處理器上運行,或在在某個I/O控制器中發(fā)生的操作)是否會依賴于內存訪問的順序。編譯器或CPU可能會自作聰明地重新排序所要求的操作,結果會發(fā)生奇怪的錯誤,并且很難調度。因此,驅動程序必須確保不使用高速緩沖,并且在訪問寄存器時不發(fā)生讀或寫指令的重新排序。
由硬件自身引起的問題很解決:只要把底層硬件配置成(可以是自動的或是由Linux初始化代碼完成)在訪問I/O區(qū)域(不管是內存還是端口)時禁止硬件緩存即可。
由編譯器優(yōu)化和硬件重新排序引起的問題的解決辦法是:對硬件(或其他處理器)必須以特定順序的操作之間設置內存屏障(memory barrier)。Linux提供了4個宏來解決所有可能的排序問題:
#include
void barrier(void)
這個函數通知編譯器插入一個內存屏障,但對硬件沒有影響。編譯后的代碼會把當前CPU寄存器中的所有修改過的數值保存到內存中,需要這些數據的時候再重新讀出來。對barrier的調用可避免在屏障前后的編譯器優(yōu)化,但硬件完成自己的重新排序。
#include
void rmb(void);
void read_barrier_depends(void);
void wmb(void);
void mb(void);
這些函數在已編譯的指令流中插入硬件內存屏障;具體實現方法是平臺相關的。rmb(讀內存屏障)保證了屏障之前的讀操作一定會在后來的讀操作之前完成。wmb保證寫操作不會亂序,mb指令保證了兩者都不會。這些函數都是barrier的超集。
void p_rmb(void);
void p_read_barrier_depends(void);
void p_wmb(void);
void p_mb(void);
上述屏障宏版本也插入硬件屏障,但僅僅在內核針對P系統(tǒng)編譯時有效;在單處理器系統(tǒng)上,它們均會被擴展為上面那些簡單的屏障調用。
設備驅動程序中使用內存屏障的典型形式如下:
writel(dev->registers.addr, io_destination_address);
writel(dev->registers.size, io_size);
writel(dev->registers.operation, DEV_READ);
wmb();
writel(dev->registers.control, DEV_GO);
在這個例子中,最重要的是要確??刂颇撤N特定操作的所有設備寄存器一定要在操作開始之前已被正確設置。其中的內存屏障會強制寫操作以要求的順序完成。
因為內存屏障會影響系統(tǒng)性能,所以應該只用于真正需要的地方。不同類型的內存屏障對性能的影響也不盡相同,所以更好盡可能使用更符合需要的特定類型。
值得注意的是,大多數處理同步的內核原語,如自旋鎖和atomic_t操作,也能作為內存屏障使用。同時還需要注意,某些外設總線(比如PCI總線)存在自身的高速緩存問題,我們將在后面的章節(jié)中討論相關問題。
在某些體系架構上,允許把賦值語句和內存屏障進行合并以提高效率。內核提供了幾個執(zhí)行這種合并的宏,在默認情況下,這些宏的定義如下:
#define set_mb(var, value) do {var = value; mb();} while 0
#define set_wmb(var, value) do {var = value; wmb();} while 0
#define set_rmb(var, value) do {var = value; rmb();} while 0
在適當的地方,中定義的這些宏可以利用體系架構特有的指令更快的完成任務。注意只有小部分體系架構定義了set_rmb宏。
使用I/O端口
I/O端口是驅動程序與許多設備之間的通信方式——至少在部分時間是這樣。本節(jié)講解了使用I/O端口的不同函數,另外也涉及到一些可移植性問題。
I/O端口分配
下面我們提供了一個注冊的接口,它允允許驅動程序聲明自己需要操作的端口:
#include
struct resource *request_region(unsigned long first, unsigned long n, const char *name);
它告訴內核,我們要使用起始于first的n個端口。name是設備的名稱。如果分配成功返回非NULL,如果失敗返回NULL。
所有分配的端口可從/proc/ioports中找到。如果我們無法分配到我們要的端口,則可以查看這個文件哪個驅動程序已經分配了這些端口。
如果不再使用這些端口,則用下面函數返回這些端口給系統(tǒng):
void release_region(unsigned long start, unsigned long n);
下面函數允許驅動程序檢查給定的I/O端口是否可用:
int check_region(unsigned long first, unsigned long n);//不可用返回負的錯誤代碼
我們不贊成用這個函數,因為它返回成功并不能確保分配能夠成功,因為檢查和其后的分配并不是原子操作。我們應該始終使用request_region,因為這個函數執(zhí)行了必要的鎖定,以確保分配過程以安全原子的方式完成。
操作I/O端口
當驅動程序請求了需要使用的I/O端口范圍后,必須讀取和/或寫入這些端口。為此,大多數硬件都會把8位、16位、32位區(qū)分開來。它們不能像訪問系統(tǒng)內存那樣混淆使用。
因此,C語言程序必須調用不同的函數訪問大小不同的端口。那些只支持映射的I/O寄存器的計算機體系架構通過把I/O端口地址重新映射到內存地址來偽裝端口I/O,并且為了易于移植,內核對驅動程序隱藏了這些細節(jié)。Linux內核頭文件中(在與體系架構相關的頭文件中)定義了如下一些訪問I/O端口的內聯(lián)函數:
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);
字節(jié)讀寫端口。
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);
訪問16位端口
unsigned inl(unsigned port);
void outl(unsigned longword, unsigned port);
訪問32位端口
在用戶空間訪問I/O端口
上面這些函數主要是提供給設備驅動程序使用的,但它們也可以用戶空間使用,至少在PC類計算機上可以使用。GNU的C庫在中定義了這些函數。如果要要用戶空間使用inb及相關函數,則必須滿足正下面這些條件:
編譯程序時必須帶有-O選項來強制內聯(lián)函數的展開。
必須用ioperm(獲取單個端口的權限)或iopl(獲取整個I/O空間)系統(tǒng)調用來獲取對端口進行I/O操作的權限。這兩個函數都是x86平臺特有的。
必須以root身份運行該程序才能調用ioperm或iopl。或者進程的祖先進程之一已經以root身份獲取對端口的訪問。
如果宿主平臺沒有以上兩個系統(tǒng)調用,則用戶空間程序仍然可以使用/dev/port設備文件訪問I/O端口。不過要注意,該設備文件的含義與平臺密切相關,并且除PC平臺以處,它幾乎沒有什么用處。
串操作
以上的I/O操作都是一次傳輸一個數據,作為補充,有些處理器實現了一次傳輸一個數據序列的特殊指令,序列中的數據單位可以是字節(jié)、字、雙字。這些指令稱為串操作指令,它們執(zhí)行這些任務時比一個C語言編寫的循環(huán)語句快得多。下面列出的宏實現了串I/O:
void in(unsigned port, void *addr, unsigned long count);
void out(unsigned port, void *addr, unsigned long count);從內存addr開始連續(xù)讀/寫count數目的字節(jié)。只對單一端口port讀取或寫入數據
void insw(unsigned port, void *addr, unsigned long count);
void outsw(unsigned port, void *addr, unsigned long count);對一個16位端口讀寫16位數據
void insl(unsigned port, void *addr, unsigned long count);
void outsl(unsigned port, void *addr, unsigned long count);對一個32位端口讀寫32位數據
在使用串I/O操作函數時,需要銘記的是:它們直接將字節(jié)流從端口中讀取或寫入。因此,當端口和主機系統(tǒng)具有不同的字節(jié)序時,將導致不可預期的結果。使用inw讀取端口將在必要時交換字節(jié),以便確保讀入的值匹配于主機的字節(jié)序。然而,串函數不會完成這種交換。
暫停式I/O
在處理器試圖從總線上快速傳輸數據時,某些平臺(特別是i386)就會出現問題。當處理器時鐘比外設時鐘(如ISA)快時就會出現問題,并且在設備板上特別慢時表現出來。為了防止出現丟失數據的情況,可以使用暫停式的I/O函數來取代通常的I/O函數,這些暫停式的I/O函數很像前面介紹的那些I/O函數,不同之處是它們的名字用_p結尾,如inb_p、outb_p等等。在linux支持的大多數平臺上都定義了這些函數,不過它們常常擴展為非暫停式I/O同樣的代碼,因為如果不使用過時的外設總線就不需要額外的暫停。
平臺相關性
I/O指令是與處理器密切相關的。因為它們的工作涉及到處理器移入移出數據的細節(jié),所以隱藏平臺間的差異非常困難。因此,大部分與I/O端口相關的源代碼都與平臺相關。
回顧前面函數列表可以看到有一處不兼容的地方,即數據類型。函數的參數根據各平臺體系架構上的不同要相應地使用不同的數據類型。例如,port參數在x86平臺上(處理器只支持64KB的I/O空間)上定義為unsigned short,但在其他平臺上定義為unsigned long,在這些平臺上,端口是與內存在同一地址空間內的一些特定區(qū)域。
感興趣的讀者可以從io.h文件獲得更多信息,除了本章介紹的函數,一些與體系架構相關的函數有時也由該文件定義。
值得注意的是,x86家族之外的處理器都不為端口提供獨立的地址空間。
I/O操作在各個平臺上執(zhí)行的細節(jié)在對應平臺的編程手冊中有詳細的敘述;也可以從web上下載這些手冊的PDF文件。
I/O端口示例
演示設備驅動程序的端口I/O的示例代碼運行于通用的數字I/O端口上,這種端口在大多數計算機平臺上都能找到。
數字I/O端口最常見的一種形式是一個字節(jié)寬度的I/O區(qū)域,它或者映射到內存,或者映射到端口。當把數字寫入到輸出區(qū)域時,輸出引腳上的電平信號隨著寫入的各位而發(fā)生相應變化。從輸入區(qū)域讀取到的數據則是輸入引腳各位當前的邏輯電平值。
這類I/O端口的具體實現和軟件接口是因系統(tǒng)而異的。大多數情況下,I/O引腳由兩個I/O區(qū)域控制的:一個區(qū)域中可以選擇用于輸入和輸出的引腳,另一個區(qū)域中可以讀寫實際的邏輯電平。不過有時情況簡單些,每個位不是輸入就是輸出(不過這種情況下就不能稱為“通用I/O”了);在所有個人計算機上都能找到的并口就是這樣的非通用的I/O端口。
并口簡介
并口的最小配置由3個8位端口組成。之一個端口是一個雙向的數據寄存器,它直接連接到物理連接器的2~9號引腳上。第二個端口是一個只讀的狀態(tài)寄存器;當并口連接打印機時,該寄存器 報告 打印機狀態(tài),如是否是線、缺紙、正忙等等。第三個端口是一個只用于輸出的控制寄存器,它的作用之一是控制是否啟用中斷。
如下所示:并口的引腳
示例驅動程序
while(count–) {
outb(*(ptr++), port);
wmb();
}
使用I/O內存
除了x86上普遍使的I/O端口之外,和設備通信的另一種主要機制是通過使用映射到內存的寄存器或設備內存,這兩種都稱為I/O內存,因為寄存器和內存的差別對軟件是透明的。
I/O內存僅僅是類似RAM的一個區(qū)域,在那里處理器可以通過總線訪問設備。這種內存有很多用途,比如存放視頻數據或以太網數據包,也可以用來實現類似I/O端口的設備寄存器(也就是說,對它們的讀寫也存在邊際效應)。
根據計算機平臺和所使用總線的不同,i/o內存可能是,也可能不是通過頁表訪問的。如果訪問是經由頁表進行的,內核必須首先安排物理地址使其對設備驅動程序可見(這通常意味著在進行任何I/O之前必須先調用ioremap)。如果訪問無需頁表,那么I/O內存區(qū)域就非常類似于I/O端口,可以使用適當形式的函數讀取它們。
不管訪問I/O內存是否需要調用ioremap,都不鼓勵直接使用指向I/O內存的指針。相反使用包裝函數訪問I/O內存,這一方面在所有平臺上都是安全的,另一方面,在可以直接對指針指向的內存區(qū)域執(zhí)行操作的時候,這些函數是經過優(yōu)化的。并且直接使用指針會影響程序的可移植性。
I/O內存分配和映射
在使用之前,必須首先分配I/O區(qū)域。分配內存區(qū)域的接口如下(在中定義):
struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);
該函數從start開始分配len字節(jié)長的內存區(qū)域。如果成功返回非NULL,否則返回NULL值。所有的I/O內存分配情況可從/proc/iomem得到。
不再使用已分配的內存區(qū)域時,使用如下接口釋放:
void release_mem_region(unsigned long start, unsigned long len);
下面函數用來檢查給定的I/O內存區(qū)域是否可用的老函數:
int check_mem_region(unsigned long start, unsigned long len);//這個函數和check_region一樣不安全,應避免使用
分配內存之后我們還必須確保該I/O內存對內存而言是可訪問的。獲取I/O內存并不意味著可引用對應的指針;在許多系統(tǒng)上,I/O內存根本不能通過這種方式直接訪問。因此,我們必須由ioremap函數建立映射,ioremap專用于為I/O內存區(qū)域分配虛擬地址。
我們根據以下定義來調用ioremap函數:
#include
void *ioremap(unsigned long phys_addr, unsigned long size);
void *ioremap_nocache(unsigned long phys_addr, unsigned long size);在大多數計算機平臺上,該函數和ioremap相同:當所有I/O內存已屬于非緩存地址時,就沒有必要實現ioremap的獨立的,非緩沖版本。
void iounmap(void *addr);
記住,由ioremap返回的地址不應該直接引用,而應該使用內核提供的accessor函數。
訪問I/O內存
在某些平臺上我們可以將ioremap的返回值直接當作指針使用。但是,這種使用不具有可移植性,訪問I/O內存的正確方法是通過一組專用于些目的的函數(在中定義)。
從I/O內存中讀取,可使用以下函數之一:
unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);
其中,addr是從ioremap獲得的地址(可能包含一個整數偏移量);返回值是從給定I/O內存讀取到的值。
寫入I/O內存的函數如下:
void iowrite8(u8 value, void *addr);
void iowrite16(u16 value, void *addr);
void iowrite32(u32 value, void *addr);
如果必須在給定的I/O內存地址處讀/寫一系列值,則可使用上述函數的重復版本:
void ioread8_rep(void *addr, void *buf, unsigned long count);
void ioread16_rep(void *addr, void *buf, unsigned long count);
void ioread32_rep(void *addr, void *buf, unsigned long count);
void iowrite8_rep(void *addr, const void *buf, unsigned long count);
void iowrite16_rep(void *addr, const void *buf, unsigned long count);
void iowrite32_rep(void *addr, const void *buf, unsigned long count);
上述函數從給定的buf向給定的addr讀取或寫入count個值。count以被寫入數據的大小為單位。
上面函數均在給定的addr處執(zhí)行所有的I/O操作,如果我們要在一塊I/O內存上執(zhí)行操作,則可以使用下面的函數:
void memset_io(void *addr, u8 value, unsigned int count);
void memcpy_fromio(void *dest, void *source, unsigned int count);
void memcpy_toio(void *dest, void *source, unsigned int count);
上述函數和C函數庫的對應函數功能一致。
像I/O內存一樣使用I/O端口
某些硬件具有一種有趣的特性:某些版本使用I/O端口,而其他版本則使用I/O內存。導出給處理器的寄存器在兩種情況下都是一樣的,但訪問方法卻不同。為了讓處理這類硬件的驅動程序更加易于編寫,也為了最小化I/O端口和I/O內存訪問這間的表面區(qū)別,2.6內核引入了ioport_map函數:
void *ioport_map(unsigned long port, unsigned int count);
該函數重新映射count個I/O端口,使其看起來像I/O內存。此后,驅動程序可在該函數返回的地址上使用ioread8及其相關函數,這樣就不必理會I/O端口和I/O內存之間的區(qū)別了。
當不需要這種映射時使用下面函數一撤消:
void ioport_unmap(void *addr);
這些函數使得I/O端口看起來像內存。但需要注意的是,在重新映射之前,我們必須通過request_region來分配這些I/O端口。
為I/O內存重用short
前面介紹的short示例模塊訪問的是I/O端口,它也可以訪問I/O內存。為此必須在加載時通知它使用I/O內存,另外還要修改base地址以使其指向I/O區(qū)域。
下例是在MIPS開發(fā)板上點亮調試用的LED:
mips.root# ./short_load use_mem=1 base = 0xb7ffffc0
mips.root# echo -n 7 > /dev/short0
下面代碼是short寫入內存區(qū)域時使用的循環(huán):
while(count–) {
iowrite8(*ptr++, address);
wmb();
}
MB地址空間之下的ISA內存
最廣為人知的I/O內存區(qū)之一就是個人計算機上的ISA內存段。它的內存范圍在64KB(0xA0000)到1MB(0x100000)之間,因此它正好出現在常規(guī)系統(tǒng)RAM的中間。這種地址看上去有點奇怪,因為這個設計決策是20世紀80年代早期作出的,在當時看來沒有人會用到640KB以上的內存。
怎樣編寫Linux設備驅動程序?
Linux是Unix操作系統(tǒng)的一種變種,在Linux下編寫驅動程序的原理和思想完全類似于其他的Unix系統(tǒng)消掘,但它dos或window環(huán)境下的驅動程序有很大的區(qū)別。在Linux環(huán)境下設計驅動程序,思想簡潔,操作方便,功能也很強大,但是支持函數少,只能依賴kernel中的函數,有些常用的操作要自己來編寫,而且調試也不方便。本人這幾周來為實驗室自行研制的一塊多媒體卡編制了驅動程序,獲得了一些經驗,愿與Linux fans共享
一、Linux device driver 的概念系統(tǒng)調用是操作系統(tǒng)內核和應用程序之間的接口,設備驅動程序是操作系統(tǒng)內核和機器硬件之間的接口。設備驅動程序為應用程序屏蔽了硬件的細節(jié),這樣在應用程序看來,硬件設備只是一個設備文件, 應用程序運敬可以象操作普通文件一樣對硬件設備進行操作。設備驅動程序是內核的一部分,它完成以下的功能:
1.對設備初始化和釋放。
2.把數據從內核傳送到硬件和從硬件讀取數據。
3.讀取應用程序傳送給設備文件的數據和回送應用程序請求的數據。
4.檢測和處旁橋慎理設備出現的錯誤。
二、實例剖析我們來寫一個最簡單的字符設備驅動程序。雖然它什么也不做,但是通過它可以了解Linux的設備驅動程序的工作原理。
google linux設備驅動程序pdf,一堆下載地址。這本書貌似是一個linux內毀前圓核開發(fā)成員寫的。這是linux驅動開發(fā)者必須看纖塌的書悔輪。
您好,這樣的情況建議您下載最新版本的驅動精靈,或是直接在線升級一下驅動精靈。希望可以幫到您。
更好看書
關于linux 塊設備驅動的介紹到此就結束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關注本站。
成都網站建設選創(chuàng)新互聯(lián)(?:028-86922220),專業(yè)從事成都網站制作設計,高端小程序APP定制開發(fā),成都網絡營銷推廣等一站式服務。
文章名稱:「探究Linux塊設備驅動」(linux塊設備驅動)
鏈接URL:http://m.5511xx.com/article/djejioo.html


咨詢
建站咨詢
