1. 程式人生 > >Linux驅動開發盲點筆記1

Linux驅動開發盲點筆記1

1. vim中在找到搜尋目標後,使用n與N進行定位查詢2. vim中使用gg到最好第一行,使用xxxG到某一行,否則G直接到最後一行;3. ln -s 產生的連結檔案最終指向的目標檔案src 新產生的當前軟連結檔案dst。ln -s project(磁碟上實際存在的檔案或者目錄) a.lnkln -s src dst(新產生的檔案dst,dst連結到src)symlink功能類似4 tar -czvf 最終生產的tar打包好的檔案 待打包的檔案或者資料夾tar czvf a.tar.bz  a5. 移植dts的關鍵點是,待編譯的dts檔案均需要放置於/arch/arm/boot/dts下面。make時會預設在這裡尋找dts編譯檔案入口。然後編譯時以同名的dtb來執行make編譯才能被makefile解析為目標,再去查詢同名的dts由DTC來生產dtb檔案。而dtb就是最終根據dts編譯出來的二進位制檔案,位於arch/arm/boot下
6.在linux核心中斷程式設計中需要注意:中斷上下文中不能出現排程休眠的情況。即不能使用互斥,訊號量PV操作會引起休眠等方式。中斷一般需要處理的自旋鎖保護臨界資源時也需要較短時間的。一般原子上下文中不能出現睡眠。msleep/wait_event_interrupt等函式都是排程休眠延遲的,故不能出現在中斷上下文中。7. list_for_each與list_for_each_safe的區別因此之遍歷連結串列不刪除結點時,可以使用list_for_each(),而當要刪除結點操作時,則要使用list_for_each_safe()。8. 模組入口函式編碼注意點module init/exit函式是無參函式,且應當是int型別的返回值9. linux編譯模組時的版本號使用modinfo可檢視編譯出來的ko檔案對應的核心版本號使用uname或者 cat /proc/version 可在目標系統上檢視核心版本號。可檢視kernel編譯過程生成的檔案: include/generated/utsrelease.h ,確定編譯出來的核心的版本號。10 df顯示磁碟分割槽資訊如df -h, du -sh來顯示當前目錄下的各檔案與目錄的大小資訊11 declare -f xxx用於輸出當前shell支援的函式輸出12 find -name *xxx 查詢檔案13 grep "xxx" -r ./*14  cat /proc/version 檢視Ubuntu版本號, 
lsb_release -acat /etc/issue15 makefile中的=與:=前者在賦值時會檢視賦值變數的全域性性後者在賦值時,只看被賦值變數再前面是否已經被定義過。16 &是程序在後臺執行不佔據終端17 linux裝置驅動阻塞與非阻塞方式,阻塞與非阻塞是針對資料的讀寫,即資源的獲取而言的,當無資源時,阻塞會排程程序休眠,而非阻塞則立刻返回。poll函式本質只是來查詢當前裝置是否已經可讀或者可寫POLLIN和POLLOUT。利用select和poll可以去確保對裝置的非阻塞操作(select和poll本身就一種阻塞操作,阻塞完成後可表明讀寫資源是ok的,從而確保資源是可讀寫操作的)而所謂的阻塞操作,是對裝置讀寫時直接進行進行程序的排程與休眠,直到資料可讀或者可寫,才回返回。在自己定義的fops poll介面中需要實現poll_wait函式,該函式只是將當前需要程序poll_table加入到一個等待佇列頭中去,並不會產生休眠,但
真正的休眠排程需要在do_sys_poll中由poll_schedule_timeout來休眠排程。在等待佇列頭被wake_up喚醒後,會繼續執行一次poll介面呼叫,再次將自己加入到wait queue中,此後一般是可以POLLIN或者POLLOUT,從而退出do_sys_poll的呼叫,返回查詢結果給使用者層。static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p){    if (p && p->_qproc && wait_address)        p->_qproc(filp, wait_address, p);//__pollwait}static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,                poll_table *p){    struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);    struct poll_table_entry *entry = poll_get_entry(pwq);    if (!entry)        return;    get_file(filp);    entry->filp = filp;    entry->wait_address = wait_address;    entry->key = p->_key;    init_waitqueue_func_entry(&entry->wait, pollwake);    entry->wait.private = pwq;    add_wait_queue(wait_address, &entry->wait);//將poll程序的wait加入到等待佇列頭}18 linux中斷巢狀基本原理1)linux響應中斷後,將響應程式分成兩部分:頂部和底部;2)在執行完頂部後,就開啟中斷(清掉了相關的中斷標誌);底部由系統排程執行,底部執行時,允許中斷;3)如果在驅動中,申請中斷request_iqr()時,使用了引數IRQF_DISABLED,則在呼叫中斷處理函式時,遮蔽所有中斷,從而使中斷得到快速執行。4)綜合2)和3),可知LINUX允許中斷巢狀。19 devm_kzalloc可以更好的管理裝置的相關資源20 dts中的lable瞭解了基本的device tree的結構後,我們總要把這些結構體現在device tree source code上來。在linux kernel中,副檔名是dts的檔案就是描述硬體資訊的device tree source file,在dts檔案中,一個node被定義成:[label:] node-name[@unit-address] {  [properties definitions]  [child nodes]}“[]”表示option,因此可以定義一個只有node name的空節點。label方便在dts檔案中引用,具體後面會描述。child node的格式和node是完全一樣的,因此,一個dts檔案中就是若干巢狀組成的node,property以及child note、child note property描述。21 dts中include dtsi的處理過程嘗試了下,貌似label的引用和include的位置無關,應該是提前於載入類似於makefile的include處理,而不是C編譯的處理22 push-pull open_drain開漏加上拉,在高電平的時候能提供的電流很小,還有一個問題就是電平的翻轉速度比較慢,總之就是驅動能力不行。但是開漏的方式可以借線與邏輯實現準雙向IO,這一點是推輓做不到的。浮空,顧名思義就是懸浮在空中,上面用繩子一拉就上去,下面用繩子一拉就沉下去了。上拉,下拉的設定主要還是看你外接的驅動電路的具體情況配置的。開漏,就等於輸出口接了個NPN三極體,並且只接了e,b. c極是開路的,你可以直接接一個電阻到3.3V,也可以接一個電阻到5v,這樣在輸出1的時候,就有5V的電壓,也可以輸出3.3V的電壓了,而不接電阻上拉,這個輸出高是不能實現的。推輓,就是有推有拉,任何時候IO口的點平都是確定的,不需要外接上拉或者下拉電阻23 dts中的&用法在root node中如果有一個A:A{}子節點,然後在這個dts中的根節點/{}外面又增加了&A{xxxxxx其他node資訊}這種方式是不是就是隻是給A節點增加資訊,本質就是隻有一個A node,只是分開來描述而已dts裝置節點定義名字定義格式:[label:] node-name[@unit-address]如cif:cif@1,其對應的device node name還是cif,[]表示可選擇的存在。23 ffs函式取最低有效的位置,並置為1,其餘位清零24 vmalloc_user每次vmalloc之後,核心會建立一個vm_struct,用以對映分配到的不連續的記憶體區域vma是將實體記憶體對映到程序的虛擬地址空間而vm_struct是將實體記憶體對映到核心的線性地址空間mm_struct是管理整個程序的虛擬地址空間,一般以current->mm來獲取。vmalloc_user的空間映射回使用者remap_vmalloc_range25 linux驅動自動載入順序,不同級別按照init的level,同一等級按照makefile中定義的編譯順序來決定,先編譯的模組則先會被連結到同等級中的區域塊Makefile中定義模組a和b:obj-y=a;obj-y=b;則同一等級的a、b模組,a先會被載入,b後加載26 dts例子/{  soc0{  compatible = "my, soc0";  node1{  compatible = "my, node1";                      node1_1{  compatible = "my, node1_1";  node1_1_1{  compatible = "my, node1_1_1";}}}  node2{ }}  soc1{ compatible = "my, soc1"; }}27 shell指令碼函式變數
變數含義
$0當前指令碼的檔名
$n傳遞給指令碼或函式的引數。n 是一個數字,表示第幾個引數。例如,第一個引數是$1,第二個引數是$2。
$#傳遞給指令碼或函式的引數個數。
$*傳遞給指令碼或函式的所有引數。
$@傳遞給指令碼或函式的所有引數。被雙引號(" ")包含時,與 $* 稍有不同,下面將會講到。
$?上個命令的退出狀態,或函式的返回值。
$$當前Shell程序ID。對於 Shell 指令碼,就是這些指令碼所在的程序ID。