diff --git a/cmake/modules/FindLIBUSB.cmake b/cmake/modules/FindLIBUSB.cmake index 4afd8afa..bf8fa22a 100644 --- a/cmake/modules/FindLIBUSB.cmake +++ b/cmake/modules/FindLIBUSB.cmake @@ -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 @@ -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) diff --git a/libnfc/buses/usbbus.c b/libnfc/buses/usbbus.c index d2477f5a..fed730e4 100644 --- a/libnfc/buses/usbbus.c +++ b/libnfc/buses/usbbus.c @@ -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: * @@ -24,56 +25,315 @@ * along with this program. If not, see * */ - -/** - * @file usbbus.c - * @brief libusb 0.1 driver wrapper - */ +#include +#include +#include +#include "usbbus.h" +#include "log.h" #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H -#include - -#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; +} + + + diff --git a/libnfc/buses/usbbus.h b/libnfc/buses/usbbus.h index 3c0381a8..8ac87091 100644 --- a/libnfc/buses/usbbus.h +++ b/libnfc/buses/usbbus.h @@ -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: * @@ -25,30 +26,32 @@ * */ -/** - * @file usbbus.h - * @brief libusb 0.1 driver header - */ +#ifndef __NFC_BUS_USBBUS_H__ +#define __NFC_BUS_USBBUS_H__ -#ifndef __NFC_BUS_USB_H__ -# define __NFC_BUS_USB_H__ - -#ifndef _WIN32 -// Under POSIX system, we use libusb (>= 0.1.12) -#include -#include -#define USB_TIMEDOUT ETIMEDOUT -#define _usb_strerror( X ) strerror(-X) -#else -// Under Windows we use libusb-win32 (>= 1.2.5) -#include -#define USB_TIMEDOUT 116 -#define _usb_strerror( X ) usb_strerror() -#endif +#include +#include +#include "nfc/nfc-types.h" + +#define EMPTY_STRING ((unsigned char *)"\0") -#include -#include +struct usbbus_device { + uint16_t vendor_id; + uint16_t product_id; + const char *name; + uint16_t max_packet_size; +}; -int usb_prepare(void); -#endif // __NFC_BUS_USB_H__ + +int usbbus_prepare(); + +size_t usbbus_usb_scan(nfc_connstring connstrings[], size_t connstrings_len, struct usbbus_device * nfc_usb_devices, size_t num_nfc_usb_devices, char * usb_driver_name); +void usbbus_get_usb_endpoints(struct libusb_device *dev, uint8_t * endpoint_in, uint8_t * endpoint_out, uint16_t * max_packet_size); +void usbbus_get_usb_device_name(struct libusb_device * dev, libusb_device_handle *udev, char *buffer, size_t len); +void usbbus_get_device(uint8_t dev_address, struct libusb_device ** dev, struct libusb_device_handle ** dev_handle); +void usbbus_close(struct libusb_device * dev, struct libusb_device_handle * dev_handle); +uint16_t usbbus_get_vendor_id(struct libusb_device * dev); +uint16_t usbbus_get_product_id(struct libusb_device * dev); +int usbbus_get_num_alternate_settings(struct libusb_device *dev, uint8_t config_idx); +#endif diff --git a/libnfc/drivers/acr122_usb.c b/libnfc/drivers/acr122_usb.c index fc545014..4e662d48 100644 --- a/libnfc/drivers/acr122_usb.c +++ b/libnfc/drivers/acr122_usb.c @@ -76,7 +76,7 @@ Thanks to d18c7db and Okko for example code #define LOG_GROUP NFC_LOG_GROUP_DRIVER #define LOG_CATEGORY "libnfc.driver.acr122_usb" -#define USB_INFINITE_TIMEOUT 0 +#define USBBUS_INFINITE_TIMEOUT 0 #define DRIVER_DATA(pnd) ((struct acr122_usb_data*)(pnd->driver_data)) @@ -174,10 +174,12 @@ struct acr122_usb_apdu_frame { // Internal data struct struct acr122_usb_data { - usb_dev_handle *pudh; - uint32_t uiEndPointIn; - uint32_t uiEndPointOut; - uint32_t uiMaxPacketSize; + libusb_device * dev; + libusb_device_handle *pudh; + uint8_t configIdx; + uint8_t uiEndPointIn; + uint8_t uiEndPointOut; + uint16_t uiMaxPacketSize; volatile bool abort_flag; // Keep some buffers to reduce memcpy() usage struct acr122_usb_tama_frame tama_frame; @@ -220,13 +222,15 @@ static int acr122_usb_send_apdu(nfc_device *pnd, static int acr122_usb_bulk_read(struct acr122_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) { - int res = usb_bulk_read(data->pudh, data->uiEndPointIn, (char *) abtRx, szRx, timeout); - if (res > 0) { - LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, res); - } else if (res < 0) { - if (res != -USB_TIMEDOUT) { + int actual_length; + int res = libusb_bulk_transfer(data->pudh, data->uiEndPointIn, (unsigned char *) abtRx, szRx, &actual_length, timeout); + if (res == 0) { + LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, actual_length); + res = actual_length; + } else { + if (res != LIBUSB_ERROR_TIMEOUT) { res = NFC_EIO; - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read from USB (%s)", _usb_strerror(res)); + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read from USB (%s)", libusb_strerror(res)); } else { res = NFC_ETIMEOUT; } @@ -238,15 +242,16 @@ static int acr122_usb_bulk_write(struct acr122_usb_data *data, uint8_t abtTx[], const size_t szTx, const int timeout) { LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTx, szTx); - int res = usb_bulk_write(data->pudh, data->uiEndPointOut, (char *) abtTx, szTx, timeout); - if (res > 0) { + int actual_length; + int res = libusb_bulk_transfer(data->pudh, data->uiEndPointOut, (unsigned char *) abtTx, szTx, &actual_length, timeout); + if (res == 0) { // HACK This little hack is a well know problem of USB, see http://www.libusb.org/ticket/6 for more details - if ((res % data->uiMaxPacketSize) == 0) { - usb_bulk_write(data->pudh, data->uiEndPointOut, "\0", 0, timeout); + if ((actual_length > 0) && ((actual_length % data->uiMaxPacketSize) == 0)) { + libusb_bulk_transfer(data->pudh, data->uiEndPointOut, EMPTY_STRING, 0, &actual_length, timeout); } - } else if (res < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", _usb_strerror(res)); - if (res == -USB_TIMEDOUT) { + } else { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", libusb_strerror(res)); + if (res == LIBUSB_ERROR_TIMEOUT) { res = NFC_ETIMEOUT; } else { res = NFC_EIO; @@ -259,120 +264,46 @@ struct acr122_usb_supported_device { uint16_t vendor_id; uint16_t product_id; const char *name; + uint16_t max_packet_size; }; const struct acr122_usb_supported_device acr122_usb_supported_devices[] = { - { 0x072F, 0x2200, "ACS ACR122" }, - { 0x072F, 0x90CC, "Touchatag" }, - { 0x072F, 0x2214, "ACS ACR1222" }, + { 0x072F, 0x2200, "ACS ACR122", 0x40 }, + { 0x072F, 0x90CC, "Touchatag", 0x40 }, + { 0x072F, 0x2214, "ACS ACR1222", 0x40 }, }; -// Find transfer endpoints for bulk transfers -static void -acr122_usb_get_end_points(struct usb_device *dev, struct acr122_usb_data *data) -{ - uint32_t uiIndex; - uint32_t uiEndPoint; - struct usb_interface_descriptor *puid = dev->config->interface->altsetting; - - // 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out - for (uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++) { - // Only accept bulk transfer endpoints (ignore interrupt endpoints) - if (puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK) - continue; - - // Copy the endpoint to a local var, makes it more readable code - uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress; - - // Test if we dealing with a bulk IN endpoint - if ((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN) { - data->uiEndPointIn = uiEndPoint; - data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize; - } - // Test if we dealing with a bulk OUT endpoint - if ((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT) { - data->uiEndPointOut = uiEndPoint; - data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize; - } - } -} +const size_t num_acr122_usb_supported_device = sizeof(acr122_usb_supported_devices) / sizeof(struct acr122_usb_supported_device); + + static size_t acr122_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { - (void)context; - - usb_prepare(); - - size_t device_found = 0; - uint32_t uiBusIndex = 0; - struct usb_bus *bus; - for (bus = usb_get_busses(); bus; bus = bus->next) { - struct usb_device *dev; - - for (dev = bus->devices; dev; dev = dev->next, uiBusIndex++) { - for (size_t n = 0; n < sizeof(acr122_usb_supported_devices) / sizeof(struct acr122_usb_supported_device); n++) { - if ((acr122_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && - (acr122_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { - // Make sure there are 2 endpoints available - // with libusb-win32 we got some null pointers so be robust before looking at endpoints: - if (dev->config == NULL || dev->config->interface == NULL || dev->config->interface->altsetting == NULL) { - // Nope, we maybe want the next one, let's try to find another - continue; - } - if (dev->config->interface->altsetting->bNumEndpoints < 2) { - // Nope, we maybe want the next one, let's try to find another - continue; - } - - usb_dev_handle *udev = usb_open(dev); - if (udev == NULL) - continue; - - // Set configuration - // acr122_usb_get_usb_device_name (dev, udev, pnddDevices[device_found].acDevice, sizeof (pnddDevices[device_found].acDevice)); - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "device found: Bus %s Device %s Name %s", bus->dirname, dev->filename, acr122_usb_supported_devices[n].name); - usb_close(udev); - if (snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", ACR122_USB_DRIVER_NAME, bus->dirname, dev->filename) >= (int)sizeof(nfc_connstring)) { - // truncation occurred, skipping that one - continue; - } - device_found++; - // Test if we reach the maximum "wanted" devices - if (device_found == connstrings_len) { - return device_found; - } - } - } - } + (void) context; + struct usbbus_device devices[num_acr122_usb_supported_device]; + for (size_t i = 0; i < num_acr122_usb_supported_device; i++) { + devices[i].product_id = acr122_usb_supported_devices[i].product_id; + devices[i].vendor_id = acr122_usb_supported_devices[i].vendor_id; + devices[i].name = acr122_usb_supported_devices[i].name; + devices[i].max_packet_size = acr122_usb_supported_devices[i].max_packet_size; } - - return device_found; + return usbbus_usb_scan(connstrings, connstrings_len, devices, num_acr122_usb_supported_device, ACR122_USB_DRIVER_NAME); } -struct acr122_usb_descriptor { - char *dirname; - char *filename; -}; - static bool -acr122_usb_get_usb_device_name(struct usb_device *dev, usb_dev_handle *udev, char *buffer, size_t len) +acr122_usb_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len) { *buffer = '\0'; - if (dev->descriptor.iManufacturer || dev->descriptor.iProduct) { - if (udev) { - usb_get_string_simple(udev, dev->descriptor.iManufacturer, buffer, len); - if (strlen(buffer) > 0) - strcpy(buffer + strlen(buffer), " / "); - usb_get_string_simple(udev, dev->descriptor.iProduct, buffer + strlen(buffer), len - strlen(buffer)); - } - } + usbbus_get_usb_device_name(dev, udev, buffer, len); + uint16_t vendor_id = usbbus_get_vendor_id(dev); + uint16_t product_id = usbbus_get_product_id(dev); if (!*buffer) { - for (size_t n = 0; n < sizeof(acr122_usb_supported_devices) / sizeof(struct acr122_usb_supported_device); n++) { - if ((acr122_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && - (acr122_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { + for (size_t n = 0; n < num_acr122_usb_supported_device; n++) { + if ((acr122_usb_supported_devices[n].vendor_id == vendor_id) && + (acr122_usb_supported_devices[n].product_id == product_id)) { strncpy(buffer, acr122_usb_supported_devices[n].name, len); buffer[len - 1] = '\0'; return true; @@ -387,106 +318,115 @@ static nfc_device * acr122_usb_open(const nfc_context *context, const nfc_connstring connstring) { nfc_device *pnd = NULL; - struct acr122_usb_descriptor desc = { NULL, NULL }; - int connstring_decode_level = connstring_decode(connstring, ACR122_USB_DRIVER_NAME, "usb", &desc.dirname, &desc.filename); - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d element(s) have been decoded from \"%s\"", connstring_decode_level, connstring); - if (connstring_decode_level < 1) { - goto free_mem; + char *dev_address_str; + char *config_idx_str; + int connstring_decode_level = connstring_decode(connstring, ACR122_USB_DRIVER_NAME, "usb", &dev_address_str, &config_idx_str); + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_DEBUG, + "%d element(s) have been decoded from \"%s\"", + connstring_decode_level, + connstring); + if (connstring_decode_level < 2) { + free(dev_address_str); + free(config_idx_str); + return NULL; } + uint8_t dev_addres = atoi(dev_address_str); + uint8_t config_idx = atoi(config_idx_str); + + usbbus_prepare(); struct acr122_usb_data data = { + .dev = NULL, .pudh = NULL, + .configIdx = config_idx, .uiEndPointIn = 0, .uiEndPointOut = 0, }; - struct usb_bus *bus; - struct usb_device *dev; - - usb_prepare(); + usbbus_get_device(dev_addres, &data.dev, &data.pudh); + // Reset device + libusb_reset_device(data.pudh); + + // Retrieve end points + usbbus_get_usb_endpoints(data.dev, &(data.uiEndPointIn), &(data.uiEndPointOut), &(data.uiMaxPacketSize)); + // Claim interface + int res = libusb_claim_interface(data.pudh, 0); + if (res < 0) { + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_ERROR, + "Unable to claim USB interface (%s)", + libusb_strerror(res)); + libusb_close(data.pudh); + // we failed to use the specified device + free(dev_address_str); + free(config_idx_str); + return NULL; + } - for (bus = usb_get_busses(); bus; bus = bus->next) { - if (connstring_decode_level > 1) { - // A specific bus have been specified - if (0 != strcmp(bus->dirname, desc.dirname)) - continue; + // Check if there are more than 0 alternative interfaces and claim the first one + if (usbbus_get_num_alternate_settings(data.dev, data.configIdx) > 0) { + res = libusb_set_interface_alt_setting(data.pudh, 0, 0); + if (res < 0) { + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_ERROR, + "Unable to set alternate setting on USB interface (%s)", + libusb_strerror(res)); + libusb_close(data.pudh); + // we failed to use the specified device + free(dev_address_str); + free(config_idx_str); + return NULL; } - for (dev = bus->devices; dev; dev = dev->next) { - if (connstring_decode_level > 2) { - // A specific dev have been specified - if (0 != strcmp(dev->filename, desc.filename)) - continue; - } - // Open the USB device - if ((data.pudh = usb_open(dev)) == NULL) - continue; - // Reset device - usb_reset(data.pudh); - // Retrieve end points - acr122_usb_get_end_points(dev, &data); - // Claim interface - int res = usb_claim_interface(data.pudh, 0); - if (res < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to claim USB interface (%s)", _usb_strerror(res)); - usb_close(data.pudh); - // we failed to use the specified device - goto free_mem; - } - - // Check if there are more than 0 alternative interfaces and claim the first one - if (dev->config->interface->altsetting->bAlternateSetting > 0) { - res = usb_set_altinterface(data.pudh, 0); - if (res < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set alternate setting on USB interface (%s)", _usb_strerror(res)); - usb_close(data.pudh); - // we failed to use the specified device - goto free_mem; - } - } - - // Allocate memory for the device info and specification, fill it and return the info - pnd = nfc_device_new(context, connstring); - if (!pnd) { - perror("malloc"); - goto error; - } - acr122_usb_get_usb_device_name(dev, data.pudh, pnd->name, sizeof(pnd->name)); - - pnd->driver_data = malloc(sizeof(struct acr122_usb_data)); - if (!pnd->driver_data) { - perror("malloc"); - goto error; - } - *DRIVER_DATA(pnd) = data; - - // Alloc and init chip's data - if (pn53x_data_new(pnd, &acr122_usb_io) == NULL) { - perror("malloc"); - goto error; - } + } - memcpy(&(DRIVER_DATA(pnd)->tama_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template)); - memcpy(&(DRIVER_DATA(pnd)->apdu_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template)); - CHIP_DATA(pnd)->timer_correction = 46; // empirical tuning - pnd->driver = &acr122_usb_driver; + // Allocate memory for the device info and specification, fill it and return the info + pnd = nfc_device_new(context, connstring); + if (!pnd) { + perror("malloc"); + free(dev_address_str); + free(config_idx_str); + return NULL; + } + acr122_usb_get_usb_device_name(data.dev, data.pudh, pnd->name, sizeof(pnd->name)); + + pnd->driver_data = malloc(sizeof(struct acr122_usb_data)); + if (!pnd->driver_data) { + perror("malloc"); + nfc_device_free(pnd); + free(dev_address_str); + free(config_idx_str); + return NULL; + } + *DRIVER_DATA(pnd) = data; + + // Alloc and init chip's data + if (pn53x_data_new(pnd, &acr122_usb_io) == NULL) { + perror("malloc"); + nfc_device_free(pnd); + free(dev_address_str); + free(config_idx_str); + return NULL; + } - if (acr122_usb_init(pnd) < 0) { - usb_close(data.pudh); - goto error; - } - DRIVER_DATA(pnd)->abort_flag = false; - goto free_mem; - } + memcpy(&(DRIVER_DATA(pnd)->tama_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template)); + memcpy(&(DRIVER_DATA(pnd)->apdu_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template)); + CHIP_DATA(pnd)->timer_correction = 46; // empirical tuning + pnd->driver = &acr122_usb_driver; + + if (acr122_usb_init(pnd) < 0) { + libusb_close(data.pudh); + nfc_device_free(pnd); + free(dev_address_str); + free(config_idx_str); + return NULL; } - // We ran out of devices before the index required - goto free_mem; + DRIVER_DATA(pnd)->abort_flag = false; -error: - // Free allocated structure on error. - nfc_device_free(pnd); - pnd = NULL; -free_mem: - free(desc.dirname); - free(desc.filename); + free(dev_address_str); + free(config_idx_str); return pnd; } @@ -496,14 +436,17 @@ acr122_usb_close(nfc_device *pnd) acr122_usb_ack(pnd); pn53x_idle(pnd); - int res; - if ((res = usb_release_interface(DRIVER_DATA(pnd)->pudh, 0)) < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to release USB interface (%s)", _usb_strerror(res)); + int res = libusb_release_interface(DRIVER_DATA(pnd)->pudh, 0); + if (res < 0) { + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_ERROR, + "Unable to release USB interface (%s)", + libusb_strerror(res)); } - if ((res = usb_close(DRIVER_DATA(pnd)->pudh)) < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to close USB connection (%s)", _usb_strerror(res)); - } + usbbus_close(DRIVER_DATA(pnd)->dev, DRIVER_DATA(pnd)->pudh); + pn53x_data_free(pnd); nfc_device_free(pnd); } @@ -579,7 +522,8 @@ acr122_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, co return NFC_SUCCESS; } -#define USB_TIMEOUT_PER_PASS 200 +#define USBBUS_TIMEOUT_PER_PASS 200 + static int acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) { @@ -589,26 +533,26 @@ acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, co int res; /* - * If no timeout is specified but the command is blocking, force a 200ms (USB_TIMEOUT_PER_PASS) + * If no timeout is specified but the command is blocking, force a 200ms (USBBUS_TIMEOUT_PER_PASS) * timeout to allow breaking the loop if the user wants to stop it. */ - int usb_timeout; + int usbbus_timeout; int remaining_time = timeout; read: - if (timeout == USB_INFINITE_TIMEOUT) { - usb_timeout = USB_TIMEOUT_PER_PASS; + if (timeout == USBBUS_INFINITE_TIMEOUT) { + usbbus_timeout = USBBUS_TIMEOUT_PER_PASS; } else { // A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism - remaining_time -= USB_TIMEOUT_PER_PASS; + remaining_time -= USBBUS_TIMEOUT_PER_PASS; if (remaining_time <= 0) { pnd->last_error = NFC_ETIMEOUT; return pnd->last_error; } else { - usb_timeout = MIN(remaining_time, USB_TIMEOUT_PER_PASS); + usbbus_timeout = MIN(remaining_time, USBBUS_TIMEOUT_PER_PASS); } } - res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), usb_timeout); + res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), usbbus_timeout); uint8_t attempted_response = RDR_to_PC_DataBlock; size_t len; diff --git a/libnfc/drivers/pn53x_usb.c b/libnfc/drivers/pn53x_usb.c index 52c40f08..2bed980e 100644 --- a/libnfc/drivers/pn53x_usb.c +++ b/libnfc/drivers/pn53x_usb.c @@ -31,6 +31,7 @@ #ifdef HAVE_CONFIG_H # include "config.h" + #endif // HAVE_CONFIG_H /* @@ -41,13 +42,13 @@ Thanks to d18c7db and Okko for example code #include #include #include -#include #include + #ifdef _MSC_VER #include #endif #include - +#include #include "nfc-internal.h" #include "buses/usbbus.h" #include "chips/pn53x.h" @@ -58,851 +59,778 @@ Thanks to d18c7db and Okko for example code #define LOG_CATEGORY "libnfc.driver.pn53x_usb" #define LOG_GROUP NFC_LOG_GROUP_DRIVER -#define USB_INFINITE_TIMEOUT 0 +#define USBBUS_INFINITE_TIMEOUT 0 #define DRIVER_DATA(pnd) ((struct pn53x_usb_data*)(pnd->driver_data)) const nfc_modulation_type no_target_support[] = {0}; typedef enum { - UNKNOWN, - NXP_PN531, - SONY_PN531, - NXP_PN533, - ASK_LOGO, - SCM_SCL3711, - SCM_SCL3712, - SONY_RCS360 + UNKNOWN, + NXP_PN531, + SONY_PN531, + NXP_PN533, + ASK_LOGO, + SCM_SCL3711, + SCM_SCL3712, + SONY_RCS360 } pn53x_usb_model; // Internal data struct struct pn53x_usb_data { - usb_dev_handle *pudh; - pn53x_usb_model model; - uint32_t uiEndPointIn; - uint32_t uiEndPointOut; - uint32_t uiMaxPacketSize; - volatile bool abort_flag; - bool possibly_corrupted_usbdesc; + libusb_device * dev; + libusb_device_handle *pudh; + uint8_t configIdx; + pn53x_usb_model model; + uint8_t uiEndPointIn; + uint8_t uiEndPointOut; + uint16_t uiMaxPacketSize; + volatile bool abort_flag; + bool possibly_corrupted_usbdesc; }; // Internal io struct const struct pn53x_io pn53x_usb_io; // Prototypes -bool pn53x_usb_get_usb_device_name(struct usb_device *dev, usb_dev_handle *udev, char *buffer, size_t len); +bool pn53x_usb_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len); int pn53x_usb_init(nfc_device *pnd); static int -pn53x_usb_bulk_read(struct pn53x_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) -{ - int res = usb_bulk_read(data->pudh, data->uiEndPointIn, (char *) abtRx, szRx, timeout); - if (res > 0) { - LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, res); - } else if (res < 0) { - if (res != -USB_TIMEDOUT) - log_put(NFC_LOG_GROUP_COM, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read from USB (%s)", _usb_strerror(res)); - } - return res; +pn53x_usb_bulk_read(struct pn53x_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) { + int actual_length; + int res = libusb_bulk_transfer(data->pudh, data->uiEndPointIn & 0xff, abtRx, szRx, &actual_length, timeout); + if (res == 0) { + LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, actual_length); + res = actual_length; + } else { + if (res != LIBUSB_ERROR_TIMEOUT) + log_put(NFC_LOG_GROUP_COM, + LOG_CATEGORY, + NFC_LOG_PRIORITY_ERROR, + "Unable to read from USB (%s)", + libusb_strerror(res)); + } + return res; } static int -pn53x_usb_bulk_write(struct pn53x_usb_data *data, uint8_t abtTx[], const size_t szTx, const int timeout) -{ - LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTx, szTx); - int res = usb_bulk_write(data->pudh, data->uiEndPointOut, (char *) abtTx, szTx, timeout); - if (res > 0) { - // HACK This little hack is a well know problem of USB, see http://www.libusb.org/ticket/6 for more details - if ((res % data->uiMaxPacketSize) == 0) { - usb_bulk_write(data->pudh, data->uiEndPointOut, "\0", 0, timeout); - } - } else { - log_put(NFC_LOG_GROUP_COM, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", _usb_strerror(res)); - } - return res; +pn53x_usb_bulk_write(struct pn53x_usb_data *data, uint8_t abtTx[], const size_t szTx, const int timeout) { + LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTx, szTx); + int actual_length; + int res = libusb_bulk_transfer(data->pudh, data->uiEndPointOut & 0xff, abtTx, szTx, &actual_length, timeout); + if (res == 0) { + // HACK This little hack is a well know problem of USB, see http://www.libusb.org/ticket/6 for more details + if ((actual_length > 0) && ((actual_length % data->uiMaxPacketSize) == 0)) { + libusb_bulk_transfer(data->pudh, data->uiEndPointOut & 0xff, EMPTY_STRING, 0, &actual_length, timeout); + } + } else { + log_put(NFC_LOG_GROUP_COM, + LOG_CATEGORY, + NFC_LOG_PRIORITY_ERROR, + "Unable to write to USB (%s)", + libusb_strerror(res)); + } + return res; } struct pn53x_usb_supported_device { - uint16_t vendor_id; - uint16_t product_id; - pn53x_usb_model model; - const char *name; - /* hardcoded known values for buggy hardware whose configuration vanishes */ - uint32_t uiEndPointIn; - uint32_t uiEndPointOut; - uint32_t uiMaxPacketSize; + uint16_t vendor_id; + uint16_t product_id; + pn53x_usb_model model; + const char *name; + /* hardcoded known values for buggy hardware whose configuration vanishes */ + uint32_t uiEndPointIn; + uint32_t uiEndPointOut; + uint32_t uiMaxPacketSize; }; const struct pn53x_usb_supported_device pn53x_usb_supported_devices[] = { - { 0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0x84, 0x04, 0x40 }, - { 0x04CC, 0x2533, NXP_PN533, "NXP / PN533", 0x84, 0x04, 0x40 }, - { 0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW", 0x84, 0x04, 0x40 }, - { 0x04E6, 0x5594, SCM_SCL3712, "SCM Micro / SCL3712-NFC&RW", 0, 0, 0 }, // to check on real device - { 0x054c, 0x0193, SONY_PN531, "Sony / PN531", 0x84, 0x04, 0x40 }, - { 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x84, 0x04, 0x40 }, - { 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]", 0x84, 0x04, 0x40 } + {0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0x84, 0x04, 0x40}, + {0x04CC, 0x2533, NXP_PN533, "NXP / PN533", 0x84, 0x04, 0x40}, + {0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW", 0x84, 0x04, 0x40}, + {0x04E6, 0x5594, SCM_SCL3712, "SCM Micro / SCL3712-NFC&RW", 0, 0, 0}, // to check on real device + {0x054c, 0x0193, SONY_PN531, "Sony / PN531", 0x84, 0x04, 0x40}, + {0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x84, 0x04, 0x40}, + {0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]", 0x84, 0x04, 0x40} }; +const size_t num_pn53x_usb_supported_devices = sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); + // PN533 USB descriptors backup buffers const uint8_t btXramUsbDesc_scl3711[] = { - 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, - 0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, - 0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x1e, 0x03, 0x53, 0x00, - 0x43, 0x00, 0x4c, 0x00, 0x33, 0x00, 0x37, 0x00, 0x31, 0x00, 0x31, 0x00, - 0x2d, 0x00, 0x4e, 0x00, 0x46, 0x00, 0x43, 0x00, 0x26, 0x00, 0x52, 0x00, - 0x57, + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, + 0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, + 0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x1e, 0x03, 0x53, 0x00, + 0x43, 0x00, 0x4c, 0x00, 0x33, 0x00, 0x37, 0x00, 0x31, 0x00, 0x31, 0x00, + 0x2d, 0x00, 0x4e, 0x00, 0x46, 0x00, 0x43, 0x00, 0x26, 0x00, 0x52, 0x00, + 0x57, }; const uint8_t btXramUsbDesc_nxppn533[] = { - 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, - 0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, - 0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x0c, 0x03, 0x50, 0x00, - 0x4e, 0x00, 0x35, 0x00, 0x33, 0x00, 0x33, 0x00, 0x04, 0x03, 0x09, 0x04, - 0x08, 0x03, 0x4e, 0x00, 0x58, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, + 0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, + 0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x0c, 0x03, 0x50, 0x00, + 0x4e, 0x00, 0x35, 0x00, 0x33, 0x00, 0x33, 0x00, 0x04, 0x03, 0x09, 0x04, + 0x08, 0x03, 0x4e, 0x00, 0x58, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, }; const uint8_t btXramUsbDesc_asklogo[] = { - 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09, 0x04, 0x00, - 0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, - 0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x0a, 0x03, 0x4c, 0x00, - 0x6f, 0x00, 0x47, 0x00, 0x4f, 0x00, 0x04, 0x03, 0x09, 0x04, 0x08, 0x03, - 0x41, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, + 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09, 0x04, 0x00, + 0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, + 0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x0a, 0x03, 0x4c, 0x00, + 0x6f, 0x00, 0x47, 0x00, 0x4f, 0x00, 0x04, 0x03, 0x09, 0x04, 0x08, 0x03, + 0x41, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, }; -static void pn533_fix_usbdesc(nfc_device *pnd) -{ - // PN533 USB descriptors may have been corrupted by large commands/responses - // so they need to be restored before closing usb connection. - // cf PN5331B3HNC270 Release Note - uint32_t szXramUsbDesc = 0; - uint8_t *btXramUsbDesc = NULL; - if (DRIVER_DATA(pnd)->model == NXP_PN533) { - btXramUsbDesc = (uint8_t *)btXramUsbDesc_nxppn533; - szXramUsbDesc = sizeof(btXramUsbDesc_nxppn533); - } else if (DRIVER_DATA(pnd)->model == SCM_SCL3711) { - btXramUsbDesc = (uint8_t *)btXramUsbDesc_scl3711; - szXramUsbDesc = sizeof(btXramUsbDesc_scl3711); - } else if (DRIVER_DATA(pnd)->model == ASK_LOGO) { - btXramUsbDesc = (uint8_t *)btXramUsbDesc_asklogo; - szXramUsbDesc = sizeof(btXramUsbDesc_asklogo); - } +static void pn533_fix_usbdesc(nfc_device *pnd) { + // PN533 USB descriptors may have been corrupted by large commands/responses + // so they need to be restored before closing usb connection. + // cf PN5331B3HNC270 Release Note + uint32_t szXramUsbDesc = 0; + uint8_t *btXramUsbDesc = NULL; + if (DRIVER_DATA(pnd)->model == NXP_PN533) { + btXramUsbDesc = (uint8_t *) btXramUsbDesc_nxppn533; + szXramUsbDesc = sizeof(btXramUsbDesc_nxppn533); + } else if (DRIVER_DATA(pnd)->model == SCM_SCL3711) { + btXramUsbDesc = (uint8_t *) btXramUsbDesc_scl3711; + szXramUsbDesc = sizeof(btXramUsbDesc_scl3711); + } else if (DRIVER_DATA(pnd)->model == ASK_LOGO) { + btXramUsbDesc = (uint8_t *) btXramUsbDesc_asklogo; + szXramUsbDesc = sizeof(btXramUsbDesc_asklogo); + } #define MAXSZXRAMUSBDESC 61 - if ((szXramUsbDesc == 0) || (MAXSZXRAMUSBDESC > 61)) - return; + if ((szXramUsbDesc == 0) || (MAXSZXRAMUSBDESC > 61)) + return; #if 0 - // Debug routine to check if corruption occurred: - // Don't read more regs at once or it will trigger the bug and corrupt what we're busy reading! - uint8_t abtCmdRR[] = { ReadRegister, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t nRRreg = ((sizeof(abtCmdRR) - 1) / 2); - uint8_t abtRxRR[1 + nRRreg]; - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "%s", "Checking USB descriptors corruption in XRAM"); - for (uint8_t i = 0x19, j = 0; i < 0x19 + szXramUsbDesc;) { - for (uint8_t k = 0; k < nRRreg; k++) { - abtCmdRR[(2 * k) + 2] = i++; - } - if (pn53x_transceive(pnd, abtCmdRR, sizeof(abtCmdRR), abtRxRR, sizeof(abtRxRR), -1) < 0) { - return; // void - } - for (int k = 0; (k < nRRreg) && (j < szXramUsbDesc); k++) { - //printf("0x%02x, ", abtRxRR[1 + k]); - if (btXramUsbDesc[j] != abtRxRR[1 + k]) - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "XRAM corruption @ addr 0x00%02X: got %02x, expected %02x", 0x0019 + (j - 1), abtRxRR[1 + k], btXramUsbDesc[j]); - j++; - } - } + // Debug routine to check if corruption occurred: + // Don't read more regs at once or it will trigger the bug and corrupt what we're busy reading! + uint8_t abtCmdRR[] = { ReadRegister, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t nRRreg = ((sizeof(abtCmdRR) - 1) / 2); + uint8_t abtRxRR[1 + nRRreg]; + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "%s", "Checking USB descriptors corruption in XRAM"); + for (uint8_t i = 0x19, j = 0; i < 0x19 + szXramUsbDesc;) { + for (uint8_t k = 0; k < nRRreg; k++) { + abtCmdRR[(2 * k) + 2] = i++; + } + if (pn53x_transceive(pnd, abtCmdRR, sizeof(abtCmdRR), abtRxRR, sizeof(abtRxRR), -1) < 0) { + return; // void + } + for (int k = 0; (k < nRRreg) && (j < szXramUsbDesc); k++) { + //printf("0x%02x, ", abtRxRR[1 + k]); + if (btXramUsbDesc[j] != abtRxRR[1 + k]) + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "XRAM corruption @ addr 0x00%02X: got %02x, expected %02x", 0x0019 + (j - 1), abtRxRR[1 + k], btXramUsbDesc[j]); + j++; + } + } #endif - // Abuse the overflow bug to restore USB descriptors in one go - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "%s", "Fixing USB descriptors corruption"); - uint8_t abtCmdWR[19 + MAXSZXRAMUSBDESC] = { GetFirmwareVersion }; - for (uint8_t i = 0; i < szXramUsbDesc; i++) { - abtCmdWR[i + 19] = btXramUsbDesc[i]; - } - size_t szCmdWR = sizeof(abtCmdWR); - uint8_t abtRxWR[4]; - if (pn53x_transceive(pnd, abtCmdWR, szCmdWR, abtRxWR, sizeof(abtRxWR), -1) < 0) { - return; // void - } - DRIVER_DATA(pnd)->possibly_corrupted_usbdesc = false; + // Abuse the overflow bug to restore USB descriptors in one go + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "%s", "Fixing USB descriptors corruption"); + uint8_t abtCmdWR[19 + MAXSZXRAMUSBDESC] = {GetFirmwareVersion}; + for (size_t i = 0; i < szXramUsbDesc; i++) { + abtCmdWR[i + 19] = btXramUsbDesc[i]; + } + size_t szCmdWR = sizeof(abtCmdWR); + uint8_t abtRxWR[4]; + if (pn53x_transceive(pnd, abtCmdWR, szCmdWR, abtRxWR, sizeof(abtRxWR), -1) < 0) { + return; // void + } + DRIVER_DATA(pnd)->possibly_corrupted_usbdesc = false; } static pn53x_usb_model -pn53x_usb_get_device_model(uint16_t vendor_id, uint16_t product_id) -{ - for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { - if ((vendor_id == pn53x_usb_supported_devices[n].vendor_id) && - (product_id == pn53x_usb_supported_devices[n].product_id)) - return pn53x_usb_supported_devices[n].model; - } - - return UNKNOWN; +pn53x_usb_get_device_model(uint16_t vendor_id, uint16_t product_id) { + for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { + if ((vendor_id == pn53x_usb_supported_devices[n].vendor_id) && + (product_id == pn53x_usb_supported_devices[n].product_id)) + return pn53x_usb_supported_devices[n].model; + } + + return UNKNOWN; } static bool -pn53x_usb_get_end_points_default(struct usb_device *dev, struct pn53x_usb_data *data) -{ - for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { - if ((dev->descriptor.idVendor == pn53x_usb_supported_devices[n].vendor_id) && - (dev->descriptor.idProduct == pn53x_usb_supported_devices[n].product_id)) { - if (pn53x_usb_supported_devices[n].uiMaxPacketSize != 0) { - data->uiEndPointIn = pn53x_usb_supported_devices[n].uiEndPointIn; - data->uiEndPointOut = pn53x_usb_supported_devices[n].uiEndPointOut; - data->uiMaxPacketSize = pn53x_usb_supported_devices[n].uiMaxPacketSize; - - return true; - } - } - } - - return false; +pn53x_usb_get_end_points_default(struct pn53x_usb_data *data) { + struct libusb_device_descriptor descriptor; + libusb_get_device_descriptor(data->dev, &descriptor); + + for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { + if ((descriptor.idVendor == pn53x_usb_supported_devices[n].vendor_id) && + (descriptor.idProduct == pn53x_usb_supported_devices[n].product_id)) { + if (pn53x_usb_supported_devices[n].uiMaxPacketSize != 0) { + data->uiEndPointIn = pn53x_usb_supported_devices[n].uiEndPointIn; + data->uiEndPointOut = pn53x_usb_supported_devices[n].uiEndPointOut; + data->uiMaxPacketSize = pn53x_usb_supported_devices[n].uiMaxPacketSize; + + return true; + } + } + } + + return false; } -int pn53x_usb_ack(nfc_device *pnd); - -// Find transfer endpoints for bulk transfers -static void -pn53x_usb_get_end_points(struct usb_device *dev, struct pn53x_usb_data *data) -{ - uint32_t uiIndex; - uint32_t uiEndPoint; - struct usb_interface_descriptor *puid = dev->config->interface->altsetting; - - // 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out - for (uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++) { - // Only accept bulk transfer endpoints (ignore interrupt endpoints) - if (puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK) - continue; - - // Copy the endpoint to a local var, makes it more readable code - uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress; - - // Test if we dealing with a bulk IN endpoint - if ((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN) { - data->uiEndPointIn = uiEndPoint; - data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize; - } - // Test if we dealing with a bulk OUT endpoint - if ((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT) { - data->uiEndPointOut = uiEndPoint; - data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize; - } - } -} +int pn53x_usb_ack(nfc_device *pnd); static size_t -pn53x_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) -{ - (void)context; - - usb_prepare(); - - size_t device_found = 0; - uint32_t uiBusIndex = 0; - struct usb_bus *bus; - for (bus = usb_get_busses(); bus; bus = bus->next) { - struct usb_device *dev; - - for (dev = bus->devices; dev; dev = dev->next, uiBusIndex++) { - for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { - if ((pn53x_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && - (pn53x_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { - // Make sure there are 2 endpoints available - // libusb-win32 may return a NULL dev->config, - // or the descriptors may be corrupted, hence - // let us assume we will use hardcoded defaults - // from pn53x_usb_supported_devices if available. - // otherwise get data from the descriptors. - if (pn53x_usb_supported_devices[n].uiMaxPacketSize == 0) { - if (dev->config->interface == NULL || dev->config->interface->altsetting == NULL) { - // Nope, we maybe want the next one, let's try to find another - continue; - } - if (dev->config->interface->altsetting->bNumEndpoints < 2) { - // Nope, we maybe want the next one, let's try to find another - continue; - } - } - - usb_dev_handle *udev = usb_open(dev); - if (udev == NULL) - continue; - - // Set configuration - int res = usb_set_configuration(udev, 1); - if (res < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set USB configuration (%s)", _usb_strerror(res)); - usb_close(udev); - // we failed to use the device - continue; - } - - // pn53x_usb_get_usb_device_name (dev, udev, pnddDevices[device_found].acDevice, sizeof (pnddDevices[device_found].acDevice)); - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "device found: Bus %s Device %s", bus->dirname, dev->filename); - usb_close(udev); - if (snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", PN53X_USB_DRIVER_NAME, bus->dirname, dev->filename) >= (int)sizeof(nfc_connstring)) { - // truncation occurred, skipping that one - continue; - } - device_found++; - // Test if we reach the maximum "wanted" devices - if (device_found == connstrings_len) { - return device_found; - } - } - } - } - } - - return device_found; +pn53x_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { + struct usbbus_device devices[num_pn53x_usb_supported_devices]; + for (size_t i = 0; i < num_pn53x_usb_supported_devices; i++) { + devices[i].product_id = pn53x_usb_supported_devices[i].product_id; + devices[i].vendor_id = pn53x_usb_supported_devices[i].vendor_id; + devices[i].name = pn53x_usb_supported_devices[i].name; + devices[i].max_packet_size = pn53x_usb_supported_devices[i].uiMaxPacketSize; + } + return usbbus_usb_scan(connstrings, connstrings_len, devices, num_pn53x_usb_supported_devices, PN53X_USB_DRIVER_NAME); } -struct pn53x_usb_descriptor { - char *dirname; - char *filename; -}; - bool -pn53x_usb_get_usb_device_name(struct usb_device *dev, usb_dev_handle *udev, char *buffer, size_t len) -{ - *buffer = '\0'; - - if (dev->descriptor.iManufacturer || dev->descriptor.iProduct) { - if (udev) { - usb_get_string_simple(udev, dev->descriptor.iManufacturer, buffer, len); - if (strlen(buffer) > 0) - strcpy(buffer + strlen(buffer), " / "); - usb_get_string_simple(udev, dev->descriptor.iProduct, buffer + strlen(buffer), len - strlen(buffer)); - } - } - - if (!*buffer) { - for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { - if ((pn53x_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && - (pn53x_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { - strncpy(buffer, pn53x_usb_supported_devices[n].name, len); - buffer[len - 1] = '\0'; - return true; - } - } - } - - return false; +pn53x_usb_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len) { + *buffer = '\0'; + + usbbus_get_usb_device_name(dev, udev, buffer, len); + uint16_t vendor_id = usbbus_get_vendor_id(dev); + uint16_t product_id = usbbus_get_product_id(dev); + + if (!*buffer) { + for (size_t n = 0; n < num_pn53x_usb_supported_devices; n++) { + if ((pn53x_usb_supported_devices[n].vendor_id == vendor_id) && + (pn53x_usb_supported_devices[n].product_id == product_id)) { + strncpy(buffer, pn53x_usb_supported_devices[n].name, len); + buffer[len - 1] = '\0'; + return true; + } + } + } + + return false; } static nfc_device * -pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring) -{ - nfc_device *pnd = NULL; - struct pn53x_usb_descriptor desc = { NULL, NULL }; - int connstring_decode_level = connstring_decode(connstring, PN53X_USB_DRIVER_NAME, "usb", &desc.dirname, &desc.filename); - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d element(s) have been decoded from \"%s\"", connstring_decode_level, connstring); - if (connstring_decode_level < 1) { - goto free_mem; - } - - struct pn53x_usb_data data = { - .pudh = NULL, - .uiEndPointIn = 0, - .uiEndPointOut = 0, - .possibly_corrupted_usbdesc = false, - }; - struct usb_bus *bus; - struct usb_device *dev; - - usb_prepare(); - - for (bus = usb_get_busses(); bus; bus = bus->next) { - if (connstring_decode_level > 1) { - // A specific bus have been specified - if (0 != strcmp(bus->dirname, desc.dirname)) - continue; - } - for (dev = bus->devices; dev; dev = dev->next) { - if (connstring_decode_level > 2) { - // A specific dev have been specified - if (0 != strcmp(dev->filename, desc.filename)) - continue; - } - // Open the USB device - if ((data.pudh = usb_open(dev)) == NULL) - continue; - - //To retrieve real USB endpoints configuration: - //pn53x_usb_get_end_points(dev, &data); - //printf("DEBUG ENDPOINTS In:0x%x Out:0x%x Size:0x%x\n", data.uiEndPointIn, data.uiEndPointOut, data.uiMaxPacketSize); - - // Retrieve end points, using hardcoded defaults if available - // or using the descriptors otherwise. - if (pn53x_usb_get_end_points_default(dev, &data) == false) { - pn53x_usb_get_end_points(dev, &data); - } - // Set configuration - int res = usb_set_configuration(data.pudh, 1); - if (res < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set USB configuration (%s)", _usb_strerror(res)); - if (EPERM == -res) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Warning: Please double check USB permissions for device %04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct); - } - usb_close(data.pudh); - // we failed to use the specified device - goto free_mem; - } - - res = usb_claim_interface(data.pudh, 0); - if (res < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to claim USB interface (%s)", _usb_strerror(res)); - usb_close(data.pudh); - // we failed to use the specified device - goto free_mem; - } - data.model = pn53x_usb_get_device_model(dev->descriptor.idVendor, dev->descriptor.idProduct); - // Allocate memory for the device info and specification, fill it and return the info - pnd = nfc_device_new(context, connstring); - if (!pnd) { - perror("malloc"); - goto error; - } - pn53x_usb_get_usb_device_name(dev, data.pudh, pnd->name, sizeof(pnd->name)); - - pnd->driver_data = malloc(sizeof(struct pn53x_usb_data)); - if (!pnd->driver_data) { - perror("malloc"); - goto error; - } - *DRIVER_DATA(pnd) = data; - - // Alloc and init chip's data - if (pn53x_data_new(pnd, &pn53x_usb_io) == NULL) { - perror("malloc"); - goto error; - } - - switch (DRIVER_DATA(pnd)->model) { - // empirical tuning - case ASK_LOGO: - CHIP_DATA(pnd)->timer_correction = 50; - CHIP_DATA(pnd)->progressive_field = true; - break; - case SCM_SCL3711: - case SCM_SCL3712: - case NXP_PN533: - CHIP_DATA(pnd)->timer_correction = 46; - break; - case NXP_PN531: - CHIP_DATA(pnd)->timer_correction = 50; - break; - case SONY_PN531: - CHIP_DATA(pnd)->timer_correction = 54; - break; - case SONY_RCS360: - case UNKNOWN: - CHIP_DATA(pnd)->timer_correction = 0; // TODO: allow user to know if timed functions are available - break; - } - pnd->driver = &pn53x_usb_driver; - - // HACK1: Send first an ACK as Abort command, to reset chip before talking to it: - pn53x_usb_ack(pnd); - - // HACK2: Then send a GetFirmware command to resync USB toggle bit between host & device - // in case host used set_configuration and expects the device to have reset its toggle bit, which PN53x doesn't do - if (pn53x_usb_init(pnd) < 0) { - usb_close(data.pudh); - goto error; - } - DRIVER_DATA(pnd)->abort_flag = false; - goto free_mem; - } - } - // We ran out of devices before the index required - goto free_mem; - -error: - // Free allocated structure on error. - nfc_device_free(pnd); - pnd = NULL; -free_mem: - free(desc.dirname); - free(desc.filename); - return pnd; +pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring) { + nfc_device *pnd = NULL; + + char *dev_address_str; + char *config_idx_str; + int connstring_decode_level = + connstring_decode(connstring, PN53X_USB_DRIVER_NAME, "usb", &dev_address_str, &config_idx_str); + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_DEBUG, + "%d element(s) have been decoded from \"%s\"", + connstring_decode_level, + connstring); + // At least the driver and the dev address need to be decoded + if (connstring_decode_level < 2) { + return NULL; + } + + uint8_t dev_addres = atoi(dev_address_str); + uint8_t config_idx = atoi(config_idx_str); + + usbbus_prepare(); + + + struct pn53x_usb_data data = { + .dev = NULL, + .pudh = NULL, + .configIdx = config_idx, + .uiEndPointIn = 0, + .uiEndPointOut = 0, + .possibly_corrupted_usbdesc = false, + }; + + usbbus_get_device(dev_addres, &data.dev, &data.pudh); + + // Retrieve end points, using hardcoded defaults if available + // or using the descriptors otherwise. + if (!pn53x_usb_get_end_points_default(&data)) { + // Find transfer endpoints for bulk transfers + usbbus_get_usb_endpoints(data.dev, &(data.uiEndPointIn), &(data.uiEndPointOut), &(data.uiMaxPacketSize)); + + } + // Set configuration + int res = libusb_set_configuration(data.pudh, data.configIdx); + if (res < 0) { + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_ERROR, + "Unable to set USB configuration (%s)", + libusb_strerror(res)); + if (res == LIBUSB_ERROR_ACCESS) { + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_INFO, + "Warning: Please double check USB permissions for device %04x:%04x:%03d", + usbbus_get_vendor_id(data.dev), + usbbus_get_product_id(data.dev), + data.configIdx); + } + // we failed to use the specified device + usbbus_close(data.dev, data.pudh); + free(dev_address_str); + free(config_idx_str); + return NULL; + } + + res = libusb_claim_interface(data.pudh, 0); + if (res < 0) { + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_ERROR, + "Unable to claim USB interface (%s)", + libusb_strerror(res)); + // we failed to use the specified device + usbbus_close(data.dev, data.pudh); + free(dev_address_str); + free(config_idx_str); + return NULL; + } + data.model = pn53x_usb_get_device_model(usbbus_get_vendor_id(data.dev), usbbus_get_product_id(data.dev)); + // Allocate memory for the device info and specification, fill it and return the info + pnd = nfc_device_new(context, connstring); + if (!pnd) { + perror("malloc"); + usbbus_close(data.dev, data.pudh); + free(dev_address_str); + free(config_idx_str); + return NULL; + } + pn53x_usb_get_usb_device_name(data.dev, data.pudh, pnd->name, sizeof(pnd->name)); + + pnd->driver_data = malloc(sizeof(struct pn53x_usb_data)); + if (!pnd->driver_data) { + perror("malloc"); + nfc_device_free(pnd); + usbbus_close(data.dev, data.pudh); + free(dev_address_str); + free(config_idx_str); + return NULL; + } + *DRIVER_DATA(pnd) = data; + + // Alloc and init chip's data + if (pn53x_data_new(pnd, &pn53x_usb_io) == NULL) { + perror("malloc"); + nfc_device_free(pnd); + usbbus_close(data.dev, data.pudh); + free(dev_address_str); + free(config_idx_str); + return NULL; + } + + switch (DRIVER_DATA(pnd)->model) { + // empirical tuning + case ASK_LOGO:CHIP_DATA(pnd)->timer_correction = 50; + CHIP_DATA(pnd)->progressive_field = true; + break; + case SCM_SCL3711: + case SCM_SCL3712: + case NXP_PN533:CHIP_DATA(pnd)->timer_correction = 46; + break; + case NXP_PN531:CHIP_DATA(pnd)->timer_correction = 50; + break; + case SONY_PN531:CHIP_DATA(pnd)->timer_correction = 54; + break; + case SONY_RCS360: + case UNKNOWN: + CHIP_DATA(pnd)->timer_correction = 0; // TODO: allow user to know if timed functions are available + break; + } + pnd->driver = &pn53x_usb_driver; + + // HACK1: Send first an ACK as Abort command, to reset chip before talking to it: + pn53x_usb_ack(pnd); + + // HACK2: Then send a GetFirmware command to resync USB toggle bit between host & device + // in case host used set_configuration and expects the device to have reset its toggle bit, which PN53x doesn't do + if (pn53x_usb_init(pnd) < 0) { + nfc_device_free(pnd); + usbbus_close(data.dev, data.pudh); + free(dev_address_str); + free(config_idx_str); + return NULL; + } + DRIVER_DATA(pnd)->abort_flag = false; + return pnd; } static void -pn53x_usb_close(nfc_device *pnd) -{ - pn53x_usb_ack(pnd); - - if (DRIVER_DATA(pnd)->model == ASK_LOGO) { - /* Set P30, P31, P32, P33, P35 to logic 1 and P34 to 0 logic */ - /* ie. Switch all LEDs off and turn off progressive field */ - pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P32) | _BV(P33) | _BV(P35)); - } - - if (DRIVER_DATA(pnd)->possibly_corrupted_usbdesc) - pn533_fix_usbdesc(pnd); - - pn53x_idle(pnd); - - int res; - if ((res = usb_release_interface(DRIVER_DATA(pnd)->pudh, 0)) < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to release USB interface (%s)", _usb_strerror(res)); - } - - if ((res = usb_close(DRIVER_DATA(pnd)->pudh)) < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to close USB connection (%s)", _usb_strerror(res)); - } - pn53x_data_free(pnd); - nfc_device_free(pnd); +pn53x_usb_close(nfc_device *pnd) { + pn53x_usb_ack(pnd); + + if (DRIVER_DATA(pnd)->model == ASK_LOGO) { + /* Set P30, P31, P32, P33, P35 to logic 1 and P34 to 0 logic */ + /* ie. Switch all LEDs off and turn off progressive field */ + pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P32) | _BV(P33) | _BV(P35)); + } + + if (DRIVER_DATA(pnd)->possibly_corrupted_usbdesc) { + pn533_fix_usbdesc(pnd); + } + + pn53x_idle(pnd); + + usbbus_close(DRIVER_DATA(pnd)->dev, DRIVER_DATA(pnd)->pudh); + + pn53x_data_free(pnd); + nfc_device_free(pnd); } #define PN53X_USB_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD) static int -pn53x_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, const int timeout) -{ - uint8_t abtFrame[PN53X_USB_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff" - size_t szFrame = 0; - int res = 0; - - if ((res = pn53x_build_frame(abtFrame, &szFrame, pbtData, szData)) < 0) { - pnd->last_error = res; - return pnd->last_error; - } - - DRIVER_DATA(pnd)->possibly_corrupted_usbdesc |= szData > 17; - if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd), abtFrame, szFrame, timeout)) < 0) { - pnd->last_error = res; - return pnd->last_error; - } - - uint8_t abtRxBuf[PN53X_USB_BUFFER_LEN]; - if ((res = pn53x_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), timeout)) < 0) { - // try to interrupt current device state - pn53x_usb_ack(pnd); - pnd->last_error = res; - return pnd->last_error; - } - - if (pn53x_check_ack_frame(pnd, abtRxBuf, res) == 0) { - // The PN53x is running the sent command - } else { - // For some reasons (eg. send another command while a previous one is - // running), the PN533 sometimes directly replies the response packet - // instead of ACK frame, so we send a NACK frame to force PN533 to resend - // response packet. With this hack, the next executed function (ie. - // pn53x_usb_receive()) will be able to retrieve the correct response - // packet. - // FIXME Sony reader is also affected by this bug but NACK is not supported - if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd), (uint8_t *)pn53x_nack_frame, sizeof(pn53x_nack_frame), timeout)) < 0) { - pnd->last_error = res; - // try to interrupt current device state - pn53x_usb_ack(pnd); - return pnd->last_error; - } - } - return NFC_SUCCESS; +pn53x_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, const int timeout) { + uint8_t abtFrame[PN53X_USB_BUFFER_LEN] = {0x00, 0x00, 0xff}; // Every packet must start with "00 00 ff" + size_t szFrame = 0; + int res = 0; + + if ((res = pn53x_build_frame(abtFrame, &szFrame, pbtData, szData)) < 0) { + pnd->last_error = res; + return pnd->last_error; + } + + DRIVER_DATA(pnd)->possibly_corrupted_usbdesc |= szData > 17; + if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd), abtFrame, szFrame, timeout)) < 0) { + pnd->last_error = res; + return pnd->last_error; + } + + uint8_t abtRxBuf[PN53X_USB_BUFFER_LEN]; + if ((res = pn53x_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), timeout)) < 0) { + // try to interrupt current device state + pn53x_usb_ack(pnd); + pnd->last_error = res; + return pnd->last_error; + } + + if (pn53x_check_ack_frame(pnd, abtRxBuf, res) == 0) { + // The PN53x is running the sent command + } else { + // For some reasons (eg. send another command while a previous one is + // running), the PN533 sometimes directly replies the response packet + // instead of ACK frame, so we send a NACK frame to force PN533 to resend + // response packet. With this hack, the next executed function (ie. + // pn53x_usb_receive()) will be able to retrieve the correct response + // packet. + // FIXME Sony reader is also affected by this bug but NACK is not supported + if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd), + (uint8_t *) pn53x_nack_frame, + sizeof(pn53x_nack_frame), + timeout)) < 0) { + pnd->last_error = res; + // try to interrupt current device state + pn53x_usb_ack(pnd); + return pnd->last_error; + } + } + return NFC_SUCCESS; } -#define USB_TIMEOUT_PER_PASS 200 +#define USBBUS_TIMEOUT_PER_PASS 200 + static int -pn53x_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) -{ - size_t len; - off_t offset = 0; - - uint8_t abtRxBuf[PN53X_USB_BUFFER_LEN]; - int res; - - /* - * If no timeout is specified but the command is blocking, force a 200ms (USB_TIMEOUT_PER_PASS) - * timeout to allow breaking the loop if the user wants to stop it. - */ - int usb_timeout; - int remaining_time = timeout; -read: - if (timeout == USB_INFINITE_TIMEOUT) { - usb_timeout = USB_TIMEOUT_PER_PASS; - } else { - // A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism - remaining_time -= USB_TIMEOUT_PER_PASS; - if (remaining_time <= 0) { - pnd->last_error = NFC_ETIMEOUT; - return pnd->last_error; - } else { - usb_timeout = MIN(remaining_time, USB_TIMEOUT_PER_PASS); - } - } - - res = pn53x_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), usb_timeout); - - if (res == -USB_TIMEDOUT) { - if (DRIVER_DATA(pnd)->abort_flag) { - DRIVER_DATA(pnd)->abort_flag = false; - pn53x_usb_ack(pnd); - pnd->last_error = NFC_EOPABORTED; - return pnd->last_error; - } else { - goto read; - } - } - - if (res < 0) { - // try to interrupt current device state - pn53x_usb_ack(pnd); - pnd->last_error = res; - return pnd->last_error; - } - - const uint8_t pn53x_preamble[3] = { 0x00, 0x00, 0xff }; - if (0 != (memcmp(abtRxBuf, pn53x_preamble, 3))) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - offset += 3; - - if ((0x01 == abtRxBuf[offset]) && (0xff == abtRxBuf[offset + 1])) { - // Error frame - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Application level error detected"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } else if ((0xff == abtRxBuf[offset]) && (0xff == abtRxBuf[offset + 1])) { - // Extended frame - offset += 2; - - // (abtRxBuf[offset] << 8) + abtRxBuf[offset + 1] (LEN) include TFI + (CC+1) - len = (abtRxBuf[offset] << 8) + abtRxBuf[offset + 1] - 2; - if (((abtRxBuf[offset] + abtRxBuf[offset + 1] + abtRxBuf[offset + 2]) % 256) != 0) { - // TODO: Retry - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - offset += 3; - } else { - // Normal frame - if (256 != (abtRxBuf[offset] + abtRxBuf[offset + 1])) { - // TODO: Retry - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - - // abtRxBuf[3] (LEN) include TFI + (CC+1) - len = abtRxBuf[offset] - 2; - offset += 2; - } - - if (len > szDataLen) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")", szDataLen, len); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - - // TFI + PD0 (CC+1) - if (abtRxBuf[offset] != 0xD5) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "TFI Mismatch"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - offset += 1; - - if (abtRxBuf[offset] != CHIP_DATA(pnd)->last_command + 1) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Command Code verification failed"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - offset += 1; - - memcpy(pbtData, abtRxBuf + offset, len); - offset += len; - - uint8_t btDCS = (256 - 0xD5); - btDCS -= CHIP_DATA(pnd)->last_command + 1; - for (size_t szPos = 0; szPos < len; szPos++) { - btDCS -= pbtData[szPos]; - } - - if (btDCS != abtRxBuf[offset]) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Data checksum mismatch"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - offset += 1; - - if (0x00 != abtRxBuf[offset]) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame postamble mismatch"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - // The PN53x command is done and we successfully received the reply - pnd->last_error = 0; - DRIVER_DATA(pnd)->possibly_corrupted_usbdesc |= len > 16; - return len; +pn53x_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) { + size_t len; + off_t offset = 0; + + uint8_t abtRxBuf[PN53X_USB_BUFFER_LEN]; + int res; + + /* + * If no timeout is specified but the command is blocking, force a 200ms (USBBUS_TIMEOUT_PER_PASS) + * timeout to allow breaking the loop if the user wants to stop it. + */ + int usbbus_timeout; + int remaining_time = timeout; + read: + if (timeout == USBBUS_INFINITE_TIMEOUT) { + usbbus_timeout = USBBUS_TIMEOUT_PER_PASS; + } else { + // A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism + remaining_time -= USBBUS_TIMEOUT_PER_PASS; + if (remaining_time <= 0) { + pnd->last_error = NFC_ETIMEOUT; + return pnd->last_error; + } else { + usbbus_timeout = MIN(remaining_time, USBBUS_TIMEOUT_PER_PASS); + } + } + + res = pn53x_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), usbbus_timeout); + + if (res == LIBUSB_ERROR_TIMEOUT) { + if (DRIVER_DATA(pnd)->abort_flag) { + DRIVER_DATA(pnd)->abort_flag = false; + pn53x_usb_ack(pnd); + pnd->last_error = NFC_EOPABORTED; + return pnd->last_error; + } else { + goto read; + } + } + + if (res < 0) { + // try to interrupt current device state + pn53x_usb_ack(pnd); + pnd->last_error = res; + return pnd->last_error; + } + + const uint8_t pn53x_preamble[3] = {0x00, 0x00, 0xff}; + if (0 != (memcmp(abtRxBuf, pn53x_preamble, 3))) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + offset += 3; + + if ((0x01 == abtRxBuf[offset]) && (0xff == abtRxBuf[offset + 1])) { + // Error frame + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Application level error detected"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } else if ((0xff == abtRxBuf[offset]) && (0xff == abtRxBuf[offset + 1])) { + // Extended frame + offset += 2; + + // (abtRxBuf[offset] << 8) + abtRxBuf[offset + 1] (LEN) include TFI + (CC+1) + len = (abtRxBuf[offset] << 8) + abtRxBuf[offset + 1] - 2; + if (((abtRxBuf[offset] + abtRxBuf[offset + 1] + abtRxBuf[offset + 2]) % 256) != 0) { + // TODO: Retry + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + offset += 3; + } else { + // Normal frame + if (256 != (abtRxBuf[offset] + abtRxBuf[offset + 1])) { + // TODO: Retry + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + + // abtRxBuf[3] (LEN) include TFI + (CC+1) + len = abtRxBuf[offset] - 2; + offset += 2; + } + + if (len > szDataLen) { + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_ERROR, + "Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")", + szDataLen, + len); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + + // TFI + PD0 (CC+1) + if (abtRxBuf[offset] != 0xD5) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "TFI Mismatch"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + offset += 1; + + if (abtRxBuf[offset] != CHIP_DATA(pnd)->last_command + 1) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Command Code verification failed"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + offset += 1; + + memcpy(pbtData, abtRxBuf + offset, len); + offset += len; + + uint8_t btDCS = (256 - 0xD5); + btDCS -= CHIP_DATA(pnd)->last_command + 1; + for (size_t szPos = 0; szPos < len; szPos++) { + btDCS -= pbtData[szPos]; + } + + if (btDCS != abtRxBuf[offset]) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Data checksum mismatch"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + offset += 1; + + if (0x00 != abtRxBuf[offset]) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame postamble mismatch"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + // The PN53x command is done and we successfully received the reply + pnd->last_error = 0; + DRIVER_DATA(pnd)->possibly_corrupted_usbdesc |= len > 16; + return len; } int -pn53x_usb_ack(nfc_device *pnd) -{ - return pn53x_usb_bulk_write(DRIVER_DATA(pnd), (uint8_t *) pn53x_ack_frame, sizeof(pn53x_ack_frame), 1000); +pn53x_usb_ack(nfc_device *pnd) { + return pn53x_usb_bulk_write(DRIVER_DATA(pnd), (uint8_t *) pn53x_ack_frame, sizeof(pn53x_ack_frame), 1000); } int -pn53x_usb_init(nfc_device *pnd) -{ - int res = 0; - // Sometimes PN53x USB doesn't reply ACK one the first frame, so we need to send a dummy one... - //pn53x_check_communication (pnd); // Sony RC-S360 doesn't support this command for now so let's use a get_firmware_version instead: - const uint8_t abtCmd[] = { GetFirmwareVersion }; - pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); - // ...and we don't care about error - pnd->last_error = 0; - if (SONY_RCS360 == DRIVER_DATA(pnd)->model) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "SONY RC-S360 initialization."); - const uint8_t abtCmd2[] = { 0x18, 0x01 }; - pn53x_transceive(pnd, abtCmd2, sizeof(abtCmd2), NULL, 0, -1); - pn53x_usb_ack(pnd); - } - - if ((res = pn53x_init(pnd)) < 0) - return res; - - if (ASK_LOGO == DRIVER_DATA(pnd)->model) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ASK LoGO initialization."); - /* Internal registers */ - /* Disable 100mA current limit, Power on Secure IC (SVDD) */ - pn53x_write_register(pnd, PN53X_REG_Control_switch_rng, 0xFF, SYMBOL_CURLIMOFF | SYMBOL_SIC_SWITCH_EN | SYMBOL_RANDOM_DATAREADY); - /* Select the signal to be output on SIGOUT: Modulation signal (envelope) from the internal coder */ - pn53x_write_register(pnd, PN53X_REG_CIU_TxSel, 0xFF, 0x14); - - /* SFR Registers */ - /* Setup push-pulls for pins from P30 to P35 */ - pn53x_write_register(pnd, PN53X_SFR_P3CFGB, 0xFF, 0x37); - - /* - On ASK LoGO hardware: - LEDs port bits definition: - * LED 1: bit 2 (P32) - * LED 2: bit 1 (P31) - * LED 3: bit 0 or 3 (depending of hardware revision) (P30 or P33) - * LED 4: bit 5 (P35) - Notes: - * Set logical 0 to switch LED on; logical 1 to switch LED off. - * Bit 4 should be maintained at 1 to keep RF field on. - - Progressive field activation: - The ASK LoGO hardware can progressively power-up the antenna. - To use this feature we have to switch on the field by switching on - the field on PN533 (RFConfiguration) then set P34 to '1', and cut-off the - field by switching off the field on PN533 then set P34 to '0'. - */ - - /* Set P30, P31, P33, P35 to logic 1 and P32, P34 to 0 logic */ - /* ie. Switch LED1 on and turn off progressive field */ - pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P33) | _BV(P35)); - } - if (DRIVER_DATA(pnd)->possibly_corrupted_usbdesc) - pn533_fix_usbdesc(pnd); - - return NFC_SUCCESS; +pn53x_usb_init(nfc_device *pnd) { + int res = 0; + // Sometimes PN53x USB doesn't reply ACK one the first frame, so we need to send a dummy one... + //pn53x_check_communication (pnd); // Sony RC-S360 doesn't support this command for now so let's use a get_firmware_version instead: + const uint8_t abtCmd[] = {GetFirmwareVersion}; + pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); + // ...and we don't care about error + pnd->last_error = 0; + if (SONY_RCS360 == DRIVER_DATA(pnd)->model) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "SONY RC-S360 initialization."); + const uint8_t abtCmd2[] = {0x18, 0x01}; + pn53x_transceive(pnd, abtCmd2, sizeof(abtCmd2), NULL, 0, -1); + pn53x_usb_ack(pnd); + } + + if ((res = pn53x_init(pnd)) < 0) + return res; + + if (ASK_LOGO == DRIVER_DATA(pnd)->model) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ASK LoGO initialization."); + /* Internal registers */ + /* Disable 100mA current limit, Power on Secure IC (SVDD) */ + pn53x_write_register(pnd, + PN53X_REG_Control_switch_rng, + 0xFF, + SYMBOL_CURLIMOFF | SYMBOL_SIC_SWITCH_EN | SYMBOL_RANDOM_DATAREADY); + /* Select the signal to be output on SIGOUT: Modulation signal (envelope) from the internal coder */ + pn53x_write_register(pnd, PN53X_REG_CIU_TxSel, 0xFF, 0x14); + + /* SFR Registers */ + /* Setup push-pulls for pins from P30 to P35 */ + pn53x_write_register(pnd, PN53X_SFR_P3CFGB, 0xFF, 0x37); + + /* + On ASK LoGO hardware: + LEDs port bits definition: + * LED 1: bit 2 (P32) + * LED 2: bit 1 (P31) + * LED 3: bit 0 or 3 (depending of hardware revision) (P30 or P33) + * LED 4: bit 5 (P35) + Notes: + * Set logical 0 to switch LED on; logical 1 to switch LED off. + * Bit 4 should be maintained at 1 to keep RF field on. + + Progressive field activation: + The ASK LoGO hardware can progressively power-up the antenna. + To use this feature we have to switch on the field by switching on + the field on PN533 (RFConfiguration) then set P34 to '1', and cut-off the + field by switching off the field on PN533 then set P34 to '0'. + */ + + /* Set P30, P31, P33, P35 to logic 1 and P32, P34 to 0 logic */ + /* ie. Switch LED1 on and turn off progressive field */ + pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P33) | _BV(P35)); + } + if (DRIVER_DATA(pnd)->possibly_corrupted_usbdesc) + pn533_fix_usbdesc(pnd); + + return NFC_SUCCESS; } static int -pn53x_usb_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable) -{ - int res = 0; - if ((res = pn53x_set_property_bool(pnd, property, bEnable)) < 0) - return res; - - switch (DRIVER_DATA(pnd)->model) { - case ASK_LOGO: - if (NP_ACTIVATE_FIELD == property) { - /* Switch on/off LED2 and Progressive Field GPIO according to ACTIVATE_FIELD option */ - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Switch progressive field %s", bEnable ? "On" : "Off"); - if (pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31)) < 0) - return NFC_ECHIP; - } - break; - case SCM_SCL3711: - if (NP_ACTIVATE_FIELD == property) { - // Switch on/off LED according to ACTIVATE_FIELD option - if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P32), bEnable ? 0 : _BV(P32))) < 0) - return res; - } - break; - case SCM_SCL3712: - if (NP_ACTIVATE_FIELD == property) { - // Switch on/off LED according to ACTIVATE_FIELD option - if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P32), bEnable ? 0 : _BV(P32))) < 0) - return res; - } - break; - case NXP_PN531: - case NXP_PN533: - case SONY_PN531: - case SONY_RCS360: - case UNKNOWN: - // Nothing to do. - break; - } - return NFC_SUCCESS; +pn53x_usb_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable) { + int res = 0; + if ((res = pn53x_set_property_bool(pnd, property, bEnable)) < 0) + return res; + + switch (DRIVER_DATA(pnd)->model) { + case ASK_LOGO: + if (NP_ACTIVATE_FIELD == property) { + /* Switch on/off LED2 and Progressive Field GPIO according to ACTIVATE_FIELD option */ + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_DEBUG, + "Switch progressive field %s", + bEnable ? "On" : "Off"); + if (pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31)) < 0) + return NFC_ECHIP; + } + break; + case SCM_SCL3711: + case SCM_SCL3712: + if (NP_ACTIVATE_FIELD == property) { + // Switch on/off LED according to ACTIVATE_FIELD option + if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P32), bEnable ? 0 : _BV(P32))) < 0) + return res; + } + break; + case NXP_PN531: + case NXP_PN533: + case SONY_PN531: + case SONY_RCS360: + case UNKNOWN: + // Nothing to do. + break; + } + return NFC_SUCCESS; } static int -pn53x_usb_abort_command(nfc_device *pnd) -{ - DRIVER_DATA(pnd)->abort_flag = true; - return NFC_SUCCESS; +pn53x_usb_abort_command(nfc_device *pnd) { + DRIVER_DATA(pnd)->abort_flag = true; + return NFC_SUCCESS; } static int -pn53x_usb_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt) -{ - if ((DRIVER_DATA(pnd)->model != ASK_LOGO) || (mode != N_TARGET)) - return pn53x_get_supported_modulation(pnd, mode, supported_mt); - else // ASK_LOGO has no N_TARGET support - *supported_mt = no_target_support; - return NFC_SUCCESS; +pn53x_usb_get_supported_modulation(nfc_device *pnd, + const nfc_mode mode, + const nfc_modulation_type **const supported_mt) { + if ((DRIVER_DATA(pnd)->model != ASK_LOGO) || (mode != N_TARGET)) + return pn53x_get_supported_modulation(pnd, mode, supported_mt); + else // ASK_LOGO has no N_TARGET support + *supported_mt = no_target_support; + return NFC_SUCCESS; } const struct pn53x_io pn53x_usb_io = { - .send = pn53x_usb_send, - .receive = pn53x_usb_receive, + .send = pn53x_usb_send, + .receive = pn53x_usb_receive, }; const struct nfc_driver pn53x_usb_driver = { - .name = PN53X_USB_DRIVER_NAME, - .scan_type = NOT_INTRUSIVE, - .scan = pn53x_usb_scan, - .open = pn53x_usb_open, - .close = pn53x_usb_close, - .strerror = pn53x_strerror, - - .initiator_init = pn53x_initiator_init, - .initiator_init_secure_element = NULL, // No secure-element support - .initiator_select_passive_target = pn53x_initiator_select_passive_target, - .initiator_poll_target = pn53x_initiator_poll_target, - .initiator_select_dep_target = pn53x_initiator_select_dep_target, - .initiator_deselect_target = pn53x_initiator_deselect_target, - .initiator_transceive_bytes = pn53x_initiator_transceive_bytes, - .initiator_transceive_bits = pn53x_initiator_transceive_bits, - .initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed, - .initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed, - .initiator_target_is_present = pn53x_initiator_target_is_present, - - .target_init = pn53x_target_init, - .target_send_bytes = pn53x_target_send_bytes, - .target_receive_bytes = pn53x_target_receive_bytes, - .target_send_bits = pn53x_target_send_bits, - .target_receive_bits = pn53x_target_receive_bits, - - .device_set_property_bool = pn53x_usb_set_property_bool, - .device_set_property_int = pn53x_set_property_int, - .get_supported_modulation = pn53x_usb_get_supported_modulation, - .get_supported_baud_rate = pn53x_get_supported_baud_rate, - .device_get_information_about = pn53x_get_information_about, - - .abort_command = pn53x_usb_abort_command, - .idle = pn53x_idle, - .powerdown = pn53x_PowerDown, + .name = PN53X_USB_DRIVER_NAME, + .scan_type = NOT_INTRUSIVE, + .scan = pn53x_usb_scan, + .open = pn53x_usb_open, + .close = pn53x_usb_close, + .strerror = pn53x_strerror, + + .initiator_init = pn53x_initiator_init, + .initiator_init_secure_element = NULL, // No secure-element support + .initiator_select_passive_target = pn53x_initiator_select_passive_target, + .initiator_poll_target = pn53x_initiator_poll_target, + .initiator_select_dep_target = pn53x_initiator_select_dep_target, + .initiator_deselect_target = pn53x_initiator_deselect_target, + .initiator_transceive_bytes = pn53x_initiator_transceive_bytes, + .initiator_transceive_bits = pn53x_initiator_transceive_bits, + .initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed, + .initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed, + .initiator_target_is_present = pn53x_initiator_target_is_present, + + .target_init = pn53x_target_init, + .target_send_bytes = pn53x_target_send_bytes, + .target_receive_bytes = pn53x_target_receive_bytes, + .target_send_bits = pn53x_target_send_bits, + .target_receive_bits = pn53x_target_receive_bits, + + .device_set_property_bool = pn53x_usb_set_property_bool, + .device_set_property_int = pn53x_set_property_int, + .get_supported_modulation = pn53x_usb_get_supported_modulation, + .get_supported_baud_rate = pn53x_get_supported_baud_rate, + .device_get_information_about = pn53x_get_information_about, + + .abort_command = pn53x_usb_abort_command, + .idle = pn53x_idle, + .powerdown = pn53x_PowerDown, }; diff --git a/m4/libnfc_check_libusb.m4 b/m4/libnfc_check_libusb.m4 index 0d5b197f..02e8365b 100644 --- a/m4/libnfc_check_libusb.m4 +++ b/m4/libnfc_check_libusb.m4 @@ -7,23 +7,10 @@ AC_DEFUN([LIBNFC_CHECK_LIBUSB], if test x"$libusb_required" = "xyes"; then HAVE_LIBUSB=0 - AC_ARG_WITH([libusb-win32], - [AS_HELP_STRING([--with-libusb-win32], [use libusb-win32 from the following location])], - [LIBUSB_WIN32_DIR=$withval], - [LIBUSB_WIN32_DIR=""]) - - # --with-libusb-win32 directory have been set - if test "x$LIBUSB_WIN32_DIR" != "x"; then - AC_MSG_NOTICE(["use libusb-win32 from $LIBUSB_WIN32_DIR"]) - libusb_CFLAGS="-I$LIBUSB_WIN32_DIR/include" - libusb_LIBS="-L$LIBUSB_WIN32_DIR/lib/gcc -lusb" - HAVE_LIBUSB=1 - fi - # Search using libusb module using pkg-config if test x"$HAVE_LIBUSB" = "x0"; then if test x"$PKG_CONFIG" != "x"; then - PKG_CHECK_MODULES([libusb], [libusb], [HAVE_LIBUSB=1], [HAVE_LIBUSB=0]) + PKG_CHECK_MODULES([libusb], [libusb-1.0], [HAVE_LIBUSB=1], [HAVE_LIBUSB=0]) if test x"$HAVE_LIBUSB" = "x1"; then if test x"$PKG_CONFIG_REQUIRES" != x""; then PKG_CONFIG_REQUIRES="$PKG_CONFIG_REQUIRES," @@ -33,33 +20,10 @@ AC_DEFUN([LIBNFC_CHECK_LIBUSB], fi fi - # Search using libusb-legacy module using pkg-config - if test x"$HAVE_LIBUSB" = "x0"; then - if test x"$PKG_CONFIG" != "x"; then - PKG_CHECK_MODULES([libusb], [libusb-legacy], [HAVE_LIBUSB=1], [HAVE_LIBUSB=0]) - if test x"$HAVE_LIBUSB" = "x1"; then - if test x"$PKG_CONFIG_REQUIRES" != x""; then - PKG_CONFIG_REQUIRES="$PKG_CONFIG_REQUIRES," - fi - PKG_CONFIG_REQUIRES="$PKG_CONFIG_REQUIRES libusb" - fi - fi - fi - - # Search using libusb-config - if test x"$HAVE_LIBUSB" = "x0"; then - AC_PATH_PROG(libusb_CONFIG,libusb-config) - if test x"$libusb_CONFIG" != "x" ; then - libusb_CFLAGS=`$libusb_CONFIG --cflags` - libusb_LIBS=`$libusb_CONFIG --libs` - HAVE_LIBUSB=1 - fi - fi - # Search the library and headers directly (last chance) if test x"$HAVE_LIBUSB" = "x0"; then - AC_CHECK_HEADER(usb.h, [], [AC_MSG_ERROR([The libusb headers are missing])]) - AC_CHECK_LIB(usb, libusb_init, [], [AC_MSG_ERROR([The libusb library is missing])]) + AC_CHECK_HEADER(libusb.h, [], [AC_MSG_ERROR([The libusb headers are missing])]) + AC_CHECK_LIB(usb-1.0, libusb_init, [], [AC_MSG_ERROR([The libusb library is missing])]) libusb_LIBS="-lusb" HAVE_LIBUSB=1