blob: 7c0a7f8736d9e5577a19148b8d087c1273dc2ee9 [file] [log] [blame]
/*
* Copyright 2012-2015 Google Inc.
*
* 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; version 2 of the License.
*
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <unistd.h>
#include <libusb.h>
#define BULK_SEND_TIMEOUT 5000 /* sentinel value */
/* SPI flash chips parameters definition */
#include "em100pro_chips.h"
volatile int do_exit_flag = 0;
void exit_handler(int sig) {
do_exit_flag = 1;
}
struct em100 {
libusb_device_handle *dev;
libusb_context *ctx;
uint16_t mcu;
uint16_t fpga;
uint32_t serialno;
};
struct em100_hold_pin_states {
const char *description;
int value;
};
static const struct em100_hold_pin_states hold_pin_states[] = {
{ "FLOAT", 0x2 },
{ "LOW", 0x0 },
{ "INPUT", 0x3 },
{ NULL, 0x0 },
};
/* USB communication */
static int send_cmd(libusb_device_handle *dev, void *data)
{
int actual;
int length = 16; /* haven't seen any other length yet */
libusb_bulk_transfer(dev, 1 | LIBUSB_ENDPOINT_OUT, data, length, &actual, BULK_SEND_TIMEOUT);
return (actual == length);
}
static int get_response(libusb_device_handle *dev, void *data, int length)
{
int actual;
libusb_bulk_transfer(dev, 2 | LIBUSB_ENDPOINT_IN, data, length, &actual, BULK_SEND_TIMEOUT);
return actual;
}
/* System level operations */
/**
* get_version: fetch firmware version information
* @param em100: initialized em100 device structure
*
* out(16 bytes): 0x10 0 .. 0
* in(len + 4 bytes): 0x04 fpga_major fpga_minor mcu_major mcu_minor
*/
static int get_version(struct em100 *em100)
{
unsigned char cmd[16];
unsigned char data[512];
memset(cmd, 0, 16);
cmd[0] = 0x10; /* version */
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
int len = get_response(em100->dev, data, 512);
if ((len == 5) && (data[0] == 4)) {
em100->mcu = (data[3] << 8) | data[4];
em100->fpga = (data[1] << 8) | data[2];
return 1;
}
return 0;
}
typedef enum {
out_trigger_vcc = 0,
out_reset_vcc = 1,
out_ref_plus = 2,
out_ref_minus = 3,
out_buffer_vcc = 4
} set_voltage_channel_t;
static int set_voltage(struct em100 *em100, set_voltage_channel_t channel, int mV)
{
unsigned char cmd[16];
if ((channel == out_buffer_vcc) &&
(mV != 18 && mV != 25 && mV != 33)) {
printf("Error: For Buffer VCC, voltage needs to be 1.8V, 2.5V or 3.3V.\n");
return 0;
}
memset(cmd, 0, 16);
cmd[0] = 0x11; /* set voltage */
cmd[1] = channel;
cmd[2] = mV >> 8;
cmd[3] = mV & 0xff;
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
return 1;
}
typedef enum {
in_v1_2 = 0,
in_e_vcc = 1,
in_ref_plus = 2,
in_ref_minus = 3,
in_buffer_vcc = 4,
in_trigger_vcc = 5,
in_reset_vcc = 6,
in_v3_3 = 7,
in_buffer_v3_3 = 8,
in_v5 = 9
} get_voltage_channel_t;
static int get_voltage(struct em100 *em100, get_voltage_channel_t channel)
{
unsigned char cmd[16];
unsigned char data[512];
int voltage = 0;
memset(cmd, 0, 16);
cmd[0] = 0x12; /* measure voltage */
cmd[1] = channel;
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
int len = get_response(em100->dev, data, 512);
if ((len == 3) && (data[0] == 2)) {
voltage = (data[1] << 8) + data[2];
return voltage;
}
return 0;
}
typedef enum {
both_off = 0,
red_on = 1,
green_on = 2,
both_on = 3
} led_state_t;
static int set_led(struct em100 *em100, led_state_t led_state)
{
unsigned char cmd[16];
memset(cmd, 0, 16);
cmd[0] = 0x13; /* set LED */
cmd[1] = led_state;
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
return 1;
}
/* FPGA related operations */
/**
* reconfig_fpga: Reconfigures FPGA after a change(?)
* @param em100: initialized em100 device structure
*
* out(16 bytes): 0x20 0 .. 0
*/
static int reconfig_fpga(struct em100 *em100)
{
unsigned char cmd[16];
memset(cmd, 0, 16);
cmd[0] = 0x20; /* reconfig FPGA */
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
/* Specification says to wait 2s before
* issuing another USB command
*/
sleep(2);
return 1;
}
/**
* check_fpga_status: Checkl FPGA configuration status
* @param em100: initialized em100 device structure
*
* out(16 bytes): 0x21 0 .. 0
* in(result): pass: 1, fail: 0
*/
static int check_fpga_status(struct em100 *em100)
{
unsigned char cmd[16];
unsigned char data[512];
printf("FPGA configuration status: ");
memset(cmd, 0, 16);
cmd[0] = 0x21; /* Check FPGA status */
if (!send_cmd(em100->dev, cmd)) {
printf("Unknown\n");
return 0;
}
int len = get_response(em100->dev, data, 512);
if (len == 1) {
printf("%s\n", data[0] == 1 ? "PASS" : "FAIL");
return 1;
}
printf("Unknown\n");
return 0;
}
/**
* read_fpga_register: Read FPGA registers
* @param em100: initialized em100 device structure
* @param reg: FPGA register to write
* @param val: pointer to value
*
* out(2 bytes): 0x22 RegAddr .. 0
* in(len + 2 bytes): 0x02 val val
*/
static int read_fpga_register(struct em100 *em100, int reg, uint16_t *val)
{
unsigned char cmd[16];
unsigned char data[256];
memset(cmd, 0, 16);
cmd[0] = 0x22; /* Read FPGA register */
cmd[1] = reg;
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
int len = get_response(em100->dev, data, 3);
if ((len == 3) && (data[0] == 2)) {
*val = (data[1] << 8) + data[2];
return 1;
}
return 0;
}
/**
* write_fpga_register: Write FPGA registers
* @param em100: initialized em100 device structure
*
* out(4 bytes): 0x23 RegAddr Val Val .. 0
*/
static int write_fpga_register(struct em100 *em100, int reg, int val)
{
unsigned char cmd[16];
memset(cmd, 0, 16);
cmd[0] = 0x23; /* Write FPGA register */
cmd[1] = reg;
cmd[2] = val >> 8;
cmd[3] = val & 0xff;
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
return 1;
}
/* SPI flash related operations */
static int get_spi_flash_id(struct em100 *em100)
{
unsigned char cmd[16];
unsigned char data[512];
memset(cmd, 0, 16);
cmd[0] = 0x30; /* Get SPI flash ID */
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
int len = get_response(em100->dev, data, 512);
if (len == 3) {
int id = (data[0] << 16) | (data[1] << 8) | data[2];
return id;
}
return 0;
}
static int erase_spi_flash(struct em100 *em100)
{
unsigned char cmd[16];
memset(cmd, 0, 16);
cmd[0] = 0x31; /* Erase SPI flash */
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
/* Specification says to wait 5s before
* issuing another USB command
*/
sleep(5);
return 1;
}
static int poll_spi_flash_status(struct em100 *em100)
{
unsigned char cmd[16];
unsigned char data[1];
memset(cmd, 0, 16);
cmd[0] = 0x32; /* Poll SPI flash status */
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
int len = get_response(em100->dev, data, 1);
if ((len == 1) && (data[0] == 1)) {
/* ready */
return 1;
}
/* busy (or read unsuccessful) */
return 0;
}
/**
* read_spi_flash_page: fetch SPI flash page
* @param em100: initialized em100 device structure
*
* out(16 bytes): 0x33 addr addr addr .. 0
* in(len + 255 bytes): 0xff ?? serno_lo serno_hi ?? ?? .. ??
*/
static int read_spi_flash_page(struct em100 *em100, int addr, unsigned char *blk)
{
unsigned char cmd[16];
unsigned char data[256];
memset(cmd, 0, 16);
cmd[0] = 0x33; /* read configuration block */
cmd[1] = (addr >> 16) & 0xff;
cmd[2] = (addr >> 8) & 0xff;
cmd[3] = addr & 0xff;
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
int len = get_response(em100->dev, data, 256);
if (len == 256) {
memcpy(blk, data, 256);
return 1;
}
return 0;
}
static int write_spi_flash_page(libusb_device_handle *dev, unsigned char *data, int address)
{
int length = 256;
int actual;
int bytes_sent=0;
int bytes_left;
unsigned char cmd[16];
memset(cmd, 0, 16);
cmd[0] = 0x34; /* host-to-em100 eeprom data */
cmd[2] = (address >> 16) & 0xff;
cmd[3] = (address >> 8) & 0xff;
cmd[4] = address & 0xff;
if (!send_cmd(dev, cmd)) {
printf("error initiating host-to-em100 transfer.\n");
return 0;
}
while ( bytes_sent < length) {
actual = 0;
bytes_left = length - bytes_sent;
libusb_bulk_transfer(dev, 1 | LIBUSB_ENDPOINT_OUT,
data + bytes_sent, bytes_left, &actual, BULK_SEND_TIMEOUT);
bytes_sent += actual;
if (actual < bytes_left) {
printf("Tried sending %d bytes, sent %d\n", bytes_left, actual);
break;
}
printf("Sent %d bytes of %d\n", bytes_sent, length);
}
printf ("Transfer %s\n",bytes_sent == length ? "Succeeded" : "Failed");
return (bytes_sent == length);
}
/* SDRAM related operations */
static int read_sdram(struct em100 *em100, void *data, int address, int length)
{
int actual;
int transfer_length = 0x200000;
int bytes_read=0;
int bytes_left;
int bytes_to_read;
unsigned char cmd[16];
memset(cmd, 0, 16);
cmd[0] = 0x41; /* em100-to-host eeprom data */
cmd[1] = (address >> 24) & 0xff;
cmd[2] = (address >> 16) & 0xff;
cmd[3] = (address >> 8) & 0xff;
cmd[4] = address & 0xff;
cmd[5] = (length >> 24) & 0xff;
cmd[6] = (length >> 16) & 0xff;
cmd[7] = (length >> 8) & 0xff;
cmd[8] = length & 0xff;
if (!send_cmd(em100->dev, cmd)) {
printf("error initiating host-to-em100 transfer.\n");
return 0;
}
while (bytes_read < length) {
actual = 0;
bytes_left = length - bytes_read;
bytes_to_read = (bytes_left < transfer_length) ?
bytes_left : transfer_length;
libusb_bulk_transfer(em100->dev, 2 | LIBUSB_ENDPOINT_IN,
data + bytes_read, bytes_to_read,
&actual, BULK_SEND_TIMEOUT);
bytes_read += actual;
if (actual < bytes_to_read) {
printf("tried reading %d bytes, got %d\n",
bytes_to_read, actual);
break;
}
printf("Read %d bytes of %d\n", bytes_read, length);
}
return (bytes_read == length);
}
static int write_sdram(struct em100 *em100, unsigned char *data, int address, int length)
{
int actual;
int transfer_length = 0x200000;
int bytes_sent=0;
int bytes_left;
int bytes_to_send;
unsigned char cmd[16];
memset(cmd, 0, 16);
cmd[0] = 0x40; /* host-to-em100 eeprom data */
cmd[1] = (address >> 24) & 0xff;
cmd[2] = (address >> 16) & 0xff;
cmd[3] = (address >> 8) & 0xff;
cmd[4] = address & 0xff;
cmd[5] = (length >> 24) & 0xff;
cmd[6] = (length >> 16) & 0xff;
cmd[7] = (length >> 8) & 0xff;
cmd[8] = length & 0xff;
if (!send_cmd(em100->dev, cmd)) {
printf("error initiating host-to-em100 transfer.\n");
return 0;
}
while ( bytes_sent < length) {
actual = 0;
bytes_left = length - bytes_sent;
bytes_to_send = (bytes_left < transfer_length) ? bytes_left : transfer_length;
libusb_bulk_transfer(em100->dev, 1 | LIBUSB_ENDPOINT_OUT,
data + bytes_sent, bytes_to_send, &actual, BULK_SEND_TIMEOUT);
bytes_sent += actual;
if (actual < bytes_to_send) {
printf("Tried sending %d bytes, sent %d\n", bytes_to_send, actual);
break;
}
printf("Sent %d bytes of %d\n", bytes_sent, length);
}
printf ("Transfer %s\n",bytes_sent == length ? "Succeeded" : "Failed");
return (bytes_sent == length);
}
/* SPI HyperTerminal related operations */
/**
* read_ht_register: Read HT registers
* @param em100: initialized em100 device structure
*
* out(2 bytes): 0x50 RegAddr .. 0
* in(len + 1 byte): 0x02 val
*/
static int read_ht_register(struct em100 *em100, int reg, uint8_t *val)
{
unsigned char cmd[16];
unsigned char data[2];
memset(cmd, 0, 16);
cmd[0] = 0x50; /* read fpga register */
cmd[1] = reg;
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
int len = get_response(em100->dev, data, 2);
if ((len == 2) && (data[0] == 1)) {
*val = data[1];
return 1;
}
return 0;
}
/**
* write_ht_register: Write HT registers
* @param em100: initialized em100 device structure
*
* out(3 bytes): 0x51 RegAddr Val .. 0
*/
static int write_ht_register(struct em100 *em100, int reg, uint8_t val)
{
unsigned char cmd[16];
memset(cmd, 0, 16);
cmd[0] = 0x51; /* write fpga registers */
cmd[1] = reg;
cmd[2] = val;
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
return 1;
}
/* SPI Trace related operations */
/**
* reset_spi_trace: clear SPI trace buffer
* @param em100: em100 device structure
*
* out(16 bytes): 0xbd 0 .. 0
*/
static int reset_spi_trace(struct em100 *em100)
{
unsigned char cmd[16];
memset(cmd, 0, 16);
cmd[0] = 0xbd; /* reset SPI trace buffer*/
if (!send_cmd(em100->dev, cmd)) {
return 0;
}
return 1;
}
/**
* read_spi_trace: fetch SPI trace data
* @param em100: em100 device structure
* globals: curpos, counter, cmdid
*
* out(16 bytes): bc 00 00 00 08 00 00 00 00 15 00 00 00 00 00 00
* in(8x8192 bytes): 2 bytes (BE) number of records (0..0x3ff),
* then records of 8 bytes each
*/
unsigned int counter = 0;
unsigned char curpos = 0;
unsigned char cmdid = 0xff; // timestamp, so never a valid command id
static int read_spi_trace(struct em100 *em100)
{
unsigned char cmd[16];
unsigned char data[8192];
unsigned int count, i, report;
memset(cmd, 0, 16);
cmd[0] = 0xbc; /* read SPI trace buffer*/
cmd[4] = 0x08; /* cmd1..cmd4 are probably u32BE on how many
reports (8192 bytes each) to fetch */
cmd[9] = 0x15; /* no idea */
if (!send_cmd(em100->dev, cmd)) {
printf("sending trace command failed\n");
return 0;
}
for (report = 0; report < 8; report++) {
memset(data, 0, sizeof(data));
int len = get_response(em100->dev, data, sizeof(data));
if (len != sizeof(data)) {
/* FIXME: handle error: device reset? */
printf("error, len = %d instead of %zd. bailing out\n\n", len, sizeof(data));
return 0;
}
count = (data[0] << 8) | data[1];
for (i = 0; i < count; i++) {
unsigned int j;
unsigned char cmd = data[2 + i*8];
if (cmd == 0xff) {
/* timestamp */
unsigned long long timestamp = 0;
timestamp = data[2 + i*8 + 2];
timestamp = (timestamp << 8) | data[2 + i*8 + 3];
timestamp = (timestamp << 8) | data[2 + i*8 + 4];
timestamp = (timestamp << 8) | data[2 + i*8 + 5];
timestamp = (timestamp << 8) | data[2 + i*8 + 6];
timestamp = (timestamp << 8) | data[2 + i*8 + 7];
printf("\ntimestamp: %lld.%lld", timestamp / 100000000, timestamp % 100000000);
continue;
}
#if 0
printf("{(%d)", curpos);
for (j = 0; j < 8; j++) {
printf("%02x ", data[2 + i*8 + j]);
}
printf("}");
#endif
/* from here, it must be data */
if (cmd != cmdid) {
/* new command */
cmdid = cmd;
printf("\nspi command %6d: ", ++counter);
curpos = 0;
}
/* this exploits 8bit wrap around in curpos */
unsigned char blocklen = (data[2 + i*8 + 1] - curpos);
blocklen /= 8;
for (j = 0; j < blocklen; j++) {
printf("%02x ", data[2 + i*8 + 2 + j]);
}
curpos = data[2 + i*8 + 1] + 0x10; // this is because the em100 counts funny
}
}
return 1;
}
/* High Level functions */
static int set_state(struct em100 *em100, int run)
{
return write_fpga_register(em100, 0x28, run & 1);
}
static int set_hold_pin_state(struct em100 *em100, int pin_state)
{
uint16_t val;
/* Read and acknowledge hold pin state setting bit 2 of pin state respone. */
if (!read_fpga_register(em100, 0x2a, &val)) {
printf("Couldn't get hold pin state.\n");
return 0;
}
write_fpga_register(em100, 0x2a, (1 << 2) | val);
if (!read_fpga_register(em100, 0x2a, &val)) {
printf("Couldn't get hold pin state.\n");
return 0;
}
/* Now set desired pin state. */
write_fpga_register(em100, 0x2a, pin_state);
/* Read the pin state. */
if (!read_fpga_register(em100, 0x2a, &val)) {
printf("Couldn't get hold pin state.\n");
return 0;
}
if (val != pin_state) {
printf("Invalid pin state response: 0x%04x (expected 0x%04x)\n",
val, pin_state);
return 0;
}
return 1;
}
static int set_hold_pin_state_from_str(struct em100 *em100, const char *state)
{
int pin_state;
const struct em100_hold_pin_states *s = &hold_pin_states[0];
while (s->description != NULL) {
if (!strcmp(s->description, state))
break;
s++;
}
if (s->description == NULL) {
printf("Invalid hold pin state: %s\n", state);
return 0;
}
pin_state = s->value;
return set_hold_pin_state(em100, pin_state);
}
/**
* get_serialno: fetch device's serial number
* @param em100: initialized em100 device structure
*/
static int get_serialno(struct em100 *em100)
{
unsigned char data[256];
if (read_spi_flash_page(em100, 0x1fff00, data)) {
em100->serialno = (data[5] << 24) | (data[4] << 16) | \
(data[3] << 8) | data[2];
return 1;
}
return 0;
}
static int check_status(struct em100 *em100)
{
int spi_flash_id;
spi_flash_id = get_spi_flash_id(em100);
if (spi_flash_id == 0x202015)
return 1;
return 0;
}
static int em100_attach(struct em100 *em100)
{
libusb_device **devs;
libusb_device_handle *dev;
libusb_context *ctx = NULL;
if (libusb_init(&ctx) < 0) {
printf("Could not init libusb.\n");
return 0;
}
libusb_set_debug(ctx, 3);
if (libusb_get_device_list(ctx, &devs) < 0) {
printf("Could not find USB devices.\n");
return 0;
}
dev = libusb_open_device_with_vid_pid(ctx, 0x4b4, 0x1235);
if (!dev) {
printf("Could not find em100pro.\n");
return 0;
}
libusb_free_device_list(devs, 1);
if (libusb_kernel_driver_active(dev, 0) == 1) {
if (libusb_detach_kernel_driver(dev, 0) != 0) {
printf("Could not detach kernel driver.\n");
return 0;
}
}
if (libusb_claim_interface(dev, 0) < 0) {
printf("Could not claim interface.\n");
return 0;
}
em100->dev = dev;
em100->ctx = ctx;
if (!check_status(em100)) {
printf("Device status unknown.\n");
return 0;
}
if (!get_version(em100)) {
printf("Failed fetching version information.\n");
return 0;
}
if (!get_serialno(em100)) {
printf("Failed fetching serial number.\n");
return 0;
}
return 1;
}
static int em100_detach(struct em100 *em100)
{
if (libusb_release_interface(em100->dev, 0) != 0) {
printf("releasing interface failed.\n");
return 1;
}
libusb_close(em100->dev);
libusb_exit(em100->ctx);
return 0;
}
static int set_chip_type(struct em100 *em100, const chipdesc *desc)
{
unsigned char cmd[16];
/* result counts unsuccessful send_cmd()s.
* These are then converted in a boolean success value
*/
int result = 0;
int i;
printf("Sending flash chip configuration\n");
memset(cmd, 0, 16);
for (i = 0; i < desc->init_len; i++) {
memcpy(&cmd[0], &desc->init[i][0], BYTES_PER_INIT_ENTRY);
result += !send_cmd(em100->dev, cmd);
}
return !result;
}
static const struct option longopts[] = {
{"set", 1, 0, 'c'},
{"download", 1, 0, 'd'},
{"start", 0, 0, 'r'},
{"stop", 0, 0, 's'},
{"verify", 0, 0, 'v'},
{"holdpin", 1, 0, 'p'},
{"help", 0, 0, 'h'},
{NULL, 0, 0, 0}
};
static void usage(void)
{
printf("em100: em100 client utility\n\n"
"-c CHIP|--set CHIP: select CHIP emulation\n"
"-d[ownload] FILE: upload FILE into em100\n"
"-r|--start: em100 shall run\n"
"-s|--stop: em100 shall stop\n"
"-v|--verify: verify EM100 content matches the file\n"
"-p|--holdpin [LOW|FLOAT|INPUT]: set the hold pin state\n"
"-h|--help: this help text\n");
}
/* get MCU and FPGA version, *100 encoded */
int main(int argc, char **argv)
{
int opt, idx;
const char *desiredchip = NULL;
const char *filename = NULL;
const char *holdpin = NULL;
int do_start = 0, do_stop = 0;
int verify = 0, trace = 0;
while ((opt = getopt_long(argc, argv, "c:d:p:rsvht",
longopts, &idx)) != -1) {
switch (opt) {
case 'c':
desiredchip = optarg;
break;
case 'd':
filename = optarg;
/* TODO: check that file exists */
break;
case 'p':
holdpin = optarg;
break;
case 'r':
do_start = 1;
break;
case 's':
do_stop = 1;
break;
case 'v':
verify = 1;
break;
case 't':
trace = 1;
break;
case 'h':
usage();
return 0;
}
}
const chipdesc *chip = chips;
if (desiredchip) {
do {
if (strcmp(desiredchip, chip->name) == 0) {
printf("will emulate '%s'\n", chip->name);
break;
}
} while ((++chip)->name);
if (chip->name == NULL) {
printf("Supported chips:\n");
chip = chips;
do {
printf("%s ", chip->name);
} while ((++chip)->name);
printf("\n\nCould not find emulation for '%s'.\n", desiredchip);
return 1;
}
}
struct em100 em100;
if (!em100_attach(&em100)) {
return 1;
}
printf("MCU version: %d.%02d\n", em100.mcu >> 8, em100.mcu & 0xff);
printf("FPGA version: %d.%02d\n", em100.fpga >> 8, em100.fpga & 0xff);
printf("Serial number: DP%06d\n", em100.serialno);
if (do_stop) {
set_state(&em100, 0);
}
if (desiredchip) {
if (!set_chip_type(&em100, chip)) {
printf("Failed configuring chip type.\n");
return 0;
}
}
if (holdpin) {
if (!set_hold_pin_state_from_str(&em100, holdpin)) {
printf("Failed configuring hold pin state.\n");
return 0;
}
}
if (filename) {
int maxlen = 0x1000000; /* largest size - 16MB */
void *data = malloc(maxlen);
if (data == NULL) {
printf("FATAL: couldn't allocate memory\n");
return 1;
}
FILE *fdata = fopen(filename, "rb");
if (!fdata) {
perror("Could not open upload file");
return 1;
}
int length = 0;
while ((!feof(fdata)) && (length < maxlen)) {
int blocksize = 65536;
length += blocksize * fread(data+length, blocksize, 1, fdata);
}
fclose(fdata);
if (length > maxlen) {
printf("FATAL: length > maxlen\n");
return 1;
}
write_sdram(&em100, (unsigned char *)data, 0x00000000, length);
if (verify) {
int done;
void *readback = malloc(length);
if (data == NULL) {
printf("FATAL: couldn't allocate memory\n");
return 1;
}
done = read_sdram(&em100, readback, 0x00000000, length);
if (done && (memcmp(data, readback, length) == 0))
printf("Verify: PASS\n");
else
printf("Verify: FAIL\n");
free(readback);
}
free(data);
}
if (do_start) {
set_state(&em100, 1);
}
if (trace) {
struct sigaction signal_action;
if (!set_hold_pin_state(&em100, 3)) {
printf("failed to set em100 to input\n");
return 1;
}
set_state(&em100, 1);
reset_spi_trace(&em100);
signal_action.sa_handler = exit_handler;
signal_action.sa_flags = 0;
sigemptyset(&signal_action.sa_mask);
sigaction(SIGINT, &signal_action, NULL);
while (!do_exit_flag) {
read_spi_trace(&em100);
}
set_state(&em100, 0);
reset_spi_trace(&em100);
if (!set_hold_pin_state(&em100, 2)) {
printf("failed to set em100 to float\n");
return 1;
}
}
return em100_detach(&em100);
}