0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include <linux/errno.h>
0026 #include <linux/kernel.h>
0027 #include <linux/module.h>
0028 #include <linux/sched.h>
0029 #include <linux/string.h>
0030 #include <linux/uaccess.h>
0031
0032 #include <media/dvb_ringbuffer.h>
0033
0034 #define PKT_READY 0
0035 #define PKT_DISPOSED 1
0036
0037
0038 void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
0039 {
0040 rbuf->pread=rbuf->pwrite=0;
0041 rbuf->data=data;
0042 rbuf->size=len;
0043 rbuf->error=0;
0044
0045 init_waitqueue_head(&rbuf->queue);
0046
0047 spin_lock_init(&(rbuf->lock));
0048 }
0049
0050
0051
0052 int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
0053 {
0054
0055
0056
0057
0058
0059
0060 return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
0061 }
0062
0063
0064
0065 ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
0066 {
0067 ssize_t free;
0068
0069
0070
0071
0072
0073
0074 free = READ_ONCE(rbuf->pread) - rbuf->pwrite;
0075 if (free <= 0)
0076 free += rbuf->size;
0077 return free-1;
0078 }
0079
0080
0081
0082 ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
0083 {
0084 ssize_t avail;
0085
0086
0087
0088
0089
0090 avail = smp_load_acquire(&rbuf->pwrite) - rbuf->pread;
0091 if (avail < 0)
0092 avail += rbuf->size;
0093 return avail;
0094 }
0095
0096
0097
0098 void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
0099 {
0100
0101
0102
0103
0104
0105
0106 smp_store_release(&rbuf->pread, smp_load_acquire(&rbuf->pwrite));
0107 rbuf->error = 0;
0108 }
0109 EXPORT_SYMBOL(dvb_ringbuffer_flush);
0110
0111 void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
0112 {
0113
0114
0115
0116 smp_store_release(&rbuf->pread, 0);
0117
0118 smp_store_release(&rbuf->pwrite, 0);
0119 rbuf->error = 0;
0120 }
0121
0122 void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
0123 {
0124 unsigned long flags;
0125
0126 spin_lock_irqsave(&rbuf->lock, flags);
0127 dvb_ringbuffer_flush(rbuf);
0128 spin_unlock_irqrestore(&rbuf->lock, flags);
0129
0130 wake_up(&rbuf->queue);
0131 }
0132
0133 ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len)
0134 {
0135 size_t todo = len;
0136 size_t split;
0137
0138 split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
0139 if (split > 0) {
0140 if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
0141 return -EFAULT;
0142 buf += split;
0143 todo -= split;
0144
0145
0146
0147
0148 smp_store_release(&rbuf->pread, 0);
0149 }
0150 if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
0151 return -EFAULT;
0152
0153
0154 smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
0155
0156 return len;
0157 }
0158
0159 void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
0160 {
0161 size_t todo = len;
0162 size_t split;
0163
0164 split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
0165 if (split > 0) {
0166 memcpy(buf, rbuf->data+rbuf->pread, split);
0167 buf += split;
0168 todo -= split;
0169
0170
0171
0172
0173 smp_store_release(&rbuf->pread, 0);
0174 }
0175 memcpy(buf, rbuf->data+rbuf->pread, todo);
0176
0177
0178 smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size);
0179 }
0180
0181
0182 ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
0183 {
0184 size_t todo = len;
0185 size_t split;
0186
0187 split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
0188
0189 if (split > 0) {
0190 memcpy(rbuf->data+rbuf->pwrite, buf, split);
0191 buf += split;
0192 todo -= split;
0193
0194
0195
0196
0197
0198 smp_store_release(&rbuf->pwrite, 0);
0199 }
0200 memcpy(rbuf->data+rbuf->pwrite, buf, todo);
0201
0202 smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
0203
0204 return len;
0205 }
0206
0207 ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
0208 const u8 __user *buf, size_t len)
0209 {
0210 int status;
0211 size_t todo = len;
0212 size_t split;
0213
0214 split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
0215
0216 if (split > 0) {
0217 status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split);
0218 if (status)
0219 return len - todo;
0220 buf += split;
0221 todo -= split;
0222
0223
0224
0225
0226
0227 smp_store_release(&rbuf->pwrite, 0);
0228 }
0229 status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
0230 if (status)
0231 return len - todo;
0232
0233 smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size);
0234
0235 return len;
0236 }
0237
0238 ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
0239 {
0240 int status;
0241 ssize_t oldpwrite = rbuf->pwrite;
0242
0243 DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
0244 DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
0245 DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY);
0246 status = dvb_ringbuffer_write(rbuf, buf, len);
0247
0248 if (status < 0) rbuf->pwrite = oldpwrite;
0249 return status;
0250 }
0251
0252 ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
0253 int offset, u8 __user *buf, size_t len)
0254 {
0255 size_t todo;
0256 size_t split;
0257 size_t pktlen;
0258
0259 pktlen = rbuf->data[idx] << 8;
0260 pktlen |= rbuf->data[(idx + 1) % rbuf->size];
0261 if (offset > pktlen) return -EINVAL;
0262 if ((offset + len) > pktlen) len = pktlen - offset;
0263
0264 idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
0265 todo = len;
0266 split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
0267 if (split > 0) {
0268 if (copy_to_user(buf, rbuf->data+idx, split))
0269 return -EFAULT;
0270 buf += split;
0271 todo -= split;
0272 idx = 0;
0273 }
0274 if (copy_to_user(buf, rbuf->data+idx, todo))
0275 return -EFAULT;
0276
0277 return len;
0278 }
0279
0280 ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
0281 int offset, u8* buf, size_t len)
0282 {
0283 size_t todo;
0284 size_t split;
0285 size_t pktlen;
0286
0287 pktlen = rbuf->data[idx] << 8;
0288 pktlen |= rbuf->data[(idx + 1) % rbuf->size];
0289 if (offset > pktlen) return -EINVAL;
0290 if ((offset + len) > pktlen) len = pktlen - offset;
0291
0292 idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
0293 todo = len;
0294 split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
0295 if (split > 0) {
0296 memcpy(buf, rbuf->data+idx, split);
0297 buf += split;
0298 todo -= split;
0299 idx = 0;
0300 }
0301 memcpy(buf, rbuf->data+idx, todo);
0302 return len;
0303 }
0304
0305 void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
0306 {
0307 size_t pktlen;
0308
0309 rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED;
0310
0311
0312 while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
0313 if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
0314 pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
0315 pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
0316 DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
0317 } else {
0318
0319 break;
0320 }
0321 }
0322 }
0323
0324 ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
0325 {
0326 int consumed;
0327 int curpktlen;
0328 int curpktstatus;
0329
0330 if (idx == -1) {
0331 idx = rbuf->pread;
0332 } else {
0333 curpktlen = rbuf->data[idx] << 8;
0334 curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
0335 idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
0336 }
0337
0338 consumed = (idx - rbuf->pread) % rbuf->size;
0339
0340 while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
0341
0342 curpktlen = rbuf->data[idx] << 8;
0343 curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
0344 curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
0345
0346 if (curpktstatus == PKT_READY) {
0347 *pktlen = curpktlen;
0348 return idx;
0349 }
0350
0351 consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
0352 idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
0353 }
0354
0355
0356 return -1;
0357 }
0358
0359
0360
0361 EXPORT_SYMBOL(dvb_ringbuffer_init);
0362 EXPORT_SYMBOL(dvb_ringbuffer_empty);
0363 EXPORT_SYMBOL(dvb_ringbuffer_free);
0364 EXPORT_SYMBOL(dvb_ringbuffer_avail);
0365 EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
0366 EXPORT_SYMBOL(dvb_ringbuffer_read_user);
0367 EXPORT_SYMBOL(dvb_ringbuffer_read);
0368 EXPORT_SYMBOL(dvb_ringbuffer_write);
0369 EXPORT_SYMBOL(dvb_ringbuffer_write_user);