diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2007-10-13 04:54:48 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-10-22 10:01:47 -0400 |
commit | 18e16f9c954c6a931ee97584014c826255e0bdaa (patch) | |
tree | 14a5833adcd021af9206f47c8530ec83c9bd3ae3 /drivers/media/video/ivtv/ivtv-streams.c | |
parent | 34ca7d3791c6a467ff6810a149bdf78be086c23a (diff) |
V4L/DVB (6342): ivtv: fix circular locking (bug 9037)
If you try to access the video device from within an udev rule,
then you get into a circular locking situation.
Changed the driver to postpone the registration of the devices until
everything else has been fully initialized, so that the newly created
device can be used immediately.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-streams.c')
-rw-r--r-- | drivers/media/video/ivtv/ivtv-streams.c | 100 |
1 files changed, 58 insertions, 42 deletions
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index ff4cb16a3439..6c954b36ee88 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c | |||
@@ -166,10 +166,9 @@ static void ivtv_stream_init(struct ivtv *itv, int type) | |||
166 | ivtv_queue_init(&s->q_io); | 166 | ivtv_queue_init(&s->q_io); |
167 | } | 167 | } |
168 | 168 | ||
169 | static int ivtv_reg_dev(struct ivtv *itv, int type) | 169 | static int ivtv_prep_dev(struct ivtv *itv, int type) |
170 | { | 170 | { |
171 | struct ivtv_stream *s = &itv->streams[type]; | 171 | struct ivtv_stream *s = &itv->streams[type]; |
172 | int vfl_type = ivtv_stream_info[type].vfl_type; | ||
173 | int minor_offset = ivtv_stream_info[type].minor_offset; | 172 | int minor_offset = ivtv_stream_info[type].minor_offset; |
174 | int minor; | 173 | int minor; |
175 | 174 | ||
@@ -187,15 +186,12 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) | |||
187 | if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | 186 | if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) |
188 | return 0; | 187 | return 0; |
189 | 188 | ||
190 | if (minor_offset >= 0) | 189 | /* card number + user defined offset + device offset */ |
191 | /* card number + user defined offset + device offset */ | 190 | minor = itv->num + ivtv_first_minor + minor_offset; |
192 | minor = itv->num + ivtv_first_minor + minor_offset; | ||
193 | else | ||
194 | minor = -1; | ||
195 | 191 | ||
196 | /* User explicitly selected 0 buffers for these streams, so don't | 192 | /* User explicitly selected 0 buffers for these streams, so don't |
197 | create them. */ | 193 | create them. */ |
198 | if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE && | 194 | if (ivtv_stream_info[type].dma != PCI_DMA_NONE && |
199 | itv->options.kilobytes[type] == 0) { | 195 | itv->options.kilobytes[type] == 0) { |
200 | IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); | 196 | IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); |
201 | return 0; | 197 | return 0; |
@@ -223,21 +219,53 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) | |||
223 | s->v4l2dev->fops = ivtv_stream_info[type].fops; | 219 | s->v4l2dev->fops = ivtv_stream_info[type].fops; |
224 | s->v4l2dev->release = video_device_release; | 220 | s->v4l2dev->release = video_device_release; |
225 | 221 | ||
226 | if (minor >= 0) { | 222 | return 0; |
227 | /* Register device. First try the desired minor, then any free one. */ | 223 | } |
228 | if (video_register_device(s->v4l2dev, vfl_type, minor) && | 224 | |
229 | video_register_device(s->v4l2dev, vfl_type, -1)) { | 225 | /* Initialize v4l2 variables and prepare v4l2 devices */ |
230 | IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n", | 226 | int ivtv_streams_setup(struct ivtv *itv) |
231 | s->name, minor); | 227 | { |
232 | video_device_release(s->v4l2dev); | 228 | int type; |
233 | s->v4l2dev = NULL; | 229 | |
234 | return -ENOMEM; | 230 | /* Setup V4L2 Devices */ |
235 | } | 231 | for (type = 0; type < IVTV_MAX_STREAMS; type++) { |
232 | /* Prepare device */ | ||
233 | if (ivtv_prep_dev(itv, type)) | ||
234 | break; | ||
235 | |||
236 | if (itv->streams[type].v4l2dev == NULL) | ||
237 | continue; | ||
238 | |||
239 | /* Allocate Stream */ | ||
240 | if (ivtv_stream_alloc(&itv->streams[type])) | ||
241 | break; | ||
236 | } | 242 | } |
237 | else { | 243 | if (type == IVTV_MAX_STREAMS) |
238 | /* Don't register a 'hidden' stream (OSD) */ | ||
239 | IVTV_INFO("Created framebuffer stream for %s\n", s->name); | ||
240 | return 0; | 244 | return 0; |
245 | |||
246 | /* One or more streams could not be initialized. Clean 'em all up. */ | ||
247 | ivtv_streams_cleanup(itv); | ||
248 | return -ENOMEM; | ||
249 | } | ||
250 | |||
251 | static int ivtv_reg_dev(struct ivtv *itv, int type) | ||
252 | { | ||
253 | struct ivtv_stream *s = &itv->streams[type]; | ||
254 | int vfl_type = ivtv_stream_info[type].vfl_type; | ||
255 | int minor; | ||
256 | |||
257 | if (s->v4l2dev == NULL) | ||
258 | return 0; | ||
259 | |||
260 | minor = s->v4l2dev->minor; | ||
261 | /* Register device. First try the desired minor, then any free one. */ | ||
262 | if (video_register_device(s->v4l2dev, vfl_type, minor) && | ||
263 | video_register_device(s->v4l2dev, vfl_type, -1)) { | ||
264 | IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n", | ||
265 | s->name, minor); | ||
266 | video_device_release(s->v4l2dev); | ||
267 | s->v4l2dev = NULL; | ||
268 | return -ENOMEM; | ||
241 | } | 269 | } |
242 | 270 | ||
243 | switch (vfl_type) { | 271 | switch (vfl_type) { |
@@ -262,27 +290,18 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) | |||
262 | return 0; | 290 | return 0; |
263 | } | 291 | } |
264 | 292 | ||
265 | /* Initialize v4l2 variables and register v4l2 devices */ | 293 | /* Register v4l2 devices */ |
266 | int ivtv_streams_setup(struct ivtv *itv) | 294 | int ivtv_streams_register(struct ivtv *itv) |
267 | { | 295 | { |
268 | int type; | 296 | int type; |
297 | int err = 0; | ||
269 | 298 | ||
270 | /* Setup V4L2 Devices */ | 299 | /* Register V4L2 devices */ |
271 | for (type = 0; type < IVTV_MAX_STREAMS; type++) { | 300 | for (type = 0; type < IVTV_MAX_STREAMS; type++) |
272 | /* Register Device */ | 301 | err |= ivtv_reg_dev(itv, type); |
273 | if (ivtv_reg_dev(itv, type)) | ||
274 | break; | ||
275 | |||
276 | if (itv->streams[type].v4l2dev == NULL) | ||
277 | continue; | ||
278 | 302 | ||
279 | /* Allocate Stream */ | 303 | if (err == 0) |
280 | if (ivtv_stream_alloc(&itv->streams[type])) | ||
281 | break; | ||
282 | } | ||
283 | if (type == IVTV_MAX_STREAMS) { | ||
284 | return 0; | 304 | return 0; |
285 | } | ||
286 | 305 | ||
287 | /* One or more streams could not be initialized. Clean 'em all up. */ | 306 | /* One or more streams could not be initialized. Clean 'em all up. */ |
288 | ivtv_streams_cleanup(itv); | 307 | ivtv_streams_cleanup(itv); |
@@ -303,11 +322,8 @@ void ivtv_streams_cleanup(struct ivtv *itv) | |||
303 | continue; | 322 | continue; |
304 | 323 | ||
305 | ivtv_stream_free(&itv->streams[type]); | 324 | ivtv_stream_free(&itv->streams[type]); |
306 | /* Free Device */ | 325 | /* Unregister device */ |
307 | if (vdev->minor == -1) /* 'Hidden' never registered stream (OSD) */ | 326 | video_unregister_device(vdev); |
308 | video_device_release(vdev); | ||
309 | else /* All others, just unregister. */ | ||
310 | video_unregister_device(vdev); | ||
311 | } | 327 | } |
312 | } | 328 | } |
313 | 329 | ||