From 04910bdc5c172af9bc937a8869e7f2907db4443f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 3 Feb 2008 23:46:16 -0300 Subject: V4L/DVB (7679): pvrusb2: add DVB API framework Add basic framework for the DVB API. This is enough to control the tuner & demod of the digital frontend, but the stream & buffer handling is still missing. Additional note from Mike Isely - also, since these changes are still very experimental arrange for DVB changes to be compiled in via new CONFIG_VIDEO_PVRUSB2_DVB option, for now. Signed-off-by: Michael Krufky Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 179 ++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 drivers/media/video/pvrusb2/pvrusb2-dvb.c (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c new file mode 100644 index 00000000000..18c18db2fe3 --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -0,0 +1,179 @@ +/* + * pvrusb2-dvb.c - linux-dvb api interface to the pvrusb2 driver. + * + * Copyright (C) 2007, 2008 Michael Krufky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "dvbdev.h" +#include "pvrusb2-hdw-internal.h" +#include "pvrusb2-hdw.h" +#include "pvrusb2-dvb.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int pvr2_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + printk(KERN_DEBUG "start pid: 0x%04x, feedtype: %d\n", + dvbdmxfeed->pid, dvbdmxfeed->type); + return 0; /* FIXME: pvr2_dvb_ctrl_feed(dvbdmxfeed, 1); */ +} + +static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + printk(KERN_DEBUG "stop pid: 0x%04x, feedtype: %d\n", + dvbdmxfeed->pid, dvbdmxfeed->type); + return 0; /* FIXME: pvr2_dvb_ctrl_feed(dvbdmxfeed, 0); */ +} + +static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) +{ + int ret; + + ret = dvb_register_adapter(&adap->dvb_adap, "pvrusb2-dvb", + THIS_MODULE/*&hdw->usb_dev->owner*/, + &adap->pvr->hdw->usb_dev->dev, + adapter_nr); + if (ret < 0) { + err("dvb_register_adapter failed: error %d", ret); + goto err; + } + adap->dvb_adap.priv = adap; + + adap->demux.dmx.capabilities = DMX_TS_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + adap->demux.priv = adap; + adap->demux.filternum = 256; + adap->demux.feednum = 256; + adap->demux.start_feed = pvr2_dvb_start_feed; + adap->demux.stop_feed = pvr2_dvb_stop_feed; + adap->demux.write_to_decoder = NULL; + + ret = dvb_dmx_init(&adap->demux); + if (ret < 0) { + err("dvb_dmx_init failed: error %d", ret); + goto err_dmx; + } + + adap->dmxdev.filternum = adap->demux.filternum; + adap->dmxdev.demux = &adap->demux.dmx; + adap->dmxdev.capabilities = 0; + + ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); + if (ret < 0) { + err("dvb_dmxdev_init failed: error %d", ret); + goto err_dmx_dev; + } + + dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); + + adap->digital_up = 1; + + return 0; + +err_dmx_dev: + dvb_dmx_release(&adap->demux); +err_dmx: + dvb_unregister_adapter(&adap->dvb_adap); +err: + return ret; +} + +static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap) +{ + if (adap->digital_up) { + printk(KERN_DEBUG "unregistering DVB devices\n"); + dvb_net_release(&adap->dvb_net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->dvb_adap); + adap->digital_up = 0; + } + return 0; +} + +static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) +{ + struct pvr2_dvb_props *dvb_props = adap->pvr->hdw->hdw_desc->dvb_props; + + if (dvb_props == NULL) { + err("fe_props not defined!"); + return -EINVAL; + } + + if (dvb_props->frontend_attach == NULL) { + err("frontend_attach not defined!"); + return -EINVAL; + } + + if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) { + + if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { + err("frontend registration failed!"); + dvb_frontend_detach(adap->fe); + adap->fe = NULL; + return -ENODEV; + } + + if (dvb_props->tuner_attach) + dvb_props->tuner_attach(adap); + + if (adap->fe->ops.analog_ops.standby) + adap->fe->ops.analog_ops.standby(adap->fe); + + } else { + err("no frontend was attached!"); + return -ENODEV; + } + + return 0; +} + +static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) +{ + if (adap->fe != NULL) { + dvb_unregister_frontend(adap->fe); + dvb_frontend_detach(adap->fe); + } + return 0; +} + +int pvr2_dvb_init(struct pvr2_context *pvr) +{ + int ret = 0; + + pvr->hdw->dvb.pvr = pvr; + + ret = pvr2_dvb_adapter_init(&pvr->hdw->dvb); + if (ret < 0) + goto fail; + + ret = pvr2_dvb_frontend_init(&pvr->hdw->dvb); +fail: + return ret; +} + +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; + + return 0; +} -- cgit v1.2.3-70-g09d2 From 99443ae04f7002530f666ba0747f7b1ecafb3002 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 3 Feb 2008 23:48:09 -0300 Subject: V4L/DVB (7680): pvrusb2-dvb: add pvr2_dvb_bus_ctrl to allow frontends to negotiate bus access This function is just a skeleton for now - a placeholder to remind us to fix it. Signed-off-by: Michael Krufky Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index 18c18db2fe3..250462265a4 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -39,6 +39,17 @@ static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) return 0; /* FIXME: pvr2_dvb_ctrl_feed(dvbdmxfeed, 0); */ } +static int pvr2_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + /* TO DO: This function will call into the core and request for + * input to be set to 'dtv' if (acquire) and if it isn't set already. + * + * If (!acquire) then we should do nothing -- don't switch inputs + * again unless the analog side of the driver requests the bus. + */ + return 0; +} + static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) { int ret; @@ -136,6 +147,9 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) if (adap->fe->ops.analog_ops.standby) adap->fe->ops.analog_ops.standby(adap->fe); + /* Ensure all frontends negotiate bus access */ + adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; + } else { err("no frontend was attached!"); return -ENODEV; -- cgit v1.2.3-70-g09d2 From d8abe97d0063cf77e9bbbee076181e4657c7e09c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 3 Feb 2008 23:55:07 -0300 Subject: V4L/DVB (7681): pvrusb2-dvb: start working on streaming / buffer handling code start work on streaming / buffer handling code to feed the software demux Signed-off-by: Michael Krufky Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 44 +++++++++++++++++++++++++++++-- drivers/media/video/pvrusb2/pvrusb2-dvb.h | 3 +++ 2 files changed, 45 insertions(+), 2 deletions(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index 250462265a4..c85477709e6 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -18,6 +18,7 @@ * */ +#include #include "dvbdev.h" #include "pvrusb2-hdw-internal.h" #include "pvrusb2-hdw.h" @@ -25,18 +26,56 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv; + int newfeedcount, ret = 0; + + if (adap == NULL) + return -ENODEV; + + mutex_lock(&adap->lock); + newfeedcount = adap->feedcount + (onoff ? 1 : -1); + + if (newfeedcount == 0) { + printk(KERN_DEBUG "stop feeding\n"); + + ret = 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"); + + if (IS_ERR(adap->thread)) { + ret = PTR_ERR(adap->thread); + adap->thread = NULL; + } + //ret = newfeedcount; + } +fail: + mutex_unlock(&adap->lock); + + return ret; +} + static int pvr2_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { printk(KERN_DEBUG "start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type); - return 0; /* FIXME: pvr2_dvb_ctrl_feed(dvbdmxfeed, 1); */ + return pvr2_dvb_ctrl_feed(dvbdmxfeed, 1); } static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { printk(KERN_DEBUG "stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type); - return 0; /* FIXME: pvr2_dvb_ctrl_feed(dvbdmxfeed, 0); */ + return pvr2_dvb_ctrl_feed(dvbdmxfeed, 0); } static int pvr2_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) @@ -172,6 +211,7 @@ int pvr2_dvb_init(struct pvr2_context *pvr) int ret = 0; pvr->hdw->dvb.pvr = pvr; + mutex_init(&pvr->hdw->dvb.lock); ret = pvr2_dvb_adapter_init(&pvr->hdw->dvb); if (ret < 0) diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.h b/drivers/media/video/pvrusb2/pvrusb2-dvb.h index 0aff05cb941..98728d44a4b 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.h +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.h @@ -19,6 +19,9 @@ struct pvr2_dvb_adapter { int feedcount; int max_feed_count; + struct task_struct *thread; + struct mutex lock; + unsigned int digital_up:1; }; -- cgit v1.2.3-70-g09d2 From bb8ce9d9143c0fe2b5cdf65fa41250446805a4be Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 4 Feb 2008 00:00:19 -0300 Subject: V4L/DVB (7682): pvrusb2-dvb: finish up stream & buffer handling Signed-off-by: Michael Krufky Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 187 ++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index c85477709e6..bde85c97305 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -19,13 +19,198 @@ */ #include +#include #include "dvbdev.h" #include "pvrusb2-hdw-internal.h" #include "pvrusb2-hdw.h" +#include "pvrusb2-io.h" #include "pvrusb2-dvb.h" 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_thread(void *data) +{ + struct pvr2_dvb_adapter *adap = data; + struct pvr2_dvb_fh fh; + int ret; + unsigned int count; + struct pvr2_buffer *bp; + + 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; + + for (;;) { + if ((0 == adap->feedcount) || (kthread_should_stop())) + break; + + /* Not sure about this... */ + try_to_freeze(); + + bp = pvr2_stream_get_ready_buffer(fh.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)], + 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. */ + ret = wait_event_interruptible( + fh.wait_data, + pvr2_stream_get_ready_count(fh.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... */ + + printk(KERN_DEBUG "dvb thread stopped\n"); + + /* from videobuf-dvb.c: */ + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + return 0; +} + static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) { struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv; @@ -52,6 +237,8 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) 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; -- cgit v1.2.3-70-g09d2 From bde316a4f1094f9a3da402c44f7315e1a94fb332 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 10 Feb 2008 05:33:37 -0300 Subject: V4L/DVB (7683): pvrusb2-dvb: set to DTV mode before attaching frontend Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index bde85c97305..69ac59aa654 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -346,13 +346,31 @@ static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap) static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) { - struct pvr2_dvb_props *dvb_props = adap->pvr->hdw->hdw_desc->dvb_props; + struct pvr2_hdw *hdw = adap->pvr->hdw; + struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props; + int ret; if (dvb_props == NULL) { err("fe_props not defined!"); return -EINVAL; } + /* FIXME: This code should be moved into the core, + * and should only be called if we don't already have + * control of the bus. + * + * We can't call "pvr2_dvb_bus_ctrl(adap->fe, 1)" from here, + * because adap->fe isn't defined yet. + */ + ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_by_id(hdw, + PVR2_CID_INPUT), + PVR2_CVAL_INPUT_DTV); + if (ret != 0) + return ret; + + pvr2_hdw_commit_ctl(hdw); + + if (dvb_props->frontend_attach == NULL) { err("frontend_attach not defined!"); return -EINVAL; -- cgit v1.2.3-70-g09d2 From ceb4340deb9bf5f8371d47ef906a83e6784345b0 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Wed, 6 Feb 2008 04:24:51 -0300 Subject: V4L/DVB (7687): pvrusb2: Fix oops in pvrusb2-dvb The pvrusb2-dvb feed thread cannot be allowed to exit by itself without first waiting for kthread_should_stop() to return true. Otherwise the driver will have a dangling task_struct context, which will cause a very nasty kernel oops. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index 69ac59aa654..dd693a1980e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -138,9 +138,8 @@ static void pvr2_dvb_fh_done(struct pvr2_dvb_fh *fh) pvr2_channel_done(&fh->channel); } -static int pvr2_dvb_feed_thread(void *data) +static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) { - struct pvr2_dvb_adapter *adap = data; struct pvr2_dvb_fh fh; int ret; unsigned int count; @@ -203,12 +202,18 @@ static int pvr2_dvb_feed_thread(void *data) printk(KERN_DEBUG "dvb thread stopped\n"); + return 0; +} + +static int pvr2_dvb_feed_thread(void *data) +{ + int stat = pvr2_dvb_feed_func(data); /* from videobuf-dvb.c: */ while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); schedule(); } - return 0; + return stat; } static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) -- cgit v1.2.3-70-g09d2 From a36416d0a70899d3724d2e69e378062e06252a41 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Wed, 6 Feb 2008 06:59:48 -0300 Subject: V4L/DVB (7688): pvrusb2: Clean up dvb streaming start/stop Eliminate the need for a separate pvr2_dvb_fh; since in the DVB context there can only ever be a single instance then there is no need for a separate instance to handle streaming state. This simplifies the module. Also move streaming start/stop out of the feed thread and into the driver's main context - which makes it possible for streaming start up failures to be detected by the DVB core. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 306 ++++++++++++++---------------- drivers/media/video/pvrusb2/pvrusb2-dvb.h | 10 +- 2 files changed, 148 insertions(+), 168 deletions(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index dd693a1980e..ab608412b41 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 (adap->thread) { + kthread_stop(adap->thread); + adap->thread = NULL; + } + + if (adap->channel.stream) { + stream = adap->channel.stream->stream; + } else { + stream = NULL; + } + 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; - if (newfeedcount == 0) { - printk(KERN_DEBUG "stop feeding\n"); + 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; + } - ret = kthread_stop(adap->thread); + 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->feedcount = newfeedcount; + adap->stream_run = !0; - if (adap->feedcount == onoff && adap->feedcount > 0) { - if (NULL != adap->thread) - goto fail; + return 0; +} - printk(KERN_DEBUG "start feeding\n"); +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; +} - adap->thread = kthread_run(pvr2_dvb_feed_thread, - adap, "pvrusb2-dvb"); - if (IS_ERR(adap->thread)) { - ret = PTR_ERR(adap->thread); - adap->thread = NULL; +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); + } } - //ret = newfeedcount; - } -fail: + } 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 98728d44a4b..651324ffab3 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 { -- cgit v1.2.3-70-g09d2 From 891d99efc5be16d2762bdbb9d0486f7250990eee Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 9 Feb 2008 15:44:30 -0300 Subject: V4L/DVB (7689): pvrusb2-dvb: Rework module tear-down Rather than making an explicit call to tear down the pvrusb2-dvb module, use the callback in the pvr2_channel structure. This has the advantage that now tear-down only happens when it makes sense. The previous implementation had scenarios where it was possible for the tear-down call to happen without a prior initialization. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 31 ++++++++++++++++++------------ drivers/media/video/pvrusb2/pvrusb2-dvb.h | 2 -- drivers/media/video/pvrusb2/pvrusb2-main.c | 3 --- 3 files changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index ab608412b41..38077b2c528 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -386,30 +386,37 @@ static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) return 0; } +static void pvr2_dvb_done(struct pvr2_dvb_adapter *adap) +{ + pvr2_dvb_stream_end(adap); + pvr2_dvb_frontend_exit(adap); + pvr2_dvb_adapter_exit(adap); + pvr2_channel_done(&adap->channel); +} + +static void pvr2_dvb_internal_check(struct pvr2_channel *chp) +{ + struct pvr2_dvb_adapter *adap; + adap = container_of(chp, struct pvr2_dvb_adapter, channel); + if (!adap->channel.mc_head->disconnect_flag) return; + pvr2_dvb_done(adap); +} + int pvr2_dvb_init(struct pvr2_context *pvr) { int ret = 0; struct pvr2_dvb_adapter *adap; adap = &pvr->hdw->dvb; - adap->init = !0; pvr2_channel_init(&adap->channel, pvr); + adap->channel.check_func = pvr2_dvb_internal_check; 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; ret = pvr2_dvb_frontend_init(&pvr->hdw->dvb); + return ret; fail: + pvr2_channel_done(&adap->channel); return ret; } -int pvr2_dvb_exit(struct pvr2_context *pvr) -{ - 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 651324ffab3..1326f6f455a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.h +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.h @@ -27,7 +27,6 @@ struct pvr2_dvb_adapter { 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]; @@ -39,6 +38,5 @@ struct pvr2_dvb_props { }; int pvr2_dvb_init(struct pvr2_context *pvr); -int pvr2_dvb_exit(struct pvr2_context *pvr); #endif /* __PVRUSB2_DVB_H__ */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 68f4a748073..42b4c8d5a1e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -99,9 +99,6 @@ static void pvr_disconnect(struct usb_interface *intf) pvr2_trace(PVR2_TRACE_INIT,"pvr_disconnect(pvr=%p) BEGIN",pvr); -#ifdef CONFIG_VIDEO_PVRUSB2_DVB - pvr2_dvb_exit(pvr); -#endif usb_set_intfdata (intf, NULL); pvr2_context_disconnect(pvr); -- cgit v1.2.3-70-g09d2 From 7dcc48fb55d18258e7db039f44a031e6828e6bad Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 9 Feb 2008 15:55:54 -0300 Subject: V4L/DVB (7690): pvrusb2-dvb: Remove digital_up flag Other pvrusb2-dvb changes have made the digital_up flag obsolete. So kill it. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 17 ++++++----------- drivers/media/video/pvrusb2/pvrusb2-dvb.h | 1 - 2 files changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index 38077b2c528..f32d052ff4e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -293,8 +293,6 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); - adap->digital_up = 1; - return 0; err_dmx_dev: @@ -307,15 +305,12 @@ err: static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap) { - if (adap->digital_up) { - printk(KERN_DEBUG "unregistering DVB devices\n"); - dvb_net_release(&adap->dvb_net); - adap->demux.dmx.close(&adap->demux.dmx); - dvb_dmxdev_release(&adap->dmxdev); - dvb_dmx_release(&adap->demux); - dvb_unregister_adapter(&adap->dvb_adap); - adap->digital_up = 0; - } + printk(KERN_DEBUG "unregistering DVB devices\n"); + dvb_net_release(&adap->dvb_net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->dvb_adap); return 0; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.h b/drivers/media/video/pvrusb2/pvrusb2-dvb.h index 1326f6f455a..e37cb7bc2fc 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.h +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.h @@ -25,7 +25,6 @@ struct pvr2_dvb_adapter { struct task_struct *thread; struct mutex lock; - unsigned int digital_up:1; unsigned int stream_run:1; wait_queue_head_t buffer_wait_data; -- cgit v1.2.3-70-g09d2 From 129a2f5efd95959c44a2bfeea8ee8b7c17252db6 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 9 Feb 2008 16:29:52 -0300 Subject: V4L/DVB (7691): pvrusb2-dvb: Don't initialize if device lacks a digital side In the end we'd like the dvb interface to always be present - even for analog devices (via the mpeg encoder). However right now pvrusb2-dvb won't operate correctly if the hardware doesn't have a digital tuner, so don't initialize the DVB interface unless we know we have a digital tuner. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index f32d052ff4e..17724005167 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -401,16 +401,25 @@ int pvr2_dvb_init(struct pvr2_context *pvr) { int ret = 0; struct pvr2_dvb_adapter *adap; + if (!pvr->hdw->hdw_desc->dvb_props) { + /* Device lacks a digital interface so don't set up + the DVB side of the driver either. For now. */ + return 0; + } adap = &pvr->hdw->dvb; pvr2_channel_init(&adap->channel, pvr); adap->channel.check_func = pvr2_dvb_internal_check; 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 fail1; ret = pvr2_dvb_frontend_init(&pvr->hdw->dvb); - return ret; -fail: + if (ret < 0) goto fail2; + return 0; + +fail2: + pvr2_dvb_adapter_exit(adap); +fail1: pvr2_channel_done(&adap->channel); return ret; } -- cgit v1.2.3-70-g09d2 From c5317b17f6ca74531a6c707873dc5d25f1877ac3 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 9 Feb 2008 19:47:07 -0300 Subject: V4L/DVB (7692): pvrusb2-dvb: Further clean up dvb init/tear-down Move pvr2_dvb_adapter usage out of the pvrusb2 driver core - it's really private to the pvrusb2-dvb module and nothing outside of the dvb implementation should care about it. Creation / destruction of the pvr2_dvb_adapter instance is now contained entirely within pvrusb2-dvb.c. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 20 +++++++++++--------- drivers/media/video/pvrusb2/pvrusb2-dvb.h | 2 +- drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 3 --- drivers/media/video/pvrusb2/pvrusb2-main.c | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index 17724005167..1a7c3ddace0 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -381,12 +381,13 @@ static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) return 0; } -static void pvr2_dvb_done(struct pvr2_dvb_adapter *adap) +static void pvr2_dvb_destroy(struct pvr2_dvb_adapter *adap) { pvr2_dvb_stream_end(adap); pvr2_dvb_frontend_exit(adap); pvr2_dvb_adapter_exit(adap); pvr2_channel_done(&adap->channel); + kfree(adap); } static void pvr2_dvb_internal_check(struct pvr2_channel *chp) @@ -394,10 +395,10 @@ static void pvr2_dvb_internal_check(struct pvr2_channel *chp) struct pvr2_dvb_adapter *adap; adap = container_of(chp, struct pvr2_dvb_adapter, channel); if (!adap->channel.mc_head->disconnect_flag) return; - pvr2_dvb_done(adap); + pvr2_dvb_destroy(adap); } -int pvr2_dvb_init(struct pvr2_context *pvr) +struct pvr2_dvb_adapter *pvr2_dvb_create(struct pvr2_context *pvr) { int ret = 0; struct pvr2_dvb_adapter *adap; @@ -406,21 +407,22 @@ int pvr2_dvb_init(struct pvr2_context *pvr) the DVB side of the driver either. For now. */ return 0; } - adap = &pvr->hdw->dvb; + adap = kzalloc(sizeof(*adap), GFP_KERNEL); + if (!adap) return adap; pvr2_channel_init(&adap->channel, pvr); adap->channel.check_func = pvr2_dvb_internal_check; init_waitqueue_head(&adap->buffer_wait_data); - mutex_init(&pvr->hdw->dvb.lock); - ret = pvr2_dvb_adapter_init(&pvr->hdw->dvb); + mutex_init(&adap->lock); + ret = pvr2_dvb_adapter_init(adap); if (ret < 0) goto fail1; - ret = pvr2_dvb_frontend_init(&pvr->hdw->dvb); + ret = pvr2_dvb_frontend_init(adap); if (ret < 0) goto fail2; - return 0; + return adap; fail2: pvr2_dvb_adapter_exit(adap); fail1: pvr2_channel_done(&adap->channel); - return ret; + return NULL; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.h b/drivers/media/video/pvrusb2/pvrusb2-dvb.h index e37cb7bc2fc..884ff916a35 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.h +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.h @@ -36,6 +36,6 @@ struct pvr2_dvb_props { int (*tuner_attach) (struct pvr2_dvb_adapter *); }; -int pvr2_dvb_init(struct pvr2_context *pvr); +struct pvr2_dvb_adapter *pvr2_dvb_create(struct pvr2_context *pvr); #endif /* __PVRUSB2_DVB_H__ */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index 6fe0a882209..c725495826c 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -41,7 +41,6 @@ #include "pvrusb2-io.h" #include #include "pvrusb2-devattr.h" -#include "pvrusb2-dvb.h" /* Legal values for PVR2_CID_HSM */ #define PVR2_CVAL_HSM_FAIL 0 @@ -374,8 +373,6 @@ struct pvr2_hdw { struct pvr2_ctrl *controls; unsigned int control_cnt; - - struct pvr2_dvb_adapter dvb; }; /* This function gets the current frequency */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 42b4c8d5a1e..54d9f168d7a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -62,7 +62,7 @@ static void pvr_setup_attach(struct pvr2_context *pvr) pvr2_v4l2_create(pvr); #ifdef CONFIG_VIDEO_PVRUSB2_DVB /* Create association with dvb layer */ - pvr2_dvb_init(pvr); + pvr2_dvb_create(pvr); #endif #ifdef CONFIG_VIDEO_PVRUSB2_SYSFS pvr2_sysfs_create(pvr,class_ptr); -- cgit v1.2.3-70-g09d2 From e6d1186543784222024da9c688766effd2ca3163 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sat, 9 Feb 2008 19:47:52 -0300 Subject: V4L/DVB (7693): pvrusb2-dvb: Change usage of 0 --> NULL Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index 1a7c3ddace0..58ef5caba83 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -405,7 +405,7 @@ struct pvr2_dvb_adapter *pvr2_dvb_create(struct pvr2_context *pvr) if (!pvr->hdw->hdw_desc->dvb_props) { /* Device lacks a digital interface so don't set up the DVB side of the driver either. For now. */ - return 0; + return NULL; } adap = kzalloc(sizeof(*adap), GFP_KERNEL); if (!adap) return adap; -- cgit v1.2.3-70-g09d2 From 07b80264c3ede47593e83189cce82b31100053f6 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 30 Mar 2008 20:36:31 -0300 Subject: V4L/DVB (7708): pvrusb2-dvb: Fix stuck thread on streaming abort If the device fails to stream, the feed thread will block forever waiting for buffers. But while in this state it was not looking for an exit condition from the driver DVB interface. This caused the thread to jam. Implement a new stop flag (which will be set appropriately) to tell the thread to stop. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 10 ++++++++-- drivers/media/video/pvrusb2/pvrusb2-dvb.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index 58ef5caba83..d82fceae468 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -41,6 +41,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) stream = adap->channel.stream->stream; for (;;) { + if (adap->feed_thread_stop) break; if (kthread_should_stop()) break; /* Not sure about this... */ @@ -70,10 +71,12 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) } - /* Wait until more buffers become available. */ + /* 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); + (pvr2_stream_get_ready_count(stream) > 0) || + adap->feed_thread_stop); if (ret < 0) break; } @@ -107,6 +110,8 @@ static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap) struct pvr2_stream *stream; if (adap->thread) { + adap->feed_thread_stop = !0; + pvr2_dvb_notify(adap); kthread_stop(adap->thread); adap->thread = NULL; } @@ -177,6 +182,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) if (ret < 0) return ret; } + adap->feed_thread_stop = 0; adap->thread = kthread_run(pvr2_dvb_feed_thread, adap, "pvrusb2-dvb"); if (IS_ERR(adap->thread)) { diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.h b/drivers/media/video/pvrusb2/pvrusb2-dvb.h index 884ff916a35..2dd0d4ef22a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.h +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.h @@ -28,6 +28,7 @@ struct pvr2_dvb_adapter { unsigned int stream_run:1; wait_queue_head_t buffer_wait_data; + int feed_thread_stop; char *buffer_storage[PVR2_DVB_BUFFER_COUNT]; }; -- cgit v1.2.3-70-g09d2 From 13e027a8bf2a507334fa0d30246ce619ff581cbb Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 7 Apr 2008 02:57:13 -0300 Subject: V4L/DVB (7713): pvrusb2: Implement cleaner DVB kernel thread shutdown Earlier fix to handle DVB feed thread aborts was overly-aggressive. We can take better advantage of what kthread_stop() can do. This change simplifies things. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 6 +----- drivers/media/video/pvrusb2/pvrusb2-dvb.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index d82fceae468..c20eef0f077 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -41,7 +41,6 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) stream = adap->channel.stream->stream; for (;;) { - if (adap->feed_thread_stop) break; if (kthread_should_stop()) break; /* Not sure about this... */ @@ -76,7 +75,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) ret = wait_event_interruptible( adap->buffer_wait_data, (pvr2_stream_get_ready_count(stream) > 0) || - adap->feed_thread_stop); + kthread_should_stop()); if (ret < 0) break; } @@ -110,8 +109,6 @@ static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap) struct pvr2_stream *stream; if (adap->thread) { - adap->feed_thread_stop = !0; - pvr2_dvb_notify(adap); kthread_stop(adap->thread); adap->thread = NULL; } @@ -182,7 +179,6 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) if (ret < 0) return ret; } - adap->feed_thread_stop = 0; adap->thread = kthread_run(pvr2_dvb_feed_thread, adap, "pvrusb2-dvb"); if (IS_ERR(adap->thread)) { diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.h b/drivers/media/video/pvrusb2/pvrusb2-dvb.h index 2dd0d4ef22a..884ff916a35 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.h +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.h @@ -28,7 +28,6 @@ struct pvr2_dvb_adapter { unsigned int stream_run:1; wait_queue_head_t buffer_wait_data; - int feed_thread_stop; char *buffer_storage[PVR2_DVB_BUFFER_COUNT]; }; -- cgit v1.2.3-70-g09d2 From 1cb03b76d09d20accfa5c1664c16ba6566f539a0 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Mon, 21 Apr 2008 03:47:43 -0300 Subject: V4L/DVB (7719): pvrusb2: Implement input selection enforcement In the pvrusb2 driver, different interfaces (e.g. V4L, DVB) have Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-context.c | 69 +++++++++++ drivers/media/video/pvrusb2/pvrusb2-context.h | 3 + drivers/media/video/pvrusb2/pvrusb2-dvb.c | 47 ++++---- drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 4 +- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 132 +++++++++++++++++---- drivers/media/video/pvrusb2/pvrusb2-hdw.h | 13 ++ drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 52 ++++---- 7 files changed, 246 insertions(+), 74 deletions(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index a2ce022c515..b5db6a5bab3 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -245,6 +245,22 @@ struct pvr2_context *pvr2_context_create( } +static void pvr2_context_reset_input_limits(struct pvr2_context *mp) +{ + unsigned int tmsk,mmsk; + struct pvr2_channel *cp; + struct pvr2_hdw *hdw = mp->hdw; + mmsk = pvr2_hdw_get_input_available(hdw); + tmsk = mmsk; + for (cp = mp->mc_first; cp; cp = cp->mc_next) { + if (!cp->input_mask) continue; + tmsk &= cp->input_mask; + } + pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk); + pvr2_hdw_commit_ctl(hdw); +} + + static void pvr2_context_enter(struct pvr2_context *mp) { mutex_lock(&mp->mutex); @@ -300,7 +316,9 @@ void pvr2_channel_done(struct pvr2_channel *cp) { struct pvr2_context *mp = cp->mc_head; pvr2_context_enter(mp); + cp->input_mask = 0; pvr2_channel_disclaim_stream(cp); + pvr2_context_reset_input_limits(mp); if (cp->mc_next) { cp->mc_next->mc_prev = cp->mc_prev; } else { @@ -316,6 +334,57 @@ void pvr2_channel_done(struct pvr2_channel *cp) } +int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk) +{ + unsigned int tmsk,mmsk; + int ret = 0; + struct pvr2_channel *p2; + struct pvr2_hdw *hdw = cp->hdw; + + mmsk = pvr2_hdw_get_input_available(hdw); + cmsk &= mmsk; + if (cmsk == cp->input_mask) { + /* No change; nothing to do */ + return 0; + } + + pvr2_context_enter(cp->mc_head); + do { + if (!cmsk) { + cp->input_mask = 0; + pvr2_context_reset_input_limits(cp->mc_head); + break; + } + tmsk = mmsk; + for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) { + if (p2 == cp) continue; + if (!p2->input_mask) continue; + tmsk &= p2->input_mask; + } + if (!(tmsk & cmsk)) { + ret = -EPERM; + break; + } + tmsk &= cmsk; + if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) { + /* Internal failure changing allowed list; probably + should not happen, but react if it does. */ + break; + } + cp->input_mask = cmsk; + pvr2_hdw_commit_ctl(hdw); + } while (0); + pvr2_context_exit(cp->mc_head); + return ret; +} + + +unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp) +{ + return cp->input_mask; +} + + int pvr2_channel_claim_stream(struct pvr2_channel *cp, struct pvr2_context_stream *sp) { diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h index 6fb6ab02285..745e270233c 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.h +++ b/drivers/media/video/pvrusb2/pvrusb2-context.h @@ -62,6 +62,7 @@ struct pvr2_channel { struct pvr2_channel *mc_prev; struct pvr2_context_stream *stream; struct pvr2_hdw *hdw; + unsigned int input_mask; void (*check_func)(struct pvr2_channel *); }; @@ -72,6 +73,8 @@ void pvr2_context_disconnect(struct pvr2_context *); void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *); void pvr2_channel_done(struct pvr2_channel *); +int pvr2_channel_limit_inputs(struct pvr2_channel *,unsigned int); +unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *); int pvr2_channel_claim_stream(struct pvr2_channel *, struct pvr2_context_stream *); struct pvr2_ioread *pvr2_channel_create_mpeg_stream( diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index c20eef0f077..2e64f98d124 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -244,13 +244,10 @@ static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) static int pvr2_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) { - /* TO DO: This function will call into the core and request for - * input to be set to 'dtv' if (acquire) and if it isn't set already. - * - * If (!acquire) then we should do nothing -- don't switch inputs - * again unless the analog side of the driver requests the bus. - */ - return 0; + struct pvr2_dvb_adapter *adap = fe->dvb->priv; + return pvr2_channel_limit_inputs( + &adap->channel, + (acquire ? (1 << PVR2_CVAL_INPUT_DTV) : 0)); } static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) @@ -320,32 +317,26 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) { struct pvr2_hdw *hdw = adap->channel.hdw; struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props; - int ret; + int ret = 0; if (dvb_props == NULL) { err("fe_props not defined!"); return -EINVAL; } - /* FIXME: This code should be moved into the core, - * and should only be called if we don't already have - * control of the bus. - * - * We can't call "pvr2_dvb_bus_ctrl(adap->fe, 1)" from here, - * because adap->fe isn't defined yet. - */ - ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_by_id(hdw, - PVR2_CID_INPUT), - PVR2_CVAL_INPUT_DTV); - if (ret != 0) + ret = pvr2_channel_limit_inputs( + &adap->channel, + (1 << PVR2_CVAL_INPUT_DTV)); + if (ret) { + err("failed to grab control of dtv input (code=%d)", + ret); return ret; - - pvr2_hdw_commit_ctl(hdw); - + } if (dvb_props->frontend_attach == NULL) { err("frontend_attach not defined!"); - return -EINVAL; + ret = -EINVAL; + goto done; } if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) { @@ -354,7 +345,8 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) err("frontend registration failed!"); dvb_frontend_detach(adap->fe); adap->fe = NULL; - return -ENODEV; + ret = -ENODEV; + goto done; } if (dvb_props->tuner_attach) @@ -368,10 +360,13 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) } else { err("no frontend was attached!"); - return -ENODEV; + ret = -ENODEV; + return ret; } - return 0; + done: + pvr2_channel_limit_inputs(&adap->channel, 0); + return ret; } static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index a67dcf84b59..a3fe251d6fd 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -336,8 +336,10 @@ struct pvr2_hdw { int v4l_minor_number_vbi; int v4l_minor_number_radio; - /* Bit mask of PVR2_CVAL_INPUT choices which are valid */ + /* Bit mask of PVR2_CVAL_INPUT choices which are valid for the hardware */ unsigned int input_avail_mask; + /* Bit mask of PVR2_CVAL_INPUT choices which are currenly allowed */ + unsigned int input_allowed_mask; /* Location of eeprom or a negative number if none */ int eeprom_addr; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 63d0af759ed..72e9056557b 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -249,6 +249,7 @@ static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = { }; +static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v); static void pvr2_hdw_state_sched(struct pvr2_hdw *); static int pvr2_hdw_state_eval(struct pvr2_hdw *); static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long); @@ -404,30 +405,12 @@ static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp) static int ctrl_check_input(struct pvr2_ctrl *cptr,int v) { - return ((1 << v) & cptr->hdw->input_avail_mask) != 0; + return ((1 << v) & cptr->hdw->input_allowed_mask) != 0; } static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v) { - struct pvr2_hdw *hdw = cptr->hdw; - - if (hdw->input_val != v) { - hdw->input_val = v; - hdw->input_dirty = !0; - } - - /* Handle side effects - if we switch to a mode that needs the RF - tuner, then select the right frequency choice as well and mark - it dirty. */ - if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { - hdw->freqSelector = 0; - hdw->freqDirty = !0; - } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) || - (hdw->input_val == PVR2_CVAL_INPUT_DTV)) { - hdw->freqSelector = 1; - hdw->freqDirty = !0; - } - return 0; + return pvr2_hdw_set_input(cptr->hdw,v); } static int ctrl_isdirty_input(struct pvr2_ctrl *cptr) @@ -1916,6 +1899,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE; if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO; hdw->input_avail_mask = m; + hdw->input_allowed_mask = hdw->input_avail_mask; /* If not a hybrid device, pathway_state never changes. So initialize it here to what it should forever be. */ @@ -3948,6 +3932,24 @@ static int pvr2_hdw_state_update(struct pvr2_hdw *hdw) } +static unsigned int print_input_mask(unsigned int msk, + char *buf,unsigned int acnt) +{ + unsigned int idx,ccnt; + unsigned int tcnt = 0; + for (idx = 0; idx < ARRAY_SIZE(control_values_input); idx++) { + if (!((1 << idx) & msk)) continue; + ccnt = scnprintf(buf+tcnt, + acnt-tcnt, + "%s%s", + (tcnt ? ", " : ""), + control_values_input[idx]); + tcnt += ccnt; + } + return tcnt; +} + + static const char *pvr2_pathway_state_name(int id) { switch (id) { @@ -4016,6 +4018,28 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, "state: %s", pvr2_get_state_name(hdw->master_state)); case 4: { + unsigned int tcnt = 0; + unsigned int ccnt; + + ccnt = scnprintf(buf, + acnt, + "Hardware supported inputs: "); + tcnt += ccnt; + tcnt += print_input_mask(hdw->input_avail_mask, + buf+tcnt, + acnt-tcnt); + if (hdw->input_avail_mask != hdw->input_allowed_mask) { + ccnt = scnprintf(buf+tcnt, + acnt-tcnt, + "; allowed inputs: "); + tcnt += ccnt; + tcnt += print_input_mask(hdw->input_allowed_mask, + buf+tcnt, + acnt-tcnt); + } + return tcnt; + } + case 5: { struct pvr2_stream_stats stats; if (!hdw->vid_stream) break; pvr2_stream_get_stats(hdw->vid_stream, @@ -4210,6 +4234,74 @@ unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw) } +unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *hdw) +{ + return hdw->input_allowed_mask; +} + + +static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v) +{ + if (hdw->input_val != v) { + hdw->input_val = v; + hdw->input_dirty = !0; + } + + /* Handle side effects - if we switch to a mode that needs the RF + tuner, then select the right frequency choice as well and mark + it dirty. */ + if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { + hdw->freqSelector = 0; + hdw->freqDirty = !0; + } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) || + (hdw->input_val == PVR2_CVAL_INPUT_DTV)) { + hdw->freqSelector = 1; + hdw->freqDirty = !0; + } + return 0; +} + + +int pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw, + unsigned int change_mask, + unsigned int change_val) +{ + int ret = 0; + unsigned int nv,m,idx; + LOCK_TAKE(hdw->big_lock); + do { + nv = hdw->input_allowed_mask & ~change_mask; + nv |= (change_val & change_mask); + nv &= hdw->input_avail_mask; + if (!nv) { + /* No legal modes left; return error instead. */ + ret = -EPERM; + break; + } + hdw->input_allowed_mask = nv; + if ((1 << hdw->input_val) & hdw->input_allowed_mask) { + /* Current mode is still in the allowed mask, so + we're done. */ + break; + } + /* Select and switch to a mode that is still in the allowed + mask */ + if (!hdw->input_allowed_mask) { + /* Nothing legal; give up */ + break; + } + m = hdw->input_allowed_mask; + for (idx = 0; idx < (sizeof(m) << 3); idx++) { + if (!((1 << idx) & m)) continue; + pvr2_hdw_set_input(hdw,idx); + break; + } + } while (0); + LOCK_GIVE(hdw->big_lock); + return ret; +} + + /* Find I2C address of eeprom */ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) { diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 74c2503f8e3..20295e0c199 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -149,6 +149,19 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *); * will be according to PVR_CVAL_INPUT_xxxx definitions. */ unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *); +/* Return a bit mask of allowed input selections for this device. Mask bits + * will be according to PVR_CVAL_INPUT_xxxx definitions. */ +unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *); + +/* Change the set of allowed input selections for this device. Both + change_mask and change_valu are mask bits according to + PVR_CVAL_INPUT_xxxx definitions. The change_mask parameter indicate + which settings are being changed and the change_val parameter indicates + whether corresponding settings are being set or cleared. */ +int pvr2_hdw_set_input_allowed(struct pvr2_hdw *, + unsigned int change_mask, + unsigned int change_val); + /* Return name for this driver instance */ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *); diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 249d7488e48..b415141b285 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -57,7 +57,6 @@ struct pvr2_v4l2_fh { struct pvr2_v4l2_fh *vprev; wait_queue_head_t wait_data; int fw_mode_flag; - int prev_input_val; }; struct pvr2_v4l2 { @@ -900,20 +899,6 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file) v4l2_prio_close(&vp->prio, &fhp->prio); file->private_data = NULL; - /* Restore the previous input selection, if it makes sense - to do so. */ - if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) { - struct pvr2_ctrl *cp; - int pval; - cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); - pvr2_ctrl_get_value(cp,&pval); - /* Only restore if we're still selecting the radio */ - if (pval == PVR2_CVAL_INPUT_RADIO) { - pvr2_ctrl_set_value(cp,fhp->prev_input_val); - pvr2_hdw_commit_ctl(hdw); - } - } - if (fhp->vnext) { fhp->vnext->vprev = fhp->vprev; } else { @@ -944,6 +929,8 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) struct pvr2_v4l2_fh *fhp; struct pvr2_v4l2 *vp; struct pvr2_hdw *hdw; + unsigned int input_mask = 0; + int ret = 0; dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase); @@ -969,6 +956,29 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp); pvr2_channel_init(&fhp->channel,vp->channel.mc_head); + if (dip->v4l_type == VFL_TYPE_RADIO) { + /* Opening device as a radio, legal input selection subset + is just the radio. */ + input_mask = (1 << PVR2_CVAL_INPUT_RADIO); + } else { + /* Opening the main V4L device, legal input selection + subset includes all analog inputs. */ + input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) | + (1 << PVR2_CVAL_INPUT_TV) | + (1 << PVR2_CVAL_INPUT_COMPOSITE) | + (1 << PVR2_CVAL_INPUT_SVIDEO)); + } + ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask); + if (ret) { + pvr2_channel_done(&fhp->channel); + pvr2_trace(PVR2_TRACE_STRUCT, + "Destroying pvr_v4l2_fh id=%p (input mask error)", + fhp); + + kfree(fhp); + return ret; + } + fhp->vnext = NULL; fhp->vprev = vp->vlast; if (vp->vlast) { @@ -979,18 +989,6 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) vp->vlast = fhp; fhp->vhead = vp; - /* Opening the /dev/radioX device implies a mode switch. - So execute that here. Note that you can get the - IDENTICAL effect merely by opening the normal video - device and setting the input appropriately. */ - if (dip->v4l_type == VFL_TYPE_RADIO) { - struct pvr2_ctrl *cp; - cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); - pvr2_ctrl_get_value(cp,&fhp->prev_input_val); - pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO); - pvr2_hdw_commit_ctl(hdw); - } - fhp->file = file; file->private_data = fhp; v4l2_prio_open(&vp->prio,&fhp->prio); -- cgit v1.2.3-70-g09d2 From a6a3a17b7fdaf824e6d73e8e4a94c9d149302f74 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Mon, 28 Apr 2008 16:50:03 -0700 Subject: media: fix integer as NULL pointer warnings drivers/media/video/v4l2-common.c:719:16: warning: Using plain integer as NULL pointer drivers/media/video/au0828/au0828-dvb.c:122:19: warning: Using plain integer as NULL pointer drivers/media/video/ivtv/ivtv-yuv.c:1101:22: warning: Using plain integer as NULL pointer drivers/media/video/ivtv/ivtv-yuv.c:1102:23: warning: Using plain integer as NULL pointer drivers/media/video/pvrusb2/pvrusb2-audio.c:78:39: warning: Using plain integer as NULL pointer drivers/media/video/pvrusb2/pvrusb2-video-v4l.c:84:39: warning: Using plain integer as NULL pointer drivers/media/video/pvrusb2/pvrusb2-v4l2.c:1264:9: warning: Using plain integer as NULL pointer drivers/media/video/pvrusb2/pvrusb2-context.c:197:28: warning: Using plain integer as NULL pointer drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c:126:39: warning: Using plain integer as NULL pointer drivers/media/video/pvrusb2/pvrusb2-dvb.c:133:32: warning: Using plain integer as NULL pointer drivers/media/video/pvrusb2/pvrusb2-dvb.c:145:31: warning: Using plain integer as NULL pointer drivers/media/video/pvrusb2/pvrusb2-dvb.c:177:55: warning: Using plain integer as NULL pointer drivers/media/video/videobuf-core.c:100:9: warning: Using plain integer as NULL pointer Signed-off-by: Harvey Harrison Signed-off-by: Linus Torvalds --- drivers/media/video/au0828/au0828-dvb.c | 2 +- drivers/media/video/ivtv/ivtv-yuv.c | 4 ++-- drivers/media/video/pvrusb2/pvrusb2-audio.c | 2 +- drivers/media/video/pvrusb2/pvrusb2-context.c | 2 +- drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c | 2 +- drivers/media/video/pvrusb2/pvrusb2-dvb.c | 6 +++--- drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 2 +- drivers/media/video/pvrusb2/pvrusb2-video-v4l.c | 2 +- drivers/media/video/v4l2-common.c | 2 +- drivers/media/video/videobuf-core.c | 5 ++++- 10 files changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers/media/video/pvrusb2/pvrusb2-dvb.c') diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c index 5040d7fc4af..1371b4e4b5f 100644 --- a/drivers/media/video/au0828/au0828-dvb.c +++ b/drivers/media/video/au0828/au0828-dvb.c @@ -119,7 +119,7 @@ static int start_urb_transfer(struct au0828_dev *dev) purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL); if (!purb->transfer_buffer) { usb_free_urb(purb); - dev->urbs[i] = 0; + dev->urbs[i] = NULL; goto err; } diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 393d917cd67..62f70bd5e3c 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -1098,8 +1098,8 @@ void ivtv_yuv_setup_stream_frame(struct ivtv *itv) ivtv_yuv_next_free(itv); /* Copy V4L2 parameters to an ivtv_dma_frame struct... */ - dma_args.y_source = 0L; - dma_args.uv_source = 0L; + dma_args.y_source = NULL; + dma_args.uv_source = NULL; dma_args.src.left = 0; dma_args.src.top = 0; dma_args.src.width = yi->v4l2_src_w; diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c index 9a7c8e9c3e8..8d859ccd48e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c @@ -75,7 +75,7 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt) pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo"); if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && + ((sp = routing_schemes + sid) != NULL) && (hdw->input_val >= 0) && (hdw->input_val < sp->cnt)) { route.input = sp->def[hdw->input_val]; diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index b5db6a5bab3..73dcb1c57ae 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -195,7 +195,7 @@ static int pvr2_context_thread_func(void *foo) int pvr2_context_global_init(void) { pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func, - 0, + NULL, "pvrusb2-context"); return (pvr2_context_thread_ptr ? 0 : -ENOMEM); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index 97350b048b8..29d50597c88 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -123,7 +123,7 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt) memset(&route,0,sizeof(route)); if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && + ((sp = routing_schemes + sid) != NULL) && (hdw->input_val >= 0) && (hdw->input_val < sp->cnt)) { vid_input = sp->def[hdw->input_val].vid; diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index 2e64f98d124..6504c97e0bb 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -130,7 +130,7 @@ static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap) 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->buffer_storage[idx] = NULL; } adap->stream_run = 0; } @@ -142,7 +142,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) unsigned int idx; int ret; struct pvr2_buffer *bp; - struct pvr2_stream *stream = 0; + struct pvr2_stream *stream = NULL; if (adap->stream_run) return -EIO; @@ -174,7 +174,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) ret = pvr2_hdw_set_streaming(adap->channel.hdw, 1); if (ret < 0) return ret; - while ((bp = pvr2_stream_get_idle_buffer(stream)) != 0) { + while ((bp = pvr2_stream_get_idle_buffer(stream)) != NULL) { ret = pvr2_buffer_queue(bp); if (ret < 0) return ret; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 087a1824556..e9b5d4e9132 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -1261,7 +1261,7 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) fail: pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp); pvr2_v4l2_destroy_no_lock(vp); - return 0; + return NULL; } /* diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index 7c47345501b..2433a316004 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -81,7 +81,7 @@ static void set_input(struct pvr2_v4l_decoder *ctxt) pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val); if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && + ((sp = routing_schemes + sid) != NULL) && (hdw->input_val >= 0) && (hdw->input_val < sp->cnt)) { route.input = sp->def[hdw->input_val]; diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 34deb68ae56..7cc42c1da45 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -716,7 +716,7 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver int err; client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) + if (!client) return -ENOMEM; client->addr = address; diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index fc51e4918bb..982f4463896 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -97,7 +97,10 @@ int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, void *videobuf_queue_to_vmalloc (struct videobuf_queue *q, struct videobuf_buffer *buf) { - return CALL(q, vmalloc, buf); + if (q->int_ops->vmalloc) + return q->int_ops->vmalloc(buf); + else + return NULL; } EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc); -- cgit v1.2.3-70-g09d2