diff --git a/src/lib/drivers.h b/src/lib/drivers.h index 57f1fff..d9f9736 100644 --- a/src/lib/drivers.h +++ b/src/lib/drivers.h @@ -31,6 +31,7 @@ #endif /* HAVE_PCSC_LITE */ #ifdef HAVE_LIBUSB + #include "drivers/pn53x_usb.h" #include "drivers/pn531_usb.h" #include "drivers/pn533_usb.h" #endif /* HAVE_LIBUSB */ @@ -47,8 +48,8 @@ const static struct driver_callbacks drivers_callbacks_list[] = { { ACR122_DRIVER_NAME, acr122_pick_device, acr122_list_devices, acr122_connect, acr122_transceive, acr122_disconnect }, #endif /* HAVE_PCSC_LITE */ #ifdef HAVE_LIBUSB - { PN531_USB_DRIVER_NAME, NULL, NULL, pn531_usb_connect, pn531_usb_transceive, pn531_usb_disconnect }, - { PN533_USB_DRIVER_NAME, NULL, NULL, pn533_usb_connect, pn533_usb_transceive, pn533_usb_disconnect }, + { PN531_USB_DRIVER_NAME, NULL, NULL, pn531_usb_connect, pn53x_usb_transceive, pn53x_usb_disconnect }, + { PN533_USB_DRIVER_NAME, NULL, NULL, pn533_usb_connect, pn53x_usb_transceive, pn53x_usb_disconnect }, #endif /* HAVE_LIBUSB */ { PN532_UART_DRIVER_NAME, pn532_uart_pick_device, pn532_uart_list_devices, pn532_uart_connect, pn532_uart_transceive, pn532_uart_disconnect }, { ARYGON_DRIVER_NAME, NULL, NULL, arygon_connect, arygon_transceive, arygon_disconnect } diff --git a/src/lib/drivers/Makefile.am b/src/lib/drivers/Makefile.am index 47d2ac8..d29be78 100644 --- a/src/lib/drivers/Makefile.am +++ b/src/lib/drivers/Makefile.am @@ -15,9 +15,9 @@ if PCSC_LITE_ENABLED endif if LIBUSB_ENABLED - noinst_HEADERS += pn531_usb.h pn533_usb.h + noinst_HEADERS += pn531_usb.h pn533_usb.h pn53x_usb.h libnfcdrivers_la_CFLAGS += @LIBUSB_CFLAGS@ -DHAVE_LIBUSB - libnfcdrivers_la_SOURCES += pn531_usb.c pn533_usb.c + libnfcdrivers_la_SOURCES += pn531_usb.c pn533_usb.c pn53x_usb.c libnfcdrivers_la_LIBADD += @LIBUSB_LIBS@ endif diff --git a/src/lib/drivers/pn531_usb.c b/src/lib/drivers/pn531_usb.c index edcaef5..16d742b 100644 --- a/src/lib/drivers/pn531_usb.c +++ b/src/lib/drivers/pn531_usb.c @@ -25,272 +25,18 @@ Thanks to d18c7db and Okko for example code */ -#include -#include -#include - -#include -#include - -#include "pn531_usb.h" #include "../drivers.h" -#include -#include "../bitutils.h" - -#define BUFFER_LENGTH 256 -#define USB_TIMEOUT 30000 - -typedef struct { - usb_dev_handle* pudh; - uint32_t uiEndPointIn; - uint32_t uiEndPointOut; -} usb_spec_t; - -// Find transfer endpoints for bulk transfers -static void get_end_points(struct usb_device *dev, usb_spec_t* pus) -{ - uint32_t uiIndex; - uint32_t uiEndPoint; - struct usb_interface_descriptor* puid = dev->config->interface->altsetting; - - // 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out - for(uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++) - { - // Only accept bulk transfer endpoints (ignore interrupt endpoints) - if(puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK) continue; - - // Copy the endpoint to a local var, makes it more readable code - uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress; - - // Test if we dealing with a bulk IN endpoint - if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN) - { - DBG("Bulk endpoint in : 0x%02X\n", uiEndPoint); - pus->uiEndPointIn = uiEndPoint; - } - - // Test if we dealing with a bulk OUT endpoint - if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT) - { - DBG("Bulk endpoint in : 0x%02X\n", uiEndPoint); - pus->uiEndPointOut = uiEndPoint; - } - } -} - nfc_device_t* pn531_usb_connect(const nfc_device_desc_t* pndd) { int idvendor = 0x04CC; int idproduct = 0x0531; int idvendor_alt = 0x054c; int idproduct_alt = 0x0193; - struct usb_bus *bus; - struct usb_device *dev; nfc_device_t* pnd = NULL; - usb_spec_t* pus; - usb_spec_t us; - uint32_t uiDevIndex; - int devs; - us.uiEndPointIn = 0; - us.uiEndPointOut = 0; - us.pudh = NULL; + if((pnd = pn53x_usb_connect(pndd, idvendor, idproduct, "PN531USB", NC_PN531)) == NULL) + pnd = pn53x_usb_connect(pndd, idvendor_alt, idproduct_alt, "PN531USB", NC_PN531); - DBG("%s", "Looking for PN531 device"); - usb_init(); - if (usb_find_busses() <= 0) - { - DBG("%s","No USB bus found"); - return NULL; - } - if ((devs= usb_find_devices()) <= 0) - { - DBG("%s","No USB devices found"); - return NULL; - } - DBG("%i USB candidates found",devs); - - // Initialize the device index we are seaching for - if( pndd == NULL ) { - uiDevIndex = 0; - } else { - uiDevIndex = pndd->uiBusIndex; - } - - for (bus = usb_get_busses(); bus; bus = bus->next) - { - for (dev = bus->devices; dev; dev = dev->next) - { - if ((idvendor==dev->descriptor.idVendor && idproduct==dev->descriptor.idProduct) || - (idvendor_alt==dev->descriptor.idVendor && idproduct_alt==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 - uiDevIndex--; - continue; - } - if (dev->config->interface->altsetting->bNumEndpoints < 2) - { - // Nope, we maybe want the next one, let's try to find another - uiDevIndex--; - continue; - } - // Test if we are looking for this device according to the current index - if (uiDevIndex != 0) - { - // Nope, we maybe want the next one, let's try to find another - uiDevIndex--; - continue; - } - DBG("%s", "Found PN531 device"); - - // Open the PN531 USB device - us.pudh = usb_open(dev); - - get_end_points(dev,&us); - if(usb_set_configuration(us.pudh,1) < 0) - { - DBG("%s", "Set config failed"); - usb_close(us.pudh); - if (pndd == NULL) { - // don't return yet as there might be other readers on USB bus - continue; - } else { - // we failed to use the specified device - return NULL; - } - } - - if(usb_claim_interface(us.pudh,0) < 0) - { - DBG("%s", "Can't claim interface"); - usb_close(us.pudh); - if (pndd == NULL) { - // don't return yet as there might be other readers on USB bus - continue; - } else { - // we failed to use the specified device - return NULL; - } - } - // Allocate memory for the device info and specification, fill it and return the info - pus = malloc(sizeof(usb_spec_t)); - *pus = us; - pnd = malloc(sizeof(nfc_device_t)); - strcpy(pnd->acName,"PN531USB"); - pnd->nc = NC_PN531; - pnd->nds = (nfc_device_spec_t)pus; - pnd->bActive = true; - pnd->bCrc = true; - pnd->bPar = true; - pnd->ui8TxBits = 0; - return pnd; - } - } - } return pnd; } - -void pn531_usb_disconnect(nfc_device_t* pnd) -{ - usb_spec_t* pus = (usb_spec_t*)pnd->nds; - int ret; - - DBG("%s","PN531 disconnecting"); - usb_reset(pus->pudh); - if((ret= usb_release_interface(pus->pudh,0)) < 0) - DBG("usb_release failed %i",ret); - if(usb_close(pus->pudh) < 0) - DBG("usb_close failed %i",ret); - free(pnd->nds); - free(pnd); -} - -bool pn531_usb_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen) -{ - size_t uiPos = 0; - int ret = 0; - byte_t abtTx[BUFFER_LENGTH] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff" - byte_t abtRx[BUFFER_LENGTH]; - usb_spec_t* pus = (usb_spec_t*)nds; - - // Packet length = data length (len) + checksum (1) + end of stream marker (1) - abtTx[3] = szTxLen; - // Packet length checksum - abtTx[4] = BUFFER_LENGTH - abtTx[3]; - // Copy the PN53X command into the packet abtTx - memmove(abtTx+5,pbtTx,szTxLen); - - // Calculate data payload checksum - abtTx[szTxLen+5] = 0; - for(uiPos=0; uiPos < szTxLen; uiPos++) - { - abtTx[szTxLen+5] -= abtTx[uiPos+5]; - } - - // End of stream marker - abtTx[szTxLen+6] = 0; - - DBG("%s","USB bulk write"); - #ifdef DEBUG - printf("Tx: "); - print_hex(abtTx,szTxLen+7); - #endif - - ret = usb_bulk_write(pus->pudh, pus->uiEndPointOut, (char*)abtTx, szTxLen+7, USB_TIMEOUT); - if( ret < 0 ) - { - DBG("usb_bulk_write failed with error %d", ret); - return false; - } - - ret = usb_bulk_read(pus->pudh, pus->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT); - if( ret < 0 ) - { - #ifdef DEBUG - printf( "usb_bulk_read failed with error %d\n", ret); - #endif - return false; - } - - DBG("%s","USB bulk read"); - #ifdef DEBUG - printf("Rx: "); - print_hex(abtRx,ret); - #endif - - if( ret == 6 ) - { - ret = usb_bulk_read(pus->pudh, pus->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT); - if( ret < 0 ) - { - DBG("usb_bulk_read failed with error %d", ret); - return false; - } - - #ifdef DEBUG - printf("Rx: "); - print_hex(abtRx,ret); - #endif - } - - // When the answer should be ignored, just return a succesful result - if(pbtRx == NULL || pszRxLen == NULL) return true; - - // Only succeed when the result is at least 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable) - if(ret < 9) - { - DBG("%s","no data, returning false"); - return false; - } - - // Remove the preceding and appending bytes 00 00 FF xx Fx .. .. .. xx 00 (x = variable) - *pszRxLen = ret - 7 - 2; - memcpy( pbtRx, abtRx + 7, *pszRxLen); - - return true; -} diff --git a/src/lib/drivers/pn531_usb.h b/src/lib/drivers/pn531_usb.h index cbef32f..fcaccb9 100644 --- a/src/lib/drivers/pn531_usb.h +++ b/src/lib/drivers/pn531_usb.h @@ -24,19 +24,10 @@ #ifndef __NFC_DRIVER_PN531_USB_H__ #define __NFC_DRIVER_PN531_USB_H__ -#include -#include - -#include - #define PN531_USB_DRIVER_NAME "PN531_USB" // Functions used by developer to handle connection to this device nfc_device_t* pn531_usb_connect(const nfc_device_desc_t* pndd); -void pn531_usb_disconnect(nfc_device_t* pnd); - -// Callback function used by libnfc to transmit commands to the PN53X chip -bool pn531_usb_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen); #endif // ! __NFC_DRIVER_PN531_USB_H__ diff --git a/src/lib/drivers/pn533_usb.c b/src/lib/drivers/pn533_usb.c index 748435a..92d15c6 100644 --- a/src/lib/drivers/pn533_usb.c +++ b/src/lib/drivers/pn533_usb.c @@ -25,270 +25,18 @@ Thanks to d18c7db and Okko for example code */ -#include -#include -#include -#include - -#include "pn533_usb.h" #include "../drivers.h" -#include - -#define BUFFER_LENGTH 256 -#define USB_TIMEOUT 30000 - -typedef struct { - usb_dev_handle* pudh; - uint32_t uiEndPointIn; - uint32_t uiEndPointOut; -} usb_spec_t; - -// Find transfer endpoints for bulk transfers -static void get_end_points(struct usb_device *dev, usb_spec_t* pus) -{ - uint32_t uiIndex; - uint32_t uiEndPoint; - struct usb_interface_descriptor* puid = dev->config->interface->altsetting; - - // 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out - for(uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++) - { - // Only accept bulk transfer endpoints (ignore interrupt endpoints) - if(puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK) continue; - - // Copy the endpoint to a local var, makes it more readable code - uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress; - - // Test if we dealing with a bulk IN endpoint - if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN) - { - #ifdef DEBUG - printf("Bulk endpoint in : 0x%02X\n", uiEndPoint); - #endif - pus->uiEndPointIn = uiEndPoint; - } - - // Test if we dealing with a bulk OUT endpoint - if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT) - { - #ifdef DEBUG - printf("Bulk endpoint in : 0x%02X\n", uiEndPoint); - #endif - pus->uiEndPointOut = uiEndPoint; - } - } -} - nfc_device_t* pn533_usb_connect(const nfc_device_desc_t* pndd) { int idvendor = 0x04cc; int idproduct = 0x2533; int idvendor_alt = 0x04e6; int idproduct_alt = 0x5591; - - struct usb_bus *bus; - struct usb_device *dev; nfc_device_t* pnd = NULL; - usb_spec_t* pus; - usb_spec_t us; - uint32_t uiDevIndex; - us.uiEndPointIn = 0; - us.uiEndPointOut = 0; - us.pudh = NULL; + if((pnd = pn53x_usb_connect(pndd, idvendor, idproduct, "PN533USB", NC_PN533)) == NULL) + pnd = pn53x_usb_connect(pndd, idvendor_alt, idproduct_alt, "PN533USB", NC_PN533); - DBG("%s", "Looking for PN533 device"); - usb_init(); - if (usb_find_busses() < 0) return NULL; - if (usb_find_devices() < 0) return NULL; - - // Initialize the device index we are seaching for - if( pndd == NULL ) { - uiDevIndex = 0; - } else { - uiDevIndex = pndd->uiBusIndex; - } - - for (bus = usb_get_busses(); bus; bus = bus->next) - { - for (dev = bus->devices; dev; dev = dev->next) - { - if ((idvendor==dev->descriptor.idVendor && idproduct==dev->descriptor.idProduct) || - (idvendor_alt==dev->descriptor.idVendor && idproduct_alt==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 - uiDevIndex--; - continue; - } - if (dev->config->interface->altsetting->bNumEndpoints < 2) - { - // Nope, we maybe want the next one, let's try to find another - uiDevIndex--; - continue; - } - // Test if we are looking for this device according to the current index - if (uiDevIndex != 0) - { - // Nope, we maybe want the next one, let's try to find another - uiDevIndex--; - continue; - } - DBG("%s", "Found PN533 device"); - - // Open the PN533 USB device - us.pudh = usb_open(dev); - - get_end_points(dev,&us); - if(usb_set_configuration(us.pudh,1) < 0) - { - DBG("%s", "Setting config failed"); - usb_close(us.pudh); - if (pndd == NULL) { - // don't return yet as there might be other readers on USB bus - continue; - } else { - // we failed to use the specified device - return NULL; - } - } - - if(usb_claim_interface(us.pudh,0) < 0) - { - DBG("%s", "Can't claim interface"); - usb_close(us.pudh); - if (pndd == NULL) { - // don't return yet as there might be other readers on USB bus - continue; - } else { - // we failed to use the specified device - return NULL; - } - } - // Allocate memory for the device info and specification, fill it and return the info - pus = malloc(sizeof(usb_spec_t)); - *pus = us; - pnd = malloc(sizeof(nfc_device_t)); - strcpy(pnd->acName,"PN533USB"); - pnd->nc = NC_PN533; - pnd->nds = (nfc_device_spec_t)pus; - pnd->bActive = true; - pnd->bCrc = true; - pnd->bPar = true; - pnd->ui8TxBits = 0; - return pnd; - } - } - } return pnd; } - -void pn533_usb_disconnect(nfc_device_t* pnd) -{ - usb_spec_t* pus = (usb_spec_t*)pnd->nds; - int ret; - - usb_reset(pus->pudh); - if((ret= usb_release_interface(pus->pudh,0)) < 0) - DBG("usb_release failed %i",ret); - if((ret= usb_close(pus->pudh)) < 0) - DBG("usb_close failed %i",ret); - free(pnd->nds); - free(pnd); -} - -bool pn533_usb_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen) -{ - size_t uiPos = 0; - int ret = 0; - byte_t abtTx[BUFFER_LENGTH] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff" - byte_t abtRx[BUFFER_LENGTH]; - usb_spec_t* pus = (usb_spec_t*)nds; - - // Packet length = data length (len) + checksum (1) + end of stream marker (1) - abtTx[3] = szTxLen; - // Packet length checksum - abtTx[4] = BUFFER_LENGTH - abtTx[3]; - // Copy the PN53X command into the packet abtTx - memmove(abtTx+5,pbtTx,szTxLen); - - // Calculate data payload checksum - abtTx[szTxLen+5] = 0; - for(uiPos=0; uiPos < szTxLen; uiPos++) - { - abtTx[szTxLen+5] -= abtTx[uiPos+5]; - } - - // End of stream marker - abtTx[szTxLen+6] = 0; - - #ifdef DEBUG - printf(" TX: "); - print_hex(abtTx,szTxLen+7); - #endif - - ret = usb_bulk_write(pus->pudh, pus->uiEndPointOut, (char*)abtTx, szTxLen+7, USB_TIMEOUT); - if( ret < 0 ) - { - #ifdef DEBUG - printf("usb_bulk_write failed with error %d\n", ret); - #endif - return false; - } - - ret = usb_bulk_read(pus->pudh, pus->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT); - if( ret < 0 ) - { - #ifdef DEBUG - printf( "usb_bulk_read failed with error %d\n", ret); - #endif - return false; - } - - #ifdef DEBUG - printf(" RX: "); - print_hex(abtRx,ret); - #endif - - if( ret == 6 ) - { - ret = usb_bulk_read(pus->pudh, pus->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT); - if( ret < 0 ) - { - #ifdef DEBUG - printf("usb_bulk_read failed with error %d\n", ret); - #endif - return false; - } - - #ifdef DEBUG - printf(" RX: "); - print_hex(abtRx,ret); - #endif - } - - // When the answer should be ignored, just return a succesful result - if(pbtRx == NULL || pszRxLen == NULL) return true; - - // Only succeed when the result is at least 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable) - if(ret < 9) return false; - - // Remove the preceding and appending bytes 00 00 FF xx Fx .. .. .. xx 00 (x = variable) - *pszRxLen = ret - 7 - 2; - - // Get register: nuke extra byte (awful hack) - if ((abtRx[5]==0xd5) && (abtRx[6]==0x07) && (*pszRxLen==2)) { - // printf("Got %02x %02x, keep %02x\n", abtRx[7], abtRx[8], abtRx[8]); - *pszRxLen = (*pszRxLen) - 1; - memcpy( pbtRx, abtRx + 8, *pszRxLen); - return true; - } - - memcpy( pbtRx, abtRx + 7, *pszRxLen); - - return true; -} diff --git a/src/lib/drivers/pn533_usb.h b/src/lib/drivers/pn533_usb.h index 4103e9a..497cccd 100644 --- a/src/lib/drivers/pn533_usb.h +++ b/src/lib/drivers/pn533_usb.h @@ -24,16 +24,10 @@ #ifndef __NFC_DRIVER_PN533_USB_H__ #define __NFC_DRIVER_PN533_USB_H__ -#include - #define PN533_USB_DRIVER_NAME "PN533_USB" // Functions used by developer to handle connection to this device nfc_device_t* pn533_usb_connect(const nfc_device_desc_t* pndd); -void pn533_usb_disconnect(nfc_device_t* pnd); - -// Callback function used by libnfc to transmit commands to the PN53X chip -bool pn533_usb_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen); #endif // ! __NFC_DRIVER_PN533_USB_H__ diff --git a/src/lib/drivers/pn53x_usb.c b/src/lib/drivers/pn53x_usb.c new file mode 100644 index 0000000..3c9180a --- /dev/null +++ b/src/lib/drivers/pn53x_usb.c @@ -0,0 +1,295 @@ +/** + * Public platform independent Near Field Communication (NFC) library + * + * Copyright (C) 2009, Roel Verdult + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + * + * + * @file pn53x_usb.c + * @brief Driver common routines for PN53x chips using USB + */ + +/* +Thanks to d18c7db and Okko for example code +*/ + +#include +#include +#include +#include + +#include "../drivers.h" +#include "../bitutils.h" + +#include + +#define BUFFER_LENGTH 256 +#define USB_TIMEOUT 30000 + +// Find transfer endpoints for bulk transfers +void get_end_points(struct usb_device *dev, usb_spec_t* pus) +{ + uint32_t uiIndex; + uint32_t uiEndPoint; + struct usb_interface_descriptor* puid = dev->config->interface->altsetting; + + // 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out + for(uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++) + { + // Only accept bulk transfer endpoints (ignore interrupt endpoints) + if(puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK) continue; + + // Copy the endpoint to a local var, makes it more readable code + uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress; + + // Test if we dealing with a bulk IN endpoint + if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN) + { + #ifdef DEBUG + printf("Bulk endpoint in : 0x%02X\n", uiEndPoint); + #endif + pus->uiEndPointIn = uiEndPoint; + } + + // Test if we dealing with a bulk OUT endpoint + if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT) + { + #ifdef DEBUG + printf("Bulk endpoint in : 0x%02X\n", uiEndPoint); + #endif + pus->uiEndPointOut = uiEndPoint; + } + } +} + +nfc_device_t* pn53x_usb_connect(const nfc_device_desc_t* pndd, int idvendor, int idproduct, char * target_name, int target_chip) +{ + int ret; + static bool usb_inited= false; + + struct usb_bus *bus; + struct usb_device *dev; + nfc_device_t* pnd = NULL; + usb_spec_t* pus; + usb_spec_t us; + uint32_t uiDevIndex; + + us.uiEndPointIn = 0; + us.uiEndPointOut = 0; + us.pudh = NULL; + + DBG("Looking for %s device",target_name); + if(!usb_inited) + { + usb_init(); + usb_inited= true; + } + + if ((ret= usb_find_busses() < 0)) return NULL; + DBG("%d busses",ret); + if ((ret= usb_find_devices() < 0)) return NULL; + DBG("%d devices",ret); + + + // Initialize the device index we are seaching for + if( pndd == NULL ) { + uiDevIndex = 0; + } else { + uiDevIndex = pndd->uiBusIndex; + } + + for (bus = usb_get_busses(); bus; bus = bus->next) + { + for (dev = bus->devices; dev; dev = dev->next) + { + DBG("Checking device %04x:%04x",dev->descriptor.idVendor,dev->descriptor.idProduct); + if (idvendor==dev->descriptor.idVendor && idproduct==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 + uiDevIndex--; + continue; + } + if (dev->config->interface->altsetting->bNumEndpoints < 2) + { + // Nope, we maybe want the next one, let's try to find another + uiDevIndex--; + continue; + } + // Test if we are looking for this device according to the current index + if (uiDevIndex != 0) + { + // Nope, we maybe want the next one, let's try to find another + uiDevIndex--; + continue; + } + DBG("Found %s device", target_name); + + // Open the USB device + us.pudh = usb_open(dev); + + get_end_points(dev,&us); + if(usb_set_configuration(us.pudh,1) < 0) + { + DBG("%s", "Setting config failed"); + usb_close(us.pudh); + if (pndd == NULL) { + // don't return yet as there might be other readers on USB bus + continue; + } else { + // we failed to use the specified device + return NULL; + } + } + + if(usb_claim_interface(us.pudh,0) < 0) + { + DBG("%s", "Can't claim interface"); + usb_close(us.pudh); + if (pndd == NULL) { + // don't return yet as there might be other readers on USB bus + continue; + } else { + // we failed to use the specified device + return NULL; + } + } + // Allocate memory for the device info and specification, fill it and return the info + pus = malloc(sizeof(usb_spec_t)); + *pus = us; + pnd = malloc(sizeof(nfc_device_t)); + strcpy(pnd->acName,target_name); + pnd->nc = target_chip; + pnd->nds = (nfc_device_spec_t)pus; + pnd->bActive = true; + pnd->bCrc = true; + pnd->bPar = true; + pnd->ui8TxBits = 0; + return pnd; + } + } + } + return pnd; +} + +void pn53x_usb_disconnect(nfc_device_t* pnd) +{ + usb_spec_t* pus = (usb_spec_t*)pnd->nds; + int ret; + + DBG("%s","resetting USB"); + usb_reset(pus->pudh); + if((ret= usb_release_interface(pus->pudh,0)) < 0) + DBG("usb_release failed %i",ret); + if((ret= usb_close(pus->pudh)) < 0) + DBG("usb_close failed %i",ret); + free(pnd->nds); + free(pnd); +} + +bool pn53x_usb_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen) +{ + size_t uiPos = 0; + int ret = 0; + byte_t abtTx[BUFFER_LENGTH] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff" + byte_t abtRx[BUFFER_LENGTH]; + usb_spec_t* pus = (usb_spec_t*)nds; + + // Packet length = data length (len) + checksum (1) + end of stream marker (1) + abtTx[3] = szTxLen; + // Packet length checksum + abtTx[4] = BUFFER_LENGTH - abtTx[3]; + // Copy the PN53X command into the packet abtTx + memmove(abtTx+5,pbtTx,szTxLen); + + // Calculate data payload checksum + abtTx[szTxLen+5] = 0; + for(uiPos=0; uiPos < szTxLen; uiPos++) + { + abtTx[szTxLen+5] -= abtTx[uiPos+5]; + } + + // End of stream marker + abtTx[szTxLen+6] = 0; + + #ifdef DEBUG + printf(" TX: "); + print_hex(abtTx,szTxLen+7); + #endif + + ret = usb_bulk_write(pus->pudh, pus->uiEndPointOut, (char*)abtTx, szTxLen+7, USB_TIMEOUT); + if( ret < 0 ) + { + #ifdef DEBUG + printf("usb_bulk_write failed with error %d\n", ret); + #endif + return false; + } + + ret = usb_bulk_read(pus->pudh, pus->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT); + if( ret < 0 ) + { + #ifdef DEBUG + printf( "usb_bulk_read failed with error %d\n", ret); + #endif + return false; + } + + #ifdef DEBUG + printf(" RX: "); + print_hex(abtRx,ret); + #endif + + if( ret == 6 ) + { + ret = usb_bulk_read(pus->pudh, pus->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT); + if( ret < 0 ) + { + #ifdef DEBUG + printf("usb_bulk_read failed with error %d\n", ret); + #endif + return false; + } + + #ifdef DEBUG + printf(" RX: "); + print_hex(abtRx,ret); + #endif + } + + // When the answer should be ignored, just return a succesful result + if(pbtRx == NULL || pszRxLen == NULL) return true; + + // Only succeed when the result is at least 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable) + if(ret < 9) return false; + + // Remove the preceding and appending bytes 00 00 FF xx Fx .. .. .. xx 00 (x = variable) + *pszRxLen = ret - 7 - 2; + + // Get register: nuke extra byte (awful hack) + if ((abtRx[5]==0xd5) && (abtRx[6]==0x07) && (*pszRxLen==2)) { + // printf("Got %02x %02x, keep %02x\n", abtRx[7], abtRx[8], abtRx[8]); + *pszRxLen = (*pszRxLen) - 1; + memcpy( pbtRx, abtRx + 8, *pszRxLen); + return true; + } + + memcpy( pbtRx, abtRx + 7, *pszRxLen); + + return true; +} diff --git a/src/lib/drivers/pn53x_usb.h b/src/lib/drivers/pn53x_usb.h new file mode 100644 index 0000000..363ab8a --- /dev/null +++ b/src/lib/drivers/pn53x_usb.h @@ -0,0 +1,39 @@ +/** + * Public platform independent Near Field Communication (NFC) library + * + * Copyright (C) 2009, Roel Verdult + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + * + * + * @file pn53x_usb.h + * @brief + */ + +#include +#include +#include + +#include + +typedef struct { + usb_dev_handle* pudh; + uint32_t uiEndPointIn; + uint32_t uiEndPointOut; +} usb_spec_t; + +nfc_device_t* pn53x_usb_connect(const nfc_device_desc_t* pndd, int idvendor, int idproduct, char * target_name, int target_chip); +void get_end_points(struct usb_device *dev, usb_spec_t* pus); +void pn53x_usb_disconnect(nfc_device_t* pnd); +bool pn53x_usb_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen);