diff options
Diffstat (limited to 'drivers/media/radio/si470x')
-rw-r--r-- | drivers/media/radio/si470x/radio-si470x-common.c | 1 | ||||
-rw-r--r-- | drivers/media/radio/si470x/radio-si470x-usb.c | 149 |
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 | */ | ||
492 | int si470x_fops_open(struct file *file) | 484 | int 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 | |||
534 | done: | ||
535 | if (retval) | ||
536 | v4l2_fh_release(file); | ||
537 | return retval; | ||
538 | } | 487 | } |
539 | 488 | ||
540 | |||
541 | /* | ||
542 | * si470x_fops_release - file release | ||
543 | */ | ||
544 | int si470x_fops_release(struct file *file) | 489 | int 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 | ||
566 | static void si470x_usb_release(struct video_device *vdev) | 494 | static 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 | ||
531 | static 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: | |||
786 | static int si470x_usb_driver_suspend(struct usb_interface *intf, | 753 | static 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 | */ |
798 | static int si470x_usb_driver_resume(struct usb_interface *intf) | 779 | static 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 | */ |
824 | static struct usb_driver si470x_usb_driver = { | 815 | static 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 | ||
834 | module_usb_driver(si470x_usb_driver); | 825 | module_usb_driver(si470x_usb_driver); |