Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
•
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
media
dvb-core
dvb_ringbuffer.c
Go to the documentation of this file.
1
/*
2
*
3
* dvb_ringbuffer.c: ring buffer implementation for the dvb driver
4
*
5
* Copyright (C) 2003 Oliver Endriss
6
* Copyright (C) 2004 Andrew de Quincey
7
*
8
* based on code originally found in av7110.c & dvb_ci.c:
9
* Copyright (C) 1999-2003 Ralph Metzler
10
* & Marcus Metzler for convergence integrated media GmbH
11
*
12
* This program is free software; you can redistribute it and/or
13
* modify it under the terms of the GNU Lesser General Public License
14
* as published by the Free Software Foundation; either version 2.1
15
* of the License, or (at your option) any later version.
16
*
17
* This program is distributed in the hope that it will be useful,
18
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
* GNU Lesser General Public License for more details.
21
*
22
* You should have received a copy of the GNU Lesser General Public License
23
* along with this program; if not, write to the Free Software
24
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
*/
26
27
28
29
#include <linux/errno.h>
30
#include <linux/kernel.h>
31
#include <linux/module.h>
32
#include <linux/sched.h>
33
#include <linux/string.h>
34
#include <asm/uaccess.h>
35
36
#include "
dvb_ringbuffer.h
"
37
38
#define PKT_READY 0
39
#define PKT_DISPOSED 1
40
41
42
void
dvb_ringbuffer_init
(
struct
dvb_ringbuffer
*rbuf,
void
*
data
,
size_t
len)
43
{
44
rbuf->
pread
=rbuf->
pwrite
=0;
45
rbuf->
data
=
data
;
46
rbuf->
size
=len;
47
rbuf->
error
=0;
48
49
init_waitqueue_head
(&rbuf->
queue
);
50
51
spin_lock_init
(&(rbuf->
lock
));
52
}
53
54
55
56
int
dvb_ringbuffer_empty
(
struct
dvb_ringbuffer
*rbuf)
57
{
58
return
(rbuf->
pread
==rbuf->
pwrite
);
59
}
60
61
62
63
ssize_t
dvb_ringbuffer_free
(
struct
dvb_ringbuffer
*rbuf)
64
{
65
ssize_t
free
;
66
67
free = rbuf->
pread
- rbuf->
pwrite
;
68
if
(free <= 0)
69
free += rbuf->
size
;
70
return
free-1;
71
}
72
73
74
75
ssize_t
dvb_ringbuffer_avail
(
struct
dvb_ringbuffer
*rbuf)
76
{
77
ssize_t
avail
;
78
79
avail = rbuf->
pwrite
- rbuf->
pread
;
80
if
(avail < 0)
81
avail += rbuf->
size
;
82
return
avail
;
83
}
84
85
86
87
void
dvb_ringbuffer_flush
(
struct
dvb_ringbuffer
*rbuf)
88
{
89
rbuf->
pread
= rbuf->
pwrite
;
90
rbuf->
error
= 0;
91
}
92
EXPORT_SYMBOL
(
dvb_ringbuffer_flush
);
93
94
void
dvb_ringbuffer_reset
(
struct
dvb_ringbuffer
*rbuf)
95
{
96
rbuf->
pread
= rbuf->
pwrite
= 0;
97
rbuf->
error
= 0;
98
}
99
100
void
dvb_ringbuffer_flush_spinlock_wakeup
(
struct
dvb_ringbuffer
*rbuf)
101
{
102
unsigned
long
flags
;
103
104
spin_lock_irqsave
(&rbuf->
lock
, flags);
105
dvb_ringbuffer_flush
(rbuf);
106
spin_unlock_irqrestore(&rbuf->
lock
, flags);
107
108
wake_up
(&rbuf->
queue
);
109
}
110
111
ssize_t
dvb_ringbuffer_read_user
(
struct
dvb_ringbuffer
*rbuf,
u8
__user *
buf
,
size_t
len)
112
{
113
size_t
todo
= len;
114
size_t
split
;
115
116
split = (rbuf->
pread
+ len > rbuf->
size
) ? rbuf->
size
- rbuf->
pread
: 0;
117
if
(split > 0) {
118
if
(
copy_to_user
(buf, rbuf->
data
+rbuf->
pread
, split))
119
return
-
EFAULT
;
120
buf +=
split
;
121
todo -=
split
;
122
rbuf->
pread
= 0;
123
}
124
if
(
copy_to_user
(buf, rbuf->
data
+rbuf->
pread
, todo))
125
return
-
EFAULT
;
126
127
rbuf->
pread
= (rbuf->
pread
+
todo
) % rbuf->
size
;
128
129
return
len;
130
}
131
132
void
dvb_ringbuffer_read
(
struct
dvb_ringbuffer
*rbuf,
u8
*
buf
,
size_t
len)
133
{
134
size_t
todo
= len;
135
size_t
split
;
136
137
split = (rbuf->
pread
+ len > rbuf->
size
) ? rbuf->
size
- rbuf->
pread
: 0;
138
if
(split > 0) {
139
memcpy
(buf, rbuf->
data
+rbuf->
pread
, split);
140
buf +=
split
;
141
todo -=
split
;
142
rbuf->
pread
= 0;
143
}
144
memcpy
(buf, rbuf->
data
+rbuf->
pread
, todo);
145
146
rbuf->
pread
= (rbuf->
pread
+
todo
) % rbuf->
size
;
147
}
148
149
150
ssize_t
dvb_ringbuffer_write
(
struct
dvb_ringbuffer
*rbuf,
const
u8
*
buf
,
size_t
len)
151
{
152
size_t
todo
= len;
153
size_t
split
;
154
155
split = (rbuf->
pwrite
+ len > rbuf->
size
) ? rbuf->
size
- rbuf->
pwrite
: 0;
156
157
if
(split > 0) {
158
memcpy
(rbuf->
data
+rbuf->
pwrite
, buf, split);
159
buf +=
split
;
160
todo -=
split
;
161
rbuf->
pwrite
= 0;
162
}
163
memcpy
(rbuf->
data
+rbuf->
pwrite
, buf, todo);
164
rbuf->
pwrite
= (rbuf->
pwrite
+
todo
) % rbuf->
size
;
165
166
return
len;
167
}
168
169
ssize_t
dvb_ringbuffer_pkt_write
(
struct
dvb_ringbuffer
*rbuf,
u8
*
buf
,
size_t
len)
170
{
171
int
status
;
172
ssize_t
oldpwrite = rbuf->
pwrite
;
173
174
DVB_RINGBUFFER_WRITE_BYTE
(rbuf, len >> 8);
175
DVB_RINGBUFFER_WRITE_BYTE
(rbuf, len & 0xff);
176
DVB_RINGBUFFER_WRITE_BYTE
(rbuf,
PKT_READY
);
177
status =
dvb_ringbuffer_write
(rbuf, buf, len);
178
179
if
(status < 0) rbuf->
pwrite
= oldpwrite;
180
return
status
;
181
}
182
183
ssize_t
dvb_ringbuffer_pkt_read_user
(
struct
dvb_ringbuffer
*rbuf,
size_t
idx
,
184
int
offset
,
u8
__user *
buf
,
size_t
len)
185
{
186
size_t
todo
;
187
size_t
split
;
188
size_t
pktlen
;
189
190
pktlen = rbuf->
data
[
idx
] << 8;
191
pktlen |= rbuf->
data
[(idx + 1) % rbuf->
size
];
192
if
(offset > pktlen)
return
-
EINVAL
;
193
if
((offset + len) >
pktlen
) len = pktlen - offset;
194
195
idx = (idx +
DVB_RINGBUFFER_PKTHDRSIZE
+
offset
) % rbuf->
size
;
196
todo = len;
197
split = ((idx + len) > rbuf->
size
) ? rbuf->
size
- idx : 0;
198
if
(split > 0) {
199
if
(
copy_to_user
(buf, rbuf->
data
+idx, split))
200
return
-
EFAULT
;
201
buf +=
split
;
202
todo -=
split
;
203
idx = 0;
204
}
205
if
(
copy_to_user
(buf, rbuf->
data
+idx, todo))
206
return
-
EFAULT
;
207
208
return
len;
209
}
210
211
ssize_t
dvb_ringbuffer_pkt_read
(
struct
dvb_ringbuffer
*rbuf,
size_t
idx
,
212
int
offset
,
u8
*
buf
,
size_t
len)
213
{
214
size_t
todo
;
215
size_t
split
;
216
size_t
pktlen
;
217
218
pktlen = rbuf->
data
[
idx
] << 8;
219
pktlen |= rbuf->
data
[(idx + 1) % rbuf->
size
];
220
if
(offset > pktlen)
return
-
EINVAL
;
221
if
((offset + len) >
pktlen
) len = pktlen - offset;
222
223
idx = (idx +
DVB_RINGBUFFER_PKTHDRSIZE
+
offset
) % rbuf->
size
;
224
todo = len;
225
split = ((idx + len) > rbuf->
size
) ? rbuf->
size
- idx : 0;
226
if
(split > 0) {
227
memcpy
(buf, rbuf->
data
+idx, split);
228
buf +=
split
;
229
todo -=
split
;
230
idx = 0;
231
}
232
memcpy
(buf, rbuf->
data
+idx, todo);
233
return
len;
234
}
235
236
void
dvb_ringbuffer_pkt_dispose
(
struct
dvb_ringbuffer
*rbuf,
size_t
idx
)
237
{
238
size_t
pktlen
;
239
240
rbuf->
data
[(idx + 2) % rbuf->
size
] =
PKT_DISPOSED
;
241
242
// clean up disposed packets
243
while
(
dvb_ringbuffer_avail
(rbuf) >
DVB_RINGBUFFER_PKTHDRSIZE
) {
244
if
(
DVB_RINGBUFFER_PEEK
(rbuf, 2) ==
PKT_DISPOSED
) {
245
pktlen =
DVB_RINGBUFFER_PEEK
(rbuf, 0) << 8;
246
pktlen |=
DVB_RINGBUFFER_PEEK
(rbuf, 1);
247
DVB_RINGBUFFER_SKIP
(rbuf, pktlen +
DVB_RINGBUFFER_PKTHDRSIZE
);
248
}
else
{
249
// first packet is not disposed, so we stop cleaning now
250
break
;
251
}
252
}
253
}
254
255
ssize_t
dvb_ringbuffer_pkt_next
(
struct
dvb_ringbuffer
*rbuf,
size_t
idx
,
size_t
*
pktlen
)
256
{
257
int
consumed;
258
int
curpktlen;
259
int
curpktstatus;
260
261
if
(idx == -1) {
262
idx = rbuf->
pread
;
263
}
else
{
264
curpktlen = rbuf->
data
[
idx
] << 8;
265
curpktlen |= rbuf->
data
[(idx + 1) % rbuf->
size
];
266
idx = (idx + curpktlen +
DVB_RINGBUFFER_PKTHDRSIZE
) % rbuf->
size
;
267
}
268
269
consumed = (idx - rbuf->
pread
) % rbuf->
size
;
270
271
while
((
dvb_ringbuffer_avail
(rbuf) - consumed) >
DVB_RINGBUFFER_PKTHDRSIZE
) {
272
273
curpktlen = rbuf->
data
[
idx
] << 8;
274
curpktlen |= rbuf->
data
[(idx + 1) % rbuf->
size
];
275
curpktstatus = rbuf->
data
[(idx + 2) % rbuf->
size
];
276
277
if
(curpktstatus ==
PKT_READY
) {
278
*pktlen = curpktlen;
279
return
idx
;
280
}
281
282
consumed += curpktlen +
DVB_RINGBUFFER_PKTHDRSIZE
;
283
idx = (idx + curpktlen +
DVB_RINGBUFFER_PKTHDRSIZE
) % rbuf->
size
;
284
}
285
286
// no packets available
287
return
-1;
288
}
289
290
291
292
EXPORT_SYMBOL
(
dvb_ringbuffer_init
);
293
EXPORT_SYMBOL
(
dvb_ringbuffer_empty
);
294
EXPORT_SYMBOL
(
dvb_ringbuffer_free
);
295
EXPORT_SYMBOL
(
dvb_ringbuffer_avail
);
296
EXPORT_SYMBOL
(
dvb_ringbuffer_flush_spinlock_wakeup
);
297
EXPORT_SYMBOL
(
dvb_ringbuffer_read_user
);
298
EXPORT_SYMBOL
(
dvb_ringbuffer_read
);
299
EXPORT_SYMBOL
(
dvb_ringbuffer_write
);
Generated on Thu Jan 10 2013 13:44:57 for Linux Kernel by
1.8.2