static int pvr2_ioread_start(struct pvr2_ioread *cp) { int stat; struct pvr2_buffer *bp; if (cp->enabled) return 0; if (!(cp->stream)) return 0; pvr2_trace(PVR2_TRACE_START_STOP, "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp); while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) { stat = pvr2_buffer_queue(bp); if (stat < 0) { pvr2_trace(PVR2_TRACE_DATA_FLOW, "/*---TRACE_READ---*/ pvr2_ioread_start id=%p error=%d", cp,stat); pvr2_ioread_stop(cp); return stat; } } cp->enabled = !0; cp->c_buf = NULL; cp->c_data_ptr = NULL; cp->c_data_len = 0; cp->c_data_offs = 0; cp->stream_running = 0; if (cp->sync_key_len) { pvr2_trace(PVR2_TRACE_DATA_FLOW, "/*---TRACE_READ---*/ sync_state <== 1"); cp->sync_state = 1; cp->sync_trashed_count = 0; cp->sync_buf_offs = 0; } cp->spigot_open = 0; return 0; }
static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) { int ret; unsigned int count; struct pvr2_buffer *bp; struct pvr2_stream *stream; pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread started"); set_freezable(); stream = adap->channel.stream->stream; for (;;) { if (kthread_should_stop()) break; /* */ try_to_freeze(); bp = pvr2_stream_get_ready_buffer(stream); if (bp != NULL) { count = pvr2_buffer_get_count(bp); if (count) { dvb_dmx_swfilter( &adap->demux, adap->buffer_storage[ pvr2_buffer_get_id(bp)], count); } else { ret = pvr2_buffer_get_status(bp); if (ret < 0) break; } ret = pvr2_buffer_queue(bp); if (ret < 0) break; /* */ continue; } /* */ ret = wait_event_interruptible( adap->buffer_wait_data, (pvr2_stream_get_ready_count(stream) > 0) || kthread_should_stop()); if (ret < 0) break; } /* */ pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread stopped"); return 0; }
static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) { int ret; unsigned int count; struct pvr2_buffer *bp; struct pvr2_stream *stream; pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread started"); set_freezable(); stream = adap->channel.stream->stream; for (;;) { if (kthread_should_stop()) break; /* Not sure about this... */ try_to_freeze(); bp = pvr2_stream_get_ready_buffer(stream); if (bp != NULL) { count = pvr2_buffer_get_count(bp); if (count) { dvb_dmx_swfilter( &adap->demux, adap->buffer_storage[ pvr2_buffer_get_id(bp)], count); } else { ret = pvr2_buffer_get_status(bp); if (ret < 0) break; } ret = pvr2_buffer_queue(bp); if (ret < 0) break; /* Since we know we did something to a buffer, just go back and try again. No point in blocking unless we really ran out of buffers to process. */ continue; } /* Wait until more buffers become available or we're told not to wait any longer. */ ret = wait_event_interruptible( adap->buffer_wait_data, (pvr2_stream_get_ready_count(stream) > 0) || kthread_should_stop()); if (ret < 0) break; } /* If we get here and ret is < 0, then an error has occurred. Probably would be a good idea to communicate that to DVB core... */ pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread stopped"); return 0; }
static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) { struct pvr2_context *pvr = adap->channel.mc_head; unsigned int idx; int ret; struct pvr2_buffer *bp; struct pvr2_stream *stream = NULL; if (adap->stream_run) return -EIO; ret = pvr2_channel_claim_stream(&adap->channel, &pvr->video_stream); /* */ if (ret < 0) return ret; stream = adap->channel.stream->stream; for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) { adap->buffer_storage[idx] = kmalloc(PVR2_DVB_BUFFER_SIZE, GFP_KERNEL); if (!(adap->buffer_storage[idx])) return -ENOMEM; } pvr2_stream_set_callback(pvr->video_stream.stream, (pvr2_stream_callback) pvr2_dvb_notify, adap); ret = pvr2_stream_set_buffer_count(stream, PVR2_DVB_BUFFER_COUNT); if (ret < 0) return ret; for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) { bp = pvr2_stream_get_buffer(stream, idx); pvr2_buffer_set_buffer(bp, adap->buffer_storage[idx], PVR2_DVB_BUFFER_SIZE); } ret = pvr2_hdw_set_streaming(adap->channel.hdw, 1); if (ret < 0) return ret; while ((bp = pvr2_stream_get_idle_buffer(stream)) != NULL) { ret = pvr2_buffer_queue(bp); if (ret < 0) return ret; } adap->thread = kthread_run(pvr2_dvb_feed_thread, adap, "pvrusb2-dvb"); if (IS_ERR(adap->thread)) { ret = PTR_ERR(adap->thread); adap->thread = NULL; return ret; } adap->stream_run = !0; return 0; }
static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp) { int stat; while (cp->c_data_len <= cp->c_data_offs) { if (cp->c_buf) { stat = pvr2_buffer_queue(cp->c_buf); if (stat < 0) { pvr2_trace(PVR2_TRACE_DATA_FLOW, "/*---TRACE_READ---*/" " pvr2_ioread_read id=%p" " queue_error=%d", cp,stat); pvr2_ioread_stop(cp); return 0; } cp->c_buf = NULL; cp->c_data_ptr = NULL; cp->c_data_len = 0; cp->c_data_offs = 0; } cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream); if (!cp->c_buf) break; cp->c_data_len = pvr2_buffer_get_count(cp->c_buf); if (!cp->c_data_len) { stat = pvr2_buffer_get_status(cp->c_buf); if (stat < 0) { pvr2_trace(PVR2_TRACE_DATA_FLOW, "/*---TRACE_READ---*/" " pvr2_ioread_read id=%p" " buffer_error=%d", cp,stat); pvr2_ioread_stop(cp); return 0; } continue; } cp->c_data_offs = 0; cp->c_data_ptr = cp->buffer_storage[ pvr2_buffer_get_id(cp->c_buf)]; } return !0; }
/* State relevant to current buffer being read */ struct pvr2_buffer *c_buf; char *c_data_ptr; unsigned int c_data_len; unsigned int c_data_offs; struct mutex mutex; }; static int pvr2_ioread_init(struct pvr2_ioread *cp) { unsigned int idx; cp->stream = NULL; mutex_init(&cp->mutex); for (idx = 0; idx < BUFFER_COUNT; idx++) { cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL); if (!(cp->buffer_storage[idx])) break; } if (idx < BUFFER_COUNT) { // An allocation appears to have failed for (idx = 0; idx < BUFFER_COUNT; idx++) { if (!(cp->buffer_storage[idx])) continue; kfree(cp->buffer_storage[idx]); } return -ENOMEM; } return 0; } static void pvr2_ioread_done(struct pvr2_ioread *cp) { unsigned int idx; pvr2_ioread_setup(cp,NULL); for (idx = 0; idx < BUFFER_COUNT; idx++) { if (!(cp->buffer_storage[idx])) continue; kfree(cp->buffer_storage[idx]); } } struct pvr2_ioread *pvr2_ioread_create(void) { struct pvr2_ioread *cp; cp = kzalloc(sizeof(*cp),GFP_KERNEL); if (!cp) return NULL; pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp); if (pvr2_ioread_init(cp) < 0) { kfree(cp); return NULL; } return cp; } void pvr2_ioread_destroy(struct pvr2_ioread *cp) { if (!cp) return; pvr2_ioread_done(cp); pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp); if (cp->sync_key_ptr) { kfree(cp->sync_key_ptr); cp->sync_key_ptr = NULL; } kfree(cp); } void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp, const char *sync_key_ptr, unsigned int sync_key_len) { if (!cp) return; if (!sync_key_ptr) sync_key_len = 0; if ((sync_key_len == cp->sync_key_len) && ((!sync_key_len) || (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return; if (sync_key_len != cp->sync_key_len) { if (cp->sync_key_ptr) { kfree(cp->sync_key_ptr); cp->sync_key_ptr = NULL; } cp->sync_key_len = 0; if (sync_key_len) { cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL); if (cp->sync_key_ptr) { cp->sync_key_len = sync_key_len; } } } if (!cp->sync_key_len) return; memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len); } static void pvr2_ioread_stop(struct pvr2_ioread *cp) { if (!(cp->enabled)) return; pvr2_trace(PVR2_TRACE_START_STOP, "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp); pvr2_stream_kill(cp->stream); cp->c_buf = NULL; cp->c_data_ptr = NULL; cp->c_data_len = 0; cp->c_data_offs = 0; cp->enabled = 0; cp->stream_running = 0; cp->spigot_open = 0; if (cp->sync_state) { pvr2_trace(PVR2_TRACE_DATA_FLOW, "/*---TRACE_READ---*/ sync_state <== 0"); cp->sync_state = 0; } } static int pvr2_ioread_start(struct pvr2_ioread *cp) { int stat; struct pvr2_buffer *bp; if (cp->enabled) return 0; if (!(cp->stream)) return 0; pvr2_trace(PVR2_TRACE_START_STOP, "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp); while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) { stat = pvr2_buffer_queue(bp); if (stat < 0) { pvr2_trace(PVR2_TRACE_DATA_FLOW, "/*---TRACE_READ---*/" " pvr2_ioread_start id=%p" " error=%d", cp,stat); pvr2_ioread_stop(cp); return stat; } } cp->enabled = !0; cp->c_buf = NULL; cp->c_data_ptr = NULL; cp->c_data_len = 0; cp->c_data_offs = 0; cp->stream_running = 0; if (cp->sync_key_len) { pvr2_trace(PVR2_TRACE_DATA_FLOW, "/*---TRACE_READ---*/ sync_state <== 1"); cp->sync_state = 1; cp->sync_trashed_count = 0; cp->sync_buf_offs = 0; } cp->spigot_open = 0; return 0; } struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp) { return cp->stream; } int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) { int ret; unsigned int idx; struct pvr2_buffer *bp; mutex_lock(&cp->mutex); do { if (cp->stream) { pvr2_trace(PVR2_TRACE_START_STOP, "/*---TRACE_READ---*/" " pvr2_ioread_setup (tear-down) id=%p",cp); pvr2_ioread_stop(cp); pvr2_stream_kill(cp->stream); if (pvr2_stream_get_buffer_count(cp->stream)) { pvr2_stream_set_buffer_count(cp->stream,0); } cp->stream = NULL; } if (sp) { pvr2_trace(PVR2_TRACE_START_STOP, "/*---TRACE_READ---*/" " pvr2_ioread_setup (setup) id=%p",cp); pvr2_stream_kill(sp); ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT); if (ret < 0) { mutex_unlock(&cp->mutex); return ret; } for (idx = 0; idx < BUFFER_COUNT; idx++) { bp = pvr2_stream_get_buffer(sp,idx); pvr2_buffer_set_buffer(bp, cp->buffer_storage[idx], BUFFER_SIZE); } cp->stream = sp; } } while (0); mutex_unlock(&cp->mutex); return 0; } int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl) { int ret = 0; if ((!fl) == (!(cp->enabled))) return ret; mutex_lock(&cp->mutex); do { if (fl) { ret = pvr2_ioread_start(cp); } else { pvr2_ioread_stop(cp); } } while (0); mutex_unlock(&cp->mutex); return ret; } #if 0 int pvr2_ioread_get_enabled(struct pvr2_ioread *cp) { return cp->enabled != 0; } #endif /* 0 */ static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp) { int stat; while (cp->c_data_len <= cp->c_data_offs) { if (cp->c_buf) { // Flush out current buffer first. stat = pvr2_buffer_queue(cp->c_buf); if (stat < 0) { // Streaming error... pvr2_trace(PVR2_TRACE_DATA_FLOW, "/*---TRACE_READ---*/" " pvr2_ioread_read id=%p" " queue_error=%d", cp,stat); pvr2_ioread_stop(cp); return 0; } cp->c_buf = NULL; cp->c_data_ptr = NULL; cp->c_data_len = 0; cp->c_data_offs = 0; } // Now get a freshly filled buffer. cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream); if (!cp->c_buf) break; // Nothing ready; done. cp->c_data_len = pvr2_buffer_get_count(cp->c_buf); if (!cp->c_data_len) { // Nothing transferred. Was there an error? stat = pvr2_buffer_get_status(cp->c_buf); if (stat < 0) { // Streaming error... pvr2_trace(PVR2_TRACE_DATA_FLOW, "/*---TRACE_READ---*/" " pvr2_ioread_read id=%p" " buffer_error=%d", cp,stat); pvr2_ioread_stop(cp); // Give up. return 0; } // Start over... continue; } cp->c_data_offs = 0; cp->c_data_ptr = cp->buffer_storage[ pvr2_buffer_get_id(cp->c_buf)]; } return !0; }