|
文件: |
driver-all.rar |
大小: |
4KB |
下载: |
下载 | |
/*
* (C) copyright 2008
*/
#define __NO_VERSION__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
unsigned int test_major = 0;
//#define MAJOR_NUM 254
//MODULE_LICENSE("GPL")
static int count;
//static char data[100];
char *data="wodeshen" ;
static spinlock_t spin=SPIN_LOCK_UNLOCKED;
static struct semaphore sem;
static wait_queue_head_t outq;
static struct fasync_struct fasync_t;
struct fasync_struct *myfasync=&fasync_t;
static struct completion test_completion;//DECLARE_COMPLETION(comp);
static int flag=0;
/*
static int __init test_init(void)
{
int ret;
ret=register_chrdev(0 ,"test",&test_op);
if(ret<0)
printk("register * failure\n");
init_MUTEX(&sem);
init_waitqueue_head(&outq);
test_major=ret;
return ret;
}
*/
/*
static void __exit test_exit(void)
{
int ret;
ret=unregister_chrdev(test_major ,"test");
if(ret<0)
printk("unregister failure\n");
}
*/
static int test_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg)
{
long retval = 0;
switch(cmd){
case 1:
printk("1\n");
break;
case 2:
printk("2\n");
break;
case 3:
printk("3\n");
break;
case 4:
printk("4\n");
break;
default:
return -ENOTTY;
}
return retval;
}
/*
static int test_mmap(struct file* filp, struct vm_area_struct *vma)
{
}
*/
static ssize_t test_open(struct inode *inode ,struct file *file)
{
spin_lock(&spin);
//防止多个进程进入,这里允许俩个进程(方便俩个终端测试),一个写一个读
if(count>1){
spin_unlock(&spin);
return -EBUSY;
}
count++;
spin_unlock(&spin);
return 0;
}
static int test_release(struct inode *inode,struct file *file)
{
count--;
return 0;
}
static ssize_t test_read( struct file *file, char *buf, size_t len, loff_t *off)
{
//slect的poll机制
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&outq, &wait);
//read的阻塞机制
//if(wait_event_interruptible(outq,flag!=0))
//return -ERESTARTSYS;
//轻量级通知机制
wait_for_completion(&test_completion);
if(down_interruptible(&sem))
return - ERESTARTSYS;
/*
即交换wait_event_interruptible(outq, flag != 0)和down_interruptible(&sem)的顺序,
这个驱动程序将变得不可运行。实际上,当两个可能要阻塞的事件同时出现时,
即两个wait_event或down摆在一起的时候,将变得非常危险,死锁的可能性很大,
这个时候我们要特别留意它们的出现顺序。当然,我们应该尽可能地避免这种情况的发生!
*/
flag=0;
if(copy_to_user(buf,data,len)){
up(&sem);
return -EFAULT;
}
up(&sem);
//删除很重要啊,要不下次一个进程执行write时候wake_up_interruptible(&outq);将崩溃
remove_wait_queue(&outq, &wait);
return len;
}
//static ssize_t test_write(struct file *file,char *buf, size_t len, loff_t *off)
static ssize_t test_write(struct file *file, const char *buf, size_t len, loff_t *f_pos)
{
printk("------test_write--------\n");
if(down_interruptible(&sem))
return -ERESTARTSYS;
if(copy_from_user(data,buf,len)){
up(&sem);
return -EFAULT;
}
up(&sem);
flag=1;
printk("------write ok--------\n");
wake_up_interruptible(&outq);
complete(&test_completion);
kill_fasync(&myfasync, SIGIO, POLL_IN);
printk("------send ok--------\n");
return len;
}
static unsigned int test_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
//poll_wait函数所做的工作是把当前进程添
//加到wait参数指定的等待列表(poll_table)中。
//poll_wait函数并不阻塞,
//程序中poll_wait(filp, &outq, wait)这句话的意思并不是说
//一直等待outq信号量可获得,
//真正的阻塞动作是上层的select/poll函数中完成的。
poll_wait(file,&outq,wait);
printk("2-----poll_wait\n");
if (flag!=0)
mask|=POLLIN |POLLRDNORM;
return mask;
}
static int test_fasync(int fd, struct file* file, int mode)
{
printk("1-----test_fasync\n");
return fasync_helper(fd, file, mode, &myfasync);
}
struct file_operations test_op={
read : test_read,
write : test_write,
open : test_open,
release: test_release,
poll : test_poll,
//异步通知和poll,和read的阻塞有一拼
fasync : test_fasync,
//存放数据和read比较mmap好
//mmap : test_mmap,
//cmd控制
ioctl : test_ioctl,
};
static unsigned int major =254;
int init_module(void)
{
//unsigned int ret;
//int i;
int ret;
printk("-------------\n");
//printk("---%d---\n",register_chrdev(0, "test", &test_op));
ret=register_chrdev(0, "test", &test_op);
if(ret<0)
printk("register eeee failure\n");
init_MUTEX(&sem);
init_waitqueue_head(&outq);
init_completion(&test_completion); //DECLARE_COMPLETION(test_completion);
printk("---%d---\n",ret);
return 0;
}
void cleanup_module(void)
{
//test_exit();
printk("------unregister_chrdev--------\n");
unregister_chrdev(test_major, "test");
printk("------unregister_chrdev-- ok------\n");
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("");
------------------------------------