diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index dd693a1980e8..ab608412b41e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -28,156 +28,39 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define BUFFER_COUNT 32 -#define BUFFER_SIZE PAGE_ALIGN(0x4000) - -struct pvr2_dvb_fh { - struct pvr2_channel channel; - struct pvr2_stream *stream; - struct pvr2_dvb_adapter *adap; - wait_queue_head_t wait_data; - char *buffer_storage[BUFFER_COUNT]; -}; - -static void pvr2_dvb_notify(struct pvr2_dvb_fh *fhp) -{ - wake_up(&fhp->wait_data); -} - -static int pvr2_dvb_fh_init(struct pvr2_dvb_fh *fh, - struct pvr2_dvb_adapter *adap) -{ - struct pvr2_context *pvr = adap->pvr; - unsigned int idx; - int ret; - struct pvr2_buffer *bp; - - init_waitqueue_head(&fh->wait_data); - - fh->adap = adap; - - pvr2_channel_init(&fh->channel, adap->pvr); - - ret = pvr2_channel_claim_stream(&fh->channel, &pvr->video_stream); - /* somebody else already has the stream */ - if (ret != 0) - return ret; - - fh->stream = pvr->video_stream.stream; - - for (idx = 0; idx < BUFFER_COUNT; idx++) { - fh->buffer_storage[idx] = kmalloc(BUFFER_SIZE, GFP_KERNEL); - if (!(fh->buffer_storage[idx])) - break; - } - - if (idx < BUFFER_COUNT) { - /* An allocation appears to have failed */ - ret = -ENOMEM; - goto cleanup; - } - - pvr2_stream_set_callback(pvr->video_stream.stream, - (pvr2_stream_callback) pvr2_dvb_notify, fh); - - ret = pvr2_stream_set_buffer_count(fh->stream, BUFFER_COUNT); - if (ret < 0) - return ret; - - for (idx = 0; idx < BUFFER_COUNT; idx++) { - bp = pvr2_stream_get_buffer(fh->stream, idx); - pvr2_buffer_set_buffer(bp, - fh->buffer_storage[idx], - BUFFER_SIZE); - } - - ret = pvr2_hdw_set_streaming(fh->channel.hdw, 1); - if (ret < 0) - goto cleanup; - - while ((bp = pvr2_stream_get_idle_buffer(fh->stream)) != 0) { - ret = pvr2_buffer_queue(bp); - if (ret < 0) - goto cleanup; - } - - return ret; - -cleanup: - if (fh->stream) - pvr2_stream_kill(fh->stream); - - for (idx = 0; idx < BUFFER_COUNT; idx++) { - if (!(fh->buffer_storage[idx])) - continue; - - kfree(fh->buffer_storage[idx]); - } - pvr2_channel_done(&fh->channel); - - return ret; -} - -static void pvr2_dvb_fh_done(struct pvr2_dvb_fh *fh) -{ - unsigned int idx; - - pvr2_hdw_set_streaming(fh->channel.hdw, 0); - - pvr2_stream_kill(fh->stream); - -// pvr2_channel_claim_stream(&fh->channel, NULL); - - for (idx = 0; idx < BUFFER_COUNT; idx++) { - if (!(fh->buffer_storage[idx])) - continue; - - kfree(fh->buffer_storage[idx]); - } - - pvr2_channel_done(&fh->channel); -} - static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) { - struct pvr2_dvb_fh fh; int ret; unsigned int count; struct pvr2_buffer *bp; + struct pvr2_stream *stream; printk(KERN_DEBUG "dvb thread started\n"); set_freezable(); - memset(&fh, 0, sizeof(fh)); - - ret = pvr2_dvb_fh_init(&fh, adap); - if (ret != 0) - return ret; + stream = adap->channel.stream->stream; for (;;) { - if ((0 == adap->feedcount) || (kthread_should_stop())) - break; + if (kthread_should_stop()) break; /* Not sure about this... */ try_to_freeze(); - bp = pvr2_stream_get_ready_buffer(fh.stream); + bp = pvr2_stream_get_ready_buffer(stream); if (bp != NULL) { count = pvr2_buffer_get_count(bp); if (count) { dvb_dmx_swfilter( &adap->demux, - fh.buffer_storage[ - pvr2_buffer_get_id(bp)], + adap->buffer_storage[ + pvr2_buffer_get_id(bp)], count); } else { ret = pvr2_buffer_get_status(bp); - if (ret < 0) - break; + if (ret < 0) break; } ret = pvr2_buffer_queue(bp); - if (ret < 0) - break; + if (ret < 0) break; /* Since we know we did something to a buffer, just go back and try again. No point in @@ -189,14 +72,11 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) /* Wait until more buffers become available. */ ret = wait_event_interruptible( - fh.wait_data, - pvr2_stream_get_ready_count(fh.stream) > 0); - if (ret < 0) - break; + adap->buffer_wait_data, + pvr2_stream_get_ready_count(stream) > 0); + if (ret < 0) break; } - pvr2_dvb_fh_done(&fh); - /* 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... */ @@ -216,41 +96,131 @@ static int pvr2_dvb_feed_thread(void *data) return stat; } -static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) +static void pvr2_dvb_notify(struct pvr2_dvb_adapter *adap) { - struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv; - int newfeedcount, ret = 0; + wake_up(&adap->buffer_wait_data); +} - if (adap == NULL) - return -ENODEV; +static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap) +{ + unsigned int idx; + struct pvr2_stream *stream; - mutex_lock(&adap->lock); - newfeedcount = adap->feedcount + (onoff ? 1 : -1); - - if (newfeedcount == 0) { - printk(KERN_DEBUG "stop feeding\n"); - - ret = kthread_stop(adap->thread); + if (adap->thread) { + kthread_stop(adap->thread); adap->thread = NULL; } - adap->feedcount = newfeedcount; - - if (adap->feedcount == onoff && adap->feedcount > 0) { - if (NULL != adap->thread) - goto fail; - - printk(KERN_DEBUG "start feeding\n"); - - adap->thread = kthread_run(pvr2_dvb_feed_thread, - adap, "pvrusb2-dvb"); - if (IS_ERR(adap->thread)) { - ret = PTR_ERR(adap->thread); - adap->thread = NULL; - } - //ret = newfeedcount; + if (adap->channel.stream) { + stream = adap->channel.stream->stream; + } else { + stream = NULL; } -fail: + if (stream) { + pvr2_hdw_set_streaming(adap->channel.hdw, 0); + pvr2_stream_set_callback(stream, NULL, NULL); + pvr2_stream_kill(stream); + pvr2_stream_set_buffer_count(stream, 0); + pvr2_channel_claim_stream(&adap->channel, NULL); + } + + if (adap->stream_run) { + for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) { + if (!(adap->buffer_storage[idx])) continue; + kfree(adap->buffer_storage[idx]); + adap->buffer_storage[idx] = 0; + } + adap->stream_run = 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 = 0; + + if (adap->stream_run) return -EIO; + + ret = pvr2_channel_claim_stream(&adap->channel, &pvr->video_stream); + /* somebody else already has the 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)) != 0) { + 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_dvb_stream_start(struct pvr2_dvb_adapter *adap) +{ + int ret = pvr2_dvb_stream_do_start(adap); + if (ret < 0) pvr2_dvb_stream_end(adap); + return ret; +} + +static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv; + int ret = 0; + + if (adap == NULL) return -ENODEV; + + mutex_lock(&adap->lock); + do { + if (onoff) { + if (!adap->feedcount) { + printk(KERN_DEBUG "start feeding\n"); + ret = pvr2_dvb_stream_start(adap); + if (ret < 0) break; + } + (adap->feedcount)++; + } else if (adap->feedcount > 0) { + (adap->feedcount)--; + if (!adap->feedcount) { + printk(KERN_DEBUG "stop feeding\n"); + pvr2_dvb_stream_end(adap); + } + } + } while (0); mutex_unlock(&adap->lock); return ret; @@ -287,7 +257,7 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) ret = dvb_register_adapter(&adap->dvb_adap, "pvrusb2-dvb", THIS_MODULE/*&hdw->usb_dev->owner*/, - &adap->pvr->hdw->usb_dev->dev, + &adap->channel.hdw->usb_dev->dev, adapter_nr); if (ret < 0) { err("dvb_register_adapter failed: error %d", ret); @@ -351,7 +321,7 @@ static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap) static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) { - struct pvr2_hdw *hdw = adap->pvr->hdw; + struct pvr2_hdw *hdw = adap->channel.hdw; struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props; int ret; @@ -419,14 +389,14 @@ static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) int pvr2_dvb_init(struct pvr2_context *pvr) { int ret = 0; - - pvr->hdw->dvb.pvr = pvr; + struct pvr2_dvb_adapter *adap; + adap = &pvr->hdw->dvb; + adap->init = !0; + pvr2_channel_init(&adap->channel, pvr); + init_waitqueue_head(&adap->buffer_wait_data); mutex_init(&pvr->hdw->dvb.lock); - ret = pvr2_dvb_adapter_init(&pvr->hdw->dvb); - if (ret < 0) - goto fail; - + if (ret < 0) goto fail; ret = pvr2_dvb_frontend_init(&pvr->hdw->dvb); fail: return ret; @@ -434,10 +404,12 @@ fail: int pvr2_dvb_exit(struct pvr2_context *pvr) { - pvr2_dvb_frontend_exit(&pvr->hdw->dvb); - pvr2_dvb_adapter_exit(&pvr->hdw->dvb); - - pvr->hdw->dvb.pvr = NULL; - + struct pvr2_dvb_adapter *adap; + adap = &pvr->hdw->dvb; + if (!adap->init) return 0; + pvr2_dvb_stream_end(adap); + pvr2_dvb_frontend_exit(adap); + pvr2_dvb_adapter_exit(adap); + pvr2_channel_done(&adap->channel); return 0; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.h b/drivers/media/video/pvrusb2/pvrusb2-dvb.h index 98728d44a4b6..651324ffab3d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.h +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.h @@ -7,8 +7,11 @@ #include "dmxdev.h" #include "pvrusb2-context.h" +#define PVR2_DVB_BUFFER_COUNT 32 +#define PVR2_DVB_BUFFER_SIZE PAGE_ALIGN(0x4000) + struct pvr2_dvb_adapter { - struct pvr2_context *pvr; + struct pvr2_channel channel; struct dvb_adapter dvb_adap; struct dmxdev dmxdev; @@ -23,6 +26,11 @@ struct pvr2_dvb_adapter { struct mutex lock; unsigned int digital_up:1; + unsigned int stream_run:1; + unsigned int init:1; + + wait_queue_head_t buffer_wait_data; + char *buffer_storage[PVR2_DVB_BUFFER_COUNT]; }; struct pvr2_dvb_props {