1/* 2 * MTD utility functions 3 * 4 * Copyright (C) 2014, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: mtd.c 289794 2011-10-14 08:24:08Z $ 19 */ 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include <unistd.h> 25#include <limits.h> 26#include <sys/sysmacros.h> 27#include <sys/types.h> 28#include <sys/stat.h> 29#include <fcntl.h> 30#include <errno.h> 31#include <error.h> 32#include <sys/ioctl.h> 33#include <sys/sysinfo.h> 34 35#ifdef LINUX26 36#include <mtd/mtd-user.h> 37#else /* LINUX26 */ 38#include <linux/mtd/mtd.h> 39#endif /* LINUX26 */ 40 41#include <trxhdr.h> 42#include <bcmutils.h> 43#include <bcmendian.h> 44#include <bcmnvram.h> 45#include <shutils.h> 46 47/* 48 * Open an MTD device 49 * @param mtd path to or partition name of MTD device 50 * @param flags open() flags 51 * @return return value of open() 52 */ 53int 54mtd_open(const char *mtd, int flags) 55{ 56 FILE *fp; 57 char dev[PATH_MAX]; 58 int i; 59 60 if ((fp = fopen("/proc/mtd", "r"))) { 61 while (fgets(dev, sizeof(dev), fp)) { 62 if (sscanf(dev, "mtd%d:", &i) && strstr(dev, mtd)) { 63#ifdef LINUX26 64 snprintf(dev, sizeof(dev), "/dev/mtd%d", i); 65#else 66 snprintf(dev, sizeof(dev), "/dev/mtd/%d", i); 67#endif 68 fclose(fp); 69 return open(dev, flags); 70 } 71 } 72 fclose(fp); 73 } 74 75 return open(mtd, flags); 76} 77 78/* 79 * Erase an MTD device 80 * @param mtd path to or partition name of MTD device 81 * @return 0 on success and errno on failure 82 */ 83int 84mtd_erase(const char *mtd) 85{ 86 int mtd_fd; 87 mtd_info_t mtd_info; 88 erase_info_t erase_info; 89 int cnt; 90 int isNvram = 0; 91 92 /* Open MTD device */ 93 if ((mtd_fd = mtd_open(mtd, O_RDWR)) < 0) { 94 perror(mtd); 95 return errno; 96 } 97 98 /* Get sector size */ 99 if (ioctl(mtd_fd, MEMGETINFO, &mtd_info) != 0) { 100 perror(mtd); 101 close(mtd_fd); 102 return errno; 103 } 104 105 /* Foxconn Bob modified start, 09/06/2013, a workaround to avoid erase to next partition, 106 unknown reason, erase bad block won't return error in the case of 15th block(last block of nvram partition) is bad block */ 107 if(!strcmp(mtd, "/dev/mtd1")) 108 isNvram = 1; 109 erase_info.length = mtd_info.erasesize; 110 cnt = 0; 111 112 for (erase_info.start = 0; 113 erase_info.start < mtd_info.size; 114 erase_info.start += mtd_info.erasesize) { 115 (void) ioctl(mtd_fd, MEMUNLOCK, &erase_info); 116 if (ioctl(mtd_fd, MEMERASE, &erase_info) != 0) { 117 cprintf("%s: erase failed, could be bad block, continue next block!\n", mtd); 118 mtd_info.size -= mtd_info.erasesize; 119 continue; 120 //perror(mtd); 121 //close(mtd_fd); 122 //return errno; 123 } 124 cnt++; 125 if(isNvram==1 && cnt>=4) 126 break; 127 } 128 /* Foxconn Bob modified end on 09/06/2013 */ 129 130 close(mtd_fd); 131 return 0; 132} 133 134extern int http_get(const char *server, char *buf, size_t count, off_t offset); 135 136/* 137 * Write a file to an MTD device 138 * @param path file to write or a URL 139 * @param mtd path to or partition name of MTD device 140 * @return 0 on success and errno on failure 141 */ 142int 143mtd_write(const char *path, const char *mtd) 144{ 145 int mtd_fd = -1; 146 mtd_info_t mtd_info; 147 erase_info_t erase_info; 148 149 struct sysinfo info; 150 struct trx_header trx; 151 unsigned long crc; 152 153 FILE *fp; 154 char *buf = NULL; 155 long count, len, off; 156 int ret = -1; 157 158 /* Examine TRX header */ 159 if ((fp = fopen(path, "r"))) 160 count = safe_fread(&trx, 1, sizeof(struct trx_header), fp); 161 else 162 count = http_get(path, (char *) &trx, sizeof(struct trx_header), 0); 163 if (count < sizeof(struct trx_header)) { 164 fprintf(stderr, "%s: File is too small (%ld bytes)\n", path, count); 165 goto fail; 166 } 167 168 /* Open MTD device and get sector size */ 169 if ((mtd_fd = mtd_open(mtd, O_RDWR)) < 0 || 170 ioctl(mtd_fd, MEMGETINFO, &mtd_info) != 0 || 171 mtd_info.erasesize < sizeof(struct trx_header)) { 172 perror(mtd); 173 goto fail; 174 } 175 176 if (trx.magic != TRX_MAGIC || 177 trx.len > mtd_info.size || 178 trx.len < sizeof(struct trx_header)) { 179 fprintf(stderr, "%s: Bad trx header\n", path); 180 goto fail; 181 } 182 183 184 /* Allocate temporary buffer */ 185 /* See if we have enough memory to store the whole file */ 186 sysinfo(&info); 187 if (info.freeram >= trx.len) { 188 erase_info.length = ROUNDUP(trx.len, mtd_info.erasesize); 189 if (!(buf = malloc(erase_info.length))) 190 erase_info.length = mtd_info.erasesize; 191 } 192 /* fallback to smaller buffer */ 193 else { 194 erase_info.length = mtd_info.erasesize; 195 buf = NULL; 196 } 197 if (!buf && (!(buf = malloc(erase_info.length)))) { 198 perror("malloc"); 199 goto fail; 200 } 201 202 /* Calculate CRC over header */ 203 crc = hndcrc32((uint8 *) &trx.flag_version, 204 sizeof(struct trx_header) - OFFSETOF(struct trx_header, flag_version), 205 CRC32_INIT_VALUE); 206 207 if (trx.flag_version & TRX_NO_HEADER) 208 trx.len -= sizeof(struct trx_header); 209 210 /* Write file or URL to MTD device */ 211 for (erase_info.start = 0; erase_info.start < trx.len; erase_info.start += count) { 212 len = MIN(erase_info.length, trx.len - erase_info.start); 213 if ((trx.flag_version & TRX_NO_HEADER) || erase_info.start) 214 count = off = 0; 215 else { 216 count = off = sizeof(struct trx_header); 217 memcpy(buf, &trx, sizeof(struct trx_header)); 218 } 219 if (fp) 220 count += safe_fread(&buf[off], 1, len - off, fp); 221 else 222 count += http_get(path, &buf[off], len - off, erase_info.start + off); 223 if (count < len) { 224 fprintf(stderr, "%s: Truncated file (actual %ld expect %ld)\n", path, 225 count - off, len - off); 226 goto fail; 227 } 228 /* Update CRC */ 229 crc = hndcrc32((uint8 *)&buf[off], count - off, crc); 230 /* Check CRC before writing if possible */ 231 if (count == trx.len) { 232 if (crc != trx.crc32) { 233 fprintf(stderr, "%s: Bad CRC\n", path); 234 goto fail; 235 } 236 } 237 /* Do it */ 238 (void) ioctl(mtd_fd, MEMUNLOCK, &erase_info); 239 if (ioctl(mtd_fd, MEMERASE, &erase_info) != 0 || 240 write(mtd_fd, buf, count) != count) { 241 perror(mtd); 242 goto fail; 243 } 244 } 245 246#ifdef PLC 247 eval("gigle_util restart"); 248 nvram_set("plc_pconfig_state", "2"); 249 nvram_commit(); 250#endif 251 252 printf("%s: CRC OK\n", mtd); 253 ret = 0; 254 255fail: 256 if (buf) { 257 /* Dummy read to ensure chip(s) are out of lock/suspend state */ 258 (void) read(mtd_fd, buf, 2); 259 free(buf); 260 } 261 262 if (mtd_fd >= 0) 263 close(mtd_fd); 264 if (fp) 265 fclose(fp); 266 return ret; 267} 268