diff options
| -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 | ||
