fwhtool.c

(plain)

    1 /*
    2  * Copyright (c) 2024 Amelia Zabardast Ziabari
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions are met:
    6  *
    7  *  1. Redistributions of source code must retain the above copyright notice,
    8  *     this list of conditions and the following disclaimer.
    9  *  2. Redistributions in binary form must reproduce the above copyright
   10  *     notice, this list of conditions and the following disclaimer in the
   11  *     documentation and/or other materials provided with the distribution.
   12  *  3. Neither the name of the copyright holder nor the names of its
   13  *     contributors may be used to endorse or promote products derived from
   14  *     this software without specific prior written permission.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   26  * POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <stdio.h>
   30 #include <stdlib.h>
   31 #include <unistd.h>
   32 #include <string.h>
   33 #include <fcntl.h>
   34 #include <time.h>
   35 #include <sys/time.h>
   36 
   37 extern char *optarg;
   38 extern int optind;
   39 
   40 /* BOARD SELECTION --------------------------------------------------------- */
   41 
   42 
   43 #define MOD_OUT 0
   44 #define MOD_IN  1
   45 #if defined(BOARD_RASPI)
   46 #include <wiringPi.h>
   47 /*
   48  * These pin definitions are BCM-logical (the "BCM" column in wiringPi's
   49  * "gpio readall" command).  They have been chosen to maintain compatibility
   50  * with previous attempts to solve this problem, in order to reduce infuriating
   51  * experiences with re-wiring breadboards for the user.
   52  *
   53  * They also have the nice property of being compatible with boards that use a
   54  * reduced GPIO connector, as well as avoiding the SPI-related GPIO pins (which
   55  * you may want to keep untouched if you also use your Raspberry Pi as an SPI
   56  * programmer).
   57  */
   58 #define PIN_RSET 17
   59 #define PIN_LAD0 22
   60 #define PIN_LAD1 23
   61 #define PIN_LAD2 24
   62 #define PIN_LAD3 25
   63 #define PIN_LFRM 27
   64 #define PIN_LCLK 18
   65 #define PIN_WREN 4
   66 #define PSETUP wiringPiSetupGpio
   67 #define OUTP(p, s) digitalWrite(p, (s) ? HIGH : LOW)
   68 #define INP(p) digitalRead(p)
   69 #define MODEP(p, m) pinMode(p, (m) ? INPUT : OUTPUT)
   70 #elif defined(BOARD_DUMMY)
   71 /* Only useful with the dummy programmer. */
   72 static void dummySetup() {}
   73 #define PSETUP dummySetup
   74 #define OUTP(p, s)
   75 #define INP(p) 1
   76 #define MODEP(p, m)
   77 #else
   78 #error "no SBC board specification selected!"
   79 #endif
   80 
   81 /* CHIP AND FUNCTIONAL DECLARATION ----------------------------------------- */
   82 
   83 
   84 typedef unsigned long long ndelay_t;
   85 
   86 #define TMMIX(a, t) (ndelay_t)((a) * (double)(t))
   87 #define USEC(t) TMMIX(1000.0, t)
   88 #define MSEC(t) TMMIX(1000000.0, t)
   89 #define  SEC(t) TMMIX(1000000000.0, t)
   90 #define STABILIZE USEC(1)
   91 #define DEFAULT_LAD .lad = STABILIZE
   92 
   93 typedef struct dself {
   94         char *name;
   95         enum {
   96                 BUS_FWH,        /* Firmware Hub Transfers */
   97                 BUS_LPC,        /* LPC Transfers */
   98                 BUS_LPC_ISA     /* LPC Transfers with ISA Compatibility */
   99         } type;
  100         enum {
  101                 NEEDS_MISC_BLOCK_UNLOCK = 0x0001,
  102                 NEEDS_WE_ALWAYS_ON      = 0x0002
  103         } quirks;
  104         enum {
  105                 TEST_WIP,       /* Not even finished */
  106                 TEST_NONE,      /* Untested */
  107                 TEST_I,         /* Identifies */
  108                 TEST_IR,        /* Identifies & Reads */
  109                 TEST_IRW        /* Identifies, Reads & Writes */
  110         } status;
  111         unsigned char ven_id;
  112         unsigned char dev_id;
  113         unsigned long register_base;
  114         unsigned long memory_base;
  115         unsigned long bsz; /* block  */
  116         unsigned long ssz; /* sector */
  117         unsigned long csz; /* chip   */
  118 
  119         struct {
  120                 unsigned long size;
  121                 enum {
  122                         XFER_N, /* terminator value (must be zero) */
  123                         XFER_RW,
  124                         XFER_R,
  125                         XFER_W
  126                 } type;
  127         } xfers[8]; /* valid "IMSIZE" field sizes. */
  128 
  129         void (*s_erase)(struct dself *, unsigned long);
  130         void (*b_erase)(struct dself *, unsigned long);
  131         void (*c_erase)(struct dself *);
  132         int (*erased)(struct dself *);
  133 
  134         void (*write)(struct dself *, unsigned long, size_t, char *);
  135         void (*read)(struct dself *, unsigned long, size_t, char *);
  136 
  137         int (*probe)(struct dself *);
  138 
  139         struct {
  140                 ndelay_t lad;
  141                 ndelay_t program;
  142                 ndelay_t s_erase;
  143                 ndelay_t b_erase;
  144                 ndelay_t c_erase;
  145                 ndelay_t toggle_bit_delay;
  146                 ndelay_t cycle;
  147                 ndelay_t regset;
  148         } delay;
  149 } mdev_t;
  150 
  151 /* "Standardized" access functions for various types of chips. */
  152 void jedec_block_erase(mdev_t *, unsigned long);
  153 void jedec_chip_erase(mdev_t *);
  154 void jedec_sector_erase(mdev_t *, unsigned long);
  155 void jedec_program(mdev_t *, unsigned long, size_t, char *);
  156 void jedec_read(mdev_t *, unsigned long, size_t, char *);
  157 int jedec_chip_identify(mdev_t *);
  158 int toggle_d6_erased(mdev_t *d);
  159 
  160 /* Dummy functions */
  161 void dummy_sector_erase(mdev_t *, unsigned long);
  162 void dummy_block_erase(mdev_t *, unsigned long);
  163 void dummy_chip_erase(mdev_t *);
  164 void dummy_program(mdev_t *, unsigned long, size_t, char *);
  165 void dummy_read(mdev_t *, unsigned long, size_t, char *);
  166 
  167 /* SST "Mini-Command" functions */
  168 int sstmc_chip_identify(mdev_t *d);
  169 
  170 mdev_t devicetab[] = {
  171         {
  172                 .name = "dummy",
  173                 .status = TEST_IRW,
  174                 .bsz = 0x10000,
  175                 .ssz = 0x1000,
  176                 .csz = 0x100000,
  177                 .xfers = { { 128, XFER_RW } },
  178                 .s_erase = dummy_sector_erase,
  179                 .b_erase = dummy_block_erase,
  180                 .c_erase = dummy_chip_erase,
  181                 .erased = NULL,
  182                 .write = dummy_program,
  183                 .read = dummy_read,
  184                 .probe = NULL,
  185                 .delay = {0}
  186         },
  187         {
  188                 /* See "Design Considerations" in the datasheet. */
  189                 .name = "SST49LF008A",
  190                 .type = BUS_FWH,
  191                 .quirks = NEEDS_MISC_BLOCK_UNLOCK,
  192                 .status = TEST_IRW,
  193                 .ven_id = 0xbf,
  194                 .dev_id = 0x5a,
  195                 .register_base = 0xff800000,
  196                 .memory_base = 0xffc00000,
  197                 .bsz = 0x10000,
  198                 .ssz = 0x1000,
  199                 .csz = 0x100000,
  200                 .s_erase = jedec_sector_erase,
  201                 .b_erase = jedec_block_erase,
  202                 .c_erase = NULL,
  203                 .erased = toggle_d6_erased,
  204                 .write = jedec_program,
  205                 .read = jedec_read,
  206                 .probe = jedec_chip_identify,
  207                 .delay = {
  208                         DEFAULT_LAD
  209                 }
  210         },
  211         {
  212                 /* Similar to SST49LF008A, but not FWH and smaller. */
  213                 .name = "SST49LF020",
  214                 .type = BUS_LPC_ISA,
  215                 .status = TEST_NONE,
  216                 .ven_id = 0xbf,
  217                 .dev_id = 0x61,
  218                 .register_base = 0xff800000,
  219                 .memory_base = 0xffc00000,
  220                 .bsz = 0x4000,
  221                 .ssz = 0x1000,
  222                 .csz = 0x40000,
  223                 .s_erase = jedec_sector_erase,
  224                 .b_erase = jedec_block_erase,
  225                 .c_erase = NULL,
  226                 .erased = toggle_d6_erased,
  227                 .write = jedec_program,
  228                 .read = jedec_read,
  229                 .probe = jedec_chip_identify,
  230                 .delay = {
  231                         DEFAULT_LAD
  232                 }
  233         },
  234         {
  235                 /* Special considerations for this chip to save you the pain I
  236                  * went through:
  237                  *  - Vpp must be 3.3V. (!)
  238                  *  - All Vdd and Vss pins must be connected.
  239                  *  - Use a high frequency/AC 0.1uF ceramic capacitor between
  240                  *    Vdd and Vss no further than 1cm away from Vdd.
  241                  */
  242                 .name = "W39V080FA",
  243                 .type = BUS_FWH,
  244                 .quirks = NEEDS_MISC_BLOCK_UNLOCK | NEEDS_WE_ALWAYS_ON,
  245                 .status = TEST_IRW,
  246                 .ven_id = 0xda,
  247                 .dev_id = 0xd3,
  248                 .register_base = 0xff800000,
  249                 .memory_base = 0xffc00000,
  250                 .bsz = 0x10000,
  251                 .ssz = 0x10000,
  252                 .csz = 0x100000,
  253                 .s_erase = jedec_sector_erase,
  254                 .b_erase = NULL,
  255                 .c_erase = NULL,
  256                 .erased = toggle_d6_erased,
  257                 .write = jedec_program,
  258                 .read = jedec_read,
  259                 .probe = jedec_chip_identify,
  260                 .delay = {
  261                         DEFAULT_LAD,
  262                         .toggle_bit_delay = MSEC(8)
  263                 }
  264         },
  265         {
  266                 /* TODO: Finish this chip (does not identify, needs special
  267                  * commands).
  268                  */
  269                 .name = "SST49LF016C",
  270                 .type = BUS_FWH,
  271                 .quirks = 0,
  272                 .status = TEST_WIP,
  273                 .ven_id = 0xbf,
  274                 .dev_id = 0x5c,
  275                 .register_base = 0xff800000,
  276                 .memory_base = 0xffc00000,
  277                 .bsz = 0x10000,
  278                 .ssz = 0x1000,
  279                 .csz = 0x200000,
  280                 .xfers = {
  281                         { 2  , XFER_RW }, { 2  , XFER_RW },
  282                         { 4  , XFER_RW }, { 4  , XFER_RW },
  283                         { 16 , XFER_R  },
  284                         { 128, XFER_R  }
  285                 },
  286                 .s_erase = NULL,
  287                 .b_erase = NULL,
  288                 .c_erase = NULL,
  289                 .erased = NULL,
  290                 .write = NULL,
  291                 .read = NULL,
  292                 .probe = sstmc_chip_identify,
  293                 .delay = {
  294                         DEFAULT_LAD
  295                 }
  296         }
  297 };
  298 int devices = sizeof(devicetab) / sizeof(devicetab[0]);
  299 
  300 /* DISPLAY AND DEBUG HELPERS ----------------------------------------------- */
  301 
  302 
  303 #ifndef DEBUG_LEVEL
  304 #define DEBUG_LEVEL 0
  305 #endif
  306 static int dbglvl = DEBUG_LEVEL;
  307 
  308 #define ABORT(...) do { fprintf(stderr, __VA_ARGS__); safe_exit(); } while (0)
  309 #define DEBUG(...) do { fprintf(stderr, __VA_ARGS__); } while (0)
  310 #define ASSERT(cond) do { if (!(cond)) \
  311                 ABORT("%d: assertion failed: " #cond "\n", __LINE__); \
  312 } while (0)
  313 #define VDEBUG(l, ...) do { if ((l) <= dbglvl) DEBUG(__VA_ARGS__); } while (0)
  314 
  315 #define TO_MS(tv) ((unsigned long long)tv.tv_sec * 1000LL) + \
  316 ((unsigned long long)tv.tv_usec / 1000LL)
  317 
  318 static void
  319 progress(char *op, unsigned long c, unsigned long t)
  320 {
  321         static struct timeval s1 = {0}, s2 = {0};
  322         struct timeval sub;
  323 
  324         gettimeofday(&s1, NULL);
  325         sub.tv_sec  = s1.tv_sec  - s2.tv_sec;
  326         sub.tv_usec = s1.tv_usec - s2.tv_usec;
  327         if (TO_MS(sub) > 250LL) {
  328                 s2 = s1;
  329                 DEBUG("   %s (%2d%%) %08lx / %08lx\r",
  330                     op, (int)((100 * c) / t), c, t);
  331         }
  332 }
  333 
  334 /* MAIN DECLARATIONS ------------------------------------------------------- */
  335 
  336 
  337 static FILE *fp = NULL;
  338 
  339 static void safe_exit(void);
  340 
  341 static void we(mdev_t *, int);
  342 static void reset(void);
  343 
  344 static void lad_output(void);
  345 static void lad_input(void);
  346 static void lad_write(mdev_t *, unsigned char, int);
  347 static unsigned char lad_read(mdev_t *);
  348 static void prepare_pins(void);
  349 
  350 static unsigned int log2i(unsigned int);
  351 
  352 static void lad_address(mdev_t *, unsigned long address);
  353 static void lad_rsync(mdev_t *);
  354 static void lad_start(mdev_t *, int);
  355 static void read_maddress(mdev_t *, unsigned long, size_t, char *);
  356 static void write_maddress(mdev_t *, unsigned long, size_t, char *);
  357 static unsigned char read_address(mdev_t *, unsigned long);
  358 static void write_address(mdev_t *, unsigned long, unsigned char);
  359 
  360 static size_t max_xfer(mdev_t *, unsigned long, size_t, int);
  361 static unsigned char read_reg(mdev_t *, unsigned long);
  362 static void write_reg(mdev_t *, unsigned long, unsigned char);
  363 static void op_mmem(mdev_t *, unsigned long, size_t, char *, int);
  364 static unsigned char read_mem(mdev_t *, unsigned long);
  365 static void write_mem(mdev_t *, unsigned long, unsigned char);
  366 
  367 static void get_jedec_id(mdev_t *, unsigned char *, unsigned char *);
  368 static void get_jedec_id2(mdev_t *, unsigned char *, unsigned char *);
  369 
  370 static void get_sstmc_id(mdev_t *, unsigned char *, unsigned char *);
  371 
  372 static void reset_echk(void);
  373 static void misc_unlock_block(mdev_t *d, unsigned long block);
  374 
  375 static void gen_chip_setup(mdev_t *);
  376 static void gen_read(mdev_t *, char *, unsigned long, unsigned long, int);
  377 static void gen_wait_status(mdev_t *, ndelay_t, int);
  378 static void gen_erase_block(mdev_t *, unsigned long);
  379 static void gen_erase_chip(mdev_t *, int);
  380 static void gen_write(mdev_t *, char *, unsigned long, unsigned long, int);
  381 
  382 static char *alloc_chip(mdev_t *);
  383 
  384 static void fwc_template(int);
  385 static void fwc_setfield(int, int, char);
  386 static void full_write_cycle(mdev_t *, char *);
  387 
  388 static mdev_t *get_chip_by_name(char *);
  389 static void usage();
  390 static const char *fmt_chip_status(int);
  391 
  392 /* HIGH-ACCURACY DELAY AND TIME ROUTINES ----------------------------------- */
  393 
  394 
  395 /* Not all operating systems can sleep for a reasonable amount of time.  On my
  396  * system, usleep(1); makes the average full-chip read take up to a whole
  397  * day(!), so in order to prioritize chip operation speed over host CPU usage,
  398  * let's just create an unoptimized no-op loop and calibrate it.
  399  */
  400 static int clob;
  401 #define NOOP asm volatile ("nop" : "+r" (clob))
  402 #define NOOPLOOP(t) do {                                                \
  403         unsigned long long i; for (i = 0; i < t; i++) NOOP;             \
  404 } while (0)
  405 #define BIGCLK(tv) (((unsigned long long)(tv)->tv_sec * 1000000000ULL)  \
  406 + (unsigned long long)(tv)->tv_nsec)
  407 #define MAX(a, b) ((a) > (b) ? (a) : (b))
  408 #define MIN(a, b) ((a) < (b) ? (a) : (b))
  409 
  410 static void
  411 ndelay(ndelay_t ns)
  412 {
  413         static unsigned long long itpms = 0, ax;
  414         if (itpms == 0) {
  415                 struct timespec r1, r2;
  416                 unsigned long long tres;
  417                 int monot, realt, i;
  418                 clockid_t clck;
  419                 DEBUG("calibrating delay scale... ");
  420                 /* select the most accurate clock, assuming it won't change */
  421                 monot = clock_getres(CLOCK_MONOTONIC, &r1);
  422                 realt = clock_getres(CLOCK_REALTIME, &r2);
  423                 if (monot != 0 || realt != 0) {
  424                         clck = realt == 0 ? CLOCK_REALTIME : CLOCK_MONOTONIC;
  425                 } else {
  426                         /* prioritizes monotonic if equal */
  427                         clck = BIGCLK(&r2) < BIGCLK(&r1) ?
  428                             CLOCK_REALTIME : CLOCK_MONOTONIC;
  429                 }
  430                 tres = clck == CLOCK_MONOTONIC ? BIGCLK(&r1) : BIGCLK(&r2);
  431                 /* warm up the processor to max freq */
  432                 NOOPLOOP(1000000);
  433                 /* now calibrate for 1msec over and over for shortest cycles */
  434                 for (i = 0; i < 128; i++) {
  435                         ax = 2;
  436                         for (;;) {
  437                                 clock_gettime(clck, &r1);
  438                                 NOOPLOOP(ax);
  439                                 clock_gettime(clck, &r2);
  440                                 tres = BIGCLK(&r2) - BIGCLK(&r1);
  441                                 if (tres >= 1000000) break;
  442                                 ax *= 2;
  443                         }
  444                         ax = (1000000.0 / (double)tres) * (double)ax;
  445                         /* need to find the quickest run (the largest number of
  446                          * required instructions) as this varies by factors
  447                          * like CPU frequency and context switches.
  448                          */
  449                         if (itpms == 0) itpms = ax;
  450                         else itpms = MAX(itpms, ax);
  451                 }
  452                 DEBUG("needs %llu iterations for 1msec\n", itpms);
  453                 clock_gettime(clck, &r1);
  454                 ndelay(150000);
  455                 clock_gettime(clck, &r2);
  456                 tres = BIGCLK(&r2) - BIGCLK(&r1);
  457                 DEBUG("slept for 150us, got %fus\n", (double)tres / 1000.0);
  458                 /* bail out if calibration is untrustworthy! */
  459                 ASSERT(tres >= 150000);
  460         } else {
  461                 ax = ((double)itpms / 1000000.0) * (double)ns;
  462                 VDEBUG(15, " (W %lluns %lluistr) ", ns, ax);
  463                 NOOPLOOP(ax);
  464         }
  465 }
  466 
  467 #define DELAY_FOR(d, a) ndelay(d->delay.a)
  468 
  469 /* ACCESS PRIMITIVES ------------------------------------------------------- */
  470 
  471 
  472 static void
  473 safe_exit(void)
  474 {
  475         OUTP(PIN_RSET, 1);
  476         MODEP(PIN_RSET, MOD_OUT);
  477         OUTP(PIN_WREN, 0);
  478         lad_input();
  479         MODEP(PIN_WREN, MOD_IN);
  480         MODEP(PIN_LFRM, MOD_IN);
  481         MODEP(PIN_LCLK, MOD_IN);
  482         if (fp != NULL) fclose(fp);
  483         exit(1);
  484 }
  485 
  486 static void
  487 lad_output(void)
  488 {
  489         MODEP(PIN_LAD0, MOD_OUT);
  490         MODEP(PIN_LAD1, MOD_OUT);
  491         MODEP(PIN_LAD2, MOD_OUT);
  492         MODEP(PIN_LAD3, MOD_OUT);
  493 }
  494 
  495 static void
  496 lad_input(void)
  497 {
  498         MODEP(PIN_LAD0, MOD_IN);
  499         MODEP(PIN_LAD1, MOD_IN);
  500         MODEP(PIN_LAD2, MOD_IN);
  501         MODEP(PIN_LAD3, MOD_IN);
  502 }
  503 
  504 static void
  505 lad_write(mdev_t *d, unsigned char data, int start_frame)
  506 {
  507         ASSERT((data & 0xf0) == 0);
  508         if (start_frame)
  509                 OUTP(PIN_LFRM, 0);
  510         OUTP(PIN_LCLK, 0);
  511         OUTP(PIN_LAD0, data & 0x1 ? 1 : 0);
  512         OUTP(PIN_LAD1, data & 0x2 ? 1 : 0);
  513         OUTP(PIN_LAD2, data & 0x4 ? 1 : 0);
  514         OUTP(PIN_LAD3, data & 0x8 ? 1 : 0);
  515         DELAY_FOR(d, lad);
  516         OUTP(PIN_LCLK, 1);
  517         if (start_frame)
  518                 OUTP(PIN_LFRM, 1);
  519         VDEBUG(10, "LAD W: %02x (%d)\n", data, start_frame);
  520 }
  521 
  522 static unsigned char
  523 lad_read(mdev_t *d)
  524 {
  525         unsigned char v = 0;
  526         OUTP(PIN_LCLK, 1);
  527         DELAY_FOR(d, lad);
  528         if (INP(PIN_LAD0)) v |= 0x1;
  529         if (INP(PIN_LAD1)) v |= 0x2;
  530         if (INP(PIN_LAD2)) v |= 0x4;
  531         if (INP(PIN_LAD3)) v |= 0x8;
  532         OUTP(PIN_LCLK, 0);
  533         VDEBUG(10, "LAD R: %02x\n", v);
  534         return v;
  535 }
  536 
  537 static void
  538 we(mdev_t *d, int v)
  539 {
  540         OUTP(PIN_WREN, d->quirks & NEEDS_WE_ALWAYS_ON ? 1 : v);
  541 }
  542 
  543 static void
  544 reset(void)
  545 {
  546         OUTP(PIN_RSET, 0);
  547         usleep(1000);
  548         OUTP(PIN_RSET, 1);
  549         usleep(500000);
  550 }
  551 
  552 static void
  553 prepare_pins(void)
  554 {
  555         PSETUP();
  556         OUTP(PIN_RSET, 0);
  557         OUTP(PIN_LCLK, 1);
  558         OUTP(PIN_LFRM, 1);
  559         OUTP(PIN_WREN, 0);
  560 
  561         OUTP(PIN_LAD0, 0);
  562         OUTP(PIN_LAD1, 0);
  563         OUTP(PIN_LAD2, 0);
  564         OUTP(PIN_LAD3, 0);
  565         lad_input();
  566         MODEP(PIN_RSET, MOD_OUT);
  567         MODEP(PIN_WREN, MOD_OUT);
  568         MODEP(PIN_LFRM, MOD_OUT);
  569         MODEP(PIN_LCLK, MOD_OUT);
  570         reset();
  571 }
  572 
  573 /* LPC/FPC PROTOCOL PRIMITIVES --------------------------------------------- */
  574 
  575 
  576 static void
  577 lad_address(mdev_t *d, unsigned long address)
  578 {
  579         int i;
  580         /* FWH has a 28-bit address space, LPC has a 32-bit address space. */
  581         for (i = 1; i <= (d->type == BUS_FWH ? 7 : 8); i++)
  582                 lad_write(d,
  583                     (address >> ((d->type == BUS_FWH ? 28 : 32) - 4 * i))
  584                     & 0xf, 0);
  585 }
  586 
  587 static int xfer_errs_fatal = 0, global_t0 = 0;
  588 
  589 static void
  590 lad_rsync(mdev_t *d)
  591 {
  592         /* Some chips do not immediately respond with an RSYNC value of 0.
  593          * The W39V080FA for example often provides a value of 5 several times,
  594          * indicating the host to wait for a few more clock cycles.
  595          */
  596         unsigned char v;
  597  rsync_reset:
  598         switch ((v = lad_read(d))) {
  599         case 0: return;
  600         case 5: ndelay(STABILIZE);      goto rsync_reset;
  601         case 6: ndelay(USEC(100));      goto rsync_reset;
  602         default:
  603                 if (xfer_errs_fatal)
  604                         ABORT("(read) field RSYNC not zero: %01x\n", v);
  605         }
  606 }
  607 
  608 static void
  609 lad_start(mdev_t *d, int write)
  610 {
  611         unsigned char cyctype = (1<<2);
  612         if (write) cyctype |= (1<<1);
  613         switch (d->type) {
  614         case BUS_FWH:
  615                 cyctype |= (1<<3);
  616                 if (!write) cyctype |= 1;
  617                 break;
  618         case BUS_LPC:
  619                 if (write) cyctype |= 1;
  620                 break;
  621         case BUS_LPC_ISA:
  622                 lad_write(d, 0x00, 1);
  623                 lad_write(d, cyctype, 0);
  624                 return;
  625         }
  626         lad_write(d, cyctype, 1);
  627 }
  628 
  629 static unsigned int
  630 log2i(unsigned int v)
  631 {
  632         /* https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog */
  633         int i;
  634         static const unsigned int b[] = {0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0,
  635                 0xFF00FF00, 0xFFFF0000};
  636         unsigned int r = (v & b[0]) != 0;
  637         for (i = 4; i > 0; i--)
  638                 r |= ((v & b[i]) != 0) << i;
  639         return r;
  640 }
  641 
  642 static void
  643 read_maddress(mdev_t *d, unsigned long address, size_t a, char *out)
  644 {
  645         size_t i;
  646         unsigned char v;
  647         lad_output();
  648         /* FWH vs. LPC use different START bits for differentiation. */
  649         lad_start(d, 0);                                /* START (READ) */
  650         lad_write(d, 0x00, 0);                          /* IDSEL 0000 */
  651         lad_address(d, address);                        /* IMADDR */
  652         lad_write(d, log2i(a), 0);                      /* IMSIZE */
  653         lad_write(d, 0x0f, 0);                          /* TAR0 */
  654         lad_input();
  655         lad_read(d);                                    /* TAR1 */
  656         lad_rsync(d);                                   /* RSYNC */
  657         for (i = 0; i < a; i++) {
  658                 out[i]  = lad_read(d);                  /* DATA (LOW) */
  659                 out[i] |= lad_read(d) << 4;             /* DATA (HIGH) */
  660         }
  661         if((v = lad_read(d)) != 0xf && xfer_errs_fatal) /* TAR0 */
  662                 ABORT("(read) field TAR0 not all ones: %01x\n", v);
  663         global_t0 |= v;
  664         lad_read(d);                                    /* TAR1 */
  665         lad_output();
  666         DELAY_FOR(d, cycle);
  667 }
  668 
  669 static void
  670 write_maddress(mdev_t *d, unsigned long address, size_t a, char *in)
  671 {
  672         size_t i;
  673         unsigned char v;
  674         lad_output();
  675         lad_start(d, 1);                                /* START (WRITE) */
  676         lad_write(d, 0x00, 0);                          /* IDSEL 0000 */
  677         lad_address(d, address);                        /* IMADDR */
  678         lad_write(d, log2i(a), 0);                      /* IMSIZE */
  679         for (i = 0; i < a; i++) {
  680                 lad_write(d,  in[i]       & 0xf , 0);   /* DATA (LOW) */
  681                 lad_write(d, (in[i] >> 4) & 0xf , 0);   /* DATA (HIGH) */
  682         }
  683         lad_write(d, 0x0f, 0);                          /* TAR0 */
  684         lad_input();
  685         lad_read(d);                                    /* TAR1 */
  686         lad_rsync(d);                                   /* RSYNC */
  687         if((v = lad_read(d)) != 0xf && xfer_errs_fatal) /* TAR0 */
  688                 ABORT("(write) field TAR0 not all ones: %01x!\n", v);
  689         global_t0 |= v;
  690         lad_read(d);                                    /* TAR1 */
  691         lad_output();
  692         DELAY_FOR(d, cycle);
  693 }
  694 
  695 static unsigned char
  696 read_address(mdev_t *d, unsigned long address)
  697 {
  698         char buf[1];
  699         read_maddress(d, address, 1, buf);
  700         VDEBUG(5, "1R: %08lx, %02x\n", address, buf[0]);
  701         return buf[0];
  702 }
  703 
  704 static void
  705 write_address(mdev_t *d, unsigned long address, unsigned char data)
  706 {
  707         char buf[1];
  708         buf[0] = data;
  709         VDEBUG(5, "1W: %08lx, %02x\n", address, buf[0]);
  710         write_maddress(d, address, 1, buf);
  711 }
  712 
  713 /* CHIP REGION ACCESS PRIMITIVES ------------------------------------------- */
  714 
  715 
  716 static size_t
  717 max_xfer(mdev_t *d, unsigned long s, size_t tc, int t)
  718 {
  719         /* XXX: work out the largest transfer size supported on the chip for
  720          * a given type (read or write operation).  "tc" (the total operation
  721          * size) and "s" (the starting address) must be evenly divisible by (or
  722          * rather, aligned with) the derived transfer chunk size.  In most
  723          * cases this is already true, so there's no real reason to optimize
  724          * for the case where it wouldn't be.
  725          */
  726         int pta, ptt, i;
  727         size_t r = 1;
  728         for (i = 0;;i++) {
  729                 pta = d->xfers[i].size;
  730                 ptt = d->xfers[i].type;
  731                 if (ptt == XFER_N) break;
  732 
  733                 if ( (pta > r)
  734                     && (ptt == t || ptt == XFER_RW)
  735                     && !(tc % pta)
  736                     && !(s  % pta)) r = pta;
  737                 VDEBUG(10, "ESTABLISH XFER SZ: %08lx\n", (unsigned long)r);
  738         }
  739         return r;
  740 }
  741 
  742 #define XFERL(v, s, a, x, e)                    \
  743 for (v = s; v < (s + a); (e),v += x)
  744 
  745 static int opp_q = 0;
  746 #define PROG_PRINT(t, c, e) do {                                        \
  747         if (!opp_q) progress(t == XFER_R ? "READ " : "WRITE", c, e);    \
  748 } while (0)
  749 #define PROG_FIN do {                           \
  750         if (!opp_q) DEBUG("\n");                \
  751 } while (0)
  752 
  753 /* Produces variables i and xf, containing the current address and transfer
  754  * size respectively, and a loop that iterates over an address space in
  755  * transfer-sized chunks.
  756  */
  757 #define XFEROP(d, s, a, t, ...) do {        \
  758         unsigned long i;                    \
  759         size_t xf = max_xfer(d, s, a, t);   \
  760         ASSERT(s + a <= d->csz);            \
  761         XFERL(i, s, a, xf, buf += xf) {     \
  762                 PROG_PRINT(t, i, s + a);    \
  763                 __VA_ARGS__;                \
  764                     }                       \
  765         PROG_FIN;                           \
  766 } while (0);
  767 
  768 static unsigned char
  769 read_reg(mdev_t *d, unsigned long address)
  770 {
  771         return read_address(d, address + d->register_base);
  772 }
  773 
  774 static void
  775 write_reg(mdev_t *d, unsigned long address, unsigned char data)
  776 {
  777         write_address(d, address + d->register_base, data);
  778         DELAY_FOR(d, regset);
  779 }
  780 
  781 static void
  782 op_mmem(mdev_t *d, unsigned long address, size_t a, char *buf, int w)
  783 {
  784         if (!w) read_maddress (d, address + d->memory_base, a, buf);
  785         else    write_maddress(d, address + d->memory_base, a, buf);
  786 }
  787 
  788 static unsigned char
  789 read_mem(mdev_t *d, unsigned long address)
  790 {
  791         return read_address(d, address + d->memory_base);
  792 }
  793 
  794 static void
  795 write_mem(mdev_t *d, unsigned long address, unsigned char data)
  796 {
  797         write_address(d, address + d->memory_base, data);
  798 }
  799 
  800 /* MISC FUNCTIONS ---------------------------------------------------------- */
  801 
  802 
  803 static void
  804 misc_unlock_block(mdev_t *d, unsigned long block)
  805 {
  806         unsigned long ulock = 0x300002 | (d->bsz * block);
  807         ASSERT(read_reg(d, ulock) == 0x01);
  808         write_reg(d, ulock, 0x00);
  809         ASSERT(read_reg(d, ulock) == 0x00);
  810 }
  811 
  812 /* JEDEC FUNCTIONS --------------------------------------------------------- */
  813 
  814 
  815 static unsigned char d6_lt;
  816 
  817 int
  818 toggle_d6_erased(mdev_t *d)
  819 {
  820         unsigned char v;
  821         if ((v = read_mem(d, 0x0000) & 0x40) == d6_lt) return 1;
  822         d6_lt = v;
  823         return 0;
  824 }
  825 
  826 static void
  827 reset_echk(void)
  828 {
  829         /*
  830          * This function should be used for resetting erase-check state for all
  831          * available chips.
  832          */
  833         d6_lt = 0xAB;
  834 }
  835 
  836 static void
  837 get_jedec_id(mdev_t *d, unsigned char *ven, unsigned char *dev)
  838 {
  839         *ven = read_reg(d, 0x3c0000);
  840         *dev = read_reg(d, 0x3c0001);
  841 }
  842 
  843 static void
  844 get_jedec_id2(mdev_t *d, unsigned char *ven, unsigned char *dev)
  845 {
  846         write_mem(d, 0x5555, 0xAA);
  847         write_mem(d, 0x2AAA, 0x55);
  848         write_mem(d, 0x5555, 0x90);
  849         *ven = read_mem(d, 0x0000);
  850         *dev = read_mem(d, 0x0001);
  851         write_mem(d, 0x0000, 0xF0);
  852 }
  853 
  854 #define IDDBG(m, c, v, d, p) DEBUG(                                     \
  855     m " identification method " c ": "                                  \
  856         "ven %02x dev %02x (%s)\n", v, d, p ? "PASSED" : "FAILED");
  857 
  858 int
  859 jedec_chip_identify(mdev_t *d)
  860 {
  861         unsigned char ven, dev;
  862         int m2;
  863         get_jedec_id(d, &ven, &dev);
  864         if (ven == d->ven_id && dev == d->dev_id) {
  865                 IDDBG("jedec", "1", ven, dev, 1);
  866                 get_jedec_id2(d, &ven, &dev);
  867                 m2 = ven == d->ven_id && dev == d->dev_id;
  868                 IDDBG("jedec", "2", ven, dev, m2);
  869                 return m2;
  870         } else return 0;
  871 }
  872 
  873 void
  874 jedec_sector_erase(mdev_t *d, unsigned long sector)
  875 {
  876         write_mem(d, 0x5555, 0xAA);
  877         write_mem(d, 0x2AAA, 0x55);
  878         write_mem(d, 0x5555, 0x80);
  879         write_mem(d, 0x5555, 0xAA);
  880         write_mem(d, 0x2AAA, 0x55);
  881         write_mem(d, d->ssz * sector, 0x30);
  882         gen_wait_status(d, d->delay.s_erase, 1);
  883 }
  884 
  885 void
  886 jedec_block_erase(mdev_t *d, unsigned long block)
  887 {
  888         write_mem(d, 0x5555, 0xAA);
  889         write_mem(d, 0x2AAA, 0x55);
  890         write_mem(d, 0x5555, 0x80);
  891         write_mem(d, 0x5555, 0xAA);
  892         write_mem(d, 0x2AAA, 0x55);
  893         write_mem(d, d->bsz * block, 0x50);
  894         gen_wait_status(d, d->delay.b_erase, 1);
  895 }
  896 
  897 void
  898 jedec_chip_erase(mdev_t *d)
  899 {
  900         write_mem(d, 0x5555, 0xAA);
  901         write_mem(d, 0x2AAA, 0x55);
  902         write_mem(d, 0x5555, 0x80);
  903         write_mem(d, 0x5555, 0xAA);
  904         write_mem(d, 0x2AAA, 0x55);
  905         write_mem(d, 0x5555, 0x10);
  906         gen_wait_status(d, d->delay.c_erase, 1);
  907 }
  908 
  909 void
  910 jedec_program(mdev_t *d, unsigned long address, size_t a, char *buf)
  911 {
  912         write_mem(d, 0x5555, 0xAA);
  913         write_mem(d, 0x2AAA, 0x55);
  914         write_mem(d, 0x5555, 0xA0);
  915         op_mmem(d, address, a, buf, 1);
  916         gen_wait_status(d, d->delay.program, 0);
  917 }
  918 
  919 void
  920 jedec_read(mdev_t *d, unsigned long address, size_t a, char *buf)
  921 {
  922         op_mmem(d, address, a, buf, 0);
  923 }
  924 
  925 /* SST MINI-COMMAND IMPLEMENTATION ----------------------------------------- */
  926 
  927 
  928 enum sstmc_modes {
  929         SSTMC_READARRAY,
  930         SSTMC_SOFTWAREID,
  931         SSTMC_STATUSREG
  932 };
  933 
  934 static int sstmc_mode = SSTMC_READARRAY;
  935 
  936 static void
  937 get_sstmc_id(mdev_t *d, unsigned char *ven, unsigned char *dev)
  938 {
  939         if (sstmc_mode != SSTMC_SOFTWAREID)
  940                 write_mem(d, 0x0000, 0x90);
  941         *ven = read_mem(d, 0x3c0000);
  942         *dev = read_mem(d, 0x3c0001);
  943         sstmc_mode = SSTMC_SOFTWAREID;
  944 }
  945 
  946 int
  947 sstmc_chip_identify(mdev_t *d)
  948 {
  949         unsigned char ven, dev;
  950         int m2;
  951         get_jedec_id(d, &ven, &dev);
  952         if ((ven == 0 && dev == 0)
  953             || (ven == d->ven_id && dev == d->dev_id)) {
  954                 get_sstmc_id(d, &ven, &dev);
  955                 m2 = ven == d->ven_id && dev == d->dev_id;
  956                 IDDBG("sstmc", "1", ven, dev, m2);
  957                 return m2;
  958         } else return 0;
  959 }
  960 
  961 /* DUMMY IMPLEMENTATION ---------------------------------------------------- */
  962 
  963 
  964 static FILE *dummy_chip = NULL;
  965 
  966 #define FFILL(f, c, a) do { int i;for (i=0;i<a;i++) {fputc(c,f);} } while (0)
  967 #define FSEEK(f, t) if (fseeko(f, t, SEEK_SET)<0) ABORT("failed to seek!\n");
  968 
  969 void
  970 dummy_sector_erase(mdev_t *d, unsigned long sector)
  971 {
  972         if (!dummy_chip) return;
  973         FSEEK(dummy_chip, sector * d->ssz);
  974         FFILL(dummy_chip, 0xFF, d->ssz);
  975 }
  976 
  977 void
  978 dummy_block_erase(mdev_t *d, unsigned long block)
  979 {
  980         if (!dummy_chip) return;
  981         FSEEK(dummy_chip, block * d->bsz);
  982         FFILL(dummy_chip, 0xFF, d->bsz);
  983 }
  984 
  985 void
  986 dummy_chip_erase(mdev_t *d)
  987 {
  988         if (!dummy_chip) return;
  989         FSEEK(dummy_chip, 0);
  990         FFILL(dummy_chip, 0xFF, d->csz);
  991 }
  992 
  993 void
  994 dummy_program(mdev_t *d, unsigned long address, size_t a, char *buf)
  995 {
  996         if (!dummy_chip) return;
  997         FSEEK(dummy_chip, address);
  998         ASSERT(fwrite(buf, a, 1, dummy_chip) == 1);
  999 }
 1000 
 1001 void
 1002 dummy_read(mdev_t *d, unsigned long address, size_t a, char *buf)
 1003 {
 1004         if (!dummy_chip) return;
 1005         FSEEK(dummy_chip, address);
 1006         ASSERT(fread(buf, a, 1, dummy_chip) == 1);
 1007 }
 1008 
 1009 /* GENERIC IMPLEMENTATION -------------------------------------------------- */
 1010 
 1011 
 1012 static void
 1013 gen_chip_setup(mdev_t *d)
 1014 {
 1015         unsigned long i, be;
 1016         unsigned char bl;
 1017         xfer_errs_fatal = 1;
 1018         if (d->quirks & NEEDS_WE_ALWAYS_ON) {
 1019                 DEBUG("WARNING: chip requires WP# always active!\n");
 1020                 we(d, 1);
 1021                 reset();
 1022                 write_mem(d, 0x5555, 0xAA);
 1023                 write_mem(d, 0x2AAA, 0x55);
 1024                 write_mem(d, 0x5555, 0x90);
 1025                 if ((bl = read_mem(d, 0x000FFFF2) & 0xc) > 0)
 1026                         ABORT("CHIP STILL LOCKED! %02x\n", bl);
 1027                 write_mem(d, 0x0000, 0xF0);
 1028         }
 1029         if (d->quirks & NEEDS_MISC_BLOCK_UNLOCK) {
 1030                 be = d->csz / d->bsz;
 1031                 for (i = 0; i < be; i++) {
 1032                         DEBUG("unlocking block %lu / %lu\r", i + 1, be);
 1033                         misc_unlock_block(d, i);
 1034                 }
 1035                 DEBUG("\n");
 1036         }
 1037 }
 1038 
 1039 static void
 1040 gen_read(mdev_t *d, char *buf, unsigned long s, unsigned long a, int o)
 1041 {
 1042         if (!d->read)
 1043                 ABORT("this chip has no read implementation!\n");
 1044         opp_q = !o;
 1045         XFEROP(d, s, a, XFER_R, do {
 1046                     VDEBUG(3, "DREAD: %08lx, %08lx\n", i, (unsigned long)xf);
 1047                     d->read(d, i, xf, buf);
 1048             } while (0));
 1049 }
 1050 
 1051 static void
 1052 gen_wait_status(mdev_t *d, ndelay_t fallback, int slow)
 1053 {
 1054         int t = 0;
 1055         reset_echk();
 1056         if (!d->erased) {
 1057                 ndelay(fallback);
 1058                 return;
 1059         } do {
 1060                 if (slow)
 1061                         DELAY_FOR(d, toggle_bit_delay);
 1062                 t++;
 1063         } while (d->erased(d) == 0);
 1064         VDEBUG(5, "WAITED: %d tries\n", t);
 1065 }
 1066 
 1067 static void
 1068 gen_erase_block(mdev_t *d, unsigned long block)
 1069 {
 1070         unsigned long i, ss, se;
 1071         char sanity[1];
 1072         we(d, 1);
 1073         if (d->b_erase) {
 1074                 d->b_erase(d, block);
 1075         } else if (d->bsz && d->csz && d->s_erase) {
 1076                 ss = (block    ) * d->bsz / d->ssz;
 1077                 se = (block + 1) * d->bsz / d->ssz;
 1078                 for (i = ss; i < se; i++)
 1079                         d->s_erase(d, i);
 1080         } else ABORT("no generic block erasure method could be employed.\n");
 1081         /* sanity check */
 1082         we(d, 0);
 1083         gen_read(d, sanity, d->bsz * block, 1, 0);
 1084         ASSERT(sanity[0] == 0xFF);
 1085 }
 1086 
 1087 static void
 1088 gen_erase_chip(mdev_t *d, int o)
 1089 {
 1090         unsigned long i, be;
 1091         we(d, 1);
 1092         if (d->c_erase) {
 1093                 DEBUG("issuing a complete chip erase command...\n");
 1094                 d->c_erase(d);
 1095         } else {
 1096                 be = d->csz / d->bsz;
 1097                 for (i = 0; i < be; i++) {
 1098                         if (o) DEBUG("erase block %lu / %lu\r", i + 1, be);
 1099                         gen_erase_block(d, i);
 1100                 }
 1101                 if (o) DEBUG("\n");
 1102         }
 1103         we(d, 0);
 1104 }
 1105 
 1106 static void
 1107 gen_write(mdev_t *d, char *buf, unsigned long s, unsigned long a, int o)
 1108 {
 1109         unsigned long e = s + a;
 1110         ASSERT(e <= d->csz);
 1111         we(d, 1);
 1112         if (!d->write)
 1113                 ABORT("this chip has no write implementation!\n");
 1114         opp_q = !o;
 1115         XFEROP(d, s, a, XFER_W, do {
 1116                     VDEBUG(3, "DWRITE: %08lx, %08lx\n", i, (unsigned long)xf);
 1117                     d->write(d, i, xf, buf);
 1118             } while (0));
 1119         we(d, 0);
 1120 }
 1121 
 1122 /* ERASE-WRITE-VERIFY CODE ------------------------------------------------- */
 1123 
 1124 
 1125 static char *
 1126 alloc_chip(mdev_t *d)
 1127 {
 1128         return malloc(d->csz);
 1129 }
 1130 
 1131 enum fwf {
 1132         FWF_ERASE,
 1133         FWF_WRITE,
 1134         FWF_VERIFY
 1135 };
 1136 
 1137 enum fwc {
 1138         FWF_WAIT        = '.',
 1139         FWF_PROGRESS    = '%',
 1140         FWF_DONE        = 'S'
 1141 };
 1142 
 1143 static void
 1144 fwc_template(int blocks)
 1145 {
 1146         int i;
 1147 #define PCM(...) for (i = 0; i < blocks; i++) DEBUG(__VA_ARGS__); DEBUG("\n");
 1148         DEBUG("   BLOCK  : "); PCM("%01X", i);
 1149         DEBUG("   ERASE  : "); PCM("%c", FWF_WAIT);
 1150         DEBUG("   WRITE  : "); PCM("%c", FWF_WAIT);
 1151         DEBUG("   VERIFY : "); PCM("%c", FWF_WAIT);
 1152 }
 1153 
 1154 static void
 1155 fwc_setfield(int field, int block, char v)
 1156 {
 1157         DEBUG("\r\033[%dA\033[%dC%c\r\033[%dB",
 1158             3 - field, 12 + block, v, 3 - field);
 1159         fflush(stderr);
 1160 }
 1161 
 1162 static void
 1163 full_write_cycle(mdev_t *d, char *buf)
 1164 {
 1165         char *vbuf;
 1166         unsigned long i, be, bs;
 1167         be = d->csz / d->bsz;
 1168         DEBUG("initiating a full EWV (Erase Write Verify) cycle...\n\n");
 1169         fwc_template(be);
 1170         vbuf = alloc_chip(d);
 1171         for (i = 0; i < be; i++) {
 1172                 bs = i * d->bsz;
 1173                 fwc_setfield(FWF_ERASE, i, FWF_PROGRESS);
 1174                 gen_erase_block(d, i);
 1175                 fwc_setfield(FWF_ERASE, i, FWF_DONE);
 1176                 fwc_setfield(FWF_WRITE, i, FWF_PROGRESS);
 1177                 gen_write(d, buf + bs, bs, d->bsz, 0);
 1178                 fwc_setfield(FWF_WRITE, i, FWF_DONE);
 1179                 fwc_setfield(FWF_VERIFY, i, FWF_PROGRESS);
 1180                 gen_read(d, vbuf, bs, d->bsz, 0);
 1181                 if (memcmp(vbuf, buf + bs, d->bsz) != 0)
 1182                         ABORT("\nverify 1 failed for block %lu\n", i);
 1183                 fwc_setfield(FWF_VERIFY, i, FWF_DONE);
 1184         }
 1185         DEBUG("\n   SUCCESS -- checking full chip...\n");
 1186         gen_read(d, vbuf, 0, d->csz, 1);
 1187         if (memcmp(vbuf, buf, d->csz) != 0)
 1188                 ABORT("verify 2 failed for chip\n");
 1189         DEBUG("   SUCCESS -- all ok!\n");
 1190         free(vbuf);
 1191 }
 1192 
 1193 /* USER INTERFACE FUNCTIONALITY -------------------------------------------- */
 1194 
 1195 
 1196 static mdev_t *
 1197 get_chip_by_name(char *name)
 1198 {
 1199         int i;
 1200         mdev_t *r;
 1201         for (i = 0; i < devices; i++)
 1202         {
 1203                 r = &devicetab[i];
 1204                 if (strcasecmp(r->name, name) == 0)
 1205                         return r;
 1206         }
 1207         return NULL;
 1208 }
 1209 
 1210 static void
 1211 usage()
 1212 {
 1213         ABORT(
 1214             "SBC FWH/LPC flash tool\n\n"
 1215             " -i (identify only)\n"
 1216             " -r <file> (read to file)\n"
 1217             " -w <file> (write from file)\n"
 1218             " -E (erase)\n"
 1219             " -W (write without erasing)\n"
 1220             " -c <chip> (override chip detection)\n"
 1221             " -d <file> (open file as backing for dummy chip)\n"
 1222             " -f (force untested chip)\n");
 1223 }
 1224 
 1225 static const char *
 1226 fmt_chip_status(int status)
 1227 {
 1228         switch (status) {
 1229         default:
 1230         case TEST_WIP:  return "!WORK IN PROGRESS!";
 1231         case TEST_NONE: return "NONE";
 1232         case TEST_I:    return "IDENTIFY";
 1233         case TEST_IR:   return "IDENTIFY READ";
 1234         case TEST_IRW:  return "IDENTIFY READ WRITE";
 1235         }
 1236 }
 1237 
 1238 int
 1239 main(int argc, char **argv)
 1240 {
 1241         int ch, dwrite = 0, force = 0;
 1242         enum {
 1243                 CM_NOTHING,
 1244                 CM_IDENTIFY,
 1245                 CM_READ,
 1246                 CM_WRITE,
 1247                 CM_ERASE
 1248         } mode = CM_NOTHING;
 1249         mdev_t *d = NULL;
 1250         char *buf, *chip_name = NULL;
 1251 #ifndef BOARD_DUMMY
 1252         int i;
 1253         mdev_t *dt;
 1254 #endif
 1255         prepare_pins();
 1256 
 1257 #define TRY_OPEN_FILE(f, m) if ((f = fopen(optarg, m)) == NULL) {       \
 1258         perror(NULL); exit(1); }
 1259         while ((ch = getopt(argc, argv, "hir:w:EW:c:d:f")) != -1) {
 1260                 switch (ch) {
 1261                 case 'i':
 1262                         mode = CM_IDENTIFY;
 1263                         break;
 1264                 case 'r':
 1265                         mode = CM_READ;
 1266                         TRY_OPEN_FILE(fp, "wb");
 1267                         break;
 1268                 case 'w':
 1269                         mode = CM_WRITE;
 1270                         TRY_OPEN_FILE(fp, "rb");
 1271                         break;
 1272                 case 'E':
 1273                         mode = CM_ERASE;
 1274                         break;
 1275                 case 'W':
 1276                         dwrite = 1;
 1277                         break;
 1278                 case 'c':
 1279                         chip_name = strdup(optarg);
 1280                         break;
 1281                 case 'd':
 1282                         TRY_OPEN_FILE(dummy_chip, "r+b");
 1283                         break;
 1284                 case 'f':
 1285                         force = 1;
 1286                         break;
 1287                 case '?':
 1288                 case 'h':
 1289                 default:
 1290                         usage();
 1291                         break;
 1292                 }
 1293         }
 1294         argc -= optind;
 1295         argv += optind;
 1296 
 1297         if (mode == CM_NOTHING)
 1298                 ABORT("no mode selected, aborting.\n");
 1299         if (dwrite && mode != CM_WRITE)
 1300                 ABORT("need to specify -w with -W.\n");
 1301 
 1302 #ifdef BOARD_DUMMY
 1303         chip_name = "dummy";
 1304         d = get_chip_by_name(chip_name);
 1305 #else
 1306         if (chip_name) {
 1307                 d = get_chip_by_name(chip_name);
 1308                 if (d->probe && !d->probe(d)) {
 1309                         DEBUG("WARNING: forced chip but probe failed!\n");
 1310                 }
 1311         } else {
 1312                 for (i = 0; i < devices; i++)
 1313                 {
 1314                         dt = &devicetab[i];
 1315                         if (dt->probe && dt->probe(dt)) {
 1316                                 d = dt;
 1317                                 break;
 1318                         }
 1319                 }
 1320         }
 1321 #endif
 1322         if (dummy_chip)
 1323                 ASSERT(ftruncate(fileno(dummy_chip), d->csz) == 0);
 1324 
 1325         if (global_t0 != 0xf)
 1326                 ABORT("wiring fault, tar0 max at %d\n", global_t0);
 1327         if (!d)
 1328                 ABORT("no supported flash chip found!\n");
 1329 
 1330         DEBUG("found %s at %s!\n", d->name,
 1331             d->type == BUS_FWH ? "FWH" : "LPC");
 1332 
 1333         DEBUG("detected chip tested for operations: %s\n",
 1334             fmt_chip_status(d->status));
 1335         if (!force && d->status != TEST_IRW)
 1336                 ABORT(
 1337                     "detected chip hasn't been fully tested!\n"
 1338                     "you may leave the chip unrecoverable. (see -f)\n");
 1339 
 1340         if (mode == CM_IDENTIFY) return 0;
 1341         gen_chip_setup(d);
 1342 
 1343         buf = alloc_chip(d);
 1344 
 1345         /*
 1346          * Chip size and block size must always be defined (even if block size
 1347          * is not a real number, although it must always be a multiple of the
 1348          * sector size).
 1349          */
 1350         ASSERT(d->bsz && d->csz);
 1351 
 1352         switch (mode) {
 1353         default:
 1354                 usage();
 1355                 break;
 1356         case CM_READ:
 1357                 gen_read(d, buf, 0, d->csz, 1);
 1358                 ASSERT(fwrite(buf, d->csz, 1, fp) == 1);
 1359                 break;
 1360         case CM_WRITE:
 1361                 ASSERT(fread(buf, d->csz, 1, fp) == 1);
 1362                 if (!dwrite) full_write_cycle(d, buf);
 1363                 else gen_write(d, buf, 0, d->csz, 1);
 1364                 break;
 1365         case CM_ERASE:
 1366                 gen_erase_chip(d, 1);
 1367                 break;
 1368         }
 1369 
 1370         if (fp) fclose(fp);
 1371         if (dummy_chip) fclose(dummy_chip);
 1372         free(buf);
 1373         return 0;
 1374 }