/*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2002 David Brownell (dbrownell@users.sourceforge.net)
* Copyright (c) 2008 Roger Williams (rawqux@users.sourceforge.net)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ident "$Id: main.c,v 1.10 2008/10/13 21:25:29 dbrownell Exp $"
/*
* This program supports loading firmware into a target USB device
* that is discovered and referenced by the hotplug usb agent. It can
* also do other useful things, like set the permissions of the device
* and create a symbolic link for the benefit of applications that are
* looking for the device.
*
* -I <path> -- Download this firmware (intel hex)
* -t <type> -- uController type: an21, fx, fx2, fx2lp
* -s <path> -- use this second stage loader
* -c <byte> -- Download to EEPROM, with this config byte
*
* -L <path> -- Create a symbolic link to the device.
* -m <mode> -- Set the permissions on the device after download.
* -D <path> -- Use this device, instead of $DEVICE
*
* -V -- Print version ID for program
*
* This program is intended to be started by hotplug scripts in
* response to a device appearing on the bus. It therefore also
* expects these environment variables which are passed by hotplug to
* its sub-scripts:
*
* DEVICE=<path>
* This is the path to the device is /proc/bus/usb. It is the
* complete path to the device, that I can pass to open and
* manipulate as a USB device.
*/
# include <stdlib.h>
# include <stdio.h>
# include <getopt.h>
# include <string.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include "ezusb.h"
#ifndef FXLOAD_VERSION
# define FXLOAD_VERSION (__DATE__ " (development)")
#endif
#include <errno.h>
#include <syslog.h>
#include <stdarg.h>
static int dosyslog=0;
void logerror(const char *format, ...)
__attribute__ ((format (__printf__, 1, 2)));
void logerror(const char *format, ...)
{
va_list ap;
va_start(ap, format);
if(dosyslog)
vsyslog(LOG_ERR, format, ap);
else
vfprintf(stderr, format, ap);
va_end(ap);
}
int main(int argc, char*argv[])
{
const char *link_path = 0;
const char *ihex_path = 0;
const char *device_path = getenv("DEVICE");
const char *type = 0;
const char *stage1 = 0;
mode_t mode = 0;
int opt;
int config = -1;
while ((opt = getopt (argc, argv, "2vV?D:I:L:c:lm:s:t:")) != EOF)
switch (opt) {
case '2': // original version of "-t fx2"
type = "fx2";
break;
case 'D':
device_path = optarg;
break;
case 'I':
ihex_path = optarg;
break;
case 'L':
link_path = optarg;
break;
case 'V':
puts (FXLOAD_VERSION);
return 0;
case 'c':
config = strtoul (optarg, 0, 0);
if (config < 0 || config > 255) {
logerror("illegal config byte: %s\n", optarg);
goto usage;
}
break;
case 'l':
openlog(argv[0], LOG_CONS|LOG_NOWAIT|LOG_PERROR, LOG_USER);
dosyslog=1;
break;
case 'm':
mode = strtoul(optarg,0,0);
mode &= 0777;
break;
case 's':
stage1 = optarg;
break;
case 't':
if (strcmp (optarg, "an21") // original AnchorChips parts
&& strcmp (optarg, "fx") // updated Cypress versions
&& strcmp (optarg, "fx2") // Cypress USB 2.0 versions
&& strcmp (optarg, "fx2lp") // updated FX2
) {
logerror("illegal microcontroller type: %s\n", optarg);
goto usage;
}
type = optarg;
break;
case 'v':
verbose++;
break;
case '?':
default:
goto usage;
}
if (config >= 0) {
if (type == 0) {
logerror("must specify microcontroller type %s",
"to write EEPROM!\n");
goto usage;
}
if (!stage1 || !ihex_path) {
logerror("need 2nd stage loader and firmware %s",
"to write EEPROM!\n");
goto usage;
}
if (link_path || mode) {
logerror("links and modes not set up when writing EEPROM\n");
goto usage;
}
}
if (!device_path) {
logerror("no device specified!\n");
usage:
fputs ("usage: ", stderr);
fputs (argv [0], stderr);
fputs (" [-vV] [-l] [-t type] [-D devpath]\n", stderr);
fputs ("\t\t[-I firmware_hexfile] ", stderr);
fputs ("[-s loader] [-c config_byte]\n", stderr);
fputs ("\t\t[-L link] [-m mode]\n", stderr);
fputs ("... [-D devpath] overrides DEVICE= in env\n", stderr);
fputs ("... device types: one of an21, fx, fx2, fx2lp\n", stderr);
fputs ("... at least one of -I, -L, -m is required\n", stderr);
return -1;
}
if (ihex_path) {
int fd = open(device_path, O_RDWR);
int status;
int fx2;
if (fd == -1) {
logerror("%s : %s\n", strerror(errno), device_path);
return -1;
}
if (type == 0) {
type = "fx"; /* an21-compatible for most purposes */
fx2 = 0;
} else if (strcmp (type, "fx2lp") == 0)
fx2 = 2;
else
fx2 = (strcmp (type, "fx2") == 0);
if (verbose)
logerror("microcontroller type: %s\n", type);
if (stage1) {
/* first stage: put loader into internal memory */
if (verbose)
logerror("1st stage: load 2nd stage loader\n");
status = ezusb_load_ram (fd, stage1, fx2, 0);
if (status != 0)
return status;
/* second stage ... write either EEPROM, or RAM. */
if (config >= 0)
status = ezusb_load_eeprom (fd, ihex_path, type, config);
else
status = ezusb_load_ram (fd, ihex_path, fx2, 1);
if (status != 0)
return status;
} else {
/* single stage, put into internal memory */
if (verbose)
logerror("single stage: load on-chip memory\n");
status = ezusb_load_ram (fd, ihex_path, fx2, 0);
if (status != 0)
return status;
}
/* some firmware won't renumerate, but typically it will.
* link and chmod only make sense without renumeration...
*/
}
if (link_path) {
int rc = unlink(link_path);
rc = symlink(device_path, link_path);
if (rc == -1) {
logerror("%s : %s\n", strerror(errno), link_path);
return -1;
}
}
if (mode != 0) {
int rc = chmod(device_path, mode);
if (rc == -1) {
logerror("%s : %s\n", strerror(errno), link_path);
return -1;
}
}
if (!ihex_path && !link_path && !mode) {
logerror("missing request! (firmware, link, or mode)\n");
return -1;
}
return 0;
}
/*
* $Log: main.c,v $
* Revision 1.10 2008/10/13 21:25:29 dbrownell
* Whitespace fixes.
*
* Revision 1.9 2008/10/13 21:23:23 dbrownell
* From Roger Williams <roger@qux.com>: FX2LP support
*
* Revision 1.8 2005/01/11 03:58:02 dbrownell
* From Dirk Jagdmann <doj@cubic.org>: optionally output messages to
* syslog instead of stderr.
*
* Revision 1.7 2002/04/12 00:28:22 dbrownell
* support "-t an21" to program EEPROMs for those microcontrollers
*
* Revision 1.6 2002/04/02 05:26:15 dbrownell
* version display now noiseless (-V);
* '-?' (usage info) convention now explicit
*
* Revision 1.5 2002/02/26 20:10:28 dbrownell
* - "-s loader" option for 2nd stage loader
* - "-c byte" option to write EEPROM with 2nd stage
* - "-V" option to dump version code
*
* Revision 1.4 2002/01/17 14:19:28 dbrownell
* fix warnings
*
* Revision 1.3 2001/12/27 17:54:04 dbrownell
* forgot an important character :)
*
* Revision 1.2 2001/12/27 17:43:29 dbrownell
* fail on firmware download errors; add "-v" flag
*
* Revision 1.1 2001/06/12 00:00:50 stevewilliams
* Added the fxload program.
* Rework root makefile and hotplug.spec to install in prefix
* location without need of spec file for install.
*
*/