Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
0005  */
0006 
0007 #include "pvrusb2-ioread.h"
0008 #include "pvrusb2-debug.h"
0009 #include <linux/errno.h>
0010 #include <linux/string.h>
0011 #include <linux/mm.h>
0012 #include <linux/slab.h>
0013 #include <linux/mutex.h>
0014 #include <linux/uaccess.h>
0015 
0016 #define BUFFER_COUNT 32
0017 #define BUFFER_SIZE PAGE_ALIGN(0x4000)
0018 
0019 struct pvr2_ioread {
0020     struct pvr2_stream *stream;
0021     char *buffer_storage[BUFFER_COUNT];
0022     char *sync_key_ptr;
0023     unsigned int sync_key_len;
0024     unsigned int sync_buf_offs;
0025     unsigned int sync_state;
0026     unsigned int sync_trashed_count;
0027     int enabled;         // Streaming is on
0028     int spigot_open;     // OK to pass data to client
0029     int stream_running;  // Passing data to client now
0030 
0031     /* State relevant to current buffer being read */
0032     struct pvr2_buffer *c_buf;
0033     char *c_data_ptr;
0034     unsigned int c_data_len;
0035     unsigned int c_data_offs;
0036     struct mutex mutex;
0037 };
0038 
0039 static int pvr2_ioread_init(struct pvr2_ioread *cp)
0040 {
0041     unsigned int idx;
0042 
0043     cp->stream = NULL;
0044     mutex_init(&cp->mutex);
0045 
0046     for (idx = 0; idx < BUFFER_COUNT; idx++) {
0047         cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL);
0048         if (!(cp->buffer_storage[idx])) break;
0049     }
0050 
0051     if (idx < BUFFER_COUNT) {
0052         // An allocation appears to have failed
0053         for (idx = 0; idx < BUFFER_COUNT; idx++) {
0054             if (!(cp->buffer_storage[idx])) continue;
0055             kfree(cp->buffer_storage[idx]);
0056         }
0057         return -ENOMEM;
0058     }
0059     return 0;
0060 }
0061 
0062 static void pvr2_ioread_done(struct pvr2_ioread *cp)
0063 {
0064     unsigned int idx;
0065 
0066     pvr2_ioread_setup(cp,NULL);
0067     for (idx = 0; idx < BUFFER_COUNT; idx++) {
0068         if (!(cp->buffer_storage[idx])) continue;
0069         kfree(cp->buffer_storage[idx]);
0070     }
0071 }
0072 
0073 struct pvr2_ioread *pvr2_ioread_create(void)
0074 {
0075     struct pvr2_ioread *cp;
0076     cp = kzalloc(sizeof(*cp),GFP_KERNEL);
0077     if (!cp) return NULL;
0078     pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
0079     if (pvr2_ioread_init(cp) < 0) {
0080         kfree(cp);
0081         return NULL;
0082     }
0083     return cp;
0084 }
0085 
0086 void pvr2_ioread_destroy(struct pvr2_ioread *cp)
0087 {
0088     if (!cp) return;
0089     pvr2_ioread_done(cp);
0090     pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp);
0091     if (cp->sync_key_ptr) {
0092         kfree(cp->sync_key_ptr);
0093         cp->sync_key_ptr = NULL;
0094     }
0095     kfree(cp);
0096 }
0097 
0098 void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp,
0099                   const char *sync_key_ptr,
0100                   unsigned int sync_key_len)
0101 {
0102     if (!cp) return;
0103 
0104     if (!sync_key_ptr) sync_key_len = 0;
0105     if ((sync_key_len == cp->sync_key_len) &&
0106         ((!sync_key_len) ||
0107          (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return;
0108 
0109     if (sync_key_len != cp->sync_key_len) {
0110         if (cp->sync_key_ptr) {
0111             kfree(cp->sync_key_ptr);
0112             cp->sync_key_ptr = NULL;
0113         }
0114         cp->sync_key_len = 0;
0115         if (sync_key_len) {
0116             cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL);
0117             if (cp->sync_key_ptr) {
0118                 cp->sync_key_len = sync_key_len;
0119             }
0120         }
0121     }
0122     if (!cp->sync_key_len) return;
0123     memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len);
0124 }
0125 
0126 static void pvr2_ioread_stop(struct pvr2_ioread *cp)
0127 {
0128     if (!(cp->enabled)) return;
0129     pvr2_trace(PVR2_TRACE_START_STOP,
0130            "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp);
0131     pvr2_stream_kill(cp->stream);
0132     cp->c_buf = NULL;
0133     cp->c_data_ptr = NULL;
0134     cp->c_data_len = 0;
0135     cp->c_data_offs = 0;
0136     cp->enabled = 0;
0137     cp->stream_running = 0;
0138     cp->spigot_open = 0;
0139     if (cp->sync_state) {
0140         pvr2_trace(PVR2_TRACE_DATA_FLOW,
0141                "/*---TRACE_READ---*/ sync_state <== 0");
0142         cp->sync_state = 0;
0143     }
0144 }
0145 
0146 static int pvr2_ioread_start(struct pvr2_ioread *cp)
0147 {
0148     int stat;
0149     struct pvr2_buffer *bp;
0150     if (cp->enabled) return 0;
0151     if (!(cp->stream)) return 0;
0152     pvr2_trace(PVR2_TRACE_START_STOP,
0153            "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp);
0154     while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) {
0155         stat = pvr2_buffer_queue(bp);
0156         if (stat < 0) {
0157             pvr2_trace(PVR2_TRACE_DATA_FLOW,
0158                    "/*---TRACE_READ---*/ pvr2_ioread_start id=%p error=%d",
0159                    cp,stat);
0160             pvr2_ioread_stop(cp);
0161             return stat;
0162         }
0163     }
0164     cp->enabled = !0;
0165     cp->c_buf = NULL;
0166     cp->c_data_ptr = NULL;
0167     cp->c_data_len = 0;
0168     cp->c_data_offs = 0;
0169     cp->stream_running = 0;
0170     if (cp->sync_key_len) {
0171         pvr2_trace(PVR2_TRACE_DATA_FLOW,
0172                "/*---TRACE_READ---*/ sync_state <== 1");
0173         cp->sync_state = 1;
0174         cp->sync_trashed_count = 0;
0175         cp->sync_buf_offs = 0;
0176     }
0177     cp->spigot_open = 0;
0178     return 0;
0179 }
0180 
0181 struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp)
0182 {
0183     return cp->stream;
0184 }
0185 
0186 int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
0187 {
0188     int ret;
0189     unsigned int idx;
0190     struct pvr2_buffer *bp;
0191 
0192     mutex_lock(&cp->mutex);
0193     do {
0194         if (cp->stream) {
0195             pvr2_trace(PVR2_TRACE_START_STOP,
0196                    "/*---TRACE_READ---*/ pvr2_ioread_setup (tear-down) id=%p",
0197                    cp);
0198             pvr2_ioread_stop(cp);
0199             pvr2_stream_kill(cp->stream);
0200             if (pvr2_stream_get_buffer_count(cp->stream)) {
0201                 pvr2_stream_set_buffer_count(cp->stream,0);
0202             }
0203             cp->stream = NULL;
0204         }
0205         if (sp) {
0206             pvr2_trace(PVR2_TRACE_START_STOP,
0207                    "/*---TRACE_READ---*/ pvr2_ioread_setup (setup) id=%p",
0208                    cp);
0209             pvr2_stream_kill(sp);
0210             ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
0211             if (ret < 0) {
0212                 mutex_unlock(&cp->mutex);
0213                 return ret;
0214             }
0215             for (idx = 0; idx < BUFFER_COUNT; idx++) {
0216                 bp = pvr2_stream_get_buffer(sp,idx);
0217                 pvr2_buffer_set_buffer(bp,
0218                                cp->buffer_storage[idx],
0219                                BUFFER_SIZE);
0220             }
0221             cp->stream = sp;
0222         }
0223     } while (0);
0224     mutex_unlock(&cp->mutex);
0225 
0226     return 0;
0227 }
0228 
0229 int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl)
0230 {
0231     int ret = 0;
0232     if ((!fl) == (!(cp->enabled))) return ret;
0233 
0234     mutex_lock(&cp->mutex);
0235     do {
0236         if (fl) {
0237             ret = pvr2_ioread_start(cp);
0238         } else {
0239             pvr2_ioread_stop(cp);
0240         }
0241     } while (0);
0242     mutex_unlock(&cp->mutex);
0243     return ret;
0244 }
0245 
0246 static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp)
0247 {
0248     int stat;
0249 
0250     while (cp->c_data_len <= cp->c_data_offs) {
0251         if (cp->c_buf) {
0252             // Flush out current buffer first.
0253             stat = pvr2_buffer_queue(cp->c_buf);
0254             if (stat < 0) {
0255                 // Streaming error...
0256                 pvr2_trace(PVR2_TRACE_DATA_FLOW,
0257                        "/*---TRACE_READ---*/ pvr2_ioread_read id=%p queue_error=%d",
0258                        cp,stat);
0259                 pvr2_ioread_stop(cp);
0260                 return 0;
0261             }
0262             cp->c_buf = NULL;
0263             cp->c_data_ptr = NULL;
0264             cp->c_data_len = 0;
0265             cp->c_data_offs = 0;
0266         }
0267         // Now get a freshly filled buffer.
0268         cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream);
0269         if (!cp->c_buf) break; // Nothing ready; done.
0270         cp->c_data_len = pvr2_buffer_get_count(cp->c_buf);
0271         if (!cp->c_data_len) {
0272             // Nothing transferred.  Was there an error?
0273             stat = pvr2_buffer_get_status(cp->c_buf);
0274             if (stat < 0) {
0275                 // Streaming error...
0276                 pvr2_trace(PVR2_TRACE_DATA_FLOW,
0277                        "/*---TRACE_READ---*/ pvr2_ioread_read id=%p buffer_error=%d",
0278                        cp,stat);
0279                 pvr2_ioread_stop(cp);
0280                 // Give up.
0281                 return 0;
0282             }
0283             // Start over...
0284             continue;
0285         }
0286         cp->c_data_offs = 0;
0287         cp->c_data_ptr = cp->buffer_storage[
0288             pvr2_buffer_get_id(cp->c_buf)];
0289     }
0290     return !0;
0291 }
0292 
0293 static void pvr2_ioread_filter(struct pvr2_ioread *cp)
0294 {
0295     unsigned int idx;
0296     if (!cp->enabled) return;
0297     if (cp->sync_state != 1) return;
0298 
0299     // Search the stream for our synchronization key.  This is made
0300     // complicated by the fact that in order to be honest with
0301     // ourselves here we must search across buffer boundaries...
0302     mutex_lock(&cp->mutex);
0303     while (1) {
0304         // Ensure we have a buffer
0305         if (!pvr2_ioread_get_buffer(cp)) break;
0306         if (!cp->c_data_len) break;
0307 
0308         // Now walk the buffer contents until we match the key or
0309         // run out of buffer data.
0310         for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) {
0311             if (cp->sync_buf_offs >= cp->sync_key_len) break;
0312             if (cp->c_data_ptr[idx] ==
0313                 cp->sync_key_ptr[cp->sync_buf_offs]) {
0314                 // Found the next key byte
0315                 (cp->sync_buf_offs)++;
0316             } else {
0317                 // Whoops, mismatched.  Start key over...
0318                 cp->sync_buf_offs = 0;
0319             }
0320         }
0321 
0322         // Consume what we've walked through
0323         cp->c_data_offs += idx;
0324         cp->sync_trashed_count += idx;
0325 
0326         // If we've found the key, then update state and get out.
0327         if (cp->sync_buf_offs >= cp->sync_key_len) {
0328             cp->sync_trashed_count -= cp->sync_key_len;
0329             pvr2_trace(PVR2_TRACE_DATA_FLOW,
0330                    "/*---TRACE_READ---*/ sync_state <== 2 (skipped %u bytes)",
0331                    cp->sync_trashed_count);
0332             cp->sync_state = 2;
0333             cp->sync_buf_offs = 0;
0334             break;
0335         }
0336 
0337         if (cp->c_data_offs < cp->c_data_len) {
0338             // Sanity check - should NEVER get here
0339             pvr2_trace(PVR2_TRACE_ERROR_LEGS,
0340                    "ERROR: pvr2_ioread filter sync problem len=%u offs=%u",
0341                    cp->c_data_len,cp->c_data_offs);
0342             // Get out so we don't get stuck in an infinite
0343             // loop.
0344             break;
0345         }
0346 
0347         continue; // (for clarity)
0348     }
0349     mutex_unlock(&cp->mutex);
0350 }
0351 
0352 int pvr2_ioread_avail(struct pvr2_ioread *cp)
0353 {
0354     int ret;
0355     if (!(cp->enabled)) {
0356         // Stream is not enabled; so this is an I/O error
0357         return -EIO;
0358     }
0359 
0360     if (cp->sync_state == 1) {
0361         pvr2_ioread_filter(cp);
0362         if (cp->sync_state == 1) return -EAGAIN;
0363     }
0364 
0365     ret = 0;
0366     if (cp->stream_running) {
0367         if (!pvr2_stream_get_ready_count(cp->stream)) {
0368             // No data available at all right now.
0369             ret = -EAGAIN;
0370         }
0371     } else {
0372         if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) {
0373             // Haven't buffered up enough yet; try again later
0374             ret = -EAGAIN;
0375         }
0376     }
0377 
0378     if ((!(cp->spigot_open)) != (!(ret == 0))) {
0379         cp->spigot_open = (ret == 0);
0380         pvr2_trace(PVR2_TRACE_DATA_FLOW,
0381                "/*---TRACE_READ---*/ data is %s",
0382                cp->spigot_open ? "available" : "pending");
0383     }
0384 
0385     return ret;
0386 }
0387 
0388 int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt)
0389 {
0390     unsigned int copied_cnt;
0391     unsigned int bcnt;
0392     const char *src;
0393     int stat;
0394     int ret = 0;
0395     unsigned int req_cnt = cnt;
0396 
0397     if (!cnt) {
0398         pvr2_trace(PVR2_TRACE_TRAP,
0399                "/*---TRACE_READ---*/ pvr2_ioread_read id=%p ZERO Request? Returning zero.",
0400 cp);
0401         return 0;
0402     }
0403 
0404     stat = pvr2_ioread_avail(cp);
0405     if (stat < 0) return stat;
0406 
0407     cp->stream_running = !0;
0408 
0409     mutex_lock(&cp->mutex);
0410     do {
0411 
0412         // Suck data out of the buffers and copy to the user
0413         copied_cnt = 0;
0414         if (!buf) cnt = 0;
0415         while (1) {
0416             if (!pvr2_ioread_get_buffer(cp)) {
0417                 ret = -EIO;
0418                 break;
0419             }
0420 
0421             if (!cnt) break;
0422 
0423             if (cp->sync_state == 2) {
0424                 // We're repeating the sync key data into
0425                 // the stream.
0426                 src = cp->sync_key_ptr + cp->sync_buf_offs;
0427                 bcnt = cp->sync_key_len - cp->sync_buf_offs;
0428             } else {
0429                 // Normal buffer copy
0430                 src = cp->c_data_ptr + cp->c_data_offs;
0431                 bcnt = cp->c_data_len - cp->c_data_offs;
0432             }
0433 
0434             if (!bcnt) break;
0435 
0436             // Don't run past user's buffer
0437             if (bcnt > cnt) bcnt = cnt;
0438 
0439             if (copy_to_user(buf,src,bcnt)) {
0440                 // User supplied a bad pointer?
0441                 // Give up - this *will* cause data
0442                 // to be lost.
0443                 ret = -EFAULT;
0444                 break;
0445             }
0446             cnt -= bcnt;
0447             buf += bcnt;
0448             copied_cnt += bcnt;
0449 
0450             if (cp->sync_state == 2) {
0451                 // Update offset inside sync key that we're
0452                 // repeating back out.
0453                 cp->sync_buf_offs += bcnt;
0454                 if (cp->sync_buf_offs >= cp->sync_key_len) {
0455                     // Consumed entire key; switch mode
0456                     // to normal.
0457                     pvr2_trace(PVR2_TRACE_DATA_FLOW,
0458                            "/*---TRACE_READ---*/ sync_state <== 0");
0459                     cp->sync_state = 0;
0460                 }
0461             } else {
0462                 // Update buffer offset.
0463                 cp->c_data_offs += bcnt;
0464             }
0465         }
0466 
0467     } while (0);
0468     mutex_unlock(&cp->mutex);
0469 
0470     if (!ret) {
0471         if (copied_cnt) {
0472             // If anything was copied, return that count
0473             ret = copied_cnt;
0474         } else {
0475             // Nothing copied; suggest to caller that another
0476             // attempt should be tried again later
0477             ret = -EAGAIN;
0478         }
0479     }
0480 
0481     pvr2_trace(PVR2_TRACE_DATA_FLOW,
0482            "/*---TRACE_READ---*/ pvr2_ioread_read id=%p request=%d result=%d",
0483            cp,req_cnt,ret);
0484     return ret;
0485 }