diff options
author | Darron Broad <darron@kewl.org> | 2008-10-15 12:48:43 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-17 16:28:41 -0400 |
commit | e43f3fab0514647e563ee8b5baf4ce100dd5caa5 (patch) | |
tree | 93d8088eb167d8d76ea06a7e66c5c44f0546c2fa | |
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>
-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 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, | |||
145 | { | 145 | { |
146 | struct list_head *list, *q; | 146 | struct list_head *list, *q; |
147 | struct videobuf_dvb_frontend *fe; | 147 | struct videobuf_dvb_frontend *fe; |
148 | int res = -EINVAL; | 148 | int res; |
149 | 149 | ||
150 | fe = videobuf_dvb_get_frontend(f, 1); | 150 | fe = videobuf_dvb_get_frontend(f, 1); |
151 | if (!fe) { | 151 | if (!fe) { |
152 | printk(KERN_WARNING "Unable to register the adapter which has no frontends\n"); | 152 | printk(KERN_WARNING "Unable to register the adapter which has no frontends\n"); |
153 | goto err; | 153 | return -EINVAL; |
154 | } | 154 | } |
155 | 155 | ||
156 | /* Bring up the adapter */ | 156 | /* Bring up the adapter */ |
157 | res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, fe->dvb.name, adapter_nr, mfe_shared); | 157 | res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, fe->dvb.name, adapter_nr, mfe_shared); |
158 | if (res < 0) { | 158 | if (res < 0) { |
159 | printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); | 159 | printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); |
160 | goto err; | 160 | return res; |
161 | } | 161 | } |
162 | 162 | ||
163 | /* Attach all of the frontends to the adapter */ | 163 | /* Attach all of the frontends to the adapter */ |
@@ -168,11 +168,15 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, | |||
168 | if (res < 0) { | 168 | if (res < 0) { |
169 | printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n", | 169 | printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n", |
170 | fe->dvb.name, res); | 170 | fe->dvb.name, res); |
171 | goto err; | ||
171 | } | 172 | } |
172 | } | 173 | } |
173 | mutex_unlock(&f->lock); | 174 | mutex_unlock(&f->lock); |
175 | return 0; | ||
174 | 176 | ||
175 | err: | 177 | err: |
178 | mutex_unlock(&f->lock); | ||
179 | videobuf_dvb_unregister_bus(f); | ||
176 | return res; | 180 | return res; |
177 | } | 181 | } |
178 | 182 | ||
@@ -264,6 +268,10 @@ int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_ | |||
264 | 268 | ||
265 | /* register network adapter */ | 269 | /* register network adapter */ |
266 | dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); | 270 | dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); |
271 | if (dvb->net.dvbdev == NULL) { | ||
272 | result = -ENOMEM; | ||
273 | goto fail_fe_conn; | ||
274 | } | ||
267 | return 0; | 275 | return 0; |
268 | 276 | ||
269 | fail_fe_conn: | 277 | fail_fe_conn: |
@@ -278,7 +286,7 @@ fail_dmx: | |||
278 | dvb_unregister_frontend(dvb->frontend); | 286 | dvb_unregister_frontend(dvb->frontend); |
279 | fail_frontend: | 287 | fail_frontend: |
280 | dvb_frontend_detach(dvb->frontend); | 288 | dvb_frontend_detach(dvb->frontend); |
281 | dvb_unregister_adapter(adapter); | 289 | dvb->frontend = NULL; |
282 | 290 | ||
283 | return result; | 291 | return result; |
284 | } | 292 | } |
@@ -291,15 +299,18 @@ void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f) | |||
291 | mutex_lock(&f->lock); | 299 | mutex_lock(&f->lock); |
292 | list_for_each_safe(list, q, &f->felist) { | 300 | list_for_each_safe(list, q, &f->felist) { |
293 | fe = list_entry(list, struct videobuf_dvb_frontend, felist); | 301 | fe = list_entry(list, struct videobuf_dvb_frontend, felist); |
294 | 302 | if(fe->dvb.net.dvbdev) { | |
295 | dvb_net_release(&fe->dvb.net); | 303 | dvb_net_release(&fe->dvb.net); |
296 | fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_mem); | 304 | fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_mem); |
297 | fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_hw); | 305 | fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_hw); |
298 | dvb_dmxdev_release(&fe->dvb.dmxdev); | 306 | dvb_dmxdev_release(&fe->dvb.dmxdev); |
299 | dvb_dmx_release(&fe->dvb.demux); | 307 | dvb_dmx_release(&fe->dvb.demux); |
300 | dvb_unregister_frontend(fe->dvb.frontend); | 308 | dvb_unregister_frontend(fe->dvb.frontend); |
301 | dvb_frontend_detach(fe->dvb.frontend); | 309 | } |
302 | 310 | if(fe->dvb.frontend) { /* always allocated, may have been reset */ | |
311 | dvb_frontend_detach(fe->dvb.frontend); | ||
312 | fe->dvb.frontend = NULL; | ||
313 | } | ||
303 | list_del(list); | 314 | list_del(list); |
304 | kfree(fe); | 315 | kfree(fe); |
305 | } | 316 | } |