Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
15112 views
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);
300
301