linux下I/O體系結構和設備驅動程序

一臺計算機包括集中不同類型的總線,它們通過被稱爲“橋”的硬件設備連接在一起。

任何I/O設備有且僅能連接一條總線。

linux內核包含了輔助函數來簡化彙編語言指令的訪問I/O端口(inb(),inb_p(),outb(),outb_p()).

通常I/O設備驅動程序爲了探測硬件設備,需要盲目地向某一I/O端口寫入數據,但是,如果其他硬件設備已經使用了這個端口,那麼系統就會崩潰,爲了防止這種情況發生,內核必須使用資源來記錄分配給每個硬件設備的I/O端口。

init_main()->set_arch()->resource_init();->request_resource();//申請了內存資源

當前分配給I/O設備的所有I/O地址的樹都可以從/proc/ioports文件中獲取。

系統中所有硬件設備由內核全權負責電源管理

/proc文件系統是首次被設計成允許用戶態應用程序訪問內核內部數據結構的一種文件系統。

sysfs文件系統的目標是要展現設備驅動程序模型組件間的層次關係。其中的不同文件的主要作用還是表示驅動程序和設備的屬性

設備驅動程序模型的核心數據結構是一個普通的數據結構叫做kobject,每個kobject對應於sysfs文件系統中的一個目錄

一個kset就是kobject集合體,但是他依賴於層次數中用於引用計數和連接的更高層kobject。//???

sysfs_create_file()函數接收kobject的地址和屬性描述符作爲它的參數,並在合適的麋鹿中創建特殊文件。

對於任何總線類型來說,都有一個鏈表存放連接到該類型總線上的所有設備。

device_register()函數的功能是往設備驅動程序模型中插入一個新的device對象,並自動地在/sys/devices目錄下爲其創建一個新的目錄。

當內核檢查一個給定的設備是否可以由給定的驅動程序處理時,就會執行mathc()方法。

當特定類型總線上的設備必須改變其供電狀態時,就會執行suspend和resume方法。

設備文件的索引節點並不包含指向磁盤上數據塊的指針 ,它們是空的,必須包含硬件設備上的一個標識符,它對應字符或塊設備文件。

mknod();用來創建設備文件。//???和device_create();有什麼區別

注意字符設備和塊設備有獨立的編號

在某些情況下,設備文件不會和任何實際的硬件對應,而是表示一個虛擬的硬件設備

內核在動態分配設備號時,是不能永久創建設備文件,只在設備驅動程序初始化一個主設備號和次設備號時才創建。此時可以吧主設備號和次設備號存放在/sys/class/子目錄下的dev屬性中。

//

udev工具集可以自動創建相應的設備文件,因爲設備驅動程序模型支持設備的熱插拔。當發現一個新的設備時,內核就會產生一個新的進程來執行用戶態shell腳本文件/sbin/hotplug,並將新設備上的有用信息作爲環境變量傳遞給shell腳本。用戶態腳本文件讀取配置文件信息並關注完成新設備初始化必需的任何操作。

設備文件的VFS處理,通過適當的文件系統函數ext3_iget()讀取磁盤上的相對應的索引節點來對索引節點對象初始化,當這個函數確定磁盤索引節點與設備文件對應時,則調用init_special_inode();該函數把索引節點對象的i_fop字段設置成def_blk_fops或者def_chr_fops文件操作的地址(根據設備文件類型),open()系統調用的服務例程調用dentry_open()函數,後者分配一個新的文件對象,並將其f_op字段設置爲i_fop中存放的地址,即再一次指向def_blk_fops或def_chr_fops的地址。正是這兩個表的引入,才使得在設備文件上所發出的任何系統調用都將激活設備驅動程序的函數而不是基本文件系統的函數。//***

由於每個設備都有一個唯一的I/O控制器,因此就有唯一的命令和唯一的狀態信息,所以大部分I/O設備都有自己的驅動程序。

如果設備文件對應的驅動程序以前沒有註冊,則該設備文件的訪問會返回錯誤碼-ENODEV

對設備驅動程序註冊和初始化是兩件不同的事,設備驅動程序應當儘快被註冊,以便用戶應用程序能通過相應的設備文件使用它,相反,設備驅動程序在最後可能的時刻才被初始化。

一般而言,所有使用中斷的I/O驅動程序都依賴中斷處理程序及read和write方法均訪問的數據結構

內核程序作用於線性地址,因此I/O共享存儲器單元必須表示成大於PAGE_OFFSET的地址,驅動程序必須把I/O共享存儲器單元的物理地址轉換成內核空間的線性地址。

爲了在內核頁表中包括對超過系統RAM最大的物理地址的I/O物理地址進行映射的線性地址,必須對頁表進行修改。可以通過ioremap()或者ioremap_nocache()函數來實現。

DMA一旦被CPU激活,就可以自行傳送數據,當數據傳送完成之後,DMA就發出一箇中斷請求。

因爲DMA的設置時間相當長,所以在傳送數量很少的數據時直接使用CPU效率更高。

設備驅動程序可以採用兩種方式使用DMA,分別是同步DMA(數據傳送是由進程觸發的),異步DMA(數據傳送是由硬件設備觸發的)

存儲器地址:邏輯地址,線性地址,物理地址,總線地址(除CPU之外的硬件設備驅動數據總線時所用的存儲器地址)。在80x86體系結構中,總線地址和物理地址是一致的。

DMA的每次數據傳送至少需要一個內存緩衝區,它包含硬件設備要讀出或寫入的數據。

使用DMA的所有I/O驅動程序在啓動一次數據傳送前必須設置好IO-MMU

在linux中,數據類型dma_addr_t代表一個通用的總線地址。

dma_set_mask()用於檢查總線是否可以接受給定大小的總線地址。

執行DMA映射操作時,DMA輔助函數必須考慮硬件高速緩存

一般來說,如果CPU和DMA處理器以不可預知的方式去訪問一個緩衝區,那麼必須強制使用一致性DMA映射方式。

流式DMA映射的內存緩衝區通常在數據傳送之前被映射,在傳送之後被取消映射。

爲了避免高速緩存一致性問題,驅動程序在開始從RAM到設備的DMA數據傳送之前,如果有必要,應該調用dma_sync_single_for_device()函數刷新與DMA緩衝區對應的高速緩存行;同樣的,從設備到RAM的一次DMA數據傳送完成之前設備驅動程序是不可以訪問內存緩衝區的。

字符設備驅動程序是由一個cdev結構體描述的

  struct cdev {
          struct kobject kobj;
          struct module *owner;
          const struct file_operations *ops;
          struct list_head list;
          dev_t dev;
          unsigned int count;
  };

一個設備驅動程序對應的設備號可以是一個範圍,而不僅僅是一個號;設備號位於同一範圍內的所有設備文件均有同一個字符設備驅動程序處理。

爲了記錄目前已經分配了哪些字符設備號,內核使用散列表chrdevs,表的大小不超過設備號的範圍。




發佈了41 篇原創文章 · 獲贊 8 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章