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, 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 **);
};
make[1]: Entering directory `/opt/ti/job_nfs/examples-03.21.00.04/driver/cmem' make -C /opt/ti/job_nfs/linux-2.6.37-ti M=/opt/ti/job_nfs/examples-03.21.00.04/driver/cmem ARCH=arm EXTRA_CFLAGS="-O3 -I -DMAX_POOLS=128" LDDINC=/opt/ti/job_nfs/examples-03.21.00.04/driver/cmem modules make[2]: Entering directory `/opt/ti/job_nfs/linux-2.6.37-ti' CC [M] /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.o /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:68:2: warning: #warning *** not a warning *** Note: LINUX_VERSION_CODE >= 2.6.26 /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:210: warning: type defaults to 'int' in declaration of 'DECLARE_MUTEX' /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:210: warning: parameter names (without types) in function declaration /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:249: error: unknown field 'ioctl' specified in initializer /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:249: warning: initialization from incompatible pointer type /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c: In function 'cmem_seq_stop': /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:819: error: 'cmem_mutex' undeclared (first use in this function) /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:819: error: (Each undeclared identifier is reported only once /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:819: error: for each function it appears in.) /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c: In function 'cmem_seq_start': /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:827: error: 'cmem_mutex' undeclared (first use in this function) /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c: In function 'ioctl': /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:1151: error: 'cmem_mutex' undeclared (first use in this function) /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c: In function 'mmap': /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:1782: error: 'cmem_mutex' undeclared (first use in this function) /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c: In function 'release': /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:1854: error: 'cmem_mutex' undeclared (first use in this function) make[3]: *** [/opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.o] Error 1 make[2]: *** [_module_/opt/ti/job_nfs/examples-03.21.00.04/driver/cmem] Error 2 make[2]: Leaving directory `/opt/ti/job_nfs/linux-2.6.37-ti' make[1]: *** [default] Error 2 make[1]: Leaving directory `/opt/ti/job_nfs/examples-03.21.00.04/driver/cmem' make: *** [all] Error 2 dsp@Ubuntu:/opt/ti/job_nfs/examples-03.21.00.04/driver$ ls cmem/ cmem.h cmemk.c Makefile修改:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
#warning *** not a warning *** Note: LINUX_VERSION_CODE >= 2.6.36
static DEFINE_SEMAPHORE(cmem_mutex);
#else
static DECLARE_MUTEX(cmem_mutex);
#endif
static struct file_operations cmem_fxns = { .owner = THIS_MODULE, .open = open, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) #warning *** not a warning Note: LINUX_VERSION_CODE >= 2.6.36 unlocked_ioctl .unlocked_ioctl = cmem_ioctl, #else .ioctl = cmem_ioctl, #endif .mmap = mmap, .release = release, };make[1]: Entering directory `/opt/ti/job_nfs/examples-03.21.00.04/driver/cmem' make -C /opt/ti/job_nfs/linux-2.6.37-ti M=/opt/ti/job_nfs/examples-03.21.00.04/driver/cmem ARCH=arm EXTRA_CFLAGS="-O3 -I -DMAX_POOLS=128" LDDINC=/opt/ti/job_nfs/examples-03.21.00.04/driver/cmem modules make[2]: Entering directory `/opt/ti/job_nfs/linux-2.6.37-ti' CC [M] /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.o /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:44:2: warning: #warning *** not a warning *** Note: LINUX_VERSION_CODE >= 2.6.28 /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:70:2: warning: #warning *** not a warning *** Note: LINUX_VERSION_CODE >= 2.6.26 /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:214:2: warning: #warning *** not a warning Note: LINUX_VERSION_CODE >= 2.6.36 DEFINE_SEMAPHORE /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:260:2: warning: #warning *** not a warning Note: LINUX_VERSION_CODE >= 2.6.36 unlocked_ioctl /opt/ti/job_nfs/examples-03.21.00.04/driver/cmem/cmemk.c:261: warning: initialization from incompatible pointer type Building modules, stage 2. MODPOST 1 modulesmake[1]: Entering directory `/opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm' make -C /opt/ti/job_nfs/linux-2.6.37-ti M=/opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm ARCH=arm EXTRA_CFLAGS="-O3 -I -DMAX_POOLS=" LDDINC=/opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm modules make[2]: Entering directory `/opt/ti/job_nfs/linux-2.6.37-ti' CC [M] /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.o /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.c:89:2: warning: #warning Note: LINUX_VERSION_CODE >= 2.6.36 DEFINE_SEMAPHORE /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.c:106:2: warning: #warning Note: LINUX_VERSION_CODE >= 2.6.36 unlocked_ioctl /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.c:107: warning: initialization from incompatible pointer type /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.c: In function 'dm365mmap_init': /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.c:300: error: implicit declaration of function 'init_MUTEX_LOCKED' make[3]: *** [/opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.o] Error 1 make[2]: *** [_module_/opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm] Error 2 make[2]: Leaving directory `/opt/ti/job_nfs/linux-2.6.37-ti' make[1]: *** [default] Error 2在运行时初始化得变化(动态分配):
以去除:
void init_MUTEX(struct semaphore *sem);void init_MUTEX_LOCKED(struct semaphore *sem);
可通过以下初始:
void sema_init(struct semaphore *sem, int val);
修改:#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) #warning Note: LINUX_VERSION_CODE >= 2.6.36 sema_init sema_init(&dm365mmap_reply_mutex, 0); #else init_MUTEX_LOCKED(&dm365mmap_reply_mutex); #endifmake[1]: Entering directory `/opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm' make -C /opt/ti/job_nfs/linux-2.6.37-ti M=/opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm ARCH=arm EXTRA_CFLAGS="-O3 -I -DMAX_POOLS=" LDDINC=/opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm modules make[2]: Entering directory `/opt/ti/job_nfs/linux-2.6.37-ti' CC [M] /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.o /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.c:89:2: warning: #warning Note: LINUX_VERSION_CODE >= 2.6.36 DEFINE_SEMAPHORE /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.c:106:2: warning: #warning Note: LINUX_VERSION_CODE >= 2.6.36 unlocked_ioctl /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.c:107: warning: initialization from incompatible pointer type /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.c:174:2: warning: #warning Note: LINUX_VERSION_CODE >= 2.6.36 sema_init /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.c:308:2: warning: #warning Note: LINUX_VERSION_CODE >= 2.6.36 sema_init Building modules, stage 2. MODPOST 1 modules CC /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.mod.o LD [M] /opt/ti/job_nfs/examples-03.21.00.04/driver/dm365mm/dm365mmap.ko
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_inodeThere 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 = NUM(file->f_path.dentry->d_inode->i_rdev); /*Which LED*/
.....
}
--------------------------------------
在file_operations 结构体中,会看到许多函数指针所指向的函数都必须传进struct file 结构体指针struct file * 作为参数。struct file 结构体定义在<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 *); 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 **); };
struct file {/* * fu_list becomes invalid after file_free is called and queued via * fu_rcuhead for RCU freeing */ union { struct list_head fu_list; struct rcu_head fu_rcuhead; } f_u; struct path f_path; #define f_dentry f_path.dentry #define f_vfsmnt f_path.mnt const struct file_operations *f_op; spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */ #ifdef CONFIG_SMP int f_sb_list_cpu; #endif 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 /* needed for tty driver, and maybe others */ void *private_data; #ifdef CONFIG_EPOLL /* Used by fs/eventpoll.c to link all the hooks to this file */ struct list_head f_ep_links; #endif /* #ifdef CONFIG_EPOLL */ 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 这个结构。