Reimplementing usb code with libusb-1.0

This commit is contained in:
Kenspeckle 2022-07-10 12:05:48 +02:00
parent c4e04d52d3
commit 1ac0d803da
5 changed files with 1451 additions and 2409 deletions

394
NEWS.md
View File

@ -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)

View File

@ -7,6 +7,7 @@
* Copyright (C) 2010-2012 Romain Tartière * Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen * Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* Copyright (C) 2022 Kenspeckle
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* *
@ -24,634 +25,300 @@
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* *
*/ */
#include <stdbool.h>
/** #include <string.h>
* @file usbbus.c
* @brief libusb 0.1 driver wrapper
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include <stdlib.h> #include <stdlib.h>
#include <libusb.h>
#include <stdint.h>
#include "usbbus.h" #include "usbbus.h"
#include "log.h" #include "log.h"
#define LOG_CATEGORY "libnfc.buses.usbbus"
#define LOG_CATEGORY "libnfc.bus.usbbus"
#define LOG_GROUP NFC_LOG_GROUP_DRIVER #define LOG_GROUP NFC_LOG_GROUP_DRIVER
/*
* This file embeds partially libusb-compat-0.1 by:
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
* Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
* 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; 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) int usbbus_prepare() {
{
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; static bool usb_initialized = false;
int res;
if (!usb_initialized) { if (!usb_initialized) {
#ifdef ENVVARS #ifdef ENVVARS
char *env_log_level = getenv("LIBNFC_LOG_LEVEL"); char *env_log_level = getenv("LIBNFC_LOG_LEVEL");
// Set libusb debug only if asked explicitely: // Set libusb debug only if asked explicitely:
// LIBUSB_LOG_LEVEL=12288 (= NFC_LOG_PRIORITY_DEBUG * 2 ^ NFC_LOG_GROUP_LIBUSB) // LIBUSB_LOG_LEVEL=12288 (= NFC_LOG_PRIORITY_DEBUG * 2 ^ NFC_LOG_GROUP_LIBUSB)
if (env_log_level && (((atoi(env_log_level) >> (NFC_LOG_GROUP_LIBUSB * 2)) & 0x00000003) >= NFC_LOG_PRIORITY_DEBUG)) { if (env_log_level
&& (((atoi(env_log_level) >> (NFC_LOG_GROUP_LIBUSB * 2)) & 0x00000003) >= NFC_LOG_PRIORITY_DEBUG)) {
setenv("USB_DEBUG", "255", 1); setenv("USB_DEBUG", "255", 1);
} }
#endif #endif
usb_init(); res = libusb_init(&ctx);
if (res != 0) {
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to init libusb (%s)",
libusb_strerror(res));
return res;
}
usb_initialized = true; 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 // 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 // called after usb_find_busses. Returns the number of changes since the
// previous call to this function (total of new device and devices removed). // previous call to this function (total of new device and devices removed).
if ((res = usb_find_devices()) < 0) { libusb_device **tmp_devices;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to find USB devices (%s)", usbbus_strerror(res)); 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 -1;
} }
return 0; return 0;
} }
usbbus_device_handle *usbbus_open(struct usbbus_device *dev)
{ TODO kenspeckle
int r; beim ende vom programm libusb dinge wieder freigeben
usbbus_device_handle *udev;
r = libusb_open((libusb_device *) dev->dev, (libusb_device_handle **)&udev); size_t usbbus_usb_scan(char **connstrings,
if (r < 0) { const size_t connstrings_len,
return NULL; 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;
} }
return (usbbus_device_handle *)udev;
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) void usbbus_get_usb_endpoints(struct libusb_device *dev,
{ uint8_t *endpoint_in,
libusb_close((libusb_device_handle *)dev); 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) uint8_t get_usb_num_configs(struct libusb_device *dev) {
{ struct libusb_device_descriptor descriptor;
return libusb_set_configuration((libusb_device_handle *)dev, configuration); 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) void usbbus_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len) {
{ struct libusb_device_descriptor descriptor;
return libusb_get_string_descriptor_ascii((libusb_device_handle *)dev, index & 0xff, libusb_get_device_descriptor(dev, &descriptor);
(unsigned char *) buf, (int) buflen); 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)
{ void usbbus_get_device(uint8_t dev_address, struct libusb_device * dev, struct libusb_device_handle * dev_handle) {
return libusb_bulk_transfer((libusb_device_handle *)dev, ep & 0xff, (unsigned char *)bytes, size, actual_length, timeout); 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)
{ uint16_t usbbus_get_vendor_id(struct libusb_device *dev) {
return libusb_claim_interface((libusb_device_handle *)dev, interface); struct libusb_device_descriptor descriptor;
libusb_get_device_descriptor(dev, &descriptor);
return descriptor.idVendor;
} }
int usbbus_release_interface(usbbus_device_handle *dev, int interface) uint16_t usbbus_get_product_id(struct libusb_device *dev) {
{ struct libusb_device_descriptor descriptor;
return libusb_release_interface((libusb_device_handle *)dev, interface); libusb_get_device_descriptor(dev, &descriptor);
return descriptor.idProduct;
} }
int usbbus_set_interface_alt_setting(usbbus_device_handle *dev, int interface, int alternate)
{ int usbbus_get_num_alternate_settings(struct libusb_device *dev, uint8_t config_idx) {
return libusb_set_interface_alt_setting((libusb_device_handle *)dev, interface, alternate); 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;
}

View File

@ -7,6 +7,7 @@
* Copyright (C) 2010-2012 Romain Tartière * Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen * Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* Copyright (C) 2022 Kenspeckle
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* *
@ -25,150 +26,29 @@
* *
*/ */
/** #ifndef __NFC_BUS_USBBUS_H__
* @file usbbus.h #define __NFC_BUS_USBBUS_H__
* @brief libusb 0.1 driver header
*/
#ifndef __NFC_BUS_USB_H__ #include <libusb-1.0/libusb.h>
# define __NFC_BUS_USB_H__
#include <stdbool.h> #define EMPTY_STRING "\0";
#include <string.h>
#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;
struct usbbus_device { struct usbbus_device {
struct usbbus_device *next, *prev; uint16_t vendor_id;
uint16_t product_id;
char filename[USBBUS_PATH_MAX + 1]; const char *name;
uint16_t max_packet_size;
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;
}; };
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

View File

@ -48,6 +48,7 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
/* /*
@ -59,16 +60,18 @@ Thanks to d18c7db and Okko for example code
#include <inttypes.h> #include <inttypes.h>
#include <sys/select.h> #include <sys/select.h>
#include <string.h> #include <string.h>
#ifdef _MSC_VER #ifdef _MSC_VER
#include <sys/types.h> #include <sys/types.h>
#endif #endif
#include <nfc/nfc.h> #include <nfc/nfc.h>
#include <libusb.h>
#include "nfc-internal.h" #include "nfc-internal.h"
#include "buses/usbbus.h"
#include "chips/pn53x.h" #include "chips/pn53x.h"
#include "chips/pn53x-internal.h" #include "chips/pn53x-internal.h"
#include "drivers/acr122_usb.h" #include "drivers/acr122_usb.h"
#include "buses/usbbus.h"
#define ACR122_USB_DRIVER_NAME "acr122_usb" #define ACR122_USB_DRIVER_NAME "acr122_usb"
@ -161,7 +164,8 @@ struct acr122_usb_tama_frame {
struct ccid_header ccid_header; struct ccid_header ccid_header;
struct apdu_header apdu_header; struct apdu_header apdu_header;
uint8_t tama_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). 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 acr122_usb_apdu_frame {
@ -173,10 +177,12 @@ struct acr122_usb_apdu_frame {
// Internal data struct // Internal data struct
struct acr122_usb_data { struct acr122_usb_data {
usbbus_device_handle *pudh; libusb_device * dev;
uint32_t uiEndPointIn; libusb_device_handle *pudh;
uint32_t uiEndPointOut; uint8_t configIdx;
uint32_t uiMaxPacketSize; uint8_t uiEndPointIn;
uint8_t uiEndPointOut;
uint16_t uiMaxPacketSize;
volatile bool abort_flag; volatile bool abort_flag;
// Keep some buffers to reduce memcpy() usage // Keep some buffers to reduce memcpy() usage
struct acr122_usb_tama_frame tama_frame; struct acr122_usb_tama_frame tama_frame;
@ -194,7 +200,6 @@ struct acr122_usb_data {
#define SW1_Warning_with_NV_changed 0x63 #define SW1_Warning_with_NV_changed 0x63
#define PN53x_Specific_Application_Level_Error_Code 0x7f #define PN53x_Specific_Application_Level_Error_Code 0x7f
// This frame template is copied at init time // 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 // 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[] = { const uint8_t acr122_usb_frame_template[] = {
@ -213,21 +218,30 @@ const struct pn53x_io acr122_usb_io;
static int acr122_usb_init(nfc_device *pnd); static int acr122_usb_init(nfc_device *pnd);
static int acr122_usb_ack(nfc_device *pnd); static int acr122_usb_ack(nfc_device *pnd);
static int acr122_usb_send_apdu(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, const uint8_t ins,
uint8_t *out, const size_t out_size); 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 static int
acr122_usb_bulk_read(struct acr122_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) acr122_usb_bulk_read(struct acr122_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) {
{
int actual_length; int actual_length;
int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointIn, (char *) abtRx, szRx, &actual_length, timeout); int res = libusb_bulk_transfer(data->pudh, data->uiEndPointIn, (unsigned char *) abtRx, szRx, &actual_length, timeout);
if (res == 0) { if (res == 0) {
LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, actual_length); LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, actual_length);
res = actual_length; res = actual_length;
} else { } else {
if (res != USBBUS_ERROR_TIMEOUT) { if (res != LIBUSB_ERROR_TIMEOUT) {
res = NFC_EIO; res = NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read from USB (%s)", usbbus_strerror(res)); log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to read from USB (%s)",
libusb_strerror(res));
} else { } else {
res = NFC_ETIMEOUT; res = NFC_ETIMEOUT;
} }
@ -236,19 +250,18 @@ acr122_usb_bulk_read(struct acr122_usb_data *data, uint8_t abtRx[], const size_t
} }
static int static int
acr122_usb_bulk_write(struct acr122_usb_data *data, uint8_t abtTx[], const size_t szTx, const int timeout) 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); LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTx, szTx);
int actual_length; int actual_length;
int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, (char *) abtTx, szTx, &actual_length, timeout); int res = libusb_bulk_transfer(data->pudh, data->uiEndPointOut, (unsigned char *) abtTx, szTx, &actual_length, timeout);
if (res == 0) { if (res == 0) {
// HACK This little hack is a well know problem of USB, see http://www.libusb.org/ticket/6 for more details // 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)) { if ((actual_length > 0) && ((actual_length % data->uiMaxPacketSize) == 0)) {
usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, "\0", 0, &actual_length, timeout); libusb_bulk_transfer(data->pudh, data->uiEndPointOut, EMPTY_STRING, 0, &actual_length, timeout);
} }
} else { } else {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", usbbus_strerror(res)); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", libusb_strerror(res));
if (res == USBBUS_ERROR_TIMEOUT) { if (res == LIBUSB_ERROR_TIMEOUT) {
res = NFC_ETIMEOUT; res = NFC_ETIMEOUT;
} else { } else {
res = NFC_EIO; res = NFC_EIO;
@ -261,120 +274,45 @@ struct acr122_usb_supported_device {
uint16_t vendor_id; uint16_t vendor_id;
uint16_t product_id; uint16_t product_id;
const char *name; const char *name;
uint16_t max_packet_size;
}; };
const struct acr122_usb_supported_device acr122_usb_supported_devices[] = { const struct acr122_usb_supported_device acr122_usb_supported_devices[] = {
{ 0x072F, 0x2200, "ACS ACR122" }, //TODO find real max_packet_sizes
{ 0x072F, 0x90CC, "Touchatag" }, {0x072F, 0x2200, "ACS ACR122", 0x40},
{ 0x072F, 0x2214, "ACS ACR1222" }, {0x072F, 0x90CC, "Touchatag", 0x40},
{0x072F, 0x2214, "ACS ACR1222", 0x40},
}; };
// Find transfer endpoints for bulk transfers const size_t
static void num_acr122_usb_supported_device = sizeof(acr122_usb_supported_devices) / sizeof(struct acr122_usb_supported_device);
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;
}
}
}
static size_t static size_t
acr122_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) acr122_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) {
{ (void) context;
(void)context; struct usbbus_device devices[num_acr122_usb_supported_device];
for (size_t i = 0; i < num_acr122_usb_supported_device; i++) {
usbbus_prepare(); devices[i].product_id = acr122_usb_supported_devices[i].product_id;
devices[i].vendor_id = acr122_usb_supported_devices[i].vendor_id;
size_t device_found = 0; devices[i].name = acr122_usb_supported_devices[i].name;
uint32_t uiBusIndex = 0; devices[i].max_packet_size = acr122_usb_supported_devices[i].max_packet_size;
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) { return usbbus_usb_scan((char **) connstrings, connstrings_len, devices, num_acr122_usb_supported_device, ACR122_USB_DRIVER_NAME);
// 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;
} }
struct acr122_usb_descriptor {
char *dirname;
char *filename;
};
static bool static bool
acr122_usb_get_usb_device_name(struct usbbus_device *dev, usbbus_device_handle *udev, char *buffer, size_t len) acr122_usb_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len) {
{
*buffer = '\0'; *buffer = '\0';
if (dev->descriptor.iManufacturer || dev->descriptor.iProduct) { usbbus_get_usb_device_name(dev, udev, buffer, len);
if (udev) { uint16_t vendor_id = usbbus_get_vendor_id(dev);
usbbus_get_string_simple(udev, dev->descriptor.iManufacturer, buffer, len); uint16_t product_id = usbbus_get_product_id(dev);
if (strlen(buffer) > 0)
strcpy(buffer + strlen(buffer), " / ");
usbbus_get_string_simple(udev, dev->descriptor.iProduct, buffer + strlen(buffer), len - strlen(buffer));
}
}
if (!*buffer) { if (!*buffer) {
for (size_t n = 0; n < sizeof(acr122_usb_supported_devices) / sizeof(struct acr122_usb_supported_device); n++) { for (size_t n = 0; n < num_acr122_usb_supported_device; n++) {
if ((acr122_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && if ((acr122_usb_supported_devices[n].vendor_id == vendor_id) &&
(acr122_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { (acr122_usb_supported_devices[n].product_id == product_id)) {
strncpy(buffer, acr122_usb_supported_devices[n].name, len); strncpy(buffer, acr122_usb_supported_devices[n].name, len);
buffer[len - 1] = '\0'; buffer[len - 1] = '\0';
return true; return true;
@ -386,62 +324,66 @@ acr122_usb_get_usb_device_name(struct usbbus_device *dev, usbbus_device_handle *
} }
static nfc_device * static nfc_device *
acr122_usb_open(const nfc_context *context, const nfc_connstring connstring) acr122_usb_open(const nfc_context *context, const nfc_connstring connstring) {
{
nfc_device *pnd = NULL; nfc_device *pnd = NULL;
struct acr122_usb_descriptor desc = { NULL, NULL }; char *dev_address_str;
int connstring_decode_level = connstring_decode(connstring, ACR122_USB_DRIVER_NAME, "usb", &desc.dirname, &desc.filename); char *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); int connstring_decode_level =
if (connstring_decode_level < 1) { connstring_decode(connstring, ACR122_USB_DRIVER_NAME, "usb", &dev_address_str, &config_idx_str);
goto free_mem; 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 = { uint8_t dev_addres = atoi(dev_address_str);
.pudh = NULL, uint8_t config_idx = atoi(config_idx_str);
.uiEndPointIn = 0,
.uiEndPointOut = 0,
};
struct usbbus_bus *bus;
struct usbbus_device *dev;
usbbus_prepare(); usbbus_prepare();
for (bus = usbbus_get_busses(); bus; bus = bus->next) { struct acr122_usb_data data = {
if (connstring_decode_level > 1) { .dev = NULL,
// A specific bus have been specified .pudh = NULL,
if (0 != strcmp(bus->dirname, desc.dirname)) .configIdx = config_idx,
continue; .uiEndPointIn = 0,
} .uiEndPointOut = 0,
for (dev = bus->devices; dev; dev = dev->next) { };
if (connstring_decode_level > 2) { usbbus_get_device(dev_addres, data.dev, data.pudh);
// 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 // Reset device
usbbus_reset(data.pudh); libusb_reset_device(data.pudh);
// Retrieve end points // Retrieve end points
acr122_usb_get_end_points(dev, &data); usbbus_get_usb_endpoints(data.dev, &(data.uiEndPointIn), &(data.uiEndPointOut), &(data.uiMaxPacketSize));
// Claim interface // Claim interface
int res = usbbus_claim_interface(data.pudh, 0); int res = libusb_claim_interface(data.pudh, 0);
if (res < 0) { if (res < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to claim USB interface (%s)", usbbus_strerror(res)); log_put(LOG_GROUP,
usbbus_close(data.pudh); 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 // we failed to use the specified device
goto free_mem; return NULL;
} }
// Check if there are more than 0 alternative interfaces and claim the first one // Check if there are more than 0 alternative interfaces and claim the first one
if (dev->config->interface->altsetting->bAlternateSetting > 0) { // TODO would it not be better to iterate the alterative interfaces (and alternative settings) and check each one?
res = usbbus_set_interface_alt_setting(data.pudh, 0, 0); if (usbbus_get_num_alternate_settings(data.dev, data.configIdx) > 0) {
res = libusb_set_interface_alt_setting(data.pudh, 0, 0);
if (res < 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)); log_put(LOG_GROUP,
usbbus_close(data.pudh); 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 // we failed to use the specified device
goto free_mem; return NULL;
} }
} }
@ -449,21 +391,23 @@ acr122_usb_open(const nfc_context *context, const nfc_connstring connstring)
pnd = nfc_device_new(context, connstring); pnd = nfc_device_new(context, connstring);
if (!pnd) { if (!pnd) {
perror("malloc"); perror("malloc");
goto error; return NULL;
} }
acr122_usb_get_usb_device_name(dev, data.pudh, pnd->name, sizeof(pnd->name)); acr122_usb_get_usb_device_name(data.dev, data.pudh, pnd->name, sizeof(pnd->name));
pnd->driver_data = malloc(sizeof(struct acr122_usb_data)); pnd->driver_data = malloc(sizeof(struct acr122_usb_data));
if (!pnd->driver_data) { if (!pnd->driver_data) {
perror("malloc"); perror("malloc");
goto error; nfc_device_free(pnd);
return NULL;
} }
*DRIVER_DATA(pnd) = data; *DRIVER_DATA(pnd) = data;
// Alloc and init chip's data // Alloc and init chip's data
if (pn53x_data_new(pnd, &acr122_usb_io) == NULL) { if (pn53x_data_new(pnd, &acr122_usb_io) == NULL) {
perror("malloc"); perror("malloc");
goto error; nfc_device_free(pnd);
return NULL;
} }
memcpy(&(DRIVER_DATA(pnd)->tama_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template)); memcpy(&(DRIVER_DATA(pnd)->tama_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template));
@ -472,38 +416,30 @@ acr122_usb_open(const nfc_context *context, const nfc_connstring connstring)
pnd->driver = &acr122_usb_driver; pnd->driver = &acr122_usb_driver;
if (acr122_usb_init(pnd) < 0) { if (acr122_usb_init(pnd) < 0) {
usbbus_close(data.pudh); libusb_close(data.pudh);
goto error; nfc_device_free(pnd);
return NULL;
} }
DRIVER_DATA(pnd)->abort_flag = false; DRIVER_DATA(pnd)->abort_flag = false;
goto free_mem;
}
}
// We ran out of devices before the index required
goto free_mem;
error:
// Free allocated structure on error.
nfc_device_free(pnd);
pnd = NULL;
free_mem:
free(desc.dirname);
free(desc.filename);
return pnd; return pnd;
} }
static void static void
acr122_usb_close(nfc_device *pnd) acr122_usb_close(nfc_device *pnd) {
{
acr122_usb_ack(pnd); acr122_usb_ack(pnd);
pn53x_idle(pnd); pn53x_idle(pnd);
int res; int res = libusb_release_interface(DRIVER_DATA(pnd)->pudh, 0);
if ((res = usbbus_release_interface(DRIVER_DATA(pnd)->pudh, 0)) < 0) { if (res < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to release USB interface (%s)", usbbus_strerror(res)); 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); libusb_close(DRIVER_DATA(pnd)->pudh);
pn53x_data_free(pnd); pn53x_data_free(pnd);
nfc_device_free(pnd); nfc_device_free(pnd);
} }
@ -513,8 +449,7 @@ acr122_usb_close(nfc_device *pnd)
uint32_t htole32(uint32_t u32); uint32_t htole32(uint32_t u32);
uint32_t uint32_t
htole32(uint32_t u32) htole32(uint32_t u32) {
{
union { union {
uint8_t arr[4]; uint8_t arr[4];
uint32_t u32; uint32_t u32;
@ -529,8 +464,13 @@ htole32(uint32_t u32)
#endif /* !defined(htole32) */ #endif /* !defined(htole32) */
static int 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) 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)) if (data_len > sizeof(DRIVER_DATA(pnd)->apdu_frame.apdu_payload))
return NFC_EINVARG; return NFC_EINVARG;
if ((data == NULL) && (data_len != 0)) if ((data == NULL) && (data_len != 0))
@ -552,8 +492,7 @@ acr122_build_frame_from_apdu(nfc_device *pnd, const uint8_t ins, const uint8_t p
} }
static int static int
acr122_build_frame_from_tama(nfc_device *pnd, const uint8_t *tama, const size_t tama_len) 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)) if (tama_len > sizeof(DRIVER_DATA(pnd)->tama_frame.tama_payload))
return NFC_EINVARG; return NFC_EINVARG;
@ -564,15 +503,15 @@ acr122_build_frame_from_tama(nfc_device *pnd, const uint8_t *tama, const size_t
} }
static int static int
acr122_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, const int timeout) acr122_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, const int timeout) {
{
int res; int res;
if ((res = acr122_build_frame_from_tama(pnd, pbtData, szData)) < 0) { if ((res = acr122_build_frame_from_tama(pnd, pbtData, szData)) < 0) {
pnd->last_error = NFC_EINVARG; pnd->last_error = NFC_EINVARG;
return pnd->last_error; return pnd->last_error;
} }
if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->tama_frame), res, timeout)) < 0) { if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) &(DRIVER_DATA(pnd)->tama_frame), res, timeout))
< 0) {
pnd->last_error = res; pnd->last_error = res;
return pnd->last_error; return pnd->last_error;
} }
@ -580,9 +519,9 @@ acr122_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, co
} }
#define USBBUS_TIMEOUT_PER_PASS 200 #define USBBUS_TIMEOUT_PER_PASS 200
static int static int
acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) {
{
off_t offset = 0; off_t offset = 0;
uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; uint8_t abtRxBuf[255 + sizeof(struct ccid_header)];
@ -594,7 +533,7 @@ acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, co
*/ */
int usbbus_timeout; int usbbus_timeout;
int remaining_time = timeout; int remaining_time = timeout;
read: read:
if (timeout == USBBUS_INFINITE_TIMEOUT) { if (timeout == USBBUS_INFINITE_TIMEOUT) {
usbbus_timeout = USBBUS_TIMEOUT_PER_PASS; usbbus_timeout = USBBUS_TIMEOUT_PER_PASS;
} else { } else {
@ -645,17 +584,35 @@ read:
return pnd->last_error; return pnd->last_error;
} }
if (abtRxBuf[10] != SW1_More_Data_Available) { if (abtRxBuf[10] != SW1_More_Data_Available) {
if ((abtRxBuf[10] == SW1_Warning_with_NV_changed) && (abtRxBuf[11] == PN53x_Specific_Application_Level_Error_Code)) { if ((abtRxBuf[10] == SW1_Warning_with_NV_changed)
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 has detected an error at the application level"); && (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)) { } 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"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 didn't reply");
} else { } else {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unexpected Status Word (SW1: %02x SW2: %02x)", abtRxBuf[10], abtRxBuf[11]); 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; pnd->last_error = NFC_EIO;
return pnd->last_error; return pnd->last_error;
} }
res = acr122_usb_send_apdu(pnd, APDU_GetAdditionnalData, 0x00, 0x00, NULL, 0, abtRxBuf[11], abtRxBuf, sizeof(abtRxBuf)); res = acr122_usb_send_apdu(pnd,
APDU_GetAdditionnalData,
0x00,
0x00,
NULL,
0,
abtRxBuf[11],
abtRxBuf,
sizeof(abtRxBuf));
if (res == NFC_ETIMEOUT) { if (res == NFC_ETIMEOUT) {
if (DRIVER_DATA(pnd)->abort_flag) { if (DRIVER_DATA(pnd)->abort_flag) {
DRIVER_DATA(pnd)->abort_flag = false; DRIVER_DATA(pnd)->abort_flag = false;
@ -684,7 +641,11 @@ read:
// 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) // 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++]; len = abtRxBuf[offset++];
if ((abtRxBuf[offset] != 0x00) && (abtRxBuf[offset + 1] != 0x00) && (abtRxBuf[offset + 2] != 0x00)) { 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."); 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; pnd->last_error = NFC_EIO;
return pnd->last_error; return pnd->last_error;
} }
@ -695,10 +656,16 @@ read:
pnd->last_error = NFC_EIO; pnd->last_error = NFC_EIO;
return pnd->last_error; 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). 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) { 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); 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; pnd->last_error = NFC_EOVFLOW;
return pnd->last_error; return pnd->last_error;
} }
@ -729,15 +696,16 @@ read:
} }
int int
acr122_usb_ack(nfc_device *pnd) acr122_usb_ack(nfc_device *pnd) {
{
(void) pnd; (void) pnd;
int res = 0; 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 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"); 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) if ((res = acr122_build_frame_from_tama(pnd, acr122_ack_frame, sizeof(acr122_ack_frame))) < 0)
return res; return res;
if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->tama_frame), res, 1000)) < 0) if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) &(DRIVER_DATA(pnd)->tama_frame), res, 1000))
< 0)
return res; return res;
uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; uint8_t abtRxBuf[255 + sizeof(struct ccid_header)];
res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), 1000); res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), 1000);
@ -746,12 +714,20 @@ acr122_usb_ack(nfc_device *pnd)
static int static int
acr122_usb_send_apdu(nfc_device *pnd, 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, const uint8_t ins,
uint8_t *out, const size_t out_size) 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; int res;
size_t frame_len = acr122_build_frame_from_apdu(pnd, ins, p1, p2, data, data_len, le); 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) if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd),
(unsigned char *) &(DRIVER_DATA(pnd)->apdu_frame),
frame_len,
1000)) < 0)
return res; return res;
if ((res = acr122_usb_bulk_read(DRIVER_DATA(pnd), out, out_size, 1000)) < 0) if ((res = acr122_usb_bulk_read(DRIVER_DATA(pnd), out, out_size, 1000)) < 0)
return res; return res;
@ -759,8 +735,7 @@ acr122_usb_send_apdu(nfc_device *pnd,
} }
int int
acr122_usb_init(nfc_device *pnd) acr122_usb_init(nfc_device *pnd) {
{
int res = 0; int res = 0;
int i; int i;
uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; uint8_t abtRxBuf[255 + sizeof(struct ccid_header)];
@ -819,8 +794,7 @@ acr122_usb_init(nfc_device *pnd)
} }
static int static int
acr122_usb_abort_command(nfc_device *pnd) acr122_usb_abort_command(nfc_device *pnd) {
{
DRIVER_DATA(pnd)->abort_flag = true; DRIVER_DATA(pnd)->abort_flag = true;
return NFC_SUCCESS; return NFC_SUCCESS;
} }

View File

@ -31,6 +31,7 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
/* /*
@ -42,11 +43,12 @@ Thanks to d18c7db and Okko for example code
#include <inttypes.h> #include <inttypes.h>
#include <sys/select.h> #include <sys/select.h>
#include <string.h> #include <string.h>
#ifdef _MSC_VER #ifdef _MSC_VER
#include <sys/types.h> #include <sys/types.h>
#endif #endif
#include <nfc/nfc.h> #include <nfc/nfc.h>
#include <libusb.h>
#include "nfc-internal.h" #include "nfc-internal.h"
#include "buses/usbbus.h" #include "buses/usbbus.h"
#include "chips/pn53x.h" #include "chips/pn53x.h"
@ -76,11 +78,13 @@ typedef enum {
// Internal data struct // Internal data struct
struct pn53x_usb_data { struct pn53x_usb_data {
usbbus_device_handle *pudh; libusb_device * dev;
libusb_device_handle *pudh;
uint8_t configIdx;
pn53x_usb_model model; pn53x_usb_model model;
uint32_t uiEndPointIn; uint8_t uiEndPointIn;
uint32_t uiEndPointOut; uint8_t uiEndPointOut;
uint32_t uiMaxPacketSize; uint16_t uiMaxPacketSize;
volatile bool abort_flag; volatile bool abort_flag;
bool possibly_corrupted_usbdesc; bool possibly_corrupted_usbdesc;
}; };
@ -89,37 +93,43 @@ struct pn53x_usb_data {
const struct pn53x_io pn53x_usb_io; const struct pn53x_io pn53x_usb_io;
// Prototypes // 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); int pn53x_usb_init(nfc_device *pnd);
static int static int
pn53x_usb_bulk_read(struct pn53x_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) pn53x_usb_bulk_read(struct pn53x_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) {
{
int actual_length; int actual_length;
int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointIn, (char *) abtRx, szRx, &actual_length, timeout); int res = libusb_bulk_transfer(data->pudh, data->uiEndPointIn & 0xff, abtRx, szRx, &actual_length, timeout);
if (res == 0) { if (res == 0) {
LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, actual_length); LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, actual_length);
res = actual_length; res = actual_length;
} else { } else {
if (res != USBBUS_ERROR_TIMEOUT) if (res != LIBUSB_ERROR_TIMEOUT)
log_put(NFC_LOG_GROUP_COM, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read from USB (%s)", usbbus_strerror(res)); log_put(NFC_LOG_GROUP_COM,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to read from USB (%s)",
libusb_strerror(res));
} }
return res; return res;
} }
static int static int
pn53x_usb_bulk_write(struct pn53x_usb_data *data, uint8_t abtTx[], const size_t szTx, const int timeout) 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); LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTx, szTx);
int actual_length; int actual_length;
int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, (char *) abtTx, szTx, &actual_length, timeout); int res = libusb_bulk_transfer(data->pudh, data->uiEndPointOut & 0xff, abtTx, szTx, &actual_length, timeout);
if (res == 0) { if (res == 0) {
// HACK This little hack is a well know problem of USB, see http://www.libusb.org/ticket/6 for more details // 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)) { if ((actual_length > 0) && ((actual_length % data->uiMaxPacketSize) == 0)) {
usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, "\0", 0, &actual_length, timeout); libusb_bulk_transfer(data->pudh, data->uiEndPointOut & 0xff, EMPTY_STRING, 0, &actual_length, timeout);
} }
} else { } else {
log_put(NFC_LOG_GROUP_COM, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", usbbus_strerror(res)); log_put(NFC_LOG_GROUP_COM,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to write to USB (%s)",
libusb_strerror(res));
} }
return res; return res;
} }
@ -136,15 +146,17 @@ struct pn53x_usb_supported_device {
}; };
const struct pn53x_usb_supported_device pn53x_usb_supported_devices[] = { const struct pn53x_usb_supported_device pn53x_usb_supported_devices[] = {
{ 0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0x84, 0x04, 0x40 }, {0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0x84, 0x04, 0x40},
{ 0x04CC, 0x2533, NXP_PN533, "NXP / PN533", 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, 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 {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 }, {0x054c, 0x0193, SONY_PN531, "Sony / PN531", 0x84, 0x04, 0x40},
{ 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x84, 0x04, 0x40 }, {0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x84, 0x04, 0x40},
{ 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]", 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 // PN533 USB descriptors backup buffers
const uint8_t btXramUsbDesc_scl3711[] = { const uint8_t btXramUsbDesc_scl3711[] = {
@ -172,21 +184,20 @@ const uint8_t btXramUsbDesc_asklogo[] = {
0x00, 0x00,
}; };
static void pn533_fix_usbdesc(nfc_device *pnd) static void pn533_fix_usbdesc(nfc_device *pnd) {
{
// PN533 USB descriptors may have been corrupted by large commands/responses // PN533 USB descriptors may have been corrupted by large commands/responses
// so they need to be restored before closing usb connection. // so they need to be restored before closing usb connection.
// cf PN5331B3HNC270 Release Note // cf PN5331B3HNC270 Release Note
uint32_t szXramUsbDesc = 0; uint32_t szXramUsbDesc = 0;
uint8_t *btXramUsbDesc = NULL; uint8_t *btXramUsbDesc = NULL;
if (DRIVER_DATA(pnd)->model == NXP_PN533) { if (DRIVER_DATA(pnd)->model == NXP_PN533) {
btXramUsbDesc = (uint8_t *)btXramUsbDesc_nxppn533; btXramUsbDesc = (uint8_t *) btXramUsbDesc_nxppn533;
szXramUsbDesc = sizeof(btXramUsbDesc_nxppn533); szXramUsbDesc = sizeof(btXramUsbDesc_nxppn533);
} else if (DRIVER_DATA(pnd)->model == SCM_SCL3711) { } else if (DRIVER_DATA(pnd)->model == SCM_SCL3711) {
btXramUsbDesc = (uint8_t *)btXramUsbDesc_scl3711; btXramUsbDesc = (uint8_t *) btXramUsbDesc_scl3711;
szXramUsbDesc = sizeof(btXramUsbDesc_scl3711); szXramUsbDesc = sizeof(btXramUsbDesc_scl3711);
} else if (DRIVER_DATA(pnd)->model == ASK_LOGO) { } else if (DRIVER_DATA(pnd)->model == ASK_LOGO) {
btXramUsbDesc = (uint8_t *)btXramUsbDesc_asklogo; btXramUsbDesc = (uint8_t *) btXramUsbDesc_asklogo;
szXramUsbDesc = sizeof(btXramUsbDesc_asklogo); szXramUsbDesc = sizeof(btXramUsbDesc_asklogo);
} }
#define MAXSZXRAMUSBDESC 61 #define MAXSZXRAMUSBDESC 61
@ -216,8 +227,8 @@ static void pn533_fix_usbdesc(nfc_device *pnd)
#endif #endif
// Abuse the overflow bug to restore USB descriptors in one go // 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"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "%s", "Fixing USB descriptors corruption");
uint8_t abtCmdWR[19 + MAXSZXRAMUSBDESC] = { GetFirmwareVersion }; uint8_t abtCmdWR[19 + MAXSZXRAMUSBDESC] = {GetFirmwareVersion};
for (uint8_t i = 0; i < szXramUsbDesc; i++) { for (size_t i = 0; i < szXramUsbDesc; i++) {
abtCmdWR[i + 19] = btXramUsbDesc[i]; abtCmdWR[i + 19] = btXramUsbDesc[i];
} }
size_t szCmdWR = sizeof(abtCmdWR); size_t szCmdWR = sizeof(abtCmdWR);
@ -229,8 +240,7 @@ static void pn533_fix_usbdesc(nfc_device *pnd)
} }
static pn53x_usb_model static pn53x_usb_model
pn53x_usb_get_device_model(uint16_t vendor_id, uint16_t product_id) 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++) { 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) && if ((vendor_id == pn53x_usb_supported_devices[n].vendor_id) &&
(product_id == pn53x_usb_supported_devices[n].product_id)) (product_id == pn53x_usb_supported_devices[n].product_id))
@ -241,11 +251,13 @@ pn53x_usb_get_device_model(uint16_t vendor_id, uint16_t product_id)
} }
static bool static bool
pn53x_usb_get_end_points_default(struct usbbus_device *dev, struct pn53x_usb_data *data) pn53x_usb_get_end_points_default(struct pn53x_usb_data *data) {
{ struct libusb_device_descriptor descriptor;
libusb_get_device_descriptor(data->dev, &descriptor);
for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { 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) && if ((descriptor.idVendor == pn53x_usb_supported_devices[n].vendor_id) &&
(dev->descriptor.idProduct == pn53x_usb_supported_devices[n].product_id)) { (descriptor.idProduct == pn53x_usb_supported_devices[n].product_id)) {
if (pn53x_usb_supported_devices[n].uiMaxPacketSize != 0) { if (pn53x_usb_supported_devices[n].uiMaxPacketSize != 0) {
data->uiEndPointIn = pn53x_usb_supported_devices[n].uiEndPointIn; data->uiEndPointIn = pn53x_usb_supported_devices[n].uiEndPointIn;
data->uiEndPointOut = pn53x_usb_supported_devices[n].uiEndPointOut; data->uiEndPointOut = pn53x_usb_supported_devices[n].uiEndPointOut;
@ -261,126 +273,30 @@ pn53x_usb_get_end_points_default(struct usbbus_device *dev, struct pn53x_usb_dat
int pn53x_usb_ack(nfc_device *pnd); 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;
}
}
}
static size_t static size_t
pn53x_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) pn53x_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) {
{ struct usbbus_device devices[num_pn53x_usb_supported_devices];
(void)context; for (size_t i = 0; i < num_pn53x_usb_supported_devices; i++) {
devices[i].product_id = pn53x_usb_supported_devices[i].product_id;
usbbus_prepare(); devices[i].vendor_id = pn53x_usb_supported_devices[i].vendor_id;
devices[i].name = pn53x_usb_supported_devices[i].name;
size_t device_found = 0; devices[i].max_packet_size = pn53x_usb_supported_devices[i].uiMaxPacketSize;
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) { return usbbus_usb_scan((char **) connstrings, connstrings_len, devices, num_pn53x_usb_supported_devices, PN53X_USB_DRIVER_NAME);
// 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;
} }
struct pn53x_usb_descriptor {
char *dirname;
char *filename;
};
bool bool
pn53x_usb_get_usb_device_name(struct usbbus_device *dev, usbbus_device_handle *udev, char *buffer, size_t len) pn53x_usb_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len) {
{
*buffer = '\0'; *buffer = '\0';
if (dev->descriptor.iManufacturer || dev->descriptor.iProduct) { usbbus_get_usb_device_name(dev, udev, buffer, len);
if (udev) { uint16_t vendor_id = usbbus_get_vendor_id(dev);
usbbus_get_string_simple(udev, dev->descriptor.iManufacturer, buffer, len); uint16_t product_id = usbbus_get_product_id(dev);
if (strlen(buffer) > 0)
strcpy(buffer + strlen(buffer), " / ");
usbbus_get_string_simple(udev, dev->descriptor.iProduct, buffer + strlen(buffer), len - strlen(buffer));
}
}
if (!*buffer) { if (!*buffer) {
for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { for (size_t n = 0; n < num_pn53x_usb_supported_devices; n++) {
if ((pn53x_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && if ((pn53x_usb_supported_devices[n].vendor_id == vendor_id) &&
(pn53x_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { (pn53x_usb_supported_devices[n].product_id == product_id)) {
strncpy(buffer, pn53x_usb_supported_devices[n].name, len); strncpy(buffer, pn53x_usb_supported_devices[n].name, len);
buffer[len - 1] = '\0'; buffer[len - 1] = '\0';
return true; return true;
@ -392,109 +308,120 @@ pn53x_usb_get_usb_device_name(struct usbbus_device *dev, usbbus_device_handle *u
} }
static nfc_device * static nfc_device *
pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring) pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring) {
{
nfc_device *pnd = NULL; 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); char *dev_address_str;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d element(s) have been decoded from \"%s\"", connstring_decode_level, connstring); char *config_idx_str;
if (connstring_decode_level < 1) { int connstring_decode_level =
goto free_mem; connstring_decode(connstring, PN53X_USB_DRIVER_NAME, "usb", &dev_address_str, &config_idx_str);
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_DEBUG,
"%d element(s) have been decoded from \"%s\"",
connstring_decode_level,
connstring);
// At least the driver and the dev address need to be decoded
if (connstring_decode_level < 2) {
return NULL;
} }
uint8_t dev_addres = atoi(dev_address_str);
uint8_t config_idx = atoi(config_idx_str);
usbbus_prepare();
struct pn53x_usb_data data = { struct pn53x_usb_data data = {
.dev = NULL,
.pudh = NULL, .pudh = NULL,
.configIdx = config_idx,
.uiEndPointIn = 0, .uiEndPointIn = 0,
.uiEndPointOut = 0, .uiEndPointOut = 0,
.possibly_corrupted_usbdesc = false, .possibly_corrupted_usbdesc = false,
}; };
struct usbbus_bus *bus;
struct usbbus_device *dev;
usbbus_prepare(); usbbus_get_device(dev_addres, data.dev, data.pudh);
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;
//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 // Retrieve end points, using hardcoded defaults if available
// or using the descriptors otherwise. // or using the descriptors otherwise.
if (pn53x_usb_get_end_points_default(dev, &data) == false) { if (!pn53x_usb_get_end_points_default(&data)) {
pn53x_usb_get_end_points(dev, &data); // Find transfer endpoints for bulk transfers
usbbus_get_usb_endpoints(data.dev, &(data.uiEndPointIn), &(data.uiEndPointOut), &(data.uiMaxPacketSize));
} }
// Set configuration // Set configuration
int res = usbbus_set_configuration(data.pudh, 1); int res = libusb_set_configuration(data.pudh, data.configIdx);
if (res < 0) { if (res < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set USB configuration (%s)", usbbus_strerror(res)); log_put(LOG_GROUP,
if (res == USBBUS_ERROR_ACCESS) { LOG_CATEGORY,
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); 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);
} }
usbbus_close(data.pudh); libusb_close(data.pudh);
// we failed to use the specified device // we failed to use the specified device
goto free_mem; return NULL;
} }
res = usbbus_claim_interface(data.pudh, 0); res = libusb_claim_interface(data.pudh, 0);
if (res < 0) { if (res < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to claim USB interface (%s)", usbbus_strerror(res)); log_put(LOG_GROUP,
usbbus_close(data.pudh); 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 // we failed to use the specified device
goto free_mem; return NULL;
} }
data.model = pn53x_usb_get_device_model(dev->descriptor.idVendor, dev->descriptor.idProduct); 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 // Allocate memory for the device info and specification, fill it and return the info
pnd = nfc_device_new(context, connstring); pnd = nfc_device_new(context, connstring);
if (!pnd) { if (!pnd) {
perror("malloc"); perror("malloc");
goto error; return NULL;
} }
pn53x_usb_get_usb_device_name(dev, data.pudh, pnd->name, sizeof(pnd->name)); pn53x_usb_get_usb_device_name(data.dev, data.pudh, pnd->name, sizeof(pnd->name));
pnd->driver_data = malloc(sizeof(struct pn53x_usb_data)); pnd->driver_data = malloc(sizeof(struct pn53x_usb_data));
if (!pnd->driver_data) { if (!pnd->driver_data) {
perror("malloc"); perror("malloc");
goto error; nfc_device_free(pnd);
return NULL;
} }
*DRIVER_DATA(pnd) = data; *DRIVER_DATA(pnd) = data;
// Alloc and init chip's data // Alloc and init chip's data
if (pn53x_data_new(pnd, &pn53x_usb_io) == NULL) { if (pn53x_data_new(pnd, &pn53x_usb_io) == NULL) {
perror("malloc"); perror("malloc");
goto error; nfc_device_free(pnd);
return NULL;
} }
switch (DRIVER_DATA(pnd)->model) { switch (DRIVER_DATA(pnd)->model) {
// empirical tuning // empirical tuning
case ASK_LOGO: case ASK_LOGO:CHIP_DATA(pnd)->timer_correction = 50;
CHIP_DATA(pnd)->timer_correction = 50;
CHIP_DATA(pnd)->progressive_field = true; CHIP_DATA(pnd)->progressive_field = true;
break; break;
case SCM_SCL3711: case SCM_SCL3711:
case SCM_SCL3712: case SCM_SCL3712:
case NXP_PN533: case NXP_PN533:CHIP_DATA(pnd)->timer_correction = 46;
CHIP_DATA(pnd)->timer_correction = 46;
break; break;
case NXP_PN531: case NXP_PN531:CHIP_DATA(pnd)->timer_correction = 50;
CHIP_DATA(pnd)->timer_correction = 50;
break; break;
case SONY_PN531: case SONY_PN531:CHIP_DATA(pnd)->timer_correction = 54;
CHIP_DATA(pnd)->timer_correction = 54;
break; break;
case SONY_RCS360: case SONY_RCS360:
case UNKNOWN: case UNKNOWN:
@ -509,29 +436,16 @@ pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring)
// HACK2: Then send a GetFirmware command to resync USB toggle bit between host & device // 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 // 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) { if (pn53x_usb_init(pnd) < 0) {
usbbus_close(data.pudh); libusb_close(data.pudh);
goto error; nfc_device_free(pnd);
return NULL;
} }
DRIVER_DATA(pnd)->abort_flag = false; DRIVER_DATA(pnd)->abort_flag = false;
goto free_mem;
}
}
// We ran out of devices before the index required
goto free_mem;
error:
// Free allocated structure on error.
nfc_device_free(pnd);
pnd = NULL;
free_mem:
free(desc.dirname);
free(desc.filename);
return pnd; return pnd;
} }
static void static void
pn53x_usb_close(nfc_device *pnd) pn53x_usb_close(nfc_device *pnd) {
{
pn53x_usb_ack(pnd); pn53x_usb_ack(pnd);
if (DRIVER_DATA(pnd)->model == ASK_LOGO) { if (DRIVER_DATA(pnd)->model == ASK_LOGO) {
@ -540,17 +454,13 @@ pn53x_usb_close(nfc_device *pnd)
pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P32) | _BV(P33) | _BV(P35)); 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) if (DRIVER_DATA(pnd)->possibly_corrupted_usbdesc) {
pn533_fix_usbdesc(pnd); pn533_fix_usbdesc(pnd);
}
pn53x_idle(pnd); pn53x_idle(pnd);
int res; libusb_close(DRIVER_DATA(pnd)->pudh);
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); pn53x_data_free(pnd);
nfc_device_free(pnd); nfc_device_free(pnd);
} }
@ -558,9 +468,8 @@ pn53x_usb_close(nfc_device *pnd)
#define PN53X_USB_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD) #define PN53X_USB_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD)
static int static int
pn53x_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, const int timeout) 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"
uint8_t abtFrame[PN53X_USB_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
size_t szFrame = 0; size_t szFrame = 0;
int res = 0; int res = 0;
@ -593,7 +502,10 @@ pn53x_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, con
// pn53x_usb_receive()) will be able to retrieve the correct response // pn53x_usb_receive()) will be able to retrieve the correct response
// packet. // packet.
// FIXME Sony reader is also affected by this bug but NACK is not supported // 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) { if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd),
(uint8_t *) pn53x_nack_frame,
sizeof(pn53x_nack_frame),
timeout)) < 0) {
pnd->last_error = res; pnd->last_error = res;
// try to interrupt current device state // try to interrupt current device state
pn53x_usb_ack(pnd); pn53x_usb_ack(pnd);
@ -604,9 +516,9 @@ pn53x_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, con
} }
#define USBBUS_TIMEOUT_PER_PASS 200 #define USBBUS_TIMEOUT_PER_PASS 200
static int static int
pn53x_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) pn53x_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) {
{
size_t len; size_t len;
off_t offset = 0; off_t offset = 0;
@ -619,7 +531,7 @@ pn53x_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, con
*/ */
int usbbus_timeout; int usbbus_timeout;
int remaining_time = timeout; int remaining_time = timeout;
read: read:
if (timeout == USBBUS_INFINITE_TIMEOUT) { if (timeout == USBBUS_INFINITE_TIMEOUT) {
usbbus_timeout = USBBUS_TIMEOUT_PER_PASS; usbbus_timeout = USBBUS_TIMEOUT_PER_PASS;
} else { } else {
@ -635,7 +547,7 @@ read:
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 (res == LIBUSB_ERROR_TIMEOUT) {
if (DRIVER_DATA(pnd)->abort_flag) { if (DRIVER_DATA(pnd)->abort_flag) {
DRIVER_DATA(pnd)->abort_flag = false; DRIVER_DATA(pnd)->abort_flag = false;
pn53x_usb_ack(pnd); pn53x_usb_ack(pnd);
@ -653,7 +565,7 @@ read:
return pnd->last_error; return pnd->last_error;
} }
const uint8_t pn53x_preamble[3] = { 0x00, 0x00, 0xff }; const uint8_t pn53x_preamble[3] = {0x00, 0x00, 0xff};
if (0 != (memcmp(abtRxBuf, pn53x_preamble, 3))) { if (0 != (memcmp(abtRxBuf, pn53x_preamble, 3))) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch");
pnd->last_error = NFC_EIO; pnd->last_error = NFC_EIO;
@ -694,7 +606,12 @@ read:
} }
if (len > szDataLen) { 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); 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; pnd->last_error = NFC_EIO;
return pnd->last_error; return pnd->last_error;
} }
@ -742,24 +659,22 @@ read:
} }
int int
pn53x_usb_ack(nfc_device *pnd) pn53x_usb_ack(nfc_device *pnd) {
{
return pn53x_usb_bulk_write(DRIVER_DATA(pnd), (uint8_t *) pn53x_ack_frame, sizeof(pn53x_ack_frame), 1000); return pn53x_usb_bulk_write(DRIVER_DATA(pnd), (uint8_t *) pn53x_ack_frame, sizeof(pn53x_ack_frame), 1000);
} }
int int
pn53x_usb_init(nfc_device *pnd) pn53x_usb_init(nfc_device *pnd) {
{
int res = 0; int res = 0;
// Sometimes PN53x USB doesn't reply ACK one the first frame, so we need to send a dummy one... // 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: //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 }; const uint8_t abtCmd[] = {GetFirmwareVersion};
pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1);
// ...and we don't care about error // ...and we don't care about error
pnd->last_error = 0; pnd->last_error = 0;
if (SONY_RCS360 == DRIVER_DATA(pnd)->model) { if (SONY_RCS360 == DRIVER_DATA(pnd)->model) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "SONY RC-S360 initialization."); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "SONY RC-S360 initialization.");
const uint8_t abtCmd2[] = { 0x18, 0x01 }; const uint8_t abtCmd2[] = {0x18, 0x01};
pn53x_transceive(pnd, abtCmd2, sizeof(abtCmd2), NULL, 0, -1); pn53x_transceive(pnd, abtCmd2, sizeof(abtCmd2), NULL, 0, -1);
pn53x_usb_ack(pnd); pn53x_usb_ack(pnd);
} }
@ -771,7 +686,10 @@ pn53x_usb_init(nfc_device *pnd)
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ASK LoGO initialization."); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ASK LoGO initialization.");
/* Internal registers */ /* Internal registers */
/* Disable 100mA current limit, Power on Secure IC (SVDD) */ /* 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); 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 */ /* 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); pn53x_write_register(pnd, PN53X_REG_CIU_TxSel, 0xFF, 0x14);
@ -808,8 +726,7 @@ pn53x_usb_init(nfc_device *pnd)
} }
static int static int
pn53x_usb_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable) pn53x_usb_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable) {
{
int res = 0; int res = 0;
if ((res = pn53x_set_property_bool(pnd, property, bEnable)) < 0) if ((res = pn53x_set_property_bool(pnd, property, bEnable)) < 0)
return res; return res;
@ -818,18 +735,16 @@ pn53x_usb_set_property_bool(nfc_device *pnd, const nfc_property property, const
case ASK_LOGO: case ASK_LOGO:
if (NP_ACTIVATE_FIELD == property) { if (NP_ACTIVATE_FIELD == property) {
/* Switch on/off LED2 and Progressive Field GPIO according to ACTIVATE_FIELD option */ /* 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"); 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) if (pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31)) < 0)
return NFC_ECHIP; return NFC_ECHIP;
} }
break; break;
case SCM_SCL3711: 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: case SCM_SCL3712:
if (NP_ACTIVATE_FIELD == property) { if (NP_ACTIVATE_FIELD == property) {
// Switch on/off LED according to ACTIVATE_FIELD option // Switch on/off LED according to ACTIVATE_FIELD option
@ -849,15 +764,15 @@ pn53x_usb_set_property_bool(nfc_device *pnd, const nfc_property property, const
} }
static int static int
pn53x_usb_abort_command(nfc_device *pnd) pn53x_usb_abort_command(nfc_device *pnd) {
{
DRIVER_DATA(pnd)->abort_flag = true; DRIVER_DATA(pnd)->abort_flag = true;
return NFC_SUCCESS; return NFC_SUCCESS;
} }
static int static int
pn53x_usb_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt) 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)) if ((DRIVER_DATA(pnd)->model != ASK_LOGO) || (mode != N_TARGET))
return pn53x_get_supported_modulation(pnd, mode, supported_mt); return pn53x_get_supported_modulation(pnd, mode, supported_mt);
else // ASK_LOGO has no N_TARGET support else // ASK_LOGO has no N_TARGET support