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