/*======================================================================
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
}
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条评论)
登录后参与讨论