顯示具有 linux 標籤的文章。 顯示所有文章
顯示具有 linux 標籤的文章。 顯示所有文章

2010年1月29日 星期五

利用automake自動產生Makefile

雖然自己寫個Makefile就行,但是open source project很多都利用這個工具來產生Makefile,還是來了解一下它吧。

假如我目錄下有 hello.c a.c兩個檔案

執行步驟:

1.#autoscan 產生 configure.scan


2.修改 configure.scan

# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.64])
AC_INIT(hello, 0.1, ecken@ecken.com)
AM_INIT_AUTOMAKE(hello,0.1)

AC_CONFIG_SRCDIR([hello.c])
#AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.

AC_OUTPUT(Makefile)


3.更改configure.scan檔名
#mv configure.scan configure.in

4.執行 aclocal
# aclocal

5.執行 autoconf
#autoconf

6.自行編輯Makefile.am
#vi Makefile.am
AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS=hello
hello_SOURCES=hello.c a.c

7.執行automake 產生Makefile.in
# automake -a

這樣就可以執行./configure 產生Makefile

所以整個需要須改手動更改新增的檔案有configure.in, Makefile.am



參考資料:

邱小新の工作筆記
陳雍穆(armor)
zjsxycli的空間

2009年11月27日 星期五

Git introduction and linux command

Git是分散式的版本控制系統(Distributed Revision Control System,DVCS),與其它CVS不同的是它並不一定需要伺服器才能使用,所以我只需要在我的PC上操作即可。它利用分散式的管理方法, 也就是說每個人下載的版本裡有包含有史以來更改過的紀錄。目前有許多的open source project都漸漸的從Subversion 轉到Git,知名的project如 linux kernel, Samba, X.org server, Ruby on Rails....還有許多的專案也都支援使用Git下載最新代碼。

在linux中要使用Git可先到Git官網下載最新版本,然後安裝。我的安裝方式如下:
[root@ecken01 work2]# tar jxvf git-1.6.5.3.tar.bz2
[root@ecken01 work2]# cd git-1.6.5.3
[root@ecken01 git-1.6.5.3]# make
[root@ecken01 git-1.6.5.3]# make install
它會安裝到預設的目錄去,預設的目錄是家目錄 ~/bin/ ,若要更改安裝目錄可使用
[root@ecken01 git-1.6.5.3]# make prefix=/usr install



在linux command 下的基本指令如下:


git init # 開始用 Git 來管理
git add mine.txt # 把 mine.txt 這個檔案加入管理
git add . # 把所有檔案加入 Git
git commit -a # 提交,將目前的檔案狀態變成一個版本
git commit -a -m "your message here" # commit 時直接寫訊息, 不用到下個螢幕上寫

git clone git://github.com/someone/some_project.git local_project #從遠端複製一份專案到我的電腦,目錄名稱為local_project

git status # 查詢從上個版本到現在哪些檔案被修改
git diff # 查詢從上個版本到現在哪幾行被修改
git diff v0.01 v0.03 # 查詢兩個版本間的差異
git diff v0.01:story.txt v0.03:story.txt # 查詢兩個版本間某個檔案的差異

git log # 顯示每個版本那些檔案被修改
git log -p # 顯示每個版本檔案修改的內容
git log --stat --summary # 查詢每個版本間變動的檔案跟行數

git tag v0.02 # 本版別名取為 v0.02
git tag v0.03 40e3e # 把版本 40e3e 取名為 v0.03
git show v1.01 # 查詢 v1.01 版裡的修改內容
git show v1.01:story.txt # 叫出在 v1.01 版時的 story.txt 檔案
git show v1.01:story.txt > test.txt # 把 v1.01 版的 story.txt 抓出來,放入一個叫 test.txt 的檔案
git show HEAD # 看此版本修改的資料
git show HEAD^ # 看此版本前一版的修改的資料

git grep "熊" # 查詢現在的版本裡有沒有熊

git branch 加英文版 # 建立新的分枝叫 "加英文版"
git branch # 查看現有的分枝
git branch beta v0.5 # 依照 "v0.5" 版裡的內容來建立一個叫 "beta" 的分枝
git checkout 加英文版 # 換到 "加英文版" 的分枝上
git checkout master # 換到主幹上
git branch -d 加英文版 # 刪除 "加英文版" 分枝

gitk # 版本瀏覽軟體(需要X-window)
git gui # 瀏覽從上一版本到現在變動的地方(需要X-window)

git gc # 維護 Git 的資料庫
git fsck --full # 同上, 三不五時下次指令

參考資料:
國網中心 Ruby on Rails
Tsuang's Blog
Book: Pro Git
朱雀雀的巴士站

2009年11月19日 星期四

Porting Glib to ARM

Glib 是一種低階的函式庫,創建 GDK 和 GTK 應用程式時該函式庫可提供許多有用的定義和函式。
它全部是用C語言構成的,當要大量使用資料結構或演算法時,它真的是一個好的library,雖然不玩GTK,不過glib的功能可以簡化我的程式碼,不用寫的哩哩摳摳一大串,現在先從它的README看一下它的功能:

GLib Core Application Support
The Main Event Loop — manages all available sources of events
Threads — thread abstraction; including threads, different mutexes, conditions and thread private data
Thread Pools — pools of threads to execute work concurrently
Asynchronous Queues — asynchronous communication between threads
Dynamic Loading of Modules — portable method for dynamically loading 'plug-ins'
Memory Allocation — general memory-handling
IO Channels — portable support for using files, pipes and sockets
Error Reporting — a system for reporting errors
Message Output and Debugging Functions — functions to output messages and help debug applications
Message Logging — versatile support for logging messages with different levels of importance

GLib Utilities
String Utility Functions — various string-related functions
Character Set Conversion — convert strings between different character sets using iconv()
Unicode Manipulation — functions operating on Unicode characters and UTF-8 strings
Base64 Encoding — encodes and decodes data in Base64 format
Data Checksums — Computes the checksum for data
Internationalization — gettext support macros
Date and Time Functions — calendrical calculations and miscellaneous time stuff
Random Numbers — pseudo-random number generator
Hook Functions — support for manipulating lists of hook functions
Miscellaneous Utility Functions — a selection of portable utility functions
Lexical Scanner — a general purpose lexical scanner
Automatic String Completion — support for automatic completion using a group of target strings
Timers — keep track of elapsed time
Spawning Processes — process launching
File Utilities — various file-related functions
URI Functions — URI Functions
Hostname Utilities — Internet hostname utilities
Shell-related Utilities — shell-like commandline handling
Commandline option parser — parses commandline options
Glob-style pattern matching — matches strings against patterns containing '*' (wildcard) and '?' (joker)
Perl-compatible regular expressions — matches strings against regular expressions
Simple XML Subset Parser — parses a subset of XML
Key-value file parser — parses .ini-like config files
Bookmark file parser — parses files containing bookmarks
Testing — a test framework
Windows Compatibility Functions — UNIX emulation on Windows

GLib Data Types
Memory Slices — efficient way to allocate groups of equal-sized chunks of memory
Memory Chunks — deprecated way to allocate groups of equal-sized chunks of memory
Doubly-Linked Lists — linked lists containing integer values or pointers to data, with the ability to iterate over the list in both directions
Singly-Linked Lists — linked lists containing integer values or pointers to data, limited to iterating over the list in one direction
Double-ended Queues — double-ended queue data structure
Sequences — scalable lists
Trash Stacks — maintain a stack of unused allocated memory chunks
Hash Tables — associations between keys and values so that given a key the value can be found quickly
Strings — text buffers which grow automatically as text is added
String Chunks — efficient storage of groups of strings
Arrays — arrays of arbitrary elements which grow automatically as elements are added
Pointer Arrays — arrays of pointers to any type of data, which grow automatically as new elements are added
Byte Arrays — arrays of bytes, which grow automatically as elements are added
Balanced Binary Trees — a sorted collection of key/value pairs optimized for searching and traversing in order
N-ary Trees — trees of data with any number of branches
Quarks — a 2-way association between a string and a unique integer identifier
Keyed Data Lists — lists of data elements which are accessible by a string or GQuark identifier
Datasets — associate groups of data elements with particular memory locations
Relations and Tuples — tables of data which can be indexed on any number of fields
Caches — caches allow sharing of complex data structures to save resources
Memory Allocators — deprecated way to allocate chunks of memory for GList, GSList and GNode

從它文件中,可以看到它提供很多的功能,為了要了解它提供的一些功能,先把它移植到ARM,順便再做一些範例。 (PS:唉,又是ARM,誰叫我是做embedded的呢。不過其實一些功能已經在PC上測過了,真的還蠻方便的,不過一直沒實做到ARM上。)

CPU:ARM9
toolchain: GCC 4.2.1
glib dependence: libiconv , gettext

gettext-0.16.1.tar.gz
[root@ecken02 gettext-0.16.1]# ./configure --host=arm-linux --prefix=/usr/local/arm_linux_4.2/arm-linux
[root@ecken02 gettext-0.16.1]# make
[root@ecken02 gettext-0.16.1]# make install

libiconv-1.13.1.tar.gz
[root@ecken02 libiconv-1.13.1]# ./configure --host=arm-linux --prefix=/usr/local/arm_linux_4.2/arm-linux
[root@ecken02 libiconv-1.13.1]# make
[root@ecken02 libiconv-1.13.1]# make install

glib-2.20.5.tar.gz
[root@ecken02 glib-2.20.5]# ./configure --host=arm-linux --prefix=/usr/local/arm_linux_4.2/arm-linux/ --enable-static --disable-selinux --cache-file=arm-linux.cache
[root@ecken02 glib-2.20.5]# make
[root@ecken02 glib-2.20.5]# make install

編譯glib之前先設好一些參數,其原因absurd在他的博客已有說明
#cat arm-linux.cache
ac_cv_type_long_long=yes
glib_cv_stack_grows=no
glib_cv_uscore=no
ac_cv_func_posix_getpwuid_r=yes
ac_cv_func_posix_getgrgid_r=yes

compile時會有一個錯誤,
giounix.c:185: error: 'SSIZE_MAX' undeclared
將#include <bits/posix1_lim.h> 加到giounix.c 即可


至此應該已經將glib library加入系統中了。接下來運用它提供的function來做些範例。

2009年9月22日 星期二

在linux上使用vncserver

由於NB上的硬碟空間不足,都得借用其他SERVER的空間,為了方便管理程式以及使用X-window於是便想到來使用linux上的vncserver,利用遠端桌面來操作。

在linux 命令列執行vncserver,第一次執行會要求建立密碼
[root@ecken02 ~]# vncserver

You will require a password to access your desktops.

Password:
Verify:

New 'ecken02:1 (root)' desktop is ecken02:1

Starting applications specified in /root/.vnc/xstartup
Log file is /root/.vnc/ecken02:1.log

我們看一下/root/.vnc/ecken02:1.log的內容
Tue Sep 22 11:39:07 2009
vncext: VNC extension running!
vncext: Listening for VNC connections on port 5901
vncext: Listening for HTTP connections on port 5801
vncext: created VNC server for screen 0

vncserver開啟了兩個port,port 5901是讓vnc client連線進入的,port 5801可以經由http進入

接下來就來試試連線進入的畫面:
1.以網頁HTTP進入
a.開啟IE,輸入IP及port,我們可以發現它是由java來執行的,它的對話框已經幫我們輸入IP,直接按OK即可。


b.輸入當初所建的密碼


c.進入的後的畫面有點醜,只有256色



2. 用vnc client進入
a.先到 RealVNC 下載VNC Free Edition並安裝,安裝完在程式集就可以看到RealVNC.

b. 執行Run VNC Viewer. 輸入IP及port


c.輸入密碼


d.進入後的畫面


以上的操作就可以很簡單的使用遠端桌面。

但事實上有些簡單的事情並不是很容易,繼續來看一些設定值。
一開始執行vncserver是無法進入X-window,要改一下設定值。
使用X-window 桌面:
修改/root/.vnc/xstartup

#!/bin/sh

# Uncomment the following two lines for normal desktop:
# unset SESSION_MANAGER
# exec /etc/X11/xinit/xinitrc

[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
xsetroot -solid grey
vncconfig -iconic &
xterm -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &
#預設值是使用twm,只有console可以用
#twm &

#使用GNOME桌面
#gnome-session

#使用KDE桌面
startkde


開機自動執行vncserver
修改/etc/sysconfig/vncservers,修改方式參閱http://fedoranews.org/tchung/vnc/01.shtml

# VNCSERVERS="2:myusername"
# VNCSERVERARGS[2]="-geometry 800x600 -nolisten tcp -nohttpd -localhost"
VNCSERVERS="1:root"

2009年9月21日 星期一

利用pkg-config幫助編譯

當我們在compile程式時,有時會利用pkgconfig來尋找某些套件include or library的位置,特別是在不同台電腦compile時更是有用,先來看看編譯時期所需要用到的路徑設定:
1. /etc/ld.so.conf
2. ldconfig
3. PKG_CONFIG_PATH

首先說下/etc/ld.so.conf:

這個文件記錄了編譯時使用的動態鏈接庫的路徑。
默認情況下,編譯器只會使用/lib和/usr/lib這兩個目錄下的庫文件
如果你安裝了某些庫,比如在安裝gtk+-2.4.13時它會需要glib-2.0 >= 2.4.0,辛苦的安裝好glib後
沒有指定 --prefix=/usr 這樣glib庫就裝到了/usr/local下,而又沒有在/etc/ld.so.conf中添加/usr/local/lib
這個搜索路徑,所以編譯gtk+-2.4.13就會出錯了
對於這種情況有兩種方法解決:
一:在編譯glib-2.4.x時,指定安裝到/usr下,這樣庫文件就會放在/usr/lib中,gtk就不會找不到需要的庫文件了 :)
對於安裝庫文件來說,這是個好辦法,這樣也不用設置PKG_CONFIG_PATH了 (稍後說明)

二:將/usr/local/lib加入到/etc/ld.so.conf中,這樣安裝gtk時就會去搜索/usr/local/lib,同樣可以找到需要的庫 :)
將/usr/local/lib加入到/etc/ld.so.conf也是必須的,這樣以後安裝東東到local下,就不會出現這樣的問題了。
將自己可能存放庫文件的路徑都加入到/etc/ld.so.conf中是明智的選擇 ^_^
添加方法也極其簡單,將庫文件的絕對路徑直接寫進去就OK了,一行一個。例如:
/usr/X11R6/lib
/usr/local/lib
/opt/lib

再來看看ldconfig是個什麼東東吧 :

它是一個程序,通常它位於/sbin下,是root用戶使用的東東。具體作用及用法可以man ldconfig查到
簡單的說,它的作用就是將/etc/ld.so.conf列出的路徑下的庫文件 緩存到/etc/ld.so.cache 以供使用
因此當安裝完一些庫文件,(例如剛安裝好glib),或者修改ld.so.conf增加新的庫路徑後,需要運行一下/sbin/ldconfig
使所有的庫文件都被緩存到ld.so.cache中,如果沒做,即使庫文件明明就在/usr/lib下的,也是不會被使用的,結果
編譯過程中抱錯,缺少xxx庫,去查看發現明明就在那放著,搞的想大罵computer蠢豬一個。 ^_^
我曾經編譯KDE時就犯過這個錯誤,(它需要每編譯好一個東東,都要運行一遍),所以

切記改動庫文件後一定要運行一下ldconfig,在任何目錄下運行都可以。


再來說說 PKG_CONFIG_PATH這個變量吧:

先來看一個編譯過程中出現的錯誤:

[root@ecken01 glib]# make
gcc `pkg-config --cflags --libs glib-2.0` -o keyfile keyfile.c -Wall
Package glib-2.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `glib-2.0.pc'
to the PKG_CONFIG_PATH environment variable
No package 'glib-2.0' found
keyfile.c:2:18: glib.h: No such file or directory

很明顯,上面這段說明,沒有找到glib-2.4.x,並且提示應該將glib-2.0.pc加入到PKG_CONFIG_PATH下。
究竟這個pkg-config PKG_CONFIG_PATH glib-2.0.pc 是做什麼的呢? let me tell you ^_^
先說說它是哪冒出來的,當安裝了pkgconfig-x.x.x這個包後,就多出了pkg-config,它就是需要PKG_CONFIG_PATH的東東
pkgconfig-x.x.x又是做什麼的? 來看一段說明:


代碼:
-->The pkgconfig package contains tools for passing the include path and/or library paths to build tools during the make file execution.

pkg-config is a function that returns meta information for the specified library.

The default setting for PKG_CONFIG_PATH is /usr/lib/pkgconfig because of the prefix we use to install pkgconfig. You may add to PKG_CONFIG_PATH by exporting additional paths on your system where pkgconfig files are installed. Note that PKG_CONFIG_PATH is only needed when compiling packages, not during run-time.-->
我想看過這段說明後,你已經大概瞭解了它是做什麼的吧。
其實pkg-config就是向configure程序提供系統信息的程序,比如軟件的版本啦,庫的版本啦,庫的路徑啦,等等
這些信息只是在編譯其間使用。你可以 ls /usr/lib/pkgconfig 下,會看到許多的*.pc,用文本編輯器打開
會發現類似下面的信息:

prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

glib_genmarshal=glib-genmarshal
gobject_query=gobject-query
glib_mkenums=glib-mkenums

Name: GLib
Description: C Utility Library
Version: 2.4.7
Libs: -L${libdir} -lglib-2.0
Cflags: -I${includedir}/glib-2.0 -I${libdir}/glib-2.0/include

明白了吧,configure就是靠這些信息判斷你的軟件版本是否符合要求。並且得到這些東東所在的位置,要不去哪裡找呀。
不用我說你也知道為什麼會出現上面那些問題了吧。

解決的辦法很簡單,設定正確的PKG_CONFIG_PATH,假如將glib-2.x.x裝到了/usr/local/下,那麼glib-2.0.pc就會在
/usr/local/lib/pkgconfig下,將這個路徑添加到PKG_CONFIG_PATH下就可以啦。
並且確保configure找到的是正確的glib-2.0.pc。(如果有的話 ^-^)
設定好後可以加入到~/.bashrc中,例如:
PKG_CONFIG_PATH=/usr/lib/pkgconfig
[root@ecken01 glib]# echo $PKG_CONFIG_PATH
/usr/lib/pkgconfig

從上面可以看出,安裝庫文件時,指定安裝到/usr,是很有好處的,無論是/etc/ld.so.conf還是PKG_CONFIG_PATH
默認都會去搜索/usr/lib的,可以省下許多麻煩,不過從源碼包管理上來說,都裝在/usr下
管理是個問題,不如裝在/usr/local下方便管理
其實只要設置好ld.so.conf,PKG_CONFIG_PATH路徑後,就OK啦

正確的編譯範例:

[root@ecken01 glib]# gcc `pkg-config glib-2.0 --cflags --libs ` -o keyfile keyfile.c -Wall
[root@ecken01 font]# gcc `pkg-config freetype2 --cflags --libs` -o ftdemo ftdemo2.c -Wall
[root@ecken01 font]# gcc -g arrow.c -o arrow `pkg-config "gtk+-2.0 > 2.0.0" --cflags --libs`

2009年4月29日 星期三

FIFO: communication between two process

為了控制另一個程式的執行,這個範例用了pipe的方式,兩個程式之間用pipe來溝通(不過是單向),利用這種方式,我們就可以很簡單的控制另一個程式的執行。

r.c: read date.
w.c: write data.

r.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF

int main(int argc, char *argv[])
{
int res;
int open_mode = 0;
int n=0;
char MYkey;
open_mode= O_RDONLY | O_NONBLOCK; //是nonblock的

if (access(FIFO_NAME, F_OK) == -1) {
res = mkfifo(FIFO_NAME, 0777);
if (res != 0) {
fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
}

res = open(FIFO_NAME, open_mode);
while(1)
{
n=read(res,&MYkey,BUFFER_SIZE);
if(n>0)
printf("%c\n",MYkey);
else
printf("No Data.\n");
sleep(1);
}
exit(EXIT_SUCCESS);
}



w.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF

int main(int argc, char *argv[])
{
int res;
int open_mode = 0;
int n=0;
char MYkey='A';
open_mode= O_WRONLY | O_NONBLOCK;

if (access(FIFO_NAME, F_OK) == -1) {
res = mkfifo(FIFO_NAME, 0777);
if (res != 0) {
fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
}

res = open(FIFO_NAME, open_mode);
while(1)
{
n=write(res,&MYkey,BUFFER_SIZE);
if(n>0)
printf("write %c\n",MYkey);
sleep(3);
MYkey++;
}
exit(EXIT_SUCCESS);
}



執行結果:

[root@ecken02 fifo]# ./r &
[1] 16226
No Data.
[root@ecken02 fifo]# ./w
write A
A
No Data.
No Data.
write B
B
No Data.
No Data.
write C
C
No Data.

2009年2月2日 星期一

diff & patch

Compare two file
#diff -u file_old file_new > file.patch

parameter of diff

[root@ecken02 temp]# ls
pnscan-1.8.tar.gz
[root@ecken02 temp]# tar zxvf pnscan-1.8.tar.gz
[root@ecken02 temp]# mv pnscan-1.8 pnscan-1.8.old
[root@ecken02 temp]# tar zxvf pnscan-1.8.tar.gz
[root@ecken02 temp]# ls
pnscan-1.8 pnscan-1.8.old pnscan-1.8.tar.gz
[root@ecken02 temp]# diff -Nur pnscan-1.8.old pnscan-1.8 > file.patch
[root@ecken02 temp]# cat file.patch
diff -Nur pnscan-1.8.old/bm.c pnscan-1.8/bm.c
--- pnscan-1.8.old/bm.c 2002-03-22 18:02:55.000000000 +0800
+++ pnscan-1.8/bm.c 2009-02-02 13:44:47.000000000 +0800
@@ -109,7 +109,7 @@
xsize = m;

saved_m = m;
- saved_x = (unsigned char *) malloc(m);
+ saved_x = (unsigned char *) malloc(m); /* I am here */
if (saved_x == NULL)
return -2;

diff -Nur pnscan-1.8.old/pnscan.c pnscan-1.8/pnscan.c
--- pnscan-1.8.old/pnscan.c 2002-03-22 21:09:52.000000000 +0800
+++ pnscan-1.8/pnscan.c 2009-02-02 13:58:05.000000000 +0800
@@ -106,7 +106,7 @@
return val & 0xFF;
}

-
+/* I am here */
int
dehex(char *str)
{
@@ -996,7 +996,9 @@
goto EndOptions;

case 'h':
- usage(stdout);
+
+ usage(stdout); /* I am here */
+
exit(0);

case 'w':
[root@ecken02 temp]#



Patch file:
#patch -p1 < file.patch

parameter of patch

[root@ecken02 temp]# cp pnscan-1.8.old pnscan-1.8.new
[root@ecken02 temp]# patch -tp1 -d pnscan-1.8.new -i /absolute path/file.patch

2008年12月3日 星期三

linux kernel



linux Platform Driver 說明

從2.6版本開始引入了 platform 這個概念,在開發底層驅動程序時,首先要確認的就是設備的資源信息,例如設備的地址,在2.6內核中將每個設備的資源用結構 platform_device 來描述,該結構體定義在linux\ include\linux\platform_device.h 中


struct platform_device {
const char *name;
int id;
struct device dev;
u32 num_resources;
struct resource *resource;
};

該結構一個重要的元素是 resource,該元素存入了最為重要的設備資源信息,定義在linux\include\ linux\ioport.h 中

struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};

下面舉個例子來說明一下:
在 linux/arch/arm/plat-s3c24xx/devs.c 定義了

static struct resource s3c_lcd_resource[ ] = {
[0] = {
.start = S3C24XX_PA_LCD,
.end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}
};

這裡定義了兩組 resource,它描述了一個 lcd 設備的資源,第1組描述了這個 lcd 設備所佔用的地址範圍,IORESOURCE_MEM 表示第 1 組描述的是內存類型的資源信息,第2組描述了這個 lcd 設備的中斷號,
IORESOURCE_IRQ 表示第 2 組描述的是中斷資源信息。設備驅動會根據 flags 來獲取相應的資源信息。

有了 resource 信息,就可以定義 platform_device 了:

static u64 s3c_device_lcd_dmamask = 0xffffffffUL;

struct platform_device s3c_device_lcd = {
.name = "s3c2410-lcd",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource,
.dev = {
.dma_mask = &s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};

EXPORT_SYMBOL( s3c_device_lcd );

將 s3c_device_lcd expoert 讓其他檔案使用

把 s3c_device_lcd 加到 platform_device 裡面 linux/arch/arm/mach-s3c2440/mach-smdk2440.c:

static struct platform_device *smdk2440_devices[ ] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
};

有了 platform_device 就可以使用函數 platform_add_devices 向系統中添加該設備了,這裡的作法是

static void __init smdk2440_machine_init(void)
{
..............

platform_add_devices( smdk2440_devices, ARRAY_SIZE( smdk2440_devices ) );

............
}

MACHINE_START(S3C2440, "SMDK2440")
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,

.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END

驅動程序需要實現結構體 struct platform_driver,參考 linux\driver\video\s3c2410fb.c,
static struct platform_driver s3c2410fb_driver = {
.probe = s3c2410fb_probe,
.remove = s3c2410fb_remove,
.suspend = s3c2410fb_suspend,
.resume = s3c2410fb_resume,
.driver = {
.name = "s3c2410-lcd",
.owner = THIS_MODULE,
},
};

在驅動初始化函數中使用函數 platform_driver_register() 註冊 platform_driver

int __init s3c2410fb_init( void )
{
return platform_driver_register( &s3c2410fb_driver );
}

module_init( s3c2410fb_init );

需要注意的是: s3c_device_lcd 結構中 name 元素和 s3c2410fb_driver 結構中 driver 的 name 必須是相同的。

這樣在 platform_driver_register() 註冊時,會對所有已註冊的所有 platform_device 中的 name 和當前注冊的 platform_driver 的 driver->name 進行比較,只有找到相同的名稱的 platfomr_device 才能註冊成功,當註冊成功時會呼叫 platform_driver 結構元素 probe 函數指針,這裡就是 s3c2410fb_probe。

當進入 probe 函數後,需要獲取設備的資源信息,獲取資源的函數有:

struct resource * platform_get_resource( struct platform_device *dev, unsigned int type, unsigned int num );

根據參數 type 所指定類型,例如 IORESOURCE_MEM,來獲取指定的資源。

struct int platform_get_irq( struct platform_device *dev, unsigned int num );

獲取資源中的中斷號。

struct resource * platform_get_resource_byname( struct platform_device *dev, unsigned int type, char *name );

根據參數 name 所指定的名稱,來獲取指定的資源。

int platform_get_irq_byname( struct platform_device *dev, char *name );

根據參數 name 所指定的名稱,來獲取資源中的中斷號。

資料來源: http://top12345tw.blogspot.com/2008/03/linux-kernel-26243-platform-device.html