//
// Copyright 2010 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#include
#include
#include
#include
#include
#include
using namespace uhd::transport;
static int libusb_debug_level = 0;
static int libusb_timeout = 0;
/***********************************************************************
* libusb-1.0 implementation of USB control transport
**********************************************************************/
class libusb_control_impl : public usb_control {
public:
libusb_control_impl(uhd::usb_descriptor_t descriptor);
~libusb_control_impl();
size_t submit(boost::uint8_t request_type,
boost::uint8_t request,
boost::uint16_t value,
boost::uint16_t index,
unsigned char *buff,
boost::uint16_t length);
static uhd::usb_descriptor_t create_descriptor(libusb_device *dev);
static std::string get_serial(libusb_device *dev);
private:
uhd::usb_descriptor_t _descriptor;
libusb_context *_ctx;
libusb_device_handle *_dev_handle;
bool open_device();
bool open_interface();
bool compare_device(libusb_device *dev, uhd::usb_descriptor_t descriptor);
};
libusb_control_impl::libusb_control_impl(uhd::usb_descriptor_t descriptor)
: _descriptor(descriptor), _ctx(NULL), _dev_handle(NULL)
{
if (libusb_init(&_ctx) < 0)
throw std::runtime_error("USB: failed to initialize libusb");
libusb_set_debug(_ctx, libusb_debug_level);
if (!open_device())
throw std::runtime_error("USB: failed to open device");
if (!open_interface())
throw std::runtime_error("USB: failed to open device interface");
}
libusb_control_impl::~libusb_control_impl()
{
libusb_close(_dev_handle);
libusb_exit(_ctx);
}
uhd::usb_descriptor_t libusb_control_impl::create_descriptor(libusb_device *dev)
{
libusb_device_descriptor desc;
if (libusb_get_device_descriptor(dev, &desc) < 0)
throw std::runtime_error("USB: failed to get device descriptor");
uhd::usb_descriptor_t descriptor;
descriptor.serial = get_serial(dev);
descriptor.product_id = desc.idProduct;
descriptor.vendor_id = desc.idVendor;
descriptor.device_addr = libusb_get_device_address(dev);
return descriptor;
}
std::string libusb_control_impl::get_serial(libusb_device *dev)
{
unsigned char buff[32];
libusb_device_descriptor desc;
if (libusb_get_device_descriptor(dev, &desc) < 0)
return "";
if (desc.iSerialNumber == 0)
return "";
//open the device because we have to
libusb_device_handle *dev_handle;
if (libusb_open(dev, &dev_handle) < 0)
return "";
if (libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber,
buff, sizeof(buff)) < 0) {
return "";
}
libusb_close(dev_handle);
return (char*) buff;
}
bool libusb_control_impl::open_device()
{
libusb_device **list;
libusb_device *dev;
ssize_t cnt = libusb_get_device_list(_ctx, &list);
if (cnt < 0)
return cnt;
ssize_t i = 0;
for (i = 0; i < cnt; i++) {
dev = list[i];
if (compare_device(dev, _descriptor))
goto found;
}
return false;
found:
int ret;
if ((ret = libusb_open(dev, &_dev_handle)) < 0)
return false;
else
return true;
}
bool libusb_control_impl::compare_device(libusb_device *dev,
uhd::usb_descriptor_t descriptor)
{
std::string serial = descriptor.serial;
boost::uint16_t vendor_id = descriptor.vendor_id;
boost::uint16_t product_id = descriptor.product_id;
boost::uint8_t device_addr = descriptor.device_addr;
libusb_device_descriptor libusb_desc;
if (libusb_get_device_descriptor(dev, &libusb_desc) < 0)
return false;
if (serial != get_serial(dev))
return false;
if (vendor_id != libusb_desc.idVendor)
return false;
if (product_id != libusb_desc.idProduct)
return false;
if (device_addr != libusb_get_device_address(dev))
return false;
return true;
}
bool libusb_control_impl::open_interface()
{
if (libusb_claim_interface(_dev_handle, 0) < 0)
return false;
else
return true;
}
size_t libusb_control_impl::submit(boost::uint8_t request_type,
boost::uint8_t request,
boost::uint16_t value,
boost::uint16_t index,
unsigned char *buff,
boost::uint16_t length)
{
return libusb_control_transfer(_dev_handle,
request_type,
request,
value,
index,
buff,
length,
libusb_timeout);
}
/***********************************************************************
* USB control public make functions
**********************************************************************/
usb_control::sptr usb_control::make(uhd::usb_descriptor_t descriptor)
{
return sptr(new libusb_control_impl(descriptor));
}
uhd::usb_descriptors_t usb_control::get_device_list()
{
libusb_device **list;
uhd::usb_descriptors_t descriptors;
if (libusb_init(NULL) < 0)
throw std::runtime_error("USB: failed to initialize libusb");
ssize_t cnt = libusb_get_device_list(NULL, &list);
if (cnt < 0)
throw std::runtime_error("USB: failed to get device list");
ssize_t i = 0;
for (i = 0; i < cnt; i++) {
libusb_device *dev = list[i];
descriptors.push_back(libusb_control_impl::create_descriptor(dev));
}
libusb_free_device_list(list, 0);
libusb_exit(NULL);
return descriptors;
}