2012年11月22日 星期四

[轉錄]Linux 驅動程式一般化設計流程


一般化設計流程
我們提過,依照驅動程式本身的實作,可以將 Linux 驅動程式分為 2 大部份:virtual device driver與physical device driver。


此流程為一個觀念流程,實際撰寫驅動程式時,並不會完全以這個流程來設計。但初學Linux驅動程式時,則應以此流程為主循序學習,才能理解基本的Linux驅動程式實作。
對Linux驅動程式而言,virtual device driver的重要性遠在physical device driver之上,乍聽之下這或許不太能理解,因為沒有physical device driver是無法真正驅動硬體的。但實作上,physical device driver是一成不變的程式寫法,能不能寫出好的驅動程式,關鍵是在virtual device driver的部份。
struct file_operations
struct file_operations 是 kernel 提供的一個重要資料結構,這是學習 Linux 驅動程式第一個會認識的對象,也是最重要的一個主題。
Linux 驅動程式建構在 file_operations 之上。file_operations定義驅動程式的system call與實作system call的函數,我們把file_operations任何一個部份拿出來討論的話,都能切成virtual device driver與physical device driver二個部份。
流程解說
Virtual device driver往上是為了連結Linux kernel的VFS層,physical device drvier往下是為了存取實體硬體。
Virtual Device Driver
Virtual device driver 的目的在於設計一個「機制」良好的kernel mode驅動程式,virtual device driver也必須考慮與user application的互動。實作上,則是需要善用kernel所提供的介面(interface),即kernel APIs。
Virtual device driver再分為3階段的觀念實作:
  1. 定義 file_operations
  2. 實作 system calls
  3. 註冊 driver (VFS)
fops 是指向 file_operations 結構的指標,驅動程式呼叫 register_chrdev() 將fops註冊到 kernel 裡後,fops 便成為該 device driver 所實作的system call進入點。實作system call的函數便是透過file_operations結構來定義,我們稱實作system call的函數為driver method。
kernel 會在需要時回呼 (callback) 我們所註冊的driver method。因此,當 driver 裡的 method 被呼叫時,kernel便將傳遞參數(parameters)給 driver method,driver method可由 kernel 所傳遞進來的參數取得驅動程式資訊。
註冊driver的動作呼叫register_chrdev()函數完成,此函數接受3個參數如下:
  1. major:要註冊的裝置 major number
  2. name:device 名稱
  3. fops:driver 的 file operation
「註冊」這個動作觀念上是將fops加到kernel的VFS層,因此user application必須透過「device file」才能呼叫到driver method。註冊這個動作的另一層涵意則是將driver method與不同的system call做「正確的對應」,當user application呼叫system call時,才能執行正確的driver method。

Physical Device Driver

Physical device driver的目的在於實作控制硬體的程式碼。Physical device driver 的設計必須隨時查閱晶片(chipsets)的 data sheet,並透過晶片的 control register 來控制裝置。
理論上,我們可以將晶片的暫存器分成3大類:
  1. data registers
  2. control registers
  3. status registers
Data register是晶片裡用來存放資料的暫存器,control register則是用來控制晶片行為的暫存器,status register則保存目前晶片的狀態。設計控制硬體周邊的驅動程式時,需要了解硬體使用的晶片組,晶片組則需要參考IC設計廠商所提供的「datasheet」才能了解晶片組的暫存器名稱與用途,通常不同的暫存器會對應到一個「相對」的偏移位址(offset)。
驅動程式則是要透過control register才能控制晶片,因此需要隨時查閱晶片的datasheet,並了解每一個暫存器的用途。通常暫存器的每個位元(bit)也都是有特定用途的,因此設計驅動程式時,必須要很熟悉C語言的位元運算用法。
實作上,首先會將晶片的 datasheet 寫成C語言的標頭檔,通常這個檔案都可以從 vendor 取得。
接著再定義一組操作暫存器的I/O函數,我們稱這組函數為I/O wrapper function。I/O wrapper functions通常是重新定義Linux kernel所提供的readb()、writeb()或inb()、outb()系列函數所寫成的。
最後,利用I/O wrapper function實作一系列的控制函數,以控制實際硬體,我們稱此函數為chipset control functions。Chipset control functions是由實作system calls的函數(driver method)所呼叫,因此在設計chipset control functions時也會回頭改寫driver method以符合此階段的實作。



本文地址:http://read.newbooks.com.cn/info/167897.html

2012年11月20日 星期二

Block/Character Device Driver


Block Device Driver      :以固定大小長度來傳送轉移資料
Character Device Driver:以不定長度的字元傳送資料

        連接的Devices也有所不同,Block Device大致是可以隨機存取(Random Access)資料的設備,如 硬 碟 機 或 光 碟 機 ;而Character Device剛好相反,依循先後順序存取資料的設備,如印表機、終端機等皆是

I/O port連接埠 和 I/O memory


     裝置通常會提供一組暫存器用來控制裝置、讀寫裝置和獲取裝置,也就是控制暫存器、資料暫存器、狀態暫存器
     這些暫存器位於I/O 空間 也可能位於記憶體空間;當位於I/O空間時通常被稱為I/O port連接埠
當位於記憶體空間時對應的記憶體空間稱為I/O memory

linux driver的裝置檔概念整理


     在UNIX系統底下我們把外部周邊裝置軍事危1個檔案,並透過此檔案與實體作溝通,此檔案就叫做device files或 special files

     設計driver時,會透過1個註冊register的動作,將自己註冊到kernel裡;註冊時會指定一個major number參數以指定此驅動程式所要實作週邊實體裝置

     當user開啟device file時,kernel便會根據device file的major number找到對應的驅動程式回應給使用者;minor number 則是device driver內部所使用,kernel並不會處理不同的minor number

2012年11月7日 星期三

vim 顯示行數


一般情況下,進入vim 後是不會顯示出行數,
如要此功能需要在 vim command 內下 :set nu! 就可以了。
但這樣使用有點麻煩,如要讓每次都顯示則需修改 /etc/vimrc 設定檔,
vim /etc/vimrc
在最底下加入
set nu
存檔離開,即可以每次使用 vim 時都會列出行數了

2012年10月25日 星期四

[轉貼]zImage,uImage 區別


資料來源: zImage,uImage 區別
對於Linux內核,編譯可以生成不同格式的映像文件,例如:
# make zImage
# make uImage
zImage是ARM Linux常用的一種壓縮映像文件,uImage是U-boot專用的映像文件,它是在zImage之前加上一個長度為0×40的「頭」,說明這個映像文件的類型、加載位置、生成時間、大小等信息。換句話說,如果直接從uImage的0×40位置開始執行,zImage和uImage沒有任何區別。另外,Linux2.4內核不支持uImage,Linux2.6內核加入了很多對嵌入式系統的支持,但是uImage的生成也需要設置。
一、vmlinuz
vmlinuz是可引導的、壓縮的內核。「vm」代表「Virtual Memory」。Linux 支持虛擬內存,不像老的操作系統比如DOS有640KB內存的限制。Linux能夠使用硬盤空間作為虛擬內存,因此得名「vm」。
vmlinuz 的建立有兩種方式。一是編譯內核時通過「make zImage」創建,然後通過:「cp /usr/src/linux-2.4/arch/i386/linux/boot/zImage/boot/vmlinuz」產生。zImage適用於小內核的情況,它的存在是為了向後的兼容性。
二是內核編譯時通過命令make bzImage創建,然後通過:「cp/usr/src/linux-2.4/arch/i386/linux/boot/bzImage /boot/vmlinuz」產生。bzImage是壓縮的內核映像,需要注意,bzImage不是用bzip2壓縮的,bzImage中的bz容易引起誤解,bz表示「big zImage」。 bzImage中的b是「big」意思。 zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip壓縮的。它們不僅是一個壓縮文件,而且在這兩個文件的開頭部分內嵌有 gzip解壓縮代碼。所以你不能用gunzip 或 gzip –dc解包vmlinuz。
二、initrd-x.x.x.img
initrd是「initial ramdisk」的簡寫。initrd一般被用來臨時的引導硬件到實際內核vmlinuz能夠接管並繼續引導的狀態。
initrd 映像文件是使用mkinitrd創建的。mkinitrd實用程序能夠創建initrd映像文件。這個命令是RedHat專有的。其它Linux發行版或許有相應的命令。這是個很方便的實用程序。具體情況請看幫助:man mkinitrd下面的命令創建initrd映像文件。
最後生成的內核鏡像有兩種 zImage 以及 uImage 。其中 zImage 下載到目標板中後,可以直接用 uboot 的命令go 來進行直接跳轉。這時候內核直接解壓啟動。但是無法掛載文件系統,因為 go 命令沒有將內核需要的相關的啟動參數傳遞給內核。傳遞啟動參數我們必須使用命令 bootm 來進行跳轉。 Bootm 命令跳轉只處理 uImage 的鏡像。
uboot 源代碼的 tools/ 目錄下有 mkimage 工具,這個工具可以用來製作不壓縮或者壓縮的多種可啟動映像文件。
mkimage 在製作映像文件的時候,是在原來的可執行映像文件的前面加上一個 0×40 字節的頭,記錄參數所指定的信息,這樣 uboot 才能識別這個映像是針對哪個 CPU 體系結構的,哪個 OS 的,哪種類型,加載內存中的哪個位置, 入口點在內存的那個位置以及映像名是什麼
用法如下:
./mkimage -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
-A ==> set architecture to ‘arch’
-O ==> set operating system to ‘os’
-T ==> set image type to ‘type’
-C ==> set compression type ‘comp’
-a ==> set load address to ‘addr’ (hex)
-e ==> set entry point to ‘ep’ (hex)
-n ==> set image name to ‘name’
-d ==> use image data from ‘datafile’
-x ==> set XIP (execute in place)
參數說明:
-A 指定 CPU 的體系結構:
取值 表示的體系結構
alpha Alpha
arm A RM
x86 Intel x86
ia64 IA64
mips MIPS
mips64 MIPS 64 Bit
ppc PowerPC
s390 IBM S390
sh SuperH
sparc SPARC
sparc64 SPARC 64 Bit
m68k MC68000
-O 指定操作系統類型,可以取以下值:
openbsd 、 netbsd 、 freebsd 、 4_4bsd 、 linux 、 svr4 、 esix 、 solaris 、 irix 、 sco 、 dell 、 ncr 、 lynxos、 vxworks 、 psos 、 qnx 、 u-boot 、 rtems 、 artos
-T 指定映像類型,可以取以下值:
standalone 、 kernel 、 ramdisk 、 multi 、 firmware 、 script 、 filesystem
-C 指定映像壓縮方式,可以取以下值:
none 不壓縮
gzip 用 gzip 的壓縮方式
bzip2 用 bzip2 的壓縮方式
-a 指定映像在內存中的加載地址,映像下載到內存中時,要按照用 mkimage 製作映像時,這個參數所指定的地址值來下載
-e 指定映像運行的入口點地址,這個地址就是 -a 參數指定的值加上 0×40 (因為前面有個 mkimage 添加的0×40 個字節的頭)
-n 指定映像名
-d 指定製作映像的源文件
我在編譯時用到的命令如下:
# make zImage      // 生成 zImage 鏡像
# /usr/local/arm/k9uboot/tools/ mkimage -n ‘Linux 2.4.27′ -A arm -O linux -T
kernel -C none -a 0×20007fc0 -e 0×20008000 -d zImage uImage

2012年10月18日 星期四