diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-05-04 08:16:57 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-05-14 12:44:02 -0400 |
commit | 4967d53dbbcebf590c5ae07c0aea38619ac51954 (patch) | |
tree | 0591424809d99161f6c420d263c6e23cedd8b724 /drivers/media/radio/si470x/radio-si470x-usb.c | |
parent | 528f0f785c042c80294708c5ae2c8005b4a0ee60 (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.c | 146 |
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 | */ | ||
376 | int 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: | |||
512 | int si470x_fops_open(struct file *file) | 492 | int 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 | ||
557 | done: | 534 | done: |
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: | |||
566 | int si470x_fops_release(struct file *file) | 544 | int 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); |
604 | done: | ||
605 | return retval; | ||
606 | } | 564 | } |
607 | 565 | ||
566 | static 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; |
785 | err_all: | 766 | err_all: |
786 | kfree(radio->buffer); | 767 | kfree(radio->buffer); |
787 | err_video: | 768 | err_ctrl: |
788 | video_device_release(radio->videodev); | 769 | v4l2_ctrl_handler_free(&radio->hdl); |
770 | err_dev: | ||
771 | v4l2_device_unregister(&radio->v4l2_dev); | ||
789 | err_urb: | 772 | err_urb: |
790 | usb_free_urb(radio->int_in_urb); | 773 | usb_free_urb(radio->int_in_urb); |
791 | err_intbuffer: | 774 | err_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 | ||