diff --git a/meta-digi-arm/recipes-bsp/nvram/nvram.bb b/meta-digi-arm/recipes-bsp/nvram/nvram.bb new file mode 100644 index 000000000..daac38f8b --- /dev/null +++ b/meta-digi-arm/recipes-bsp/nvram/nvram.bb @@ -0,0 +1,45 @@ +SUMMARY = "Digi's NVRAM tool" +SECTION = "base" +LICENSE = "GPL-2.0" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6" + +PR = "r0" + +DEPENDS = "libdigi" + +SRCREV = "${AUTOREV}" +SRC_URI = " \ + ${DIGI_LOG_GIT}u-boot-denx.git;protocol=git;branch=refs/heads/master \ + file://main.c \ + file://nvram_priv_linux.c \ + " + +S = "${WORKDIR}" + +CMD_GIT_SHA1 = "$(cd ${THISDIR} && git rev-parse --short HEAD)" +LIB_GIT_SHA1 = "$(cd ${WORKDIR}/git && git rev-parse --short HEAD)" + +CFLAGS += "-Wall -DLINUX -DCMD_GIT_SHA1=\"${CMD_GIT_SHA1}\" -DLIB_GIT_SHA1=\"${LIB_GIT_SHA1}\" -Ilib/include -I${STAGING_INCDIR}/libdigi" + +do_configure() { + rm -f lib && ln -s git/common/digi/cmd_nvram/lib +} + +do_compile() { + # 'libnvram.a' static library + ${CC} ${CFLAGS} -c -o nvram.o lib/src/nvram.c + ${CC} ${CFLAGS} -c -o nvram_cmdline.o lib/src/nvram_cmdline.c + ${CC} ${CFLAGS} -c -o nvram_priv_linux.o nvram_priv_linux.c + ${AR} -rcs libnvram.a nvram.o nvram_cmdline.o nvram_priv_linux.o + # 'nvram' command-line tool + ${CC} ${CFLAGS} -o nvram main.c libnvram.a -ldigi +} + +do_install() { + mkdir -p ${D}${base_sbindir} ${D}${includedir} ${D}${libdir} + install -m 0644 libnvram.a ${D}${libdir}/ + install -m 0644 lib/include/nvram.h lib/include/nvram_types.h ${D}${includedir}/ + install -m 0755 nvram ${D}${base_sbindir}/ +} + +PACKAGE_ARCH = "${MACHINE_ARCH}" diff --git a/meta-digi-arm/recipes-bsp/nvram/nvram/main.c b/meta-digi-arm/recipes-bsp/nvram/nvram/main.c new file mode 100644 index 000000000..f3627cf0f --- /dev/null +++ b/meta-digi-arm/recipes-bsp/nvram/nvram/main.c @@ -0,0 +1,266 @@ +/* + * nvram/src/main.c + * + * Copyright (C) 2006-2013 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version2 as published by + * the Free Software Foundation. + */ +/* + * !Author: Markus Pietrek + * !Descr: main() and user code for nvram. + */ + +#include /* errno */ +#include /* open */ +#include /* vprintf */ +#include /* snprintf */ +#include /* EXIT_SUCCESS */ +#include /* strdup */ +#include + +/* from libdigi */ +#include +#include +#include + +#include "nvram.h" /* Nv* */ + +#define CA(cmd) \ + do { \ + if( !cmd ) \ + ExitError( #cmd ); \ + } while( 0 ) + +#define VERSION "1.15" "-g"CMD_GIT_SHA1 + +/* Hack to change priv_linux mode */ +void NvPrivLinuxSetMode(char bManufMode); + +/* local functions */ +static void ExitError(const char *szFormat, ...); +static void OnExit(void); +static void ExtendedUsage(char bCmdLine); +static void OSLoadFromFile(nv_os_type_e eOS, const char *szFile); +static void OSSaveToFile(nv_os_type_e eOS, const char *szFile); + +static char l_bOptDetailed = 0; +static char quiet = 0; +static char l_bManufMode = 0; + +int main(int argc, char *argv[]) +{ + char acVersion[128]; + uint32_t uiLibVerMajor; + uint32_t uiLibVerMinor; + int iExtendedArgs; + const char *xPrintAll[] = { "printall" }; + const char *szOSOutFile = NULL; + const char *szOSInFile = NULL; + const char *szOS = NULL; + char bSave = 0; + nv_os_type_e eOS = NVOS_NONE; + int ret; + + CmdOptEntry aCmdEntries[] = { + /*@@-nullassign@@ */// only COT_NONE may have a NULL for vValuePtr + {COT_BOOL, 'e', &l_bOptDetailed, "error_detailed", + "detailed error messages"}, + {COT_BOOL, 'b', &g_markBadBlocks, "bad-block-marking", + "On repeated error, mark block as bad."}, + {COT_STRING, 'g', &szOSOutFile, "get_os_cfg", + "copies the os configuration block to file"}, + {COT_STRING, 's', &szOSInFile, "set_os_cfg", + "copies the os configuration block from file"}, + {COT_STRING, 'o', &szOS, "os", + "select's the OS to get configuration from"}, + {COT_BOOL, 'q', &quiet, "quiet", + "display no error messages"}, + {COT_BOOL, 'm', &l_bManufMode, "manuf-mode", + "manufacturing mode (no auto-repair, permit reset)"}, + {COT_MORE_OPT, 0, NULL, "", ""}, + {COT_NONE, 0, NULL, NULL, NULL}, + /*@@+nullassign@@ */ + }; + + NvGetLibVersion(&uiLibVerMajor, &uiLibVerMinor); + snprintf(acVersion, + sizeof(acVersion) - 1, + "Version: " VERSION ", NVRAM Library %u.%u-g" LIB_GIT_SHA1 ", compiled on " + __DATE__ "," __TIME__, uiLibVerMajor, uiLibVerMinor); + acVersion[sizeof(acVersion) - 1] = 0U; + szCmdOptVersion = acVersion; + fnCmdOptExtendedUsage = ExtendedUsage; + + iExtendedArgs = cmdOptParse(argc, argv, aCmdEntries, + "NVRAM Tool for updating nvram settings"); + logMsg(LOG_HARDWARE1, + "Sizes: Critical: %i\n" + " Module ID: %i\n" + " IP: %i\n" + " IP Device: %i\n" + " Partition Table: %i\n" + " Partition Entry: %i\n" + " OS Cfg Table: %i\n" + " OS Cfg: %i\n", + sizeof(nv_critical_t), + sizeof(nv_param_module_id_t), + sizeof(nv_param_ip_t), + sizeof(nv_param_ip_device_t), + sizeof(nv_param_part_table_t), + sizeof(nv_param_part_t), + sizeof(nv_param_os_cfg_table_t), + sizeof(nv_param_os_cfg_t)); + + /* so we can close everything even on error() or on return of main */ + atexit(OnExit); + + NvPrivLinuxSetMode(l_bManufMode); + + /* In manufacturing mode, do not let library auto-repair the NVRAM */ + ret = NvInit(l_bManufMode ? NVR_MANUAL : NVR_AUTO); + if (!ret) { + /* If NVRAM was not initialized, only continue if + * we are requesting a reset. + */ + if (argc == iExtendedArgs) { + ExitError("NvInit"); + } else { + if (strcmp("reset", argv[iExtendedArgs])) + ExitError("NvInit"); + } + } + + if (NULL != szOS) { + if (!NvToOS(&eOS, szOS)) + error("OS not known: %s\n", szOS); + } + + if (NULL != szOSInFile) { + bSave = 1; + OSLoadFromFile(eOS, szOSInFile); + } + + if (NULL != szOSOutFile) + /* it's load from NVRAM view */ + OSSaveToFile(eOS, szOSOutFile); + + if (argc == iExtendedArgs) { + if ((NULL == szOSInFile) && (NULL == szOSOutFile)) + /* on -o, the user likes to read/write something */ + CA(NvCmdLine(ARRAY_SIZE(xPrintAll), xPrintAll)); + } else { + CA(NvCmdLine(argc - iExtendedArgs, (const char **)&argv[iExtendedArgs])); + + if (!strcmp("set", argv[iExtendedArgs]) || + !strcmp("reset", argv[iExtendedArgs]) || + !strcmp("init", argv[iExtendedArgs])) + bSave = 1; + } + + if (bSave) + CA(NvSave()); + + return EXIT_SUCCESS; +} + +/* ********** local functions ********** */ + +static void ExtendedUsage(char bCmdLine) +{ + if (bCmdLine == 1) + CA(NvPrintHelp()); +} + +static void ExitError(const char *szFormat, ...) +{ + const char *szError = NULL; + const char *szWhat = NULL; + const char *szFunc = NULL; + const char *szFile = NULL; + int iLine; + + va_list ap; + + if (!quiet || l_bOptDetailed) { + fprintf(stderr, "*** Error: "); + if (l_bOptDetailed) { + /*@-formatconst@ */ + va_start(ap, szFormat); + vfprintf(stderr, szFormat, ap); + va_end(ap); + fprintf(stderr, ": "); + /*@+formatconst@ */ + } + + if (NVE_GOOD != NvErrorMsg(&szError, &szWhat, &szFunc, &szFile, &iLine)) { + if (l_bOptDetailed) + fprintf(stderr, " %s: (%s) @ %s:%i (%s)", + szError, szWhat, szFile, iLine, szFunc); + else + fprintf(stderr, " %s: (%s)", szError, szWhat); + } + + fprintf(stderr, "\n"); + } + + exit(EXIT_FAILURE); +} + +static void OSLoadFromFile(nv_os_type_e eOS, const char *szFile) +{ + int iFd; + nv_param_os_cfg_t xCfg; + void *pvTmp; + + CA(NvOSCfgFind(&xCfg, eOS)); + pvTmp = malloc(xCfg.uiSize); + if (NULL == pvTmp) + systemError("malloc: %i", xCfg.uiSize); + + iFd = open(szFile, O_RDONLY); + if (-1 == iFd) + systemError("%s", szFile); + if (-1 == read(iFd, pvTmp, xCfg.uiSize)) + systemError("read"); + CLOSE(iFd); + + CA(NvOSCfgSet(eOS, pvTmp, xCfg.uiSize)); + + FREE(pvTmp); + + printf("Loaded from %s\n", szFile); +} + +static void OSSaveToFile(nv_os_type_e eOS, const char *szFile) +{ + int iFd; + nv_param_os_cfg_t xCfg; + void *pvTmp; + size_t iSize; + + CA(NvOSCfgFind(&xCfg, eOS)); + pvTmp = malloc(xCfg.uiSize); + if (NULL == pvTmp) + systemError("malloc: %i", xCfg.uiSize); + + CA(NvOSCfgGet(eOS, pvTmp, xCfg.uiSize, &iSize)); + + iFd = open(szFile, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (-1 == iFd) + systemError("%s", szFile); + if (xCfg.uiSize != write(iFd, pvTmp, xCfg.uiSize)) + systemError("write"); + CLOSE(iFd); + FREE(pvTmp); + + printf("Stored to %s\n", szFile); +} + +/*! \brief closes all descriptors on any exit */ +static void OnExit(void) +{ + NvFinish(); +} diff --git a/meta-digi-arm/recipes-bsp/nvram/nvram/nvram_priv_linux.c b/meta-digi-arm/recipes-bsp/nvram/nvram/nvram_priv_linux.c new file mode 100644 index 000000000..47cbffe65 --- /dev/null +++ b/meta-digi-arm/recipes-bsp/nvram/nvram/nvram_priv_linux.c @@ -0,0 +1,302 @@ +/* + * nvram/src/nvram_priv_linux.c + * + * Copyright (C) 2006-2013 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version2 as published by + * the Free Software Foundation. + */ +/* + * !Author: Markus Pietrek + * !Descr: Defines the private functions needed by the nvram core to + * access I2C, Flash and a console for linux userspace. + */ + +#define _XOPEN_SOURCE 500 /* for pread/pwrite */ + +#include /* ENOTSUP */ +#include /* open */ +#include /* MEMERASE */ +#include /* vprintf */ +#include /* ioctl */ +#include /* stat */ + +/* from libdigi */ +#include /* systemError */ +#include /* CLEAR */ + +#include "nvram_priv.h" + +#define NVRAM_PARTITION 1 + +char g_markBadBlocks = 0; + +/* ********** local variables ********** */ +static char l_acMtd[32]; +static int l_iFdMtd = -1; +static mtd_info_t l_xMtdInfo; +static unsigned char bbMaxRetries = 3; +extern void MemDump(const void *pvBase, loff_t iOffset, size_t iLen); + +static char l_bManufMode = 0; + +/* ********** global functions ********** */ +void NvPrivLinuxSetMode(char bManufMode) +{ + /* Hack so linux nvram can change behavior of priv_linux */ + /* without ubootenv also changing. */ + l_bManufMode = bManufMode; +} + +int NvPrivOSInit(void) +{ + struct stat xStat; + + CLEAR(xStat); + + /* detect NVRAM partition */ + SPRINTF(l_acMtd, "/dev/mtd/%i", NVRAM_PARTITION); + + /* determine whether we are /dev/mtd/ or /dev/mtd */ + if (-1 == stat(l_acMtd, &xStat)) { + SPRINTF(l_acMtd, "/dev/mtd%i", NVRAM_PARTITION); + /* not dev fs */ + if (-1 == stat(l_acMtd, &xStat)) + return NV_SET_ERROR(NVE_NO_DEV, strerror(errno)); + } + + return 1; +} + +int NvPrivOSFinish(void) +{ + return 1; +} + +int NvPrivOSPostInit(void) +{ + return 1; +} + +int NvPrivOSCriticalPostReset(struct nv_critical *pParams) +{ + /* nothing to do */ + return 1; +} + +int NvPrivOSCriticalPartReset(struct nv_critical *pCrit, nv_os_type_e eForOS) +{ + if (l_bManufMode) { + /* + * In manufacturing mode, don't return an error, assuming + * that caller knows what they're doing. + */ + return 1; + } else { + /* + * Retain previous behavior of returning an error, which + * will cause us to exit before calling NvSave(); this is + * done to prevent 'nvram reset' from linux from erasing the + * OSCfgTable, since we won't properly restore the ubootenv + * section. + */ + RETURN_NOT_IMPLEMENTED(); + } +} + +int NvPrivOSFlashOpen(char bForWrite) +{ + l_iFdMtd = open(l_acMtd, bForWrite ? (O_RDWR | O_SYNC) : O_RDONLY); + if (-1 == l_iFdMtd) + return NV_SET_ERROR(NVE_NO_DEV, strerror(errno)); + + CLEAR(l_xMtdInfo); + /* read partition info */ + if (ioctl(l_iFdMtd, MEMGETINFO, &l_xMtdInfo)) { + CLOSE(l_iFdMtd); + return NV_SET_ERROR(NVE_NO_DEV, strerror(errno)); + } + + return 1; +} + +int NvPrivOSFlashClose(void) +{ + CLOSE(l_iFdMtd); + + return 1; +} + +/* A block is marked as bad as a consequence of consecutive read/write errors, + * for example unrecoverable CRC errors, or if the data verification after a + * write finds data mismatch after a number of retries. */ +static int NvPrivMarkBadBlock(int fd, loff_t iOffset) +{ + logMsg(LOG_STATUS, "Marking offset %d as bad\n", (int)iOffset); + return (ioctl(fd, MEMSETBADBLOCK, &iOffset)); +} + +int NvPrivOSFlashRead(void *pvBuf, loff_t iOffs, size_t iLength) +{ + int iRead; + int i, iRet; + + for (i = 0; i < bbMaxRetries; i++) { + iRead = pread(l_iFdMtd, pvBuf, iLength, iOffs); + + if (iRead != iLength) { + if (g_markBadBlocks) { + systemLog("Retrying failed read:Got %i " + "Bytes instead of %i.\n", iRead, iLength); + continue; + } else { + systemLog("read failed. Got %i Bytes " + "instead of %i\n", iRead, iLength); + return NV_SET_ERROR(NVE_IO, strerror(errno)); + } + } + break; + } + + if (g_markBadBlocks && (i >= bbMaxRetries)) { + /* Read error, for example unrecoverable ECC */ + iRet = NvPrivMarkBadBlock(l_iFdMtd, iOffs); + return NV_SET_ERROR(NVE_IO, strerror(iRet)); + } + + return 1; +} + +int NvPrivOSFlashErase(loff_t iOffs) +{ + erase_info_t xErase; + CLEAR(xErase); + + xErase.length = l_xMtdInfo.erasesize; + xErase.start = iOffs; + if (ioctl(l_iFdMtd, MEMERASE, &xErase)) + return NV_SET_ERROR(NVE_IO, strerror(errno)); + + return 1; +} + +int NvPrivOSFlashWrite( /*@in@ */ const void *pvBuf, loff_t iOffs, size_t iLength) +{ + int iWritten, iRead; + int i, iRet; + unsigned char *pvRdBuf; + + /* we are not called for bad sectors */ + + for (i = 0; i < bbMaxRetries; i++) { + iWritten = pwrite(l_iFdMtd, pvBuf, iLength, iOffs); + if (iWritten != iLength) { + if (g_markBadBlocks) { + systemLog("Retrying failed write:" + "Wrote %i Bytes" + " instead of %i.\n", iWritten, iLength); + continue; + } else { + logMsg(LOG_ERR, "write failed." + " Wrote %i Bytes" " instead of %i\n", iWritten, iLength); + return NV_SET_ERROR(NVE_IO, strerror(errno)); + } + } + + if (g_markBadBlocks) { + pvRdBuf = (unsigned char *)malloc(iLength); + if (NULL == pvRdBuf) { + systemLog("Malloc failed.\n"); + return NV_SET_ERROR(NVE_IO, strerror(errno)); + } + for (i = 0; i < bbMaxRetries; i++) { + iRead = pread(l_iFdMtd, pvRdBuf, iLength, iOffs); + if (iRead != iLength) { + systemLog("Retrying failed read:" + "%i < > %i.\n", iRead, iLength); + continue; + } + if (memcmp(pvRdBuf, pvBuf, iLength) != 0) { + logMsg(LOG_ERR, + "\nData mismatch at offset 0x%08x\n", iOffs); + logMsg(LOG_ERR, "Source is"); + MemDump(pvBuf, iOffs & ~0xf, MIN(iLength, 0x20)); + logMsg(LOG_ERR, "Flash is"); + MemDump(pvRdBuf, iOffs & ~0xf, MIN(iRead, 0x20)); + continue; + } + break; + } + FREE(pvRdBuf); + } + break; + } + + if (g_markBadBlocks && (i >= bbMaxRetries)) { + iRet = NvPrivMarkBadBlock(l_iFdMtd, iOffs); + return NV_SET_ERROR(NVE_IO, strerror(iRet)); + } + + return 1; +} + +int NvPrivOSFlashProtect(loff_t iOffs, size_t iLength, char bProtect) +{ + erase_info_t xErase; + CLEAR(xErase); + + xErase.length = l_xMtdInfo.erasesize; + xErase.start = iOffs; + if (ioctl(l_iFdMtd, (bProtect ? MEMLOCK : MEMUNLOCK), &xErase)) { + if (ENOTSUP != errno) + /* e.g. NAND */ + return NV_SET_ERROR(NVE_IO, strerror(errno)); + } + + return 1; +} + +int NvPrivOSFlashInfo(loff_t iOffs, +/*@out@*/ struct nv_priv_flash_status *pStatus) +{ + int iRes; + + CLEAR(*pStatus); + + /* linux hasn't an interface yet to determine erase size at iOffs. + Anyway, we place NVRAM immediately after U-Boot, so we have unique + erase sizes */ + pStatus->iEraseSize = l_xMtdInfo.erasesize; + pStatus->type = l_xMtdInfo.type; + + /* determine whether block at iOffs is bad */ + iRes = ioctl(l_iFdMtd, MEMGETBADBLOCK, &iOffs); + + if (iRes > 0) + pStatus->bBad = 1; + else if ((iRes < 0) && (ENOTSUP != errno)) + return NV_SET_ERROR(NVE_IO, strerror(errno)); + /* else if not supported (NOR), is is assumed good */ + + return 1; +} + +void NvPrivOSPrintf(const char *szFormat, ...) +{ + va_list ap; + + va_start(ap, szFormat); + vprintf(szFormat, ap); + va_end(ap); +} + +void NvPrivOSPrintfError(const char *szFormat, ...) +{ + va_list ap; + + va_start(ap, szFormat); + vfprintf(stderr, szFormat, ap); + va_end(ap); +} diff --git a/meta-digi-dbl/recipes-core/packagegroups/packagegroup-dbl-core.bb b/meta-digi-dbl/recipes-core/packagegroups/packagegroup-dbl-core.bb index c88642b6c..ecd232126 100644 --- a/meta-digi-dbl/recipes-core/packagegroups/packagegroup-dbl-core.bb +++ b/meta-digi-dbl/recipes-core/packagegroups/packagegroup-dbl-core.bb @@ -35,6 +35,7 @@ RDEPENDS_${PN} = "\ ${@base_contains("MACHINE_FEATURES", "touchscreen", "tslib tslib-calibrate tslib-tests", "",d)} \ modutils-initscripts \ netbase \ + nvram \ ${VIRTUAL-RUNTIME_login_manager} \ ${VIRTUAL-RUNTIME_init_manager} \ ${VIRTUAL-RUNTIME_update-alternatives} \ diff --git a/meta-digi-del/recipes-core/packagegroups/packagegroup-del-core.bb b/meta-digi-del/recipes-core/packagegroups/packagegroup-del-core.bb index 30b7c99c4..02f59c3f3 100644 --- a/meta-digi-del/recipes-core/packagegroups/packagegroup-del-core.bb +++ b/meta-digi-del/recipes-core/packagegroups/packagegroup-del-core.bb @@ -35,6 +35,7 @@ RDEPENDS_${PN} = "\ ${@base_contains("MACHINE_FEATURES", "touchscreen", "tslib tslib-calibrate tslib-tests", "",d)} \ modutils-initscripts \ netbase \ + nvram \ ${VIRTUAL-RUNTIME_login_manager} \ ${VIRTUAL-RUNTIME_init_manager} \ ${VIRTUAL-RUNTIME_update-alternatives} \