9/30/2011

Git patch



最近為了發佈patch煩惱中....因為對於GIT還不是能運用自如,但下面找到很不錯的文章,解決我的困擾^^


UNIX世界的軟件開發大多都是協作式的,因此,Patch(補丁)是一個相當重要的東西,因為幾乎所有的大型UNIX項目的普通貢獻者,都是通過Patch來提交代碼的。作為最重要的開源項目之一,Linux,也是這樣的。普通開發者從軟件倉庫clone下代碼,然後寫入代碼,做一個Patch,最後用E-mail發給Linux Kernel的維護者就好了。Git最初作為Linux的版本控制工具,提供了透明、完整、穩定的Patch功能。
我們先介紹一下Patch是什麼。如果一個軟件有了新版本,我們可以完整地下載新版本的代碼進行編譯安裝。然而,像Linux Kernel這樣的大型項目,代碼即使壓縮,也超過70MB,每次全新下載是有相當大的代價的。然而,每次更新變動的代碼可能不超過1MB,因此,我們只要能夠有兩個版本代碼的diff的數據,應該就可以以極低的代價更新程序了。因此,Larry Wall開發了一個工具:patch。它可以根據一個diff文件進行版本更新。
不過在git中,我們沒有必要直接使用diff和patch來做補丁,這樣做既危險又麻煩。git提供了兩種簡單的patch方案。一是用git diff生成的標準patch,二是git format-patch生成的Git專用Patch。

1.git diff生成的標準patch

我們可以首先用git diff製作一個patch。本文示例的工作目錄裡最初有一個文件a,內容是“This is the file a.”,放置在master分支中。為了修改代碼,我們一般的做法是建立一個新分支:
sweetdum@sweetdum-ASUS:~/GitEx$ git branch Fix
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout Fix
Switched to branch ‘Fix’
接下來我們在a文件裡面追加一行,然後執行git diff。
sweetdum@sweetdum-ASUS:~/GitEx$ echo ‘Fix!!!’>>a
sweetdum@sweetdum-ASUS:~/GitEx$ git diff
diff –git a/a b/a
index 4add65f..0d295ac 100644
— a/a
+++ b/a
@@ -1 +1,2 @@
This is the file a.
+Fix!!!
我們看到了Git diff的輸出,這是一個非常典型的Patch式diff。這樣我們可以直接把這個輸出變為一個Patch:
sweetdum@sweetdum-ASUS:~/GitEx$ git commit -a -m “Fix”
[Fix b88c46b] Fix
1 files changed, 1 insertions(+), 0 deletions(-)
sweetdum@sweetdum-ASUS:~/GitEx$ git diff master > patch
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout master
Switched to branch ‘master’
我們現在有一個patch文件,並且簽出了master,接下來我們可以使用git apply來應用這個patch。當然了,實際應用中,我們不會這樣在一個分支建patch,到另一個分支去應用,因為只有merge一下就好了。我們現在權當沒有這個Fix分支。一般情況下,為了保護master,我們會建立一個專門處理新交來的patch的分支:
sweetdum@sweetdum-ASUS:~/GitEx$ git branch PATCH
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout PATCH
Switched to branch ‘PATCH’
sweetdum@sweetdum-ASUS:~/GitEx$ git apply patch
sweetdum@sweetdum-ASUS:~/GitEx$ git commit -a -m “Patch Apply”
[PATCH 9740af8] Patch Apply
1 files changed, 1 insertions(+), 0 deletions(-)
看,現在我們在PATCH分支中應用了這個補丁,我們可以把PATCH分支和Fix比對一下,結果肯定是什麼也沒有,說明PATCH分支和Fix分支完全一樣。patch應用成功。即使有多個文件git diff 也能生成一個patch。

2.git format-patch生成的git專用補丁。

我們同樣用上面那個例子的工作目錄,這次,我們在Fix分支中的a添加了新行之後,用git format-patch生成一個patch。
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout Fix
Switched to branch ‘Fix’
sweetdum@sweetdum-ASUS:~/GitEx$ echo ‘Fix!!!’>>a
sweetdum@sweetdum-ASUS:~/GitEx$ git commit -a -m “Fix1″
[Fix 6991743] Fix1
1 files changed, 1 insertions(+), 0 deletions(-)
sweetdum@sweetdum-ASUS:~/GitEx$ git format-patch -M master
0001-Fix1.patch
git format-patch的-M選項表示這個patch要和那個分支比對。現在它生成了一個patch文件,我們看看那是什麼:
sweetdum@sweetdum-ASUS:~/GitEx$ cat 0001-Fix1.patch
From 6991743354857c9a6909a253e859e886165b0d90 Mon Sep 17 00:00:00 2001
From: Sweetdumplings
Date: Mon, 29 Aug 2011 14:06:12 +0800
Subject: [PATCH] Fix1

a |    1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff –git a/a b/a
index 4add65f..0d295ac 100644
— a/a
+++ b/a
@@ -1 +1,2 @@
This is the file a.
+Fix!!!

1.7.4.1
看,這次多了好多東西,不僅有diff的信息,還有提交者,時間等等,仔細一看你會發現,這是個E-mail的文件,你可以直接發送它!這種patch,我們要用git am來應用。
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout master
Switched to branch ‘master’
sweetdum@sweetdum-ASUS:~/GitEx$ git branch PATCH
sweetdum@sweetdum-ASUS:~/GitEx$ git checkout PATCH
sweetdum@sweetdum-ASUS:~/GitEx$ git am 0001-Fix1.patch
Applying: Fix1
sweetdum@sweetdum-ASUS:~/GitEx$ git commit -a -m “PATCH apply”
在提交了補丁之後,我們可以再看看目前文件a的情況:
sweetdum@sweetdum-ASUS:~/GitEx$ cat a
This is the file a.
Fix!!!
果然,多了一個Fix!!!
不過要注意的是,如果master與Fix分支中間有多次提交,它會針對每次提交生成一個patch。

3.兩種patch的比較:

  • 兼容性:很明顯,git diff生成的Patch兼容性強。如果你在修改的代碼的官方版本庫不是Git管理的版本庫,那麼你必須使用git diff生成的patch才能讓你的代碼被項目的維護人接受。
  • 除錯功能:對於git diff生成的patch,你可以用git apply –check 查看補丁是否能夠乾淨順利地應用到當前分支中;如果git format-patch 生成的補丁不能打到當前分支,git am會給出提示,並協助你完成打補丁工作,你也可以使用git am -3進行三方合併,詳細的做法可以參考git手冊或者《Progit》。從這一點上看,兩者除錯功能都很強。
  • 版本庫信息:由於git format-patch生成的補丁中含有這個補丁開發者的名字,因此在應用補丁時,這個名字會被記錄進版本庫,顯然,這樣做是恰當的。因此,目前使用Git的開源社區往往建議大家使用format-patch生成補丁。

Tutorial VIM on interrnet

無意中發現一個很棒的網站,線上教學的VIM

http://www.openvim.com/tutorial.html

當然這些都只是非常基本的操作

但感覺真的很不錯 !

9/16/2011

GIT 相關script 和 自定義快速鍵


=======================================

function git_branch {
    ref=$(git symbolic-ref HEAD 2> /dev/null) || return;
    echo "("${ref#refs/heads/}") ";
}

function git_since_last_commit {
    now=`date +%s`;
    last_commit=$(git log --pretty=format:%at -1 2> /dev/null) || return;
    seconds_since_last_commit=$((now-last_commit));
    minutes_since_last_commit=$((seconds_since_last_commit/60));
    hours_since_last_commit=$((minutes_since_last_commit/60));
    minutes_since_last_commit=$((minutes_since_last_commit%60));
    
    echo "${hours_since_last_commit}h${minutes_since_last_commit}m ";
}

PS1="[\[\033[1;32m\]\w\[\033[0m\]] \[\033[0m\]\[\033[1;36m\]\$(git_branch)\[\033[0;33m\]\$(git_since_last_commit)\[\033[0m\]$ "

=======================================

把上面的程式貼到 ~/.bash_profile,如果沒有就新建。

如果shell重啟之後沒反應,可以直接在~/.bashrc加入,讓它自動幫你執行 :

if [ -f ~/.bash_profile ]; then                                                                                                                           
    . ~/.bash_profile
fi

好了之後,重啟shell就會變成這樣 :DDD



顯示在哪個branch之下,還有溫馨小提示有多久沒有commit了 XD


常用的git alias :
git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.br branch

GIT STATUS


git status主要就是用來看目前working directory中所有檔案的情形,主要有下列幾種狀態
1. project file
就是原來就已經在GIT裡面並且沒有被更改過的檔案,這類型的檔案在git status中並不會列出來。
2. modified file
如果你更動任何一個project file,那隻檔案的狀態就會變成modified。
3. untracked file
所有新增出來、還沒用git add加到project裡面的檔案,他們的狀態就會是untracked。
這些檔案裡面可能有你新增的程式,也有可能是你在make的過程中動到或產生的中間檔。
如果是前者,記得在commit之前先add,如果是後者,就不需要理了,就讓它們留在untracked裡面就行了。
4. new file
untracked file被git add之後,狀態就會變成new file,commit之後就變成project file。

git status的output會根據你的color.status來決定要不要讓輸出結果帶有顏色 (或直接設定color.ui為auto)
$ git config --global color.ui auto
or
$ git config --global color.status true
如此一來,git status的output便會有顏色了。(有顏色好看很多)


如果git status後面不加path,會對整個working directory下的檔案檢查;如果後面有加路徑的話,就只會指定路徑下的所有檔案做檢查。
$ git status .
$ git status ./foo

註: 如果你目前不是在.git的同一層目錄的話,git會一直往parent目錄往上找到.git目錄,所以不必特別cd回.git那層目錄就可以做git操作了。

另外,git好像到了1.7.0.4之後,git-status多了幾個參數可以使用,個人最推的是 -s
-s, --short
用簡潔的格式來印出結果
ex.
$ git status
# On branch new
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#       new file:   kkkk
#
$ git status -s
A  kkkk

前面的A代表added,另外還有幾個字母
M = modified
D = deleted
R = renamed
C = copied
U = updated but unmerged

最常見的的狀態:
? ?: untracked
A: new
M: Modified but not added
M  : Modified and added
MM: Modified again after added
  D: deleted project file
完整的format可以用git help status查詢OUTPUT那一節,在這裡就不列出來了。

--porcelain
porcelain的翻譯是"瓷" (f-__-),加這個參數的意義是輸出來的結果會讓script較易於處理,不過目前這個參數其實是指到--short,結果是一樣的。
-u[], --untracked-files[=]
這個參數是用來設定如何顯示untracked files的狀態
mode (Default all)
no:     不顯示untracked files
normal: 顯示untracked files & directories,但untracked directories裡面的內容則不列出來
例如,新產生了一個newdir,newdir目錄裡面又有子目錄及其他檔案,在normal mode的時候,在status裡只會列出一行newdir/。
all:    將所有untracked files列出來,包含在untracked directories裡面的,所以用all的話列出來就會是落落長一大串。

-z
用NUL代替LF當成行的結尾,應該也是為了要把結果output給script處理而設計的,和--porcelain搭配使用。

Kconfig 文件的用途 (Make 選單的建立)


 配置選項是以樹的形式組織的,每個選項都有其自己的依賴關係。
這些依賴關係決定了選項是否是可見的。父選項可見,子選項才能可見。

核心原始碼的目錄下都有兩個文件 Kconfig(2.4版本是Config.in)和 Makefile。
分佈到各目錄的Kconfig構成了一個分散式的核心配置資料庫,
每個 Kconfig分別描述了與所屬目錄文件相關的核心配置功能表。
在核心配置 make menuconfig(或 xconfig 等)時,
從 Kconfig 中讀出功能表,用戶選擇後保存到 .config的核心配置文件中。
在核心編譯時,主Makefile 調用這個 .config,就知道了用戶的選擇。

*上面的內容說明了, Kconfig 就是對應著核心的配置功能表。
假如想添加新的驅動到核心的原始碼中,修改 Kconfig,這樣就能夠選擇這個驅動,
假如想編譯這個驅動,要修改 Makefile,所以添加新的驅動時需要修改的文件有兩種(注意不只是兩個)
Kconfig
Makefile

要想知道怎麼修改這兩種文件,就要知道兩種文件的語法結構

Kconfig
每個功能表都有一個關鍵字標識,最常見的就是config

config MODVERSIONS
    bool "Set version information on all module symbols"
    depends MODULES
    help
      Usually, modules have to be recompiled whenever you switch to a new
      kernel.  ...

每行都是以關鍵字開始,並可以接多個參數。
"config" 為定義了一新的配置選項。
而緊接著的下面幾行定義了該配置選項的屬性。
屬性可以是該配置選項的類型,輸入提示(input prompt),依賴關係,幫助資訊和預設值。
配置選項可以用相同的名字定義多次,但每個定義只能有一個輸入提示並且類型不能衝突。

語法:
config
symbol是個新的標記的功能表項,options是在這個新的功能表項下的屬性和選項
其中options部分有:

- 類型定義:"bool"/"tristate"/"string"/"hex"/"int"
  每個config功能表項都要有類型定義,每個配置選項都必須指定類型。
  有兩個基本類型:tristate 和 string,其他類型都是基於這兩個基本類型。

  bool布林類型、
  tristate三態:內建、模組、移除、
  string字串、
  hex十六進位、
  integer整型

  例如config HELLO_MODULE
  bool "hello test module"
  bool 類型的只能選或不選,tristate 類型的選項多了編譯成核心模組的選項,
       假如選擇編譯成核心模組,則會在 .config 中生成一個 CONFIG_HELLO_MODULE=m 的配置,
       假如選擇內建,就是直接編譯進核心,就會在 .config 中生成一個 CONFIG_HELLO_MODULE=y 的配置.

  類型定義可以用輸入提示,所以下面的兩個例子是等價的:
     bool "Networking support"
  and
     bool
          prompt "Networking support"

- 依賴型定義 depends on或 requires
  指此功能表的出現與否是依賴另一個定義
  config HELLO_MODULE
         bool "hello test module"
         depends on ARCH_PXA

  這個例子表明HELLO_MODULE這個功能表項只對XScale處理器有效。

- 幫助資訊: "help" or "---help---"
  定義一幫助資訊。幫助資訊的結束就由縮進的水準決定的,
  這也就意味著資訊是在第一個比幫助資訊開始行的縮進小的行結束。
  "---help---" 和 "help" 在實現的作用上沒有區別,
  "---help---" 有助於將檔中的配置邏輯與給開發人員的提示分開。

- 輸入提示: "prompt" ["if" ]
  每個功能表選項最多只能有一個顯示給用戶的輸入提示。
  可以用 "if" 來表示該提示的依賴關係,當然這是可選的。

- 預設值:"default" ["if" ]
  一個配置選項可以有任意多個預設值。
  如果有多個預設值,那麼只有第一個被定義的值是可用的。
  預設值並不是只限於應用在定義他們的功能表選項。
  這就意味著預設值可以定義在任何地方或被更早的定義覆蓋。
  如果用戶沒有設置(通過上面的輸入提示),配置選項的值就是預設值。
  如果可以顯示輸入提示的話,就會把預設值顯示給用戶,並可以讓用戶進行修改。
  預設值的依賴關係可以用 "if" 添加。(可選項)

- 依賴關係:"depends on"/"requires"
  為一功能表選項定義依賴關係。
  如果定義了多個依賴關係,它們之間用 '&&' 間隔。
  依賴關係也可以應用到該功能表中所有的其他選項(同樣接受一if運算式),
  所以下面的兩個例子是等價的:

    bool "foo" if BAR
         default y if BAR
  and
    depends on BAR
    bool "foo"
         default y

- 反向依賴關係:"select" ["if" ]
  儘管普通的依賴關係可以降低一選項的上限,反向依賴能將這一限制降的更低。
  當前功能表選項的值是symbol的最小值。
  如果symbol被選擇了多次,上限就是其中的最大值。
  反向依賴只能用在 boolean 或 tristate 選項上。

- 資料範圍:"range" ["if" ]
  為int和hex類型的選項設置可以接受輸入值範圍。
  用戶只能輸入大於等於第一個symbol,小於等於第二個symbol的值。


選單依賴關係
------------

依賴關係決定了功能表選項是否可見,也可以減少tristate的輸入範圍。
tristate邏輯比boolean邏輯在表達式中用更多的狀態(state)來表示模組的狀態。
依賴關係運算式的語法如下:

::=                              (1)
           '='                 (2)
           '!='                (3)
           '(' ')'                       (4)
           '!'                            (5)
           '&&'                    (6)
           '||'                    (7)

運算式是以優先順序的降冪列出的。

(1) 將symbol賦給運算式。boolean和tristate類型的symbol直接賦給運算式。
    所有其他類型的symbol都賦 'n'。
(2) 如果兩個symbol相等,返回'y',否則為'n'。
(3) 如果兩個symbol相等,返回'n',否則為'y'。
(4) 返回運算式的值。用於改變優先順序。
(5) 返回 (2-/expr/) 的結果。
(6) 返回 min(/expr/,/expr/) 的結果。
(7) 返回 max(/expr/,/expr/) 的結果。

一個運算式的值可以是'n','m'或'y'(或者是計算的結果 0,1,2)。
當運算式的值為'm'或'y'的時候,選單選項才是可見的。

symbol有兩種類型:不可變的和可變的。不可變的symbol是最普通的,
由'config'語句定義,完全由數字、字母和下劃線組成(alphanumeric characters or underscores)。
不可變的symbol只是運算式的一部分。經常用單引號或雙引號括起來。
在引號中,可以使用任何字元,使用引號要用轉義字元'\'。

功能表結構
--------

功能表在樹中的位置可由兩種方法決定。第一種可以是這樣:

menu "Network device support"
    depends NET

config NETDEVICES
    ...

endmenu

所有的在"menu" ... "endmenu" 之間都是"Network device support"的子功能表。
所有的子功能表選項都繼承了父功能表的依賴關係,
比如,"NET"的依賴關係就被加到了配置選項NETDEVICES的依賴列表中。

還有就是通過分析依賴關係生成功能表的結構。
如果功能表選項在一定程度上依賴於前面的選項,它就能成為該選項的子功能表。
首先,前面的(父)選項必須是依賴列表中的一部分並且它們中必須有滿足下面兩個條件的選項:
- 如果父選項為'n',子選項必須不可見。
- 如果父選項可見,子選項才能可見。

config MODULES
    bool "Enable loadable module support"

config MODVERSIONS
    bool "Set version information on all module symbols"
    depends MODULES

comment "module support disabled"
    depends !MODULES

MODVERSIONS 直接依賴 MODULES,這就意味著如果MODULES不為'n',該選項才可見。
換句話說,當MODULES可見時,選項才可見(MODULES的(空)依賴關係也是選項依賴關係的一部分)。

Kconfig 語法
------------

配置檔描述了功能表選項,每行都是以一關鍵字開頭(除了幫助資訊)。
下面的關鍵字結束一功能表選項:
- config
- menuconfig
- choice/endchoice
- comment
- menu/endmenu
- if/endif
- source
前5個同樣可以用在功能表選項定義的開始。

config:

    "config"
   

定義了一配置選項 並且可以接受任何前面介紹的屬性。

menuconfig:
    "menuconfig"
   

此關鍵字和前面的關鍵字很相似,但它在前面的基礎上要求所有的子選項作為獨立的行顯示。
( This is similar to the simple config entry above,
  but it also gives a hint to front ends,
  that all suboptions should be displayed as a separate list of options.)

choices:

    "choice"
   
   
    "endchoice"

該關鍵字定義了一組選擇項,並且選項可以是前面描述的任何屬性。
儘管boolean只允許選擇一個配置選項,tristate可以於多個配置選項設為'm',
但選項只能是boolean或tristate類型。
這可以在一個硬體有多個驅動的情況下使用,最終只有一個驅動被編譯進/載入到核心,
但所有的驅動都可以編譯成模組。
選項可以接受的另一個選項是"optional",這樣選項就被設置為'n',沒有被選中的。

comment:

    "comment"
   

這裡定義了在配置過程中顯示給用戶的註釋,該註釋還將寫進輸出檔中。
唯一可用的可選項是依賴關係。

menu:

    "menu"
 

    "endmenu"

這裡定義了一個功能表,詳細資訊請看前面的"功能表結構"。
唯一可用的可選項是依賴關係。

if:

    "if"
   
    "endif"

這裡定義了if結構。依賴關係被加到所有在if ... endif 中的功能表選項中。
(lb:請看linux-source/drivers/ata/Kconfig:20)



Makefile
在 linux2.6.x/Documentation/kbuild 目錄下有詳細關於 kernel makefile 的介紹。
核心的Makefile分為5個組成部分:
Makefile  最頂層的Makefile
.config   核心的當前配置文件,編譯時成為定層Makefile的一部分
arch/$(ARCH)/Makefile 和體系結構相關的 Makefile
s/ Makefile.*   一些Makefile的通用規則
kbuild Makefile 各級目錄下的大約有500個文件,編譯時根據上層 Makefile 傳下來的
                巨集定義和其他編譯規則,將源代碼編譯成模組或編入核心

頂層的Makefile文件讀取 .config 文件的內容,並且在總體上負責建立核心和模組。
Arch Makefile 則提供補充系統結構相關的資訊。
s 目錄下的 Makefile 文件包含了任何根據 kbuild Makefile 構建核心所需的定義和規則。
(其中 .config 的內容是在 make menuconfig 的時候,通過 Kconfig 文件配置的結果。

舉個例子:
假設想把自己寫的一個flash的驅動程式載入到工程中,而且能夠通過 menuconfig 配置
核心時選擇該驅動該怎麼辦呢?能夠分三步:

第一:將您寫的 flashtest.c 文件添加到 /driver/mtd/maps/ 目錄下。
第二:修改 /driver/mtd/maps 目錄下的 kconfig 文件:
      config MTD_flashtest
      tristate 「ap71 flash"
      這樣當 make menuconfig 時 ,將會出現 ap71 flash選項。
第三:修改該目錄下makefile文件。
      添加如下內容:obj-$(CONFIG_MTD_flashtest)+= flashtest.o

這樣,當您運行 make menucofnig 時,您將發現ap71 flash選項。
假如您選擇了此項,該選擇就會保存在 .config 文件中。
當您編譯核心時,將會讀取 .config 文件,當發現 ap71 flash 選項為 yes 時,
系統在呼叫 /driver/mtd/maps/ 下的 makefile 時,將會把 flashtest.o 加入到核心中。

9/03/2011

TI 128x BT/GPS/FM Share transport design and architecture (2)

Trace the ST related source code

預設OMAP4會把ST driver直接built in進kernel,另外GPS和FM driver則會compile成模組型式 :

CONFIG_TI_ST=y
CONFIG_ST_FM=m
CONFIG_ST_GPS=m

GPS & FM driver path : kernel/drivers/staging/ti-st/

ST driver path : kernel/drivers/misc/ti-st

從上面知道,ST driver包含3個sub-moudules,所以這個目錄底下就有相對應的source code:

st_core.c     st_kim.c       st_ll.c

這三個檔案會被compile成叫st_drv.o....

UIM就有點小麻煩...因為TI在OMAP4 Blaze BSP裡面放了3個UIM code...

分別叫 "uim" , "uim-rfkill" , "uim-sysfs",該UIM的路徑是在mydroid/hardware/ti/wpan/ti_st/

之前知道UIM一支deamon,是系統boot時就開始run了,所以馬上就可以知道TI會在init.rc加入UIM service ...

service uim /system/bin/uim-sysfs
    user root         
    group media bluetooth                                                                                                 
    oneshot

uim-sysfs加上oneshot,可以知道TI所使用的是 "uim-sysfs" ,從裡面的uim.c瞭解它會把st/bt/fm/gps等driver一個個insmod進去,利用lstat來檢查.ko是否存在。

因為現在是built-in,所以UIM並不會跑這段...

而是在更早之前,st_kim的init func是__init,所以在kernel一起來時就會register,而且還是register一個platform_drive的結構 :

static struct platform_driver kim_platform_driver = {
    .probe = kim_probe,
    .remove = kim_remove,
    .suspend = kim_suspend,
    .resume = kim_resume,
    .driver = {                                                                                                             
        .name = "kim",
        .owner = THIS_MODULE,
    }, 
};  

出現了platform_driver結構,就一定會有想對應的platform_device結構來讓kernel assigned,所以可以在arch/arm/mach-omap2/board-4430sdp.c找到 :

struct ti_st_plat_data wilink_pdata = {
    .nshutdown_gpio = 55,
    .dev_name = BLUETOOTH_UART_DEV_NAME,
    .flow_cntrl = 1,
    .baud_rate = 3000000,
    .suspend = plat_kim_suspend,
    .resume = plat_kim_resume,
}; 
static struct platform_device wl128x_device = {
    .name       = "kim",
    .id     = -1,
    .dev.platform_data = &wilink_pdata,
}; 
static struct platform_device btwilink_device = {
    .name = "btwilink",
    .id = -1,                                                                                                               
};   

nshutdown_gpio是BT/GPS/FM Enable pin...所以要改GPIO直接改這。(不太清楚TI怎麼去控制單一GPIO來防止3個device打架...還是真的3個只能開1個 !? 手邊沒平台...哎)

dev_name是UART deivce name...像是/dev/ttyxx之類的,所以要修改其它port,就修改這個定義。

接下來就是kim probe了,為每個device建構結構.....分配記憶體位址.....取得private data等等..

但這時就會去呼叫st_core,通知st_core initialization的時候到了....

int st_core_init(struct st_data_s **core_data)
{
    .....
    err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops);
    .....
}

st_core 就最重要的就是註冊Line Discipline了。

什麼是Line Discipline ? 對 TTY device 的 I/O 動作,會經由 TTY core 送給 TTY driver,而資料往來於 TTY 與 TTY driver 的過程中...

可以這麼想,連結TTY Core和TTY driver資料往來的線,就叫Line Discipline。

Line Discipline是被設計成可以抽換的,例如,今天我想要讓這個TTY device是接收的資料是數據機而不要來自終端機,就把N_TTY改成N_PPP。

想要只接收藍芽的資料,就改成N_HCI....

簡言而之,就是Line Discipline會按照某個特殊的協議進行格式化,然後再送給TTY driver,讓TTY driver可以跟特定的硬體做溝通。

現在TI自己定義了一個N_TI_WL這個Line Discipline,所以porting時就要注意,要在kernel裡定義該Line Discipline....可以在kernel/include/linux/tty.h加入該定義。

接著st_kim會去request GPIO,並把GPIO設成輸出模式....

後面最後一道程序滿重要的,st_kim會create entries sysfs :

kim_gdata->kim_pdev = pdev;
init_completion(&kim_gdata->kim_rcvd);
init_completion(&kim_gdata->ldisc_installed);
   
status = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp);
if (status) {                                                                                                           
    pr_err("failed to create sysfs entries");
     return status;
}
   
/* copying platform data */
strncpy(kim_gdata->dev_name, pdata->dev_name, UART_DEV_NAME_LEN);
kim_gdata->flow_cntrl = pdata->flow_cntrl;
kim_gdata->baud_rate = pdata->baud_rate;
pr_info("sysfs entries created\n");

其中uim_attr_grp的結構為 :

/* structures specific for sysfs entries */
static struct kobj_attribute ldisc_install =
__ATTR(install, 0444, (void *)show_install, NULL);
   
static struct kobj_attribute uart_dev_name =
__ATTR(dev_name, 0444, (void *)show_dev_name, NULL);
       
static struct kobj_attribute uart_baud_rate =
__ATTR(baud_rate, 0444, (void *)show_baud_rate, NULL);
   
static struct kobj_attribute uart_flow_cntrl =
__ATTR(flow_cntrl, 0444, (void *)show_flow_cntrl, NULL);
   
static struct attribute *uim_attrs[] = {
    &ldisc_install.attr,
    &uart_dev_name.attr,
    &uart_baud_rate.attr,
    &uart_flow_cntrl.attr,
    NULL,
}; 
   
static struct attribute_group uim_attr_grp = {                                                                              
    .attrs = uim_attrs,
};  

TI會去Create這些sysfs的最主要目的就是讓UIM能在user space透過該檔案系統去open在kernel space的st_core

到這裡st_kim和st_core的initialization就結束了,回頭繼續看UIM

UIM會去check剛剛的sysfs這些路徑有沒有建立成功 :

#define INSTALL_SYSFS_ENTRY "/sys/devices/platform/kim/install"
#define DEV_NAME_SYSFS      "/sys/devices/platform/kim/dev_name"                                                            
#define BAUD_RATE_SYSFS     "/sys/devices/platform/kim/baud_rate"
#define FLOW_CTRL_SYSFS     "/sys/devices/platform/kim/flow_cntrl"

如果都有,而且BT/GPS/FM等相關的.ko和裝置節點都有存在的話,就會去create rfkill的路徑了 :

if (change_rfkill_perms() < 0) {                                                                                        
     /* possible error condition */
     UIM_ERR("rfkill not enabled in st_drv - BT on from UI might fail\n");
}   

這樣一來,bluedroid (system/bluetooth/bluedroid/bluetooth.c)就可以透過rfkill來控制BT power。

然後UIM就去open st_core,讓st_core能成功install line discipline.

st_fd = open(INSTALL_SYSFS_ENTRY, O_RDONLY);
if (st_fd < 0) {
      UIM_DBG("unable to open %s (%s)", INSTALL_SYSFS_ENTRY,
      strerror(errno));
      remove_modules();
      return -1;
}

到這裡,UIM的任務就算暫時結束了 !

註 : hciattach的opation部份被改"-l"...它做的也只是print每個attach的結構,並沒做任何事... 
      所以hciattach的功用完全被UIM/KIM替代掉了,因為KIM己經把/dev/ttyx帶起來了 XD (如果    
      不用GPS的話...ST應該可以放一邊吧0.0?)