Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update libusb to version 1.0 #673

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmake/modules/FindLIBUSB.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ IF(NOT LIBUSB_FOUND)
SET(LIBUSB_LIBRARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/LibUSB-Win32/bin/x86/")
ELSE(MINGW)
FIND_PATH(LIBUSB_INCLUDE_DIRS lusb0_usb.h "$ENV{ProgramW6432}/libusb-win32/include" NO_SYSTEM_ENVIRONMENT_PATH)
FIND_LIBRARY(LIBUSB_LIBRARIES NAMES libusb PATHS "$ENV{ProgramW6432}/libusb-win32/lib/msvc_x64")
FIND_LIBRARY(LIBUSB_LIBRARIES NAMES usb-1.0 libusb-1.0 libusb PATHS "$ENV{ProgramW6432}/libusb-win32/lib/msvc_x64")
SET(LIBUSB_LIBRARY_DIR "$ENV{ProgramW6432}/libusb-win32/bin/amd64/")
ENDIF(MINGW)
# Must fix up variable to avoid backslashes during packaging
Expand All @@ -41,7 +41,7 @@ IF(NOT LIBUSB_FOUND)
# If not under Windows we use PkgConfig
FIND_PACKAGE (PkgConfig)
IF(PKG_CONFIG_FOUND)
PKG_CHECK_MODULES(LIBUSB REQUIRED libusb)
PKG_CHECK_MODULES(LIBUSB REQUIRED libusb-1.0)
ELSE(PKG_CONFIG_FOUND)
MESSAGE(FATAL_ERROR "Could not find PkgConfig")
ENDIF(PKG_CONFIG_FOUND)
Expand Down
308 changes: 284 additions & 24 deletions libnfc/buses/usbbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau
* Copyright (C) 2022 Kenspeckle
* See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file:
*
Expand All @@ -24,56 +25,315 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

/**
* @file usbbus.c
* @brief libusb 0.1 driver wrapper
*/
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include "usbbus.h"
#include "log.h"

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H

#include <stdlib.h>

#include "usbbus.h"
#include "log.h"
#define LOG_CATEGORY "libnfc.buses.usbbus"
#define LOG_CATEGORY "libnfc.bus.usbbus"
#define LOG_GROUP NFC_LOG_GROUP_DRIVER

int usb_prepare(void)
{
static libusb_context *ctx = NULL;

uint8_t get_usb_num_configs(struct libusb_device *dev);

int usbbus_prepare() {
static bool usb_initialized = false;
int res;
if (!usb_initialized) {

#ifdef ENVVARS
char *env_log_level = getenv("LIBNFC_LOG_LEVEL");
// Set libusb debug only if asked explicitely:
// LIBUSB_LOG_LEVEL=12288 (= NFC_LOG_PRIORITY_DEBUG * 2 ^ NFC_LOG_GROUP_LIBUSB)
if (env_log_level && (((atoi(env_log_level) >> (NFC_LOG_GROUP_LIBUSB * 2)) & 0x00000003) >= NFC_LOG_PRIORITY_DEBUG)) {
if (env_log_level
&& (((atoi(env_log_level) >> (NFC_LOG_GROUP_LIBUSB * 2)) & 0x00000003) >= NFC_LOG_PRIORITY_DEBUG)) {
setenv("USB_DEBUG", "255", 1);
}
#endif

usb_init();
res = libusb_init(&ctx);
if (res != 0) {
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to init libusb (%s)",
libusb_strerror(res));
return res;
}
usb_initialized = true;
}

int res;
// usb_find_busses will find all of the busses on the system. Returns the
// number of changes since previous call to this function (total of new
// busses and busses removed).
if ((res = usb_find_busses()) < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to find USB busses (%s)", _usb_strerror(res));
return -1;
}
// usb_find_devices will find all of the devices on each bus. This should be
// called after usb_find_busses. Returns the number of changes since the
// previous call to this function (total of new device and devices removed).
if ((res = usb_find_devices()) < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to find USB devices (%s)", _usb_strerror(res));
libusb_device **tmp_devices;
ssize_t num_devices = libusb_get_device_list(ctx, &tmp_devices);
libusb_free_device_list(tmp_devices, (int) num_devices);
if (num_devices <= 0) {
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to find USB devices (%s)",
libusb_strerror((int) num_devices));
return -1;
}
return 0;
}

size_t usbbus_usb_scan(nfc_connstring connstrings[],
const size_t connstrings_len,
struct usbbus_device *nfc_usb_devices,
const size_t num_nfc_usb_devices,
char *usb_driver_name) {
usbbus_prepare();

size_t device_found = 0;
struct libusb_device **devices;
ssize_t num_devices = libusb_get_device_list(ctx, &devices);
for (size_t i = 0; i < num_devices; i++) {
struct libusb_device *dev = devices[i];

for (size_t nfc_dev_idx = 0; nfc_dev_idx < num_nfc_usb_devices; nfc_dev_idx++) {
if (nfc_usb_devices[nfc_dev_idx].vendor_id == usbbus_get_vendor_id(dev)
&& nfc_usb_devices[nfc_dev_idx].product_id == usbbus_get_product_id(dev)) {

size_t valid_config_idx = 1;

// Make sure there are 2 endpoints available
// with libusb-win32 we got some null pointers so be robust before looking at endpoints
if (nfc_usb_devices[nfc_dev_idx].max_packet_size == 0) {

bool found_valid_config = false;

for (size_t config_idx = 0; config_idx < get_usb_num_configs(dev); i++) {
struct libusb_config_descriptor *usb_config;
int r = libusb_get_config_descriptor(dev, config_idx, &usb_config);

if (r != 0
|| usb_config->interface == NULL
|| usb_config->interface->altsetting == NULL
|| usb_config->interface->altsetting->bNumEndpoints < 2) {
// Nope, we maybe want the next one, let's try to find another
libusb_free_config_descriptor(usb_config);
continue;
}

libusb_free_config_descriptor(usb_config);

found_valid_config = true;
valid_config_idx = config_idx;
break;
}
if (!found_valid_config) {
libusb_unref_device(dev);
continue;
}
}

libusb_device_handle *udev;
int res = libusb_open(dev, &udev);
if (res < 0 && udev == NULL) {
libusb_unref_device(dev);
continue;
}

// Set configuration
res = libusb_set_configuration(udev, (int) valid_config_idx);
if (res < 0) {
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to set USB configuration (%s)",
libusb_strerror(res));
libusb_close(udev);
libusb_unref_device(dev);
// we failed to use the device
continue;
}

log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "device found: Vendor-Id: %d Product-Id %d",
usbbus_get_vendor_id(dev), usbbus_get_product_id(dev));
libusb_close(udev);

uint8_t dev_address = libusb_get_device_address(dev);
printf("%s:%03d:%03d",
"Test",
dev_address,
(int) valid_config_idx);
size_t size_new_str = snprintf(
connstrings[device_found],
sizeof(connstrings[device_found]),
"%s:%03d:%03d",
usb_driver_name,
dev_address,
(int) valid_config_idx);

if (size_new_str >= (int) sizeof(nfc_connstring)) {
// truncation occurred, skipping that one
libusb_unref_device(dev);
continue;
}
device_found++;
// Test if we reach the maximum "wanted" devices
if (device_found == connstrings_len) {
libusb_free_device_list(devices, 0);
return device_found;
}
}
}
}
libusb_free_device_list(devices, 0);
return device_found;
}

void usbbus_get_usb_endpoints(struct libusb_device *dev,
uint8_t *endpoint_in,
uint8_t *endpoint_out,
uint16_t *max_packet_size) {

bool endpoint_in_set = false;
bool endpoint_out_set = false;
size_t num_configs = get_usb_num_configs(dev);
for (size_t config_idx = 0; config_idx < num_configs; config_idx++) {
struct libusb_config_descriptor *usb_config;

int r = libusb_get_config_descriptor(dev, config_idx, &usb_config);
if (r != 0) {
continue;
}

if (!usb_config->interface) {
continue;
}
for (size_t interface_idx = 0; interface_idx < usb_config->bNumInterfaces; interface_idx++) {
struct libusb_interface interface = usb_config->interface[interface_idx];
if (!interface.altsetting) {
continue;
}
for (size_t settings_idx = 0; settings_idx < interface.num_altsetting; settings_idx++) {
struct libusb_interface_descriptor settings = interface.altsetting[settings_idx];
if (!settings.endpoint) {
continue;
}

// 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out
for (size_t endpoint_idx = 0; endpoint_idx < settings.bNumEndpoints; endpoint_idx++) {
struct libusb_endpoint_descriptor endpoint = settings.endpoint[endpoint_idx];

// Only accept bulk transfer endpoints (ignore interrupt endpoints)
if (endpoint.bmAttributes != LIBUSB_ENDPOINT_TRANSFER_TYPE_BULK) {
continue;
}

// Copy the endpoint to a local var, makes it more readable code
uint8_t endpoint_address = endpoint.bEndpointAddress;

// Test if we dealing with a bulk IN endpoint
if ((endpoint_address & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN && !endpoint_in_set) {
*endpoint_in = endpoint_address;
*max_packet_size = endpoint.wMaxPacketSize;
endpoint_in_set = true;
}
// Test if we dealing with a bulk OUT endpoint
if ((endpoint_address & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT && !endpoint_out_set) {
*endpoint_out = endpoint_address;
*max_packet_size = endpoint.wMaxPacketSize;
endpoint_out_set = true;
}

if (endpoint_in_set && endpoint_out_set) {
libusb_free_config_descriptor(usb_config);
return;
}
}
}
}

libusb_free_config_descriptor(usb_config);
}
}

uint8_t get_usb_num_configs(struct libusb_device *dev) {
struct libusb_device_descriptor descriptor;
libusb_get_device_descriptor(dev, &descriptor);
return descriptor.bNumConfigurations;
}

void usbbus_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len) {
struct libusb_device_descriptor descriptor;
libusb_get_device_descriptor(dev, &descriptor);
if (descriptor.iManufacturer || descriptor.iProduct) {
if (udev) {
libusb_get_string_descriptor_ascii(udev, descriptor.iManufacturer & 0xff, (unsigned char *) buffer, len);
if (strlen(buffer) > 0) {
strncpy(buffer + strlen(buffer), " / ", 4);
}
libusb_get_string_descriptor_ascii(udev,
descriptor.iProduct & 0xff,
(unsigned char *) buffer + strlen(buffer),
len - strlen(buffer));
}
}
}


void usbbus_get_device(uint8_t dev_address, struct libusb_device ** dev, struct libusb_device_handle ** dev_handle) {
struct libusb_device ** device_list;
ssize_t num_devices = libusb_get_device_list(ctx, &device_list);
for (size_t i = 0; i < num_devices; i++) {
if (libusb_get_device_address(device_list[i]) != dev_address) {
continue;
} else {
*dev = device_list[i];
int res = libusb_open(*dev, dev_handle);
if (res != 0 || dev_handle == NULL) {
log_put(LOG_GROUP,LOG_CATEGORY,NFC_LOG_PRIORITY_ERROR,
"Unable to open libusb device (%s)",libusb_strerror(res));
continue;
}
}
}

// libusb works with a reference counter which is set to 1 for each device when calling libusb_get_device_list and increased
// by libusb_open. Thus we decrease the counter by 1 for all devices and only the "real" device will survive
libusb_free_device_list(device_list, num_devices);
}


void usbbus_close(struct libusb_device * dev, struct libusb_device_handle * dev_handle) {
libusb_close(dev_handle);
libusb_unref_device(dev);
libusb_exit(ctx);
}

uint16_t usbbus_get_vendor_id(struct libusb_device *dev) {
struct libusb_device_descriptor descriptor;
libusb_get_device_descriptor(dev, &descriptor);
return descriptor.idVendor;
}

uint16_t usbbus_get_product_id(struct libusb_device *dev) {
struct libusb_device_descriptor descriptor;
libusb_get_device_descriptor(dev, &descriptor);
return descriptor.idProduct;
}


int usbbus_get_num_alternate_settings(struct libusb_device *dev, uint8_t config_idx) {
struct libusb_config_descriptor *usb_config;
int r = libusb_get_config_descriptor(dev, config_idx, &usb_config);
if (r != 0 || usb_config == NULL) {
return -1;
}
libusb_free_config_descriptor(usb_config);
return usb_config->interface->num_altsetting;
}



Loading