1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/power/light_bar.h"
6
7#include <cstring>  // needed for strlen()
8
9#include "base/command_line.h"
10#include "base/files/file_util.h"
11#include "base/logging.h"
12#include "base/message_loop/message_loop.h"
13#include "chromeos/chromeos_switches.h"
14#include "chromeos/dbus/dbus_thread_manager.h"
15
16namespace chromeos {
17
18namespace {
19const int kDarkSuspendDelaySeconds = 4;
20const char kLightBarControlPath[] =
21    "/sys/devices/platform/cros_ec_lpc.0/cros-ec-dev.0/chromeos/cros_ec/"
22    "lightbar/sequence";
23const char kKonamiCommand[] = "KONAMI";
24
25// TODO(chirantan): These are used by a temporary workaround for lucid sleep and
26// should be removed once the proper implementation is ready (crbug.com/414949).
27const char kDarkResumeAlwaysFile[] = "/sys/power/dark_resume_always";
28const char kEnableDarkResumeAlways[] = "1";
29
30}  // namespace
31
32LightBar::LightBar()
33    : control_path_(base::FilePath(kLightBarControlPath)),
34      has_light_bar_(base::PathIsWritable(control_path_)) {
35  DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
36
37  // Until the kernel can properly detect the wakeup source, we need to use a
38  // hack to tell the kernel to always enter dark resume.  Chrome can then
39  // detect any user activity and have the power manager transition out of dark
40  // resume into regular resume.  We don't care if the write succeeds or not
41  // because most devices will not have this file.
42  //
43  // TODO(chirantan): Remove this once we can properly detect the wakeup
44  // source (crbug.com/414949).
45  base::WriteFile(base::FilePath(kDarkResumeAlwaysFile),
46                  kEnableDarkResumeAlways,
47                  strlen(kEnableDarkResumeAlways));
48}
49
50LightBar::~LightBar() {
51  DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
52}
53
54void LightBar::DarkSuspendImminent() {
55  // The plan is to track the progress of push events and then re-suspend as
56  // soon as we know they have been processed.  In the meanwhile, we can hack
57  // around this by just having the light bar delay for a long time so that
58  // people can at least start playing around with this feature for their apps.
59  //
60  // TODO(chirantan): Remove this once we can accurately track the progress of
61  // push events.
62  base::MessageLoop::current()->PostDelayedTask(
63      FROM_HERE,
64      DBusThreadManager::Get()
65          ->GetPowerManagerClient()
66          ->GetSuspendReadinessCallback(),
67      base::TimeDelta::FromSeconds(kDarkSuspendDelaySeconds));
68
69  if (!has_light_bar_)
70    return;
71
72  if (base::WriteFile(control_path_, kKonamiCommand, strlen(kKonamiCommand)) !=
73      static_cast<int>(strlen(kKonamiCommand)))
74    PLOG(WARNING) << "Unable to flash light bar during dark resume.";
75}
76
77}  // namespace chromeos
78