aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/radio/si470x
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2012-05-04 08:42:29 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-05-14 12:45:44 -0400
commit6fd522a6d12d0ebac528f2d4553c4bf51c0c3275 (patch)
treed4fffc048e45264f848903dfb8bec83ff0d3598e /drivers/media/radio/si470x
parent340bd4c16cead8bf8f5205c7d283a3bd9d699f76 (diff)
[media] radio-si470x-usb: remove autosuspend, implement suspend/resume
The radio-si470x-usb driver supported both autosuspend and it stopped the radio the moment the last user of the radio device closed it. However, that was very confusing since if you play the audio from the device (e.g. through arecord -D ... | aplay) then no sound would play unless you had the radio device open at the same time, even though there is no need to do anything with that node. On the other hand, the actual suspend/resume functions didn't do anything, which would fail if you *did* have the radio node open at that time. So: - remove autosuspend (bad idea in general for USB radio devices) - move the start/stop out of the open/release functions into the resume/suspend functions. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Acked-by: Tobias Lorenz <tobias.lorenz@gmx.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/radio/si470x')
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c1
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c149
2 files changed, 70 insertions, 80 deletions
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index b9a44d4a032f..969cf494d85b 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -570,7 +570,6 @@ static int si470x_s_ctrl(struct v4l2_ctrl *ctrl)
570 else 570 else
571 radio->registers[POWERCFG] |= POWERCFG_DMUTE; 571 radio->registers[POWERCFG] |= POWERCFG_DMUTE;
572 return si470x_set_register(radio, POWERCFG); 572 return si470x_set_register(radio, POWERCFG);
573 break;
574 default: 573 default:
575 return -EINVAL; 574 return -EINVAL;
576 } 575 }
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index f133c3dea648..e9f638761296 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -481,91 +481,20 @@ resubmit:
481} 481}
482 482
483 483
484
485/**************************************************************************
486 * File Operations Interface
487 **************************************************************************/
488
489/*
490 * si470x_fops_open - file open
491 */
492int si470x_fops_open(struct file *file) 484int si470x_fops_open(struct file *file)
493{ 485{
494 struct si470x_device *radio = video_drvdata(file); 486 return v4l2_fh_open(file);
495 int retval = v4l2_fh_open(file);
496
497 if (retval)
498 return retval;
499
500 retval = usb_autopm_get_interface(radio->intf);
501 if (retval < 0)
502 goto done;
503
504 if (v4l2_fh_is_singular_file(file)) {
505 /* start radio */
506 retval = si470x_start(radio);
507 if (retval < 0) {
508 usb_autopm_put_interface(radio->intf);
509 goto done;
510 }
511
512 /* initialize interrupt urb */
513 usb_fill_int_urb(radio->int_in_urb, radio->usbdev,
514 usb_rcvintpipe(radio->usbdev,
515 radio->int_in_endpoint->bEndpointAddress),
516 radio->int_in_buffer,
517 le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize),
518 si470x_int_in_callback,
519 radio,
520 radio->int_in_endpoint->bInterval);
521
522 radio->int_in_running = 1;
523 mb();
524
525 retval = usb_submit_urb(radio->int_in_urb, GFP_KERNEL);
526 if (retval) {
527 dev_info(&radio->intf->dev,
528 "submitting int urb failed (%d)\n", retval);
529 radio->int_in_running = 0;
530 usb_autopm_put_interface(radio->intf);
531 }
532 }
533
534done:
535 if (retval)
536 v4l2_fh_release(file);
537 return retval;
538} 487}
539 488
540
541/*
542 * si470x_fops_release - file release
543 */
544int si470x_fops_release(struct file *file) 489int si470x_fops_release(struct file *file)
545{ 490{
546 struct si470x_device *radio = video_drvdata(file);
547
548 if (v4l2_fh_is_singular_file(file)) {
549 /* shutdown interrupt handler */
550 if (radio->int_in_running) {
551 radio->int_in_running = 0;
552 if (radio->int_in_urb)
553 usb_kill_urb(radio->int_in_urb);
554 }
555
556 /* cancel read processes */
557 wake_up_interruptible(&radio->read_queue);
558
559 /* stop radio */
560 si470x_stop(radio);
561 usb_autopm_put_interface(radio->intf);
562 }
563 return v4l2_fh_release(file); 491 return v4l2_fh_release(file);
564} 492}
565 493
566static void si470x_usb_release(struct video_device *vdev) 494static void si470x_usb_release(struct v4l2_device *v4l2_dev)
567{ 495{
568 struct si470x_device *radio = video_get_drvdata(vdev); 496 struct si470x_device *radio =
497 container_of(v4l2_dev, struct si470x_device, v4l2_dev);
569 498
570 usb_free_urb(radio->int_in_urb); 499 usb_free_urb(radio->int_in_urb);
571 v4l2_ctrl_handler_free(&radio->hdl); 500 v4l2_ctrl_handler_free(&radio->hdl);
@@ -599,6 +528,38 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
599} 528}
600 529
601 530
531static int si470x_start_usb(struct si470x_device *radio)
532{
533 int retval;
534
535 /* start radio */
536 retval = si470x_start(radio);
537 if (retval < 0)
538 return retval;
539
540 v4l2_ctrl_handler_setup(&radio->hdl);
541
542 /* initialize interrupt urb */
543 usb_fill_int_urb(radio->int_in_urb, radio->usbdev,
544 usb_rcvintpipe(radio->usbdev,
545 radio->int_in_endpoint->bEndpointAddress),
546 radio->int_in_buffer,
547 le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize),
548 si470x_int_in_callback,
549 radio,
550 radio->int_in_endpoint->bInterval);
551
552 radio->int_in_running = 1;
553 mb();
554
555 retval = usb_submit_urb(radio->int_in_urb, GFP_KERNEL);
556 if (retval) {
557 dev_info(&radio->intf->dev,
558 "submitting int urb failed (%d)\n", retval);
559 radio->int_in_running = 0;
560 }
561 return retval;
562}
602 563
603/************************************************************************** 564/**************************************************************************
604 * USB Interface 565 * USB Interface
@@ -658,6 +619,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
658 goto err_intbuffer; 619 goto err_intbuffer;
659 } 620 }
660 621
622 radio->v4l2_dev.release = si470x_usb_release;
661 retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); 623 retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
662 if (retval < 0) { 624 if (retval < 0) {
663 dev_err(&intf->dev, "couldn't register v4l2_device\n"); 625 dev_err(&intf->dev, "couldn't register v4l2_device\n");
@@ -678,7 +640,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
678 radio->videodev.ctrl_handler = &radio->hdl; 640 radio->videodev.ctrl_handler = &radio->hdl;
679 radio->videodev.lock = &radio->lock; 641 radio->videodev.lock = &radio->lock;
680 radio->videodev.v4l2_dev = &radio->v4l2_dev; 642 radio->videodev.v4l2_dev = &radio->v4l2_dev;
681 radio->videodev.release = si470x_usb_release; 643 radio->videodev.release = video_device_release_empty;
682 set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags); 644 set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
683 video_set_drvdata(&radio->videodev, radio); 645 video_set_drvdata(&radio->videodev, radio);
684 646
@@ -754,11 +716,16 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
754 init_waitqueue_head(&radio->read_queue); 716 init_waitqueue_head(&radio->read_queue);
755 usb_set_intfdata(intf, radio); 717 usb_set_intfdata(intf, radio);
756 718
719 /* start radio */
720 retval = si470x_start_usb(radio);
721 if (retval < 0)
722 goto err_all;
723
757 /* register video device */ 724 /* register video device */
758 retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, 725 retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
759 radio_nr); 726 radio_nr);
760 if (retval) { 727 if (retval) {
761 dev_warn(&intf->dev, "Could not register video device\n"); 728 dev_err(&intf->dev, "Could not register video device\n");
762 goto err_all; 729 goto err_all;
763 } 730 }
764 731
@@ -786,8 +753,22 @@ err_initial:
786static int si470x_usb_driver_suspend(struct usb_interface *intf, 753static int si470x_usb_driver_suspend(struct usb_interface *intf,
787 pm_message_t message) 754 pm_message_t message)
788{ 755{
756 struct si470x_device *radio = usb_get_intfdata(intf);
757
789 dev_info(&intf->dev, "suspending now...\n"); 758 dev_info(&intf->dev, "suspending now...\n");
790 759
760 /* shutdown interrupt handler */
761 if (radio->int_in_running) {
762 radio->int_in_running = 0;
763 if (radio->int_in_urb)
764 usb_kill_urb(radio->int_in_urb);
765 }
766
767 /* cancel read processes */
768 wake_up_interruptible(&radio->read_queue);
769
770 /* stop radio */
771 si470x_stop(radio);
791 return 0; 772 return 0;
792} 773}
793 774
@@ -797,9 +778,12 @@ static int si470x_usb_driver_suspend(struct usb_interface *intf,
797 */ 778 */
798static int si470x_usb_driver_resume(struct usb_interface *intf) 779static int si470x_usb_driver_resume(struct usb_interface *intf)
799{ 780{
781 struct si470x_device *radio = usb_get_intfdata(intf);
782
800 dev_info(&intf->dev, "resuming now...\n"); 783 dev_info(&intf->dev, "resuming now...\n");
801 784
802 return 0; 785 /* start radio */
786 return si470x_start_usb(radio);
803} 787}
804 788
805 789
@@ -815,11 +799,18 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
815 video_unregister_device(&radio->videodev); 799 video_unregister_device(&radio->videodev);
816 usb_set_intfdata(intf, NULL); 800 usb_set_intfdata(intf, NULL);
817 mutex_unlock(&radio->lock); 801 mutex_unlock(&radio->lock);
802 v4l2_device_put(&radio->v4l2_dev);
818} 803}
819 804
820 805
821/* 806/*
822 * si470x_usb_driver - usb driver interface 807 * si470x_usb_driver - usb driver interface
808 *
809 * A note on suspend/resume: this driver had only empty suspend/resume
810 * functions, and when I tried to test suspend/resume it always disconnected
811 * instead of resuming (using my ADS InstantFM stick). So I've decided to
812 * remove these callbacks until someone else with better hardware can
813 * implement and test this.
823 */ 814 */
824static struct usb_driver si470x_usb_driver = { 815static struct usb_driver si470x_usb_driver = {
825 .name = DRIVER_NAME, 816 .name = DRIVER_NAME,
@@ -827,8 +818,8 @@ static struct usb_driver si470x_usb_driver = {
827 .disconnect = si470x_usb_driver_disconnect, 818 .disconnect = si470x_usb_driver_disconnect,
828 .suspend = si470x_usb_driver_suspend, 819 .suspend = si470x_usb_driver_suspend,
829 .resume = si470x_usb_driver_resume, 820 .resume = si470x_usb_driver_resume,
821 .reset_resume = si470x_usb_driver_resume,
830 .id_table = si470x_usb_driver_id_table, 822 .id_table = si470x_usb_driver_id_table,
831 .supports_autosuspend = 1,
832}; 823};
833 824
834module_usb_driver(si470x_usb_driver); 825module_usb_driver(si470x_usb_driver);