blob: f428cc7d88b2d40f9e457e0126ae704b0a93a240 [file] [log] [blame]
// Copyright (c) 2013 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 "mist/usb_device.h"
#include <libusb.h>
#include <base/logging.h>
#include "mist/usb_config_descriptor.h"
#include "mist/usb_device_descriptor.h"
namespace mist {
UsbDevice::UsbDevice(libusb_device* device)
: device_(device), device_handle_(nullptr) {
CHECK(device_);
libusb_ref_device(device_);
}
UsbDevice::UsbDevice(libusb_device_handle* device_handle)
: device_(nullptr), device_handle_(device_handle) {
CHECK(device_handle_);
device_ = libusb_get_device(device_handle_);
CHECK(device_);
libusb_ref_device(device_);
}
UsbDevice::~UsbDevice() {
Close();
libusb_unref_device(device_);
device_ = nullptr;
}
bool UsbDevice::IsOpen() const {
return device_handle_ != nullptr;
}
bool UsbDevice::VerifyOpen() {
if (IsOpen())
return true;
error_.set_type(UsbError::kErrorDeviceNotOpen);
return false;
}
bool UsbDevice::Open() {
if (IsOpen()) {
error_.Clear();
return true;
}
int result = libusb_open(device_, &device_handle_);
return error_.SetFromLibUsbError(static_cast<libusb_error>(result));
}
void UsbDevice::Close() {
if (!IsOpen())
return;
libusb_close(device_handle_);
device_handle_ = nullptr;
}
bool UsbDevice::Reset() {
if (!VerifyOpen())
return false;
int result = libusb_reset_device(device_handle_);
return error_.SetFromLibUsbError(static_cast<libusb_error>(result));
}
uint8_t UsbDevice::GetBusNumber() const {
return libusb_get_bus_number(device_);
}
uint8_t UsbDevice::GetDeviceAddress() const {
return libusb_get_device_address(device_);
}
UsbSpeed UsbDevice::GetDeviceSpeed() const {
int speed = libusb_get_device_speed(device_);
switch (speed) {
case kUsbSpeedLow:
case kUsbSpeedFull:
case kUsbSpeedHigh:
case kUsbSpeedSuper:
return static_cast<UsbSpeed>(speed);
default:
return kUsbSpeedUnknown;
}
}
bool UsbDevice::GetConfiguration(int* configuration) {
if (!VerifyOpen())
return false;
int result = libusb_get_configuration(device_handle_, configuration);
return error_.SetFromLibUsbError(static_cast<libusb_error>(result));
}
bool UsbDevice::SetConfiguration(int configuration) {
if (!VerifyOpen())
return false;
int result = libusb_set_configuration(device_handle_, configuration);
return error_.SetFromLibUsbError(static_cast<libusb_error>(result));
}
bool UsbDevice::ClaimInterface(int interface_number) {
if (!VerifyOpen())
return false;
int result = libusb_claim_interface(device_handle_, interface_number);
return error_.SetFromLibUsbError(static_cast<libusb_error>(result));
}
bool UsbDevice::ReleaseInterface(int interface_number) {
if (!VerifyOpen())
return false;
int result = libusb_release_interface(device_handle_, interface_number);
return error_.SetFromLibUsbError(static_cast<libusb_error>(result));
}
bool UsbDevice::SetInterfaceAlternateSetting(int interface_number,
int alternate_setting) {
if (!VerifyOpen())
return false;
int result = libusb_set_interface_alt_setting(
device_handle_, interface_number, alternate_setting);
return error_.SetFromLibUsbError(static_cast<libusb_error>(result));
}
bool UsbDevice::IsKernelDriverActive(int interface_number) {
if (!VerifyOpen())
return false;
int result = libusb_kernel_driver_active(device_handle_, interface_number);
if (result == 1) {
error_.Clear();
return true;
}
return error_.SetFromLibUsbError(static_cast<libusb_error>(result));
}
bool UsbDevice::AttachKernelDriver(int interface_number) {
if (!VerifyOpen())
return false;
int result = libusb_attach_kernel_driver(device_handle_, interface_number);
return error_.SetFromLibUsbError(static_cast<libusb_error>(result));
}
bool UsbDevice::DetachKernelDriver(int interface_number) {
if (!VerifyOpen())
return false;
int result = libusb_detach_kernel_driver(device_handle_, interface_number);
return error_.SetFromLibUsbError(static_cast<libusb_error>(result));
}
bool UsbDevice::ClearHalt(uint8_t endpoint) {
if (!VerifyOpen())
return false;
int result = libusb_clear_halt(device_handle_, endpoint);
return error_.SetFromLibUsbError(static_cast<libusb_error>(result));
}
std::unique_ptr<UsbConfigDescriptor> UsbDevice::GetActiveConfigDescriptor() {
libusb_config_descriptor* config_descriptor = nullptr;
int result = libusb_get_active_config_descriptor(device_, &config_descriptor);
if (error_.SetFromLibUsbError(static_cast<libusb_error>(result)))
return std::make_unique<UsbConfigDescriptor>(AsWeakPtr(), config_descriptor,
true);
return nullptr;
}
std::unique_ptr<UsbConfigDescriptor> UsbDevice::GetConfigDescriptor(
uint8_t index) {
libusb_config_descriptor* config_descriptor = nullptr;
int result = libusb_get_config_descriptor(device_, index, &config_descriptor);
if (error_.SetFromLibUsbError(static_cast<libusb_error>(result)))
return std::make_unique<UsbConfigDescriptor>(AsWeakPtr(), config_descriptor,
true);
return nullptr;
}
std::unique_ptr<UsbConfigDescriptor> UsbDevice::GetConfigDescriptorByValue(
uint8_t configuration_value) {
libusb_config_descriptor* config_descriptor = nullptr;
int result = libusb_get_config_descriptor_by_value(
device_, configuration_value, &config_descriptor);
if (error_.SetFromLibUsbError(static_cast<libusb_error>(result)))
return std::make_unique<UsbConfigDescriptor>(AsWeakPtr(), config_descriptor,
true);
return nullptr;
}
std::unique_ptr<UsbDeviceDescriptor> UsbDevice::GetDeviceDescriptor() {
if (!device_descriptor_)
device_descriptor_.reset(new libusb_device_descriptor());
int result = libusb_get_device_descriptor(device_, device_descriptor_.get());
if (error_.SetFromLibUsbError(static_cast<libusb_error>(result)))
return std::make_unique<UsbDeviceDescriptor>(AsWeakPtr(),
device_descriptor_.get());
return nullptr;
}
std::string UsbDevice::GetStringDescriptorAscii(uint8_t index) {
if (!VerifyOpen())
return std::string();
// libusb_get_string_descriptor_ascii uses an internal buffer that can only
// hold up to 128 ASCII characters.
int length = 128;
auto data = std::make_unique<uint8_t[]>(length);
int result = libusb_get_string_descriptor_ascii(device_handle_, index,
data.get(), length);
if (result < 0) {
error_.SetFromLibUsbError(static_cast<libusb_error>(result));
return std::string();
}
error_.Clear();
return std::string(reinterpret_cast<const char*>(data.get()), result);
}
} // namespace mist