blob: 412c23d7434d5d60e8ba677f361ce00ed932a8b3 [file] [log] [blame]
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "libusb.hpp"
#include <stdplus/util/cexec.hpp>
#include <system_error>
#include <utility>
namespace google
{
namespace hoth
{
namespace libusb
{
int toErrno(int error)
{
switch (error)
{
case LIBUSB_SUCCESS:
return 0;
case LIBUSB_ERROR_IO:
return EIO;
case LIBUSB_ERROR_INVALID_PARAM:
return EINVAL;
case LIBUSB_ERROR_ACCESS:
return EACCES;
case LIBUSB_ERROR_NO_DEVICE:
return ENODEV;
case LIBUSB_ERROR_NOT_FOUND:
return ENOENT;
case LIBUSB_ERROR_BUSY:
return EBUSY;
case LIBUSB_ERROR_TIMEOUT:
return ETIMEDOUT;
case LIBUSB_ERROR_OVERFLOW:
return EOVERFLOW;
case LIBUSB_ERROR_PIPE:
return EPIPE;
case LIBUSB_ERROR_INTERRUPTED:
return EINTR;
case LIBUSB_ERROR_NO_MEM:
return ENOMEM;
case LIBUSB_ERROR_NOT_SUPPORTED:
return ENOTSUP;
default:
return ENOSYS;
}
}
inline auto makeError(int error, const char* msg)
{
return std::system_error(toErrno(-error), std::generic_category(), msg);
}
template <typename... Args>
inline auto callCheck(const char* msg, Args&&... args)
{
return stdplus::util::callCheckRet<makeError, Args...>(
msg, std::forward<Args>(args)...);
}
InterfaceClaim::InterfaceClaim(LibusbIntf* libusb, libusb_device_handle* handle,
int interface) :
libusb(libusb),
handle(init(handle, interface), interface, libusb)
{}
void InterfaceClaim::drop(libusb_device_handle*&& handle, int& interface,
LibusbIntf*& libusb)
{
libusb->release_interface(handle, interface);
}
libusb_device_handle* InterfaceClaim::init(libusb_device_handle* handle,
int interface)
{
callCheck("claim_interface", &LibusbIntf::claim_interface, libusb, handle,
interface);
return handle;
}
InterfaceClaim DeviceHandle::claim_interface(int interface)
{
return InterfaceClaim(libusb, *handle, interface);
}
unsigned DeviceHandle::bulk_transfer(const libusb_endpoint_descriptor& ep,
uint8_t* data, size_t size,
std::chrono::milliseconds timeout)
{
int ret;
callCheck("bulk_transfer", &LibusbIntf::bulk_transfer, libusb, *handle,
ep.bEndpointAddress, data, size, &ret, timeout.count());
return ret;
}
void DeviceHandle::drop(libusb_device_handle*&& handle, LibusbIntf*& libusb)
{
libusb->close(handle);
}
libusb_config_descriptor& Device::get_active_config_descriptor()
{
libusb_config_descriptor* ret;
callCheck("get_active_config_descriptor",
&LibusbIntf::get_active_config_descriptor, libusb, *dev, &ret);
return *ret;
}
uint8_t Device::get_bus_number()
{
return libusb->get_bus_number(*dev);
}
std::vector<uint8_t> Device::get_port_numbers()
{
// 7 is the maximum depth per the usb spec
std::vector<uint8_t> ret(7);
int r = callCheck("get_port_numbers", &LibusbIntf::get_port_numbers, libusb,
*dev, ret.data(), ret.size());
ret.resize(r);
return ret;
}
DeviceHandle Device::open()
{
libusb_device_handle* handle;
callCheck("open", &LibusbIntf::open, libusb, *dev, &handle);
return DeviceHandle(libusb, handle);
}
void Device::drop(libusb_device*&& dev, LibusbIntf*& libusb)
{
libusb->unref_device(dev);
}
std::vector<Device> Context::get_device_list()
{
libusb_device** devs;
callCheck("get_device_list", &LibusbIntf::get_device_list, libusb, *ctx,
&devs);
std::vector<Device> ret;
for (size_t i = 0; devs[i] != nullptr; ++i)
{
ret.push_back(Device(libusb, devs[i]));
}
libusb->free_device_list(devs, 0);
return ret;
}
void Context::drop(libusb_context*&& ctx, LibusbIntf*& libusb)
{
libusb->exit(ctx);
}
libusb_context* Context::init()
{
libusb_context* ctx = nullptr;
callCheck("init", &LibusbIntf::init, libusb, &ctx);
return ctx;
}
} // namespace libusb
} // namespace hoth
} // namespace google