pn53x_usb.c

Go to the documentation of this file.
00001 /*-
00002  * Public platform independent Near Field Communication (NFC) library
00003  * 
00004  * Copyright (C) 2009, Roel Verdult
00005  * Copyright (C) 2010, Romain Tartière, Romuald Conty
00006  * 
00007  * This program is free software: you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation, either version 3 of the License, or (at your
00010  * option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00015  * more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00019  */
00020 
00026 #ifdef HAVE_CONFIG_H
00027 #  include "config.h"
00028 #endif // HAVE_CONFIG_H
00029 
00030 /*
00031 Thanks to d18c7db and Okko for example code
00032 */
00033 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <usb.h>
00037 #include <string.h>
00038 
00039 #include "../drivers.h"
00040 #include "../chips/pn53x.h"
00041 
00042 #include <nfc/nfc.h>
00043 #include <nfc/nfc-messages.h>
00044 
00045 #define BUFFER_LENGTH 256
00046 #define USB_TIMEOUT   30000
00047 
00048 // Find transfer endpoints for bulk transfers
00049 void
00050 get_end_points (struct usb_device *dev, usb_spec_t * pus)
00051 {
00052   uint32_t uiIndex;
00053   uint32_t uiEndPoint;
00054   struct usb_interface_descriptor *puid = dev->config->interface->altsetting;
00055 
00056   // 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out
00057   for (uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++) {
00058     // Only accept bulk transfer endpoints (ignore interrupt endpoints)
00059     if (puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK)
00060       continue;
00061 
00062     // Copy the endpoint to a local var, makes it more readable code
00063     uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress;
00064 
00065     // Test if we dealing with a bulk IN endpoint
00066     if ((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN) {
00067       pus->uiEndPointIn = uiEndPoint;
00068     }
00069     // Test if we dealing with a bulk OUT endpoint
00070     if ((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT) {
00071       pus->uiEndPointOut = uiEndPoint;
00072     }
00073   }
00074 }
00075 
00076 bool
00077 pn53x_usb_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound,
00078                         usb_candidate_t candidates[], int num_candidates, char *target_name)
00079 {
00080   int     ret,
00081           i;
00082 
00083   struct usb_bus *bus;
00084   struct usb_device *dev;
00085   usb_dev_handle *udev;
00086   uint32_t uiBusIndex = 0;
00087   char    string[256];
00088 
00089   string[0] = '\0';
00090   usb_init ();
00091 
00092   // 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).
00093   if ((ret = usb_find_busses () < 0))
00094     return false;
00095   // usb_find_devices will find all of the devices on each bus. This should be called after usb_find_busses. Returns the number of changes since the previous call to this function (total of new device and devices removed).
00096   if ((ret = usb_find_devices () < 0))
00097     return false;
00098 
00099   *pszDeviceFound = 0;
00100 
00101   for (bus = usb_get_busses (); bus; bus = bus->next) {
00102     for (dev = bus->devices; dev; dev = dev->next, uiBusIndex++) {
00103       for (i = 0; i < num_candidates; ++i) {
00104         // DBG("Checking device %04x:%04x (%04x:%04x)",dev->descriptor.idVendor,dev->descriptor.idProduct,candidates[i].idVendor,candidates[i].idProduct);
00105         if (candidates[i].idVendor == dev->descriptor.idVendor && candidates[i].idProduct == dev->descriptor.idProduct) {
00106           // Make sure there are 2 endpoints available
00107           // with libusb-win32 we got some null pointers so be robust before looking at endpoints:
00108           if (dev->config == NULL || dev->config->interface == NULL || dev->config->interface->altsetting == NULL) {
00109             // Nope, we maybe want the next one, let's try to find another
00110             continue;
00111           }
00112           if (dev->config->interface->altsetting->bNumEndpoints < 2) {
00113             // Nope, we maybe want the next one, let's try to find another
00114             continue;
00115           }
00116           if (dev->descriptor.iManufacturer || dev->descriptor.iProduct) {
00117             udev = usb_open (dev);
00118             if (udev) {
00119               usb_get_string_simple (udev, dev->descriptor.iManufacturer, string, sizeof (string));
00120               if (strlen (string) > 0)
00121                 strcpy (string + strlen (string), " / ");
00122               usb_get_string_simple (udev, dev->descriptor.iProduct, string + strlen (string),
00123                                      sizeof (string) - strlen (string));
00124             }
00125             usb_close (udev);
00126           }
00127           if (strlen (string) == 0)
00128             strcpy (pnddDevices[*pszDeviceFound].acDevice, target_name);
00129           else
00130             strcpy (pnddDevices[*pszDeviceFound].acDevice, string);
00131           pnddDevices[*pszDeviceFound].pcDriver = target_name;
00132           pnddDevices[*pszDeviceFound].uiBusIndex = uiBusIndex;
00133           (*pszDeviceFound)++;
00134           // Test if we reach the maximum "wanted" devices
00135           if ((*pszDeviceFound) == szDevices) {
00136             return true;
00137           }
00138         }
00139       }
00140     }
00141   }
00142   if (*pszDeviceFound)
00143     return true;
00144   return false;
00145 }
00146 
00147 nfc_device_t *
00148 pn53x_usb_connect (const nfc_device_desc_t * pndd, const char *target_name, int target_chip)
00149 {
00150   nfc_device_t *pnd = NULL;
00151   usb_spec_t *pus;
00152   usb_spec_t us;
00153   struct usb_bus *bus;
00154   struct usb_device *dev;
00155   uint32_t uiBusIndex;
00156 
00157   us.uiEndPointIn = 0;
00158   us.uiEndPointOut = 0;
00159   us.pudh = NULL;
00160 
00161   DBG ("Attempt to connect to %s device", target_name);
00162   usb_init ();
00163 
00164   uiBusIndex = pndd->uiBusIndex;
00165 
00166   for (bus = usb_get_busses (); bus; bus = bus->next) {
00167     for (dev = bus->devices; dev; dev = dev->next, uiBusIndex--) {
00168       // DBG("Checking device %04x:%04x",dev->descriptor.idVendor,dev->descriptor.idProduct);
00169       if (uiBusIndex == 0) {
00170         // Open the USB device
00171         us.pudh = usb_open (dev);
00172 
00173         get_end_points (dev, &us);
00174         if (usb_set_configuration (us.pudh, 1) < 0) {
00175           DBG ("%s", "Setting config failed");
00176           usb_close (us.pudh);
00177           // we failed to use the specified device
00178           return NULL;
00179         }
00180 
00181         if (usb_claim_interface (us.pudh, 0) < 0) {
00182           DBG ("%s", "Can't claim interface");
00183           usb_close (us.pudh);
00184           // we failed to use the specified device
00185           return NULL;
00186         }
00187         // Allocate memory for the device info and specification, fill it and return the info
00188         pus = malloc (sizeof (usb_spec_t));
00189         *pus = us;
00190         pnd = malloc (sizeof (nfc_device_t));
00191         strcpy (pnd->acName, target_name);
00192         pnd->nc = target_chip;
00193         pnd->nds = (nfc_device_spec_t) pus;
00194         pnd->bActive = true;
00195         pnd->bCrc = true;
00196         pnd->bPar = true;
00197         pnd->ui8TxBits = 0;
00198         return pnd;
00199       }
00200     }
00201   }
00202   // We ran out of devices before the index required
00203   DBG ("%s", "Device index not found!");
00204   return NULL;
00205 }
00206 
00207 void
00208 pn53x_usb_disconnect (nfc_device_t * pnd)
00209 {
00210   usb_spec_t *pus = (usb_spec_t *) pnd->nds;
00211   int     ret;
00212 
00213   if ((ret = usb_release_interface (pus->pudh, 0)) < 0) {
00214     ERR ("usb_release_interface failed (%i)", ret);
00215   }
00216 
00217   if ((ret = usb_close (pus->pudh)) < 0) {
00218     ERR ("usb_close failed (%i)", ret);
00219   }
00220 /*  
00221   if((ret = usb_reset(pus->pudh)) < 0) {
00222     ERR("usb_reset failed (%i, if errno: %s)",ret, strerror(-ret));
00223   }
00224 */
00225   free (pnd->nds);
00226   free (pnd);
00227 }
00228 
00229 bool
00230 pn53x_usb_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTxLen, byte_t * pbtRx, size_t * pszRxLen)
00231 {
00232   size_t  uiPos = 0;
00233   int     ret = 0;
00234   byte_t  abtTx[BUFFER_LENGTH] = { 0x00, 0x00, 0xff };  // Every packet must start with "00 00 ff"
00235   byte_t  abtRx[BUFFER_LENGTH];
00236   usb_spec_t *pus = (usb_spec_t *) pnd->nds;
00237   // TODO: Move this one level up for libnfc-1.6
00238   uint8_t ack_frame[] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
00239 
00240   // Packet length = data length (len) + checksum (1) + end of stream marker (1)
00241   abtTx[3] = szTxLen;
00242   // Packet length checksum 
00243   abtTx[4] = 0x0100 - abtTx[3];
00244   // Copy the PN53X command into the packet abtTx
00245   memmove (abtTx + 5, pbtTx, szTxLen);
00246 
00247   // Calculate data payload checksum
00248   abtTx[szTxLen + 5] = 0;
00249   for (uiPos = 0; uiPos < szTxLen; uiPos++) {
00250     abtTx[szTxLen + 5] -= abtTx[uiPos + 5];
00251   }
00252 
00253   // End of stream marker
00254   abtTx[szTxLen + 6] = 0;
00255 
00256 #ifdef DEBUG
00257   PRINT_HEX ("TX", abtTx, szTxLen + 7);
00258 #endif
00259 
00260   ret = usb_bulk_write (pus->pudh, pus->uiEndPointOut, (char *) abtTx, szTxLen + 7, USB_TIMEOUT);
00261   if (ret < 0) {
00262     DBG ("usb_bulk_write failed with error %d", ret);
00263     pnd->iLastError = DEIO;
00264     return false;
00265   }
00266 
00267   ret = usb_bulk_read (pus->pudh, pus->uiEndPointIn, (char *) abtRx, BUFFER_LENGTH, USB_TIMEOUT);
00268   if (ret < 0) {
00269     DBG ("usb_bulk_read failed with error %d", ret);
00270     pnd->iLastError = DEIO;
00271     return false;
00272   }
00273 #ifdef DEBUG
00274   PRINT_HEX ("RX", abtRx, ret);
00275 #endif
00276 
00277   if (!pn53x_transceive_check_ack_frame_callback (pnd, abtRx, ret))
00278     return false;
00279 
00280   ret = usb_bulk_read (pus->pudh, pus->uiEndPointIn, (char *) abtRx, BUFFER_LENGTH, USB_TIMEOUT);
00281   if (ret < 0) {
00282     DBG ("usb_bulk_read failed with error %d", ret);
00283     pnd->iLastError = DEIO;
00284     return false;
00285   }
00286 #ifdef DEBUG
00287   PRINT_HEX ("RX", abtRx, ret);
00288 #endif
00289 
00290 #ifdef DEBUG
00291   PRINT_HEX ("TX", ack_frame, 6);
00292 #endif
00293   usb_bulk_write (pus->pudh, pus->uiEndPointOut, (char *) ack_frame, 6, USB_TIMEOUT);
00294 
00295   if (!pn53x_transceive_check_error_frame_callback (pnd, abtRx, ret))
00296     return false;
00297 
00298   // When the answer should be ignored, just return a succesful result
00299   if (pbtRx == NULL || pszRxLen == NULL)
00300     return true;
00301 
00302   // Only succeed when the result is at least 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable)
00303   if (ret < 9) {
00304     DBG ("%s", "No data");
00305     pnd->iLastError = DEINVAL;
00306     return false;
00307   }
00308   // Remove the preceding and appending bytes 00 00 FF xx Fx .. .. .. xx 00 (x = variable)
00309   *pszRxLen = ret - 7 - 2;
00310 
00311   // Get register: nuke extra byte (awful hack)
00312   if ((abtRx[5] == 0xd5) && (abtRx[6] == 0x07) && (*pszRxLen == 2)) {
00313     // DBG("awful hack: abtRx[7]=%02x, abtRx[8]=%02x, we only keep abtRx[8]=%02x", abtRx[7], abtRx[8], abtRx[8]);
00314     *pszRxLen = (*pszRxLen) - 1;
00315     memcpy (pbtRx, abtRx + 8, *pszRxLen);
00316     return true;
00317   }
00318 
00319   memcpy (pbtRx, abtRx + 7, *pszRxLen);
00320 
00321   return true;
00322 }