src/dfu-programmer/src/dfu.c
/*
* dfu-programmer
*
* $Id$
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#ifdef HAVE_LIBUSB_1_0
#include <libusb.h>
#else
#include <usb.h>
#endif
#include <errno.h>
#include "dfu.h"
#include "util.h"
#include "dfu-bool.h"
/* DFU commands */
#define DFU_DETACH 0
#define DFU_DNLOAD 1
#define DFU_UPLOAD 2
#define DFU_GETSTATUS 3
#define DFU_CLRSTATUS 4
#define DFU_GETSTATE 5
#define DFU_ABORT 6
#define USB_CLASS_APP_SPECIFIC 0xfe
#define DFU_SUBCLASS 0x01
/* Wait for 20 seconds before a timeout since erasing/flashing can take some time.
* The longest erase cycle is for the AT32UC3A0512-TA automotive part,
* which needs a timeout of at least 19 seconds to erase the whole flash. */
#define DFU_TIMEOUT 20000
/* Time (in ms) for the device to wait for the usb reset after being told to detach
* before the giving up going into dfu mode. */
#define DFU_DETACH_TIMEOUT 1000
#define DFU_DEBUG_THRESHOLD 100
#define DFU_TRACE_THRESHOLD 200
#define DFU_MESSAGE_DEBUG_THRESHOLD 300
#define DEBUG(...) dfu_debug( __FILE__, __FUNCTION__, __LINE__, \
DFU_DEBUG_THRESHOLD, __VA_ARGS__ )
#define TRACE(...) dfu_debug( __FILE__, __FUNCTION__, __LINE__, \
DFU_TRACE_THRESHOLD, __VA_ARGS__ )
#define MSG_DEBUG(...) dfu_debug( __FILE__, __FUNCTION__, __LINE__, \
DFU_MESSAGE_DEBUG_THRESHOLD, __VA_ARGS__ )
static uint16_t transaction = 0;
// ________ P R O T O T Y P E S _______________________________
#ifdef HAVE_LIBUSB_1_0
static int32_t dfu_find_interface( struct libusb_device *device,
const dfu_bool honor_interfaceclass,
const uint8_t bNumConfigurations);
#else
static int32_t dfu_find_interface( const struct usb_device *device,
const dfu_bool honor_interfaceclass );
#endif
/* Used to find the dfu interface for a device if there is one.
*
* device - the device to search
* honor_interfaceclass - if the actual interface class information
* should be checked, or ignored (bug in device DFU code)
*
* returns the interface number if found, < 0 otherwise
*/
static int32_t dfu_make_idle( dfu_device_t *device, const dfu_bool initial_abort );
/* Gets the device into the dfuIDLE state if possible.
*
* device - the dfu device to commmunicate with
*
* returns 0 on success, 1 if device was reset, error otherwise
*/
static int32_t dfu_transfer_out( dfu_device_t *device,
uint8_t request,
const int32_t value,
uint8_t* data,
const size_t length );
static int32_t dfu_transfer_in( dfu_device_t *device,
uint8_t request,
const int32_t value,
uint8_t* data,
const size_t length );
static void dfu_msg_response_output( const char *function, const int32_t result );
/* Used to output the response from our USB request in a human reable
* form.
*
* function - the calling function to output on behalf of
* result - the result to interpret
*/
// ________ F U N C T I O N S _______________________________
void dfu_set_transaction_num( uint16_t newnum ) {
TRACE( "%s( %u )\n", __FUNCTION__, newnum );
transaction = newnum;
DEBUG("wValue set to %d\n", transaction);
}
uint16_t dfu_get_transaction_num( void ) {
TRACE( "%s( %u )\n", __FUNCTION__ );
return transaction;
}
int32_t dfu_detach( dfu_device_t *device, const int32_t timeout ) {
int32_t result;
TRACE( "%s( %p, %d )\n", __FUNCTION__, device, timeout );
if( (NULL == device) || (NULL == device->handle) || (timeout < 0) ) {
DEBUG( "Invalid parameter\n" );
return -1;
}
result = dfu_transfer_out( device, DFU_DETACH, timeout, NULL, 0 );
dfu_msg_response_output( __FUNCTION__, result );
return result;
}
int32_t dfu_download( dfu_device_t *device,
const size_t length,
uint8_t* data ) {
int32_t result;
TRACE( "%s( %p, %u, %p )\n", __FUNCTION__, device, length, data );
/* Sanity checks */
if( (NULL == device) || (NULL == device->handle) ) {
DEBUG( "Invalid parameter\n" );
return -1;
}
if( (0 != length) && (NULL == data) ) {
DEBUG( "data was NULL, but length != 0\n" );
return -2;
}
if( (0 == length) && (NULL != data) ) {
DEBUG( "data was not NULL, but length == 0\n" );
return -3;
}
{
size_t i;
for( i = 0; i < length; i++ ) {
MSG_DEBUG( "Message: m[%u] = 0x%02x\n", i, data[i] );
}
}
result = dfu_transfer_out( device, DFU_DNLOAD, transaction++, data, length );
dfu_msg_response_output( __FUNCTION__, result );
return result;
}
int32_t dfu_upload( dfu_device_t *device, const size_t length, uint8_t* data ) {
int32_t result;
TRACE( "%s( %p, %u, %p )\n", __FUNCTION__, device, length, data );
/* Sanity checks */
if( (NULL == device) || (NULL == device->handle) ) {
DEBUG( "Invalid parameter\n" );
return -1;
}
if( (0 == length) || (NULL == data) ) {
DEBUG( "data was NULL, or length is 0\n" );
return -2;
}
result = dfu_transfer_in( device, DFU_UPLOAD, transaction++, data, length );
dfu_msg_response_output( __FUNCTION__, result );
return result;
}
int32_t dfu_get_status( dfu_device_t *device, dfu_status_t *status ) {
uint8_t buffer[6];
int32_t result;
TRACE( "%s( %p, %p )\n", __FUNCTION__, device, status );
if( (NULL == device) || (NULL == device->handle) ) {
DEBUG( "Invalid parameter\n" );
return -1;
}
/* Initialize the status data structure */
status->bStatus = DFU_STATUS_ERROR_UNKNOWN;
status->bwPollTimeout = 0;
status->bState = STATE_DFU_ERROR;
status->iString = 0;
result = dfu_transfer_in( device, DFU_GETSTATUS, 0, buffer, sizeof(buffer) );
dfu_msg_response_output( __FUNCTION__, result );
if( 6 == result ) {
status->bStatus = buffer[0];
status->bwPollTimeout = ((0xff & buffer[3]) << 16) |
((0xff & buffer[2]) << 8) |
(0xff & buffer[1]);
status->bState = buffer[4];
status->iString = buffer[5];
DEBUG( "==============================\n" );
DEBUG( "status->bStatus: %s (0x%02x)\n",
dfu_status_to_string(status->bStatus), status->bStatus );
DEBUG( "status->bwPollTimeout: 0x%04x ms\n", status->bwPollTimeout );
DEBUG( "status->bState: %s (0x%02x)\n",
dfu_state_to_string(status->bState), status->bState );
DEBUG( "status->iString: 0x%02x\n", status->iString );
DEBUG( "------------------------------\n" );
} else {
if( 0 < result ) {
/* There was an error, we didn't get the entire message. */
DEBUG( "result: %d\n", result );
return -2;
}
}
return 0;
}
int32_t dfu_clear_status( dfu_device_t *device ) {
int32_t result;
TRACE( "%s( %p )\n", __FUNCTION__, device );
if( (NULL == device) || (NULL == device->handle) ) {
DEBUG( "Invalid parameter\n" );
return -1;
}
result = dfu_transfer_out( device, DFU_CLRSTATUS, 0, NULL, 0 );
dfu_msg_response_output( __FUNCTION__, result );
return result;
}
int32_t dfu_get_state( dfu_device_t *device ) {
int32_t result;
uint8_t buffer[1];
TRACE( "%s( %p )\n", __FUNCTION__, device );
if( (NULL == device) || (NULL == device->handle) ) {
DEBUG( "Invalid parameter\n" );
return -1;
}
result = dfu_transfer_in( device, DFU_GETSTATE, 0, buffer, sizeof(buffer) );
dfu_msg_response_output( __FUNCTION__, result );
/* Return the error if there is one. */
if( result < 1 ) {
return result;
}
/* Return the state. */
return buffer[0];
}
int32_t dfu_abort( dfu_device_t *device ) {
int32_t result;
TRACE( "%s( %p )\n", __FUNCTION__, device );
if( (NULL == device) || (NULL == device->handle) ) {
DEBUG( "Invalid parameter\n" );
return -1;
}
result = dfu_transfer_out( device, DFU_ABORT, 0, NULL, 0 );
dfu_msg_response_output( __FUNCTION__, result );
return result;
}
#ifdef HAVE_LIBUSB_1_0
struct libusb_device *dfu_device_init( const uint32_t vendor,
const uint32_t product,
const uint32_t bus_number,
const uint32_t device_address,
dfu_device_t *dfu_device,
const dfu_bool initial_abort,
const dfu_bool honor_interfaceclass ) {
libusb_device **list;
size_t i,devicecount;
extern libusb_context *usbcontext;
int32_t retries = 4;
TRACE( "%s( %u, %u, %p, %s, %s )\n", __FUNCTION__, vendor, product,
dfu_device, ((true == initial_abort) ? "true" : "false"),
((true == honor_interfaceclass) ? "true" : "false") );
DEBUG( "%s(%08x, %08x)\n",__FUNCTION__, vendor, product );
retry:
devicecount = libusb_get_device_list( usbcontext, &list );
for( i = 0; i < devicecount; i++ ) {
libusb_device *device = list[i];
struct libusb_device_descriptor descriptor;
if( libusb_get_device_descriptor(device, &descriptor) ) {
DEBUG( "Failed in libusb_get_device_descriptor\n" );
break;
}
DEBUG( "%2d: 0x%04x, 0x%04x\n", (int) i,
descriptor.idVendor, descriptor.idProduct );
if( (vendor == descriptor.idVendor) &&
(product == descriptor.idProduct) &&
((bus_number == 0)
|| ((libusb_get_bus_number(device) == bus_number) &&
(libusb_get_device_address(device) == device_address))) )
{
int32_t tmp;
DEBUG( "found device at USB:%d,%d\n", libusb_get_bus_number(device), libusb_get_device_address(device) );
/* We found a device that looks like it matches...
* let's try to find the DFU interface, open the device
* and claim it. */
tmp = dfu_find_interface( device, honor_interfaceclass,
descriptor.bNumConfigurations );
if( 0 <= tmp ) { /* The interface is valid. */
dfu_device->interface = tmp;
if( 0 == libusb_open(device, &dfu_device->handle) ) {
DEBUG( "opened interface %d...\n", tmp );
if( 0 == libusb_set_configuration(dfu_device->handle, 1) ) {
DEBUG( "set configuration %d...\n", 1 );
if( 0 == libusb_claim_interface(dfu_device->handle, dfu_device->interface) )
{
DEBUG( "claimed interface %d...\n", dfu_device->interface );
switch( dfu_make_idle(dfu_device, initial_abort) )
{
case 0:
libusb_free_device_list( list, 1 );
return device;
case 1:
retries--;
libusb_free_device_list( list, 1 );
goto retry;
}
DEBUG( "Failed to put the device in dfuIDLE mode.\n" );
libusb_release_interface( dfu_device->handle, dfu_device->interface );
retries = 4;
} else {
DEBUG( "Failed to claim the DFU interface.\n" );
}
} else {
DEBUG( "Failed to set configuration.\n" );
}
libusb_close(dfu_device->handle);
}
}
}
}
libusb_free_device_list( list, 1 );
dfu_device->handle = NULL;
dfu_device->interface = 0;
return NULL;
}
#else
struct usb_device *dfu_device_init( const uint32_t vendor,
const uint32_t product,
const uint32_t bus_number,
const uint32_t device_address,
dfu_device_t *dfu_device,
const dfu_bool initial_abort,
const dfu_bool honor_interfaceclass ) {
struct usb_bus *usb_bus;
struct usb_device *device;
int32_t retries = 4;
TRACE( "%s( %u, %u, %p, %s, %s )\n", __FUNCTION__, vendor, product,
dfu_device, ((true == initial_abort) ? "true" : "false"),
((true == honor_interfaceclass) ? "true" : "false") );
retry:
if( 0 < retries ) {
usb_find_busses();
usb_find_devices();
/* Walk the tree and find our device. */
for( usb_bus = usb_get_busses(); NULL != usb_bus; usb_bus = usb_bus->next ) {
for( device = usb_bus->devices; NULL != device; device = device->next) {
if( (vendor == device->descriptor.idVendor)
&& (product == device->descriptor.idProduct)
&& ((bus_number == 0)
|| (device->devnum == device_address
&& (usb_bus->location >> 24) == bus_number)))
{
int32_t tmp;
DEBUG( "found device at USB:%d,%d\n", device->devnum, (usb_bus->location >> 24) );
/* We found a device that looks like it matches...
* let's try to find the DFU interface, open the device
* and claim it. */
tmp = dfu_find_interface( device, honor_interfaceclass );
if( 0 <= tmp ) {
/* The interface is valid. */
dfu_device->interface = tmp;
dfu_device->handle = usb_open( device );
if( NULL != dfu_device->handle ) {
if( 0 == usb_set_configuration(dfu_device->handle, 1) ) {
if( 0 == usb_claim_interface(dfu_device->handle, dfu_device->interface) ) {
switch( dfu_make_idle(dfu_device, initial_abort) )
{
case 0:
return device;
case 1:
retries--;
goto retry;
}
DEBUG( "Failed to put the device in dfuIDLE mode.\n" );
usb_release_interface( dfu_device->handle, dfu_device->interface );
usb_close( dfu_device->handle );
retries = 4;
} else {
DEBUG( "Failed to claim the DFU interface.\n" );
usb_close( dfu_device->handle );
}
} else {
DEBUG( "Failed to set configuration.\n");
usb_close( dfu_device->handle );
}
} else {
DEBUG( "Failed to open device.\n" );
}
} else {
DEBUG( "Failed to find the DFU interface.\n" );
}
}
}
}
}
dfu_device->handle = NULL;
dfu_device->interface = 0;
return NULL;
}
#endif
char* dfu_state_to_string( const int32_t state ) {
char *message = "unknown state";
switch( state ) {
case STATE_APP_IDLE:
message = "appIDLE";
break;
case STATE_APP_DETACH:
message = "appDETACH";
break;
case STATE_DFU_IDLE:
message = "dfuIDLE";
break;
case STATE_DFU_DOWNLOAD_SYNC:
message = "dfuDNLOAD-SYNC";
break;
case STATE_DFU_DOWNLOAD_BUSY:
message = "dfuDNBUSY";
break;
case STATE_DFU_DOWNLOAD_IDLE:
message = "dfuDNLOAD-IDLE";
break;
case STATE_DFU_MANIFEST_SYNC:
message = "dfuMANIFEST-SYNC";
break;
case STATE_DFU_MANIFEST:
message = "dfuMANIFEST";
break;
case STATE_DFU_MANIFEST_WAIT_RESET:
message = "dfuMANIFEST-WAIT-RESET";
break;
case STATE_DFU_UPLOAD_IDLE:
message = "dfuUPLOAD-IDLE";
break;
case STATE_DFU_ERROR:
message = "dfuERROR";
break;
}
return message;
}
char* dfu_status_to_string( const int32_t status ) {
char *message = "unknown status";
switch( status ) {
case DFU_STATUS_OK:
message = "OK";
break;
case DFU_STATUS_ERROR_TARGET:
message = "errTARGET";
break;
case DFU_STATUS_ERROR_FILE:
message = "errFILE";
break;
case DFU_STATUS_ERROR_WRITE:
message = "errWRITE";
break;
case DFU_STATUS_ERROR_ERASE:
message = "errERASE";
break;
case DFU_STATUS_ERROR_CHECK_ERASED:
message = "errCHECK_ERASED";
break;
case DFU_STATUS_ERROR_PROG:
message = "errPROG";
break;
case DFU_STATUS_ERROR_VERIFY:
message = "errVERIFY";
break;
case DFU_STATUS_ERROR_ADDRESS:
message = "errADDRESS";
break;
case DFU_STATUS_ERROR_NOTDONE:
message = "errNOTDONE";
break;
case DFU_STATUS_ERROR_FIRMWARE:
message = "errFIRMWARE";
break;
case DFU_STATUS_ERROR_VENDOR:
message = "errVENDOR";
break;
case DFU_STATUS_ERROR_USBR:
message = "errUSBR";
break;
case DFU_STATUS_ERROR_POR:
message = "errPOR";
break;
case DFU_STATUS_ERROR_UNKNOWN:
message = "errUNKNOWN";
break;
case DFU_STATUS_ERROR_STALLEDPKT:
message = "errSTALLEDPKT";
break;
}
return message;
}
#ifdef HAVE_LIBUSB_1_0
static int32_t dfu_find_interface( struct libusb_device *device,
const dfu_bool honor_interfaceclass,
const uint8_t bNumConfigurations) {
int32_t c,i,s;
TRACE( "%s()\n", __FUNCTION__ );
/* Loop through all of the configurations */
for( c = 0; c < bNumConfigurations; c++ ) {
struct libusb_config_descriptor *config;
if( libusb_get_config_descriptor(device, c, &config) ) {
DEBUG( "can't get_config_descriptor: %d\n", c );
return -1;
}
DEBUG( "config %d: maxpower=%d*2 mA\n", c, config->MaxPower );
/* Loop through all of the interfaces */
for( i = 0; i < config->bNumInterfaces; i++ ) {
struct libusb_interface interface;
interface = config->interface[i];
DEBUG( "interface %d\n", i );
/* Loop through all of the settings */
for( s = 0; s < interface.num_altsetting; s++ ) {
struct libusb_interface_descriptor setting;
setting = interface.altsetting[s];
DEBUG( "setting %d: class:%d, subclass %d, protocol:%d\n", s,
setting.bInterfaceClass, setting.bInterfaceSubClass,
setting.bInterfaceProtocol );
if( honor_interfaceclass ) {
/* Check if the interface is a DFU interface */
if( (USB_CLASS_APP_SPECIFIC == setting.bInterfaceClass)
&& (DFU_SUBCLASS == setting.bInterfaceSubClass) )
{
DEBUG( "Found DFU Interface: %d\n", setting.bInterfaceNumber );
return setting.bInterfaceNumber;
}
} else {
/* If there is a bug in the DFU firmware, return the first
* found interface. */
DEBUG( "Found DFU Interface: %d\n", setting.bInterfaceNumber );
return setting.bInterfaceNumber;
}
}
}
libusb_free_config_descriptor( config );
}
return -1;
}
#else
static int32_t dfu_find_interface( const struct usb_device *device,
const dfu_bool honor_interfaceclass ) {
int32_t c, i;
struct usb_config_descriptor *config;
struct usb_interface_descriptor *interface;
/* Loop through all of the configurations */
for( c = 0; c < device->descriptor.bNumConfigurations; c++ ) {
config = &(device->config[c]);
/* Loop through all of the interfaces */
for( i = 0; i < config->interface->num_altsetting; i++) {
interface = &(config->interface->altsetting[i]);
if( true == honor_interfaceclass ) {
/* Check if the interface is a DFU interface */
if( (USB_CLASS_APP_SPECIFIC == interface->bInterfaceClass)
&& (DFU_SUBCLASS == interface->bInterfaceSubClass) )
{
DEBUG( "Found DFU Inteface: %d\n", interface->bInterfaceNumber );
return interface->bInterfaceNumber;
}
} else {
/* If there is a bug in the DFU firmware, return the first
* found interface. */
DEBUG( "Found DFU Inteface: %d\n", interface->bInterfaceNumber );
return interface->bInterfaceNumber;
}
}
}
return -1;
}
#endif
static int32_t dfu_make_idle( dfu_device_t *device,
const dfu_bool initial_abort ) {
dfu_status_t status;
int32_t retries = 4;
if( true == initial_abort ) {
dfu_abort( device );
}
while( 0 < retries ) {
if( 0 != dfu_get_status(device, &status) ) {
dfu_clear_status( device );
continue;
}
DEBUG( "State: %s (%d)\n", dfu_state_to_string(status.bState), status.bState );
switch( status.bState ) {
case STATE_DFU_IDLE:
if( DFU_STATUS_OK == status.bStatus ) {
return 0;
}
/* We need the device to have the DFU_STATUS_OK status. */
dfu_clear_status( device );
break;
case STATE_DFU_DOWNLOAD_SYNC: /* abort -> idle */
case STATE_DFU_DOWNLOAD_IDLE: /* abort -> idle */
case STATE_DFU_MANIFEST_SYNC: /* abort -> idle */
case STATE_DFU_UPLOAD_IDLE: /* abort -> idle */
case STATE_DFU_DOWNLOAD_BUSY: /* abort -> error */
case STATE_DFU_MANIFEST: /* abort -> error */
dfu_abort( device );
break;
case STATE_DFU_ERROR:
dfu_clear_status( device );
break;
case STATE_APP_IDLE:
dfu_detach( device, DFU_DETACH_TIMEOUT );
break;
case STATE_APP_DETACH:
case STATE_DFU_MANIFEST_WAIT_RESET:
DEBUG( "Resetting the device\n" );
#ifdef HAVE_LIBUSB_1_0
libusb_reset_device( device->handle );
#else
usb_reset( device->handle );
#endif
return 1;
}
retries--;
}
DEBUG( "Not able to transition the device into the dfuIDLE state.\n" );
return -2;
}
static int32_t dfu_transfer_out( dfu_device_t *device,
uint8_t request,
const int32_t value,
uint8_t* data,
const size_t length ) {
#ifdef HAVE_LIBUSB_1_0
return libusb_control_transfer( device->handle,
/* bmRequestType */ LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
/* bRequest */ request,
/* wValue */ value,
/* wIndex */ device->interface,
/* Data */ data,
/* wLength */ length,
DFU_TIMEOUT );
#else
return usb_control_msg( device->handle,
/* bmRequestType */ USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
/* bRequest */ request,
/* wValue */ value,
/* wIndex */ device->interface,
/* Data */ (char*) data,
/* wLength */ length,
DFU_TIMEOUT );
#endif
}
static int32_t dfu_transfer_in( dfu_device_t *device,
uint8_t request,
const int32_t value,
uint8_t* data,
const size_t length ) {
#ifdef HAVE_LIBUSB_1_0
return libusb_control_transfer( device->handle,
/* bmRequestType */ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
/* bRequest */ request,
/* wValue */ value,
/* wIndex */ device->interface,
/* Data */ data,
/* wLength */ length,
DFU_TIMEOUT );
#else
return usb_control_msg( device->handle,
/* bmRequestType */ USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
/* bRequest */ request,
/* wValue */ value,
/* wIndex */ device->interface,
/* Data */ (char*) data,
/* wLength */ length,
DFU_TIMEOUT );
#endif
}
static void dfu_msg_response_output( const char *function,
const int32_t result ) {
char *msg = NULL;
if( 0 <= result ) {
msg = "No error.";
} else {
switch( result ) {
#ifdef HAVE_LIBUSB_1_0
case LIBUSB_ERROR_IO :
msg = "LIBUSB_ERROR_IO: Input/output error.";
break;
case LIBUSB_ERROR_INVALID_PARAM :
msg = "LIBUSB_ERROR_INVALID_PARAM: Invalid parameter.";
break;
case LIBUSB_ERROR_ACCESS :
msg = "LIBUSB_ERROR_ACCESS: Access denied (insufficient permissions)";
break;
case LIBUSB_ERROR_NO_DEVICE :
msg = "LIBUSB_ERROR_NO_DEVICE: No such device (it may have been disconnected)";
break;
case LIBUSB_ERROR_NOT_FOUND :
msg = "LIBUSB_ERROR_NOT_FOUND: Entity not found.";
break;
case LIBUSB_ERROR_BUSY :
msg = "LIBUSB_ERROR_BUSY: Resource busy.";
break;
case LIBUSB_ERROR_TIMEOUT :
msg = "LIBUSB_ERROR_TIMEOUT: Operation timed out.";
break;
case LIBUSB_ERROR_OVERFLOW :
msg = "LIBUSB_ERROR_OVERFLOW: Overflow.";
break;
case LIBUSB_ERROR_PIPE :
msg = "LIBUSB_ERROR_PIPE: Pipe error.";
break;
case LIBUSB_ERROR_INTERRUPTED :
msg = "LIBUSB_ERROR_INTERRUPTED: System call interrupted (perhaps due to signal)";
break;
case LIBUSB_ERROR_NO_MEM :
msg = "LIBUSB_ERROR_NO_MEM: Insufficient memory.";
break;
case LIBUSB_ERROR_NOT_SUPPORTED :
msg = "LIBUSB_ERROR_NOT_SUPPORTED: Operation not supported or unimplemented on this platform.";
break;
case LIBUSB_ERROR_OTHER :
msg = "LIBUSB_ERROR_OTHER: Other error.";
break;
#else /* HAVE_LIBUSB_1_0 */
case -ENOENT:
msg = "-ENOENT: URB was canceled by unlink_urb";
break;
#ifdef EINPROGRESS
case -EINPROGRESS:
msg = "-EINPROGRESS: URB still pending, no results yet "
"(actually no error until now)";
break;
#endif
#ifdef EPROTO
case -EPROTO:
msg = "-EPROTO: a) Bitstuff error or b) Unknown USB error";
break;
#endif
case -EILSEQ:
msg = "-EILSEQ: CRC mismatch";
break;
case -EPIPE:
msg = "-EPIPE: a) Babble detect or b) Endpoint stalled";
break;
#ifdef ETIMEDOUT
case -ETIMEDOUT:
msg = "-ETIMEDOUT: Transfer timed out, NAK";
break;
#endif
case -ENODEV:
msg = "-ENODEV: Device was removed";
break;
case -EIO:
msg = "-EIO: USB I/O error";
break;
#ifdef EREMOTEIO
case -EREMOTEIO:
msg = "-EREMOTEIO: Short packet detected";
break;
#endif
case -EXDEV:
msg = "-EXDEV: ISO transfer only partially completed look at "
"individual frame status for details";
break;
case -EINVAL:
msg = "-EINVAL: ISO madness, if this happens: Log off and go home";
break;
#endif /* HAVE_LIBUSB_1_0 */
default:
msg = "Unknown error";
break;
}
DEBUG( "%s ERR: %s 0x%08x (%d)\n", function, msg, result, result );
}
}
#ifdef malloc
#undef malloc
void* rpl_malloc( size_t n ) {
if( 0 == n ) {
n = 1;
}
return malloc( n );
}
#endif