aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2007-10-13 04:54:48 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-10-22 10:01:47 -0400
commit18e16f9c954c6a931ee97584014c826255e0bdaa (patch)
tree14a5833adcd021af9206f47c8530ec83c9bd3ae3
parent34ca7d3791c6a467ff6810a149bdf78be086c23a (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>
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c11
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c100
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.h1
3 files changed, 65 insertions, 47 deletions
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index fd7a932e1d33..6d2dd8764f81 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1003,8 +1003,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
1003 1003
1004 IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr); 1004 IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);
1005 1005
1006 mutex_lock(&itv->serialize_lock);
1007
1008 /* PCI Device Setup */ 1006 /* PCI Device Setup */
1009 if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) { 1007 if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) {
1010 if (retval == -EIO) 1008 if (retval == -EIO)
@@ -1064,7 +1062,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
1064 IVTV_DEBUG_INFO("activating i2c...\n"); 1062 IVTV_DEBUG_INFO("activating i2c...\n");
1065 if (init_ivtv_i2c(itv)) { 1063 if (init_ivtv_i2c(itv)) {
1066 IVTV_ERR("Could not initialize i2c\n"); 1064 IVTV_ERR("Could not initialize i2c\n");
1067 goto free_irq; 1065 goto free_io;
1068 } 1066 }
1069 1067
1070 IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active); 1068 IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
@@ -1176,7 +1174,11 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
1176 IVTV_ERR("Failed to register irq %d\n", retval); 1174 IVTV_ERR("Failed to register irq %d\n", retval);
1177 goto free_streams; 1175 goto free_streams;
1178 } 1176 }
1179 mutex_unlock(&itv->serialize_lock); 1177 retval = ivtv_streams_register(itv);
1178 if (retval) {
1179 IVTV_ERR("Error %d registering devices\n", retval);
1180 goto free_irq;
1181 }
1180 IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); 1182 IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
1181 return 0; 1183 return 0;
1182 1184
@@ -1195,7 +1197,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
1195 release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); 1197 release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
1196 free_workqueue: 1198 free_workqueue:
1197 destroy_workqueue(itv->irq_work_queues); 1199 destroy_workqueue(itv->irq_work_queues);
1198 mutex_unlock(&itv->serialize_lock);
1199 err: 1200 err:
1200 if (retval == 0) 1201 if (retval == 0)
1201 retval = -ENODEV; 1202 retval = -ENODEV;
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
169static int ivtv_reg_dev(struct ivtv *itv, int type) 169static 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", 226int 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
251static 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 */
266int ivtv_streams_setup(struct ivtv *itv) 294int 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
diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h
index 8f5f5b1c7c89..3d76a415fbd8 100644
--- a/drivers/media/video/ivtv/ivtv-streams.h
+++ b/drivers/media/video/ivtv/ivtv-streams.h
@@ -22,6 +22,7 @@
22#define IVTV_STREAMS_H 22#define IVTV_STREAMS_H
23 23
24int ivtv_streams_setup(struct ivtv *itv); 24int ivtv_streams_setup(struct ivtv *itv);
25int ivtv_streams_register(struct ivtv *itv);
25void ivtv_streams_cleanup(struct ivtv *itv); 26void ivtv_streams_cleanup(struct ivtv *itv);
26 27
27/* Capture related */ 28/* Capture related */