On Fri, Jun 17, 2011 at 4:39 PM, Mike Frysinger <[email protected]> wrote:
> On Friday, June 17, 2011 16:09:47 Jie Zhang wrote:
>> On Fri, Jun 17, 2011 at 1:58 PM, Mike Frysinger wrote:
>> >> +static int get_hex_digit (char *p)
>> >> +static int get_hex_byte (char *p)
>> >> +static int get_hex_half_word (char *p)
>> >
>> > these look like useful utility funcs that should probably go into common
>> > code. and rather than use "byte" and "half_word", let's use "u8" and
>> > "u16".
>>
>> Can we not do this until there is such requirement from other parts of
>> UrJTAG? I want to keep as many functions static as possible.
>
> the problem is that people wont notice them.  no one is going to read through
> the ADI ICE cable driver looking for util funcs that are applicable to them.
> they will however look at the urjtag headers to see what is already done for
> them to leverage.
>
OK. I have posted a patch to import hex.c from libiberty since we
already has libiberty.h. I modified the firmware updater to use the
functions and macros provided by hex.c. There is no need for these
three functions now.

>> > the "p" arg needs to be constified
>> >
>> >> +    hex_file = fopen (filename, "r");
>> >
>> > probably just paranoid, but should use "rbe"
>>
>> Why?
>
> "b" is needed for proper operation in Windows, and "e" is to keep fd's leaking
> into forked processes
>
Thank you.

>> >> +  urj_log (URJ_LOG_LEVEL_ERROR, _("Open file %s failed\n"), filename);
>> >
>> > should use IO level so the errno is included in the output ?
>>
>> There is no IO level. You might meant URJ_ERROR_IO. But using
>> urj_error_set here might not be good since the error will be discarded
>> deliberately in some cases.
>
> in what cases ?  ice_update_firmware() is only called in one place, and that's
> in the cable's init func.  if that fails, the init func should fail.  and no
> errors get discarded at that point.
>
> which also points out that the current init code doesnt check the return value
> of ice_update_firmware() ...
>
It was a mess. I considered how to deal with the error messages again
and now it uses the error mechanism of UrJTAG.

>> >> +  q = (struct flash_block *) malloc (sizeof (struct flash_block));
>> >
>> > no need for the cast, and i'd use sizeof (*q)
>>
>> OK. Seems I'm still living in old days.
>
> it's needed in C++ code, but that's not what urjtag is written in :)
>
malloc returned "char *" in old days.

>> >> +    const char *ex_short = "[firmware=FILE]";
>> >> +    const char *ex_desc = "FILE       Upgrade the ICE firmware.  See
>> >> this
>> >
>> > page:\n"
>> >
>> > const char foo[] = "..."
>>
>> Why?
>
> one less pointer.  compare the assembly output:
> $ echo 'const char foo[] = "asdf";' | gcc -S -o - -x c -
> $ echo 'const char *foo = "asdf";' | gcc -S -o - -x c -
>
But when it's passed as an argument, the former will pass the whole
string but the latter will only pass a pointer.

The new patch is attached. It's based on the hex.c patch I posted
earlier. It also addressed all your comments I agreed in my last
reply.

I also found I forgot to reply your comment on extracting the CRC
function. There are many kinds of CRC algorithms. So even in future
another part of UrJTAG uses a CRC function, it might use a different
one. So I still prefer to keep it in ice100b.c.


Regards,
Jie
  * include/urjtag/cable.h (urj_cable_param_key_t): Add
    URJ_CABLE_PARAM_KEY_FIRMWARE.
  * src/tap/cable.c (cable_param[]): Add URJ_CABLE_PARAM_KEY_FIRMWARE.
  * src/tap/cable/ice100.c: Include "libiberty.h".
    (params_t): Add firmware_filename.
    (HOST_PROGRAM_FLASH): Define.
    (ICE100B_DOC_URL): Define.
    (adi_usb_read_or_ret): Use urj_error_IO_set.
    (adi_usb_write_or_ret): Likewise.
    (struct flash_block): Define.
    (NIBBLE): Define.
    (HEX2): Define.
    (HEX4): Define.
    (ISHEX): Define.
    (ISHEX2): Define.
    (ISHEX4): Define.
    (ice_read_hex_file): New.
    (ice_calculate_crc): New.
    (ice_send_flash_data): New.
    (ice_firmware_crc): New.
    (ice_update_firmware): New.
    (ice_connect): Handle firmware parameter.
    (kit_10_connect): Initialize firmware_filename to NULL.
    (kit_20_connect): Likewise.
    (ice_init): Add firmware updater.
    (ice_cable_free): Free firmware_filename.
    (ice_cable_help): New.
    (urj_tap_cable_ice100B_driver): Use ice_cable_help.
    Add Emacs file local variables.


Index: include/urjtag/cable.h
===================================================================
--- include/urjtag/cable.h.orig	2011-06-23 16:56:35.000000000 -0400
+++ include/urjtag/cable.h	2011-06-23 16:59:43.000000000 -0400
@@ -64,6 +64,7 @@
     URJ_CABLE_PARAM_KEY_TMS,            /* lu           gpio used as TMS */
     URJ_CABLE_PARAM_KEY_TCK,            /* lu           gpio used as TCK */
     URJ_CABLE_PARAM_KEY_INTERFACE,      /* lu           ftdi */
+    URJ_CABLE_PARAM_KEY_FIRMWARE,       /* string       ice100 */
 }
 urj_cable_param_key_t;
 
Index: src/tap/cable.c
===================================================================
--- src/tap/cable.c.orig	2011-06-23 16:56:35.000000000 -0400
+++ src/tap/cable.c	2011-06-23 16:59:43.000000000 -0400
@@ -673,6 +673,7 @@
     { URJ_CABLE_PARAM_KEY_TMS,          URJ_PARAM_TYPE_LU,      "tms", },
     { URJ_CABLE_PARAM_KEY_TCK,          URJ_PARAM_TYPE_LU,      "tck", },
     { URJ_CABLE_PARAM_KEY_INTERFACE,    URJ_PARAM_TYPE_LU,      "interface", },
+    { URJ_CABLE_PARAM_KEY_FIRMWARE,     URJ_PARAM_TYPE_STRING,  "firmware", },
 };
 
 const urj_param_list_t urj_cable_param_list =
Index: src/tap/cable/ice100.c
===================================================================
--- src/tap/cable/ice100.c.orig	2011-06-23 16:56:35.000000000 -0400
+++ src/tap/cable/ice100.c	2011-06-23 16:59:43.000000000 -0400
@@ -33,6 +33,8 @@
 #include <urjtag/chain.h>
 #include <urjtag/cmd.h>
 
+#include "libiberty.h"
+
 #include "generic.h"
 #include "generic_usbconn.h"
 
@@ -93,6 +95,7 @@
     uint32_t wr_buf_addr;            /* USB: For Kits */
     uint32_t r_buf_addr;             /* USB: For Kits */
     num_tap_pairs tap_info;          /* For collecting and sending tap scans */
+    char *firmware_filename;         /* The update firmware file name */
 } params_t;
 
 /* Emulators's USB Data structure */
@@ -167,6 +170,7 @@
 #define HOST_GET_SINGLE_REG             0x08    /* set a JTAG register */
 #define HOST_SET_SINGLE_REG             0x09    /* set a JTAG register */
 #define HOST_DO_RAW_SCAN                0x0A    /* do a raw scan */
+#define HOST_PROGRAM_FLASH              0x0C    /* program flash */
 #define HOST_HARD_RESET_JTAG_CTRLR      0x0E    /* do a hard reset on JTAG controller */
 #define    HOST_FAST_MODE               0x10    /* Sets Kits in right mode */
 #define HOST_SC_AUTHENTICATE            0x17    /* Kit 20 */
@@ -214,6 +218,9 @@
 #define BLACKFIN_DATA_BUFFER_OUT_ADDRESS        0xF0006100
 #define BLACKFIN_DATA_BUFFER_IN_ADDRESS         0xF000A000
 
+#define ICE100B_DOC_URL \
+    "http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:ice100b";
+
 /* frequency settings for ice-100b */
 #define MAX_FREQ    4        /* size of freq_set */
 static const uint8_t freq_set[MAX_FREQ]     = { 9, 4, 2, 1 };
@@ -236,10 +243,9 @@
                                   &__actual, cable_params->r_timeout); \
     if (__ret || __actual != __size) \
     { \
-        urj_log (URJ_LOG_LEVEL_ERROR, \
-                 _("%s: unable to read from usb to " #buf ": %i;" \
-                   "wanted %i bytes but only received %i bytes"), \
-                 __func__, __ret, __size, __actual); \
+        urj_error_IO_set (_("%s: unable to read from usb to " #buf ": %i;" \
+                            "wanted %i bytes but only received %i bytes"), \
+                          __func__, __ret, __size, __actual); \
         return URJ_STATUS_FAIL; \
     } \
 } while (0)
@@ -253,10 +259,9 @@
                                   &__actual, cable_params->wr_timeout); \
     if (__ret || __actual != __size) \
     { \
-        urj_log (URJ_LOG_LEVEL_ERROR, \
-                 _("%s: unable to write from " #buf " to usb: %i;" \
-                   "wanted %i bytes but only wrote %i bytes"), \
-                 __func__, __ret, __size, __actual); \
+        urj_error_IO_set (_("%s: unable to write from " #buf " to usb: %i;" \
+                            "wanted %i bytes but only wrote %i bytes"), \
+                          __func__, __ret, __size, __actual); \
         return URJ_STATUS_FAIL; \
     } \
 } while (0)
@@ -395,13 +400,377 @@
     return URJ_STATUS_OK;
 }
 
+struct flash_block
+{
+    uint32_t addr;
+    int bytes;
+    uint8_t *data;
+    struct flash_block *next;
+};
+
+/* Macros for converting between hex and binary.  */
+
+#define NIBBLE(x)      (hex_value (x))
+#define HEX2(buffer)   ((NIBBLE ((buffer)[0]) << 4) + NIBBLE ((buffer)[1]))
+#define HEX4(buffer)   ((HEX2 (buffer) << 8) + HEX2 ((buffer) + 2))
+#define ISHEX(x)       (hex_p (x))
+#define ISHEX2(buffer) (ISHEX ((buffer)[0]) && ISHEX ((buffer)[1]))
+#define ISHEX4(buffer) (ISHEX2 (buffer) && ISHEX2 ((buffer + 2)))
+
+static void
+ice_hex_init (void)
+{
+    static bool inited;
+
+    if (!inited)
+    {
+        inited = true;
+        hex_init ();
+    }
+}
+
+static int
+ice_read_hex_file (const char *filename, struct flash_block **flash_list)
+{
+    FILE *hex_file;
+    char *input_line, *p;
+    size_t len;
+    int lineno, i;
+    bool done = false;
+    struct flash_block *last_flash_block = NULL, *q;
+    int base_address = 0;
+
+    hex_file = fopen (filename, "rbe");
+    if (!hex_file)
+    {
+        urj_error_IO_set (_("Unable to open file `%s'"), filename);
+        return URJ_STATUS_FAIL;
+    }
+
+    ice_hex_init ();
+
+    input_line = NULL;
+    len = 0;
+    lineno = 0;
+    while (getline (&input_line, &len, hex_file) != -1 && !done)
+    {
+        int byte_count, address, record_type, checksum;
+        int sum;
+
+        lineno++;
+        p = input_line;
+        /* A line should contain
+           1. start code : 1 character ':'
+           2. byte count : 2 hex digits
+           3. address    : 4 hex digits
+           4. record type: 2 hex digits
+           5. data       : 2n hex digits
+           6. checksum   : 2 hex digits */
+        if (len < 11)
+        {
+            urj_error_set (URJ_ERROR_FIRMWARE,
+                           _("Line %d is too short in file %s"),
+                           lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+
+        if (*p++ != ':')
+        {
+            urj_error_set (URJ_ERROR_FIRMWARE,
+                           _("Invalid start code on line %d in file %s"),
+                           lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+
+        if (!ISHEX2 (p))
+        {
+            urj_error_set (URJ_ERROR_FIRMWARE,
+                           _("Bad byte count on line %d in file %s"),
+                           lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+        byte_count = HEX2 (p);
+        p += 2;
+        sum = byte_count;
+
+        if (!ISHEX4 (p))
+        {
+            urj_error_set (URJ_ERROR_FIRMWARE,
+                           _("Bad address on line %d in file %s"),
+                           lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+        address = HEX4 (p);
+        p += 4;
+        sum += (address >> 8) + (address & 0xff);
+        sum &= 0xff;
+
+        /* record type */
+        if (!ISHEX2 (p))
+            goto bad_record_type;
+        record_type = HEX2 (p);
+        p += 2;
+        sum += record_type;
+        sum &= 0xff;
+
+        switch (record_type)
+        {
+        case 0:
+            q = last_flash_block;
+
+            if (!q
+                || q->addr + q->bytes != base_address + address)
+            {
+                q = malloc (sizeof (*q));
+                if (!q)
+                {
+                    urj_error_set (URJ_ERROR_OUT_OF_MEMORY,
+                                   _("malloc (%zd) failed"), sizeof (*q));
+                    return URJ_STATUS_FAIL;
+                }
+                q->addr = base_address + address;
+                q->data = NULL;
+                q->bytes = 0;
+                q->next = NULL;
+
+                if (last_flash_block)
+                    last_flash_block->next = q;
+                else
+                    *flash_list = q;
+                last_flash_block = q;
+            }
+
+            q->data = realloc (q->data, q->bytes + byte_count);
+            if (!q->data)
+            {
+                urj_error_set (URJ_ERROR_OUT_OF_MEMORY,
+                               _("realloc (%d) failed"),
+                               q->bytes + byte_count);
+                return URJ_STATUS_FAIL;
+            }
+
+            for (i = 0; i < byte_count; i++)
+            {
+                int data;
+
+                if (!ISHEX2 (p))
+                {
+                    urj_error_set (URJ_ERROR_FIRMWARE,
+                                   _("Bad HEX data %c%c on line %d in file %s"),
+                                   p[0], p[1], lineno, filename);
+                    return URJ_STATUS_FAIL;
+                }
+                data = HEX2 (p);
+                q->data[q->bytes] = data;
+                q->bytes++;
+                p += 2;
+                sum += data;
+            }
+            break;
+
+        case 1:
+            done = true;
+            break;
+
+        case 2:
+            /* fall through */
+        case 4:
+            if (!ISHEX4 (p))
+            {
+                urj_error_set (URJ_ERROR_FIRMWARE,
+                               _("Bad extended segment address on line %d in file %s"),
+                               lineno, filename);
+                return URJ_STATUS_FAIL;
+            }
+            base_address = HEX4 (p);
+            sum += (base_address >> 8) + (base_address & 0xff);
+            sum &= 0xff;
+            base_address <<= (record_type == 2 ? 4 : 16);
+            p += 4;
+            break;
+
+        default:
+        bad_record_type:
+            urj_error_set (URJ_ERROR_FIRMWARE,
+                           _("Bad HEX record type on line %d in file %s"),
+                           lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+
+        if (!ISHEX2 (p))
+        {
+            urj_error_set (URJ_ERROR_FIRMWARE,
+                           _("Bad HEX checksum on line %d in file %s"),
+                           lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+        checksum = HEX2 (p);
+        if (((sum + checksum) & 0xff) != 0)
+        {
+            urj_error_set (URJ_ERROR_FIRMWARE,
+                           _("The checksum is not correct on line %d in file %s"),
+                           lineno, filename);
+            return URJ_STATUS_FAIL;
+        }
+    }
+    return URJ_STATUS_OK;
+}
+
+/* Calculate the CRC using forward CRC-16-CCITT algorithm.  */
+
+static uint16_t
+ice_calculate_crc (struct flash_block *p)
+{
+    uint16_t crc = 0xffff;
+
+    while (p)
+    {
+        int i;
+
+        for (i = 0; i < p->bytes; i++)
+        {
+            uint8_t byte = p->data[i];
+            int j;
+
+            for (j = 0; j < 8; j++)
+            {
+                bool add = ((crc >> 15) != (byte >> 7));
+                crc <<= 1;
+                byte <<= 1;
+                if (add)
+                    crc ^= 0x1021;
+            }
+        }
+        p = p->next;
+    }
+
+    return crc;
+}
+
+static int
+ice_send_flash_data (urj_cable_t *cable, struct flash_block *p, uint16_t crc)
+{
+    params_t *cable_params = cable->params;
+    /* ICE_100B_READ_BUFFER_SIZE / 4 (i.e. 0x2000) was chosen by experiments.
+       It might not be related to ICE_100B_READ_BUFFER_SIZE at all.  */
+    uint8_t buffer[ICE_100B_READ_BUFFER_SIZE / 4];
+    uint8_t first = 1, last = 0;
+
+    while (p)
+    {
+        int remaining = p->bytes;
+        uint32_t address = p->addr;
+
+        while (remaining)
+        {
+            usb_command_block usb_cmd_blk;
+            uint32_t count;
+
+            urj_log (URJ_LOG_LEVEL_NORMAL, ".");
+
+            if (remaining < ICE_100B_READ_BUFFER_SIZE / 4 - 16)
+                count = remaining;
+            else
+                count = ICE_100B_READ_BUFFER_SIZE / 4 - 16;
+            remaining -= count;
+            if (remaining == 0)
+                last = 1;
+
+            buffer[0] = first;
+            buffer[1] = last;
+            buffer[2] = HOST_PROGRAM_FLASH;
+            buffer[3] = 0;
+            memcpy (buffer + 4, &address, 4);
+            memcpy (buffer + 8, &count, 4);
+            memcpy (buffer + 12, &crc, 2);
+            memcpy (buffer + 16, p->data + p->bytes - remaining - count, count);
+
+            usb_cmd_blk.command = HOST_REQUEST_TX_DATA;
+            usb_cmd_blk.count = count + 16;
+            usb_cmd_blk.buffer = cable_params->wr_buf_addr;
+            adi_usb_write_or_ret (cable->link.usb->params, &usb_cmd_blk, sizeof (usb_cmd_blk));
+
+            adi_usb_write_or_ret (cable->link.usb->params, buffer, usb_cmd_blk.count);
+
+            first = 0;
+
+            address += count;
+        }
+
+        p = p->next;
+    }
+
+    return URJ_STATUS_OK;
+}
+
+/* The CRC is stored in the output buffer after programming the firmware
+   into the flash.  Read the buffer after programming get the CRC.  */
+
+static int
+ice_firmware_crc (urj_cable_t *cable, uint16_t *p)
+{
+    params_t *cable_params = cable->params;
+    usb_command_block usb_cmd_blk;
+
+    usb_cmd_blk.command = HOST_REQUEST_RX_DATA;
+    usb_cmd_blk.count = 2;
+    usb_cmd_blk.buffer = 0;
+
+    adi_usb_write_or_ret (cable->link.usb->params, &usb_cmd_blk, sizeof (usb_cmd_blk));
+
+    adi_usb_read_or_ret (cable->link.usb->params, p, sizeof (*p));
+
+    return URJ_STATUS_OK;
+}
+
+static int
+ice_update_firmware (urj_cable_t *cable, const char *filename)
+{
+    struct flash_block *flash_list = NULL, *p;
+    unsigned short crc1, crc2;
+    int ret;
+
+    urj_log (URJ_LOG_LEVEL_NORMAL, _("Updating to firmware %s\n"), filename);
+
+    if ((ret = ice_read_hex_file (filename, &flash_list)) != URJ_STATUS_OK)
+        return ret;
+
+    crc1 = ice_calculate_crc (flash_list);
+
+    ret = ice_send_flash_data (cable, flash_list, crc1);
+    urj_log (URJ_LOG_LEVEL_NORMAL, "\n");
+    if (ret != URJ_STATUS_OK)
+        return ret;
+
+    if ((ret = ice_firmware_crc (cable, &crc2)) != URJ_STATUS_OK)
+        return ret;
+
+    while (flash_list)
+    {
+        p = flash_list->next;
+        free (flash_list->data);
+        free (flash_list);
+        flash_list = p;
+    }
+
+    if (crc1 == crc2)
+    {
+        return URJ_STATUS_OK;
+    }
+    else
+    {
+        urj_error_set (URJ_ERROR_FIRMWARE, _("CRCs do NOT match"));
+        return URJ_STATUS_FAIL;
+    }
+}
+
 /*
  * This function sets us up the cable and data
  */
 static int ice_connect (urj_cable_t *cable, const urj_param_t *params[])
 {
     params_t *cable_params;
-    int ret;
+    int ret, i;
 
     if ((ret = adi_connect (cable, params)) != URJ_STATUS_OK)
         return ret;
@@ -419,6 +788,26 @@
     cable_params->wr_buf_addr     = 0;
     cable_params->r_buf_addr      = 0;
     cable_params->bytewize_scan   = 1;
+    cable_params->firmware_filename = NULL;
+
+    if (params != NULL)
+        for (i = 0; params[i] != NULL; i++)
+        {
+            switch (params[i]->key)
+            {
+            case URJ_CABLE_PARAM_KEY_FIRMWARE:
+                cable_params->firmware_filename = strdup (params[i]->value.string);
+                if (!cable_params->firmware_filename)
+                {
+                    urj_log (URJ_LOG_LEVEL_ERROR,
+                             _("strdup (%s) fails\n"), params[i]->value.string);
+                    return URJ_STATUS_FAIL;
+                }
+                break;
+            default:
+                break;
+            }
+        }
 
     return URJ_STATUS_OK;
 }
@@ -447,6 +836,7 @@
     cable_params->wr_buf_addr     = BLACKFIN_OLD_DATA_BUFFER_OUT_ADDRESS;
     cable_params->r_buf_addr      = BLACKFIN_OLD_DATA_BUFFER_IN_ADDRESS;
     cable_params->bytewize_scan   = 0;
+    cable_params->firmware_filename = NULL;
 
     return URJ_STATUS_OK;
 }
@@ -475,6 +865,7 @@
     cable_params->wr_buf_addr     = BLACKFIN_DATA_BUFFER_OUT_ADDRESS;
     cable_params->r_buf_addr      = BLACKFIN_DATA_BUFFER_IN_ADDRESS;
     cable_params->bytewize_scan   = 0;
+    cable_params->firmware_filename = NULL;
 
     return URJ_STATUS_OK;
 }
@@ -485,6 +876,7 @@
 static int ice_init (urj_cable_t *cable)
 {
     params_t *cable_params = cable->params;
+    int ret;
 
     /* Open usb conn port */
     if (urj_tap_usbconn_open (cable->link.usb))
@@ -492,7 +884,7 @@
 
     cable_params->version = do_host_cmd (cable, HOST_GET_FW_VERSION, 0, 1);
     do_host_cmd (cable, HOST_HARD_RESET_JTAG_CTRLR, 0, 0);
-    urj_log (URJ_LOG_LEVEL_NORMAL, "%s Firmware Version is %d.%d.%d\n",
+    urj_log (URJ_LOG_LEVEL_NORMAL, _("%s firmware version is %d.%d.%d\n"),
              cable->driver->name,
              ((cable_params->version >> 8) & 0xFF),
              ((cable_params->version >> 4) & 0x0F),
@@ -501,9 +893,31 @@
     if (cable_params->version < 0x0107)
     {
         urj_log (URJ_LOG_LEVEL_ERROR,
-                 _("The firmware on the ICE-100b needs to be upgraded. Please go to:\n"
-                   "%sto learn how to update the firmware.\n"),
-                   "http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:ice100b\n";);
+                 _("Error: The firmware on the ICE-100B needs to be updated.  Please go to:\n"
+                   "  %s\nto learn how to update the firmware.\n"),
+                 ICE100B_DOC_URL);
+    }
+
+    if (cable_params->firmware_filename)
+    {
+        ret = ice_update_firmware (cable, cable_params->firmware_filename);
+
+        if (ret == URJ_STATUS_OK)
+            urj_log (URJ_LOG_LEVEL_NORMAL,
+                     _("The firmware has been updated successfully.\n"
+                       "Please unplug the ICE-100B cable and reconnect it to finish the update process.\n"));
+        else
+        {
+            urj_log (URJ_LOG_LEVEL_ERROR, "%s\n",
+                     urj_error_describe (URJ_LOG_LEVEL_ERROR));
+            urj_error_reset ();
+            urj_log (URJ_LOG_LEVEL_ERROR,
+                     _("The firmware failed to update.\n"));
+        }
+    }
+
+    if (cable_params->version < 0x0107 || cable_params->firmware_filename)
+    {
         return URJ_STATUS_FAIL;
     }
 
@@ -626,6 +1040,7 @@
         tap_info->cur_dat = -1;
         tap_info->rcv_dat = -1;
     }
+    free (cable_params->firmware_filename);
     urj_tap_cable_generic_usbconn_free (cable);
 }
 
@@ -1849,6 +2264,15 @@
     return URJ_STATUS_OK;
 }
 
+static void
+ice_cable_help (urj_log_level_t ll, const char *cablename)
+{
+    const char *ex_short = "[firmware=FILE]";
+    const char *ex_desc = "FILE       Upgrade the ICE firmware.  See this page:\n"
+        "           " ICE100B_DOC_URL "\n";
+    urj_tap_cable_generic_usbconn_help_ex (ll, cablename, ex_short, ex_desc);
+}
+
 /*
  * Cable Intefaces
  */
@@ -1870,7 +2294,7 @@
     ice_set_sig,
     ice_get_sig,
     adi_flush,
-    urj_tap_cable_generic_usbconn_help,
+    ice_cable_help,
     URJ_CABLE_QUIRK_ONESHOT
 };
 URJ_DECLARE_USBCONN_CABLE(0x064B, 0x0225, "libusb", "ICE-100B", ice100B)
@@ -1920,3 +2344,11 @@
 };
 URJ_DECLARE_USBCONN_CABLE(0x064B, 0x3217, "libusb", "EZ-KIT-2.0", ezkit_20_bf518)
 URJ_DECLARE_USBCONN_CABLE(0x064B, 0x3212, "libusb", "EZ-KIT-2.0", ezkit_20_bf526)
+
+/*
+ Local Variables:
+ mode:C
+ c-default-style:gnu
+ indent-tabs-mode:nil
+ End:
+*/
Index: include/urjtag/error.h
===================================================================
--- include/urjtag/error.h.orig	2011-06-23 16:56:35.000000000 -0400
+++ include/urjtag/error.h	2011-06-23 16:59:43.000000000 -0400
@@ -73,6 +73,8 @@
     URJ_ERROR_PLD,
 
     URJ_ERROR_UNIMPLEMENTED,
+
+    URJ_ERROR_FIRMWARE,
 }
 urj_error_t;
 
Index: src/global/log-error.c
===================================================================
--- src/global/log-error.c.orig	2011-06-23 16:56:35.000000000 -0400
+++ src/global/log-error.c	2011-06-23 16:59:43.000000000 -0400
@@ -136,6 +136,8 @@
     case URJ_ERROR_PLD:                 return "pld subsystem";
 
     case URJ_ERROR_UNIMPLEMENTED:       return "unimplemented";
+
+    case URJ_ERROR_FIRMWARE:            return "firmware";
     }
 
     return "UNDEFINED ERROR";
------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure contains a 
definitive record of customers, application performance, security 
threats, fraudulent activity and more. Splunk takes this data and makes 
sense of it. Business sense. IT sense. Common sense.. 
http://p.sf.net/sfu/splunk-d2d-c1
_______________________________________________
UrJTAG-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/urjtag-development

Reply via email to