blob: 5c33ff2056e467986cc24242bb8d08be2435dac3 [file] [log] [blame]
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cfm-device-monitor/mimo-monitor/mimo_monitor.h"
#include <base/bind.h>
#include <base/logging.h>
#include <brillo/message_loops/message_loop.h>
#include <brillo/syslog_logging.h>
#include <libusb-1.0/libusb.h>
#include <stdlib.h>
#include <memory>
#include "cfm-device-monitor/mimo-monitor/utils.h"
namespace {
const int kFindMimoSleepTimeMs = 60e3;
const int kResetSleepTimeMs = 10e3;
const int kPingIntervalMs = 60e3;
const int kTouchInterface = 0;
} // namespace
namespace mimo_monitor {
std::unique_ptr<MimoMonitor> MimoMonitor::Create() {
libusb_context* ctx = nullptr;
int ret = libusb_init(&ctx);
if (ret < 0) {
LOG(WARNING) << "Init libusb context fail. error " << ret;
return nullptr;
}
return std::unique_ptr<MimoMonitor>(new MimoMonitor(ctx));
}
MimoMonitor::MimoMonitor(libusb_context* ctx) : ctx_(ctx), weak_factory_(this) {
display_device_ = nullptr;
touch_device_ = nullptr;
mimo_found_ = false;
libusb_set_debug(ctx_, 3);
}
MimoMonitor::~MimoMonitor() {
if (display_device_) {
libusb_unref_device(display_device_);
}
if (touch_device_) {
libusb_unref_device(touch_device_);
}
libusb_exit(ctx_);
}
base::WeakPtr<MimoMonitor> MimoMonitor::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void MimoMonitor::FindMimo() {
libusb_device** raw_devs = nullptr;
libusb_device_descriptor desc;
bool dl_found = false;
bool sis_found = false;
int ret, device_cnt = 0;
ssize_t cnt = libusb_get_device_list(ctx_, &raw_devs);
ScopedUsbDevs devs(raw_devs);
// There was an error in getting the devices on the USB bus.
if (cnt < 0) {
LOG(WARNING) << "Get device list fail, error: " << cnt;
mimo_found_ = false;
// Post a task instead of call TaskScheduler directly so current function
// won't be blocked by it.
base::MessageLoop::current()->task_runner()->PostTask(
FROM_HERE, base::Bind(&MimoMonitor::TaskScheduler, GetWeakPtr()));
return;
}
// Interate through all the devices
VLOG(1) << "Searching for SiS and DisplayLink in device list..";
// Interate through all the devices
for (ssize_t i = 0; i < cnt; i++) {
libusb_device* dev = devs.get()[i];
// Get device descriptor.
ret = libusb_get_device_descriptor(dev, &desc);
if (ret < 0) {
LOG(WARNING) << "Failed to get devcie descriptor, error: " << ret;
continue;
}
// Currently don't support multiple Mimos. So only try to find the first
// device.
if (!dl_found) {
if (dl_monitor.IsDisplaylink(dev, desc)) {
device_cnt += 1;
dl_found = true;
display_device_ = libusb_ref_device(dev);
VLOG(1) << "Displaylink found.";
}
}
if (!sis_found) {
if (sis_monitor.IsSiS(dev, desc)) {
device_cnt += 1;
sis_found = true;
touch_device_ = libusb_ref_device(dev);
VLOG(1) << "SiS found.";
}
}
}
switch (device_cnt) {
case 0: {
// Nothing found.
VLOG(1) << "Didn't find Displaylink or SiSMonitor";
break;
}
case 1: {
// Only found part of Mimo.
LOG(WARNING) << "Only found part of Mimo.";
break;
}
case 2: {
// Mimo found.
VLOG(1) << "Mimo found.";
mimo_found_ = true;
break;
}
default: {
// Invalid number.
LOG(WARNING) << "Invalid conponents number " << device_cnt
<< " some error happens.";
}
}
base::MessageLoop::current()->task_runner()->PostTask(
FROM_HERE, base::Bind(&MimoMonitor::TaskScheduler, GetWeakPtr()));
}
void MimoMonitor::CheckMimoHealth() {
// Check status of Displaylink.
dl_monitor.CheckDLHealth(display_device_);
// Check status of SiS.
sis_monitor.CheckSiSHealth(touch_device_);
base::MessageLoop::current()->task_runner()->PostTask(
FROM_HERE, base::Bind(&MimoMonitor::TaskScheduler, GetWeakPtr()));
}
void MimoMonitor::TaskScheduler() {
// Didn't find Mimo.
if (!mimo_found_) {
base::MessageLoop::current()->task_runner()->PostDelayedTask(
FROM_HERE, base::Bind(&MimoMonitor::FindMimo, GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kFindMimoSleepTimeMs));
return;
}
// Both touch and display fail.
if (!dl_monitor.DisplayStatus() && !sis_monitor.TouchStatus()) {
// Please see b/109866345 before modyfing the below line.
LOG(WARNING) << "Both touch and display are down. Resetting Mimo.";
ResetDevice(libusb_get_parent(display_device_));
mimo_found_ = false;
base::MessageLoop::current()->task_runner()->PostDelayedTask(
FROM_HERE, base::Bind(&MimoMonitor::FindMimo, GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kResetSleepTimeMs));
return;
}
// Touch fails.
if (!sis_monitor.TouchStatus()) {
// Please see b/109866345 before modyfing the below line.
LOG(WARNING) << "Trying to reset touch panel.";
mimo_found_ = false;
sis_monitor.ResetSiS(touch_device_, kTouchInterface);
base::MessageLoop::current()->task_runner()->PostDelayedTask(
FROM_HERE, base::Bind(&MimoMonitor::FindMimo, GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kResetSleepTimeMs));
return;
}
// Display fails.
if (!dl_monitor.DisplayStatus()) {
// Please see b/109866345 before modyfing the below line.
LOG(WARNING) << "Trying to reset display.";
mimo_found_ = false;
ResetDevice(display_device_);
base::MessageLoop::current()->task_runner()->PostDelayedTask(
FROM_HERE, base::Bind(&MimoMonitor::FindMimo, GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kResetSleepTimeMs));
return;
}
// Everything looks good.
VLOG(1) << "Mimo is alive.";
base::MessageLoop::current()->task_runner()->PostDelayedTask(
FROM_HERE, base::Bind(&MimoMonitor::CheckMimoHealth, GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kPingIntervalMs));
return;
}
void MimoMonitor::OnShutdown(int* return_code) {
VLOG(1) << "Shutdown MimoMonitor, return code: " << *return_code;
if (!mimo_found_) {
return;
}
// Make sure SiS interface is attached back on shutdown.
libusb_device_handle* dev_handle_ = NULL;
int ret = libusb_open(touch_device_, &dev_handle_);
if (ret < 0) {
// There was an error opening the handle. Device is not there.
LOG(WARNING) << "Failed to check SiS status on shutdown, error " << ret;
return;
}
ScopedUsbDevHandle dev_handle(dev_handle_);
ret = libusb_kernel_driver_active(dev_handle.get(), kTouchInterface);
if (ret < 0) {
LOG(WARNING) << "Failed to get kernel driver status on shutdown, error "
<< ret;
return;
}
if (ret == 0) {
ret = libusb_attach_kernel_driver(dev_handle.get(), kTouchInterface);
if (ret < 0) {
LOG(WARNING) << "Re-attach SiS interface fail on shutdown, error " << ret;
return;
}
}
}
} // namespace mimo_monitor