原创 A globalfifo driver as an example of char device d

2009-4-27 09:51 2261 6 6 分类: MCU/ 嵌入式
















/*======================================================================


A
globalfifo driver as an example of char device drivers


This
example is to introduce poll,blocking and non-blocking access




The
initial developer of the original code is Baohua Song


<author@linuxdriver.cn>.
All Rights Reserved.


======================================================================*/

点击下载


/*设备驱动模块加载函数*/








1
int globalfifo_init(void)


2
{


3
int ret;


4
dev_t devno = MKDEV(globalfifo_major, 0);


5


6
/*
申请设备号*/


7
if (globalfifo_major)


8
ret = register_chrdev_region(devno, 1, "globalfifo");


9
else /*
动态申请设备号
*/


10
{


11
ret = alloc_chrdev_region(&devno, 0, 1, "globalfifo");


12
globalfifo_major = MAJOR(devno);


13
}


14
if (ret < 0)


15
return ret;


16
/*
动态申请设备结构体的内存*/


17
globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev),
GFP_KERNEL);


18
if (!globalfifo_devp) /*
申请失败*/


19
{


20
ret = - ENOMEM;


21
goto fail_malloc;


22
}


23


24
memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));


25


26
globalfifo_setup_cdev(globalfifo_devp, 0);


27


28
init_MUTEX(&globalfifo_devp->sem); /*
初始化信号量*/


29
init_waitqueue_head(&globalfifo_devp->r_wait); /*
初始化读等待队列头*/


30
init_waitqueue_head(&globalfifo_devp->w_wait); /*
初始化写等待队列头*/


31


32
return 0;


33


34
fail_malloc: unregister_chrdev_region(devno, 1);


35
return ret;


36
}





增加等待队列后的globalfifo读写函数








1
/*globalfifo
读函数*/


2
static ssize_t globalfifo_read(struct file *filp, char __user *buf,
size_t c ount, loff_t *ppos)


3
{


4
int ret;


5
struct globalfifo_dev *dev = filp->private_data; //
获得设备结构体指针


6
DECLARE_WAITQUEUE(wait, current); //
定义等待队列


7


8
down(&dev->sem); //
获得信号量


9
add_wait_queue(&dev->r_wait, &wait); //
进入读等待队列头


10


11
/*
等待FIFO非空
*/


12
if (dev->current_len == 0)


13
{


14
if (filp->f_flags &O_NONBLOCK)


15
{


16
ret = - EAGAIN;


17
goto out;


18
}


19
__set_current_state(TASK_INTERRUPTIBLE); //
改变进程状态为睡眠


20
up(&dev->sem);


21


22
schedule(); //
调度其他进程执行



23 if (signal_pending(current))


24
//
如果是因为信号唤醒


25
{


26
ret = - ERESTARTSYS;


27
goto out2;


28
}


29


30
down(&dev->sem);


31
}


32


33
/*
拷贝到用户空间 */


34
if (count > dev->current_len)


35
count = dev->current_len;


36


37
if (copy_to_user(buf, dev->mem, count))


38
{


39
ret = - EFAULT;


40
goto out;


41
}


42
else


43
{


44
memcpy(dev->mem, dev->mem + count, dev->current_len -
count); //fifo
数据


前移


45
dev->current_len -= count; //
有效数据长度减少


46
printk(KERN_INFO "read %d bytes(s),current_len:%d\n",
count, dev->curren t_len);


47


48
wake_up_interruptible(&dev->w_wait); //
唤醒写等待队列


49


50
ret = count;


51
}


52
out: up(&dev->sem); //
释放信号量


53
out2:remove_wait_queue(&dev->w_wait, &wait);//
从附属的等待队列头移除


54
set_current_state(TASK_RUNNING);


55
return ret;


56
}


57


58
/*globalfifo
写操作*/


59
static ssize_t globalfifo_write(struct file *filp, const char __user
*buf,


60
size_t count, loff_t *ppos)


61
{


62
struct globalfifo_dev *dev = filp->private_data; //
获得设备结构体指针


63
int ret;


64
DECLARE_WAITQUEUE(wait, current); //
定义等待队列


65


66
down(&dev->sem); //
获取信号量


67
add_wait_queue(&dev->w_wait, &wait); //
进入写等待队列头


68


69
/*
等待FIFO非满
*/


70
if (dev->current_len == GLOBALFIFO_SIZE)


71
{


72
if (filp->f_flags &O_NONBLOCK)


73
//
如果是非阻塞访问


74
{


75
ret = - EAGAIN;


76
goto out;


77
}


78
__set_current_state(TASK_INTERRUPTIBLE); //
改变进程状态为睡眠


79
up(&dev->sem);


80


81
schedule(); //
调度其他进程执行


82
if (signal_pending(current))


83
//
如果是因为信号唤醒


84
{


85
ret = - ERESTARTSYS;


86
goto out2;


87
}


88


89
down(&dev->sem); //
获得信号量


90
}


91


92
/*
从用户空间拷贝到内核空间*/


93
if (count > GLOBALFIFO_SIZE - dev->current_len)


94
count = GLOBALFIFO_SIZE - dev->current_len;


95


96
if (copy_from_user(dev->mem + dev->current_len, buf, count))


97
{


98
ret = - EFAULT;


99
goto out;


100
}


101
else


102
{


103
dev->current_len += count;


104
printk(KERN_INFO "written %d bytes(s),current_len:%d\n",
count, dev


105
->current_len);


106


107
wake_up_interruptible(&dev->r_wait); //
唤醒读等待队列


108


109
ret = count;


111


112
out: up(&dev->sem); //
释放信号量


113
out2:remove_wait_queue(&dev->w_wait, &wait);
//
从附属的等待队列头移除


114
set_current_state(TASK_RUNNING);


115
return ret;


116
}


117



文章评论0条评论)

登录后参与讨论
我要评论
0
6
关闭 站长推荐上一条 /2 下一条