+// SPDX-License-Identifier: GPL-2.0-or-later
+
/***************************************************************************
* Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> *
* *
* Copyright (C) 2011 by Mauro Gamba <maurillo71@gmail.com> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 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 General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include <jtag/drivers/jtag_usb_common.h>
+
+#include <string.h>
+
+#include <helper/log.h>
+#include <jtag/adapter.h>
#include "libusb_helper.h"
-#include "log.h"
/*
* comment from libusb:
}
}
-static bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc,
+bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc,
const uint16_t vids[], const uint16_t pids[])
{
for (unsigned i = 0; vids[i]; i++) {
}
dev_bus = libusb_get_bus_number(device);
- return jtag_usb_location_equal(dev_bus, port_path, path_len);
+ return adapter_usb_location_equal(dev_bus, port_path, path_len);
}
#else /* HAVE_LIBUSB_GET_PORT_NUMBERS */
static bool jtag_libusb_location_equal(struct libusb_device *device)
char *alternate_serial = adapter_get_alternate_serial(device, dev_desc);
/* check possible failures */
- if (alternate_serial == NULL)
+ if (!alternate_serial)
return false;
/* then compare and free the alternate serial */
}
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
- const char *serial,
- struct libusb_device_handle **out,
+ const char *product, struct libusb_device_handle **out,
adapter_get_alternate_serial_fn adapter_get_alternate_serial)
{
- int cnt, idx, errCode;
+ int cnt, idx, err_code;
int retval = ERROR_FAIL;
bool serial_mismatch = false;
+ bool product_mismatch = false;
struct libusb_device_handle *libusb_handle = NULL;
+ const char *serial = adapter_get_required_serial();
if (libusb_init(&jtag_libusb_context) < 0)
return ERROR_FAIL;
if (!jtag_libusb_match_ids(&dev_desc, vids, pids))
continue;
- if (jtag_usb_get_location() && !jtag_libusb_location_equal(devs[idx]))
+ if (adapter_usb_get_location() && !jtag_libusb_location_equal(devs[idx]))
continue;
- errCode = libusb_open(devs[idx], &libusb_handle);
+ err_code = libusb_open(devs[idx], &libusb_handle);
- if (errCode) {
+ if (err_code) {
LOG_ERROR("libusb_open() failed with %s",
- libusb_error_name(errCode));
+ libusb_error_name(err_code));
continue;
}
/* Device must be open to use libusb_get_string_descriptor_ascii. */
- if (serial != NULL &&
+ if (serial &&
!jtag_libusb_match_serial(libusb_handle, &dev_desc, serial, adapter_get_alternate_serial)) {
serial_mismatch = true;
libusb_close(libusb_handle);
continue;
}
+ if (product &&
+ !string_descriptor_equal(libusb_handle, dev_desc.iProduct, product)) {
+ product_mismatch = true;
+ libusb_close(libusb_handle);
+ continue;
+ }
+
/* Success. */
*out = libusb_handle;
retval = ERROR_OK;
serial_mismatch = false;
+ product_mismatch = false;
break;
}
if (cnt >= 0)
if (serial_mismatch)
LOG_INFO("No device matches the serial string");
+ if (product_mismatch)
+ LOG_INFO("No device matches the product string");
+
if (retval != ERROR_OK)
libusb_exit(jtag_libusb_context);
libusb_exit(jtag_libusb_context);
}
-int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t requestType,
- uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes,
- uint16_t size, unsigned int timeout)
+int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t request_type,
+ uint8_t request, uint16_t value, uint16_t index, char *bytes,
+ uint16_t size, unsigned int timeout, int *transferred)
{
- int transferred = 0;
-
- transferred = libusb_control_transfer(dev, requestType, request, wValue, wIndex,
+ int retval = libusb_control_transfer(dev, request_type, request, value, index,
(unsigned char *)bytes, size, timeout);
- if (transferred < 0)
- transferred = 0;
+ if (retval < 0) {
+ LOG_ERROR("libusb_control_transfer error: %s", libusb_error_name(retval));
+ if (transferred)
+ *transferred = 0;
+ return jtag_libusb_error(retval);
+ }
- return transferred;
+ if (transferred)
+ *transferred = retval;
+
+ return ERROR_OK;
}
int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep, char *bytes,
int configuration)
{
struct libusb_device *udev = libusb_get_device(devh);
- int retCode = -99;
+ int retval = -99;
struct libusb_config_descriptor *config = NULL;
int current_config = -1;
- retCode = libusb_get_configuration(devh, ¤t_config);
- if (retCode != 0)
- return retCode;
+ retval = libusb_get_configuration(devh, ¤t_config);
+ if (retval != 0)
+ return retval;
- retCode = libusb_get_config_descriptor(udev, configuration, &config);
- if (retCode != 0 || config == NULL)
- return retCode;
+ retval = libusb_get_config_descriptor(udev, configuration, &config);
+ if (retval != 0 || !config)
+ return retval;
/* Only change the configuration if it is not already set to the
same one. Otherwise this issues a lightweight reset and hangs
LPC-Link2 with JLink firmware. */
if (current_config != config->bConfigurationValue)
- retCode = libusb_set_configuration(devh, config->bConfigurationValue);
+ retval = libusb_set_configuration(devh, config->bConfigurationValue);
libusb_free_config_descriptor(config);
- return retCode;
+ return retval;
}
int jtag_libusb_choose_interface(struct libusb_device_handle *devh,
{
return libusb_handle_events_completed(jtag_libusb_context, completed);
}
+
+static enum {
+ DEV_MEM_NOT_YET_DECIDED,
+ DEV_MEM_AVAILABLE,
+ DEV_MEM_FALLBACK_MALLOC
+} dev_mem_allocation;
+
+/* Older libusb does not implement following API calls - define stubs instead */
+#if !defined(LIBUSB_API_VERSION) || (LIBUSB_API_VERSION < 0x01000105)
+static uint8_t *libusb_dev_mem_alloc(libusb_device_handle *devh, size_t length)
+{
+ return NULL;
+}
+
+static int libusb_dev_mem_free(libusb_device_handle *devh,
+ uint8_t *buffer, size_t length)
+{
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+#endif
+
+uint8_t *oocd_libusb_dev_mem_alloc(libusb_device_handle *devh,
+ size_t length)
+{
+ uint8_t *buffer = NULL;
+ if (dev_mem_allocation != DEV_MEM_FALLBACK_MALLOC)
+ buffer = libusb_dev_mem_alloc(devh, length);
+
+ if (dev_mem_allocation == DEV_MEM_NOT_YET_DECIDED)
+ dev_mem_allocation = buffer ? DEV_MEM_AVAILABLE : DEV_MEM_FALLBACK_MALLOC;
+
+ if (dev_mem_allocation == DEV_MEM_FALLBACK_MALLOC)
+ buffer = malloc(length);
+
+ return buffer;
+}
+
+int oocd_libusb_dev_mem_free(libusb_device_handle *devh,
+ uint8_t *buffer, size_t length)
+{
+ if (!buffer)
+ return ERROR_OK;
+
+ switch (dev_mem_allocation) {
+ case DEV_MEM_AVAILABLE:
+ return jtag_libusb_error(libusb_dev_mem_free(devh, buffer, length));
+
+ case DEV_MEM_FALLBACK_MALLOC:
+ free(buffer);
+ return ERROR_OK;
+
+ case DEV_MEM_NOT_YET_DECIDED:
+ return ERROR_FAIL;
+ }
+ return ERROR_FAIL;
+}