aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/radio/si470x/radio-si470x-usb.c
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2012-05-04 08:16:57 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-05-14 12:44:02 -0400
commit4967d53dbbcebf590c5ae07c0aea38619ac51954 (patch)
tree0591424809d99161f6c420d263c6e23cedd8b724 /drivers/media/radio/si470x/radio-si470x-usb.c
parent528f0f785c042c80294708c5ae2c8005b4a0ee60 (diff)
[media] si470x: Clean up, introduce the control framework
This cleans up the code and si470x now uses the proper v4l2 frameworks and passes most of the v4l2-compliance tests. 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/radio-si470x-usb.c')
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c146
1 files changed, 58 insertions, 88 deletions
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index b7debb67932a..f133c3dea648 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -367,23 +367,6 @@ static int si470x_get_scratch_page_versions(struct si470x_device *radio)
367 367
368 368
369/************************************************************************** 369/**************************************************************************
370 * General Driver Functions - DISCONNECT_CHECK
371 **************************************************************************/
372
373/*
374 * si470x_disconnect_check - check whether radio disconnects
375 */
376int si470x_disconnect_check(struct si470x_device *radio)
377{
378 if (radio->disconnected)
379 return -EIO;
380 else
381 return 0;
382}
383
384
385
386/**************************************************************************
387 * RDS Driver Functions 370 * RDS Driver Functions
388 **************************************************************************/ 371 **************************************************************************/
389 372
@@ -414,9 +397,6 @@ static void si470x_int_in_callback(struct urb *urb)
414 } 397 }
415 } 398 }
416 399
417 /* safety checks */
418 if (radio->disconnected)
419 return;
420 if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) 400 if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
421 goto resubmit; 401 goto resubmit;
422 402
@@ -512,19 +492,16 @@ resubmit:
512int si470x_fops_open(struct file *file) 492int si470x_fops_open(struct file *file)
513{ 493{
514 struct si470x_device *radio = video_drvdata(file); 494 struct si470x_device *radio = video_drvdata(file);
515 int retval; 495 int retval = v4l2_fh_open(file);
516 496
517 mutex_lock(&radio->lock); 497 if (retval)
518 radio->users++; 498 return retval;
519 499
520 retval = usb_autopm_get_interface(radio->intf); 500 retval = usb_autopm_get_interface(radio->intf);
521 if (retval < 0) { 501 if (retval < 0)
522 radio->users--;
523 retval = -EIO;
524 goto done; 502 goto done;
525 }
526 503
527 if (radio->users == 1) { 504 if (v4l2_fh_is_singular_file(file)) {
528 /* start radio */ 505 /* start radio */
529 retval = si470x_start(radio); 506 retval = si470x_start(radio);
530 if (retval < 0) { 507 if (retval < 0) {
@@ -555,7 +532,8 @@ int si470x_fops_open(struct file *file)
555 } 532 }
556 533
557done: 534done:
558 mutex_unlock(&radio->lock); 535 if (retval)
536 v4l2_fh_release(file);
559 return retval; 537 return retval;
560} 538}
561 539
@@ -566,45 +544,36 @@ done:
566int si470x_fops_release(struct file *file) 544int si470x_fops_release(struct file *file)
567{ 545{
568 struct si470x_device *radio = video_drvdata(file); 546 struct si470x_device *radio = video_drvdata(file);
569 int retval = 0;
570 547
571 /* safety check */ 548 if (v4l2_fh_is_singular_file(file)) {
572 if (!radio) {
573 retval = -ENODEV;
574 goto done;
575 }
576
577 mutex_lock(&radio->lock);
578 radio->users--;
579 if (radio->users == 0) {
580 /* shutdown interrupt handler */ 549 /* shutdown interrupt handler */
581 if (radio->int_in_running) { 550 if (radio->int_in_running) {
582 radio->int_in_running = 0; 551 radio->int_in_running = 0;
583 if (radio->int_in_urb) 552 if (radio->int_in_urb)
584 usb_kill_urb(radio->int_in_urb); 553 usb_kill_urb(radio->int_in_urb);
585 }
586
587 if (radio->disconnected) {
588 video_unregister_device(radio->videodev);
589 kfree(radio->int_in_buffer);
590 kfree(radio->buffer);
591 mutex_unlock(&radio->lock);
592 kfree(radio);
593 goto done;
594 } 554 }
595 555
596 /* cancel read processes */ 556 /* cancel read processes */
597 wake_up_interruptible(&radio->read_queue); 557 wake_up_interruptible(&radio->read_queue);
598 558
599 /* stop radio */ 559 /* stop radio */
600 retval = si470x_stop(radio); 560 si470x_stop(radio);
601 usb_autopm_put_interface(radio->intf); 561 usb_autopm_put_interface(radio->intf);
602 } 562 }
603 mutex_unlock(&radio->lock); 563 return v4l2_fh_release(file);
604done:
605 return retval;
606} 564}
607 565
566static void si470x_usb_release(struct video_device *vdev)
567{
568 struct si470x_device *radio = video_get_drvdata(vdev);
569
570 usb_free_urb(radio->int_in_urb);
571 v4l2_ctrl_handler_free(&radio->hdl);
572 v4l2_device_unregister(&radio->v4l2_dev);
573 kfree(radio->int_in_buffer);
574 kfree(radio->buffer);
575 kfree(radio);
576}
608 577
609 578
610/************************************************************************** 579/**************************************************************************
@@ -623,9 +592,9 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
623 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); 592 strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
624 usb_make_path(radio->usbdev, capability->bus_info, 593 usb_make_path(radio->usbdev, capability->bus_info,
625 sizeof(capability->bus_info)); 594 sizeof(capability->bus_info));
626 capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | 595 capability->device_caps = V4L2_CAP_HW_FREQ_SEEK |
627 V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; 596 V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
628 597 capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
629 return 0; 598 return 0;
630} 599}
631 600
@@ -653,8 +622,6 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
653 retval = -ENOMEM; 622 retval = -ENOMEM;
654 goto err_initial; 623 goto err_initial;
655 } 624 }
656 radio->users = 0;
657 radio->disconnected = 0;
658 radio->usbdev = interface_to_usbdev(intf); 625 radio->usbdev = interface_to_usbdev(intf);
659 radio->intf = intf; 626 radio->intf = intf;
660 mutex_init(&radio->lock); 627 mutex_init(&radio->lock);
@@ -691,20 +658,34 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
691 goto err_intbuffer; 658 goto err_intbuffer;
692 } 659 }
693 660
694 /* video device allocation and initialization */ 661 retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
695 radio->videodev = video_device_alloc(); 662 if (retval < 0) {
696 if (!radio->videodev) { 663 dev_err(&intf->dev, "couldn't register v4l2_device\n");
697 retval = -ENOMEM;
698 goto err_urb; 664 goto err_urb;
699 } 665 }
700 memcpy(radio->videodev, &si470x_viddev_template, 666
701 sizeof(si470x_viddev_template)); 667 v4l2_ctrl_handler_init(&radio->hdl, 2);
702 video_set_drvdata(radio->videodev, radio); 668 v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops,
669 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
670 v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops,
671 V4L2_CID_AUDIO_VOLUME, 0, 15, 1, 15);
672 if (radio->hdl.error) {
673 retval = radio->hdl.error;
674 dev_err(&intf->dev, "couldn't register control\n");
675 goto err_dev;
676 }
677 radio->videodev = si470x_viddev_template;
678 radio->videodev.ctrl_handler = &radio->hdl;
679 radio->videodev.lock = &radio->lock;
680 radio->videodev.v4l2_dev = &radio->v4l2_dev;
681 radio->videodev.release = si470x_usb_release;
682 set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
683 video_set_drvdata(&radio->videodev, radio);
703 684
704 /* get device and chip versions */ 685 /* get device and chip versions */
705 if (si470x_get_all_registers(radio) < 0) { 686 if (si470x_get_all_registers(radio) < 0) {
706 retval = -EIO; 687 retval = -EIO;
707 goto err_video; 688 goto err_ctrl;
708 } 689 }
709 dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", 690 dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
710 radio->registers[DEVICEID], radio->registers[CHIPID]); 691 radio->registers[DEVICEID], radio->registers[CHIPID]);
@@ -721,7 +702,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
721 /* get software and hardware versions */ 702 /* get software and hardware versions */
722 if (si470x_get_scratch_page_versions(radio) < 0) { 703 if (si470x_get_scratch_page_versions(radio) < 0) {
723 retval = -EIO; 704 retval = -EIO;
724 goto err_video; 705 goto err_ctrl;
725 } 706 }
726 dev_info(&intf->dev, "software version %d, hardware version %d\n", 707 dev_info(&intf->dev, "software version %d, hardware version %d\n",
727 radio->software_version, radio->hardware_version); 708 radio->software_version, radio->hardware_version);
@@ -764,28 +745,30 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
764 radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); 745 radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
765 if (!radio->buffer) { 746 if (!radio->buffer) {
766 retval = -EIO; 747 retval = -EIO;
767 goto err_video; 748 goto err_ctrl;
768 } 749 }
769 750
770 /* rds buffer configuration */ 751 /* rds buffer configuration */
771 radio->wr_index = 0; 752 radio->wr_index = 0;
772 radio->rd_index = 0; 753 radio->rd_index = 0;
773 init_waitqueue_head(&radio->read_queue); 754 init_waitqueue_head(&radio->read_queue);
755 usb_set_intfdata(intf, radio);
774 756
775 /* register video device */ 757 /* register video device */
776 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, 758 retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
777 radio_nr); 759 radio_nr);
778 if (retval) { 760 if (retval) {
779 dev_warn(&intf->dev, "Could not register video device\n"); 761 dev_warn(&intf->dev, "Could not register video device\n");
780 goto err_all; 762 goto err_all;
781 } 763 }
782 usb_set_intfdata(intf, radio);
783 764
784 return 0; 765 return 0;
785err_all: 766err_all:
786 kfree(radio->buffer); 767 kfree(radio->buffer);
787err_video: 768err_ctrl:
788 video_device_release(radio->videodev); 769 v4l2_ctrl_handler_free(&radio->hdl);
770err_dev:
771 v4l2_device_unregister(&radio->v4l2_dev);
789err_urb: 772err_urb:
790 usb_free_urb(radio->int_in_urb); 773 usb_free_urb(radio->int_in_urb);
791err_intbuffer: 774err_intbuffer:
@@ -828,23 +811,10 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
828 struct si470x_device *radio = usb_get_intfdata(intf); 811 struct si470x_device *radio = usb_get_intfdata(intf);
829 812
830 mutex_lock(&radio->lock); 813 mutex_lock(&radio->lock);
831 radio->disconnected = 1; 814 v4l2_device_disconnect(&radio->v4l2_dev);
815 video_unregister_device(&radio->videodev);
832 usb_set_intfdata(intf, NULL); 816 usb_set_intfdata(intf, NULL);
833 if (radio->users == 0) { 817 mutex_unlock(&radio->lock);
834 /* set led to disconnect state */
835 si470x_set_led_state(radio, BLINK_ORANGE_LED);
836
837 /* Free data structures. */
838 usb_free_urb(radio->int_in_urb);
839
840 kfree(radio->int_in_buffer);
841 video_unregister_device(radio->videodev);
842 kfree(radio->buffer);
843 mutex_unlock(&radio->lock);
844 kfree(radio);
845 } else {
846 mutex_unlock(&radio->lock);
847 }
848} 818}
849 819
850 820