diff options
author | Antti Palosaari <crope@iki.fi> | 2012-08-14 21:21:05 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 18:17:02 -0400 |
commit | 0898b95409489abd7219f5f7ca675c84656fb94f (patch) | |
tree | 59d9b3909dde1641ca7dd71e8032b27064dc094e /drivers/media | |
parent | 6304a60eb891137cfc20047263073a5d087e2f69 (diff) |
[media] dvb_usb_v2: implement power-management for suspend
Put device full sleep on suspend, wake-up it on resume and acquire
retune in order to return same television channel.
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 83 |
1 files changed, 63 insertions, 20 deletions
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index a72f9c7de68..7ce8ffef8ac 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | |||
@@ -486,7 +486,6 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe) | |||
486 | int ret; | 486 | int ret; |
487 | struct dvb_usb_adapter *adap = fe->dvb->priv; | 487 | struct dvb_usb_adapter *adap = fe->dvb->priv; |
488 | struct dvb_usb_device *d = adap_to_d(adap); | 488 | struct dvb_usb_device *d = adap_to_d(adap); |
489 | mutex_lock(&adap->sync_mutex); | ||
490 | dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, | 489 | dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, |
491 | fe->id); | 490 | fe->id); |
492 | 491 | ||
@@ -506,22 +505,30 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe) | |||
506 | goto err; | 505 | goto err; |
507 | } | 506 | } |
508 | 507 | ||
509 | adap->active_fe = fe->id; | ||
510 | mutex_unlock(&adap->sync_mutex); | ||
511 | |||
512 | return 0; | 508 | return 0; |
513 | err: | 509 | err: |
514 | mutex_unlock(&adap->sync_mutex); | ||
515 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 510 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); |
516 | return ret; | 511 | return ret; |
517 | } | 512 | } |
518 | 513 | ||
514 | static int dvb_usb_fe_init_lock(struct dvb_frontend *fe) | ||
515 | { | ||
516 | int ret; | ||
517 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
518 | mutex_lock(&adap->sync_mutex); | ||
519 | |||
520 | ret = dvb_usb_fe_init(fe); | ||
521 | adap->active_fe = fe->id; | ||
522 | |||
523 | mutex_unlock(&adap->sync_mutex); | ||
524 | return ret; | ||
525 | } | ||
526 | |||
519 | static int dvb_usb_fe_sleep(struct dvb_frontend *fe) | 527 | static int dvb_usb_fe_sleep(struct dvb_frontend *fe) |
520 | { | 528 | { |
521 | int ret; | 529 | int ret; |
522 | struct dvb_usb_adapter *adap = fe->dvb->priv; | 530 | struct dvb_usb_adapter *adap = fe->dvb->priv; |
523 | struct dvb_usb_device *d = adap_to_d(adap); | 531 | struct dvb_usb_device *d = adap_to_d(adap); |
524 | mutex_lock(&adap->sync_mutex); | ||
525 | dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, | 532 | dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, |
526 | fe->id); | 533 | fe->id); |
527 | 534 | ||
@@ -541,16 +548,25 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) | |||
541 | if (ret < 0) | 548 | if (ret < 0) |
542 | goto err; | 549 | goto err; |
543 | 550 | ||
544 | adap->active_fe = -1; | ||
545 | mutex_unlock(&adap->sync_mutex); | ||
546 | |||
547 | return 0; | 551 | return 0; |
548 | err: | 552 | err: |
549 | mutex_unlock(&adap->sync_mutex); | ||
550 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 553 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); |
551 | return ret; | 554 | return ret; |
552 | } | 555 | } |
553 | 556 | ||
557 | static int dvb_usb_fe_sleep_lock(struct dvb_frontend *fe) | ||
558 | { | ||
559 | int ret; | ||
560 | struct dvb_usb_adapter *adap = fe->dvb->priv; | ||
561 | mutex_lock(&adap->sync_mutex); | ||
562 | |||
563 | ret = dvb_usb_fe_sleep(fe); | ||
564 | adap->active_fe = -1; | ||
565 | |||
566 | mutex_unlock(&adap->sync_mutex); | ||
567 | return ret; | ||
568 | } | ||
569 | |||
554 | int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) | 570 | int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) |
555 | { | 571 | { |
556 | int ret, i, count_registered = 0; | 572 | int ret, i, count_registered = 0; |
@@ -578,9 +594,9 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) | |||
578 | adap->fe[i]->id = i; | 594 | adap->fe[i]->id = i; |
579 | /* re-assign sleep and wakeup functions */ | 595 | /* re-assign sleep and wakeup functions */ |
580 | adap->fe_init[i] = adap->fe[i]->ops.init; | 596 | adap->fe_init[i] = adap->fe[i]->ops.init; |
581 | adap->fe[i]->ops.init = dvb_usb_fe_init; | 597 | adap->fe[i]->ops.init = dvb_usb_fe_init_lock; |
582 | adap->fe_sleep[i] = adap->fe[i]->ops.sleep; | 598 | adap->fe_sleep[i] = adap->fe[i]->ops.sleep; |
583 | adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; | 599 | adap->fe[i]->ops.sleep = dvb_usb_fe_sleep_lock; |
584 | 600 | ||
585 | ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); | 601 | ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); |
586 | if (ret < 0) { | 602 | if (ret < 0) { |
@@ -950,18 +966,30 @@ EXPORT_SYMBOL(dvb_usbv2_disconnect); | |||
950 | int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) | 966 | int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) |
951 | { | 967 | { |
952 | struct dvb_usb_device *d = usb_get_intfdata(intf); | 968 | struct dvb_usb_device *d = usb_get_intfdata(intf); |
953 | int i; | 969 | int i, active_fe; |
970 | struct dvb_frontend *fe; | ||
954 | dev_dbg(&d->udev->dev, "%s:\n", __func__); | 971 | dev_dbg(&d->udev->dev, "%s:\n", __func__); |
955 | 972 | ||
956 | /* stop remote controller poll */ | 973 | /* stop remote controller poll */ |
957 | if (d->rc.query && !d->rc.bulk_mode) | 974 | if (d->rc.query && !d->rc.bulk_mode) |
958 | cancel_delayed_work_sync(&d->rc_query_work); | 975 | cancel_delayed_work_sync(&d->rc_query_work); |
959 | 976 | ||
960 | /* stop streaming */ | ||
961 | for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { | 977 | for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { |
962 | if (d->adapter[i].dvb_adap.priv && | 978 | active_fe = d->adapter[i].active_fe; |
963 | d->adapter[i].active_fe != -1) | 979 | if (d->adapter[i].dvb_adap.priv && active_fe != -1) { |
980 | fe = d->adapter[i].fe[active_fe]; | ||
981 | |||
982 | if (d->props->streaming_ctrl) | ||
983 | d->props->streaming_ctrl(fe, 0); | ||
984 | |||
985 | /* stop usb streaming */ | ||
964 | usb_urb_killv2(&d->adapter[i].stream); | 986 | usb_urb_killv2(&d->adapter[i].stream); |
987 | |||
988 | if (fe->ops.tuner_ops.sleep) | ||
989 | fe->ops.tuner_ops.sleep(fe); | ||
990 | |||
991 | dvb_usb_fe_sleep(fe); | ||
992 | } | ||
965 | } | 993 | } |
966 | 994 | ||
967 | return 0; | 995 | return 0; |
@@ -971,14 +999,29 @@ EXPORT_SYMBOL(dvb_usbv2_suspend); | |||
971 | int dvb_usbv2_resume(struct usb_interface *intf) | 999 | int dvb_usbv2_resume(struct usb_interface *intf) |
972 | { | 1000 | { |
973 | struct dvb_usb_device *d = usb_get_intfdata(intf); | 1001 | struct dvb_usb_device *d = usb_get_intfdata(intf); |
974 | int i; | 1002 | int i, active_fe; |
1003 | struct dvb_frontend *fe; | ||
975 | dev_dbg(&d->udev->dev, "%s:\n", __func__); | 1004 | dev_dbg(&d->udev->dev, "%s:\n", __func__); |
976 | 1005 | ||
977 | /* start streaming */ | ||
978 | for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) { | 1006 | for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) { |
979 | if (d->adapter[i].dvb_adap.priv && | 1007 | active_fe = d->adapter[i].active_fe; |
980 | d->adapter[i].active_fe != -1) | 1008 | if (d->adapter[i].dvb_adap.priv && active_fe != -1) { |
1009 | fe = d->adapter[i].fe[active_fe]; | ||
1010 | |||
1011 | dvb_usb_fe_init(fe); | ||
1012 | |||
1013 | if (fe->ops.tuner_ops.init) | ||
1014 | fe->ops.tuner_ops.init(fe); | ||
1015 | |||
1016 | /* acquire dvb-core perform retune */ | ||
1017 | dvb_frontend_retune(fe); | ||
1018 | |||
1019 | /* resume usb streaming */ | ||
981 | usb_urb_submitv2(&d->adapter[i].stream, NULL); | 1020 | usb_urb_submitv2(&d->adapter[i].stream, NULL); |
1021 | |||
1022 | if (d->props->streaming_ctrl) | ||
1023 | d->props->streaming_ctrl(fe, 1); | ||
1024 | } | ||
982 | } | 1025 | } |
983 | 1026 | ||
984 | /* start remote controller poll */ | 1027 | /* start remote controller poll */ |