View more presentations from Wu Bo-Yi
這投影片是我在接手公司其中一個專案,所做的 Slide,當然最主要是深入了解 GPMC (General Purpose Memory Control),GPMC 本來是ARM 用來跟 Memory 溝通的 interface,現在用來跟 FPGA 溝通,目前我只有看到 TI 的線上文件有看到相關說明,以及解釋 GPMC 的 Program Model,在寫 GPMC 之前請先注意 Platform Device 跟 Platform Driver 的關係,之後才會開始設定 GPMC Config(1~7) 的設定檔,這樣拿示波器就可以看到 GPMC Chip Select 訊號,每個 ARM 只能接 8 個 Chip Select,這點大家必須注意,Flash 會用掉一個,在這專案學到蠻多東西,畢竟 Driver 這塊非常大,之前寫 G-Sensor 的 i2c Driver 也是如此。此 Slide 只是初步介紹,更詳細的就要實際撰寫程式碼了。
Category: Kernel
[Linux Kernel] 讀取 /proc 底下資料最佳方法: seq_file interface
前言
最近在整合公司內部 Atheros(被高通買下) 晶片的 Router,從原本 2.6.15 升級到 2.6.34.7,升級過程遇到很多困難,其中一項升級 Wireless Driver 部份,發現在 Kernel Socket 與 User Space 溝通之間出了問題,利用 Ioctl 來取得目前在 AP 上面所有 Client 資料(包含 mac address, 處於 N or G mode…等),在 User Space 上會掉資料,後來利用 /proc 底下檔案來跟 User 之間溝通,才沒有發生任何問題,由於輸出的檔案比較多,就偏向用 2.6 Kernel 提供的 seq_file 介面( interface )建立虛擬檔案 (virtual file) 與 User Space 溝通(此方法為 Alexander Viro 所設計),此功能其實在 2.4.15 已經實做了,只是在 2.6 版本才被大量使用。 程式設計師可以透過引入The iterator interface
為了能夠讓 iterator 正常運作,我們必須實做 4 個 function (start, next, stop, show),跑得過程為 start -> show -> next -> show -> next -> stop,為了方便講解,參考 Linux Kernel(4)- seq_file 裡面範例如下:#includeContinue reading “[Linux Kernel] 讀取 /proc 底下資料最佳方法: seq_file interface”#include #include /* Necessary because we use proc fs */ #include /* for seq_file */ #include MODULE_LICENSE("GPL"); #define MAX_LINE 1000 static uint32_t *lines; /** * seq_start() takes a position as an argument and returns an iterator which * will start reading at that position. */ static void* seq_start(struct seq_file *s, loff_t *pos) { uint32_t *lines; if (*pos >= MAX_LINE) { return NULL; // no more data to read } lines = kzalloc(sizeof(uint32_t), GFP_KERNEL); if (!lines) { return NULL; } *lines = *pos + 1; return lines; } /** * move the iterator forward to the next position in the sequence */ static void* seq_next(struct seq_file *s, void *v, loff_t *pos) { uint32_t *lines = v; *pos = ++(*lines); if (*pos >= MAX_LINE) { return NULL; // no more data to read } return lines; } /** * stop() is called when iteration is complete (clean up) */ static void seq_stop(struct seq_file *s, void *v) { kfree(v); } /** * success return 0, otherwise return error code */ static int seq_show(struct seq_file *s, void *v) { seq_printf(s, "Line #%d: This is Brook's demo\n", *((uint32_t*)v)); return 0; } static struct seq_operations seq_ops = { .start = seq_start, .next = seq_next, .stop = seq_stop, .show = seq_show }; static int proc_open(struct inode *inode, struct file *file) { return seq_open(file, &seq_ops); } static struct file_operations proc_ops = { .owner = THIS_MODULE, // system .open = proc_open, .read = seq_read, // system .llseek = seq_lseek, // system .release = seq_release // system }; static int __init init_modules(void) { struct proc_dir_entry *ent; ent = create_proc_entry("brook", 0, NULL); if (ent) { ent->proc_fops = &proc_ops; } return 0; } static void __exit exit_modules(void) { if (lines) { kfree(lines); } remove_proc_entry("brook", NULL); } module_init(init_modules); module_exit(exit_modules);
[Linux] 釋放虛擬記憶體 (cache)
Linux Kernel 2.6.16 之後加入了 drop caches 的機制,可以讓系統清出多餘的記憶體,這對於搞嵌入式系統相當重要阿,Memory 不夠就不能 upgrade firmware,我們只要利用讀寫 proc 檔案就可以清除 cache 記憶體檔案,底下是操作步驟:
釋放 pagecache:捨棄一般沒使用的 cache
echo 1 > /proc/sys/vm/drop_caches
釋放 dentries and inodes
echo 2 > /proc/sys/vm/drop_caches
釋放 pagecache, dentries and inodes
echo 3 > /proc/sys/vm/drop_caches
Reference: Drop Caches 觀察 Linux 的虛擬記憶體
[網站] 好站連結 (七) Android, javascript, Css, PHP, Perl, FreeBSD, Linux
Windows C#
- C# 比較字串
- MSDN 比較字串
- Request.Form Collection
- Request Query String / Form Parametrs
- ASP.NET QueryString Usage
- Using include files with ASP.NET
- jQuery Week Calendar
- Javascript: reference the parent window from a popup
- How to get and set form element values with jQuery
- How to check and uncheck a checkbox with jQuery
- Loop through parameters passed to a Javascript function
- perl-completion.vim now supports simple context completion.
- Get URL parameters & values with jQuery
- IE6 and the !important rule
- IE 8 CSS Hack
- CSS Hack
- IE6 !IMPORTANT BUG
- Change the cursor with Javascript
- oxdroid open source
- android 實做觸控版螢幕校準
- Android事件處理
- Android事件處理下(按鍵、觸摸屏和滾動球的一些實現細節)
- Android touch screen keyboard 移植記錄
- Android Sensors Development(HAL)
- G-sensor: Accelerometer data retrieval
- 閱讀 android 有關 sensor 的原始碼總結
- Android Screen Roatation
- kernel makefile解讀
- 輸入子系統分析
- Linux輸入子系統
- Touch screen 觸控面板設備驅動中資料結構
- 按鍵設備驅動讀取函數
- 用ssh或http連線進Virtualbox的虛擬電腦
- 使用 Git 管理自己的 dotfiles
- Linux Kernel Driver 從命令行傳遞參數給 Driver 驅動程式
[PHP] GoEz Framework
[Kernel Driver] 撰寫簡易 Timer 機制
在底層 Linux Kernel 提供了時序(timing)機制,方便驅動程式設計者所使用,核心是依據硬體發出的『計時器中斷』來追蹤時間的流動狀況。我們可以依據 HZ 的值來設計 Delay 機制,讓驅動程式可以每隔固定一段時間啟動或者是發出訊號,也可以利用 Timer 來讓 LED 閃爍變化,在介紹 Timer API 之前,可以先參考 Linux Kernel: 簡介HZ, tick and jiffies 這篇文章,瞭解一些相關名詞,舉例:如果想知道一秒後的 jiffies 時間,可以寫成底下:
#ifdef CONFIG_BMA150_TIMER #include#endif j = jiffies; /* 一秒之後 */ stamp_1 = j + HZ; /* 半秒之後 */ stamp_1 = j + HZ/2; /* 20秒之後 */ stamp_1 = j + 20*HZ;
Timer API 用法
筆記一下自己在寫 BOSCH Sensortec 三軸加速偵測器(BMA150 Sensor) Driver 的時候,遇到底層要回報 input event X,Y,Z 到 Android HAL(Hardware abstraction layer),所以利用 Timer 的機制定時 report 給 Android。 首先宣告:#ifdef CONFIG_BMA150_TIMER #include在 Driver 內的 bma150_probe 裡面 call function:#endif /* 定義 timer_list struct */ #ifdef CONFIG_BMA150_TIMER struct timer_list bma150_report_timer; #endif
#ifdef CONFIG_BMA150_TIMER bma150_init_timer(); #endif撰寫 bma150_init_timer 函式:
#ifdef CONFIG_BMA150_TIMER static void bma150_init_timer(void) { D("BMA150 init_timer start\n"); /* Timer 初始化 */ init_timer(&bma150_report_timer); /* 定義 timer 所執行之函式 */ bma150_report_timer.function = bma150_report; /* 定義 timer 傳入函式之 Data */ bma150_report_timer.data = ((unsigned long) 0); /* 定義 timer Delay 時間 */ bma150_report_timer.expires = jiffies + BMA150_REPORT_DELAY_1; /* 啟動 Timer*/ add_timer(&bma150_report_timer); } #endif上述 add_timer 執行之後,會在一秒後執行 bma150_report 函式,執行之後就會停止,所以如果要一直產生迴圈,就必須在 bma150_report 裡面繼續加入 add_timer,改寫如下:
static int bma150_report(void) { D("appleboy: test timer. \n"); #ifdef CONFIG_BMA150_TIMER bma150_report_timer.expires = jiffies + BMA150_REPORT_DELAY_2; add_timer(&bma150_report_timer); #endif return 0; }我們可以重新定義 expires 時間 jiffies + BMA150_REPORT_DELAY_2,就可以一直循環了,要離開 Timer 可以在最後加入 deltimer(&bma150_report_timer),最後就完成簡易的 Timer 功能。 參考: add_timer的使用方法 Linux Kernel: 簡介HZ, tick and jiffies
[Linux Kernel] 簡單 hello world: License and Module 介紹(part 3)
在 Kernel 2.4 或以上版本,在編譯模組完成,要進行 load module 之前,你會發現底下訊息:
# insmod hello-3.o Warning: loading hello-3.o will taint the kernel: no license See http://www.tux.org/lkml/#export-tainted for information about tainted modules很顯然這訊息是要您在 kernel module 裡面加上版權宣告,例如:”GPL”,”GPL v2″…等來宣告您的 module 並非 open source,利用 MODULE_LICENSE() 巨集來宣告程式 License,同樣的,可以用 MODULE_DESCRIPTION() 來描述此模組或者是 Driver 的功用跟簡介,以及用 MODULE_AUTHOR() 來定義此模組作者,這些巨集都可以在 linux/module.h 裡找到,但是這些並非用於 Kernel 本身,如果大家想看範例程式,可以到 drivers/ 資料夾底下觀看每一個 Driver 程式,底下是簡單 hello world 範例:
#include在 linux/module.h 裡頭,可以找到 MODULE_LICENSE 可定義的 License/* pr_info所需 include 檔案*/ #include #include /* 所有 module 巨集需要檔案*/ #include static int __init hello_init(void) { pr_info("Hello, world appleboy\n"); pr_info("The process is \"%s\" (pid %i)\n", current->comm, current->pid); return 0; } static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye\n"); } MODULE_DESCRIPTION("Hello World !!");/* 此程式介紹與描述*/ MODULE_AUTHOR("Bo-Yi Wu ");/* 此程式作者*/ MODULE_LICENSE("GPL");/* 程式 License*/ module_init(hello_init); module_exit(hello_exit);
/* * The following license idents are currently accepted as indicating free * software modules * * "GPL" [GNU Public License v2 or later] * "GPL v2" [GNU Public License v2] * "GPL and additional rights" [GNU Public License v2 rights and more] * "Dual BSD/GPL" [GNU Public License v2 * or BSD license choice] * "Dual MIT/GPL" [GNU Public License v2 * or MIT license choice] * "Dual MPL/GPL" [GNU Public License v2 * or Mozilla license choice] * * The following other idents are available * * "Proprietary" [Non free products] * * There are dual licensed components, but when running with Linux it is the * GPL that is relevant so this is a non issue. Similarly LGPL linked with GPL * is a GPL combined work. * * This exists for several reasons * 1. So modinfo can show license info for users wanting to vet their setup * is free * 2. So the community can ignore bug reports including proprietary modules * 3. So vendors can do likewise based on their own policies */巨集 define:
#define MODULE_LICENSE(_license) MODULE_INFO(license, _license) /* * Author(s), use "Name" or just "Name", for multiple * authors use multiple MODULE_AUTHOR() statements/lines. */ #define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) /* What your module does. */ #define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
[Linux Kernel] 撰寫 Hello, World module: The __init and __exit Macros (part 2).
再看此篇之前,可以先閱讀作者先前寫的:『[Linux Kernel Driver] 撰寫簡單 Hello, World module (part 1).』,今天要介紹 Driver 的 init module 區別,在 Kernel 2.4 版本,您可以自行定義 init 跟 cleanup 函式,他們不再被個別稱為 init_module() 和 cleanup_module(),現在都使用 module_init() 和 module_exit() 兩大巨集,這兩函式被定義在 linux/init.h 檔案裡面,所以在寫程式務必將其 include 喔,另外一個核心模組(MODULE_LICENSE),用於讓核心知道此模組遵守自由授權條款,若沒這項宣告,核心會跟您抱怨的喔,底下為範例:
#include編譯過程,可以自行修改 Makefile,可以打開 kernel/android-2.6.29/drivers/i2c/chips/Makefile 參考範例,您會發現很多類似底下寫法:/* pr_info所需 include 檔案*/ #include #include /* 所有 module 需要檔案*/ #include MODULE_DESCRIPTION("Hello World !!"); MODULE_AUTHOR("Bo-Yi Wu "); MODULE_LICENSE("GPL"); static int __init hello_init(void) { pr_info("Hello, world appleboy\n"); pr_info("The process is \"%s\" (pid %i)\n", current->comm, current->pid); return 0; } static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye\n"); } module_init(hello_init); module_exit(hello_exit);
obj-$(CONFIG_TWL4030_POWEROFF) += twl4030-poweroff.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_RTC_X1205_I2C) += x1205.o obj-$(CONFIG_SENSORS_BOSCH_BMA150) += bma150.o如果要編譯成 module 可以設定成 obj-m += bma150.o,編譯到 Kernel image,則會寫成 obj-y += bma150.o,然而 $(CONFIG_SENSORS_BOSCH_BMA150) 是從 make menuconfig 設定,當然為什麼 menuconfig 會出現此設定,那就要從 kernel/android-2.6.29/drivers/i2c/chips/Kconfig 裡面加入 CONFIG_SENSORS_BOSCH_BMA150 設定, 選好之後,觀看 Kernel 資料夾底下的 .config 內容,看到 CONFIG_SENSORS_BOSCH_BMA150=y,這樣就正確了。
What is different of __init and __exit?
在寫 G-Senser Driver 時候,您會發現 static int __init BMA150_init(void) 跟 static void __exit BMA150_exit(void),跟平常寫 C 語言宣告函式不一樣吧,這兩個巨集分別有不同意義喔,當然也可以將 span style=”color:red”>__init 跟 __exit 拿掉,這不會影響 Driver 的編譯,但是會影響記憶體的優化,Driver 啟動時會呼叫 BMA150_init 函式,如果有加上 __init,當此 init function 執行完,會將記憶體 Release 給系統,這是針對 built-in 的方式才適用,如果是編譯成模組方式,則不會有此功能,然而 __exit 是 Driver 結束後會呼叫的 function,但是跟 __init 剛好功能相反,在 built-in 的 Kernel 映像檔並不會執行到 __exit,編譯成模組才會有釋放記憶體效果,這兩巨集可以參考 linux/init.h 檔案。[Linux Kernel] 撰寫簡單 Hello, World module (part 1).
來筆記如何在 Kernel 撰寫 hello world! module,在 Ubuntu Kernel 2.6.31-14 環境下撰寫,其實不難啦,首先先進入 Kernel 目錄,請在 /usr/src 底下看自己的系統版本,或者是利用 uname -r 來知道 Kernel 版本,底下是在 Ubuntu Kernel 2.6.31-14 Kernel 實做:
進入 Kernel 目錄
# # cd Kernel directory # cd /usr/src/linux-headers-2.6.31-14-generic-pae
建立 hello 目錄
# # mkdir directory # mkdir hello
建立 Makfile 以及 hello.c
hello.c:#includeMakefile:/* pr_info 所需 include 檔案*/ #include #include /* 所有 module 需要檔案*/ #include MODULE_DESCRIPTION("Hello World !!"); MODULE_AUTHOR("Bo-Yi Wu "); MODULE_LICENSE("GPL"); static int __init hello_init(void) { pr_info("Hello, world\n"); pr_info("The process is \"%s\" (pid %i)\n", current->comm, current->pid); return 0; } static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye\n"); } module_init(hello_init); module_exit(hello_exit);
# # Makefile by appleboy之後只要切換到 hello 目錄,直接打 make 就可以產生出 hello.ko 檔案,直接載入 hello.ko 方式:# obj-m += hello.o KVERSION := $(shell uname -r) all: $(MAKE) -C /lib/modules/$(KVERSION)/build M=$(PWD) modules clean: $(MAKE) -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
insmod ./hello.ko移除 hello.ko
rmmod ./hello.ko之後到 /var/log/message 底下就可以看到訊息:
