顯示具有 device drivers 標籤的文章。 顯示所有文章
顯示具有 device drivers 標籤的文章。 顯示所有文章

2009年3月15日 星期日

2.重要的資料結構file_operations,file,inode


***************************************
重要的資料結構file_operations,file,inode
***************************************/
//file_operations
此結構定義在<linux/fs.h> 是一組函數指標的集合

loff_t參數:是一個long offset , 其長度最少有64bits ?
__user參數:這是一種另類的註解,註明該指標是指向user-space位址,不可直接取值

原型如下:
struct file_operations {
struct module *owner;/*
此欄位的作用,是避免模組仍在活動中時,被卸載出核心.
通常初始化為 THIS_MODULE (所定義的?#64;個巨集)
幾乎沒有例外
*/
loff_t (*llseek) (struct file *, loff_t, int); /*
改變檔案的存取位置,使得下次讀寫在新位置開始
改變的是file結構裡的loff_t f_pos參數,file結構看後面
*/
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);/*
後面詳細介紹
*/
ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);/*
類似read,但不同步
*/
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);/*
後面詳細介紹
*/
ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);/*
類似write,但不同步
*/
int (*readdir) (struct file *, void *, filldir_t);/*
讀取檔案系統上的目錄 詳細操作不詳
*/
unsigned int (*poll) (struct file *, struct poll_table_struct *);/*
檢查檔案I/O狀態,下次的讀寫如有停頓,延遲,來不及的情況,應該提供kernel用來休眠等待
直到可以順利I/O為止,指向NULL則kernel會假設你的裝置永遠都可流暢讀寫,而不會停頓
*/
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);/*
後面詳細介紹
*/
int (*mmap) (struct file *, struct vm_area_struct *);/*
?
*/
int (*open) (struct inode *, struct file *);/*
後面詳細介紹
*/
int (*flush) (struct file *);/*
為了避免資料尚未完全寫出之前,裝置檔被關閉
process關閉裝置檔時會呼叫flush
*/
int (*release) (struct inode *, struct file *);/*
後面詳細介紹
*/
int (*fsync) (struct file *, struct dentry *, int datasync);/*
讓應用程式用來將滯留在記憶體中的資料全數確實寫入裝置
*/
int (*aio_fsync) (struct kiocb *, int datasync);/*
類似fsynce,但不同步
*/
int (*fasync) (int, struct file *, int);/*
異步作業通知?
*/
int (*lock) (struct file *, int, struct file_lock *);/*
檔案鎖定
*/
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
int (*flock) (struct file *, int, struct file_lock *);
};

//初始化
1.
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.ioctl = device_ioctl,
.open = device_open,
.release = device_release
};
2.
static struct file_operation fops = {
read: device_read,
write: device_write,
ioctl: device_ioctl,
open: device_open,
release: device_release
};



//file
此結構定義在<linux/fs.h>
file結構表示已開啟的檔案
每一個file結構都是kernel在收到open系統呼叫時自動建立的
在最後一次close系統呼叫時會被釋放
原型如下:
struct file {
struct list_head f_list;
struct dentry *f_dentry;/*
通常不在乎自己在哪個目錄項,
但會有需要透過file->f_dentry->d_inode來存取inode結構
*/
struct vfsmount *f_vfsmnt;
struct file_operations *f_op;/*
指向file_operations結構
*/
atomic_t f_count;
unsigned int f_flags;/*
?
*/
mode_t f_mode;/*
包含可讀可寫的權限資訊
*/
int f_error;
loff_t f_pos;/*
目前的讀寫位置
*/
struct fown_struct f_owner;
unsigned int f_uid, f_gid;
struct file_ra_state f_ra;

unsigned long f_version;
void *f_security;

/* needed for tty driver, and maybe others */
void *private_data;/*
驅動程式可自行運用此指標,典型用法是讓他指向一塊私有資料區
如果有用到這個,release時要記得釋放此指標的記憶體
非常好用的功能
*/
#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
spinlock_t f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
};



//inode
kernel內部用inode來表示檔案
不同於file結構
同一個檔案可以被開啟很多次就會有很多file結構
但他們全部指向同一個inode結構

重要的結構內容只有兩個
dev_t i_rdev;/*
此欄位含有實際的裝置編號
可用unsigned int imajor(struct inode* inode);
unsigned int iminor(struct inode* inode);
來取得major和minor號碼 原型如下:
static inline unsigned iminor(struct inode *inode)
{
return MINOR(inode->i_rdev);
}
static inline unsigned imajor(struct inode *inode)
{
return MAJOR(inode->i_rdev);
}
*/
struct cdev *i_cdev;/*
用來表示字元裝置的結構,後面會詳談
*/
}

2009年2月24日 星期二

1.主編號與次編號major與minor

/***************************************
主編號與次編號major與minor
***************************************/
dev_t型態 定義在<linux/types.h>

這三個定義在<linux/kdev_t.h>
MAJOR(dev_t dev);
MINOR(dev_t dev);
MKDEV(int major , int minor);

//取得&釋放裝置編號2.6版
<linux/fs.h> 定義的
//給定主編號
1.int register_chrdev_region(dev_t first , unsigned int count , char *name);
ex: register_chrdev_region( MKDEV(major,minor) , 1 , "char_reg" );
第一個參數:要配置的裝置號碼 (次編號通常是0)
第二個參數:申請連續裝置編號的總數
第三個參數:出現在/proc/devices與sysfs的名稱 (2.6以上 sysfs /sys/module/..)
回傳值: 0表示成功 負值表示失敗

//自動給主編號
2.int alloc_chrdev_region(dev_t *dev , unsigned int firstminor , unsigned int count , char *name);
ex: alloc_chrdev_region( &dnoev , 0 , 1 , "char_reg" );
第一個參數:僅供輸出的參數,當配置成功,此參數持有配置的裝備編號
第二個參數:你想申請的第一個次編號 (通常是0)
第三個參數:申請連續裝置編號的總數
第四個參數:出現在/proc/devices與sysfs的名稱 (2.6以上 sysfs /sys/module/..)
回傳值: 0表示成功 負值表示失敗

//釋放裝置編號
3.void unregister_chrdev_region(dev_t first , unsigned int count);
ex: unregister_chrdev_region( MKDEV(major,minor) , 1 );
第一個參數:配置的裝置號碼 (次編號通常是0)
第二個參數:申請連續裝置編號的總數




//取得&連結&釋放裝置編號2.4版
<linux/fs.h> 定義的
//取得裝置編號&連結
1.int register_chrdev(unsigned int major, const char *name , struct file_operations *fops );
ex: major=register_chrdev( 0 , "char_reg" , &fops );
第一個參數:為0時,給kernel自動分配; 其他值就是給定的主編號
第二個參數:出現在/proc/devices與sysfs的名稱 (2.6以上 sysfs /sys/module/..)
第三個參數:將裝置編號連結到驅動程式的作業功能,後面會說明
回傳值: 為major號碼 負值表示失敗

//釋放裝置編號
2.int unregister_chrdev(unsigned int major , const char *name );
ex: unregister_chrdev( major , "char_reg" );
第一個參數:主編號
第二個參數:出現在/proc/devices與sysfs的名稱 (2.6以上 sysfs /sys/module/..)


}

2009年2月22日 星期日

design the new driver in make menuconfig

design the new driver

1.driver程式中的進入點和結束點要用以下寫法
int __init test_init(void) { }
void __exit test_exit(void) { }
module_init(test_init);
module_exit(test_exit);
2.Modify for menuconfig
Character Driver
– 2.4: kernel/drivers/char/Config.in
– 2.6: Kernel/drivers/char/Kconfig
/usr/src/linux-2.4.x /drivers/char/Config.in
tristate ‘My test module' CONFIG_HELLO
/usr/src/linux-2.6.x /drivers/char/Kconfig
config HELLO
tristate “My test module"
help
This is my test module
3.Add the New Item in the Makefile
Character Driver
– kernel/drivers/char/Makefile
/usr/src/linux-2.4.x /drivers/char/Makefile
obj-$(CONFIG_HELLO) += test.o
/usr/src/linux-2.6.x /drivers/char/Makefile
obj-$(CONFIG_HELLO) += test.o

2009年2月5日 星期四

depmod


有相依性的程式
在程式中需多上
**************************
* EXPORT_SYMBOL(symbol); *
**************************
告知公開的函式

make後
再把*.ko檔放入depmod搜索路徑內
/lib/modules/2.6.9/kernel/drivers/.....

在打上指令
depmod -ae
來讓/lib/modules/2.6.9/modules.dep檔建立相依關係
最後再用modprobe -V xxxx 來讓相依檔都載入核心
移除用modprobe -r xxxx移除
相依檔也會移除
###############################
第二種方法
不好用
用的人少
**************************
* request_module("xxxx") *
**************************
還要多標頭檔linux/kmod.h
移除也沒辦法一次移除
要一個一個來
因為沒相依
但載入都會一起進去

2009年2月4日 星期三

標頭檔 不能有空白


#includ< 空白linux/module.h空白>
這樣是錯的
在 < >之間加空白 make 就會失敗
切記

PO在這邊的文章
為求PO文方便
都有加上空白
要記得改

para多上變數



#######################
[root@localhost para]# cat para.c
#include < linux/kernel.h >
#include < linux/module.h >
#include < linux/init.h >

static int myint=10;
static int myarr[2]={2.45};
static char mybyte='a';
static unsigned short myshort=1;
static long mylong=9999;
static char *mystring="karta";

MODULE_PARM(myint,"i");
MODULE_PARM(myarr,"1-2i");
MODULE_PARM(mybyte,"b");
MODULE_PARM(myshort,"h");
MODULE_PARM(mylong,"l");
MODULE_PARM(mystring,"s");
/*
MODULE_PARM(var,type);
type可用很多表示 上面已列出差不多了
*/

MODULE_PARM_DESC(myint,"this is int");
MODULE_PARM_DESC(myaaa,"this is aaa");
//MODULE_PARM_DESC 這個訊息在用modinfo可以看到
/*
[root@localhost para]# modinfo para.ko
filename: para.ko
parm: myint:this is int
parm: myaaa:this is aaa
vermagic: 2.6.9 686 REGPARM gcc-3.4
depends:
[root@localhost para]#
*/

static int __init hello_init(void){
printk("<1>myint is=%i\n",myint);
//用%i 和 %d是一樣的
printk("<1>myarr is=%i %i\n",myarr[0],myarr[1]);
printk("<1>mybyte is=%i\n",mybyte);
printk("<1>myshort is=%hi\n",myshort);
printk("<1>mylong is=%li\n",mylong);
printk("<1>mystring is=%s\n",mystring);
return 0;
}

static void __exit hello_exit(void){
printk("<1>Bye!Bye!!\n");
}

module_init(hello_init);
module_exit(hello_exit);

[root@localhost para]#

#######################
[root@localhost para]# cat Makefile
obj-m += para.o
all:
make -C /lib/modules/2.6.9/build M=/mnt/driver/para modules
clean:
make -C /lib/modules/2.6.9/build M=/mnt/driver/para clean

[root@localhost para]#

#######################
Feb 4 19:46:53 localhost kernel: myint is=10
Feb 4 19:46:53 localhost kernel: myarr is=2 0
Feb 4 19:46:53 localhost kernel: mybyte is=97
Feb 4 19:46:53 localhost kernel: myshort is=1
Feb 4 19:46:53 localhost kernel: mylong is=9999
Feb 4 19:46:53 localhost kernel: mystring is=karta
Feb 4 19:53:23 localhost kernel: Bye!Bye!!
[root@localhost para]#

hello world 3 #ifdef


一樣是分開成兩個檔案
再多上#ifdef的用法
[root@localhost driver]# cd hello3
[root@localhost hello3]# ls
Makefile start.c stop.c

###########################################################
[root@localhost hello3]# cat start.c
#include < linux/kernel.h >
#include < linux/module.h >
#include < linux/init.h >

static int __init hello_init(void){
#ifdef __TEST__
printk("<1>Hello, World!!TEST\n");
#else
printk("<1>not __TEST__\n");
#endif
return 0;
}

module_init(hello_init);
[root@localhost hello3]#

###########################################################
[root@localhost hello3]# cat stop.c
#include < linux/kernel.h >
#include < linux/module.h >
#include < linux/init.h >

static void __exit hello_exit(void){
printk("<1>Bye!Bye!!\n");
}

module_exit(hello_exit);
[root@localhost hello3]#

###########################################################
[root@localhost hello3]# cat Makefile
obj-m += startstop.o
startstop-objs := start.o stop.o
EXTRA_CFLAGS += -D__TEST__
# makefile上多上這行等於是#define __TEST__
# 或等於在gcc上 多加上-D__TEST__這行
all:
make -C /lib/modules/2.6.9/build M=/mnt/driver/hello3 modules
clean:
make -C /lib/modules/2.6.9/build M=/mnt/driver/hello3 clean

[root@localhost hello3]#


hello world 2 單一hello.c檔變兩個


[root@localhost driver]# cd hello2
[root@localhost hello2]# ls
Makefile start.c stop.c
關鍵在Makefile
##########################################################
[root@localhost hello2]# cat start.c
#include < linux/kernel.h >
#include < linux/module.h >
#include < linux/init.h >

static int __init hello_init(void){
printk("<1>Hello, World!!\n");
return 0;
}

module_init(hello_init);
[root@localhost hello2]#

##########################################################
[root@localhost hello2]# cat stop.c
#include < linux/kernel.h >
#include < linux/module.h >
#include < linux/init.h >

static void __exit hello_exit(void){
printk("<1>Bye!Bye!!\n");
}

module_exit(hello_exit);
[root@localhost hello2]#

##########################################################
[root@localhost hello2]# cat Makefile
obj-m += startstop.o
startstop-objs := start.o stop.o
all:
make -C /lib/modules/2.6.9/build M=/mnt/driver/hello2 modules
clean:
make -C /lib/modules/2.6.9/build M=/mnt/driver/hello2 clean

[root@localhost hello2]#


hello world

第一個的程式 hello world for device drivers
#######################################################
[root@localhost hello]# cat hello.c
#include < linux/kernel.h >
#include < linux/module.h >
#include < linux/init.h >


static int __init hello_init(void){
printk("<1>Hello, World!!\n");
return 0;
}

static void __exit hello_exit(void){
printk("<1>Bye!Bye!!\n");
}

module_init(hello_init);
module_exit(hello_exit);
[root@localhost hello]#

#######################################################

[root@localhost hello]# cat Makefile
obj-m += hello.o
all:
make -C /lib/modules/2.6.9/build M=/mnt/driver/hello modules
# 上列可改成
# make V=1 -C /lib/modules/`uname -r`/build M=`pwd` modules
# #號為註解

clean:
make -C /lib/modules/2.6.9/build M=/mnt/driver/hello clean

[root@localhost hello]#

#######################################################

[root@localhost hello]# insmod hello.ko
Hello, World!!
[root@localhost hello]# rmmod hello
Bye!Bye!!
[root@localhost hello]#