root/drivers/media/usb/pvrusb2/pvrusb2-ioread.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pvr2_ioread_init
  2. pvr2_ioread_done
  3. pvr2_ioread_create
  4. pvr2_ioread_destroy
  5. pvr2_ioread_set_sync_key
  6. pvr2_ioread_stop
  7. pvr2_ioread_start
  8. pvr2_ioread_get_stream
  9. pvr2_ioread_setup
  10. pvr2_ioread_set_enabled
  11. pvr2_ioread_get_buffer
  12. pvr2_ioread_filter
  13. pvr2_ioread_avail
  14. pvr2_ioread_read

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *
   4  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
   5  */
   6 
   7 #include "pvrusb2-ioread.h"
   8 #include "pvrusb2-debug.h"
   9 #include <linux/errno.h>
  10 #include <linux/string.h>
  11 #include <linux/mm.h>
  12 #include <linux/slab.h>
  13 #include <linux/mutex.h>
  14 #include <linux/uaccess.h>
  15 
  16 #define BUFFER_COUNT 32
  17 #define BUFFER_SIZE PAGE_ALIGN(0x4000)
  18 
  19 struct pvr2_ioread {
  20         struct pvr2_stream *stream;
  21         char *buffer_storage[BUFFER_COUNT];
  22         char *sync_key_ptr;
  23         unsigned int sync_key_len;
  24         unsigned int sync_buf_offs;
  25         unsigned int sync_state;
  26         unsigned int sync_trashed_count;
  27         int enabled;         // Streaming is on
  28         int spigot_open;     // OK to pass data to client
  29         int stream_running;  // Passing data to client now
  30 
  31         /* State relevant to current buffer being read */
  32         struct pvr2_buffer *c_buf;
  33         char *c_data_ptr;
  34         unsigned int c_data_len;
  35         unsigned int c_data_offs;
  36         struct mutex mutex;
  37 };
  38 
  39 static int pvr2_ioread_init(struct pvr2_ioread *cp)
  40 {
  41         unsigned int idx;
  42 
  43         cp->stream = NULL;
  44         mutex_init(&cp->mutex);
  45 
  46         for (idx = 0; idx < BUFFER_COUNT; idx++) {
  47                 cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL);
  48                 if (!(cp->buffer_storage[idx])) break;
  49         }
  50 
  51         if (idx < BUFFER_COUNT) {
  52                 // An allocation appears to have failed
  53                 for (idx = 0; idx < BUFFER_COUNT; idx++) {
  54                         if (!(cp->buffer_storage[idx])) continue;
  55                         kfree(cp->buffer_storage[idx]);
  56                 }
  57                 return -ENOMEM;
  58         }
  59         return 0;
  60 }
  61 
  62 static void pvr2_ioread_done(struct pvr2_ioread *cp)
  63 {
  64         unsigned int idx;
  65 
  66         pvr2_ioread_setup(cp,NULL);
  67         for (idx = 0; idx < BUFFER_COUNT; idx++) {
  68                 if (!(cp->buffer_storage[idx])) continue;
  69                 kfree(cp->buffer_storage[idx]);
  70         }
  71 }
  72 
  73 struct pvr2_ioread *pvr2_ioread_create(void)
  74 {
  75         struct pvr2_ioread *cp;
  76         cp = kzalloc(sizeof(*cp),GFP_KERNEL);
  77         if (!cp) return NULL;
  78         pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
  79         if (pvr2_ioread_init(cp) < 0) {
  80                 kfree(cp);
  81                 return NULL;
  82         }
  83         return cp;
  84 }
  85 
  86 void pvr2_ioread_destroy(struct pvr2_ioread *cp)
  87 {
  88         if (!cp) return;
  89         pvr2_ioread_done(cp);
  90         pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp);
  91         if (cp->sync_key_ptr) {
  92                 kfree(cp->sync_key_ptr);
  93                 cp->sync_key_ptr = NULL;
  94         }
  95         kfree(cp);
  96 }
  97 
  98 void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp,
  99                               const char *sync_key_ptr,
 100                               unsigned int sync_key_len)
 101 {
 102         if (!cp) return;
 103 
 104         if (!sync_key_ptr) sync_key_len = 0;
 105         if ((sync_key_len == cp->sync_key_len) &&
 106             ((!sync_key_len) ||
 107              (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return;
 108 
 109         if (sync_key_len != cp->sync_key_len) {
 110                 if (cp->sync_key_ptr) {
 111                         kfree(cp->sync_key_ptr);
 112                         cp->sync_key_ptr = NULL;
 113                 }
 114                 cp->sync_key_len = 0;
 115                 if (sync_key_len) {
 116                         cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL);
 117                         if (cp->sync_key_ptr) {
 118                                 cp->sync_key_len = sync_key_len;
 119                         }
 120                 }
 121         }
 122         if (!cp->sync_key_len) return;
 123         memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len);
 124 }
 125 
 126 static void pvr2_ioread_stop(struct pvr2_ioread *cp)
 127 {
 128         if (!(cp->enabled)) return;
 129         pvr2_trace(PVR2_TRACE_START_STOP,
 130                    "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp);
 131         pvr2_stream_kill(cp->stream);
 132         cp->c_buf = NULL;
 133         cp->c_data_ptr = NULL;
 134         cp->c_data_len = 0;
 135         cp->c_data_offs = 0;
 136         cp->enabled = 0;
 137         cp->stream_running = 0;
 138         cp->spigot_open = 0;
 139         if (cp->sync_state) {
 140                 pvr2_trace(PVR2_TRACE_DATA_FLOW,
 141                            "/*---TRACE_READ---*/ sync_state <== 0");
 142                 cp->sync_state = 0;
 143         }
 144 }
 145 
 146 static int pvr2_ioread_start(struct pvr2_ioread *cp)
 147 {
 148         int stat;
 149         struct pvr2_buffer *bp;
 150         if (cp->enabled) return 0;
 151         if (!(cp->stream)) return 0;
 152         pvr2_trace(PVR2_TRACE_START_STOP,
 153                    "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp);
 154         while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) {
 155                 stat = pvr2_buffer_queue(bp);
 156                 if (stat < 0) {
 157                         pvr2_trace(PVR2_TRACE_DATA_FLOW,
 158                                    "/*---TRACE_READ---*/ pvr2_ioread_start id=%p error=%d",
 159                                    cp,stat);
 160                         pvr2_ioread_stop(cp);
 161                         return stat;
 162                 }
 163         }
 164         cp->enabled = !0;
 165         cp->c_buf = NULL;
 166         cp->c_data_ptr = NULL;
 167         cp->c_data_len = 0;
 168         cp->c_data_offs = 0;
 169         cp->stream_running = 0;
 170         if (cp->sync_key_len) {
 171                 pvr2_trace(PVR2_TRACE_DATA_FLOW,
 172                            "/*---TRACE_READ---*/ sync_state <== 1");
 173                 cp->sync_state = 1;
 174                 cp->sync_trashed_count = 0;
 175                 cp->sync_buf_offs = 0;
 176         }
 177         cp->spigot_open = 0;
 178         return 0;
 179 }
 180 
 181 struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp)
 182 {
 183         return cp->stream;
 184 }
 185 
 186 int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
 187 {
 188         int ret;
 189         unsigned int idx;
 190         struct pvr2_buffer *bp;
 191 
 192         mutex_lock(&cp->mutex);
 193         do {
 194                 if (cp->stream) {
 195                         pvr2_trace(PVR2_TRACE_START_STOP,
 196                                    "/*---TRACE_READ---*/ pvr2_ioread_setup (tear-down) id=%p",
 197                                    cp);
 198                         pvr2_ioread_stop(cp);
 199                         pvr2_stream_kill(cp->stream);
 200                         if (pvr2_stream_get_buffer_count(cp->stream)) {
 201                                 pvr2_stream_set_buffer_count(cp->stream,0);
 202                         }
 203                         cp->stream = NULL;
 204                 }
 205                 if (sp) {
 206                         pvr2_trace(PVR2_TRACE_START_STOP,
 207                                    "/*---TRACE_READ---*/ pvr2_ioread_setup (setup) id=%p",
 208                                    cp);
 209                         pvr2_stream_kill(sp);
 210                         ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
 211                         if (ret < 0) {
 212                                 mutex_unlock(&cp->mutex);
 213                                 return ret;
 214                         }
 215                         for (idx = 0; idx < BUFFER_COUNT; idx++) {
 216                                 bp = pvr2_stream_get_buffer(sp,idx);
 217                                 pvr2_buffer_set_buffer(bp,
 218                                                        cp->buffer_storage[idx],
 219                                                        BUFFER_SIZE);
 220                         }
 221                         cp->stream = sp;
 222                 }
 223         } while (0);
 224         mutex_unlock(&cp->mutex);
 225 
 226         return 0;
 227 }
 228 
 229 int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl)
 230 {
 231         int ret = 0;
 232         if ((!fl) == (!(cp->enabled))) return ret;
 233 
 234         mutex_lock(&cp->mutex);
 235         do {
 236                 if (fl) {
 237                         ret = pvr2_ioread_start(cp);
 238                 } else {
 239                         pvr2_ioread_stop(cp);
 240                 }
 241         } while (0);
 242         mutex_unlock(&cp->mutex);
 243         return ret;
 244 }
 245 
 246 static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp)
 247 {
 248         int stat;
 249 
 250         while (cp->c_data_len <= cp->c_data_offs) {
 251                 if (cp->c_buf) {
 252                         // Flush out current buffer first.
 253                         stat = pvr2_buffer_queue(cp->c_buf);
 254                         if (stat < 0) {
 255                                 // Streaming error...
 256                                 pvr2_trace(PVR2_TRACE_DATA_FLOW,
 257                                            "/*---TRACE_READ---*/ pvr2_ioread_read id=%p queue_error=%d",
 258                                            cp,stat);
 259                                 pvr2_ioread_stop(cp);
 260                                 return 0;
 261                         }
 262                         cp->c_buf = NULL;
 263                         cp->c_data_ptr = NULL;
 264                         cp->c_data_len = 0;
 265                         cp->c_data_offs = 0;
 266                 }
 267                 // Now get a freshly filled buffer.
 268                 cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream);
 269                 if (!cp->c_buf) break; // Nothing ready; done.
 270                 cp->c_data_len = pvr2_buffer_get_count(cp->c_buf);
 271                 if (!cp->c_data_len) {
 272                         // Nothing transferred.  Was there an error?
 273                         stat = pvr2_buffer_get_status(cp->c_buf);
 274                         if (stat < 0) {
 275                                 // Streaming error...
 276                                 pvr2_trace(PVR2_TRACE_DATA_FLOW,
 277                                            "/*---TRACE_READ---*/ pvr2_ioread_read id=%p buffer_error=%d",
 278                                            cp,stat);
 279                                 pvr2_ioread_stop(cp);
 280                                 // Give up.
 281                                 return 0;
 282                         }
 283                         // Start over...
 284                         continue;
 285                 }
 286                 cp->c_data_offs = 0;
 287                 cp->c_data_ptr = cp->buffer_storage[
 288                         pvr2_buffer_get_id(cp->c_buf)];
 289         }
 290         return !0;
 291 }
 292 
 293 static void pvr2_ioread_filter(struct pvr2_ioread *cp)
 294 {
 295         unsigned int idx;
 296         if (!cp->enabled) return;
 297         if (cp->sync_state != 1) return;
 298 
 299         // Search the stream for our synchronization key.  This is made
 300         // complicated by the fact that in order to be honest with
 301         // ourselves here we must search across buffer boundaries...
 302         mutex_lock(&cp->mutex);
 303         while (1) {
 304                 // Ensure we have a buffer
 305                 if (!pvr2_ioread_get_buffer(cp)) break;
 306                 if (!cp->c_data_len) break;
 307 
 308                 // Now walk the buffer contents until we match the key or
 309                 // run out of buffer data.
 310                 for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) {
 311                         if (cp->sync_buf_offs >= cp->sync_key_len) break;
 312                         if (cp->c_data_ptr[idx] ==
 313                             cp->sync_key_ptr[cp->sync_buf_offs]) {
 314                                 // Found the next key byte
 315                                 (cp->sync_buf_offs)++;
 316                         } else {
 317                                 // Whoops, mismatched.  Start key over...
 318                                 cp->sync_buf_offs = 0;
 319                         }
 320                 }
 321 
 322                 // Consume what we've walked through
 323                 cp->c_data_offs += idx;
 324                 cp->sync_trashed_count += idx;
 325 
 326                 // If we've found the key, then update state and get out.
 327                 if (cp->sync_buf_offs >= cp->sync_key_len) {
 328                         cp->sync_trashed_count -= cp->sync_key_len;
 329                         pvr2_trace(PVR2_TRACE_DATA_FLOW,
 330                                    "/*---TRACE_READ---*/ sync_state <== 2 (skipped %u bytes)",
 331                                    cp->sync_trashed_count);
 332                         cp->sync_state = 2;
 333                         cp->sync_buf_offs = 0;
 334                         break;
 335                 }
 336 
 337                 if (cp->c_data_offs < cp->c_data_len) {
 338                         // Sanity check - should NEVER get here
 339                         pvr2_trace(PVR2_TRACE_ERROR_LEGS,
 340                                    "ERROR: pvr2_ioread filter sync problem len=%u offs=%u",
 341                                    cp->c_data_len,cp->c_data_offs);
 342                         // Get out so we don't get stuck in an infinite
 343                         // loop.
 344                         break;
 345                 }
 346 
 347                 continue; // (for clarity)
 348         }
 349         mutex_unlock(&cp->mutex);
 350 }
 351 
 352 int pvr2_ioread_avail(struct pvr2_ioread *cp)
 353 {
 354         int ret;
 355         if (!(cp->enabled)) {
 356                 // Stream is not enabled; so this is an I/O error
 357                 return -EIO;
 358         }
 359 
 360         if (cp->sync_state == 1) {
 361                 pvr2_ioread_filter(cp);
 362                 if (cp->sync_state == 1) return -EAGAIN;
 363         }
 364 
 365         ret = 0;
 366         if (cp->stream_running) {
 367                 if (!pvr2_stream_get_ready_count(cp->stream)) {
 368                         // No data available at all right now.
 369                         ret = -EAGAIN;
 370                 }
 371         } else {
 372                 if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) {
 373                         // Haven't buffered up enough yet; try again later
 374                         ret = -EAGAIN;
 375                 }
 376         }
 377 
 378         if ((!(cp->spigot_open)) != (!(ret == 0))) {
 379                 cp->spigot_open = (ret == 0);
 380                 pvr2_trace(PVR2_TRACE_DATA_FLOW,
 381                            "/*---TRACE_READ---*/ data is %s",
 382                            cp->spigot_open ? "available" : "pending");
 383         }
 384 
 385         return ret;
 386 }
 387 
 388 int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt)
 389 {
 390         unsigned int copied_cnt;
 391         unsigned int bcnt;
 392         const char *src;
 393         int stat;
 394         int ret = 0;
 395         unsigned int req_cnt = cnt;
 396 
 397         if (!cnt) {
 398                 pvr2_trace(PVR2_TRACE_TRAP,
 399                            "/*---TRACE_READ---*/ pvr2_ioread_read id=%p ZERO Request? Returning zero.",
 400 cp);
 401                 return 0;
 402         }
 403 
 404         stat = pvr2_ioread_avail(cp);
 405         if (stat < 0) return stat;
 406 
 407         cp->stream_running = !0;
 408 
 409         mutex_lock(&cp->mutex);
 410         do {
 411 
 412                 // Suck data out of the buffers and copy to the user
 413                 copied_cnt = 0;
 414                 if (!buf) cnt = 0;
 415                 while (1) {
 416                         if (!pvr2_ioread_get_buffer(cp)) {
 417                                 ret = -EIO;
 418                                 break;
 419                         }
 420 
 421                         if (!cnt) break;
 422 
 423                         if (cp->sync_state == 2) {
 424                                 // We're repeating the sync key data into
 425                                 // the stream.
 426                                 src = cp->sync_key_ptr + cp->sync_buf_offs;
 427                                 bcnt = cp->sync_key_len - cp->sync_buf_offs;
 428                         } else {
 429                                 // Normal buffer copy
 430                                 src = cp->c_data_ptr + cp->c_data_offs;
 431                                 bcnt = cp->c_data_len - cp->c_data_offs;
 432                         }
 433 
 434                         if (!bcnt) break;
 435 
 436                         // Don't run past user's buffer
 437                         if (bcnt > cnt) bcnt = cnt;
 438 
 439                         if (copy_to_user(buf,src,bcnt)) {
 440                                 // User supplied a bad pointer?
 441                                 // Give up - this *will* cause data
 442                                 // to be lost.
 443                                 ret = -EFAULT;
 444                                 break;
 445                         }
 446                         cnt -= bcnt;
 447                         buf += bcnt;
 448                         copied_cnt += bcnt;
 449 
 450                         if (cp->sync_state == 2) {
 451                                 // Update offset inside sync key that we're
 452                                 // repeating back out.
 453                                 cp->sync_buf_offs += bcnt;
 454                                 if (cp->sync_buf_offs >= cp->sync_key_len) {
 455                                         // Consumed entire key; switch mode
 456                                         // to normal.
 457                                         pvr2_trace(PVR2_TRACE_DATA_FLOW,
 458                                                    "/*---TRACE_READ---*/ sync_state <== 0");
 459                                         cp->sync_state = 0;
 460                                 }
 461                         } else {
 462                                 // Update buffer offset.
 463                                 cp->c_data_offs += bcnt;
 464                         }
 465                 }
 466 
 467         } while (0);
 468         mutex_unlock(&cp->mutex);
 469 
 470         if (!ret) {
 471                 if (copied_cnt) {
 472                         // If anything was copied, return that count
 473                         ret = copied_cnt;
 474                 } else {
 475                         // Nothing copied; suggest to caller that another
 476                         // attempt should be tried again later
 477                         ret = -EAGAIN;
 478                 }
 479         }
 480 
 481         pvr2_trace(PVR2_TRACE_DATA_FLOW,
 482                    "/*---TRACE_READ---*/ pvr2_ioread_read id=%p request=%d result=%d",
 483                    cp,req_cnt,ret);
 484         return ret;
 485 }

/* [<][>][^][v][top][bottom][index][help] */