This commit is contained in:
Triss 2022-01-20 05:20:10 +01:00
commit bed7488a9c
6 changed files with 2249 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*.bin
*.bak
*.rom
fx3tool
*.img
*.txt

12
Makefile Normal file
View File

@ -0,0 +1,12 @@
default: all
all: fx3tool
fx3tool: cyusb.h download_fx3.cpp libcyusb.cpp
$(CXX) -o "$@" $^ -lusb-1.0
clean:
@$(RM) -v fx3tool
.PHONY: all default clean

8
README.md Normal file
View File

@ -0,0 +1,8 @@
# fx3tool
Download and upload code and query the status of a Cypress FX3 in USB
bootloader mode. Built on top of Cypress' own code, so license is LGPL v2.1
## Planned
* Converter from ELF to FX3-IMG and back.

455
cyusb.h Normal file
View File

@ -0,0 +1,455 @@
#ifndef __CYUSB_H
#define __CYUSB_H
/*********************************************************************************\
* This is the main header file for the cyusb suite for Linux/Mac, called cyusb.h *
* *
* Author : V. Radhakrishnan ( rk@atr-labs.com ) *
* License : LGPL Ver 2.1 *
* Copyright : Cypress Semiconductors Inc. / ATR-LABS *
* Date written : March 12, 2012 *
* Modification Notes : *
* 1. Cypress Semiconductor, January 23, 2013 *
* Added function documentation. *
* Added new constant to specify number of device ID entries. *
* *
\********************************************************************************/
#include <libusb-1.0/libusb.h>
typedef struct libusb_device cyusb_device;
typedef struct libusb_device_handle cyusb_handle;
/* This is the maximum number of 'devices of interest' we are willing to store as default. */
/* These are the maximum number of devices we will communicate with simultaneously */
#define MAXDEVICES 10
/* This is the maximum number of VID/PID pairs that this library will consider. This limits
the number of valid VID/PID entries in the configuration file.
*/
#define MAX_ID_PAIRS 100
/* This is the maximum length for the description string for a device in the configuration
file. If the actual string in the file is longer, only the first MAX_STR_LEN characters
will be considered.
*/
#define MAX_STR_LEN 30
struct cydev {
cyusb_device *dev; /* as above ... */
cyusb_handle *handle; /* as above ... */
unsigned short vid; /* Vendor ID */
unsigned short pid; /* Product ID */
unsigned char is_open; /* When device is opened, val = 1 */
unsigned char busnum; /* The bus number of this device */
unsigned char devaddr; /* The device address*/
unsigned char filler; /* Padding to make struct = 16 bytes */
};
/* Function prototypes */
/*******************************************************************************************
Prototype : int cyusb_error(int err);
Description : Print out a verbose message corresponding to an error code, to the stderr
stream.
Parameters :
int err : Error code
Return Value : none
*******************************************************************************************/
extern void cyusb_error(int err);
/*******************************************************************************************
Prototype : int cyusb_open(void);
Description : This initializes the underlying libusb library, populates the cydev[]
array, and returns the number of devices of interest detected. A
'device of interest' is a device which appears in the /etc/cyusb.conf file.
Parameters : None
Return Value : Returns an integer, equal to number of devices of interest detected.
*******************************************************************************************/
extern int cyusb_open(void);
/*******************************************************************************************
Prototype : int cyusb_open(unsigned short vid, unsigned short pid);
Description : This is an overloaded function that populates the cydev[] array with
just one device that matches the provided vendor ID and Product ID.
This function is only useful if you know in advance that there is only
one device with the given VID and PID attached to the host system.
Parameters :
unsigned short vid : Vendor ID
unsigned short pid : Product ID
Return Value : Returns 1 if a device of interest exists, else returns 0.
*******************************************************************************************/
extern int cyusb_open(unsigned short vid, unsigned short pid);
/*******************************************************************************************
Prototype : cyusb_handle * cyusb_gethandle(int index);
Description : This function returns a libusb_device_handle given an index from the cydev[] array.
Parameters :
int index : Equal to the index in the cydev[] array that gets populated
during the cyusb_open() call described above.
Return Value : Returns the pointer to a struct of type cyusb_handle, also called as
libusb_device_handle.
*******************************************************************************************/
extern cyusb_handle * cyusb_gethandle(int index);
/*******************************************************************************************
Prototype : unsigned short cyusb_getvendor(cyusb_handle *);
Description : This function returns a 16-bit value corresponding to the vendor ID given
a device's handle.
Parameters :
cyusb_handle *handle : Pointer to a struct of type cyusb_handle.
Return Value : Returns the 16-bit unique vendor ID of the given device.
*******************************************************************************************/
extern unsigned short cyusb_getvendor(cyusb_handle *);
/*******************************************************************************************
Prototype : unsigned short cyusb_getproduct(cyusb_handle *);
Description : This function returns a 16-bit value corresponding to the device ID given
a device's handle.
Parameters :
cyusb_handle *handle : Pointer to a struct of type cyusb_handle.
Return Value : Returns the 16-bit product ID of the given device.
*******************************************************************************************/
extern unsigned short cyusb_getproduct(cyusb_handle *);
/*******************************************************************************************
Prototype : void cyusb_close(void);
Description : This function closes the libusb library and releases memory allocated to cydev[].
Parameters : none.
Return Value : none.
*******************************************************************************************/
extern void cyusb_close(void);
/*******************************************************************************************
Prototype : int cyusb_get_busnumber(cyusb_handle * handle);
Description : This function returns the Bus Number pertaining to a given device handle.
Parameters :
cyusb_handle *handle : The libusb device handle
Return Value : An integer value corresponding to the Bus Number on which the device resides.
This is also the same value present in the cydev[] array.
*******************************************************************************************/
extern int cyusb_get_busnumber(cyusb_handle *);
/*******************************************************************************************
Prototype : int cyusb_get_devaddr(cyusb_handle * handle);
Description : This function returns the device address pertaining to a given device handle
Parameters :
cyusb_handle *handle : The libusb device handle
Return Value : An integer value corresponding to the device address (between 1 and 127).
This is also the same value present in the cydev[] array.
*******************************************************************************************/
extern int cyusb_get_devaddr(cyusb_handle *);
/*******************************************************************************************
Prototype : int cyusb_get_max_packet_size(cyusb_handle * handle,unsigned char endpoint);
Description : This function returns the max packet size that an endpoint can handle, without
taking into account high-bandwidth capabiity. It is therefore only useful
for Bulk, not Isochronous endpoints.
Parameters :
cyusb_handle *handle : The libusb device handle
unsigned char endpoint : The endpoint number
Return Value : Max packet size in bytes for the endpoint.
*******************************************************************************************/
extern int cyusb_get_max_packet_size(cyusb_handle *, unsigned char endpoint);
/*******************************************************************************************
Prototype : int cyusb_get_max_iso_packet_size(cyusb_handle * handle,unsigned char endpoint);
Description : This function returns the max packet size that an isochronous endpoint can
handle, after considering multiple transactions per microframe if present.
Parameters :
cyusb_handle *handle : The libusb device handle
unsigned char endpoint : The endpoint number
Return Value : Maximum amount of data that an isochronous endpoint can transfer per
microframe.
*******************************************************************************************/
extern int cyusb_get_max_iso_packet_size(cyusb_handle *, unsigned char endpoint);
/*******************************************************************************************
Prototype : int cyusb_get_configuration(cyusb_handle * handle,int *config);
Description : This function determines the bConfiguration value of the active configuration.
Parameters :
cyusb_handle *handle : The libusb device handle
int * config : Address of an integer variable that will store the
currently active configuration number.
Return Value : 0 on success, or an appropriate LIBUSB_ERROR
*******************************************************************************************/
extern int cyusb_get_configuration(cyusb_handle *, int *config);
/*******************************************************************************************
Prototype : int cyusb_set_configuration(cyusb_handle * handle,int config);
Description : This function sets the device's active configuration (standard request).
Parameters :
cyusb_handle *handle : The libusb device handle
int config : Configuration number required to be made active.
Return Value : 0 on success, or an appropriate LIBUSB_ERROR
*******************************************************************************************/
extern int cyusb_set_configuration(cyusb_handle *, int config);
/*******************************************************************************************
Prototype : int cyusb_claim_interface(cyusb_handle * handle,int interface);
Description : This function claims an interface for a given device handle.
You must claim an interface before performing I/O operations on the device.
Parameters :
cyusb_handle *handle : The libusb device handle
int interface : The bInterfaceNumber of the interface you wish to claim.
Return Value : 0 on success, or an appropriate LIBUSB_ERROR
*******************************************************************************************/
extern int cyusb_claim_interface(cyusb_handle *, int interface);
/*********************************************************************************************
Prototype : int cyusb_release_interface(cyusb_handle * handle,int interface);
Description : This function releases an interface previously claimed for a given device handle.
You must release all claimed interfaces before closing a device handle.
This is a blocking funcion, where a standard SET_INTERFACE control request is
sent to the device, resetting interface state to the first alternate setting.
Parameters :
cyusb_handle *handle : The libusb device handle
int interface : The bInterfaceNumber of the interface you wish to release
Return Value : 0 on success, or an appropriate LIBUSB_ERROR
*********************************************************************************************/
extern int cyusb_release_interface(cyusb_handle *, int interface);
/*******************************************************************************************
Prototype : int cyusb_set_interface_alt_setting(cyusb_handle * handle,
int interface,int altsetting);
Description : This function activates an alternate setting for an interface.
The interface itself must have been previously claimed using
cyusb_claim_interface. This is a blocking funcion, where a standard
control request is sent to the device.
Parameters :
cyusb_handle *handle : The libusb device handle
int interface : The bInterfaceNumber of the interface you wish to set,
int altsetting : The bAlternateSetting number to activate
Return Value : 0 on success, or an appropriate LIBUSB_ERROR
*****************************************************************************************/
extern int cyusb_set_interface_alt_setting(cyusb_handle *, int interface, int altsetting);
/*******************************************************************************************
Prototype : int cyusb_clear_halt(cyusb_handle * handle, unsigned char endpoint);
Description : This function clears a halt condition on an endpoint.
Endpoints with a halt condition are unable to send/receive data unless
the condition is specifically cleared by the Host.
This is a blocking funcion.
Parameters :
cyusb_handle *handle : The libusb device handle
unsigned char endpoint : The endpoint for which the clear request is sent.
Return Value : 0 on success, or an appropriate LIBUSB_ERROR
*****************************************************************************************/
extern int cyusb_clear_halt(cyusb_handle *, unsigned char endpoint);
/******************************************************************************************
Prototype : int cyusb_reset_device(cyusb_handle * handle);
Description : This function performs a USB port reset to the device.
This is a blocking funcion.
Parameters :
cyusb_handle *handle : The libusb device handle
Return Value : 0 on success, or an appropriate LIBUSB_ERROR
*****************************************************************************************/
extern int cyusb_reset_device(cyusb_handle *);
/******************************************************************************************
Prototype : int cyusb_kernel_driver_active(cyusb_handle * handle, int interface);
Description : This function returns whether a kernel driver has already claimed an
interface. If a kernel driver is active and has claimed an interface,
cyusb cannot perform I/O operations on that interface unless the interface
is first released.
Parameters :
cyusb_handle *handle : The libusb device handle
int interface : The interface which you are testing.
Return Value : 0 if no kernel driver is active, 1 if a kernel driver is active;
LIBUSB error code in case of error.
*****************************************************************************************/
extern int cyusb_kernel_driver_active(cyusb_handle *, int interface);
/******************************************************************************************
Prototype : int cyusb_detach_kernel_driver(cyusb_handle * handle, int interface);
Description : This function detaches a kernel mode driver in order for cyusb to claim
the interface. If a kernel driver is active and has claimed an interface,
cyusb cannot perform I/O operations on that interface unless the interface
is first released.
Parameters :
cyusb_handle *handle : The libusb device handle
int interface : The interface which you want to be detached.
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
*****************************************************************************************/
extern int cyusb_detach_kernel_driver(cyusb_handle *, int interface);
/******************************************************************************************
Prototype : int cyusb_attach_kernel_driver(cyusb_handle * handle, int interface);
Description : This function reattaches a kernel mode driver which was previously detached.
Parameters :
cyusb_handle *handle : The libusb device handle
int interface : The interface which you want to be reattached.
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
*****************************************************************************************/
extern int cyusb_attach_kernel_driver(cyusb_handle *, int interface);
/******************************************************************************************
Prototype : int cyusb_get_device_descriptot(cyusb_handle * handle,
struct libusb_device_descriptor *);
Description : This function returns the usb device descriptor for the given device.
Parameters :
cyusb_handle *handle : The libusb device handle
struct libusb_device_descriptor *desc : Address of a device_desc structure
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
*****************************************************************************************/
extern int cyusb_get_device_descriptor(cyusb_handle *, struct libusb_device_descriptor *desc);
/******************************************************************************************
Prototype : int cyusb_get_active_config_descriptor(cyusb_handle * handle,
struct libusb_config_descriptor **);
Description : This function returns the usb configuration descriptor for the given device.
The descriptor structure must be freed with cyusb_free_config_descriptor()
explained below.
Parameters :
cyusb_handle *handle : The libusb device handle
struct libusb_configuration_descriptor **desc : Address of a config_descriptor
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
******************************************************************************************/
extern int cyusb_get_active_config_descriptor(cyusb_handle *, struct libusb_config_descriptor **config);
/*****************************************************************************************
Prototype : int cyusb_get_config_descriptor(cyusb_handle * handle, unsigned char index,
struct libusb_config_descriptor **);
Description : This function returns the usb configuration descriptor with the specified
index for the given device. The descriptor structure must be freed using
the cyusb_free_config_descriptor() call later.
Parameters :
cyusb_handle *handle : The libusb device handle
unsigned char index : Index of configuration you wish to retrieve.
struct libusb_configuration_descriptor **desc : Address of a config_descriptor
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
*****************************************************************************************/
extern int cyusb_get_config_descriptor(cyusb_handle *, unsigned char index, struct libusb_config_descriptor **config);
/*****************************************************************************************
Prototype : void cyusb_free_config_descriptor(struct libusb_config_descriptor *);
Description : Frees the configuration descriptor obtained earlier.
Parameters :
struct libusb_config_descriptor *config : The config descriptor you wish to free.
Return Value : NIL.
*****************************************************************************************/
extern void cyusb_free_config_descriptor(struct libusb_config_descriptor *config);
/*****************************************************************************************
Prototype : void cyusb_control_transfer(cyusb_handle *h, unsigned char bmRequestType,
unsigned char bRequest, unsigned short wValue, unsigned short wIndex,
unsigned char *data, unsigned short wLength, unsigned int timeout);
Description : Performs a USB Control Transfer. Please note that this is a generic transfer
function which can be used for READ (IN) and WRITE (OUT) data transfers, as
well as transfers with no data. The direction bit (MSB) in the bmRequestType
parameter should be set in the case of READ requests, and cleared in the case
of WRITE requests.
Parameters :
cyusb_handle *h : Device handle
unsigned char bmRequestType : The request type field for the setup packet
unsigned char bRequest : The request field of the setup packet
unsigned short wValue : The value field of the setup packet
unsigned short wIndex : The index field of the setup packet
unsigned char *data : Data Buffer ( for input or output )
unsigned short wLength : The length field of the setup packet.
unsigned int timeout : Timeout in milliseconds. 0 means no Timeout.
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
****************************************************************************************/
extern int cyusb_control_transfer(cyusb_handle *h, unsigned char bmRequestType, unsigned char bRequest,
unsigned short wValue, unsigned short wIndex, unsigned char *data, unsigned short wLength,
unsigned int timeout);
/*****************************************************************************************
Prototype : void cyusb_control_read(cyusb_handle *h, unsigned char bmRequestType,
unsigned char bRequest, unsigned short wValue, unsigned short wIndex,
unsigned char *data, unsigned short wLength, unsigned int timeout);
Description : Performs a USB control transfer including a READ (IN) data phase. Please
note that it is not advisable to use this function with wLength=0, because
most USB hosts/devices do not handle this case properly.
Parameters :
cyusb_handle *h : Device handle
unsigned char bmRequestType : The request type field for the setup packet
unsigned char bRequest : The request field of the setup packet
unsigned short wValue : The value field of the setup packet
unsigned short wIndex : The index field of the setup packet
unsigned char *data : Data Buffer ( for input or output )
unsigned short wLength : The length field of the setup packet.
unsigned int timeout : Timeout in milliseconds. 0 means no Timeout.
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
****************************************************************************************/
extern int cyusb_control_read(cyusb_handle *h, unsigned char bmRequestType, unsigned char bRequest,
unsigned short wValue, unsigned short wIndex, unsigned char *data, unsigned short wLength,
unsigned int timeout);
/*****************************************************************************************
Prototype : void cyusb_control_write(cyusb_handle *h, unsigned char bmRequestType,
unsigned char bRequest, unsigned short wValue, unsigned short wIndex,
unsigned char *data, unsigned short wLength, unsigned int timeout);
Description : Performs a USB control transfer including a WRITE (OUT) data phase.
Parameters :
cyusb_handle *h : Device handle
unsigned char bmRequestType : The request type field for the setup packet
unsigned char bRequest : The request field of the setup packet
unsigned short wValue : The value field of the setup packet
unsigned short wIndex : The index field of the setup packet
unsigned char *data : Data Buffer ( for input or output )
unsigned short wLength : The length field of the setup packet.
unsigned int timeout : Timeout in milliseconds. 0 means no Timeout.
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
****************************************************************************************/
extern int cyusb_control_write(cyusb_handle *h, unsigned char bmRequestType, unsigned char bRequest,
unsigned short wValue, unsigned short wIndex, unsigned char *data, unsigned short wLength,
unsigned int timeout);
/****************************************************************************************
Prototype : void cyusb_bulk_transfer(cyusb_handle *h, unsigned char endpoint,
unsigned char *data, int length, int *transferred, int timeout);
Description : Performs a USB Bulk Transfer.
Parameters :
cyusb_handle *h : Device handle
unsigned char endpoint : Address of endpoint to comunicate with
unsigned char *data : Data Buffer ( for input or output )
unsigned short wLength : The length field of the data buffer for read or write
int * transferred : Output location of bytes actually transferred
unsigned int timeout : Timeout in milliseconds. 0 means no Timeout.
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
****************************************************************************************/
extern int cyusb_bulk_transfer(cyusb_handle *h, unsigned char endpoint, unsigned char *data,
int length, int *transferred, int timeout);
/****************************************************************************************
Prototype : void cyusb_interrupt_transfer(cyusb_handle *h, unsigned char endpoint,
unsigned char *data, int length, int *transferred, int timeout);
Description : Performs a USB Interrupt Transfer.
Parameters :
cyusb_handle *h : Device handle
unsigned char endpoint : Address of endpoint to comunicate with
unsigned char *data : Data Buffer ( for input or output )
unsigned short wLength : The length field of the data buffer for read or write
int * transferred : Output location of bytes actually transferred
unsigned int timeout : Timeout in milliseconds. 0 means no Timeout.
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
****************************************************************************************/
extern int cyusb_interrupt_transfer(cyusb_handle *h, unsigned char endpoint, unsigned char *data,
int length, int *transferred, unsigned int timeout);
/****************************************************************************************
Prototype : void cyusb_download_fx2(cyusb_handle *h, char *filename,
unsigned char vendor_command);
Description : Performs firmware download on FX2.
Parameters :
cyusb_handle *h : Device handle
char * filename : Path where the firmware file is stored
unsigned char vendor_command : Vendor command that needs to be passed during download
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
****************************************************************************************/
extern int cyusb_download_fx2(cyusb_handle *h, char *filename, unsigned char vendor_command);
/****************************************************************************************
Prototype : void cyusb_download_fx3(cyusb_handle *h, char *filename);
Description : Performs firmware download on FX3.
Parameters :
cyusb_handle *h : Device handle
char *filename : Path where the firmware file is stored
Return Value : 0 on success, or an appropriate LIBUSB_ERROR.
***************************************************************************************/
extern int cyusb_download_fx3(cyusb_handle *h, char *filename);
#endif /* __CYUSB_H */

850
download_fx3.cpp Normal file
View File

@ -0,0 +1,850 @@
/*
* Filename : download_fx3.cpp
* Description : Downloads FX3 firmware to RAM, I2C EEPROM or SPI Flash.
*/
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <libusb-1.0/libusb.h>
#include "cyusb.h"
#define FLASHPROG_VID (0x04b4) // USB VID for the FX3 flash programmer.
#define MAX_FWIMG_SIZE (512 * 1024) // Maximum size of the firmware binary.
#define MAX_WRITE_SIZE (2 * 1024) // Max. size of data that can be written through one vendor command.
#define I2C_PAGE_SIZE (64) // Page size for I2C EEPROM.
#define I2C_SLAVE_SIZE (64 * 1024) // Max. size of data that can fit on one EEPROM address.
#define SPI_PAGE_SIZE (256) // Page size for SPI flash memory.
#define SPI_SECTOR_SIZE (64 * 1024) // Sector size for SPI flash memory.
#define VENDORCMD_TIMEOUT (5000) // Timeout (in milliseconds) for each vendor command.
#define GETHANDLE_TIMEOUT (5) // Timeout (in seconds) for getting a FX3 flash programmer handle.
/* Utility macros. */
#define ROUND_UP(n,v) ((((n) + ((v) - 1)) / (v)) * (v)) // Round n upto a multiple of v.
#define GET_LSW(v) ((unsigned short)((v) & 0xFFFF)) // Get Least Significant Word part of an integer.
#define GET_MSW(v) ((unsigned short)((v) >> 16)) // Get Most Significant Word part of an integer.
/* Enumeration representing the FX3 firmware target. */
typedef enum {
FW_TARGET_NONE = 0, // Invalid value
FW_TARGET_RAM, // Program to device RAM
FW_TARGET_I2C, // Program to I2C EEPROM
FW_TARGET_SPI // Program to SPI Flash
} fx3_fw_target;
typedef enum {
FW_ACTION_NONE = 0,
FW_ACTION_STATUS,
FW_ACTION_LOAD,
FW_ACTION_READ,
FW_ACTION_ERASE
} fx3_ldr_action;
/* Array representing physical size of EEPROM corresponding to each size encoding. */
const int i2c_eeprom_size[] =
{
1024, // bImageCtl[2:0] = 'b000
2048, // bImageCtl[2:0] = 'b001
4096, // bImageCtl[2:0] = 'b010
8192, // bImageCtl[2:0] = 'b011
16384, // bImageCtl[2:0] = 'b100
32768, // bImageCtl[2:0] = 'b101
65536, // bImageCtl[2:0] = 'b110
131072 // bImageCtl[2:0] = 'b111
};
static int
fx3_ram_read (
cyusb_handle *h,
unsigned char *buf,
unsigned int ramAddress,
int len)
{
int r;
int index = 0;
int size;
while (len > 0) {
size = (len > MAX_WRITE_SIZE) ? MAX_WRITE_SIZE : len;
r = cyusb_control_transfer (h, 0xC0, 0xA0, GET_LSW(ramAddress), GET_MSW(ramAddress),
&buf[index], size, VENDORCMD_TIMEOUT);
if (r != size) {
fprintf (stderr, "Error: Vendor read from FX3 RAM failed\n");
return -1;
}
ramAddress += size;
index += size;
len -= size;
}
return 0;
}
static int
fx3_ram_write (
cyusb_handle *h,
unsigned char *buf,
unsigned int ramAddress,
int len)
{
int r;
int index = 0;
int size;
while (len > 0) {
size = (len > MAX_WRITE_SIZE) ? MAX_WRITE_SIZE : len;
r = cyusb_control_transfer (h, 0x40, 0xA0, GET_LSW(ramAddress), GET_MSW(ramAddress),
&buf[index], size, VENDORCMD_TIMEOUT);
if (r != size) {
fprintf (stderr, "Error: Vendor write to FX3 RAM failed\n");
return -1;
}
ramAddress += size;
index += size;
len -= size;
}
return 0;
}
/* Read the firmware image from the file into a buffer. */
static int
read_firmware_image (
const char *filename,
unsigned char *buf,
int *romsize,
int *filesize)
{
int fd;
int nbr;
struct stat filestat;
if (stat (filename, &filestat) != 0) {
fprintf (stderr, "Error: Failed to stat file %s\n", filename);
return -1;
}
// Verify that the file size does not exceed our limits.
*filesize = filestat.st_size;
if (*filesize > MAX_FWIMG_SIZE) {
fprintf (stderr, "Error: File size exceeds maximum firmware image size\n");
return -2;
}
fd = open (filename, O_RDONLY);
if (fd < 0) {
fprintf (stderr, "Error: File not found\n");
return -3;
}
nbr = read (fd, buf, 2); /* Read first 2 bytes, must be equal to 'CY' */
if (strncmp ((char *)buf,"CY",2)) {
fprintf (stderr, "Error: Image does not have 'CY' at start.\n");
return -4;
}
nbr = read (fd, buf, 1); /* Read 1 byte. bImageCTL */
if (buf[0] & 0x01) {
fprintf (stderr, "Error: Image does not contain executable code\n");
return -5;
}
if (romsize != 0)
*romsize = i2c_eeprom_size[(buf[0] >> 1) & 0x07];
nbr = read (fd, buf, 1); /* Read 1 byte. bImageType */
if (!(buf[0] == 0xB0)) {
fprintf (stderr, "Error: Not a normal FW binary with checksum\n");
return -6;
}
// Read the complete firmware binary into a local buffer.
lseek (fd, 0, SEEK_SET);
nbr = read (fd, buf, *filesize);
close (fd);
return 0;
}
static int
fx3_usbboot_download (
cyusb_handle *h,
const char *filename)
{
unsigned char *fwBuf;
unsigned int *data_p;
unsigned int i, checksum;
unsigned int address, length;
int r, index, filesize;
fwBuf = (unsigned char *)calloc (1, MAX_FWIMG_SIZE);
if (fwBuf == 0) {
fprintf (stderr, "Error: Failed to allocate buffer to store firmware binary\n");
return -1;
}
// Read the firmware image into the local RAM buffer.
r = read_firmware_image (filename, fwBuf, NULL, &filesize);
if (r != 0) {
fprintf (stderr, "Error: Failed to read firmware file %s\n", filename);
free (fwBuf);
return -2;
}
// Run through each section of code, and use vendor commands to download them to RAM.
index = 4;
checksum = 0;
while (index < filesize) {
data_p = (unsigned int *)(fwBuf + index);
length = data_p[0];
address = data_p[1];
if (length != 0) {
for (i = 0; i < length; i++)
checksum += data_p[2 + i];
r = fx3_ram_write (h, fwBuf + index + 8, address, length * 4);
if (r != 0) {
fprintf (stderr, "Error: Failed to download data to FX3 RAM\n");
free (fwBuf);
return -3;
}
} else {
if (checksum != data_p[2]) {
fprintf (stderr, "Error: Checksum error in firmware binary\n");
free (fwBuf);
return -4;
}
r = cyusb_control_transfer (h, 0x40, 0xA0, GET_LSW(address), GET_MSW(address), NULL,
0, VENDORCMD_TIMEOUT);
if (r != 0)
printf ("Info: Ignored error in control transfer: %d\n", r);
break;
}
index += (8 + length * 4);
}
free (fwBuf);
return 0;
}
/* Check if the current device handle corresponds to the FX3 flash programmer. */
static int check_fx3_flashprog (cyusb_handle *handle)
{
int r;
char local[8];
r = cyusb_control_transfer (handle, 0xC0, 0xB0, 0, 0, (unsigned char *)local, 8, VENDORCMD_TIMEOUT);
if ((r != 8) || (strncasecmp (local, "FX3PROG", 7) != 0)) {
printf ("Info: Current device is not the FX3 flash programmer\n");
return -1;
}
printf ("Info: Found FX3 flash programmer\n");
return 0;
}
/* Get the handle to the FX3 flash programmer device, if found. */
static int
get_fx3_prog_handle (
cyusb_handle **h)
{
char *progfile_p, *tmp;
cyusb_handle *handle;
int i, j, r;
struct stat filestat;
handle = *h;
r = check_fx3_flashprog (handle);
if (r == 0)
return 0;
printf ("Info: Trying to download flash programmer to RAM\n");
tmp = getenv ("CYUSB_ROOT");
if (tmp != NULL) {
i = strlen (tmp);
progfile_p = (char *)malloc (i + 32);
strcpy (progfile_p, tmp);
strcat (progfile_p, "/fx3_images/cyfxflashprog.img");
}
else {
progfile_p = (char *)malloc (32);
strcpy (progfile_p, "fx3_images/cyfxflashprog.img");
}
r = stat (progfile_p, &filestat);
if (r != 0) {
fprintf (stderr, "Error: Failed to find cyfxflashprog.img file\n");
return -1;
}
r = fx3_usbboot_download (handle, progfile_p);
free (progfile_p);
if (r != 0) {
fprintf (stderr, "Error: Failed to download flash prog utility\n");
return -1;
}
cyusb_close ();
*h = NULL;
// Now wait for the flash programmer to enumerate, and get a handle to it.
for (j = 0; j < GETHANDLE_TIMEOUT; j++) {
sleep (1);
r = cyusb_open ();
if (r > 0) {
for (i = 0; i < r; i++) {
handle = cyusb_gethandle (i);
if (cyusb_getvendor (handle) == FLASHPROG_VID) {
r = check_fx3_flashprog (handle);
if (r == 0) {
printf ("Info: Got handle to FX3 flash programmer\n");
*h = handle;
return 0;
}
}
}
printf("cyusb close\n");
cyusb_close ();
printf("cyusb closeD!\n");
}
}
fprintf (stderr, "Error: Failed to get handle to flash programmer\n");
return -2;
}
static int fx3_init_progimg(cyusb_handle* h) {
int r = 0;
r = get_fx3_prog_handle(&h);
if (r != 0) {
fprintf (stderr, "Error: FX3 flash programmer not found\n");
return -1;
}
return 0;
}
static int
fx3_i2c_write (
cyusb_handle *h,
unsigned char *buf,
int devAddr,
int start,
int len)
{
int r = 0;
int index = start;
unsigned short address = 0;
int size;
while (len > 0) {
size = (len > MAX_WRITE_SIZE) ? MAX_WRITE_SIZE : len;
r = cyusb_control_transfer (h, 0x40, 0xBA, devAddr, address, &buf[index], size, VENDORCMD_TIMEOUT);
if (r != size) {
fprintf (stderr, "Error: I2C write failed\n");
return -1;
}
address += size ;
index += size;
len -= size;
}
return 0;
}
/* Function to read I2C data and compare against the expected value. */
static int
fx3_i2c_read (
cyusb_handle *h,
uint8_t* dst,
int devAddr,
int len)
{
int r = 0;
int index = 0;
unsigned short address = 0;
int size;
while (len > 0) {
size = (len > MAX_WRITE_SIZE) ? MAX_WRITE_SIZE : len;
r = cyusb_control_transfer (h, 0xC0, 0xBB, devAddr, address, dst, size, VENDORCMD_TIMEOUT);
if (r != size) {
fprintf (stderr, "Error: I2C read failed\n");
return -1;
}
address += size;
index += size;
len -= size;
dst += size;
}
return 0;
}
/* Function to read I2C data and compare against the expected value. */
static int
fx3_i2c_read_verify (
cyusb_handle *h,
unsigned char *expData,
int devAddr,
int len)
{
int r = 0;
int index = 0;
unsigned short address = 0;
int size;
unsigned char tmpBuf[MAX_WRITE_SIZE];
while (len > 0) {
size = (len > MAX_WRITE_SIZE) ? MAX_WRITE_SIZE : len;
r = cyusb_control_transfer (h, 0xC0, 0xBB, devAddr, address, tmpBuf, size, VENDORCMD_TIMEOUT);
if (r != size) {
fprintf (stderr, "Error: I2C read failed\n");
return -1;
}
if (memcmp (expData + index, tmpBuf, size) != 0) {
fprintf (stderr, "Error: Failed to read expected data from I2C EEPROM\n");
return -2;
}
address += size ;
index += size;
len -= size;
}
return 0;
}
int
fx3_i2cboot_download (
cyusb_handle *h,
const char *filename)
{
int romsize, size;
int address = 0, offset = 0;
int r, filesize;
unsigned char *fwBuf = 0;
// Check if we have a handle to the FX3 flash programmer.
r = get_fx3_prog_handle (&h);
if (r != 0) {
fprintf (stderr, "Error: FX3 flash programmer not found\n");
return -1;
}
// Allocate memory for holding the firmware binary.
fwBuf = (unsigned char *)calloc (1, MAX_FWIMG_SIZE);
if (read_firmware_image (filename, fwBuf, &romsize, &filesize)) {
fprintf (stderr, "Error: File %s does not contain valid FX3 firmware image\n", filename);
free (fwBuf);
return -2;
}
printf ("Info: Writing firmware image to I2C EEPROM\n");
filesize = ROUND_UP(filesize, I2C_PAGE_SIZE);
while (filesize != 0) {
size = (filesize <= romsize) ? filesize : romsize;
if (size > I2C_SLAVE_SIZE) {
r = fx3_i2c_write (h, fwBuf, address, offset, I2C_SLAVE_SIZE);
if (r == 0) {
r = fx3_i2c_read_verify (h, fwBuf + offset, address, I2C_SLAVE_SIZE);
if (r != 0) {
fprintf (stderr, "Error: Read-verify from I2C EEPROM failed\n");
free (fwBuf);
return -3;
}
r = fx3_i2c_write (h, fwBuf, address + 4, offset + I2C_SLAVE_SIZE, size - I2C_SLAVE_SIZE);
if (r == 0) {
r = fx3_i2c_read_verify (h, fwBuf + offset + I2C_SLAVE_SIZE,
address + 4, size - I2C_SLAVE_SIZE);
if (r != 0) {
fprintf (stderr, "Error: Read-verify from I2C EEPROM failed\n");
free (fwBuf);
return -3;
}
}
}
} else {
r = fx3_i2c_write (h, fwBuf, address, offset, size);
if (r == 0) {
r = fx3_i2c_read_verify (h, fwBuf + offset, address, size);
if (r != 0) {
fprintf (stderr, "Error: Read-verify from I2C EEPROM failed\n");
free (fwBuf);
return -3;
}
}
}
if (r != 0) {
fprintf (stderr, "Error: Write to I2C EEPROM failed\n");
free (fwBuf);
return -4;
}
/* Move to the next slave address. */
offset += size;
filesize -= size;
address++;
}
free (fwBuf);
printf ("Info: I2C programming completed\n");
return 0;
}
static int
fx3_spi_read (
cyusb_handle *h,
unsigned char *buf,
int offset,
int len)
{
int r = 0;
int index = 0;
int size;
unsigned short page_address = offset / SPI_PAGE_SIZE;
while (len > 0) {
size = (len > MAX_WRITE_SIZE) ? MAX_WRITE_SIZE : len;
r = cyusb_control_transfer (h, 0xC0, 0xC2, 0, page_address, &buf[index], size, VENDORCMD_TIMEOUT); // TODO: C3? C1?
if (r != size) {
fprintf (stderr, "Error: Read from SPI flash failed\n");
return -1;
}
index += size;
len -= size;
page_address += (size / SPI_PAGE_SIZE);
}
return 0;
}
static int
fx3_spi_write (
cyusb_handle *h,
unsigned char *buf,
int len)
{
int r = 0;
int index = 0;
int size;
unsigned short page_address = 0;
while (len > 0) {
size = (len > MAX_WRITE_SIZE) ? MAX_WRITE_SIZE : len;
r = cyusb_control_transfer (h, 0x40, 0xC2, 0, page_address, &buf[index], size, VENDORCMD_TIMEOUT);
if (r != size) {
fprintf (stderr, "Error: Write to SPI flash failed\n");
return -1;
}
index += size;
len -= size;
page_address += (size / SPI_PAGE_SIZE);
}
return 0;
}
static int
fx3_spi_erase_sector (
cyusb_handle *h,
unsigned short nsector)
{
unsigned char stat;
int timeout = 10;
int r;
r = cyusb_control_transfer (h, 0x40, 0xC4, 1, nsector, NULL, 0, VENDORCMD_TIMEOUT);
if (r != 0) {
fprintf (stderr, "Error: SPI sector erase failed\n");
return -1;
}
// Wait for the SPI flash to become ready again.
do {
r = cyusb_control_transfer (h, 0xC0, 0xC4, 0, 0, &stat, 1, VENDORCMD_TIMEOUT);
if (r != 1) {
fprintf (stderr, "Error: SPI status read failed\n");
return -2;
}
sleep (1);
timeout--;
} while ((stat != 0) && (timeout > 0));
if (stat != 0) {
fprintf (stderr, "Error: Timed out on SPI status read\n");
return -3;
}
printf ("Info: Erased sector %d of SPI flash\n", nsector);
return 0;
}
int
fx3_spiboot_download (
cyusb_handle *h,
const char *filename)
{
unsigned char *fwBuf;
int r, i, filesize;
// Check if we have a handle to the FX3 flash programmer.
r = get_fx3_prog_handle (&h);
if (r != 0) {
fprintf (stderr, "Error: FX3 flash programmer not found\n");
return -1;
}
// Allocate memory for holding the firmware binary.
fwBuf = (unsigned char *)calloc (1, MAX_FWIMG_SIZE);
if (fwBuf == 0) {
fprintf (stderr, "Error: Failed to allocate buffer to store firmware binary\n");
return -2;
}
if (read_firmware_image (filename, fwBuf, NULL, &filesize)) {
fprintf (stderr, "Error: File %s does not contain valid FX3 firmware image\n", filename);
free (fwBuf);
return -3;
}
filesize = ROUND_UP(filesize, SPI_PAGE_SIZE);
// Erase as many SPI sectors as are required to hold the firmware binary.
for (i = 0; i < ((filesize + SPI_SECTOR_SIZE - 1) / SPI_SECTOR_SIZE); i++) {
r = fx3_spi_erase_sector (h, i);
if (r != 0) {
fprintf (stderr, "Error: Failed to erase SPI flash\n");
free (fwBuf);
return -4;
}
}
r = fx3_spi_write (h, fwBuf, filesize);
if (r != 0) {
fprintf (stderr, "Error: SPI write failed\n");
} else {
printf ("Info: SPI flash programming completed\n");
}
free (fwBuf);
return r;
}
void
print_usage_info (
const char *arg0)
{
printf ("%s: FX3 firmware programmer\n\n", arg0);
printf ("Usage:\n");
printf ("\t%s -h: Print this help message\n\n", arg0);
printf ("\t%s-a status: display device status\n", arg0);
printf ("\t%s-a load -t <target> -i <img filename>: Program firmware binary from <img filename> to <target>\n", arg0);
printf ("\t\t\twhere <target> is one of:\n");
printf ("\t\t\t\t\"RAM\": Program to FX3 RAM\n");
printf ("\t\t\t\t\"I2C\": Program to I2C EEPROM\n");
printf ("\t\t\t\t\"SPI\": Program to SPI FLASH\n");
printf ("\t%s-a read -t <target> -i <filename> -o <offset> -l <length>: read data from <target> into <filename> at the specified offset and length (in bytes)\n", arg0);
printf ("\t%s-a erase -t <target> -o <offset>: erase sector #<offset> from <target>\n", arg0);
printf ("\n\n");
}
int main (
int argc,
char **argv)
{
char *filename = NULL;
char *tgt_str = NULL;
fx3_fw_target tgt = FW_TARGET_NONE;
fx3_ldr_action act = FW_ACTION_NONE;
long offset = -1, length = -1;
/* Parse command line arguments. */
for (int i = 1; i < argc; i++) {
if ((strcasecmp (argv[i], "-h") == 0) || (strcasecmp (argv[i], "--help") == 0)) {
print_usage_info (argv[0]);
return 0;
} else {
if ((strcasecmp (argv[i], "-t") == 0) || (strcasecmp (argv[i], "--target") == 0)) {
if (argc > (i + 1)) {
tgt_str = argv[i + 1];
if (strcasecmp (argv[i + 1], "ram") == 0)
tgt = FW_TARGET_RAM;
if (strcasecmp (argv[i + 1], "i2c") == 0)
tgt = FW_TARGET_I2C;
if (strcasecmp (argv[i + 1], "spi") == 0)
tgt = FW_TARGET_SPI;
if (tgt == FW_TARGET_NONE) {
fprintf (stderr, "Error: Unknown target %s\n", argv[i + 1]);
print_usage_info (argv[0]);
return 1;
}
}
i++;
} else if (!strcmp(argv[i], "-a")) {
if (argc > i + 1) {
const char* acts = argv[i+1];
if (!strcasecmp(acts, "status")) act = FW_ACTION_STATUS;
if (!strcasecmp(acts, "load")) act = FW_ACTION_LOAD;
if (!strcasecmp(acts, "read")) act = FW_ACTION_READ;
if (!strcasecmp(acts, "erase")) act = FW_ACTION_ERASE;
if (act == FW_ACTION_NONE) {
fprintf(stderr, "Error: unknown action '%s'\n", acts);
print_usage_info(argv[0]);
return 1;
}
}
++i;
} else if ((strcmp (argv[i], "-i") == 0) || (strcmp (argv[i], "--image") == 0)) {
if (argc > (i + 1))
filename = argv[i + 1];
i++;
} else if (!strcmp(argv[i], "-o")) {
if (argc > i + 1)
if (sscanf(argv[i+1], "%li", &offset) != 1)
offset = -1;
++i;
} else if (!strcmp(argv[i], "-l")) {
if (argc > i + 1)
if (sscanf(argv[i+1], "%li", &length) != 1)
length = -1;
++i;
} else {
fprintf (stderr, "Error: Unknown parameter %s\n", argv[i]);
print_usage_info (argv[0]);
return 1;
}
}
}
int r = cyusb_open ();
if (r < 0) {
fprintf (stderr, "Error opening library\n");
return 2;
}
else if (r == 0) {
fprintf (stderr, "Error: No FX3 device found\n");
return 2;
}
else if (r > 1) {
fprintf (stderr, "Error: More than one Cypress device found\n");
return 1;
}
cyusb_handle *h = cyusb_gethandle (0);
switch (act) {
case FW_ACTION_STATUS:
r = check_fx3_flashprog(h);
break;
case FW_ACTION_LOAD:
if ((filename == NULL) || (tgt == FW_TARGET_NONE)) {
fprintf (stderr, "Error: Firmware binary or target not specified\n");
print_usage_info (argv[0]);
return 1;
}
switch (tgt) {
case FW_TARGET_RAM:
r = fx3_usbboot_download (h, filename);
break;
case FW_TARGET_I2C:
r = fx3_i2cboot_download (h, filename);
break;
case FW_TARGET_SPI:
r = fx3_spiboot_download (h, filename);
break;
default: break;
}
break;
case FW_ACTION_READ: {
if ((filename == NULL) || (tgt == FW_TARGET_NONE)) {
fprintf (stderr, "Error: Firmware binary or target not specified\n");
print_usage_info (argv[0]);
return 1;
}
if (length <= 0 || offset == -1) {
fprintf(stderr, "Error: need an offset and length (both in bytes) specified.\n");
return 1;
}
uint8_t *databuf = (uint8_t*)calloc(1, length);
switch (tgt) {
case FW_TARGET_RAM:
r = fx3_ram_read(h, databuf, offset, length);
break;
case FW_TARGET_I2C:
r = fx3_init_progimg(h);
printf("progimg done\n");
if (r == 0) r = fx3_i2c_read(h, databuf, offset, length);
printf("read done\n");
break;
case FW_TARGET_SPI:
r = fx3_init_progimg(h);
if (r == 0) r = fx3_spi_read(h, databuf, offset, length);
break;
default:
r = -1;
break;
}
if (r == 0) {
FILE* rf = fopen(filename, "wb");
fwrite(databuf, 1, length, rf);
fclose(rf);
}
free(databuf);
} break;
case FW_ACTION_ERASE:
if ((tgt == FW_TARGET_NONE)) {
fprintf (stderr, "Error: Target not specified\n");
print_usage_info (argv[0]);
return 1;
}
if (offset <= 0) {
fprintf(stderr, "Error: need an offset (in sectors) specified.\n");
return 1;
}
switch (tgt) {
case FW_TARGET_SPI:
r = fx3_init_progimg(h);
if (r == 0) r = fx3_spi_erase_sector(h, offset);
break;
default:
printf("Info: target does not support erasing\n");
break;
}
default: break;
}
if (r != 0) {
fprintf (stderr, "Error: FX3 firmware programming failed\n");
return 3;
} else {
printf ("FX3 firmware programming to %s completed\n", tgt_str);
}
return 0;
}

918
libcyusb.cpp Normal file
View File

@ -0,0 +1,918 @@
/*******************************************************************************\
* Program Name : libcyusb.cpp *
* Author : V. Radhakrishnan ( rk@atr-labs.com ) *
* License : LGPL Ver 2.1 *
* Copyright : Cypress Semiconductors Inc. / ATR-LABS *
* Date written : March 12, 2012 *
* Modification Notes : *
* *
* This program is the main library for all cyusb applications to use. *
* This is a thin wrapper around libusb *
\*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <libusb-1.0/libusb.h>
#include "cyusb.h"
/* Maximum length of a string read from the Configuration file (/etc/cyusb.conf) for the library. */
#define MAX_CFG_LINE_LENGTH (120)
/* Maximum length for a filename. */
#define MAX_FILEPATH_LENGTH (256)
/* Maximum size of EZ-USB FX3 firmware binary. Limited by amount of RAM available. */
#define FX3_MAX_FW_SIZE (524288)
static struct cydev cydev[MAXDEVICES]; /* List of devices of interest that are connected. */
static int nid; /* Number of Interesting Devices. */
static libusb_device **list; /* libusb device list used by the cyusb library. */
/*
struct VPD
Used to store information about the devices of interest listed in /etc/cyusb.conf
*/
struct VPD {
unsigned short vid; /* USB Vendor ID. */
unsigned short pid; /* USB Product ID. */
char desc[MAX_STR_LEN]; /* Device description. */
};
static struct VPD vpd[MAX_ID_PAIRS]; /* Known device database. */
static int maxdevices; /* Number of devices in the vpd database. */
static unsigned int checksum = 0; /* Checksum calculated on the Cypress firmware binary. */
/* The following variables are used by the cyusb_linux application. */
char pidfile[MAX_FILEPATH_LENGTH]; /* Full path to the PID file specified in /etc/cyusb.conf */
char logfile[MAX_FILEPATH_LENGTH]; /* Full path to the LOG file specified in /etc/cyusb.conf */
int logfd; /* File descriptor for the LOG file. */
int pidfd; /* File descriptor for the PID file. */
/* isempty:
Check if the first L characters of the string buf are white-space characters.
*/
static bool
isempty (
char *buf,
int L)
{
bool flag = true;
int i;
for (i = 0; i < L; ++i ) {
if ( (buf[i] != ' ') && ( buf[i] != '\t' ) ) {
flag = false;
break;
}
}
return flag;
}
/* parse_configfile:
Parse the /etc/cyusb.conf file and get the list of USB devices of interest.
*/
static void
parse_configfile (
void)
{
FILE *inp;
char buf[MAX_CFG_LINE_LENGTH];
char *cp1, *cp2, *cp3;
int i;
inp = fopen("/etc/cyusb.conf", "r");
if (inp == NULL)
return;
memset(buf,'\0',MAX_CFG_LINE_LENGTH);
while ( fgets(buf,MAX_CFG_LINE_LENGTH,inp) ) {
if ( buf[0] == '#' ) /* Any line starting with a # is a comment */
continue;
if ( buf[0] == '\n' )
continue;
if ( isempty(buf,strlen(buf)) ) /* Any blank line is also ignored */
continue;
cp1 = strtok(buf," =\t\n");
if ( !strcmp(cp1,"LogFile") ) {
cp2 = strtok(NULL," \t\n");
strcpy(logfile,cp2);
}
else if ( !strcmp(cp1,"PIDFile") ) {
cp2 = strtok(NULL," \t\n");
strcpy(pidfile,cp2);
}
else if ( !strcmp(cp1,"<VPD>") ) {
while ( fgets(buf,MAX_CFG_LINE_LENGTH,inp) ) {
if ( buf[0] == '#' ) /* Any line starting with a # is a comment */
continue;
if ( buf[0] == '\n' )
continue;
if ( isempty(buf,strlen(buf)) ) /* Any blank line is also ignored */
continue;
if ( maxdevices == (MAX_ID_PAIRS - 1) )
continue;
cp1 = strtok(buf," \t\n");
if ( !strcmp(cp1,"</VPD>") )
break;
cp2 = strtok(NULL, " \t");
cp3 = strtok(NULL, " \t\n");
vpd[maxdevices].vid = strtol(cp1,NULL,16);
vpd[maxdevices].pid = strtol(cp2,NULL,16);
strncpy(vpd[maxdevices].desc,cp3,MAX_STR_LEN);
vpd[maxdevices].desc[MAX_STR_LEN - 1] = '\0'; /* Make sure of NULL-termination. */
++maxdevices;
}
}
else {
printf("Error in config file /etc/cyusb.conf: %s \n",buf);
exit(1);
}
}
fclose(inp);
}
/* device_is_of_interest:
Check whether the current USB device is among the devices of interest.
*/
static int
device_is_of_interest (
cyusb_device *d)
{
int i;
int found = 0;
struct libusb_device_descriptor desc;
int vid;
int pid;
libusb_get_device_descriptor(d, &desc);
vid = desc.idProduct;
pid = desc.idProduct;
for ( i = 0; i < maxdevices; ++i ) {
if ( (vpd[i].vid == desc.idVendor) && (vpd[i].pid == desc.idProduct) ) {
found = 1;
break;
}
}
return found;
}
/* cyusb_getvendor:
Get the Vendor ID for the current USB device.
*/
unsigned short
cyusb_getvendor (
cyusb_handle *h)
{
struct libusb_device_descriptor d;
cyusb_get_device_descriptor(h, &d);
return d.idVendor;
}
/* cyusb_getproduct:
Get the Product ID for the current USB device.
*/
unsigned short
cyusb_getproduct (
cyusb_handle *h)
{
struct libusb_device_descriptor d;
cyusb_get_device_descriptor(h, &d);
return d.idProduct;
}
/* renumerate:
Get handles to and store information about all USB devices of interest.
*/
static int
renumerate (
void)
{
cyusb_device *dev = NULL;
cyusb_handle *handle = NULL;
int numdev;
int found = 0;
int i;
int r;
numdev = libusb_get_device_list(NULL, &list);
if ( numdev < 0 ) {
printf("Library: Error in enumerating devices...\n");
return -ENODEV;
}
nid = 0;
for ( i = 0; i < numdev; ++i ) {
cyusb_device *tdev = list[i];
if ( device_is_of_interest(tdev) ) {
cydev[nid].dev = tdev;
r = libusb_open(tdev, &cydev[nid].handle);
if ( r ) {
printf("Error in opening device\n");
return -EACCES;
}
else
handle = cydev[nid].handle;
cydev[nid].vid = cyusb_getvendor(handle);
cydev[nid].pid = cyusb_getproduct(handle);
cydev[nid].is_open = 1;
cydev[nid].busnum = cyusb_get_busnumber(handle);
cydev[nid].devaddr = cyusb_get_devaddr(handle);
++nid;
}
}
return nid;
}
/* cyusb_open:
Opens handles to all USB devices of interest, and returns their count.
*/
int cyusb_open (
void)
{
int fd1;
int r;
fd1 = open("/etc/cyusb.conf", O_RDONLY);
if ( fd1 < 0 ) {
printf("/etc/cyusb.conf file not found. Exiting\n");
return -ENOENT;
}
else {
close(fd1);
parse_configfile(); /* Parse the file and store information inside exported data structures */
}
r = libusb_init(NULL);
if (r) {
printf("Error in initializing libusb library...\n");
return -EACCES;
}
/* Get list of USB devices of interest. */
r = renumerate();
return r;
}
/* cyusb_open:
Open a handle to the USB device with specified vid/pid.
*/
int cyusb_open (
unsigned short vid,
unsigned short pid)
{
int r;
cyusb_handle *h = NULL;
r = libusb_init(NULL);
if (r) {
printf("Error in initializing libusb library...\n");
return -EACCES;
}
h = libusb_open_device_with_vid_pid(NULL, vid, pid);
if ( !h ) {
printf("Device not found\n");
return -ENODEV;
}
cydev[0].dev = libusb_get_device(h);
cydev[0].handle = h;
cydev[0].vid = cyusb_getvendor(h);
cydev[0].pid = cyusb_getproduct(h);
cydev[0].is_open = 1;
cydev[0].busnum = cyusb_get_busnumber(h);
cydev[0].devaddr = cyusb_get_devaddr(h);
nid = 1;
return 1;
}
/* cyusb_error:
Print verbose information about the error returned by the cyusb API. These are essentially descriptions of
status values defined as part of the libusb library.
*/
void
cyusb_error (
int err)
{
switch (err)
{
case -1:
fprintf(stderr, "Input/output error\n");
break;
case -2:
fprintf(stderr, "Invalid parameter\n");
break;
case -3:
fprintf(stderr, "Access denied (insufficient permissions)\n");
break;
case -4:
fprintf(stderr, "No such device. Disconnected...?\n");
break;
case -5:
fprintf(stderr, "Entity not found\n");
break;
case -6:
fprintf(stderr, "Resource busy\n");
break;
case -7:
fprintf(stderr, "Operation timed out\n");
break;
case -8:
fprintf(stderr, "Overflow\n");
break;
case -9:
fprintf(stderr, "Pipe error\n");
break;
case -10:
fprintf(stderr, "System call interrupted, ( due to signal ? )\n");
break;
case -11:
fprintf(stderr, "Insufficient memory\n");
break;
case -12:
fprintf(stderr, "Operation not supported/implemented\n");
break;
default:
fprintf(stderr, "Unknown internal error\n");
break;
}
}
/* cyusb_gethandle:
Get a handle to the USB device with specified index.
*/
cyusb_handle *
cyusb_gethandle (
int index)
{
return cydev[index].handle;
}
/* cyusb_close:
Close all device handles and de-initialize the libusb library.
*/
void
cyusb_close (
void)
{
int i;
for ( i = 0; i < nid; ++i ) {
libusb_close(cydev[i].handle);
}
libusb_free_device_list(list, 1);
libusb_exit(NULL);
}
/* cyusb_get_busnumber:
Get USB bus number on which the specified device is connected.
*/
int
cyusb_get_busnumber (
cyusb_handle *h)
{
cyusb_device *tdev = libusb_get_device(h);
return libusb_get_bus_number( tdev );
}
/* cyusb_get_devaddr:
Get USB device address assigned to the specified device.
*/
int
cyusb_get_devaddr (
cyusb_handle *h)
{
cyusb_device *tdev = libusb_get_device(h);
return libusb_get_device_address( tdev );
}
/* cyusb_get_max_packet_size:
Get the max packet size for the specified USB endpoint.
*/
int
cyusb_get_max_packet_size (
cyusb_handle *h,
unsigned char endpoint)
{
cyusb_device *tdev = libusb_get_device(h);
return ( libusb_get_max_packet_size(tdev, endpoint) );
}
/* cyusb_get_max_iso_packet_size:
Calculate the maximum packet size which a specific isochronous endpoint is capable of sending or
receiving in the duration of 1 microframe.
*/
int
cyusb_get_max_iso_packet_size (
cyusb_handle *h,
unsigned char endpoint)
{
cyusb_device *tdev = libusb_get_device(h);
return ( libusb_get_max_iso_packet_size(tdev, endpoint) );
}
/* cyusb_get_configuration:
Get the id of the active configuration on the specified USB device.
*/
int
cyusb_get_configuration (
cyusb_handle *h,
int *config)
{
return ( libusb_get_configuration(h, config) );
}
/* cyusb_set_configuration:
Set the active configuration for the specified USB device.
*/
int
cyusb_set_configuration (
cyusb_handle *h,
int config)
{
return ( libusb_set_configuration(h, config) );
}
/* cyusb_claim_interface:
Claim the specified USB device interface, so that cyusb/libusb APIs can be used for transfers on the
corresponding endpoints.
*/
int
cyusb_claim_interface (
cyusb_handle *h,
int interface)
{
return ( libusb_claim_interface(h, interface) );
}
/* cyusb_release_interface:
Release an interface previously claimed using cyusb_claim_interface.
*/
int
cyusb_release_interface (
cyusb_handle *h,
int interface)
{
return ( libusb_release_interface(h, interface) );
}
/* cyusb_set_interface_alt_setting:
Select the alternate setting for the specified USB device and interface.
*/
int
cyusb_set_interface_alt_setting (
cyusb_handle *h,
int interface,
int altsetting)
{
return ( libusb_set_interface_alt_setting(h, interface, altsetting) );
}
/* cyusb_clear_halt:
Clear the STALL or HALT condition on the specified endpoint.
*/
int
cyusb_clear_halt (
cyusb_handle *h,
unsigned char endpoint)
{
return ( libusb_clear_halt(h, endpoint) );
}
/* cyusb_reset_device:
Perform a USB port reset to re-initialize the specified USB device.
*/
int
cyusb_reset_device (
cyusb_handle *h)
{
return ( libusb_reset_device(h) );
}
/* cyusb_kernel_driver_active:
Check whether a Kernel driver is currently bound to the specified USB device and interface. The cyusb/libusb
APIs cannot be used on an interface while a kernel driver is active.
*/
int
cyusb_kernel_driver_active (
cyusb_handle *h,
int interface)
{
return ( libusb_kernel_driver_active(h, interface) );
}
/* cyusb_detach_kernel_driver:
Detach the kernel driver from the specified USB device and interface, so that the APIs can be used.
*/
int
cyusb_detach_kernel_driver (
cyusb_handle *h,
int interface)
{
return ( libusb_detach_kernel_driver(h, interface) );
}
/* cyusb_attach_kernel_driver:
Re-attach the kernel driver from the specified USB device and interface.
*/
int
cyusb_attach_kernel_driver (
cyusb_handle *h,
int interface)
{
return ( libusb_attach_kernel_driver(h, interface) );
}
/* cyusb_get_device_descriptor:
Get the device descriptor for the specified USB device.
*/
int
cyusb_get_device_descriptor (
cyusb_handle *h,
struct libusb_device_descriptor *desc)
{
cyusb_device *tdev = libusb_get_device(h);
return ( libusb_get_device_descriptor(tdev, desc ) );
}
/* cyusb_get_active_config_descriptor:
Get the active configuration descriptor for the specified USB device.
*/
int
cyusb_get_active_config_descriptor (
cyusb_handle *h,
struct libusb_config_descriptor **config)
{
cyusb_device *tdev = libusb_get_device(h);
return ( libusb_get_active_config_descriptor(tdev, config) );
}
/* cyusb_get_config_descriptor:
Get the configuration descriptor at index config_index, for the specified USB device.
*/
int
cyusb_get_config_descriptor (
cyusb_handle *h,
unsigned char config_index,
struct libusb_config_descriptor **config)
{
cyusb_device *tdev = libusb_get_device(h);
return ( libusb_get_config_descriptor(tdev, config_index, config) );
}
/* cyusb_get_config_descriptor_by_value:
Get the configuration descriptor with value bConfigurationValue for the specified USB device.
*/
int
cyusb_get_config_descriptor_by_value (
cyusb_handle *h,
unsigned char bConfigurationValue,
struct usb_config_descriptor **config)
{
cyusb_device *tdev = libusb_get_device(h);
return ( libusb_get_config_descriptor_by_value(tdev, bConfigurationValue,
(struct libusb_config_descriptor **)config) );
}
/* cyusb_free_config_descriptor:
Free the configuration descriptor structure after it has been used.
*/
void
cyusb_free_config_descriptor (
struct libusb_config_descriptor *config)
{
libusb_free_config_descriptor( (libusb_config_descriptor *)config );
}
/* cyusb_get_string_descriptor_ascii:
Get the specified USB string descriptor in the format of an ASCII string.
*/
int
cyusb_get_string_descriptor_ascii (
cyusb_handle *h,
unsigned char index,
unsigned char *data,
int length)
{
cyusb_device *tdev = libusb_get_device(h);
return ( libusb_get_string_descriptor_ascii(h, index, data, length) );
}
/* cyusb_get_descriptor:
Get a USB descriptor given the type and index.
*/
int
cyusb_get_descriptor (
cyusb_handle *h,
unsigned char desc_type,
unsigned char desc_index,
unsigned char *data,
int len)
{
return ( libusb_get_descriptor(h, desc_type, desc_index, data, len) );
}
/* cyusb_get_string_descriptor:
Get the USB string descriptor with the specified index.
*/
int
cyusb_get_string_descriptor (
cyusb_handle *h,
unsigned char desc_index,
unsigned short langid,
unsigned char *data,
int len)
{
return ( libusb_get_string_descriptor(h, desc_index, langid, data, len) );
}
/* cyusb_control_transfer:
Perform the desired USB control transfer (can be read or write based on the bmRequestType value).
*/
int
cyusb_control_transfer (
cyusb_handle *h,
unsigned char bmRequestType,
unsigned char bRequest,
unsigned short wValue,
unsigned short wIndex,
unsigned char *data,
unsigned short wLength,
unsigned int timeout)
{
return ( libusb_control_transfer(h, bmRequestType, bRequest, wValue, wIndex, data, wLength, timeout) );
}
/* cyusb_control_read:
Perform a read transfer on the USB control endpoint.
*/
int
cyusb_control_read (
cyusb_handle *h,
unsigned char bmRequestType,
unsigned char bRequest,
unsigned short wValue,
unsigned short wIndex,
unsigned char *data,
unsigned short wLength,
unsigned int timeout)
{
/* Set the direction bit to indicate a read transfer. */
return ( libusb_control_transfer(h, bmRequestType | 0x80, bRequest, wValue, wIndex, data, wLength, timeout) );
}
/* cyusb_control_write:
Perform a write transfer on the USB control endpoint. This can be a zero byte (no data) transfer as well.
*/
int
cyusb_control_write (
cyusb_handle *h,
unsigned char bmRequestType,
unsigned char bRequest,
unsigned short wValue,
unsigned short wIndex,
unsigned char *data,
unsigned short wLength,
unsigned int timeout)
{
/* Clear the direction bit to indicate a write transfer. */
return ( libusb_control_transfer(h, bmRequestType & 0x7F, bRequest, wValue, wIndex, data, wLength, timeout) );
}
/* cyusb_bulk_transfer:
Perform a data transfer on a USB Bulk endpoint.
*/
int
cyusb_bulk_transfer (
cyusb_handle *h,
unsigned char endpoint,
unsigned char *data,
int length,
int *transferred,
int timeout)
{
return ( libusb_bulk_transfer(h, endpoint, data, length, transferred, timeout) );
}
/* cyusb_interrupt_transfer:
Perform a data transfer on a USB interrupt endpoint.
*/
int
cyusb_interrupt_transfer (
cyusb_handle *h,
unsigned char endpoint,
unsigned char *data,
int length,
int *transferred,
unsigned int timeout)
{
return ( libusb_interrupt_transfer(h, endpoint, data, length, transferred, timeout) );
}
/* cyusb_download_fx2:
Download firmware to the Cypress FX2/FX2LP device using USB vendor commands.
*/
int
cyusb_download_fx2 (
cyusb_handle *h,
char *filename,
unsigned char vendor_command)
{
FILE *fp = NULL;
char buf[256];
char tbuf1[3];
char tbuf2[5];
char tbuf3[3];
unsigned char reset = 0;
int r;
int count = 0;
unsigned char num_bytes = 0;
unsigned short address = 0;
unsigned char *dbuf = NULL;
int i;
fp = fopen(filename, "r" );
tbuf1[2] ='\0';
tbuf2[4] = '\0';
tbuf3[2] = '\0';
/* Place the FX2/FX2LP CPU in reset, so that the vendor commands can be handled by the device. */
reset = 1;
r = cyusb_control_transfer(h, 0x40, 0xA0, 0xE600, 0x00, &reset, 0x01, 1000);
if ( !r ) {
printf("Error in control_transfer\n");
return r;
}
sleep(1);
count = 0;
while ( fgets(buf, 256, fp) != NULL ) {
if ( buf[8] == '1' )
break;
strncpy(tbuf1,buf+1,2);
num_bytes = strtoul(tbuf1,NULL,16);
strncpy(tbuf2,buf+3,4);
address = strtoul(tbuf2,NULL,16);
dbuf = (unsigned char *)malloc(num_bytes);
for ( i = 0; i < num_bytes; ++i ) {
strncpy(tbuf3,&buf[9+i*2],2);
dbuf[i] = strtoul(tbuf3,NULL,16);
}
r = cyusb_control_transfer(h, 0x40, vendor_command, address, 0x00, dbuf, num_bytes, 1000);
if ( !r ) {
printf("Error in control_transfer\n");
free(dbuf);
return r;
}
count += num_bytes;
free(dbuf);
}
printf("Total bytes downloaded = %d\n", count);
sleep(1);
/* Bring the CPU out of reset to run the newly loaded firmware. */
reset = 0;
r = cyusb_control_transfer(h, 0x40, 0xA0, 0xE600, 0x00, &reset, 0x01, 1000);
fclose(fp);
return 0;
}
/* control_transfer:
Internal function that issues the vendor command that incrementally loads firmware segments to the
Cypress FX3 device RAM.
*/
static void
control_transfer (
cyusb_handle *h,
unsigned int address,
unsigned char *dbuf,
int len)
{
int j;
int r;
int b;
unsigned int *pint;
int index;
int balance = len;
pint = (unsigned int *)dbuf;
index = 0;
while ( balance > 0 ) {
if ( balance > 4096 )
b = 4096;
else b = balance;
r = cyusb_control_transfer (h, 0x40, 0xA0, ( address & 0x0000ffff ), address >> 16,
&dbuf[index], b, 1000);
if ( r != b ) {
printf("Error in control_transfer\n");
}
address += b ;
balance -= b;
index += b;
}
/* Update the firmware checksum as the download is being performed. */
for ( j = 0; j < len/4; ++j )
checksum += pint[j];
}
/* cyusb_download_fx3:
Download a firmware binary the Cypress FX3 device RAM.
*/
int
cyusb_download_fx3 (
cyusb_handle *h,
const char *filename)
{
int fd;
unsigned char buf[FX3_MAX_FW_SIZE];
int nbr;
int dlen;
int count;
unsigned int *pdbuf = NULL;
unsigned int address;
unsigned int *pint;
unsigned int program_entry;
int r;
fd = open(filename, O_RDONLY);
if ( fd < 0 ) {
printf("File not found\n");
return -ENOENT;
}
else
printf("File successfully opened\n");
count = 0;
checksum = 0;
nbr = read(fd, buf, 2); /* Read first 2 bytes, must be equal to 'CY' */
if ( strncmp((char *)buf,"CY",2) ) {
printf("Image does not have 'CY' at start. aborting\n");
return -EINVAL;
}
nbr = read(fd, buf, 1); /* Read 1 byte. bImageCTL */
if ( buf[0] & 0x01 ) {
printf("Image does not contain executable code\n");
return -EINVAL;
}
nbr = read(fd, buf, 1); /* Read 1 byte. bImageType */
if ( !(buf[0] == 0xB0) ) {
printf("Not a normal FW binary with checksum\n");
return -EINVAL;
}
while (1) {
nbr = read(fd, buf, 4); /* Read Length of section 1,2,3, ... */
pdbuf = (unsigned int *)buf;
dlen = *pdbuf;
nbr = read(fd,buf,4); /* Read Address of section 1,2,3,... */
pint = (unsigned int *)buf;
address = *pint;
if ( dlen != 0 ) {
nbr = read(fd, buf, dlen*4); /* Read data bytes */
control_transfer(h, address, buf, dlen*4);
}
else {
program_entry = address;
break;
}
}
nbr = read(fd, buf, 4); /* Read checksum */
pdbuf = (unsigned int *)buf;
if ( *pdbuf != checksum ) {
printf("Error in checksum\n");
return -EINVAL;
}
sleep(1);
r = cyusb_control_transfer(h, 0x40, 0xA0, (program_entry & 0x0000ffff ) , program_entry >> 16, NULL, 0, 1000);
if ( r ) {
printf("Ignored error in control_transfer: %d\n", r);
}
close(fd);
return 0;
}
/*[]*/