Linux裝置驅動程式學習(7)-核心的資料型別
核心資料使用的資料型別主要分為 3 個型別: 標準 C 語言型別、確定大小的型別和特定核心物件的型別。
標準 C 語言型別當需要“一個2位元組填充符”或“用一個4位元組字串來代表某個東西”,就不能使用標準C語言型別,因為在不同的體系結構,C 語言的資料型別所佔的空間大小不同。後面的datasize 程式實驗展示了使用者空間各種 C 的資料型別在當前平臺所佔空間的大小。而且有的構架,核心空間和使用者空間的C 資料型別所佔空間大小也可能不同。kdatasize模組顯示了當前模組的核心空間C 資料型別所佔空間大小。
儘管概念上地址是指標,但使用一個無符號整型可以更好地實現記憶體管理; 核心把實體記憶體看成一個巨型陣列, 記憶體地址就是該陣列的索引。 我們可以方便地對指標取值,但直接處理記憶體地址時,我們幾乎從不會以這種方式對他取值。使用一個整數型別避免了這種取值,因此避免了 bug。所以,利用至少在 Linux 目前支援的所有平臺上,指標和長整型始終是相同大小的這一事實,核心中記憶體地址常常是 unsigned long。
C99 標準定義了 intptr_t 和 uintptr_t 型別,它們是能夠儲存指標值的整型變數。但沒在 2.6 核心中幾乎沒使用。
確定大小的型別當需要知道你定義的資料的大小時,可以使用核心提供的下列資料型別(所有的資料宣告在 <asm/types.h>, 被包含在 <linux/types.h> ):
|
若一個使用者空間程式需要使用這些型別,可在符號前加一個雙下劃線: __u8和其它型別是獨立於 __KERNEL__ 定義的。
這些型別是 Linux 特定的,它們妨礙了移植軟體到其他的 Unix 機器。新的編譯器系統支援 C99-標準 型別,如 uint8_t 和 uint32_t。若考慮移植性,使用這些型別比 Linux特定的變體要好。
核心中最常用的資料型別由它們自己的 typedef 宣告,阻止了任何移植性問題。“介面特定(interface-specific)”由某個庫定義的一種資料型別, 以便為了某個特定的資料結構提供介面。很多 _t 型別在 <linux/types.h> 中定義。
注意:近來已經很少定義新的介面特定的型別。有許多核心開發者已經不再喜歡使用 typedef 語句,他們寧願看到程式碼中直接使用的真實型別資訊。很多老的介面特定型別在核心中保留,他們不會很快消失。
即使沒有定義介面特定型別,也應該始終是用和核心其他部分保持一致、適當的資料型別。只要驅動使用了這種“定製”型別的函式,但又不遵照約定,編譯器會發出警告,這時使用 -Wall 編譯器選項並小心去除所有的警告,就可以確信程式碼的可移植性了。
_t 型別的主要問題是:列印它們時,常常不容易選擇正確的 printk 或 printf 格式。列印介面特定的資料的最好方法是:將其強制轉換為可能的最大型別(常常是 long 或 unsigned long ) 並用相應的格式列印。
其他移植性問題移植的一個通常規則是:避免使用顯式的常量值,要使用預處理巨集使常量值引數化。
時間間隔
當處理時間間隔時,不要假定每秒的jiffies個數,不是每個 Linux 平臺都以固定的速度執行.當計算時間間隔時,要使用 HZ ( 每秒的定時器中斷數 ) 來標定你的時間。s3c2410的HZ值預設為200。
頁大小
當使用記憶體時,記住一個記憶體頁是 PAGE_SIZE 位元組, 不是 4KB。相關的巨集定義是 PAGE_SIZE 和 PAGE_SHIT(包含將一個地址移位來獲得它的頁號的位數),在 <asm/page.h> 中定義。如果使用者空間程式需要這些資訊,可以使用 getpagesize 庫函式。
若一個驅動需要 16 KB 來暫存資料,一個可移植得解決方法是 get_order:
|
位元組序
不要假設位元組序。 程式碼應該編寫成不依賴所操作資料的位元組序的方式。
標頭檔案 <asm/byteorder.h> 定義:
|
在<linux/byteorder/big_endian.h>中定義了__BIG_ENDIAN ,而在<linux/byteorder/little_endian.h>中定義了__LITTLE_ENDIAN,這些依賴處理器的位元組序當處理位元組序問題時,需要編碼一堆類似 #ifdef __LITTTLE_ENDIAN 的條件語句。
但是還有一個更好的方法:Linux 核心有一套巨集定義來處理處理器位元組序和特定位元組序之間的轉換。例如:
|
編寫可移植程式碼而值得考慮的最後一個問題是如何訪問未對齊的資料。存取不對齊的資料應當使用下列巨集:
|
關於對齊的另一個問題是資料結構的跨平臺移植性。同樣的資料結構在不同的平臺上可能被不同地編譯。為了編寫可以跨體系移植的資料結構,應當始終強制資料項的自然對齊。自然對齊(natural alignment)指的是:資料項大小的整數倍的地址上儲存資料項。 應當使用填充符避免強制自然對齊時編譯器移動資料結構的欄位,在資料結構中留下空洞。
dataalign 程式實驗展示了編譯器如何強制對齊。
為了目標處理器的良好效能,編譯器可能悄悄地插入填充符到結構中,來保證每個成員是對齊的。若定義一個和裝置要求的結構體相匹配結構,自動填充符會破壞這個意圖。解決這個問題的方法是告訴編譯器這個結構必須是"緊湊的", 不能增加填充符。例如下列的定義:
|
你還可以在利用ARM9和USB攝像頭進行視訊採集的servfox原始碼的spcaframe.h標頭檔案中找到這種方法的實際應用:
|
許多核心介面通過將錯誤值編碼到指標值中來返回錯誤資訊。這樣的資訊必須小心使用,因為它們的返回值不能簡單地與 NULL 比較。為幫助建立和使用這類介面, <linux/err.h>提供了這樣的函式:
|
連結串列
作業系統核心常需要維護資料結構的連結串列。Linux 核心已經同時有幾個連結串列實現。為減少複製程式碼的數量, 核心已經建立了一個標準環形雙向連結串列,並鼓勵需要操作連結串列的人使用這個設施.
使用連結串列介面時,應當記住列表函式沒做加鎖。若驅動可能同一個列表併發操作,就必須實現一個鎖方案。
為使用連結串列機制,驅動必須包含檔案 <linux/list.h> ,它定義了一個簡單的list_head 型別 結構:
|
實際程式碼中使用的連結串列幾乎總是由某個結構型別組成, 每個結構描述連結串列中的一項. 為使用 Linux 連結串列,只需嵌入一個 list_head 在構成在這個連結串列的結構裡面。連結串列頭常常是一個獨立的 list_head 結構。下圖顯示了這個簡單的 struct list_head 是如何用來維護一個數據結構的列表的.
|
ARM9實驗板實驗
datasize實驗
實驗中有用到uname函式,介紹如下(載自《UNIX環境高階程式設計》,第6章系統資料檔案和資訊 6.8 系統標識):
POSIX.1定義了uname函式,它返回與主機和作業系統有關的資訊。 |
kdatasize模組實驗
實驗中有用到utsname函式,原始碼如下:
|
kdataalign模組實驗
具體試驗原理請看原始碼
實驗現象:
|
相關推薦
Linux裝置驅動程式學習(7)-核心的資料型別
由於前面的學習中有用到 第十一章 核心資料結構型別 的知識,所以我先看了。要點如下: 將linux 移植到新的體系結構時,開發者遇到的若干問題都與不正確的資料型別有關。堅持使用嚴格的資料型別和使用 -Wall -Wstrict-prototypes 進行編譯可能避免大部分
Linux裝置驅動程式學習(13)
匯流排 匯流排是處理器和一個或多個裝置之間的通道,在裝置模型中, 所有的裝置都通過匯流排相連, 甚至是內部的虛擬"platform"匯流排。匯流排可以相互插入。裝置模型展示了匯流排和它們所控制的裝置之間的實際連線。在 Linux 裝置模型中, 匯流排由 bus_type 結構
Linux裝置驅動程式學習(12) -Linux裝置模型(底層原理簡介)
以《LDD3》的說法:Linux裝置模型這部分內容可以認為是高階教材,對於多數程式作者來說是不必要的。但是我個人認為:對於一個嵌入式Linux的底層程式設計師來說,這部分內容是很重要的。 以我學習的ARM9為例,有很多匯流排(如SPI、IIC、IIS等等)在Linux下已經被
Linux裝置驅動程式學習(14)
通過一個裝置在核心中生命週期的各個階段,可以更好地理解Linux裝置模型。我將通過分析lddbus和sculld的原始碼來了解Linux裝置模型中各環節的整合。《LDD3》中的(PCI匯流排)各環節的整合這部分內容作為參考資料,因為嵌入式Linux比較少用到PCI匯流排。看這
Linux裝置驅動程式學習筆記7--時間、延遲及延緩操作
#include <linux/timer.h>struct timer_list { struct list_head entry; unsigned long expires;/*期望定時器執行的絕對 jiffies 值,不是一個 jiffies_64 值,因為定時器不被期望在將來
Linux裝置驅動程式學習(基於2440的GPIO字元裝置驅動)
GPIO驅動程式如下: #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> #include <li
嵌入式Linux裝置驅動開發筆記(一)
一、Linux裝置的分類 字元裝置、塊裝置、網路裝置,三種裝置之間的區別是資料的互動模式,分別為: 位元組流、資料塊、資料包。 二、VFS核心結構體 VFS核心結構體定義在”linux/fs.h”標頭檔案中。 1、struct inode結構體 記
linux裝置驅動歸納總結(五):2.操作硬體——IO記憶體
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSi
linux裝置驅動歸納總結(六):3.中斷下半部之tasklet
linux裝置驅動歸納總結(六):3.中斷的上半部和下半部——tasklet xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 一、什麼是下半部 中斷是一個很霸道的東西,處理
linux裝置驅動歸納總結(九):1.platform匯流排的裝置和驅動
linux裝置驅動歸納總結(九):1.platform匯流排的裝置和驅動 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 這一節可
linux裝置驅動歸納總結(九):1.platform裝置驅動
http://blog.chinaunix.net/uid-25014876-id-111745.html 這一節可以理解是第八章的延伸,從這節開始介紹platform裝置驅動。 一、什麼是paltform匯流排 一個現實的linux裝置和驅
Linux裝置驅動程式學習----1.裝置驅動程式簡介
裝置驅動程式簡介 更多內容請參考Linux裝置驅動程式學習----目錄 1. 簡介 Linux系統的優點是,系統內部實現細節對所有人都是公開的。Linux核心由大量複雜的程式碼組成,裝置驅動程式可以作為進入Linux核心世界大門的切入口。 裝置驅動程式在Linux核心中,是一個個獨立的黑盒子,在呼叫內
Python學習(1)——基礎資料型別
目錄 1、Python的應用 2、Python的優缺點 2.1 優點 2.2缺點 3.使用者輸入 4、格式化輸出 5、資料型別 5.1 bytes 5.2 字串 5.3 列表 5.4 元組 5.5 字典 5.6 集合 6、綜合例項 1、
Python學習(3)—— 基本資料型別一:數字型別
基本資料型別一:數字型別 Python中最基本的資料型別之一就是int資料型別。 數字型別中有int、long 、float、complex。 python3.x之後已經不區分int和long,統一用int;python2.x還是區分的。 floa
openCV學習(一)Mat資料型別
Mat資料結構Mat型別是opencv2.0後的型別,使用此型別無需進行記憶體管理,即無需手動分配記憶體,在不需要時自動釋放記憶體,但因目前的許多嵌入式系統僅支援c語言,故而除了在某些嵌入式系統中使用cvMat或IplImage, 基本使用Mat型別。注:後續的matrix均
go學習(二)——基本資料型別和基本語法
在 Go 程式語言中,資料型別用於宣告函式和變數。 資料型別的出現是為了把資料分成所需記憶體大小不同的資料,程式設計的時候需要用大資料的時候才需要申請大記憶體,就可以充分利用記憶體。 1.常見資料型別 Go 語言按類別有以下幾種資料型別: 1 布林型 布林型的值只可
Java學習(十)基本資料型別的包裝類
byte ——> Byte short ——> Short char——> Character int ——> Integer long ——> Long float ——> Float double ——> Double boolean ——> Boolean
redis學習(四)——Hash資料型別
一、概述 我們可以將Redis中的Hash型別看成具有String Key和String Value的map容器。所以該型別非常適合於儲存值物件的資訊。如Username、Password和Age等。如果Hash中包含很少的欄位,那麼該型別的資料也將僅佔用很少的磁碟
Linux裝置驅動程式架構分析之I2C架構(基於3.10.1核心)
作者:劉昊昱 核心版本:3.10.1 I2C體系架構的硬體實體包括兩部分: 硬體I2C Adapter:硬體I2C Adapter表示一個硬體I2C介面卡,也就是I2C控制器。一般是SOC中的一個介面,也可以用GPIO模擬。硬體I2C Adapter主要用來在I2
Linux裝置驅動程式架構分析之MMC/SD(二)
作者:劉昊昱 核心版本:3.10.1 一、s3cmci_ops分析 在上一篇文章中我們分析了Mini2440 MMC/SD驅動的probe函式s3cmci_probe。在該函式中初始化了struct mmc_host指標變數mmc,其中,設定mmc->ops為s