summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarron Broad <darron@kewl.org>2008-10-15 13:48:43 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-10-17 17:28:41 -0300
commite43f3fab0514647e563ee8b5baf4ce100dd5caa5 (patch)
tree93d8088eb167d8d76ea06a7e66c5c44f0546c2fa
parent7bdf84fc47f2d2ed2194b6ade480d043207c4098 (diff)
downloadkernel-common-e43f3fab0514647e563ee8b5baf4ce100dd5caa5.tar.gz
kernel-common-e43f3fab0514647e563ee8b5baf4ce100dd5caa5.tar.bz2
kernel-common-e43f3fab0514647e563ee8b5baf4ce100dd5caa5.zip
V4L/DVB (9266): videobuf: properly handle attachment failure
This fixes attachment failure where we now unwind attachment and skip non-attached nodes where necessary so we can survive a fault situation correctly. Signed-off-by: Darron Broad <darron@kewl.org> Signed-off-by: Steven Toth <stoth@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/videobuf-dvb.c37
1 files changed, 24 insertions, 13 deletions
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index fc4cfaa7bf5f..7c74845af267 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -145,19 +145,19 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
{
struct list_head *list, *q;
struct videobuf_dvb_frontend *fe;
- int res = -EINVAL;
+ int res;
fe = videobuf_dvb_get_frontend(f, 1);
if (!fe) {
printk(KERN_WARNING "Unable to register the adapter which has no frontends\n");
- goto err;
+ return -EINVAL;
}
/* Bring up the adapter */
res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, fe->dvb.name, adapter_nr, mfe_shared);
if (res < 0) {
printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res);
- goto err;
+ return res;
}
/* Attach all of the frontends to the adapter */
@@ -168,11 +168,15 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
if (res < 0) {
printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n",
fe->dvb.name, res);
+ goto err;
}
}
mutex_unlock(&f->lock);
+ return 0;
err:
+ mutex_unlock(&f->lock);
+ videobuf_dvb_unregister_bus(f);
return res;
}
@@ -264,6 +268,10 @@ int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_
/* register network adapter */
dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx);
+ if (dvb->net.dvbdev == NULL) {
+ result = -ENOMEM;
+ goto fail_fe_conn;
+ }
return 0;
fail_fe_conn:
@@ -278,7 +286,7 @@ fail_dmx:
dvb_unregister_frontend(dvb->frontend);
fail_frontend:
dvb_frontend_detach(dvb->frontend);
- dvb_unregister_adapter(adapter);
+ dvb->frontend = NULL;
return result;
}
@@ -291,15 +299,18 @@ void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f)
mutex_lock(&f->lock);
list_for_each_safe(list, q, &f->felist) {
fe = list_entry(list, struct videobuf_dvb_frontend, felist);
-
- dvb_net_release(&fe->dvb.net);
- fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_mem);
- fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_hw);
- dvb_dmxdev_release(&fe->dvb.dmxdev);
- dvb_dmx_release(&fe->dvb.demux);
- dvb_unregister_frontend(fe->dvb.frontend);
- dvb_frontend_detach(fe->dvb.frontend);
-
+ if(fe->dvb.net.dvbdev) {
+ dvb_net_release(&fe->dvb.net);
+ fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_mem);
+ fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_hw);
+ dvb_dmxdev_release(&fe->dvb.dmxdev);
+ dvb_dmx_release(&fe->dvb.demux);
+ dvb_unregister_frontend(fe->dvb.frontend);
+ }
+ if(fe->dvb.frontend) { /* always allocated, may have been reset */
+ dvb_frontend_detach(fe->dvb.frontend);
+ fe->dvb.frontend = NULL;
+ }
list_del(list);
kfree(fe);
}