summaryrefslogtreecommitdiff
path: root/cleopatre/application/libspid/src/image.c
diff options
context:
space:
mode:
Diffstat (limited to 'cleopatre/application/libspid/src/image.c')
-rw-r--r--cleopatre/application/libspid/src/image.c357
1 files changed, 357 insertions, 0 deletions
diff --git a/cleopatre/application/libspid/src/image.c b/cleopatre/application/libspid/src/image.c
new file mode 100644
index 0000000000..fd658067d6
--- /dev/null
+++ b/cleopatre/application/libspid/src/image.c
@@ -0,0 +1,357 @@
+/* SPC300 bundle {{{
+ *
+ * Copyright (C) 2009 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file application/libspid/src/image.c
+ * \brief firmware image management
+ * \ingroup libspid
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#ifndef __UTESTS__
+ #include <mtd/mtd-user.h>
+#endif /* __UTESTS__ */
+#include "libspid.h"
+
+/**
+ * Give informations on the stored firmware images : current,
+ * alternate, #0 and #1.<BR>
+ * The provided image descriptor structure is fill with requested
+ * image infomration.<BR>
+ * The device name of flash partition where image is stored is
+ * put inside the provided mtd_name buffer. Buffer length must
+ * be >= LIBSPID_MTD_NAME_MAX_LEN (16).
+ *
+ * \param type type of image to get information
+ * \param image_desc pointer to structure where information is
+ * filled
+ * \param mtd_name buffer to get the mtd device name where the
+ * requested image is stored.
+ * \return error type (LIBSPID_SUCCESS if success)
+ * \return LIBSPID_ERROR_PARAM: bad input parameters
+ * \return LIBSPID_ERROR_NOT_FOUND: requested image not found
+ * \return LIBSPID_ERROR_SYSTEM: system error, see errno
+ */
+
+libspid_error_t libspid_image_get_desc(libspid_image_desc_type_t type, spidcom_image_desc_t *image_desc, char *mtd_name)
+{
+ int fd0 = 0;
+ int fd1 = 0;
+ spidcom_image_desc_t image_desc_temp[2];
+ char mtd_name_temp[2][32] = {{0}};
+ int found_index = -1;
+ char line_buffer[LIBSPID_LINE_MAX_LEN];
+ char *strtok_ctx;
+ int img_desc_0_found = 0;
+ int img_desc_1_found = 0;
+ FILE *fp;
+ char *img_desc_mtd_num;
+ spc300_nvram_t nvram;
+
+ if ( (image_desc == NULL) || (mtd_name == NULL) )
+ {
+ return LIBSPID_ERROR_PARAM;
+ }
+
+ if ( (type < 0) || (type >= LIBSPID_IMAGE_DESC_TYPE_NB) )
+ {
+ return LIBSPID_ERROR_PARAM;
+ }
+
+ if ( LIBSPID_SUCCESS != libspid_system_get_nvram(&nvram) )
+ {
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ if ( nvram.nb_images == 1 && ( type != LIBSPID_IMAGE_DESC_TYPE_0 && type != LIBSPID_IMAGE_DESC_TYPE_CURRENT ) )
+ {
+ return LIBSPID_ERROR_PARAM;
+ }
+
+ if( (fp = fopen (LIBSPID_SYSTEM_MTD_PATH, "r")) == NULL)
+ {
+ return LIBSPID_ERROR_SYSTEM;
+ }
+ while ( fgets(line_buffer, LIBSPID_LINE_MAX_LEN - 1, fp) != NULL )
+ {
+ if ( strstr(line_buffer, SPIDCOM_IMG_DESC_MTD_NAME_0) != NULL )
+ {
+ img_desc_0_found = 1;
+ /* Extract mtd path from line mtd<num>: <size> <erasesize> "nvram" */
+ img_desc_mtd_num = strtok_r(line_buffer, ": ", &strtok_ctx);
+ sprintf(mtd_name_temp[0], "%s/%s", LIBSPID_DEV_PATH, img_desc_mtd_num);
+ }
+
+ else if ( nvram.nb_images > 1 && ( strstr(line_buffer, SPIDCOM_IMG_DESC_MTD_NAME_1) != NULL ) )
+ {
+ img_desc_1_found = 1;
+ /* Extract mtd path from line mtd<num>: <size> <erasesize> "nvram" */
+ img_desc_mtd_num = strtok_r(line_buffer, ": ", &strtok_ctx);
+ sprintf(mtd_name_temp[1], "%s/%s",LIBSPID_DEV_PATH, img_desc_mtd_num);
+ }
+ }
+
+ fclose (fp);
+
+ if ( img_desc_0_found == 0 || (nvram.nb_images > 1 && img_desc_1_found == 0) )
+ {
+ return LIBSPID_ERROR_NOT_FOUND;
+ }
+
+ /* open the MTD devices for partition #0 and #1 */
+ if ( (fd0 = open(mtd_name_temp[0], O_RDONLY)) < 0 )
+ {
+ return LIBSPID_ERROR_SYSTEM;
+ }
+ if ( nvram.nb_images > 1 && (fd1 = open(mtd_name_temp[1], O_RDONLY)) < 0 )
+ {
+ close(fd0);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* get image descriptor infos from both MTD */
+ if ( (read(fd0, &image_desc_temp[0], sizeof(spidcom_image_desc_t)) < sizeof(spidcom_image_desc_t))
+ || ( nvram.nb_images > 1 && ( read(fd1, &image_desc_temp[1], sizeof(spidcom_image_desc_t)) < sizeof(spidcom_image_desc_t) ) ) )
+ {
+ close(fd0);
+ if (nvram.nb_images > 1)
+ close(fd1);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+ close(fd0);
+ close(fd1);
+
+ /* give asked type */
+ switch(type)
+ {
+ case LIBSPID_IMAGE_DESC_TYPE_0 :
+ if ( SPIDCOM_IMG_DESC_IS_VALID(image_desc_temp) )
+ {
+ found_index = 0;
+ }
+ break;
+
+ case LIBSPID_IMAGE_DESC_TYPE_1:
+ if ( SPIDCOM_IMG_DESC_IS_VALID(image_desc_temp + 1) )
+ {
+ found_index = 1;
+ }
+ break;
+
+ case LIBSPID_IMAGE_DESC_TYPE_CURRENT:
+ case LIBSPID_IMAGE_DESC_TYPE_ALTERNATE:
+ /* check image validity */
+ if ( nvram.nb_images == 1 )
+ {
+ found_index = 0;
+ }
+ else if ( !SPIDCOM_IMG_DESC_IS_VALID(image_desc_temp) )
+ {
+ found_index = 1;
+ }
+ else if ( !SPIDCOM_IMG_DESC_IS_VALID(image_desc_temp + 1) )
+ {
+ found_index = 0;
+ }
+ else
+ {
+ /* we have two images and both are valid, find the highest index */
+ if ( image_desc_temp[0].index > image_desc_temp[1].index )
+ {
+ found_index = 0;
+ }
+ else
+ {
+ found_index = 1;
+ }
+ }
+ /* give alternate index if asked */
+ if ( type == LIBSPID_IMAGE_DESC_TYPE_ALTERNATE )
+ {
+ found_index = (found_index + 1) % 2;
+ }
+ break;
+
+ default:
+ /* hum : not possible */
+ break;
+ }
+ mtd_name[0] = '\0';
+ if (found_index >= 0)
+ {
+ strcpy(mtd_name, mtd_name_temp[found_index]);
+ }
+
+ if ( (found_index < 0) || !SPIDCOM_IMG_DESC_IS_VALID(image_desc_temp + found_index) )
+ {
+ return LIBSPID_ERROR_SYSTEM;
+ }
+ memcpy( image_desc, &image_desc_temp[found_index], sizeof(spidcom_image_desc_t) );
+
+ return LIBSPID_SUCCESS;
+}
+
+/**
+ * Select the current image firmware to boot on the next time.
+ *
+ * \param select the image to select for nrxt boot
+ * \return error type (LIBSPID_SUCCESS if success)
+ * \return LIBSPID_ERROR_PARAM: bad input parameters
+ * \return LIBSPID_ERROR_NOT_FOUND: selected image is not valid
+ * \return LIBSPID_ERROR_SYSTEM: system error, see errno
+ */
+
+libspid_error_t libspid_image_select(libspid_image_select_t select)
+{
+ int fd;
+ spidcom_image_desc_t image_desc[2], *image_desc_ptr;
+ char mtd_name[2][32], current_mtd_name[32];
+ unsigned char *sector_data;
+ //region_info_t reginfo;
+ //char cmd_buffer[256];
+ spc300_nvram_t nvram;
+#ifndef __UTESTS__
+ volatile mtd_info_t meminfo;
+ erase_info_t erase;
+#else
+ struct meminfo_utests
+ {
+ int erasesize;
+ } meminfo;
+#endif /* __UTESTS__ */
+
+ if ( (select < LIBSPID_IMAGE_SELECT_0) || (select >= LIBSPID_IMAGE_SELECT_NB) )
+ {
+ return LIBSPID_ERROR_PARAM;
+ }
+
+ if ( LIBSPID_SUCCESS != libspid_system_get_nvram(&nvram) )
+ {
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ if ( nvram.nb_images == 1 )
+ {
+ if ( select != LIBSPID_IMAGE_SELECT_0 )
+ return LIBSPID_ERROR_PARAM;
+ else
+ return LIBSPID_SUCCESS;
+ }
+
+ /* get the current partition mtd_name */
+ if ( LIBSPID_SUCCESS != libspid_image_get_desc(LIBSPID_IMAGE_DESC_TYPE_CURRENT, image_desc, current_mtd_name) )
+ {
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* fill table with index 0='the new selected', 1='the other' */
+ switch(select)
+ {
+ case LIBSPID_IMAGE_SELECT_0:
+ libspid_image_get_desc(LIBSPID_IMAGE_DESC_TYPE_0, image_desc, mtd_name[0]);
+ libspid_image_get_desc(LIBSPID_IMAGE_DESC_TYPE_1, image_desc + 1, mtd_name[1]);
+ break;
+ case LIBSPID_IMAGE_SELECT_1:
+ libspid_image_get_desc(LIBSPID_IMAGE_DESC_TYPE_1, image_desc, mtd_name[0]);
+ libspid_image_get_desc(LIBSPID_IMAGE_DESC_TYPE_0, image_desc + 1, mtd_name[1]);
+ break;
+ case LIBSPID_IMAGE_SELECT_SWITCH:
+ libspid_image_get_desc(LIBSPID_IMAGE_DESC_TYPE_ALTERNATE, image_desc, mtd_name[0]);
+ libspid_image_get_desc(LIBSPID_IMAGE_DESC_TYPE_CURRENT, image_desc + 1, mtd_name[1]);
+ break;
+ default:
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* check the validity of selected partition */
+ if (!image_desc[0].is_valid)
+ {
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* check if we are selecting our current partition */
+ if ( !strcmp(current_mtd_name, mtd_name[0]) )
+ {
+ /* no work to be done
+ * bacause we are demanded to switch to the image
+ * that we are actually already running */
+ return LIBSPID_SUCCESS;
+ }
+
+ /* open the selected mtd partition */
+ if ( (fd = open(mtd_name[0], O_RDWR)) < 0 )
+ {
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+#ifndef __UTESTS__
+ /* get the flash block erase size */
+ if ( ioctl(fd, MEMGETINFO, &meminfo) < 0 )
+ {
+ //syslog(LOG_WARNING, "%s: cannot get info from %s (errno=%d)", __FUNCTION__, mtd_name[0], errno);
+ close(fd);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+#else
+ meminfo.erasesize = 64000; /* 64K sector */
+#endif /* __UTESTS__ */
+
+ /* allocate memory to copy the 1st sector of new selected partition */
+ if ( (sector_data = malloc(meminfo.erasesize)) == NULL )
+ {
+ //syslog(LOG_WARNING, "%s: memory allocation of %d bytes failed (errno=%d)", __FUNCTION__, meminfo.erasesize, errno);
+ close(fd);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* read the 1st sector data */
+ if ( read(fd, sector_data, meminfo.erasesize) < 0 )
+ {
+ free(sector_data);
+ close(fd);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+
+ /* set the new index to alternate.index + 1 */
+ image_desc_ptr = (spidcom_image_desc_t *)sector_data;
+ image_desc_ptr->index = image_desc[1].index + 1;
+
+#ifndef __UTESTS__
+ /* erase the 1st sector */
+ erase.start = 0;
+ erase.length = meminfo.erasesize;
+ if (ioctl(fd, MEMERASE, &erase) != 0)
+ {
+ //syslog(LOG_WARNING, "%s: flash erase of %s failed (errno=%d)", __FUNCTION__, mtd_name[0], errno);
+ free(sector_data);
+ close(fd);
+ return LIBSPID_ERROR_SYSTEM;
+ }
+#endif /* __UTESTS__ */
+
+ /* restore the save 1st sector */
+ /*if((fd = open(mtd_name[0], O_RDWR)) < 0)
+ {
+ syslog(LOG_WARNING, "%s: cannot open %s to restore the 1st sector (errno=%d) !!!", __FUNCTION__, mtd_name[0], errno);
+ free(sector_data);
+ return -errno;
+ }*/
+ lseek(fd, 0, SEEK_SET);
+ write(fd, sector_data, meminfo.erasesize);
+ close(fd);
+ free(sector_data);
+
+ /* ok, new sector is selected */
+ return LIBSPID_SUCCESS;
+}
+