概述
设备驱动中的操作方法集中所有的函数,第一个参数都是struct file *filp。这个结构体中有个成员,专门标识阻塞和非阻塞。
1.file结构体剖析:
<include/linux/fs.h>
struct file {
union {
struct llist_node fu_llist;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
struct inode *f_inode;
const struct file_operations *f_op;
spinlock_t f_lock;
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
struct mutex f_pos_lock;
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;
struct list_head f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
} __attribute__((aligned(4)));
2.flags标识:
非阻塞:
O_NONBLOCK
if(filp->f_flags & O_NONBLOCK)
阻塞:
O_BLOCK
if(filp->f_flags & O_BLOCK)
工程实例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <asm/current.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <asm/atomic.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/device.h>
static struct class *cls = NULL;
static int major = 0;
static int minor = 0;
const int count = 6;
#define DEVNAME "demo"
static struct cdev *demop = NULL;
static atomic_t tv;
static wait_queue_head_t wq;
static int counter = 0;
static int demo_open(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);
if(!atomic_dec_and_test(&tv)){
atomic_inc(&tv);
return -EBUSY;
}
return 0;
}
static int demo_release(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);
atomic_inc(&tv);
return 0;
}
static ssize_t demo_read(struct file *filp, char __user *buf, size_t size, loff_t *offset)
{
int err = 0;
struct inode *inode = filp->f_path.dentry->d_inode;
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);
if(!counter){
if(filp->f_flags & O_NONBLOCK){
return -EAGAIN;
}
err = wait_event_interruptible(wq, (0 != counter));
if(err){
return err;
}
}
counter = 0;
return 0;
}
static ssize_t demo_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{
struct inode *inode = filp->f_path.dentry->d_inode;
printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);
counter = 10;
wake_up_interruptible(&wq);
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = demo_open,
.release= demo_release,
.read = demo_read,
.write = demo_write,
};
static int __init demo_init(void)
{
dev_t devnum;
int ret, i;
struct device *devp = NULL;
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
demop = cdev_alloc();
if(NULL == demop){
return -ENOMEM;
}
cdev_init(demop, &fops);
ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME);
if(ret){
goto ERR_STEP;
}
major = MAJOR(devnum);
ret = cdev_add(demop, devnum, count);
if(ret){
goto ERR_STEP1;
}
cls = class_create(THIS_MODULE, DEVNAME);
if(IS_ERR(cls)){
ret = PTR_ERR(cls);
goto ERR_STEP1;
}
for(i = minor; i < (count+minor); i++){
devp = device_create(cls, NULL, MKDEV(major, i), NULL, "%s%d", DEVNAME, i);
if(IS_ERR(devp)){
ret = PTR_ERR(devp);
goto ERR_STEP2;
}
}
atomic_set(&tv, 1);
init_waitqueue_head(&wq);
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - ok.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
return 0;
ERR_STEP2:
for(--i; i >= minor; i--){
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
ERR_STEP1:
unregister_chrdev_region(devnum, count);
ERR_STEP:
cdev_del(demop);
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - fail.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
return ret;
}
static void __exit demo_exit(void)
{
int i;
printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.\n",
current->comm, current->pid, __FILE__, __func__, __LINE__);
for(i=minor; i < (count+minor); i++){
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
unregister_chrdev_region(MKDEV(major, minor), count);
cdev_del(demop);
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Farsight");
MODULE_DESCRIPTION("Demo for kernel module");