blob: 370771097cccb78541ea2bcf6bc2d08e4e1ec3ea [file] [log] [blame]
// Copyright 2017 The Chromium 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 "device/usb/usb_device_win.h"
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/device_event_log/device_event_log.h"
#include "device/usb/usb_device_handle_win.h"
#include "device/usb/webusb_descriptors.h"
#include <windows.h>
namespace device {
namespace {
const uint16_t kUsbVersion2_1 = 0x0210;
} // namespace
UsbDeviceWin::UsbDeviceWin(const std::string& device_path,
const std::string& hub_path,
uint32_t bus_number,
uint32_t port_number,
const std::string& driver_name)
: UsbDevice(bus_number, port_number),
device_path_(device_path),
hub_path_(hub_path),
driver_name_(driver_name) {}
UsbDeviceWin::~UsbDeviceWin() {}
void UsbDeviceWin::Open(OpenCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
scoped_refptr<UsbDeviceHandle> device_handle;
if (base::EqualsCaseInsensitiveASCII(driver_name_, "winusb"))
device_handle = new UsbDeviceHandleWin(this, false);
// TODO: Support composite devices.
// else if (base::EqualsCaseInsensitiveASCII(driver_name_, "usbccgp"))
// device_handle = new UsbDeviceHandleWin(this, true);
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), device_handle));
}
void UsbDeviceWin::ReadDescriptors(base::OnceCallback<void(bool)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
scoped_refptr<UsbDeviceHandle> device_handle;
base::win::ScopedHandle handle(
CreateFileA(hub_path_.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr));
if (handle.IsValid()) {
device_handle = new UsbDeviceHandleWin(this, std::move(handle));
} else {
USB_PLOG(ERROR) << "Failed to open " << hub_path_;
std::move(callback).Run(false);
return;
}
ReadUsbDescriptors(device_handle,
base::BindOnce(&UsbDeviceWin::OnReadDescriptors, this,
std::move(callback), device_handle));
}
void UsbDeviceWin::OnReadDescriptors(
base::OnceCallback<void(bool)> callback,
scoped_refptr<UsbDeviceHandle> device_handle,
std::unique_ptr<UsbDeviceDescriptor> descriptor) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!descriptor) {
USB_LOG(ERROR) << "Failed to read descriptors from " << device_path_ << ".";
device_handle->Close();
std::move(callback).Run(false);
return;
}
descriptor_ = *descriptor;
// WinUSB only supports the configuration 1.
ActiveConfigurationChanged(1);
auto string_map = std::make_unique<std::map<uint8_t, base::string16>>();
if (descriptor_.i_manufacturer)
(*string_map)[descriptor_.i_manufacturer] = base::string16();
if (descriptor_.i_product)
(*string_map)[descriptor_.i_product] = base::string16();
if (descriptor_.i_serial_number)
(*string_map)[descriptor_.i_serial_number] = base::string16();
ReadUsbStringDescriptors(
device_handle, std::move(string_map),
base::BindOnce(&UsbDeviceWin::OnReadStringDescriptors, this,
std::move(callback), device_handle));
}
void UsbDeviceWin::OnReadStringDescriptors(
base::OnceCallback<void(bool)> callback,
scoped_refptr<UsbDeviceHandle> device_handle,
std::unique_ptr<std::map<uint8_t, base::string16>> string_map) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
device_handle->Close();
if (descriptor_.i_manufacturer)
manufacturer_string_ = (*string_map)[descriptor_.i_manufacturer];
if (descriptor_.i_product)
product_string_ = (*string_map)[descriptor_.i_product];
if (descriptor_.i_serial_number)
serial_number_ = (*string_map)[descriptor_.i_serial_number];
if (usb_version() >= kUsbVersion2_1) {
Open(base::BindOnce(&UsbDeviceWin::OnOpenedToReadWebUsbDescriptors, this,
std::move(callback)));
} else {
std::move(callback).Run(true);
}
}
void UsbDeviceWin::OnOpenedToReadWebUsbDescriptors(
base::OnceCallback<void(bool)> callback,
scoped_refptr<UsbDeviceHandle> device_handle) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!device_handle) {
USB_LOG(ERROR) << "Failed to open device to read WebUSB descriptors.";
// Failure to read WebUSB descriptors is not fatal.
std::move(callback).Run(true);
return;
}
ReadWebUsbDescriptors(
device_handle,
base::BindRepeating(&UsbDeviceWin::OnReadWebUsbDescriptors, this,
base::Passed(&callback), device_handle));
}
void UsbDeviceWin::OnReadWebUsbDescriptors(
base::OnceCallback<void(bool)> callback,
scoped_refptr<UsbDeviceHandle> device_handle,
const GURL& landing_page) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
webusb_landing_page_ = landing_page;
device_handle->Close();
std::move(callback).Run(true);
}
} // namespace device