diff --git a/NEWS.md b/NEWS.md deleted file mode 100644 index 2e38d06..0000000 --- a/NEWS.md +++ /dev/null @@ -1,394 +0,0 @@ -New in 1.8.0: - -API Changes: - - Restore nfc_modulation_type enum order to keep compatibility with libnfc 1.7.1 - - Bump library version to 6.0.0 - -New in 1.7.2: - -Drivers: - - * New driver for pn71xx NXP's NFC Controllers through Linux Libnfc-nci (untested) - * New driver for contactless PC/SC readers (only as initiator) - -API Changes: - - * nfc_device_get_supported_baud_rate() now takes also "mode" as argument - * New nfc_device_get_supported_baud_rate_target_mode() - * New NFC modulation type NMT_BARCODE and nfc_barcode_info struct to support Thinfilm NFC Barcode protocol - * New NFC modulation type NMT_ISO14443BICLASS and NMT_ISO14443BICLASS struct to support HID iClass (Picopass) - * pn53x_transceive() is now part of public API - -New in 1.7.1: - -API Changes: - - * nfc_initiator_select_passive_target() provides defaults if pbtInitData=NULL - * nfc_initiator_target_is_present() allow NULL pointer to tag - -New in 1.7.0: - -Drivers: - - * New PN532 over I2C driver, see contrib/libnfc/pn532_i2c_on_rpi.conf.sample - -API Changes: - - * New function iso14443b_crc_append() - -New in 1.7.0-rc7: - -Drivers: - - * New PN532 over SPI driver, see contrib/libnfc/pn532_spi_on_rpi.conf.sample - -API Changes: - - * Functions - - nfc_initiator_target_is_present() & str_nfc_target(): - now take a pointer to nfc_target as argument - - nfc_init(): upon malloc error, doesn't force exit() anymore - so now you should test if context != NULL after nfc_init() call - -New in 1.7.0-rc5: - -API Changes: - - * Functions - - New nfc_register_driver() function allowing to hook custom drivers. - -New in 1.7.0-rc3: - -API Changes: - - * Functions - - Add timeout param to nfc_emulate_target() - -New in 1.7.0-rc2: - -Configuration: - libnfc can now use a configuration file for special setups, or features - activation. This file (/etc/nfc/libnfc.conf under GNU/Linux systems) - supports already some keywords: - - "allow_autoscan" to enable/disable device auto-detection feature; - - "allow_intrusive_scan" to enable/disable intrusive auto-detection - (ie. serial port probing); - - "log_level" to select library verbosity; - - "device.name" and "device.connstring" to define a user device, - this is the recommended method if user has a not easily detectable - device (ie. a serial one). - It is also possible to define devices using dedicated configuration files and - put them into device search directory (/etc/nfc/devices.d under GNU/Linux). - Example for the OpenPCD2: create /etc/nfc/devices.d/openpcd2.conf with: - name = "OpenPCD2" - connstring = "pn532_uart:/dev/ttyACM0" - optional = true - The keyword "optional" does not mandate the device to be present always - (it detects if the reader is indeed present before using it) - -API Changes: - - * Types - - New NFC_ESOFT error to handle software errors (allocations, pipe - creation, etc.) - - * Functions - - Remove nfc_get_default_device() function: the default device is now the - first in nfc_list_devices() or could be open using NULL connstring with - nfc_open() function. - - New enum-to-string converter functions str_nfc_modulation_type() and - str_nfc_baud_rate() - - New str_nfc_target() to convert nfc_target struct into allocated string - - New nfc_device_get_information_about() function to retreive some device's - information - - No more in/out function parameter: nfc_initiator_transceive_*() now - take a constant size for Rx buffer - - New nfc_initiator_target_is_present() to test is the previously selected - target is available in the field - - nfc_initiator_transceive_bytes() returns NFC_EMFCAUTHFAIL when AUTH - command failed on a Mifare Classic - - New nfc_initiator_init_secure_element() to initiate a connection with - secure element (Only supported with a PN532 with SAM equipped) - -New in 1.6.0-rc1: - -API Changes: - - * Types - - '_t' suffix removed from all types (e.g. nfc_device_t is now nfc_device) - - All errors removed in flavour of NFC_EIO, NFC_EINVARG, NFC_EDEVNOTSUPP, - NFC_ENOTSUCHDEV, NFC_EOVFLOW, NFC_ETIMEOUT, NFC_EOPABORTED, NFC_ENOTIMPL, - NFC_ETGRELEASED, NFC_ERFTRANS, NFC_ECHIP and NFC_SUCCESS - - nfc_device_desc_t replaced by nfc_connstring: libnfc now uses connection - strings to describe a device - - byte_t typedef removed, libnfc now uses uint8_t from C99 - - nfc_device is now an opaque type - - nfc_properties replaces nfc_options - - * Functions - - New nfc_get_default_device() function that allows to grab the connstring - stored in LIBNFC_DEFAULT_DEVICE environnement variable or returns the - first available device if not set - - New nfc_device_get_connstring() accessor function to know the device - connstring - - New nfc_device_set_property_bool() function that replace nfc_configure() - - New nfc_device_set_property_int() function to set integer property - - nfc_device_name() renamed to nfc_device_get_name() for the sake of - consistency - - New nfc_device_get_last_error() function, an accessor to last error occured - - Whole libnfc's functions now return 0 (NFC_SUCCESS) or positive value if - appropriated on success and libnfc's error code on failure - - nfc_connect(), nfc_disconnect() renamed to nfc_open(), nfc_close() - respectively - - Add 2 new functions: initialization and deinitialization functions: - nfc_init() and nfc_exit() - - New nfc_device_get_supported_modulation() and - nfc_device_get_supported_baud_rate() functions - - * Dependencies - - log4c is not anymore used for debugging facility. It was a bad choice, - sorry for inconvenience. - -New in 1.5.1: - -API Changes - - * Types - - Communication-level errors DEIO and DETIMEOUT are now know as ECOMIO, - ECOMTIMEOUT respectively - - Common device-level errors DEINVAL and DEABORT are now know as EINVALARG, - EOPABORT respectively - - New errors: EFRAACKMISMATCH, EFRAISERRFRAME, EDEVNOTSUP and ENOTIMPL - - * Functions - - nfc_abort_command() returns a boolean - - timeout (struct timeval) pointer added to - nfc_initiator_transceive_bytes(), nfc_target_send_bytes() and - nfc_target_receive_bytes() - - timed functions nfc_initiator_transceive_bytes_timed() and - nfc_initiator_transceive_bits_timed() now takes uint32_t as cycles - pointer - - nfc_initiator_poll_targets() renamed to nfc_initiator_poll_target() and - only return one target - -New in 1.5.0: - -Installed files - - nfc-message.h have been removed, internal macros are not part of API. - - New nfc-emulation.h file offers a middle level API to handle emulation (see - nfc-emulate-forum-tag4 example) - -API Changes - - * Types - - New error: DEABORT raised when operation is aborted by user (using - nfc_abort_command()) - - nfc_chip_t type removed from public API (have been renamed to pn53x_type - in chips/pn53x) - - nfc_device_spec_t removed, each driver can use his own way to keep a - connection pointer - - * Structures - - nfc_device_t now have a nfc_driver_t struct pointer (named .driver) and - void pointer (.driver_data) to handle device specific wrapping - - nfc_device_t now have a void pointer (.chip_data) to keep some chip - specific data - - nfc_device_t now have an file descriptor array to manage to abort request - - nfc_device_t does have .nc member (nfc_chip_t) anymore (different chips - handling in now in chip level) - - nfc_device_t does have .nds member (nfc_device_spec_t) anymore, each - driver handle its communication using driver_data pointer - - nfc_device_t does have .bActive member (bool) anymore, this variable was - almost not used and was not efficient - - nfc_device_t does have chip's register caches anymore, this is handle in - chip level (using chip_data pointer) - - driver_callbacks structure have been removed from public API - - New nfc_emulator structure used by the new emulation API (see - nfc_emulate_target()) - - New nfc_emulation_state_machine structure used by the new emulation API, - it handles an I/O function and data pointer to create a software based - state-machine. - - * Functions - - New nfc_abort_command() function to abort current running command. - - New nfc_initiator_transceive_bits_timed() and - nfc_initiator_transceive_bytes_timed() to transceive bits/bytes and - measure the time to have a reply - - New nfc_emulate_target() function to start a target emulation using an - nfc_emulator structure (it contains a custom state-machine - (nfc_emulation_state_machine struct) and a custom target (nfc_target_t) - (see nfc-emulate-forum-tag4 to have a look on how-to use it) - - - -New in 1.4.1: - -API Changes - - * Types - - New error: ETGUIDNOTSUP raised when UID is not 4 bytes long or does not - start with 0x08 (Security restriction present in the NXP PN53x chips) - - - -New in 1.4.0: - -API Changes - - * Types - - New nfc_device_option value (enum): NDO_FORCE_ISO14443_A to force the - chip to switch in ISO14443-A - - New nfc_dep_mode_t (enum) for DEP mode: - NDM_UNDEFINED, NDM_PASSIVE, NDM_ACTIVE - - New nfc_modulation_type_t (enum) that lists modulation types: - NMT_ISO14443A, NMT_ISO14443B, NMT_FELICA, NMT_JEWEL, NMT_DEP - - New nfc_baud_rate_t (enum): list of baud rates: - NBR_UNDEFINED, NBR_106, NBR_212, NBR_424, NBR_847 - - nfc_target_type_t have been removed from API (use nfc_modulation_t - instead) - - * Structures - - nfc_device_t now have a boolean bAutoIso14443_4 to keep the locally the - state of NDO_AUTO_ISO14443_4 (should not be directly set, use - nfc_configure() with NDO_AUTO_ISO14443_4) - - nfc_device_t now have an uint8_t ui8Parameters to cache PN53x parameters - - nfc_device_t now have a byte_t btSupportByte to cache supported - modulations - - nfc_dep_info_t have completely changed, please see API documentation - - nfc_iso14443b_info_t have completely changed, please see API - documentation - - nfc_modulation_t have completely changed: it now contains a - nfc_modulation_type_t and nfc_baud_rate_t couple. Initialization example: - nfc_modulation_t nm = { - .nmt = NMT_ISO14443A, - .nbr = NBR_106, - }; - - nfc_target_t now contains new nfc_modulation_t instead of - nfc_target_type_t. Initialization example: - nfc_target_t nt = { - .nm.nmt = NMT_ISO14443A, - .nm.nbr = NBR_UNDEFINED, - .nti.nai.abtAtqa = { 0x03, 0x44 }, - .nti.nai.abtUid = { 0x08, 0xab, 0xcd, 0xef }, - .nti.nai.btSak = 0x20, - .nti.nai.szUidLen = 4, - .nti.nai.abtAts = { 0x75, 0x77, 0x81, 0x02, 0x80 }, - .nti.nai.szAtsLen = 5, - }; - - * Functions - - nfc_initiator_select_passive_target() now use new nfc_modulation_t and - nfc_target_t instead of nfc_target_info_t - - nfc_initiator_list_passive_targets() now use new nfc_modulation_t and - nfc_target_t instead of nfc_target_info_t - - nfc_initiator_poll_targets() use new nfc_modulation_t instead of - nfc_target_type_t - - nfc_initiator_select_dep_target() completely changed, use now - nfc_dep_mode_t, nfc_baudrate_t, nfc_dep_info_t and nfc_target_t, please - see API documentation - - nfc_target_init() have an additional argument: nfc_target_t to describe - the wanted target - - append_iso14443a_crc() was renamed to iso14443a_crc_append() - - New iso14443a_locate_historical_bytes() to locate historical bytes in ATS - - - -New in 1.3.9 (since 1.3.4): - -Installed files - - - mifaretag.h and mifareultag.h are removed, Mifare features are not a part - of libnfc API anymore (these features are always available in examples/) - -API Changes - - * Types - - New nfc_device_option_t value (enum): NDO_AUTO_14443_4, an option to - enable/disable auto-switching to ISO/IEC 14443-4 if device is compliliant - - New nfc_device_option_t value (enum): NDO_EASY_FRAMING, an option to - enable/disable automatic frames encapsulation and chaining - - New nfc_target_type_t (enum), with values like NTT_MIFARE, - NTT_ISO14443B_106, NTT_DEP_ACTIVE_424, etc. - - Mifare related types have been removed from API: mifare_cmd, - mifare_param_auth, mifare_param_data, mifare_param_value, mifare_param - - * Structures - - nfc_device_t now have boolean bEasyFraming to enable/disable "easy - framing" feature (should not be directly set, use nfc_configure() with - NDO_EASY_FRAMING) - - nfc_device_t now have integer iLastError to handle last error - - New chip_callbacks to handle error lookup per chip - - driver_callbacks now have a pointer to chip_callbacks - - New nfc_target_t that contains nfc_target_info_t and nfc_target_type_t - - * Functions - - nfc_initiator_select_tag() became nfc_initiator_select_passive_target() - - New nfc_initiator_list_passive_targets() returns a list of detected - target on desired modulation - - (experimental) New nfc_initiator_poll_targets() returns targets that are - detected during hardware polling (available only with PN532) - - nfc_initiator_transceive_dep_bytes(), nfc_target_receive_dep_bytes() and - nfc_target_send_dep_bytes() have been removed from API, use - NDO_EASY_FRAMING option to switch from raw mode to "easy framing" - - nfc_initiator_mifare_cmd() have been removed: no more Mifare related - stuff in libnfc's API - - New nfc_strerror(), nfc_strerror_r() and nfc_perror() to report errors - - New append_iso14443a_crc() to append iso14443a_crc() to a string - - -New in 1.3.4 (since 1.2.1): - -Installed files - - - Headers are now installed in include/nfc instead of include/libnfc - - libnfc.h have been renamed to nfc.h - - defines.h and types.h have been merge into nfc-types.h - - bitutils.h is not installed anymore, some functions are now in - examples/nfc-utils.c - - devices.h, dev_acr122.h, dev_arygon.h, dev_pn531.h, dev_pn533.h and rs232.h - are not installed anymore - - New header mifareultag.h, like mifaretag.h for Mifare UltraLight - - New header nfc-messages.h with messages macros (DBG, ERR, INFO) - -API Changes - - * Types - - uint32_t which was used as size now are size_t - - chip_type became nfc_chip_t (enum) - - init_modulation became nfc_modulation_t (enum), and now have - NM_ACTIVE_DEP and NM_PASSIVE_DEP modulation values added - - * Structures - - dev_info became nfc_device_t - - dev_config_option became nfc_device_option_t - - New nfc_device_desc_t to describe the way to access to a NFC device. - Initialisation example: - nfc_device_desc_t ndd = { - ndd.pcDriver = "ARYGON"; - ndd.pcPort = "/dev/ttyUSB0"; - ndd.uiSpeed = 115200; - }; - - dev_callbacks became driver_callbacks and now have two function pointers - more: pick_device() and list_devices() - - New nfc_dep_info_t to handle DEP targets info - - tag_info_iso14443a became nfc_iso14443a_info_t - - tag_info_iso14443b became nfc_iso14443b_info_t - - tag_info_felica became nfc_felica_info_t - - tag_info_jewel became nfc_jewel_info_t - - tag_info became nfc_target_info_t, and now have extended union to - nfc_dep_info_t - - * Functions - - nfc_connect() now takes 1 nfc_devive_desc_t argument (can be NULL) - - New nfc_list_devices(), it find available NFC devices using all know - drivers - - (experimental) New nfc_initiator_select_dep(), it looks for DEP targets - - (experimental) New nfc_initiator_transceive_dep_bytes(), like - nfc_initiator_transceive_bytes() for DEP targets - - (experimental) New nfc_target_receive_dep_bytes() and - nfc_target_send_dep_bytes(), to receive/send bytes to DEP target - (configured as initiator) while local NFC device is configured as target - - New nfc_device_name() returns the device's name - - New iso14443a_crc() computes CRC as described in ISO/IEC 14443 - - New nfc_version() returns the actual version of libnfc (with SVN - revision, if available) diff --git a/libnfc/buses/usbbus.c b/libnfc/buses/usbbus.c index e894340..120090a 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,634 +25,300 @@ * along with this program. If not, see * */ - -/** - * @file usbbus.c - * @brief libusb 0.1 driver wrapper - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif // HAVE_CONFIG_H - +#include +#include #include -#include -#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 -/* - * This file embeds partially libusb-compat-0.1 by: - * Copyright (C) 2008 Daniel Drake - * Copyright (c) 2000-2003 Johannes Erdfelt - * This layer will be removed ASAP before integration in the main trunk - */ - - -#define LIST_ADD(begin, ent) \ - do { \ - if (begin) { \ - ent->next = begin; \ - ent->next->prev = ent; \ - } else \ - ent->next = NULL; \ - ent->prev = NULL; \ - begin = ent; \ - } while(0) - -#define LIST_DEL(begin, ent) \ - do { \ - if (ent->prev) \ - ent->prev->next = ent->next; \ - else \ - begin = ent->next; \ - if (ent->next) \ - ent->next->prev = ent->prev; \ - ent->prev = NULL; \ - ent->next = NULL; \ - } while (0) - -#define USBBUS_DT_CONFIG_SIZE 9 -#define USBBUS_DT_INTERFACE_SIZE 9 -#define USBBUS_DT_ENDPOINT_AUDIO_SIZE 9 - static libusb_context *ctx = NULL; -struct usbbus_bus *usb_busses = NULL; +uint8_t get_usb_num_configs(struct libusb_device *dev); -static void _usb_finalize(void) -{ - if (ctx) { - libusb_exit(ctx); - ctx = NULL; - } -} - -static void usb_init(void) -{ - if (!ctx) { - int r; - r = libusb_init(&ctx); - if (r < 0) { - return; - } - - atexit(_usb_finalize); - } -} - -static int find_busses(struct usbbus_bus **ret) -{ - libusb_device **dev_list = NULL; - struct usbbus_bus *busses = NULL; - struct usbbus_bus *bus; - int dev_list_len = 0; - int i; - int r; - - r = libusb_get_device_list(ctx, &dev_list); - if (r < 0) { - return r; - } - - if (r == 0) { - libusb_free_device_list(dev_list, 1); - /* no buses */ - return 0; - } - - /* iterate over the device list, identifying the individual busses. - * we use the location field of the usbbus_bus structure to store the - * bus number. */ - - dev_list_len = r; - for (i = 0; i < dev_list_len; i++) { - libusb_device *dev = dev_list[i]; - uint8_t bus_num = libusb_get_bus_number(dev); - - /* if we already know about it, continue */ - if (busses) { - bus = busses; - int found = 0; - do { - if (bus_num == bus->location) { - found = 1; - break; - } - } while ((bus = bus->next) != NULL); - if (found) - continue; - } - - /* add it to the list of busses */ - bus = malloc(sizeof(*bus)); - if (!bus) - goto err; - - memset(bus, 0, sizeof(*bus)); - bus->location = bus_num; - snprintf(bus->dirname, USBBUS_PATH_MAX, "%03d", bus_num); - LIST_ADD(busses, bus); - } - - libusb_free_device_list(dev_list, 1); - *ret = busses; - return 0; - -err: - bus = busses; - while (bus) { - struct usbbus_bus *tbus = bus->next; - free(bus); - bus = tbus; - } - return LIBUSB_ERROR_NO_MEM; -} - -static int usb_find_busses(void) -{ - struct usbbus_bus *new_busses = NULL; - struct usbbus_bus *bus; - int changes = 0; - int r; - - /* libusb-1.0 initialization might have failed, but we can't indicate - * this with libusb-0.1, so trap that situation here */ - if (!ctx) - return 0; - - r = find_busses(&new_busses); - if (r < 0) { - return r; - } - - /* walk through all busses we already know about, removing duplicates - * from the new list. if we do not find it in the new list, the bus - * has been removed. */ - - bus = usb_busses; - while (bus) { - struct usbbus_bus *tbus = bus->next; - struct usbbus_bus *nbus = new_busses; - int found = 0; - - while (nbus) { - struct usbbus_bus *tnbus = nbus->next; - - if (bus->location == nbus->location) { - LIST_DEL(new_busses, nbus); - free(nbus); - found = 1; - break; - } - nbus = tnbus; - } - - if (!found) { - /* bus removed */ - changes++; - LIST_DEL(usb_busses, bus); - free(bus); - } - - bus = tbus; - } - - /* anything remaining in new_busses is a new bus */ - bus = new_busses; - while (bus) { - struct usbbus_bus *tbus = bus->next; - LIST_DEL(new_busses, bus); - LIST_ADD(usb_busses, bus); - changes++; - bus = tbus; - } - - return changes; -} - -static int find_devices(libusb_device **dev_list, int dev_list_len, - struct usbbus_bus *bus, struct usbbus_device **ret) -{ - struct usbbus_device *devices = NULL; - struct usbbus_device *dev; - int i; - - for (i = 0; i < dev_list_len; i++) { - libusb_device *newlib_dev = dev_list[i]; - uint8_t bus_num = libusb_get_bus_number(newlib_dev); - - if (bus_num != bus->location) - continue; - - dev = malloc(sizeof(*dev)); - if (!dev) - goto err; - - /* No need to reference the device now, just take the pointer. We - * increase the reference count later if we keep the device. */ - dev->dev = newlib_dev; - - dev->bus = bus; - dev->devnum = libusb_get_device_address(newlib_dev); - snprintf(dev->filename, USBBUS_PATH_MAX, "%03d", dev->devnum); - LIST_ADD(devices, dev); - } - - *ret = devices; - return 0; - -err: - dev = devices; - while (dev) { - struct usbbus_device *tdev = dev->next; - free(dev); - dev = tdev; - } - return LIBUSB_ERROR_NO_MEM; -} - -static void clear_endpoint_descriptor(struct usbbus_endpoint_descriptor *ep) -{ - if (ep->extra) - free(ep->extra); -} - -static void clear_interface_descriptor(struct usbbus_interface_descriptor *iface) -{ - if (iface->extra) - free(iface->extra); - if (iface->endpoint) { - int i; - for (i = 0; i < iface->bNumEndpoints; i++) - clear_endpoint_descriptor(iface->endpoint + i); - free(iface->endpoint); - } -} - -static void clear_interface(struct usbbus_interface *iface) -{ - if (iface->altsetting) { - int i; - for (i = 0; i < iface->num_altsetting; i++) - clear_interface_descriptor(iface->altsetting + i); - free(iface->altsetting); - } -} - -static void clear_config_descriptor(struct usbbus_config_descriptor *config) -{ - if (config->extra) - free(config->extra); - if (config->interface) { - int i; - for (i = 0; i < config->bNumInterfaces; i++) - clear_interface(config->interface + i); - free(config->interface); - } -} - -static void clear_device(struct usbbus_device *dev) -{ - int i; - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) - clear_config_descriptor(dev->config + i); -} - -static int copy_endpoint_descriptor(struct usbbus_endpoint_descriptor *dest, - const struct libusb_endpoint_descriptor *src) -{ - memcpy(dest, src, USBBUS_DT_ENDPOINT_AUDIO_SIZE); - - dest->extralen = src->extra_length; - if (src->extra_length) { - dest->extra = malloc(src->extra_length); - if (!dest->extra) - return LIBUSB_ERROR_NO_MEM; - memcpy(dest->extra, src->extra, src->extra_length); - } - - return 0; -} - -static int copy_interface_descriptor(struct usbbus_interface_descriptor *dest, - const struct libusb_interface_descriptor *src) -{ - int i; - int num_endpoints = src->bNumEndpoints; - size_t alloc_size = sizeof(struct usbbus_endpoint_descriptor) * num_endpoints; - - memcpy(dest, src, USBBUS_DT_INTERFACE_SIZE); - dest->endpoint = malloc(alloc_size); - if (!dest->endpoint) - return LIBUSB_ERROR_NO_MEM; - memset(dest->endpoint, 0, alloc_size); - - for (i = 0; i < num_endpoints; i++) { - int r = copy_endpoint_descriptor(dest->endpoint + i, &src->endpoint[i]); - if (r < 0) { - clear_interface_descriptor(dest); - return r; - } - } - - dest->extralen = src->extra_length; - if (src->extra_length) { - dest->extra = malloc(src->extra_length); - if (!dest->extra) { - clear_interface_descriptor(dest); - return LIBUSB_ERROR_NO_MEM; - } - memcpy(dest->extra, src->extra, src->extra_length); - } - - return 0; -} - -static int copy_interface(struct usbbus_interface *dest, - const struct libusb_interface *src) -{ - int i; - int num_altsetting = src->num_altsetting; - size_t alloc_size = sizeof(struct usbbus_interface_descriptor) - * num_altsetting; - - dest->num_altsetting = num_altsetting; - dest->altsetting = malloc(alloc_size); - if (!dest->altsetting) - return LIBUSB_ERROR_NO_MEM; - memset(dest->altsetting, 0, alloc_size); - - for (i = 0; i < num_altsetting; i++) { - int r = copy_interface_descriptor(dest->altsetting + i, - &src->altsetting[i]); - if (r < 0) { - clear_interface(dest); - return r; - } - } - - return 0; -} - -static int copy_config_descriptor(struct usbbus_config_descriptor *dest, - const struct libusb_config_descriptor *src) -{ - int i; - int num_interfaces = src->bNumInterfaces; - size_t alloc_size = sizeof(struct usbbus_interface) * num_interfaces; - - memcpy(dest, src, USBBUS_DT_CONFIG_SIZE); - dest->interface = malloc(alloc_size); - if (!dest->interface) - return LIBUSB_ERROR_NO_MEM; - memset(dest->interface, 0, alloc_size); - - for (i = 0; i < num_interfaces; i++) { - int r = copy_interface(dest->interface + i, &src->interface[i]); - if (r < 0) { - clear_config_descriptor(dest); - return r; - } - } - - dest->extralen = src->extra_length; - if (src->extra_length) { - dest->extra = malloc(src->extra_length); - if (!dest->extra) { - clear_config_descriptor(dest); - return LIBUSB_ERROR_NO_MEM; - } - memcpy(dest->extra, src->extra, src->extra_length); - } - - return 0; -} - -static int initialize_device(struct usbbus_device *dev) -{ - libusb_device *newlib_dev = dev->dev; - int num_configurations; - size_t alloc_size; - int r; - int i; - - /* device descriptor is identical in both libs */ - r = libusb_get_device_descriptor(newlib_dev, - (struct libusb_device_descriptor *) &dev->descriptor); - if (r < 0) { - return r; - } - - num_configurations = dev->descriptor.bNumConfigurations; - alloc_size = sizeof(struct usbbus_config_descriptor) * num_configurations; - dev->config = malloc(alloc_size); - if (!dev->config) - return LIBUSB_ERROR_NO_MEM; - memset(dev->config, 0, alloc_size); - - for (i = 0; i < num_configurations; i++) { - struct libusb_config_descriptor *newlib_config; - r = libusb_get_config_descriptor(newlib_dev, i, &newlib_config); - if (r < 0) { - clear_device(dev); - free(dev->config); - return r; - } - r = copy_config_descriptor(dev->config + i, newlib_config); - libusb_free_config_descriptor(newlib_config); - if (r < 0) { - clear_device(dev); - free(dev->config); - return r; - } - } - dev->num_children = 0; - dev->children = NULL; - - libusb_ref_device(newlib_dev); - return 0; -} - -static void free_device(struct usbbus_device *dev) -{ - clear_device(dev); - libusb_unref_device(dev->dev); - free(dev); -} - -static int usb_find_devices(void) -{ - struct usbbus_bus *bus; - libusb_device **dev_list; - int dev_list_len; - int changes = 0; - - /* libusb-1.0 initialization might have failed, but we can't indicate - * this with libusb-0.1, so trap that situation here */ - if (!ctx) - return 0; - - dev_list_len = libusb_get_device_list(ctx, &dev_list); - if (dev_list_len < 0) - return dev_list_len; - - for (bus = usb_busses; bus; bus = bus->next) { - int r; - struct usbbus_device *new_devices = NULL; - struct usbbus_device *dev; - - r = find_devices(dev_list, dev_list_len, bus, &new_devices); - if (r < 0) { - libusb_free_device_list(dev_list, 1); - return r; - } - - /* walk through the devices we already know about, removing duplicates - * from the new list. if we do not find it in the new list, the device - * has been removed. */ - dev = bus->devices; - while (dev) { - int found = 0; - struct usbbus_device *tdev = dev->next; - struct usbbus_device *ndev = new_devices; - - while (ndev) { - if (ndev->devnum == dev->devnum) { - LIST_DEL(new_devices, ndev); - free(ndev); - found = 1; - break; - } - ndev = ndev->next; - } - - if (!found) { - LIST_DEL(bus->devices, dev); - free_device(dev); - changes++; - } - - dev = tdev; - } - - /* anything left in new_devices is a new device */ - dev = new_devices; - while (dev) { - struct usbbus_device *tdev = dev->next; - r = initialize_device(dev); - if (r < 0) { - dev = tdev; - continue; - } - LIST_DEL(new_devices, dev); - LIST_ADD(bus->devices, dev); - changes++; - dev = tdev; - } - } - - libusb_free_device_list(dev_list, 1); - return changes; -} - -int usbbus_prepare(void) -{ - static bool usb_initialized = false; - if (!usb_initialized) { +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)) { - setenv("USB_DEBUG", "255", 1); - } + 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)) { + setenv("USB_DEBUG", "255", 1); + } #endif - usb_init(); - usb_initialized = true; - } + 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)", usbbus_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)", usbbus_strerror(res)); - return -1; - } - return 0; + // 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). + 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; } -usbbus_device_handle *usbbus_open(struct usbbus_device *dev) -{ - int r; - usbbus_device_handle *udev; - r = libusb_open((libusb_device *) dev->dev, (libusb_device_handle **)&udev); - if (r < 0) { - return NULL; - } - return (usbbus_device_handle *)udev; + +TODO kenspeckle +beim ende vom programm libusb dinge wieder freigeben + +size_t usbbus_usb_scan(char **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) { + continue; + } + } + + libusb_device_handle *udev; + int res = libusb_open(dev, &udev); + if (res < 0 && udev == NULL) { + 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); + // 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); + size_t size_new_str = snprintf( + connstrings[device_found], + sizeof(nfc_connstring), + "%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 + continue; + } + device_found++; + // Test if we reach the maximum "wanted" devices + if (device_found == connstrings_len) { + return device_found; + } + } + } + } + + return device_found; } -void usbbus_close(usbbus_device_handle *dev) -{ - libusb_close((libusb_device_handle *)dev); +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); + } } -int usbbus_set_configuration(usbbus_device_handle *dev, int configuration) -{ - return libusb_set_configuration((libusb_device_handle *)dev, configuration); +uint8_t get_usb_num_configs(struct libusb_device *dev) { + struct libusb_device_descriptor descriptor; + libusb_get_device_descriptor(dev, &descriptor); + return descriptor.bNumConfigurations; } -int usbbus_get_string_simple(usbbus_device_handle *dev, int index, char *buf, size_t buflen) -{ - return libusb_get_string_descriptor_ascii((libusb_device_handle *)dev, index & 0xff, - (unsigned char *) buf, (int) buflen); +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)); + } + } } -int usbbus_bulk_transfer(usbbus_device_handle *dev, int ep, char *bytes, int size, int *actual_length, int timeout) -{ - return libusb_bulk_transfer((libusb_device_handle *)dev, ep & 0xff, (unsigned char *)bytes, size, actual_length, timeout); + +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); + } -int usbbus_claim_interface(usbbus_device_handle *dev, int interface) -{ - return libusb_claim_interface((libusb_device_handle *)dev, interface); + +uint16_t usbbus_get_vendor_id(struct libusb_device *dev) { + struct libusb_device_descriptor descriptor; + libusb_get_device_descriptor(dev, &descriptor); + return descriptor.idVendor; } -int usbbus_release_interface(usbbus_device_handle *dev, int interface) -{ - return libusb_release_interface((libusb_device_handle *)dev, interface); +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_set_interface_alt_setting(usbbus_device_handle *dev, int interface, int alternate) -{ - return libusb_set_interface_alt_setting((libusb_device_handle *)dev, interface, alternate); + +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; } -int usbbus_reset(usbbus_device_handle *dev) -{ - return libusb_reset_device((libusb_device_handle *)dev); -} -const char *usbbus_strerror(int errcode) -{ - return libusb_strerror((enum libusb_error)errcode); -} - -struct usbbus_bus *usbbus_get_busses(void) -{ - return usb_busses; -} diff --git a/libnfc/buses/usbbus.h b/libnfc/buses/usbbus.h index abf71fc..8da762d 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,150 +26,29 @@ * */ -/** - * @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__ +#include -#include -#include - -#define USBBUS_ERROR_ACCESS -3 -#define USBBUS_ERROR_TIMEOUT -7 - -int usbbus_prepare(void); - -// Libusb-0.1 API: -#define USBBUS_ENDPOINT_DIR_MASK 0x80 -#define USBBUS_ENDPOINT_TYPE_BULK 2 -#define USBBUS_ENDPOINT_IN 0x80 -#define USBBUS_ENDPOINT_OUT 0x00 - -#ifdef PATH_MAX -#define USBBUS_PATH_MAX PATH_MAX -#else -#define USBBUS_PATH_MAX 4096 -#endif - -struct usbbus_device_handle; -typedef struct usbbus_device_handle usbbus_device_handle; - -struct usbbus_endpoint_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bEndpointAddress; - uint8_t bmAttributes; - uint16_t wMaxPacketSize; - uint8_t bInterval; - uint8_t bRefresh; - uint8_t bSynchAddress; - - unsigned char *extra; - int extralen; -}; - -struct usbbus_interface_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bInterfaceNumber; - uint8_t bAlternateSetting; - uint8_t bNumEndpoints; - uint8_t bInterfaceClass; - uint8_t bInterfaceSubClass; - uint8_t bInterfaceProtocol; - uint8_t iInterface; - - struct usbbus_endpoint_descriptor *endpoint; - - unsigned char *extra; - int extralen; -}; - -struct usbbus_interface { - struct usbbus_interface_descriptor *altsetting; - int num_altsetting; -}; - -struct usbbus_config_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t wTotalLength; - uint8_t bNumInterfaces; - uint8_t bConfigurationValue; - uint8_t iConfiguration; - uint8_t bmAttributes; - uint8_t MaxPower; - - struct usbbus_interface *interface; - - unsigned char *extra; - int extralen; -}; - -/* Device descriptor */ -struct usbbus_device_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bcdUSB; - uint8_t bDeviceClass; - uint8_t bDeviceSubClass; - uint8_t bDeviceProtocol; - uint8_t bMaxPacketSize0; - uint16_t idVendor; - uint16_t idProduct; - uint16_t bcdDevice; - uint8_t iManufacturer; - uint8_t iProduct; - uint8_t iSerialNumber; - uint8_t bNumConfigurations; -}; - - -struct usbbus_bus; +#define EMPTY_STRING "\0"; struct usbbus_device { - struct usbbus_device *next, *prev; - - char filename[USBBUS_PATH_MAX + 1]; - - struct usbbus_bus *bus; - - struct usbbus_device_descriptor descriptor; - struct usbbus_config_descriptor *config; - - void *dev; - - uint8_t devnum; - - unsigned char num_children; - struct usbbus_device **children; -}; - -struct usbbus_bus { - struct usbbus_bus *next, *prev; - - char dirname[USBBUS_PATH_MAX + 1]; - - struct usbbus_device *devices; - uint32_t location; - - struct usbbus_device *root_dev; + uint16_t vendor_id; + uint16_t product_id; + const char *name; + uint16_t max_packet_size; }; -usbbus_device_handle *usbbus_open(struct usbbus_device *dev); -void usbbus_close(usbbus_device_handle *dev); -int usbbus_set_configuration(usbbus_device_handle *dev, int configuration); -int usbbus_get_string_simple(usbbus_device_handle *dev, int index, char *buf, size_t buflen); -int usbbus_bulk_transfer(usbbus_device_handle *dev, int ep, char *bytes, int size, int *actual_length, int timeout); -int usbbus_claim_interface(usbbus_device_handle *dev, int interface); -int usbbus_release_interface(usbbus_device_handle *dev, int interface); -int usbbus_set_interface_alt_setting(usbbus_device_handle *dev, int interface, int alternate); -int usbbus_reset(usbbus_device_handle *dev); -const char *usbbus_strerror(int errcode); -struct usbbus_bus *usbbus_get_busses(void); -#endif // __NFC_BUS_USB_H__ +int usbbus_prepare(); + +size_t usbbus_usb_scan(char ** 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); +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 cbe0bb2..3438c6c 100644 --- a/libnfc/drivers/acr122_usb.c +++ b/libnfc/drivers/acr122_usb.c @@ -48,6 +48,7 @@ #ifdef HAVE_CONFIG_H # include "config.h" + #endif // HAVE_CONFIG_H /* @@ -59,16 +60,18 @@ Thanks to d18c7db and Okko for example code #include #include #include + #ifdef _MSC_VER #include #endif #include +#include #include "nfc-internal.h" -#include "buses/usbbus.h" #include "chips/pn53x.h" #include "chips/pn53x-internal.h" #include "drivers/acr122_usb.h" +#include "buses/usbbus.h" #define ACR122_USB_DRIVER_NAME "acr122_usb" @@ -142,65 +145,67 @@ PC_to_RDR_XfrBlock APDU #pragma pack(1) struct ccid_header { - uint8_t bMessageType; - uint32_t dwLength; - uint8_t bSlot; - uint8_t bSeq; - uint8_t bMessageSpecific[3]; + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; + uint8_t bMessageSpecific[3]; }; struct apdu_header { - uint8_t bClass; - uint8_t bIns; - uint8_t bP1; - uint8_t bP2; - uint8_t bLen; + uint8_t bClass; + uint8_t bIns; + uint8_t bP1; + uint8_t bP2; + uint8_t bLen; }; struct acr122_usb_tama_frame { - struct ccid_header ccid_header; - struct apdu_header apdu_header; - uint8_t tama_header; - uint8_t tama_payload[254]; // According to ACR122U manual: Pseudo APDUs (Section 6.0), Lc is 1-byte long (Data In: 255-bytes). + struct ccid_header ccid_header; + struct apdu_header apdu_header; + uint8_t tama_header; + uint8_t tama_payload[254 + ]; // According to ACR122U manual: Pseudo APDUs (Section 6.0), Lc is 1-byte long (Data In: 255-bytes). }; struct acr122_usb_apdu_frame { - struct ccid_header ccid_header; - struct apdu_header apdu_header; - uint8_t apdu_payload[255]; // APDU Lc is 1-byte long + struct ccid_header ccid_header; + struct apdu_header apdu_header; + uint8_t apdu_payload[255]; // APDU Lc is 1-byte long }; #pragma pack() // Internal data struct struct acr122_usb_data { - usbbus_device_handle *pudh; - uint32_t uiEndPointIn; - uint32_t uiEndPointOut; - uint32_t uiMaxPacketSize; - volatile bool abort_flag; - // Keep some buffers to reduce memcpy() usage - struct acr122_usb_tama_frame tama_frame; - struct acr122_usb_apdu_frame apdu_frame; + 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; + struct acr122_usb_apdu_frame apdu_frame; }; // CCID Bulk-Out messages type -#define PC_to_RDR_IccPowerOn 0x62 -#define PC_to_RDR_XfrBlock 0x6f +#define PC_to_RDR_IccPowerOn 0x62 +#define PC_to_RDR_XfrBlock 0x6f -#define RDR_to_PC_DataBlock 0x80 +#define RDR_to_PC_DataBlock 0x80 // ISO 7816-4 #define SW1_More_Data_Available 0x61 #define SW1_Warning_with_NV_changed 0x63 #define PN53x_Specific_Application_Level_Error_Code 0x7f - // This frame template is copied at init time // Its designed for TAMA sending but is also used for simple ADPU frame: acr122_build_frame_from_apdu() will overwrite needed bytes const uint8_t acr122_usb_frame_template[] = { - PC_to_RDR_XfrBlock, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // CCID header - 0xff, 0x00, 0x00, 0x00, 0x00, // ADPU header - 0xd4, // PN532 direction + PC_to_RDR_XfrBlock, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // CCID header + 0xff, 0x00, 0x00, 0x00, 0x00, // ADPU header + 0xd4, // PN532 direction }; // APDUs instructions @@ -213,299 +218,230 @@ const struct pn53x_io acr122_usb_io; static int acr122_usb_init(nfc_device *pnd); static int acr122_usb_ack(nfc_device *pnd); static int acr122_usb_send_apdu(nfc_device *pnd, - const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint8_t *const data, size_t data_len, const uint8_t le, - uint8_t *out, const size_t out_size); + const uint8_t ins, + const uint8_t p1, + const uint8_t p2, + const uint8_t *const data, + size_t data_len, + const uint8_t le, + uint8_t *out, + const size_t out_size); static int -acr122_usb_bulk_read(struct acr122_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) -{ - int actual_length; - int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointIn, (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 != USBBUS_ERROR_TIMEOUT) { - res = NFC_EIO; - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read from USB (%s)", usbbus_strerror(res)); - } else { - res = NFC_ETIMEOUT; - } - } - return res; +acr122_usb_bulk_read(struct acr122_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, (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)", + libusb_strerror(res)); + } else { + res = NFC_ETIMEOUT; + } + } + return res; } 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 actual_length; - int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, (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 ((actual_length > 0) && ((actual_length % data->uiMaxPacketSize) == 0)) { - usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, "\0", 0, &actual_length, timeout); - } - } else { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", usbbus_strerror(res)); - if (res == USBBUS_ERROR_TIMEOUT) { - res = NFC_ETIMEOUT; - } else { - res = NFC_EIO; - } - } - return res; +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 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 ((actual_length > 0) && ((actual_length % data->uiMaxPacketSize) == 0)) { + libusb_bulk_transfer(data->pudh, data->uiEndPointOut, EMPTY_STRING, 0, &actual_length, timeout); + } + } 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; + } + } + return res; } struct acr122_usb_supported_device { - uint16_t vendor_id; - uint16_t product_id; - const char *name; + 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" }, + //TODO find real max_packet_sizes + {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 usbbus_device *dev, struct acr122_usb_data *data) -{ - uint32_t uiIndex; - uint32_t uiEndPoint; - struct usbbus_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 != USBBUS_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 & USBBUS_ENDPOINT_DIR_MASK) == USBBUS_ENDPOINT_IN) { - data->uiEndPointIn = uiEndPoint; - data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize; - } - // Test if we dealing with a bulk OUT endpoint - if ((uiEndPoint & USBBUS_ENDPOINT_DIR_MASK) == USBBUS_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; - - usbbus_prepare(); - - size_t device_found = 0; - uint32_t uiBusIndex = 0; - struct usbbus_bus *bus; - for (bus = usbbus_get_busses(); bus; bus = bus->next) { - struct usbbus_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; - } - - usbbus_device_handle *udev = usbbus_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); - usbbus_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; - } - } - } - } - } - - return device_found; +acr122_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { + (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 usbbus_usb_scan((char **) 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 usbbus_device *dev, usbbus_device_handle *udev, char *buffer, size_t len) -{ - *buffer = '\0'; +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) { - usbbus_get_string_simple(udev, dev->descriptor.iManufacturer, buffer, len); - if (strlen(buffer) > 0) - strcpy(buffer + strlen(buffer), " / "); - usbbus_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)) { - strncpy(buffer, acr122_usb_supported_devices[n].name, len); - buffer[len - 1] = '\0'; - return true; - } - } - } + if (!*buffer) { + 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; + } + } + } - return false; + return false; } 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; - } +acr122_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, 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) { + return NULL; + } - struct acr122_usb_data data = { - .pudh = NULL, - .uiEndPointIn = 0, - .uiEndPointOut = 0, - }; - struct usbbus_bus *bus; - struct usbbus_device *dev; + uint8_t dev_addres = atoi(dev_address_str); + uint8_t config_idx = atoi(config_idx_str); - usbbus_prepare(); + usbbus_prepare(); - for (bus = usbbus_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 = usbbus_open(dev)) == NULL) - continue; - // Reset device - usbbus_reset(data.pudh); - // Retrieve end points - acr122_usb_get_end_points(dev, &data); - // Claim interface - int res = usbbus_claim_interface(data.pudh, 0); - if (res < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to claim USB interface (%s)", usbbus_strerror(res)); - usbbus_close(data.pudh); - // we failed to use the specified device - goto free_mem; - } + struct acr122_usb_data data = { + .dev = NULL, + .pudh = NULL, + .configIdx = config_idx, + .uiEndPointIn = 0, + .uiEndPointOut = 0, + }; + usbbus_get_device(dev_addres, data.dev, data.pudh); + // Reset device + libusb_reset_device(data.pudh); - // Check if there are more than 0 alternative interfaces and claim the first one - if (dev->config->interface->altsetting->bAlternateSetting > 0) { - res = usbbus_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)", usbbus_strerror(res)); - usbbus_close(data.pudh); - // we failed to use the specified device - goto free_mem; - } - } + // 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 + return NULL; + } - // 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)); + // Check if there are more than 0 alternative interfaces and claim the first one + // TODO would it not be better to iterate the alterative interfaces (and alternative settings) and check each 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 + return NULL; + } + } - pnd->driver_data = malloc(sizeof(struct acr122_usb_data)); - if (!pnd->driver_data) { - perror("malloc"); - goto error; - } - *DRIVER_DATA(pnd) = data; + // Allocate memory for the device info and specification, fill it and return the info + pnd = nfc_device_new(context, connstring); + if (!pnd) { + perror("malloc"); + return NULL; + } + acr122_usb_get_usb_device_name(data.dev, data.pudh, pnd->name, sizeof(pnd->name)); - // Alloc and init chip's data - if (pn53x_data_new(pnd, &acr122_usb_io) == NULL) { - perror("malloc"); - goto error; - } + pnd->driver_data = malloc(sizeof(struct acr122_usb_data)); + if (!pnd->driver_data) { + perror("malloc"); + nfc_device_free(pnd); + return NULL; + } + *DRIVER_DATA(pnd) = data; - 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; + // Alloc and init chip's data + if (pn53x_data_new(pnd, &acr122_usb_io) == NULL) { + perror("malloc"); + nfc_device_free(pnd); + return NULL; + } - if (acr122_usb_init(pnd) < 0) { - usbbus_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; + 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; -error: - // Free allocated structure on error. - nfc_device_free(pnd); - pnd = NULL; -free_mem: - free(desc.dirname); - free(desc.filename); - return pnd; + if (acr122_usb_init(pnd) < 0) { + libusb_close(data.pudh); + nfc_device_free(pnd); + return NULL; + } + DRIVER_DATA(pnd)->abort_flag = false; + + return pnd; } static void -acr122_usb_close(nfc_device *pnd) -{ - acr122_usb_ack(pnd); - pn53x_idle(pnd); +acr122_usb_close(nfc_device *pnd) { + acr122_usb_ack(pnd); + pn53x_idle(pnd); - int res; - if ((res = usbbus_release_interface(DRIVER_DATA(pnd)->pudh, 0)) < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to release USB interface (%s)", usbbus_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)); + } - usbbus_close(DRIVER_DATA(pnd)->pudh); - pn53x_data_free(pnd); - nfc_device_free(pnd); + libusb_close(DRIVER_DATA(pnd)->pudh); + pn53x_data_free(pnd); + nfc_device_free(pnd); } #if !defined(htole32) @@ -513,357 +449,395 @@ acr122_usb_close(nfc_device *pnd) uint32_t htole32(uint32_t u32); uint32_t -htole32(uint32_t u32) -{ - union { - uint8_t arr[4]; - uint32_t u32; - } u; - for (int i = 0; i < 4; i++) { - u.arr[i] = (u32 & 0xff); - u32 >>= 8; - } - return u.u32; +htole32(uint32_t u32) { + union { + uint8_t arr[4]; + uint32_t u32; + } u; + for (int i = 0; i < 4; i++) { + u.arr[i] = (u32 & 0xff); + u32 >>= 8; + } + return u.u32; } #endif /* !defined(htole32) */ static int -acr122_build_frame_from_apdu(nfc_device *pnd, const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint8_t *data, const size_t data_len, const uint8_t le) -{ - if (data_len > sizeof(DRIVER_DATA(pnd)->apdu_frame.apdu_payload)) - return NFC_EINVARG; - if ((data == NULL) && (data_len != 0)) - return NFC_EINVARG; +acr122_build_frame_from_apdu(nfc_device *pnd, + const uint8_t ins, + const uint8_t p1, + const uint8_t p2, + const uint8_t *data, + const size_t data_len, + const uint8_t le) { + if (data_len > sizeof(DRIVER_DATA(pnd)->apdu_frame.apdu_payload)) + return NFC_EINVARG; + if ((data == NULL) && (data_len != 0)) + return NFC_EINVARG; - DRIVER_DATA(pnd)->apdu_frame.ccid_header.dwLength = htole32(data_len + sizeof(struct apdu_header)); - DRIVER_DATA(pnd)->apdu_frame.apdu_header.bIns = ins; - DRIVER_DATA(pnd)->apdu_frame.apdu_header.bP1 = p1; - DRIVER_DATA(pnd)->apdu_frame.apdu_header.bP2 = p2; - if (data) { - // bLen is Lc when data != NULL - DRIVER_DATA(pnd)->apdu_frame.apdu_header.bLen = data_len; - memcpy(DRIVER_DATA(pnd)->apdu_frame.apdu_payload, data, data_len); - } else { - // bLen is Le when no data. - DRIVER_DATA(pnd)->apdu_frame.apdu_header.bLen = le; - } - return (sizeof(struct ccid_header) + sizeof(struct apdu_header) + data_len); + DRIVER_DATA(pnd)->apdu_frame.ccid_header.dwLength = htole32(data_len + sizeof(struct apdu_header)); + DRIVER_DATA(pnd)->apdu_frame.apdu_header.bIns = ins; + DRIVER_DATA(pnd)->apdu_frame.apdu_header.bP1 = p1; + DRIVER_DATA(pnd)->apdu_frame.apdu_header.bP2 = p2; + if (data) { + // bLen is Lc when data != NULL + DRIVER_DATA(pnd)->apdu_frame.apdu_header.bLen = data_len; + memcpy(DRIVER_DATA(pnd)->apdu_frame.apdu_payload, data, data_len); + } else { + // bLen is Le when no data. + DRIVER_DATA(pnd)->apdu_frame.apdu_header.bLen = le; + } + return (sizeof(struct ccid_header) + sizeof(struct apdu_header) + data_len); } static int -acr122_build_frame_from_tama(nfc_device *pnd, const uint8_t *tama, const size_t tama_len) -{ - if (tama_len > sizeof(DRIVER_DATA(pnd)->tama_frame.tama_payload)) - return NFC_EINVARG; +acr122_build_frame_from_tama(nfc_device *pnd, const uint8_t *tama, const size_t tama_len) { + if (tama_len > sizeof(DRIVER_DATA(pnd)->tama_frame.tama_payload)) + return NFC_EINVARG; - DRIVER_DATA(pnd)->tama_frame.ccid_header.dwLength = htole32(tama_len + sizeof(struct apdu_header) + 1); - DRIVER_DATA(pnd)->tama_frame.apdu_header.bLen = tama_len + 1; - memcpy(DRIVER_DATA(pnd)->tama_frame.tama_payload, tama, tama_len); - return (sizeof(struct ccid_header) + sizeof(struct apdu_header) + 1 + tama_len); + DRIVER_DATA(pnd)->tama_frame.ccid_header.dwLength = htole32(tama_len + sizeof(struct apdu_header) + 1); + DRIVER_DATA(pnd)->tama_frame.apdu_header.bLen = tama_len + 1; + memcpy(DRIVER_DATA(pnd)->tama_frame.tama_payload, tama, tama_len); + return (sizeof(struct ccid_header) + sizeof(struct apdu_header) + 1 + tama_len); } static int -acr122_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, const int timeout) -{ - int res; - if ((res = acr122_build_frame_from_tama(pnd, pbtData, szData)) < 0) { - pnd->last_error = NFC_EINVARG; - return pnd->last_error; - } +acr122_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, const int timeout) { + int res; + if ((res = acr122_build_frame_from_tama(pnd, pbtData, szData)) < 0) { + pnd->last_error = NFC_EINVARG; + return pnd->last_error; + } - if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->tama_frame), res, timeout)) < 0) { - pnd->last_error = res; - return pnd->last_error; - } - return NFC_SUCCESS; + if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) &(DRIVER_DATA(pnd)->tama_frame), res, timeout)) + < 0) { + pnd->last_error = res; + return pnd->last_error; + } + return NFC_SUCCESS; } #define USBBUS_TIMEOUT_PER_PASS 200 + static int -acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) -{ - off_t offset = 0; +acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) { + off_t offset = 0; - uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; - int res; + uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; + 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); - } - } + /* + * 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 = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), usbbus_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; + uint8_t attempted_response = RDR_to_PC_DataBlock; + size_t len; - if (res == NFC_ETIMEOUT) { - if (DRIVER_DATA(pnd)->abort_flag) { - DRIVER_DATA(pnd)->abort_flag = false; - acr122_usb_ack(pnd); - pnd->last_error = NFC_EOPABORTED; - return pnd->last_error; - } else { - goto read; - } - } - if (res < 12) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Invalid RDR_to_PC_DataBlock frame"); - // try to interrupt current device state - acr122_usb_ack(pnd); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - if (abtRxBuf[offset] != attempted_response) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame header mismatch"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - offset++; + if (res == NFC_ETIMEOUT) { + if (DRIVER_DATA(pnd)->abort_flag) { + DRIVER_DATA(pnd)->abort_flag = false; + acr122_usb_ack(pnd); + pnd->last_error = NFC_EOPABORTED; + return pnd->last_error; + } else { + goto read; + } + } + if (res < 12) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Invalid RDR_to_PC_DataBlock frame"); + // try to interrupt current device state + acr122_usb_ack(pnd); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + if (abtRxBuf[offset] != attempted_response) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame header mismatch"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + offset++; - len = abtRxBuf[offset++]; - if (!((len > 1) && (abtRxBuf[10] == 0xd5))) { // In case we didn't get an immediate answer: - if (len != 2) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Wrong reply"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - if (abtRxBuf[10] != SW1_More_Data_Available) { - if ((abtRxBuf[10] == SW1_Warning_with_NV_changed) && (abtRxBuf[11] == PN53x_Specific_Application_Level_Error_Code)) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 has detected an error at the application level"); - } else if ((abtRxBuf[10] == SW1_Warning_with_NV_changed) && (abtRxBuf[11] == 0x00)) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 didn't reply"); - } else { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unexpected Status Word (SW1: %02x SW2: %02x)", abtRxBuf[10], abtRxBuf[11]); - } - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - res = acr122_usb_send_apdu(pnd, APDU_GetAdditionnalData, 0x00, 0x00, NULL, 0, abtRxBuf[11], abtRxBuf, sizeof(abtRxBuf)); - if (res == NFC_ETIMEOUT) { - if (DRIVER_DATA(pnd)->abort_flag) { - DRIVER_DATA(pnd)->abort_flag = false; - acr122_usb_ack(pnd); - pnd->last_error = NFC_EOPABORTED; - return pnd->last_error; - } else { - goto read; // FIXME May cause some trouble on Touchatag, right ? - } - } - if (res < 12) { - // try to interrupt current device state - acr122_usb_ack(pnd); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - } - offset = 0; - if (abtRxBuf[offset] != attempted_response) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame header mismatch"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - offset++; + len = abtRxBuf[offset++]; + if (!((len > 1) && (abtRxBuf[10] == 0xd5))) { // In case we didn't get an immediate answer: + if (len != 2) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Wrong reply"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + if (abtRxBuf[10] != SW1_More_Data_Available) { + if ((abtRxBuf[10] == SW1_Warning_with_NV_changed) + && (abtRxBuf[11] == PN53x_Specific_Application_Level_Error_Code)) { + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_ERROR, + "%s", + "PN532 has detected an error at the application level"); + } else if ((abtRxBuf[10] == SW1_Warning_with_NV_changed) && (abtRxBuf[11] == 0x00)) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 didn't reply"); + } else { + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_ERROR, + "Unexpected Status Word (SW1: %02x SW2: %02x)", + abtRxBuf[10], + abtRxBuf[11]); + } + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + res = acr122_usb_send_apdu(pnd, + APDU_GetAdditionnalData, + 0x00, + 0x00, + NULL, + 0, + abtRxBuf[11], + abtRxBuf, + sizeof(abtRxBuf)); + if (res == NFC_ETIMEOUT) { + if (DRIVER_DATA(pnd)->abort_flag) { + DRIVER_DATA(pnd)->abort_flag = false; + acr122_usb_ack(pnd); + pnd->last_error = NFC_EOPABORTED; + return pnd->last_error; + } else { + goto read; // FIXME May cause some trouble on Touchatag, right ? + } + } + if (res < 12) { + // try to interrupt current device state + acr122_usb_ack(pnd); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + } + offset = 0; + if (abtRxBuf[offset] != attempted_response) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame header mismatch"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + offset++; - // XXX In CCID specification, len is a 32-bits (dword), do we need to decode more than 1 byte ? (0-255 bytes for PN532 reply) - len = abtRxBuf[offset++]; - if ((abtRxBuf[offset] != 0x00) && (abtRxBuf[offset + 1] != 0x00) && (abtRxBuf[offset + 2] != 0x00)) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Not implemented: only 1-byte length is supported, please report this bug with a full trace."); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - offset += 3; + // XXX In CCID specification, len is a 32-bits (dword), do we need to decode more than 1 byte ? (0-255 bytes for PN532 reply) + len = abtRxBuf[offset++]; + if ((abtRxBuf[offset] != 0x00) && (abtRxBuf[offset + 1] != 0x00) && (abtRxBuf[offset + 2] != 0x00)) { + log_put(LOG_GROUP, + LOG_CATEGORY, + NFC_LOG_PRIORITY_ERROR, + "%s", + "Not implemented: only 1-byte length is supported, please report this bug with a full trace."); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + offset += 3; - if (len < 4) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Too small reply"); - pnd->last_error = NFC_EIO; - return pnd->last_error; - } - len -= 4; // We skip 2 bytes for PN532 direction byte (D5) and command byte (CMD+1), then 2 bytes for APDU status (90 00). + if (len < 4) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Too small reply"); + pnd->last_error = NFC_EIO; + return pnd->last_error; + } + len -= + 4; // We skip 2 bytes for PN532 direction byte (D5) and command byte (CMD+1), then 2 bytes for APDU status (90 00). - 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_EOVFLOW; - return pnd->last_error; - } + 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_EOVFLOW; + return pnd->last_error; + } - // Skip CCID remaining bytes - offset += 2; // bSlot and bSeq are not used - offset += 2; // XXX bStatus and bError should maybe checked ? - offset += 1; // bRFU should be 0x00 + // Skip CCID remaining bytes + offset += 2; // bSlot and bSeq are not used + offset += 2; // XXX bStatus and bError should maybe checked ? + offset += 1; // bRFU should be 0x00 - // 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; + // 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; + 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); + memcpy(pbtData, abtRxBuf + offset, len); - return len; + return len; } int -acr122_usb_ack(nfc_device *pnd) -{ - (void) pnd; - int res = 0; - uint8_t acr122_ack_frame[] = { GetFirmwareVersion }; // We can't send a PN532's ACK frame, so we use a normal command to cancel current command - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 Abort"); - if ((res = acr122_build_frame_from_tama(pnd, acr122_ack_frame, sizeof(acr122_ack_frame))) < 0) - return res; - if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->tama_frame), res, 1000)) < 0) - return res; - uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; - res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), 1000); - return res; +acr122_usb_ack(nfc_device *pnd) { + (void) pnd; + int res = 0; + uint8_t acr122_ack_frame[] = + {GetFirmwareVersion}; // We can't send a PN532's ACK frame, so we use a normal command to cancel current command + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 Abort"); + if ((res = acr122_build_frame_from_tama(pnd, acr122_ack_frame, sizeof(acr122_ack_frame))) < 0) + return res; + if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) &(DRIVER_DATA(pnd)->tama_frame), res, 1000)) + < 0) + return res; + uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; + res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), 1000); + return res; } static int acr122_usb_send_apdu(nfc_device *pnd, - const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint8_t *const data, size_t data_len, const uint8_t le, - uint8_t *out, const size_t out_size) -{ - int res; - size_t frame_len = acr122_build_frame_from_apdu(pnd, ins, p1, p2, data, data_len, le); - if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->apdu_frame), frame_len, 1000)) < 0) - return res; - if ((res = acr122_usb_bulk_read(DRIVER_DATA(pnd), out, out_size, 1000)) < 0) - return res; - return res; + const uint8_t ins, + const uint8_t p1, + const uint8_t p2, + const uint8_t *const data, + size_t data_len, + const uint8_t le, + uint8_t *out, + const size_t out_size) { + int res; + size_t frame_len = acr122_build_frame_from_apdu(pnd, ins, p1, p2, data, data_len, le); + if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), + (unsigned char *) &(DRIVER_DATA(pnd)->apdu_frame), + frame_len, + 1000)) < 0) + return res; + if ((res = acr122_usb_bulk_read(DRIVER_DATA(pnd), out, out_size, 1000)) < 0) + return res; + return res; } int -acr122_usb_init(nfc_device *pnd) -{ - int res = 0; - int i; - uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; +acr122_usb_init(nfc_device *pnd) { + int res = 0; + int i; + uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; - /* - // See ACR122 manual: "Bi-Color LED and Buzzer Control" section - uint8_t acr122u_get_led_state_frame[] = { - 0x6b, // CCID - 0x09, // lenght of frame - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding - // frame: - 0xff, // Class - 0x00, // INS - 0x40, // P1: Get LED state command - 0x00, // P2: LED state control - 0x04, // Lc - 0x00, 0x00, 0x00, 0x00, // Blinking duration control - }; + /* + // See ACR122 manual: "Bi-Color LED and Buzzer Control" section + uint8_t acr122u_get_led_state_frame[] = { + 0x6b, // CCID + 0x09, // lenght of frame + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding + // frame: + 0xff, // Class + 0x00, // INS + 0x40, // P1: Get LED state command + 0x00, // P2: LED state control + 0x04, // Lc + 0x00, 0x00, 0x00, 0x00, // Blinking duration control + }; - log_put (LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 Get LED state"); - if ((res = acr122_usb_bulk_write (DRIVER_DATA (pnd), (uint8_t *) acr122u_get_led_state_frame, sizeof (acr122u_get_led_state_frame), 1000)) < 0) - return res; + log_put (LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 Get LED state"); + if ((res = acr122_usb_bulk_write (DRIVER_DATA (pnd), (uint8_t *) acr122u_get_led_state_frame, sizeof (acr122u_get_led_state_frame), 1000)) < 0) + return res; - if ((res = acr122_usb_bulk_read (DRIVER_DATA (pnd), abtRxBuf, sizeof (abtRxBuf), 1000)) < 0) - return res; - */ + if ((res = acr122_usb_bulk_read (DRIVER_DATA (pnd), abtRxBuf, sizeof (abtRxBuf), 1000)) < 0) + return res; + */ - if ((res = pn53x_set_property_int(pnd, NP_TIMEOUT_COMMAND, 1000)) < 0) - return res; + if ((res = pn53x_set_property_int(pnd, NP_TIMEOUT_COMMAND, 1000)) < 0) + return res; - // Power On ICC - uint8_t ccid_frame[] = { - PC_to_RDR_IccPowerOn, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 - }; + // Power On ICC + uint8_t ccid_frame[] = { + PC_to_RDR_IccPowerOn, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 + }; - if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), ccid_frame, sizeof(struct ccid_header), 1000)) < 0) - return res; - if ((res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), 1000)) < 0) - return res; + if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), ccid_frame, sizeof(struct ccid_header), 1000)) < 0) + return res; + if ((res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), 1000)) < 0) + return res; - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 PICC Operating Parameters"); - if ((res = acr122_usb_send_apdu(pnd, 0x00, 0x51, 0x00, NULL, 0, 0, abtRxBuf, sizeof(abtRxBuf))) < 0) - return res; + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 PICC Operating Parameters"); + if ((res = acr122_usb_send_apdu(pnd, 0x00, 0x51, 0x00, NULL, 0, 0, abtRxBuf, sizeof(abtRxBuf))) < 0) + return res; - res = 0; - for (i = 0; i < 3; i++) { - if (res < 0) - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 init failed, trying again..."); - if ((res = pn53x_init(pnd)) >= 0) - break; - } - if (res < 0) - return res; + res = 0; + for (i = 0; i < 3; i++) { + if (res < 0) + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 init failed, trying again..."); + if ((res = pn53x_init(pnd)) >= 0) + break; + } + if (res < 0) + return res; - return NFC_SUCCESS; + return NFC_SUCCESS; } static int -acr122_usb_abort_command(nfc_device *pnd) -{ - DRIVER_DATA(pnd)->abort_flag = true; - return NFC_SUCCESS; +acr122_usb_abort_command(nfc_device *pnd) { + DRIVER_DATA(pnd)->abort_flag = true; + return NFC_SUCCESS; } const struct pn53x_io acr122_usb_io = { - .send = acr122_usb_send, - .receive = acr122_usb_receive, + .send = acr122_usb_send, + .receive = acr122_usb_receive, }; const struct nfc_driver acr122_usb_driver = { - .name = ACR122_USB_DRIVER_NAME, - .scan_type = NOT_INTRUSIVE, - .scan = acr122_usb_scan, - .open = acr122_usb_open, - .close = acr122_usb_close, - .strerror = pn53x_strerror, + .name = ACR122_USB_DRIVER_NAME, + .scan_type = NOT_INTRUSIVE, + .scan = acr122_usb_scan, + .open = acr122_usb_open, + .close = acr122_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, + .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, + .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_set_property_bool, - .device_set_property_int = pn53x_set_property_int, - .get_supported_modulation = pn53x_get_supported_modulation, - .get_supported_baud_rate = pn53x_get_supported_baud_rate, - .device_get_information_about = pn53x_get_information_about, + .device_set_property_bool = pn53x_set_property_bool, + .device_set_property_int = pn53x_set_property_int, + .get_supported_modulation = pn53x_get_supported_modulation, + .get_supported_baud_rate = pn53x_get_supported_baud_rate, + .device_get_information_about = pn53x_get_information_about, - .abort_command = acr122_usb_abort_command, - .idle = pn53x_idle, - /* Even if PN532, PowerDown is not recommended on those devices */ - .powerdown = NULL, + .abort_command = acr122_usb_abort_command, + .idle = pn53x_idle, + /* Even if PN532, PowerDown is not recommended on those devices */ + .powerdown = NULL, }; diff --git a/libnfc/drivers/pn53x_usb.c b/libnfc/drivers/pn53x_usb.c index 71b3670..8c23e68 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 /* @@ -42,11 +43,12 @@ Thanks to d18c7db and Okko for example code #include #include #include + #ifdef _MSC_VER #include #endif #include - +#include #include "nfc-internal.h" #include "buses/usbbus.h" #include "chips/pn53x.h" @@ -64,845 +66,758 @@ Thanks to d18c7db and Okko for example code 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 { - usbbus_device_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 usbbus_device *dev, usbbus_device_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 actual_length; - int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointIn, (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 != USBBUS_ERROR_TIMEOUT) - log_put(NFC_LOG_GROUP_COM, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read from USB (%s)", usbbus_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 actual_length; - int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, (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 ((actual_length > 0) && ((actual_length % data->uiMaxPacketSize) == 0)) { - usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, "\0", 0, &actual_length, timeout); - } - } else { - log_put(NFC_LOG_GROUP_COM, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", usbbus_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; - } +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; + return UNKNOWN; } static bool -pn53x_usb_get_end_points_default(struct usbbus_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; +pn53x_usb_get_end_points_default(struct pn53x_usb_data *data) { + struct libusb_device_descriptor descriptor; + libusb_get_device_descriptor(data->dev, &descriptor); - return true; - } - } - } + 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 false; + 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 usbbus_device *dev, struct pn53x_usb_data *data) -{ - uint32_t uiIndex; - uint32_t uiEndPoint; - struct usbbus_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 != USBBUS_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 & USBBUS_ENDPOINT_DIR_MASK) == USBBUS_ENDPOINT_IN) { - data->uiEndPointIn = uiEndPoint; - data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize; - } - // Test if we dealing with a bulk OUT endpoint - if ((uiEndPoint & USBBUS_ENDPOINT_DIR_MASK) == USBBUS_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; - - usbbus_prepare(); - - size_t device_found = 0; - uint32_t uiBusIndex = 0; - struct usbbus_bus *bus; - for (bus = usbbus_get_busses(); bus; bus = bus->next) { - struct usbbus_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; - } - } - - usbbus_device_handle *udev = usbbus_open(dev); - if (udev == NULL) - continue; - - // Set configuration - int res = usbbus_set_configuration(udev, 1); - if (res < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set USB configuration (%s)", usbbus_strerror(res)); - usbbus_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); - usbbus_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((char **) 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 usbbus_device *dev, usbbus_device_handle *udev, char *buffer, size_t len) -{ - *buffer = '\0'; +pn53x_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) { - usbbus_get_string_simple(udev, dev->descriptor.iManufacturer, buffer, len); - if (strlen(buffer) > 0) - strcpy(buffer + strlen(buffer), " / "); - usbbus_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(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; - } - } - } + 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; + 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; - } +pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring) { + nfc_device *pnd = NULL; - struct pn53x_usb_data data = { - .pudh = NULL, - .uiEndPointIn = 0, - .uiEndPointOut = 0, - .possibly_corrupted_usbdesc = false, - }; - struct usbbus_bus *bus; - struct usbbus_device *dev; + 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; + } - usbbus_prepare(); + uint8_t dev_addres = atoi(dev_address_str); + uint8_t config_idx = atoi(config_idx_str); - for (bus = usbbus_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 = usbbus_open(dev)) == NULL) - continue; + usbbus_prepare(); - //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 = usbbus_set_configuration(data.pudh, 1); - if (res < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set USB configuration (%s)", usbbus_strerror(res)); - if (res == USBBUS_ERROR_ACCESS) { - 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); - } - usbbus_close(data.pudh); - // we failed to use the specified device - goto free_mem; - } + struct pn53x_usb_data data = { + .dev = NULL, + .pudh = NULL, + .configIdx = config_idx, + .uiEndPointIn = 0, + .uiEndPointOut = 0, + .possibly_corrupted_usbdesc = false, + }; - res = usbbus_claim_interface(data.pudh, 0); - if (res < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to claim USB interface (%s)", usbbus_strerror(res)); - usbbus_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)); + usbbus_get_device(dev_addres, data.dev, data.pudh); - 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); + // 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)); - // 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) { - usbbus_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; + } + // 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); + } + libusb_close(data.pudh); + // we failed to use the specified device + return NULL; + } -error: - // Free allocated structure on error. - nfc_device_free(pnd); - pnd = NULL; -free_mem: - free(desc.dirname); - free(desc.filename); - return pnd; + 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 + 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"); + 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); + 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); + 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) { + libusb_close(data.pudh); + nfc_device_free(pnd); + return NULL; + } + DRIVER_DATA(pnd)->abort_flag = false; + return pnd; } static void -pn53x_usb_close(nfc_device *pnd) -{ - pn53x_usb_ack(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)->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); + if (DRIVER_DATA(pnd)->possibly_corrupted_usbdesc) { + pn533_fix_usbdesc(pnd); + } - pn53x_idle(pnd); + pn53x_idle(pnd); - int res; - if ((res = usbbus_release_interface(DRIVER_DATA(pnd)->pudh, 0)) < 0) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to release USB interface (%s)", usbbus_strerror(res)); - } - - usbbus_close(DRIVER_DATA(pnd)->pudh); - pn53x_data_free(pnd); - nfc_device_free(pnd); + libusb_close(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; +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; - } + 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; - } + 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; - } + 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; + 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 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; +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; + 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); - } - } + /* + * 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); + res = pn53x_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), usbbus_timeout); - if (res == USBBUS_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 == 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; - } + 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; + 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; + 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[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; - } + // 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; - } + 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; + // 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; + 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; + 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]; - } + 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 (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; + 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); - } +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 ((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); + 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); + /* 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. + /* + 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'. - */ + 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); + /* 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; + 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; +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; + 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, + .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, + .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, + .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, + .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, + .abort_command = pn53x_usb_abort_command, + .idle = pn53x_idle, + .powerdown = pn53x_PowerDown, };