diff options
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/radio/radio-si470x.c | 83 |
1 files changed, 75 insertions, 8 deletions
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index c72a9e7ad885..649f14d2c013 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c | |||
@@ -81,6 +81,10 @@ | |||
81 | * - racy interruptible_sleep_on(), | 81 | * - racy interruptible_sleep_on(), |
82 | * replaced with wait_event_interruptible() | 82 | * replaced with wait_event_interruptible() |
83 | * - handle signals in read() | 83 | * - handle signals in read() |
84 | * 2008-02-08 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
85 | * Oliver Neukum <oliver@neukum.org> | ||
86 | * Version 1.0.7 | ||
87 | * - usb autosuspend support | ||
84 | * | 88 | * |
85 | * ToDo: | 89 | * ToDo: |
86 | * - add seeking support | 90 | * - add seeking support |
@@ -415,6 +419,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); | |||
415 | struct si470x_device { | 419 | struct si470x_device { |
416 | /* reference to USB and video device */ | 420 | /* reference to USB and video device */ |
417 | struct usb_device *usbdev; | 421 | struct usb_device *usbdev; |
422 | struct usb_interface *intf; | ||
418 | struct video_device *videodev; | 423 | struct video_device *videodev; |
419 | 424 | ||
420 | /* driver management */ | 425 | /* driver management */ |
@@ -762,9 +767,17 @@ static int si470x_stop(struct si470x_device *radio) | |||
762 | */ | 767 | */ |
763 | static int si470x_rds_on(struct si470x_device *radio) | 768 | static int si470x_rds_on(struct si470x_device *radio) |
764 | { | 769 | { |
770 | int retval; | ||
771 | |||
765 | /* sysconfig 1 */ | 772 | /* sysconfig 1 */ |
773 | mutex_lock(&radio->lock); | ||
766 | radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; | 774 | radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; |
767 | return si470x_set_register(radio, SYSCONFIG1); | 775 | retval = si470x_set_register(radio, SYSCONFIG1); |
776 | if (retval < 0) | ||
777 | radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; | ||
778 | mutex_unlock(&radio->lock); | ||
779 | |||
780 | return retval; | ||
768 | } | 781 | } |
769 | 782 | ||
770 | 783 | ||
@@ -961,10 +974,22 @@ static unsigned int si470x_fops_poll(struct file *file, | |||
961 | static int si470x_fops_open(struct inode *inode, struct file *file) | 974 | static int si470x_fops_open(struct inode *inode, struct file *file) |
962 | { | 975 | { |
963 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); | 976 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); |
977 | int retval; | ||
964 | 978 | ||
965 | radio->users++; | 979 | radio->users++; |
966 | if (radio->users == 1) | 980 | |
967 | return si470x_start(radio); | 981 | retval = usb_autopm_get_interface(radio->intf); |
982 | if (retval < 0) { | ||
983 | radio->users--; | ||
984 | return -EIO; | ||
985 | } | ||
986 | |||
987 | if (radio->users == 1) { | ||
988 | retval = si470x_start(radio); | ||
989 | if (retval < 0) | ||
990 | usb_autopm_put_interface(radio->intf); | ||
991 | return retval; | ||
992 | } | ||
968 | 993 | ||
969 | return 0; | 994 | return 0; |
970 | } | 995 | } |
@@ -976,6 +1001,7 @@ static int si470x_fops_open(struct inode *inode, struct file *file) | |||
976 | static int si470x_fops_release(struct inode *inode, struct file *file) | 1001 | static int si470x_fops_release(struct inode *inode, struct file *file) |
977 | { | 1002 | { |
978 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); | 1003 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); |
1004 | int retval; | ||
979 | 1005 | ||
980 | if (!radio) | 1006 | if (!radio) |
981 | return -ENODEV; | 1007 | return -ENODEV; |
@@ -988,7 +1014,9 @@ static int si470x_fops_release(struct inode *inode, struct file *file) | |||
988 | /* cancel read processes */ | 1014 | /* cancel read processes */ |
989 | wake_up_interruptible(&radio->read_queue); | 1015 | wake_up_interruptible(&radio->read_queue); |
990 | 1016 | ||
991 | return si470x_stop(radio); | 1017 | retval = si470x_stop(radio); |
1018 | usb_autopm_put_interface(radio->intf); | ||
1019 | return retval; | ||
992 | } | 1020 | } |
993 | 1021 | ||
994 | return 0; | 1022 | return 0; |
@@ -1377,6 +1405,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
1377 | sizeof(si470x_viddev_template)); | 1405 | sizeof(si470x_viddev_template)); |
1378 | radio->users = 0; | 1406 | radio->users = 0; |
1379 | radio->usbdev = interface_to_usbdev(intf); | 1407 | radio->usbdev = interface_to_usbdev(intf); |
1408 | radio->intf = intf; | ||
1380 | mutex_init(&radio->lock); | 1409 | mutex_init(&radio->lock); |
1381 | video_set_drvdata(radio->videodev, radio); | 1410 | video_set_drvdata(radio->videodev, radio); |
1382 | 1411 | ||
@@ -1440,6 +1469,41 @@ err_initial: | |||
1440 | 1469 | ||
1441 | 1470 | ||
1442 | /* | 1471 | /* |
1472 | * si470x_usb_driver_suspend - suspend the device | ||
1473 | */ | ||
1474 | static int si470x_usb_driver_suspend(struct usb_interface *intf, | ||
1475 | pm_message_t message) | ||
1476 | { | ||
1477 | struct si470x_device *radio = usb_get_intfdata(intf); | ||
1478 | |||
1479 | printk(KERN_INFO DRIVER_NAME ": suspending now...\n"); | ||
1480 | |||
1481 | cancel_delayed_work_sync(&radio->work); | ||
1482 | |||
1483 | return 0; | ||
1484 | } | ||
1485 | |||
1486 | |||
1487 | /* | ||
1488 | * si470x_usb_driver_resume - resume the device | ||
1489 | */ | ||
1490 | static int si470x_usb_driver_resume(struct usb_interface *intf) | ||
1491 | { | ||
1492 | struct si470x_device *radio = usb_get_intfdata(intf); | ||
1493 | |||
1494 | printk(KERN_INFO DRIVER_NAME ": resuming now...\n"); | ||
1495 | |||
1496 | mutex_lock(&radio->lock); | ||
1497 | if (radio->users && radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) | ||
1498 | schedule_delayed_work(&radio->work, | ||
1499 | msecs_to_jiffies(rds_poll_time)); | ||
1500 | mutex_unlock(&radio->lock); | ||
1501 | |||
1502 | return 0; | ||
1503 | } | ||
1504 | |||
1505 | |||
1506 | /* | ||
1443 | * si470x_usb_driver_disconnect - disconnect the device | 1507 | * si470x_usb_driver_disconnect - disconnect the device |
1444 | */ | 1508 | */ |
1445 | static void si470x_usb_driver_disconnect(struct usb_interface *intf) | 1509 | static void si470x_usb_driver_disconnect(struct usb_interface *intf) |
@@ -1458,10 +1522,13 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf) | |||
1458 | * si470x_usb_driver - usb driver interface | 1522 | * si470x_usb_driver - usb driver interface |
1459 | */ | 1523 | */ |
1460 | static struct usb_driver si470x_usb_driver = { | 1524 | static struct usb_driver si470x_usb_driver = { |
1461 | .name = DRIVER_NAME, | 1525 | .name = DRIVER_NAME, |
1462 | .probe = si470x_usb_driver_probe, | 1526 | .probe = si470x_usb_driver_probe, |
1463 | .disconnect = si470x_usb_driver_disconnect, | 1527 | .disconnect = si470x_usb_driver_disconnect, |
1464 | .id_table = si470x_usb_driver_id_table, | 1528 | .suspend = si470x_usb_driver_suspend, |
1529 | .resume = si470x_usb_driver_resume, | ||
1530 | .id_table = si470x_usb_driver_id_table, | ||
1531 | .supports_autosuspend = 1, | ||
1465 | }; | 1532 | }; |
1466 | 1533 | ||
1467 | 1534 | ||