diff options
author | Darron Broad <darron@kewl.org> | 2008-10-15 13:48:43 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-17 17:28:41 -0300 |
commit | e43f3fab0514647e563ee8b5baf4ce100dd5caa5 (patch) | |
tree | 93d8088eb167d8d76ea06a7e66c5c44f0546c2fa /drivers/media/video | |
parent | 7bdf84fc47f2d2ed2194b6ade480d043207c4098 (diff) |
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>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/videobuf-dvb.c | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c index fc4cfaa7bf5..7c74845af26 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); } |