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