Linux 2.6.36以後file_operations和DECLARE_MUTEX 的變化
今天嘗試移植了2.6.38的內核到AT91SAM9260上,在編譯驅動時發現從2.6.36的內核開始,include/linux/semaphore.h 和 include/linux/fs.h中有了兩處變化與驅動相關:
1, 在include/linux/semaphore.h 中
將#define DECLARE_MUTEX(name) 改成了 #define DEFINE_SEMAPHORE(name)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
DECLARE_MUTEX(led_sem);
#else
DEFINE_SEMAPHORE(led_sem);
#endif
2,usb_buffer_alloc 和 usb_buffer_free
在linux2.6.34和之前的代碼中還可以使用usb_buffer_alloc 和 usb_buffer_free 這兩個函數,在2.6.35和之後的內核中
usb_buffer_alloc 和 usb_buffer_free這兩個函數已不在使用了,可以用usb_alloc_coherent 和 usb_free_coherent代替。
3, file_operations結構體有了一些變化,它去掉了:
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
另外添加了:
long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);
這是2.6.36的內核裏的定義include/linux/fs.h:
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
//從2.6.36開始刪除ioctl(), 2.6.35中有
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
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 (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
// long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); 從2.6.38內核開始添加該項,2.6.37以下無
};
下麵是Linux-2.6.35裏的file_operations
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
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 (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
};
[guowenxue@localhost at91sam9260]$ make
make[1]: Entering directory `/usr/.devices_group/guowenxue/l350-dev06/src/kernel/linux-2.6.38'
CC [M] /usr/.devices_group/guowenxue/embedded_project/drivers/at91sam9260/dev_skeleton.o
/usr/.devices_group/guowenxue/embedded_project/drivers/at91sam9260/dev_skeleton.c:93: error: unknown field 'ioctl' specified in initializer
/usr/.devices_group/guowenxue/embedded_project/drivers/at91sam9260/dev_skeleton.c:93: warning: initialization from incompatible pointer type
make[2]: *** [/usr/.devices_group/guowenxue/embedded_project/drivers/at91sam9260/dev_skeleton.o] Error 1
make[1]: *** [_module_/usr/.devices_group/guowenxue/embedded_project/drivers/at91sam9260] Error 2
make[1]: Leaving directory `/usr/.devices_group/guowenxue/l350-dev06/src/kernel/linux-2.6.38'
make: *** [modules] Error 2
參考別的字元設備的驅動drivers/char/ppdev.c:
static const struct file_operations pp_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = pp_read,
.write = pp_write,
.poll = pp_poll,
.unlocked_ioctl = pp_ioctl,
.open = pp_open,
.release = pp_release,
};
這裏ioctl()已使用unlocked_ioctl代替。
但這裏不是一個簡單的替換,要注意unlocked_ioctl和ioctl的函數原型並不一致。
unlocked_ioctl: long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
ioctl: int(*ioctl) (struct inode *,struct file *, unsigned int, unsigned long);
The 'inode' value that was passed to 'ioctl' function is available for use with the 'unlocked_ioctl' function by way of filp->d_entry->d_inode:
long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);
...
struct inode *inode = filp->f_path.dentry->d_inode
There is a nice explanation of this at http://lwn.net/Articles/119652/
如:
static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int index = iminor(file->f_path.dentry->d_inode); /* Which Channel*/
.....
}
--------------------------------------
在file_operations 結構體中,會看到許多函數指標所指向的函數都必須傳進struct file 結構體指標struct file * 作為參數。struct file 結構體定義在<linux/fs.h> 中,完整如下:
引用
struct file {
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
#definef_dentry f_path.dentry
#definef_vfsmnt f_path.mnt
const struct file_operations *f_op;
spinlock_t f_lock;
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
loff_t f_pos;
struct fown_struct f_owner;
const struct cred *f_cred;
struct file_ra_state f_ra;
u64 f_version;
#ifdef CONFIG_SECURITY
void *f_security;
#endif
void *private_data;
#ifdef CONFIG_EPOLL
struct list_head f_ep_links;
#endif
struct address_space *f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
unsigned long f_mnt_write_state;
#endif
};
在設備驅動中,struct file 結構體也是一個非常重要的資料結構。注意的是,這裏的file 和應用程式中的FILE 流指標沒有什麼關係,FILE 定義在C 庫中,它永遠不會出現在內核代碼中。
file structure 結構代表一個打開的檔(open file).(打開的檔並沒有確切的指定到哪個設備驅動,實際上每個打開的檔都與內核空間中的struct file 結構相關聯)。
file structure 結構在調用open 打開一個檔時由內核創建,並會被傳遞給任一個對這個打開檔進行操作的函數;當所有事情都做完後,會調用close() 關閉掉檔,此時內核釋放這個資料結構。
一般地,在內核源碼中,struct file 結構體的指標往往寫成filp 。
struct file 中的幾個重要成員:
mode_t f_mode;
文 件模式根據FMMODE_READ 和FMODE_WRITE 位元來識別文件是否可讀或可寫,或是可讀可寫。在read() 和write() 系統調用 中,沒有必要對此許可權進行檢查,因為內核已經在你的系統調用之前已經做了檢查。如果檔沒有相應的讀或寫許可權,那麼如果嘗試讀寫都將被拒絕,驅動程式甚至 對此情況毫無知覺。
loff_t f_pos;
此變數表示當前的檔讀寫位置。loff_t 在所有的平臺上都是64 位元的變數 ( long long 型, gcc 專用術語)。驅動程式如果想知道當前在檔中所處位置,那麼可以通過讀取此變數得知,但是一般地不應直接對此進行更改。通過llseek() 方 法可以改變檔位置。
unsigned int f_flags;
這是表示如O_RDONLY, O_NONBLOCK與O_SYNC 這樣的標誌。一個驅動程式應該檢查O_NONBLOCK 標誌,以查看是否有非阻塞操作的請求。其他的標誌用得比較 少。需要注意的是,檢查read/write 許可權應該是通過檢查f_mode 得到而不是f_flags 。所有的標誌定義在頭檔linux /fcntl.h 中可以看到。
struct file_operations*f_op;
內核安排這個指標作為它的open 實現的一部分,當需要分派什麼操作時,會讀取它。filp->f_op 因為不會被內核保存起來以在其後之用,所以我們可以改變我們對相關檔的操作,在對檔使用新的操作方法時,我們就會轉移到相應調用上。
void *private_data;
在 對驅動調用open 方法之前,open() 系統調用會這個指標設置為NULL 。用戶可以自由使用這個域,或者對其忽略。可以使用這個域之想分配的數 據空間,但必須記得在內核銷毀file structure 之前在release 方法裏釋放掉原來分配的記憶體。private_data 對於系統調用之間資訊的保存會顯得非常有用。
struct dentry*f_dentry;
目錄入口(dentry) 結構與檔相關。一般的,除了在以filp->f_dentry->d_inode 來訪問inode 結構時,我們不太關心dentry 這個結構。
http://hi.baidu.com/kkernel/item/ea0ae8f4abb46929743c4c96
留言列表