2007年7月29日 星期日

Linux Device Driver 1

要如何控制硬體裝置呢?

應用程式觀點:
應用程式透過一組標準化的呼叫就可以來間接操作硬體
ex: open("/dev/Lucky1", ....) , read(), write() ioctl()



Example:
strace cat /dev/input/mice
(strace可以看到system call)

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

Device Driver扮演的角色:
以實際的硬體動作來實現"系統呼叫"所定義的功能
模組化:驅動程式跟核心分開製作, 且再有需要時, 才在執行期將驅動程式"insert"到核心裡

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

機制 Mechanism & 法則 Policy

機制:要提供甚麼能力?
法則:如何只用這個能力?

留下 How to use it?(Policy) 的問題給application
Policy-free的驅動程式, 盡量徹底發揮硬體能力(Sync, Async, Multiple opened, ....)

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

分類:

Character Device
有device node
"Direct Data Channel" to H/W
Device node可以直接被讀寫
ex: /dev/tty1

Block Device
有device node
Transfer Blocks data => 可以適合拿來high speed H/W
"No Direct channel"所以不可以直接access
ex: /dev/sda 要以File System來存取

Network Interface
沒有device node
沒有read/write operation,使用packet transmission fuction
系統會自行負責packet

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

來掛載最簡單的Driver吧~

-----------------------------------------------------------------------------------------------------
hello.c

#include
#include
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Lucky Chang");

static char* name="Quanta";
module_param(name, charp, 0);

static int __init hello_init(void) {
printk(KERN_ALERT "Hello, %s\n",name);
return 0;
}

static void __exit hello_exit(void) {
printk(KERN_ALERT "Bye\n");
}

module_init(hello_init);
module_exit(hello_exit);

-----------------------------------------------------------------------------------------------------
P.S.

function前面加static?
此function只有此file看的到 (OOP的 private 觀念)

__init ?
讓kernel知道該函式僅用於初始期間, 當module被順利載入, 模組裝載器會丟掉初始函式, 將記憶體空出來做其他用途

__exit ?
讓kernel知道該函式僅用於卸載期間, 如果這個模組要直接嵌在核心裡, 或核心設定不容許卸載, 則標示__exit的函式就可以丟掉了

printk() ?
當執行到driver時, 以進入kernel mode, 並無法使用標準C函式庫的library
printk()函式定義在Linux核心內, 再沒有C函式庫的協助下, 自己執行自己
KERN_ALERT代表訊息優先度

寫Driver一定會用到的Macros
module_init( init_func );
module_exit( clean_func );

module_param(name, type, perm)
type: byte, short, ushort, int, uint, long, ulong, charp, bool
ex:
static char* name="Quanta"
module_param(name, charp, 0:
static int address=0;
module_param(address, int, 0);

EXPORT_SYMBOL( name ); //加到kernel Symbol Table, 以後其他Driver or 誰就可以用到了

MODULE_LICENSE()
MODULE_AUTHOR( name ) //才能把自己的名字藏進去啊

Makefile
-----------------------------------------------------------------------------------------------------

# Comment/uncomment the following line to disable/enable debugging
#DEBUG = y

# Add your debugging flag (or not) to CFLAGS
ifeq ($(DEBUG),y)
DEBFLAGS = -O -g # "-O" is needed to expand inlines
else
DEBFLAGS = -O2
endif

CFLAGS += $(DEBFLAGS) -I$(LDDINCDIR)

ifneq ($(KERNELRELEASE),)
# call from kernel build system

obj-m := hello.o

else

KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINCDIR=$(PWD)/../include modules

endif



clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

depend .depend dep:
$(CC) $(CFLAGS) -M *.c > .depend


ifeq (.depend,$(wildcard .depend))
include .depend
endif
-----------------------------------------------------------------------------------------------------

如何執行?
make
modinfo hello.ko
insmod hello.ko name="Lucky"
dmesg
rmmod hello
dmesg

加新功能 多一個數字參數
insmod hello.ko name="Lucky" count=5

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

1 則留言: