From 1a88e745dbdc61dc6b4002df36560f3b821a37a0 Mon Sep 17 00:00:00 2001
From: Grzegorz Daniluk <grzegorz.daniluk@gmail.com>
Date: Thu, 19 Jul 2012 16:30:14 +0200
Subject: [PATCH] shell: handling init configuration script stored in FMC
 EEPROM

---
 dev/eeprom.c     | 131 ++++++++++++++++++++++++++++++++++++++++++++++-
 include/eeprom.h |   8 ++-
 include/shell.h  |   4 ++
 shell/cmd_init.c |  42 +++++++++++++++
 shell/shell.c    |  29 +++++++++++
 shell/shell.mk   |   3 +-
 wrc_main.c       |   3 ++
 7 files changed, 215 insertions(+), 5 deletions(-)
 create mode 100644 shell/cmd_init.c

diff --git a/dev/eeprom.c b/dev/eeprom.c
index 5e2ae37..559b919 100644
--- a/dev/eeprom.c
+++ b/dev/eeprom.c
@@ -11,7 +11,7 @@
  * is that it starts with 0xdeadbeef pattern. The structure of SFP section is:
  *
  * --------------
- * | count (4B) |
+ * | count (1B) |
  * --------------------------------------------------------------------------------------------
  * |   SFP(1) part number (16B)       | alpha (4B) | deltaTx (4B) | deltaRx (4B) | chksum(1B) |
  * --------------------------------------------------------------------------------------------
@@ -30,6 +30,19 @@
  *
  */
 
+/*
+ * The init script area consist of 2-byte size field and a set of shell commands
+ * separated with '\n' character.
+ *
+ * -------------------
+ * | bytes used (2B) |
+ * ------------------------------------------------
+ * | shell commands separated with '\n'.....      |
+ * |                                              |
+ * |                                              |
+ * ------------------------------------------------
+ */
+
 
 int eeprom_read(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size)
 {
@@ -127,7 +140,7 @@ int32_t eeprom_get_sfp(uint8_t i2cif, uint8_t i2c_addr, struct s_sfpinfo* sfp, u
     for(i=0; i<sizeof(struct s_sfpinfo)-1; ++i) //'-1' because we do not include chksum in computation
       chksum = (uint8_t) ((uint16_t)chksum + *(ptr++)) & 0xff;
     if(chksum != sfp->chksum)
-      EE_RET_CHKSUM;
+      EE_RET_CORRPT;
   }
   else
   {
@@ -173,3 +186,117 @@ int8_t eeprom_match_sfp(uint8_t i2cif, uint8_t i2c_addr, struct s_sfpinfo* sfp)
 
   return 0;
 }
+
+int8_t eeprom_init_erase(uint8_t i2cif, uint8_t i2c_addr)
+{
+  uint16_t used = 0;
+
+  if( eeprom_write(i2cif, i2c_addr, EE_BASE_INIT, &used, sizeof(used)) != sizeof(used))
+    return EE_RET_I2CERR;
+  else
+    return used;
+}
+
+int8_t eeprom_init_purge(uint8_t i2cif, uint8_t i2c_addr)
+{
+  uint16_t used = 0xffff, i;
+  uint16_t pattern = 0xff;
+
+  eeprom_read(i2cif, i2c_addr, EE_BASE_INIT, &used, sizeof(used));
+  if(used==0xffff) used=0;
+  for(i=0; i<used; ++i)
+    eeprom_write(i2cif, i2c_addr, EE_BASE_INIT+sizeof(used)+i, &pattern, 1);
+  used = 0xffff;
+  eeprom_write(i2cif, i2c_addr, EE_BASE_INIT, &used, 2);
+
+  return used;
+}
+
+/* 
+ * Appends a new shell command at the end of boot script
+ */
+int8_t eeprom_init_add(uint8_t i2cif, uint8_t i2c_addr, const char *args[])
+{
+  uint8_t i=1;
+  char separator = ' ';
+  uint16_t used, readback;
+
+  if( eeprom_read(i2cif, i2c_addr, EE_BASE_INIT, &used, sizeof(used)) != sizeof(used) )
+    return EE_RET_I2CERR;
+
+  if( used==0xffff ) used=0;  //this means the memory is blank
+
+  while(args[i]!='\0')
+  {
+    if( eeprom_write(i2cif, i2c_addr, EE_BASE_INIT+sizeof(used)+used, args[i], strlen(args[i])) != strlen(args[i]))
+      return EE_RET_I2CERR;
+    used += strlen(args[i]);
+    if( eeprom_write(i2cif, i2c_addr, EE_BASE_INIT+sizeof(used)+used, &separator, sizeof(separator)) != sizeof(separator) )
+      return EE_RET_I2CERR;
+    ++used;
+    ++i;
+  }
+  //the end of the command, replace last separator with '\n'
+  separator = '\n';
+  if( eeprom_write(i2cif, i2c_addr, EE_BASE_INIT+sizeof(used)+used-1, &separator, sizeof(separator)) != sizeof(separator) )
+    return EE_RET_I2CERR;
+  //and finally update the size of the script
+  if( eeprom_write(i2cif, i2c_addr, EE_BASE_INIT, &used, sizeof(used)) != sizeof(used) )
+    return EE_RET_I2CERR;
+
+  if( eeprom_read(i2cif, i2c_addr, EE_BASE_INIT, &readback, sizeof(readback)) != sizeof(readback) )
+    return EE_RET_I2CERR;
+
+  return 0;
+}
+
+int32_t eeprom_init_show(uint8_t i2cif, uint8_t i2c_addr)
+{
+  uint16_t used, i;
+  char byte;
+
+  if( eeprom_read(i2cif, i2c_addr, EE_BASE_INIT, &used, sizeof(used)) != sizeof(used) )
+    return EE_RET_I2CERR;
+
+  if(used==0 || used==0xffff) 
+  {
+    used = 0;  //this means the memory is blank
+    mprintf("Empty init script...\n");
+  }
+
+  //just read and print to the screen char after char
+  for(i=0; i<used; ++i)
+  {
+    if( eeprom_read(i2cif, i2c_addr, EE_BASE_INIT+sizeof(used)+i, &byte, sizeof(byte)) != sizeof(byte) )
+      return EE_RET_I2CERR;
+    mprintf("%c", byte);
+  }
+
+  return 0;
+}
+
+int8_t eeprom_init_readcmd(uint8_t i2cif, uint8_t i2c_addr, char* buf, uint8_t bufsize, uint8_t next)
+{
+  static uint16_t ptr;
+  static uint16_t used = 0;
+  uint8_t i=0;
+
+  if(next == 0) 
+  {
+    if( eeprom_read(i2cif, i2c_addr, EE_BASE_INIT, &used, sizeof(used)) != sizeof(used) )
+      return EE_RET_I2CERR;
+    ptr = sizeof(used);
+  }
+
+  if(ptr-sizeof(used) >= used)
+    return 0;
+
+  do
+  {
+    if(ptr-sizeof(used) > bufsize) return EE_RET_CORRPT;
+    if( eeprom_read(i2cif, i2c_addr, EE_BASE_INIT+(ptr++), &buf[i], sizeof(char)) != sizeof(char) )
+      return EE_RET_I2CERR;
+  }while(buf[i++]!='\n');
+
+  return i;
+}
diff --git a/include/eeprom.h b/include/eeprom.h
index ebe5593..e1a2dd6 100644
--- a/include/eeprom.h
+++ b/include/eeprom.h
@@ -9,7 +9,7 @@
 
 #define EE_RET_I2CERR -1
 #define EE_RET_DBFULL -2
-#define EE_RET_CHKSUM -3
+#define EE_RET_CORRPT -3
 #define EE_RET_POSERR -4
 
 extern int32_t sfp_alpha;
@@ -28,9 +28,13 @@ struct s_sfpinfo
 int eeprom_read(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size);
 int eeprom_write(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size);
 
-
 int32_t eeprom_sfpdb_erase(uint8_t i2cif, uint8_t i2c_addr);
 int32_t eeprom_sfp_section(uint8_t i2cif, uint8_t i2c_addr, size_t size, uint16_t *section_sz);
 int8_t eeprom_match_sfp(uint8_t i2cif, uint8_t i2c_addr, struct s_sfpinfo* sfp);
 
+int8_t eeprom_init_erase(uint8_t i2cif, uint8_t i2c_addr);
+int8_t eeprom_init_add(uint8_t i2cif, uint8_t i2c_addr, const char *args[]);
+int32_t eeprom_init_show(uint8_t i2cif, uint8_t i2c_addr);
+int8_t eeprom_init_readcmd(uint8_t i2cif, uint8_t i2c_addr, char* buf, uint8_t bufsize, uint8_t next);
+
 #endif
diff --git a/include/shell.h b/include/shell.h
index 30c4863..7f780ee 100644
--- a/include/shell.h
+++ b/include/shell.h
@@ -23,6 +23,8 @@ int cmd_time(const char *args[]);
 int cmd_ip(const char *args[]);
 int cmd_sdb(const char *args[]);
 int cmd_mac(const char *args[]);
+int cmd_init(const char *args[]);
+
 
 int cmd_env(const char *args[]);
 int cmd_saveenv(const char *args[]);
@@ -35,5 +37,7 @@ void env_init();
 int shell_exec(const char *buf);
 void shell_interactive();
 
+int shell_boot_script(void);
+
 #endif
 
diff --git a/shell/cmd_init.c b/shell/cmd_init.c
new file mode 100644
index 0000000..ee9d5cf
--- /dev/null
+++ b/shell/cmd_init.c
@@ -0,0 +1,42 @@
+
+#include "shell.h"
+#include "eeprom.h"
+#include "syscon.h"
+
+
+int cmd_init(const char *args[])
+{
+  if( !mi2c_devprobe(WRPC_FMC_I2C, FMC_EEPROM_ADR) )
+  {
+    mprintf("EEPROM not found..\n");
+    return -1;
+  }
+
+  if(args[0] && !strcasecmp(args[0], "erase"))
+  {
+    if( eeprom_init_erase(WRPC_FMC_I2C, FMC_EEPROM_ADR) < 0 )
+      mprintf("Could not erase init script\n");
+  }
+  else if(args[0] && !strcasecmp(args[0], "purge"))
+  {
+    eeprom_init_purge(WRPC_FMC_I2C, FMC_EEPROM_ADR);
+  }
+  else if(args[1] && !strcasecmp(args[0], "add"))
+  {
+    if( eeprom_init_add(WRPC_FMC_I2C, FMC_EEPROM_ADR, args) < 0 )
+      mprintf("Could not add the command\n");
+    else
+      mprintf("OK.\n");
+  }
+  else if(args[0] && !strcasecmp(args[0], "show"))
+  {
+    eeprom_init_show(WRPC_FMC_I2C, FMC_EEPROM_ADR);
+  }
+  else if(args[0] && !strcasecmp(args[0], "boot"))
+  {
+    shell_boot_script();
+  }
+
+  return 0;
+}
+
diff --git a/shell/shell.c b/shell/shell.c
index 57a300c..3cd9749 100644
--- a/shell/shell.c
+++ b/shell/shell.c
@@ -4,6 +4,7 @@
 
 #include "util.h"
 #include "uart.h"
+#include "syscon.h"
 #include "shell.h"
 
 #define SH_MAX_LINE_LEN 80	
@@ -45,6 +46,7 @@ static const struct shell_cmd cmds_list[] = {
 		{ "saveenv",				cmd_saveenv },
 		{ "time",						cmd_time },
 		{ "sfp",						cmd_sfp },
+    { "init",           cmd_init },
 #if WITH_ETHERBONE
 		{ "ip",							cmd_ip },
 #endif
@@ -266,3 +268,30 @@ const char* fromdec(const char* dec, int* v) {
   *v = o;
   return dec;
 }
+
+int shell_boot_script(void)
+{
+  uint8_t next=0;
+
+  //first check if EEPROM is really there
+  if( !mi2c_devprobe(WRPC_FMC_I2C, FMC_EEPROM_ADR) )
+    if( !mi2c_devprobe(WRPC_FMC_I2C, FMC_EEPROM_ADR) )
+      return -1;
+
+  while(1)
+  {
+    cmd_len = eeprom_init_readcmd(WRPC_FMC_I2C, FMC_EEPROM_ADR, cmd_buf, SH_MAX_LINE_LEN, next);
+    if(cmd_len <= 0)
+    { 
+      if(next==0) mprintf("Empty init script...\n");
+      break;
+    }
+    cmd_buf[cmd_len] = 0;
+    
+    mprintf("executing: %s", cmd_buf);
+    _shell_exec();
+    next = 1;
+  }
+
+  return 0;
+}
diff --git a/shell/shell.mk b/shell/shell.mk
index cd67fb5..d1e89ca 100644
--- a/shell/shell.mk
+++ b/shell/shell.mk
@@ -10,7 +10,8 @@ OBJS_SHELL = 	shell/shell.o \
 							shell/cmd_time.o \
 							shell/cmd_gui.o \
 							shell/cmd_sdb.o \
-							shell/cmd_mac.o
+							shell/cmd_mac.o \
+							shell/cmd_init.o
 
 ifneq ($(WITH_ETHERBONE), 0)
 OBJS_SHELL += shell/cmd_ip.o
diff --git a/wrc_main.c b/wrc_main.c
index d7ea79e..cef1876 100644
--- a/wrc_main.c
+++ b/wrc_main.c
@@ -71,6 +71,9 @@ void wrc_initialize()
   ipv4_init("wru1");
   arp_init("wru1");
 #endif
+
+  //try to read and execute init script from EEPROM
+  shell_boot_script();
 }
 
 #define LINK_WENT_UP 1
-- 
GitLab