diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-11-10 23:08:26 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:02:06 -0500 |
commit | a225452ef80a7bd894fd2dfd01a4973d444152f4 (patch) | |
tree | 397c483c75751106545ef989d83fe25a7c57347b /drivers/media | |
parent | a3a048cea301baba5d451991074a85dc20a8f228 (diff) |
V4L/DVB (6583): Fix em28xx read stream locking
On some situations, closing an streaming application and re-opening were
returning -EBUSY.
Uses the same locking schema also present on cx88.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 77 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 5 |
2 files changed, 59 insertions, 23 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 5b17ca9cad11..f0191779a8e2 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -225,6 +225,44 @@ static void video_mux(struct em28xx *dev, int index) | |||
225 | } | 225 | } |
226 | } | 226 | } |
227 | 227 | ||
228 | /* Usage lock check functions */ | ||
229 | static int res_get(struct em28xx_fh *fh) | ||
230 | { | ||
231 | struct em28xx *dev = fh->dev; | ||
232 | int rc = 0; | ||
233 | |||
234 | /* This instance already has stream_on */ | ||
235 | if (fh->stream_on) | ||
236 | return rc; | ||
237 | |||
238 | mutex_lock(&dev->lock); | ||
239 | |||
240 | if (dev->stream_on) | ||
241 | rc = -EINVAL; | ||
242 | else { | ||
243 | dev->stream_on = 1; | ||
244 | fh->stream_on = 1; | ||
245 | } | ||
246 | |||
247 | mutex_unlock(&dev->lock); | ||
248 | return rc; | ||
249 | } | ||
250 | |||
251 | static int res_check(struct em28xx_fh *fh) | ||
252 | { | ||
253 | return (fh->stream_on); | ||
254 | } | ||
255 | |||
256 | static void res_free(struct em28xx_fh *fh) | ||
257 | { | ||
258 | struct em28xx *dev = fh->dev; | ||
259 | |||
260 | mutex_lock(&dev->lock); | ||
261 | fh->stream_on = 0; | ||
262 | dev->stream_on = 0; | ||
263 | mutex_unlock(&dev->lock); | ||
264 | } | ||
265 | |||
228 | /* | 266 | /* |
229 | * em28xx_v4l2_open() | 267 | * em28xx_v4l2_open() |
230 | * inits the device and starts isoc transfer | 268 | * inits the device and starts isoc transfer |
@@ -328,15 +366,16 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) | |||
328 | 366 | ||
329 | em28xx_videodbg("users=%d\n", dev->users); | 367 | em28xx_videodbg("users=%d\n", dev->users); |
330 | 368 | ||
369 | |||
370 | if (res_check(fh)) | ||
371 | res_free(fh); | ||
372 | |||
331 | mutex_lock(&dev->lock); | 373 | mutex_lock(&dev->lock); |
332 | if (fh->reader == 1) | ||
333 | fh->reader = 0; | ||
334 | 374 | ||
335 | if (dev->users == 1) { | 375 | if (dev->users == 1) { |
336 | dev->reader = 0; | ||
337 | |||
338 | em28xx_uninit_isoc(dev); | 376 | em28xx_uninit_isoc(dev); |
339 | em28xx_release_buffers(dev); | 377 | em28xx_release_buffers(dev); |
378 | dev->io = IO_NONE; | ||
340 | 379 | ||
341 | /* the device is already disconnect, | 380 | /* the device is already disconnect, |
342 | free the remaining resources */ | 381 | free the remaining resources */ |
@@ -377,16 +416,15 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, | |||
377 | struct em28xx_fh *fh = filp->private_data; | 416 | struct em28xx_fh *fh = filp->private_data; |
378 | struct em28xx *dev = fh->dev; | 417 | struct em28xx *dev = fh->dev; |
379 | 418 | ||
419 | |||
420 | if (unlikely(res_get(fh) < 0)) | ||
421 | return -EBUSY; | ||
422 | |||
380 | mutex_lock(&dev->lock); | 423 | mutex_lock(&dev->lock); |
381 | 424 | ||
382 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | 425 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
383 | em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); | 426 | em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); |
384 | 427 | ||
385 | if (dev->reader > 0 && fh->reader == 0) { | ||
386 | mutex_unlock(&dev->lock); | ||
387 | return -EBUSY; | ||
388 | } | ||
389 | |||
390 | if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | 428 | if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { |
391 | em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); | 429 | em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); |
392 | em28xx_videodbg("not supported yet! ...\n"); | 430 | em28xx_videodbg("not supported yet! ...\n"); |
@@ -425,9 +463,6 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, | |||
425 | " the device again to choose the read method\n"); | 463 | " the device again to choose the read method\n"); |
426 | mutex_unlock(&dev->lock); | 464 | mutex_unlock(&dev->lock); |
427 | return -EINVAL; | 465 | return -EINVAL; |
428 | } else { | ||
429 | dev->reader = 1; | ||
430 | fh->reader = 1; | ||
431 | } | 466 | } |
432 | 467 | ||
433 | if (dev->io == IO_NONE) { | 468 | if (dev->io == IO_NONE) { |
@@ -499,6 +534,9 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) | |||
499 | struct em28xx_fh *fh = filp->private_data; | 534 | struct em28xx_fh *fh = filp->private_data; |
500 | struct em28xx *dev = fh->dev; | 535 | struct em28xx *dev = fh->dev; |
501 | 536 | ||
537 | if (unlikely(res_get(fh) < 0)) | ||
538 | return POLLERR; | ||
539 | |||
502 | mutex_lock(&dev->lock); | 540 | mutex_lock(&dev->lock); |
503 | 541 | ||
504 | if (dev->state & DEV_DISCONNECTED) { | 542 | if (dev->state & DEV_DISCONNECTED) { |
@@ -572,15 +610,10 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) | |||
572 | void *pos; | 610 | void *pos; |
573 | u32 i; | 611 | u32 i; |
574 | 612 | ||
575 | mutex_lock(&dev->lock); | 613 | if (unlikely(res_get(fh) < 0)) |
576 | |||
577 | if (dev->reader > 0 && fh->reader == 0) { | ||
578 | mutex_unlock(&dev->lock); | ||
579 | return -EBUSY; | 614 | return -EBUSY; |
580 | } else { | 615 | |
581 | dev->reader = 1; | 616 | mutex_lock(&dev->lock); |
582 | fh->reader = 1; | ||
583 | } | ||
584 | 617 | ||
585 | if (dev->state & DEV_DISCONNECTED) { | 618 | if (dev->state & DEV_DISCONNECTED) { |
586 | em28xx_videodbg("mmap: device not present\n"); | 619 | em28xx_videodbg("mmap: device not present\n"); |
@@ -1219,6 +1252,9 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, | |||
1219 | if (list_empty(&dev->inqueue)) | 1252 | if (list_empty(&dev->inqueue)) |
1220 | return -EINVAL; | 1253 | return -EINVAL; |
1221 | 1254 | ||
1255 | if (unlikely(res_get(fh) < 0)) | ||
1256 | return -EBUSY; | ||
1257 | |||
1222 | dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ | 1258 | dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ |
1223 | 1259 | ||
1224 | em28xx_videodbg("VIDIOC_STREAMON: starting stream\n"); | 1260 | em28xx_videodbg("VIDIOC_STREAMON: starting stream\n"); |
@@ -1243,7 +1279,6 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, | |||
1243 | } | 1279 | } |
1244 | } | 1280 | } |
1245 | 1281 | ||
1246 | fh->reader = 0; | ||
1247 | em28xx_empty_framequeues(dev); | 1282 | em28xx_empty_framequeues(dev); |
1248 | mutex_unlock(&dev->lock); | 1283 | mutex_unlock(&dev->lock); |
1249 | 1284 | ||
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index f8ad0f4ae6d2..3efc05d2df67 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -224,6 +224,8 @@ struct em28xx { | |||
224 | unsigned int has_msp34xx:1; | 224 | unsigned int has_msp34xx:1; |
225 | unsigned int has_tda9887:1; | 225 | unsigned int has_tda9887:1; |
226 | 226 | ||
227 | unsigned int stream_on:1; /* Locks streams */ | ||
228 | |||
227 | u32 i2s_speed; /* I2S speed for audio digital stream */ | 229 | u32 i2s_speed; /* I2S speed for audio digital stream */ |
228 | 230 | ||
229 | enum em28xx_decoder decoder; | 231 | enum em28xx_decoder decoder; |
@@ -258,7 +260,6 @@ struct em28xx { | |||
258 | int vscale; /* vertical scale factor (see datasheet) */ | 260 | int vscale; /* vertical scale factor (see datasheet) */ |
259 | int interlaced; /* 1=interlace fileds, 0=just top fileds */ | 261 | int interlaced; /* 1=interlace fileds, 0=just top fileds */ |
260 | int type; | 262 | int type; |
261 | unsigned int reader:1; | ||
262 | 263 | ||
263 | unsigned long hash; /* eeprom hash - for boards with generic ID */ | 264 | unsigned long hash; /* eeprom hash - for boards with generic ID */ |
264 | unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ | 265 | unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ |
@@ -297,7 +298,7 @@ struct em28xx { | |||
297 | 298 | ||
298 | struct em28xx_fh { | 299 | struct em28xx_fh { |
299 | struct em28xx *dev; | 300 | struct em28xx *dev; |
300 | unsigned int reader:1; | 301 | unsigned int stream_on:1; /* Locks streams */ |
301 | }; | 302 | }; |
302 | 303 | ||
303 | /* Provided by em28xx-i2c.c */ | 304 | /* Provided by em28xx-i2c.c */ |