Pages

2009年2月27日 星期五

驅動程式初體驗

因為需求,必須去了解 Linux Driver,所以就東問西問、看非常艱澀的驅動程式第3版、亂試一通,終於把 Dualview 給弄出來,所以趁著空檔時間,來po個文章..:)。##ReadMore##

這裡先簡單把如何寫一個驅動程式的基本程式碼列出來做說明,當然也可以從歐萊禮下載原始碼來做測試,如果官方網站掛掉還有這裡
// 定義模組的初始函式(__init)與清理函式(__exit)
#include <linux/init.h>
// 定義許多 module_ 開頭的函式或 MODULE_ 開頭的巨集
#include <linux/module.h>

#define DRIVER_AUTHOR   "Linly"
#define DRIVER_DESC     "Hello World crap driver"
#ifndef DRIVER_VERSION
#define DRIVER_VERSION  "v0.0.1"
#endif

/*
* KERN_ALERT = <1>,代表訊息優先度,最高為 <0>
* 用法同 printf,只是不支援浮點數
*/
static int __init helloworld_init(void)
{
 printk(KERN_ALERT "Hello, world\n");
 return 0;
}

static void __exit helloworld_cleanup(void)
{
 printk(KERN_ALERT "Goodbye, cruel world\n");
}

module_init(helloworld_init);    // for insmod calls
module_exit(helloworld_cleanup); // for rmmod calls

// 模組資訊,可從 modinfo helloworld.ko 查詢
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);
說明如下:
  1. 前兩行的標頭檔通常都會加入,作用如註解所述。
  2. module_init 是模組(驅動程式)載入會執行的;module_exit 是模組(驅動程式)移除會執行的。
  3. printk 是寫 kernel module 會使用的 API,因為一般開發應用程式的 API 都不能再撰寫驅動程式時使用,只能使用 kernel API。而優先度的部份共分為七種<0>到<7>,數字越小代表優先度越高,如果你希望訊息可以再你期望的地方印出來,就讓它優先度高一點吧,我通常使用<1>,而這些訊息可以透過「dmesg」看到。
  4. MODULE_LICENSE 一定要加上所規定的一些字串,有幾種選擇,擇一即可,如:"GPL"、"GPL v2"、"GPL and additional rights"、"Dual BSD/GPL"、"Dual MPL/GPL"、"Proprietary"。
  5. 載入模組為「sudo insmod xxxx.ko」;移除模組為「sudo rmmod xxxx.ko」,如果說要重新掛載已經存在的模組,需先移除,然後再載入。  
再來就是 Makefile,它和以往所寫的不同,在於驅動程式使用的是核心提供的函式,所以編譯時必須把目錄切換至 kernel source tree 來做編譯,這個東西可以把它想成是 develop toolkit,像標頭檔就會這裡頭。如果是 Ubuntu,該路徑位於「/usr/src」;如果是 fedora,需要去下載安裝,因為作業系統裝好並不會存在。
KERNEL_VERSION    := `uname -r`
KERNEL_DIR    := /lib/modules/$(KERNEL_VERSION)/build

PWD        := $(shell pwd)

obj-m        := helloworld.o
#module-objs   := helloworld.o

all:
    echo "Building Hello World driver..."
    make -C $(KERNEL_DIR) M=$(PWD) modules

clean:
    -rm -f *.o *.ko *.mod.c Module.symvers version.h

你會看到 KERNEL_DIR 是指派成 bra bra build,不過實際到那邊看,會發現 build 其實是一個 symbolic link,指向 /usr/src/$(KERNEL_VERSION),也就是 kernel source tree。編譯後會回到 pwd,並且在程式的目錄下,產生 .o 檔案,最後再根據 obj-m 的名稱,產生 .ko 檔(如根據 helloworld.o 產生 helloworld.ko)。然後「sudo insmod helloworld.ko」,就可以再 dmesg 看到訊息囉。

1 則留言:

Eric 提到...

lsmod:列印目前裝載的模組名稱、佔記憶體的大小與狀態。

depmod:把相依性的模組重新連結。

 
Blogger Templates