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 23 24 25 #include <linux/errno.h> 26 #include <linux/kernel.h> 27 #include <linux/module.h> 28 #include <linux/sched.h> 29 #include <linux/string.h> 30 #include <linux/uaccess.h> 31 32 #include <media/dvb_ringbuffer.h> 33 34 #define PKT_READY 0 35 #define PKT_DISPOSED 1 36 37 38 void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len) 39 { 40 rbuf->pread = 0; 41 rbuf->pwrite = 0; 42 rbuf->data = data; 43 rbuf->size = len; 44 rbuf->error = 0; 45 46 init_waitqueue_head(&rbuf->queue); 47 48 spin_lock_init(&(rbuf->lock)); 49 } 50 51 52 53 int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf) 54 { 55 /* smp_load_acquire() to load write pointer on reader side 56 * this pairs with smp_store_release() in dvb_ringbuffer_write(), 57 * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset() 58 * 59 * for memory barriers also see Documentation/core-api/circular-buffers.rst 60 */ 61 return (rbuf->pread == smp_load_acquire(&rbuf->pwrite)); 62 } 63 64 65 66 ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf) 67 { 68 ssize_t free; 69 70 /* READ_ONCE() to load read pointer on writer side 71 * this pairs with smp_store_release() in dvb_ringbuffer_read(), 72 * dvb_ringbuffer_read_user(), dvb_ringbuffer_flush(), 73 * or dvb_ringbuffer_reset() 74 */ 75 free = READ_ONCE(rbuf->pread) - rbuf->pwrite; 76 if (free <= 0) 77 free += rbuf->size; 78 return free-1; 79 } 80 81 82 83 ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf) 84 { 85 ssize_t avail; 86 87 /* smp_load_acquire() to load write pointer on reader side 88 * this pairs with smp_store_release() in dvb_ringbuffer_write(), 89 * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset() 90 */ 91 avail = smp_load_acquire(&rbuf->pwrite) - rbuf->pread; 92 if (avail < 0) 93 avail += rbuf->size; 94 return avail; 95 } 96 97 98 99 void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf) 100 { 101 /* dvb_ringbuffer_flush() counts as read operation 102 * smp_load_acquire() to load write pointer 103 * smp_store_release() to update read pointer, this ensures that the 104 * correct pointer is visible for subsequent dvb_ringbuffer_free() 105 * calls on other cpu cores 106 */ 107 smp_store_release(&rbuf->pread, smp_load_acquire(&rbuf->pwrite)); 108 rbuf->error = 0; 109 } 110 EXPORT_SYMBOL(dvb_ringbuffer_flush); 111 112 void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf) 113 { 114 /* dvb_ringbuffer_reset() counts as read and write operation 115 * smp_store_release() to update read pointer 116 */ 117 smp_store_release(&rbuf->pread, 0); 118 /* smp_store_release() to update write pointer */ 119 smp_store_release(&rbuf->pwrite, 0); 120 rbuf->error = 0; 121 } 122 123 void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf) 124 { 125 unsigned long flags; 126 127 spin_lock_irqsave(&rbuf->lock, flags); 128 dvb_ringbuffer_flush(rbuf); 129 spin_unlock_irqrestore(&rbuf->lock, flags); 130 131 wake_up(&rbuf->queue); 132 } 133 134 ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len) 135 { 136 size_t todo = len; 137 size_t split; 138 139 split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; 140 if (split > 0) { 141 if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) 142 return -EFAULT; 143 buf += split; 144 todo -= split; 145 /* smp_store_release() for read pointer update to ensure 146 * that buf is not overwritten until read is complete, 147 * this pairs with READ_ONCE() in dvb_ringbuffer_free() 148 */ 149 smp_store_release(&rbuf->pread, 0); 150 } 151 if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) 152 return -EFAULT; 153 154 /* smp_store_release() to update read pointer, see above */ 155 smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size); 156 157 return len; 158 } 159 160 void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len) 161 { 162 size_t todo = len; 163 size_t split; 164 165 split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; 166 if (split > 0) { 167 memcpy(buf, rbuf->data+rbuf->pread, split); 168 buf += split; 169 todo -= split; 170 /* smp_store_release() for read pointer update to ensure 171 * that buf is not overwritten until read is complete, 172 * this pairs with READ_ONCE() in dvb_ringbuffer_free() 173 */ 174 smp_store_release(&rbuf->pread, 0); 175 } 176 memcpy(buf, rbuf->data+rbuf->pread, todo); 177 178 /* smp_store_release() to update read pointer, see above */ 179 smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size); 180 } 181 182 183 ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len) 184 { 185 size_t todo = len; 186 size_t split; 187 188 split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; 189 190 if (split > 0) { 191 memcpy(rbuf->data+rbuf->pwrite, buf, split); 192 buf += split; 193 todo -= split; 194 /* smp_store_release() for write pointer update to ensure that 195 * written data is visible on other cpu cores before the pointer 196 * update, this pairs with smp_load_acquire() in 197 * dvb_ringbuffer_empty() or dvb_ringbuffer_avail() 198 */ 199 smp_store_release(&rbuf->pwrite, 0); 200 } 201 memcpy(rbuf->data+rbuf->pwrite, buf, todo); 202 /* smp_store_release() for write pointer update, see above */ 203 smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size); 204 205 return len; 206 } 207 208 ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, 209 const u8 __user *buf, size_t len) 210 { 211 int status; 212 size_t todo = len; 213 size_t split; 214 215 split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; 216 217 if (split > 0) { 218 status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split); 219 if (status) 220 return len - todo; 221 buf += split; 222 todo -= split; 223 /* smp_store_release() for write pointer update to ensure that 224 * written data is visible on other cpu cores before the pointer 225 * update, this pairs with smp_load_acquire() in 226 * dvb_ringbuffer_empty() or dvb_ringbuffer_avail() 227 */ 228 smp_store_release(&rbuf->pwrite, 0); 229 } 230 status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo); 231 if (status) 232 return len - todo; 233 /* smp_store_release() for write pointer update, see above */ 234 smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size); 235 236 return len; 237 } 238 239 ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len) 240 { 241 int status; 242 ssize_t oldpwrite = rbuf->pwrite; 243 244 DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8); 245 DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff); 246 DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY); 247 status = dvb_ringbuffer_write(rbuf, buf, len); 248 249 if (status < 0) 250 rbuf->pwrite = oldpwrite; 251 return status; 252 } 253 254 ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, 255 int offset, u8 __user *buf, size_t len) 256 { 257 size_t todo; 258 size_t split; 259 size_t pktlen; 260 261 pktlen = rbuf->data[idx] << 8; 262 pktlen |= rbuf->data[(idx + 1) % rbuf->size]; 263 if (offset > pktlen) 264 return -EINVAL; 265 if ((offset + len) > pktlen) 266 len = pktlen - offset; 267 268 idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size; 269 todo = len; 270 split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; 271 if (split > 0) { 272 if (copy_to_user(buf, rbuf->data+idx, split)) 273 return -EFAULT; 274 buf += split; 275 todo -= split; 276 idx = 0; 277 } 278 if (copy_to_user(buf, rbuf->data+idx, todo)) 279 return -EFAULT; 280 281 return len; 282 } 283 284 ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, 285 int offset, u8 *buf, size_t len) 286 { 287 size_t todo; 288 size_t split; 289 size_t pktlen; 290 291 pktlen = rbuf->data[idx] << 8; 292 pktlen |= rbuf->data[(idx + 1) % rbuf->size]; 293 if (offset > pktlen) 294 return -EINVAL; 295 if ((offset + len) > pktlen) 296 len = pktlen - offset; 297 298 idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size; 299 todo = len; 300 split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; 301 if (split > 0) { 302 memcpy(buf, rbuf->data+idx, split); 303 buf += split; 304 todo -= split; 305 idx = 0; 306 } 307 memcpy(buf, rbuf->data+idx, todo); 308 return len; 309 } 310 311 void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) 312 { 313 size_t pktlen; 314 315 rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED; 316 317 // clean up disposed packets 318 while (dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) { 319 if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) { 320 pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8; 321 pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1); 322 DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE); 323 } else { 324 // first packet is not disposed, so we stop cleaning now 325 break; 326 } 327 } 328 } 329 330 ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t *pktlen) 331 { 332 int consumed; 333 int curpktlen; 334 int curpktstatus; 335 336 if (idx == -1) { 337 idx = rbuf->pread; 338 } else { 339 curpktlen = rbuf->data[idx] << 8; 340 curpktlen |= rbuf->data[(idx + 1) % rbuf->size]; 341 idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; 342 } 343 344 consumed = (idx - rbuf->pread); 345 if (consumed < 0) 346 consumed += rbuf->size; 347 348 while ((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) { 349 350 curpktlen = rbuf->data[idx] << 8; 351 curpktlen |= rbuf->data[(idx + 1) % rbuf->size]; 352 curpktstatus = rbuf->data[(idx + 2) % rbuf->size]; 353 354 if (curpktstatus == PKT_READY) { 355 *pktlen = curpktlen; 356 return idx; 357 } 358 359 consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE; 360 idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; 361 } 362 363 // no packets available 364 return -1; 365 } 366 367 368 369 EXPORT_SYMBOL(dvb_ringbuffer_init); 370 EXPORT_SYMBOL(dvb_ringbuffer_empty); 371 EXPORT_SYMBOL(dvb_ringbuffer_free); 372 EXPORT_SYMBOL(dvb_ringbuffer_avail); 373 EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); 374 EXPORT_SYMBOL(dvb_ringbuffer_read_user); 375 EXPORT_SYMBOL(dvb_ringbuffer_read); 376 EXPORT_SYMBOL(dvb_ringbuffer_write); 377 EXPORT_SYMBOL(dvb_ringbuffer_write_user); 378