diff options
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 151 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 2 |
2 files changed, 80 insertions, 73 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 18b8568c634c..bc495a11dc2d 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -126,8 +126,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { | |||
126 | 126 | ||
127 | static struct usb_driver em28xx_usb_driver; | 127 | static struct usb_driver em28xx_usb_driver; |
128 | 128 | ||
129 | static DEFINE_MUTEX(em28xx_sysfs_lock); | ||
130 | static DECLARE_RWSEM(em28xx_disconnect); | ||
131 | 129 | ||
132 | /********************* v4l2 interface ******************************************/ | 130 | /********************* v4l2 interface ******************************************/ |
133 | 131 | ||
@@ -253,22 +251,18 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
253 | em28xx_videodbg("open minor=%d type=%s users=%d\n", | 251 | em28xx_videodbg("open minor=%d type=%s users=%d\n", |
254 | minor,v4l2_type_names[dev->type],dev->users); | 252 | minor,v4l2_type_names[dev->type],dev->users); |
255 | 253 | ||
256 | if (!down_read_trylock(&em28xx_disconnect)) | 254 | mutex_lock(&dev->lock); |
257 | return -ERESTARTSYS; | ||
258 | 255 | ||
259 | if (dev->users) { | 256 | if (dev->users) { |
260 | em28xx_warn("this driver can be opened only once\n"); | 257 | em28xx_warn("this driver can be opened only once\n"); |
261 | up_read(&em28xx_disconnect); | 258 | mutex_unlock(&dev->lock); |
262 | return -EBUSY; | 259 | return -EBUSY; |
263 | } | 260 | } |
264 | 261 | ||
265 | mutex_init(&dev->fileop_lock); /* to 1 == available */ | ||
266 | spin_lock_init(&dev->queue_lock); | 262 | spin_lock_init(&dev->queue_lock); |
267 | init_waitqueue_head(&dev->wait_frame); | 263 | init_waitqueue_head(&dev->wait_frame); |
268 | init_waitqueue_head(&dev->wait_stream); | 264 | init_waitqueue_head(&dev->wait_stream); |
269 | 265 | ||
270 | mutex_lock(&dev->lock); | ||
271 | |||
272 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 266 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
273 | em28xx_set_alternate(dev); | 267 | em28xx_set_alternate(dev); |
274 | 268 | ||
@@ -306,7 +300,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) | |||
306 | 300 | ||
307 | err: | 301 | err: |
308 | mutex_unlock(&dev->lock); | 302 | mutex_unlock(&dev->lock); |
309 | up_read(&em28xx_disconnect); | ||
310 | return errCode; | 303 | return errCode; |
311 | } | 304 | } |
312 | 305 | ||
@@ -317,7 +310,6 @@ err: | |||
317 | */ | 310 | */ |
318 | static void em28xx_release_resources(struct em28xx *dev) | 311 | static void em28xx_release_resources(struct em28xx *dev) |
319 | { | 312 | { |
320 | mutex_lock(&em28xx_sysfs_lock); | ||
321 | 313 | ||
322 | /*FIXME: I2C IR should be disconnected */ | 314 | /*FIXME: I2C IR should be disconnected */ |
323 | 315 | ||
@@ -329,7 +321,6 @@ static void em28xx_release_resources(struct em28xx *dev) | |||
329 | video_unregister_device(dev->vbi_dev); | 321 | video_unregister_device(dev->vbi_dev); |
330 | em28xx_i2c_unregister(dev); | 322 | em28xx_i2c_unregister(dev); |
331 | usb_put_dev(dev->udev); | 323 | usb_put_dev(dev->udev); |
332 | mutex_unlock(&em28xx_sysfs_lock); | ||
333 | 324 | ||
334 | 325 | ||
335 | /* Mark device as unused */ | 326 | /* Mark device as unused */ |
@@ -389,6 +380,8 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, | |||
389 | int ret = 0; | 380 | int ret = 0; |
390 | struct em28xx *dev = filp->private_data; | 381 | struct em28xx *dev = filp->private_data; |
391 | 382 | ||
383 | mutex_lock(&dev->lock); | ||
384 | |||
392 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 385 | if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
393 | em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); | 386 | em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); |
394 | } | 387 | } |
@@ -396,47 +389,46 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, | |||
396 | em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); | 389 | em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); |
397 | em28xx_videodbg("not supported yet! ...\n"); | 390 | em28xx_videodbg("not supported yet! ...\n"); |
398 | if (copy_to_user(buf, "", 1)) { | 391 | if (copy_to_user(buf, "", 1)) { |
399 | mutex_unlock(&dev->fileop_lock); | 392 | mutex_unlock(&dev->lock); |
400 | return -EFAULT; | 393 | return -EFAULT; |
401 | } | 394 | } |
395 | mutex_unlock(&dev->lock); | ||
402 | return (1); | 396 | return (1); |
403 | } | 397 | } |
404 | if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { | 398 | if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { |
405 | em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); | 399 | em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); |
406 | em28xx_videodbg("not supported yet! ...\n"); | 400 | em28xx_videodbg("not supported yet! ...\n"); |
407 | if (copy_to_user(buf, "", 1)) { | 401 | if (copy_to_user(buf, "", 1)) { |
408 | mutex_unlock(&dev->fileop_lock); | 402 | mutex_unlock(&dev->lock); |
409 | return -EFAULT; | 403 | return -EFAULT; |
410 | } | 404 | } |
405 | mutex_unlock(&dev->lock); | ||
411 | return (1); | 406 | return (1); |
412 | } | 407 | } |
413 | 408 | ||
414 | if (mutex_lock_interruptible(&dev->fileop_lock)) | ||
415 | return -ERESTARTSYS; | ||
416 | |||
417 | if (dev->state & DEV_DISCONNECTED) { | 409 | if (dev->state & DEV_DISCONNECTED) { |
418 | em28xx_videodbg("device not present\n"); | 410 | em28xx_videodbg("device not present\n"); |
419 | mutex_unlock(&dev->fileop_lock); | 411 | mutex_unlock(&dev->lock); |
420 | return -ENODEV; | 412 | return -ENODEV; |
421 | } | 413 | } |
422 | 414 | ||
423 | if (dev->state & DEV_MISCONFIGURED) { | 415 | if (dev->state & DEV_MISCONFIGURED) { |
424 | em28xx_videodbg("device misconfigured; close and open it again\n"); | 416 | em28xx_videodbg("device misconfigured; close and open it again\n"); |
425 | mutex_unlock(&dev->fileop_lock); | 417 | mutex_unlock(&dev->lock); |
426 | return -EIO; | 418 | return -EIO; |
427 | } | 419 | } |
428 | 420 | ||
429 | if (dev->io == IO_MMAP) { | 421 | if (dev->io == IO_MMAP) { |
430 | em28xx_videodbg ("IO method is set to mmap; close and open" | 422 | em28xx_videodbg ("IO method is set to mmap; close and open" |
431 | " the device again to choose the read method\n"); | 423 | " the device again to choose the read method\n"); |
432 | mutex_unlock(&dev->fileop_lock); | 424 | mutex_unlock(&dev->lock); |
433 | return -EINVAL; | 425 | return -EINVAL; |
434 | } | 426 | } |
435 | 427 | ||
436 | if (dev->io == IO_NONE) { | 428 | if (dev->io == IO_NONE) { |
437 | if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { | 429 | if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { |
438 | em28xx_errdev("read failed, not enough memory\n"); | 430 | em28xx_errdev("read failed, not enough memory\n"); |
439 | mutex_unlock(&dev->fileop_lock); | 431 | mutex_unlock(&dev->lock); |
440 | return -ENOMEM; | 432 | return -ENOMEM; |
441 | } | 433 | } |
442 | dev->io = IO_READ; | 434 | dev->io = IO_READ; |
@@ -445,13 +437,13 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, | |||
445 | } | 437 | } |
446 | 438 | ||
447 | if (!count) { | 439 | if (!count) { |
448 | mutex_unlock(&dev->fileop_lock); | 440 | mutex_unlock(&dev->lock); |
449 | return 0; | 441 | return 0; |
450 | } | 442 | } |
451 | 443 | ||
452 | if (list_empty(&dev->outqueue)) { | 444 | if (list_empty(&dev->outqueue)) { |
453 | if (filp->f_flags & O_NONBLOCK) { | 445 | if (filp->f_flags & O_NONBLOCK) { |
454 | mutex_unlock(&dev->fileop_lock); | 446 | mutex_unlock(&dev->lock); |
455 | return -EAGAIN; | 447 | return -EAGAIN; |
456 | } | 448 | } |
457 | ret = wait_event_interruptible | 449 | ret = wait_event_interruptible |
@@ -459,11 +451,11 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, | |||
459 | (!list_empty(&dev->outqueue)) || | 451 | (!list_empty(&dev->outqueue)) || |
460 | (dev->state & DEV_DISCONNECTED)); | 452 | (dev->state & DEV_DISCONNECTED)); |
461 | if (ret) { | 453 | if (ret) { |
462 | mutex_unlock(&dev->fileop_lock); | 454 | mutex_unlock(&dev->lock); |
463 | return ret; | 455 | return ret; |
464 | } | 456 | } |
465 | if (dev->state & DEV_DISCONNECTED) { | 457 | if (dev->state & DEV_DISCONNECTED) { |
466 | mutex_unlock(&dev->fileop_lock); | 458 | mutex_unlock(&dev->lock); |
467 | return -ENODEV; | 459 | return -ENODEV; |
468 | } | 460 | } |
469 | } | 461 | } |
@@ -482,12 +474,12 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, | |||
482 | count = f->buf.length; | 474 | count = f->buf.length; |
483 | 475 | ||
484 | if (copy_to_user(buf, f->bufmem, count)) { | 476 | if (copy_to_user(buf, f->bufmem, count)) { |
485 | mutex_unlock(&dev->fileop_lock); | 477 | mutex_unlock(&dev->lock); |
486 | return -EFAULT; | 478 | return -EFAULT; |
487 | } | 479 | } |
488 | *f_pos += count; | 480 | *f_pos += count; |
489 | 481 | ||
490 | mutex_unlock(&dev->fileop_lock); | 482 | mutex_unlock(&dev->lock); |
491 | 483 | ||
492 | return count; | 484 | return count; |
493 | } | 485 | } |
@@ -501,8 +493,7 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) | |||
501 | unsigned int mask = 0; | 493 | unsigned int mask = 0; |
502 | struct em28xx *dev = filp->private_data; | 494 | struct em28xx *dev = filp->private_data; |
503 | 495 | ||
504 | if (mutex_lock_interruptible(&dev->fileop_lock)) | 496 | mutex_lock(&dev->lock); |
505 | return POLLERR; | ||
506 | 497 | ||
507 | if (dev->state & DEV_DISCONNECTED) { | 498 | if (dev->state & DEV_DISCONNECTED) { |
508 | em28xx_videodbg("device not present\n"); | 499 | em28xx_videodbg("device not present\n"); |
@@ -527,13 +518,13 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) | |||
527 | if (!list_empty(&dev->outqueue)) | 518 | if (!list_empty(&dev->outqueue)) |
528 | mask |= POLLIN | POLLRDNORM; | 519 | mask |= POLLIN | POLLRDNORM; |
529 | 520 | ||
530 | mutex_unlock(&dev->fileop_lock); | 521 | mutex_unlock(&dev->lock); |
531 | 522 | ||
532 | return mask; | 523 | return mask; |
533 | } | 524 | } |
534 | } | 525 | } |
535 | 526 | ||
536 | mutex_unlock(&dev->fileop_lock); | 527 | mutex_unlock(&dev->lock); |
537 | return POLLERR; | 528 | return POLLERR; |
538 | } | 529 | } |
539 | 530 | ||
@@ -575,25 +566,24 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) | |||
575 | 566 | ||
576 | struct em28xx *dev = filp->private_data; | 567 | struct em28xx *dev = filp->private_data; |
577 | 568 | ||
578 | if (mutex_lock_interruptible(&dev->fileop_lock)) | 569 | mutex_lock(&dev->lock); |
579 | return -ERESTARTSYS; | ||
580 | 570 | ||
581 | if (dev->state & DEV_DISCONNECTED) { | 571 | if (dev->state & DEV_DISCONNECTED) { |
582 | em28xx_videodbg("mmap: device not present\n"); | 572 | em28xx_videodbg("mmap: device not present\n"); |
583 | mutex_unlock(&dev->fileop_lock); | 573 | mutex_unlock(&dev->lock); |
584 | return -ENODEV; | 574 | return -ENODEV; |
585 | } | 575 | } |
586 | 576 | ||
587 | if (dev->state & DEV_MISCONFIGURED) { | 577 | if (dev->state & DEV_MISCONFIGURED) { |
588 | em28xx_videodbg ("mmap: Device is misconfigured; close and " | 578 | em28xx_videodbg ("mmap: Device is misconfigured; close and " |
589 | "open it again\n"); | 579 | "open it again\n"); |
590 | mutex_unlock(&dev->fileop_lock); | 580 | mutex_unlock(&dev->lock); |
591 | return -EIO; | 581 | return -EIO; |
592 | } | 582 | } |
593 | 583 | ||
594 | if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || | 584 | if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || |
595 | size != PAGE_ALIGN(dev->frame[0].buf.length)) { | 585 | size != PAGE_ALIGN(dev->frame[0].buf.length)) { |
596 | mutex_unlock(&dev->fileop_lock); | 586 | mutex_unlock(&dev->lock); |
597 | return -EINVAL; | 587 | return -EINVAL; |
598 | } | 588 | } |
599 | 589 | ||
@@ -603,7 +593,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) | |||
603 | } | 593 | } |
604 | if (i == dev->num_frames) { | 594 | if (i == dev->num_frames) { |
605 | em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); | 595 | em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); |
606 | mutex_unlock(&dev->fileop_lock); | 596 | mutex_unlock(&dev->lock); |
607 | return -EINVAL; | 597 | return -EINVAL; |
608 | } | 598 | } |
609 | 599 | ||
@@ -615,7 +605,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) | |||
615 | while (size > 0) { /* size is page-aligned */ | 605 | while (size > 0) { /* size is page-aligned */ |
616 | if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { | 606 | if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { |
617 | em28xx_videodbg("mmap: vm_insert_page failed\n"); | 607 | em28xx_videodbg("mmap: vm_insert_page failed\n"); |
618 | mutex_unlock(&dev->fileop_lock); | 608 | mutex_unlock(&dev->lock); |
619 | return -EAGAIN; | 609 | return -EAGAIN; |
620 | } | 610 | } |
621 | start += PAGE_SIZE; | 611 | start += PAGE_SIZE; |
@@ -627,7 +617,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) | |||
627 | vma->vm_private_data = &dev->frame[i]; | 617 | vma->vm_private_data = &dev->frame[i]; |
628 | 618 | ||
629 | em28xx_vm_open(vma); | 619 | em28xx_vm_open(vma); |
630 | mutex_unlock(&dev->fileop_lock); | 620 | mutex_unlock(&dev->lock); |
631 | return 0; | 621 | return 0; |
632 | } | 622 | } |
633 | 623 | ||
@@ -1084,7 +1074,9 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, | |||
1084 | } | 1074 | } |
1085 | } | 1075 | } |
1086 | } | 1076 | } |
1077 | mutex_lock(&dev->lock); | ||
1087 | em28xx_i2c_call_clients(dev,cmd,qc); | 1078 | em28xx_i2c_call_clients(dev,cmd,qc); |
1079 | mutex_unlock(&dev->lock); | ||
1088 | if (qc->type) | 1080 | if (qc->type) |
1089 | return 0; | 1081 | return 0; |
1090 | else | 1082 | else |
@@ -1098,7 +1090,9 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, | |||
1098 | if (!dev->has_msp34xx) | 1090 | if (!dev->has_msp34xx) |
1099 | retval=em28xx_get_ctrl(dev, ctrl); | 1091 | retval=em28xx_get_ctrl(dev, ctrl); |
1100 | if (retval==-EINVAL) { | 1092 | if (retval==-EINVAL) { |
1093 | mutex_lock(&dev->lock); | ||
1101 | em28xx_i2c_call_clients(dev,cmd,arg); | 1094 | em28xx_i2c_call_clients(dev,cmd,arg); |
1095 | mutex_unlock(&dev->lock); | ||
1102 | return 0; | 1096 | return 0; |
1103 | } else return retval; | 1097 | } else return retval; |
1104 | } | 1098 | } |
@@ -1106,21 +1100,26 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, | |||
1106 | { | 1100 | { |
1107 | struct v4l2_control *ctrl = arg; | 1101 | struct v4l2_control *ctrl = arg; |
1108 | u8 i; | 1102 | u8 i; |
1103 | mutex_lock(&dev->lock); | ||
1109 | 1104 | ||
1110 | if (!dev->has_msp34xx){ | 1105 | if (!dev->has_msp34xx){ |
1111 | for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { | 1106 | for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { |
1112 | if (ctrl->id == em28xx_qctrl[i].id) { | 1107 | if (ctrl->id == em28xx_qctrl[i].id) { |
1108 | int retval=-EINVAL; | ||
1113 | if (ctrl->value < | 1109 | if (ctrl->value < |
1114 | em28xx_qctrl[i].minimum | 1110 | em28xx_qctrl[i].minimum |
1115 | || ctrl->value > | 1111 | || ctrl->value > |
1116 | em28xx_qctrl[i].maximum) | 1112 | em28xx_qctrl[i].maximum) |
1117 | return -ERANGE; | 1113 | return -ERANGE; |
1118 | return em28xx_set_ctrl(dev, ctrl); | 1114 | retval = em28xx_set_ctrl(dev, ctrl); |
1115 | mutex_unlock(&dev->lock); | ||
1116 | return retval; | ||
1119 | } | 1117 | } |
1120 | } | 1118 | } |
1121 | } | 1119 | } |
1122 | 1120 | ||
1123 | em28xx_i2c_call_clients(dev,cmd,arg); | 1121 | em28xx_i2c_call_clients(dev,cmd,arg); |
1122 | mutex_unlock(&dev->lock); | ||
1124 | return 0; | 1123 | return 0; |
1125 | } | 1124 | } |
1126 | /* --- tuner ioctls ------------------------------------------ */ | 1125 | /* --- tuner ioctls ------------------------------------------ */ |
@@ -1220,12 +1219,16 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, | |||
1220 | || dev->io != IO_MMAP) | 1219 | || dev->io != IO_MMAP) |
1221 | return -EINVAL; | 1220 | return -EINVAL; |
1222 | 1221 | ||
1222 | mutex_lock(&dev->lock); | ||
1223 | if (dev->stream == STREAM_ON) { | 1223 | if (dev->stream == STREAM_ON) { |
1224 | em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n"); | 1224 | em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n"); |
1225 | if ((ret = em28xx_stream_interrupt(dev))) | 1225 | if ((ret = em28xx_stream_interrupt(dev))){ |
1226 | mutex_unlock(&dev->lock); | ||
1226 | return ret; | 1227 | return ret; |
1228 | } | ||
1227 | } | 1229 | } |
1228 | em28xx_empty_framequeues(dev); | 1230 | em28xx_empty_framequeues(dev); |
1231 | mutex_unlock(&dev->lock); | ||
1229 | 1232 | ||
1230 | return 0; | 1233 | return 0; |
1231 | } | 1234 | } |
@@ -1291,11 +1294,23 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, | |||
1291 | return 0; | 1294 | return 0; |
1292 | } | 1295 | } |
1293 | case VIDIOC_G_FMT: | 1296 | case VIDIOC_G_FMT: |
1294 | return em28xx_get_fmt(dev, (struct v4l2_format *) arg); | 1297 | { |
1298 | int retval; | ||
1299 | mutex_lock(&dev->lock); | ||
1300 | retval = em28xx_get_fmt(dev, (struct v4l2_format *) arg); | ||
1301 | mutex_unlock(&dev->lock); | ||
1302 | return retval; | ||
1295 | 1303 | ||
1304 | } | ||
1296 | case VIDIOC_TRY_FMT: | 1305 | case VIDIOC_TRY_FMT: |
1297 | case VIDIOC_S_FMT: | 1306 | case VIDIOC_S_FMT: |
1298 | return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg); | 1307 | { |
1308 | int retval; | ||
1309 | mutex_lock(&dev->lock); | ||
1310 | retval = em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg); | ||
1311 | mutex_unlock(&dev->lock); | ||
1312 | return retval; | ||
1313 | } | ||
1299 | 1314 | ||
1300 | case VIDIOC_REQBUFS: | 1315 | case VIDIOC_REQBUFS: |
1301 | { | 1316 | { |
@@ -1320,10 +1335,13 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, | |||
1320 | return -EINVAL; | 1335 | return -EINVAL; |
1321 | } | 1336 | } |
1322 | 1337 | ||
1338 | mutex_lock(&dev->lock); | ||
1323 | if (dev->stream == STREAM_ON) { | 1339 | if (dev->stream == STREAM_ON) { |
1324 | em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); | 1340 | em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); |
1325 | if ((ret = em28xx_stream_interrupt(dev))) | 1341 | if ((ret = em28xx_stream_interrupt(dev))){ |
1342 | mutex_unlock(&dev->lock); | ||
1326 | return ret; | 1343 | return ret; |
1344 | } | ||
1327 | } | 1345 | } |
1328 | 1346 | ||
1329 | em28xx_empty_framequeues(dev); | 1347 | em28xx_empty_framequeues(dev); |
@@ -1338,6 +1356,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, | |||
1338 | em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n", | 1356 | em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n", |
1339 | rb->count); | 1357 | rb->count); |
1340 | dev->io = rb->count ? IO_MMAP : IO_NONE; | 1358 | dev->io = rb->count ? IO_MMAP : IO_NONE; |
1359 | mutex_unlock(&dev->lock); | ||
1341 | return 0; | 1360 | return 0; |
1342 | } | 1361 | } |
1343 | case VIDIOC_QUERYBUF: | 1362 | case VIDIOC_QUERYBUF: |
@@ -1439,26 +1458,19 @@ static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp, | |||
1439 | int ret = 0; | 1458 | int ret = 0; |
1440 | struct em28xx *dev = filp->private_data; | 1459 | struct em28xx *dev = filp->private_data; |
1441 | 1460 | ||
1442 | if (mutex_lock_interruptible(&dev->fileop_lock)) | ||
1443 | return -ERESTARTSYS; | ||
1444 | |||
1445 | if (dev->state & DEV_DISCONNECTED) { | 1461 | if (dev->state & DEV_DISCONNECTED) { |
1446 | em28xx_errdev("v4l2 ioctl: device not present\n"); | 1462 | em28xx_errdev("v4l2 ioctl: device not present\n"); |
1447 | mutex_unlock(&dev->fileop_lock); | ||
1448 | return -ENODEV; | 1463 | return -ENODEV; |
1449 | } | 1464 | } |
1450 | 1465 | ||
1451 | if (dev->state & DEV_MISCONFIGURED) { | 1466 | if (dev->state & DEV_MISCONFIGURED) { |
1452 | em28xx_errdev | 1467 | em28xx_errdev |
1453 | ("v4l2 ioctl: device is misconfigured; close and open it again\n"); | 1468 | ("v4l2 ioctl: device is misconfigured; close and open it again\n"); |
1454 | mutex_unlock(&dev->fileop_lock); | ||
1455 | return -EIO; | 1469 | return -EIO; |
1456 | } | 1470 | } |
1457 | 1471 | ||
1458 | ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl); | 1472 | ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl); |
1459 | 1473 | ||
1460 | mutex_unlock(&dev->fileop_lock); | ||
1461 | |||
1462 | return ret; | 1474 | return ret; |
1463 | } | 1475 | } |
1464 | 1476 | ||
@@ -1519,8 +1531,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1519 | return -ENOMEM; | 1531 | return -ENOMEM; |
1520 | } | 1532 | } |
1521 | 1533 | ||
1522 | mutex_lock(&dev->lock); | ||
1523 | |||
1524 | /* register i2c bus */ | 1534 | /* register i2c bus */ |
1525 | em28xx_i2c_register(dev); | 1535 | em28xx_i2c_register(dev); |
1526 | 1536 | ||
@@ -1530,8 +1540,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1530 | /* configure the device */ | 1540 | /* configure the device */ |
1531 | em28xx_config_i2c(dev); | 1541 | em28xx_config_i2c(dev); |
1532 | 1542 | ||
1533 | mutex_unlock(&dev->lock); | ||
1534 | |||
1535 | for (i = 0; i < TVNORMS; i++) | 1543 | for (i = 0; i < TVNORMS; i++) |
1536 | if (em28xx_boards[dev->model].norm == tvnorms[i].mode) | 1544 | if (em28xx_boards[dev->model].norm == tvnorms[i].mode) |
1537 | break; | 1545 | break; |
@@ -1599,8 +1607,18 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1599 | 1607 | ||
1600 | list_add_tail(&dev->devlist,&em28xx_devlist); | 1608 | list_add_tail(&dev->devlist,&em28xx_devlist); |
1601 | 1609 | ||
1610 | |||
1611 | if (dev->has_msp34xx) { | ||
1612 | /* Send a reset to other chips via gpio */ | ||
1613 | em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); | ||
1614 | msleep(3); | ||
1615 | em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); | ||
1616 | msleep(3); | ||
1617 | |||
1618 | } | ||
1619 | video_mux(dev, 0); | ||
1620 | |||
1602 | /* register v4l2 device */ | 1621 | /* register v4l2 device */ |
1603 | mutex_lock(&dev->lock); | ||
1604 | if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, | 1622 | if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, |
1605 | video_nr[dev->devno]))) { | 1623 | video_nr[dev->devno]))) { |
1606 | em28xx_errdev("unable to register video device (error=%i).\n", | 1624 | em28xx_errdev("unable to register video device (error=%i).\n", |
@@ -1627,18 +1645,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
1627 | printk("registered VBI\n"); | 1645 | printk("registered VBI\n"); |
1628 | } | 1646 | } |
1629 | 1647 | ||
1630 | if (dev->has_msp34xx) { | ||
1631 | /* Send a reset to other chips via gpio */ | ||
1632 | em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); | ||
1633 | msleep(3); | ||
1634 | em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); | ||
1635 | msleep(3); | ||
1636 | |||
1637 | } | ||
1638 | video_mux(dev, 0); | ||
1639 | |||
1640 | mutex_unlock(&dev->lock); | ||
1641 | |||
1642 | em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", | 1648 | em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", |
1643 | dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, | 1649 | dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, |
1644 | dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); | 1650 | dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); |
@@ -1762,18 +1768,19 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
1762 | */ | 1768 | */ |
1763 | static void em28xx_usb_disconnect(struct usb_interface *interface) | 1769 | static void em28xx_usb_disconnect(struct usb_interface *interface) |
1764 | { | 1770 | { |
1765 | struct em28xx *dev = usb_get_intfdata(interface); | 1771 | struct em28xx *dev; |
1772 | |||
1773 | dev = usb_get_intfdata(interface); | ||
1766 | usb_set_intfdata(interface, NULL); | 1774 | usb_set_intfdata(interface, NULL); |
1767 | 1775 | ||
1768 | if (!dev) | 1776 | if (!dev) |
1769 | return; | 1777 | return; |
1770 | 1778 | ||
1771 | down_write(&em28xx_disconnect); | 1779 | em28xx_info("disconnecting %s\n", dev->vdev->name); |
1772 | 1780 | ||
1781 | /* wait until all current v4l2 io is finished then deallocate resources */ | ||
1773 | mutex_lock(&dev->lock); | 1782 | mutex_lock(&dev->lock); |
1774 | 1783 | ||
1775 | em28xx_info("disconnecting %s\n", dev->vdev->name); | ||
1776 | |||
1777 | wake_up_interruptible_all(&dev->open); | 1784 | wake_up_interruptible_all(&dev->open); |
1778 | 1785 | ||
1779 | if (dev->users) { | 1786 | if (dev->users) { |
@@ -1792,6 +1799,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) | |||
1792 | em28xx_release_resources(dev); | 1799 | em28xx_release_resources(dev); |
1793 | } | 1800 | } |
1794 | 1801 | ||
1802 | |||
1795 | mutex_unlock(&dev->lock); | 1803 | mutex_unlock(&dev->lock); |
1796 | 1804 | ||
1797 | if (!dev->users) { | 1805 | if (!dev->users) { |
@@ -1799,7 +1807,6 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) | |||
1799 | kfree(dev); | 1807 | kfree(dev); |
1800 | } | 1808 | } |
1801 | 1809 | ||
1802 | up_write(&em28xx_disconnect); | ||
1803 | } | 1810 | } |
1804 | 1811 | ||
1805 | static struct usb_driver em28xx_usb_driver = { | 1812 | static struct usb_driver em28xx_usb_driver = { |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 209f6f9d5581..65670ae2945b 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
@@ -265,7 +265,7 @@ struct em28xx { | |||
265 | enum em28xx_stream_state stream; | 265 | enum em28xx_stream_state stream; |
266 | enum em28xx_io_method io; | 266 | enum em28xx_io_method io; |
267 | /* locks */ | 267 | /* locks */ |
268 | struct mutex lock, fileop_lock; | 268 | struct mutex lock; |
269 | spinlock_t queue_lock; | 269 | spinlock_t queue_lock; |
270 | struct list_head inqueue, outqueue; | 270 | struct list_head inqueue, outqueue; |
271 | wait_queue_head_t open, wait_frame, wait_stream; | 271 | wait_queue_head_t open, wait_frame, wait_stream; |