3
* Copyright (c) 2d3D, Inc.
4
* Written by Abraham vd Merwe <abraham@2d3d.co.za>
7
* $Id: flashcp.c,v 1.4 2004/05/05 20:46:28 gleixner Exp $
9
* Renamed to flashcp.c to avoid conflicts with fcp from fsh package
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions and the following disclaimer.
16
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
* 3. Neither the name of the author nor the names of other contributors
20
* may be used to endorse or promote products derived from this software
21
* without specific prior written permission.
23
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
#include <sys/types.h>
41
#include <sys/ioctl.h>
44
#include <mtd/mtd-user.h>
51
#define EXIT_FAILURE 1
52
#define EXIT_SUCCESS 0
54
/* for debugging purposes only */
57
#define DEBUG(fmt,args...) { log_printf (LOG_ERROR,"%d: ",__LINE__); log_printf (LOG_ERROR,fmt,## args); }
60
#define DEBUG(fmt,args...)
63
#define KB(x) ((x) / 1024)
64
#define PERCENTAGE(x,total) (((x) * 100) / (total))
66
/* size of read/write buffer */
67
#define BUFSIZE (10 * 1024)
70
#define FLAG_NONE 0x00
71
#define FLAG_VERBOSE 0x01
72
#define FLAG_HELP 0x02
73
#define FLAG_FILENAME 0x04
74
#define FLAG_DEVICE 0x08
80
static void log_printf (int level,const char *fmt, ...)
82
FILE *fp = level == LOG_NORMAL ? stdout : stderr;
90
static void showusage (const char *progname,bool error)
92
int level = error ? LOG_ERROR : LOG_NORMAL;
96
"Flash Copy - Written by Abraham van der Merwe <abraham@2d3d.co.za>\n"
98
"usage: %s [ -v | --verbose ] <filename> <device>\n"
101
" -h | --help Show this help message\n"
102
" -v | --verbose Show progress reports\n"
103
" <filename> File which you want to copy to flash\n"
104
" <device> Flash device to write to (e.g. /dev/mtd0, /dev/mtd1, etc.)\n"
108
exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
111
static int safe_open (const char *pathname,int flags)
115
fd = open (pathname,flags);
118
log_printf (LOG_ERROR,"While trying to open %s",pathname);
120
log_printf (LOG_ERROR," for read/write access");
121
else if (flags & O_RDONLY)
122
log_printf (LOG_ERROR," for read access");
123
else if (flags & O_WRONLY)
124
log_printf (LOG_ERROR," for write access");
125
log_printf (LOG_ERROR,": %m\n");
132
static void safe_read (int fd,const char *filename,void *buf,size_t count,bool verbose)
136
result = read (fd,buf,count);
139
if (verbose) log_printf (LOG_NORMAL,"\n");
142
log_printf (LOG_ERROR,"While reading data from %s: %m\n",filename);
145
log_printf (LOG_ERROR,"Short read count returned while reading from %s\n",filename);
150
static void safe_rewind (int fd,const char *filename)
152
if (lseek (fd,0L,SEEK_SET) < 0)
154
log_printf (LOG_ERROR,"While seeking to start of %s: %m\n",filename);
159
/******************************************************************************/
161
static int dev_fd = -1,fil_fd = -1;
163
static void cleanup (void)
165
if (dev_fd > 0) close (dev_fd);
166
if (fil_fd > 0) close (fil_fd);
169
int main (int argc,char *argv[])
171
const char *progname,*filename = NULL,*device = NULL;
172
int i,flags = FLAG_NONE;
173
size_t result,size,written;
174
struct mtd_info_user mtd;
175
struct erase_info_user erase;
176
struct stat filestat;
177
unsigned char src[BUFSIZE],dest[BUFSIZE];
179
(progname = strrchr (argv[0],'/')) ? progname++ : (progname = argv[0]);
181
/*********************
186
int option_index = 0;
187
static const char *short_options = "hv";
188
static const struct option long_options[] = {
189
{"help", no_argument, 0, 'h'},
190
{"verbose", no_argument, 0, 'v'},
194
int c = getopt_long(argc, argv, short_options,
195
long_options, &option_index);
203
DEBUG("Got FLAG_HELP\n");
206
flags |= FLAG_VERBOSE;
207
DEBUG("Got FLAG_VERBOSE\n");
210
DEBUG("Unknown parameter: %s\n",argv[option_index]);
211
showusage (progname,true);
214
if (optind+2 == argc) {
215
flags |= FLAG_FILENAME;
216
filename = argv[optind];
217
DEBUG("Got filename: %s\n",filename);
219
flags |= FLAG_DEVICE;
220
device = argv[optind+1];
221
DEBUG("Got device: %s\n",device);
224
if (flags & FLAG_HELP || progname == NULL || device == NULL)
225
showusage (progname,flags != FLAG_HELP);
229
/* get some info about the flash device */
230
dev_fd = safe_open (device,O_SYNC | O_RDWR);
231
if (ioctl (dev_fd,MEMGETINFO,&mtd) < 0)
233
DEBUG("ioctl(): %m\n");
234
log_printf (LOG_ERROR,"This doesn't seem to be a valid MTD flash device!\n");
238
/* get some info about the file we want to copy */
239
fil_fd = safe_open (filename,O_RDONLY);
240
if (fstat (fil_fd,&filestat) < 0)
242
log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename);
246
/* does it fit into the device/partition? */
247
if (filestat.st_size > mtd.size)
249
log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device);
253
/*****************************************************
254
* erase enough blocks so that we can write the file *
255
*****************************************************/
257
#warning "Check for smaller erase regions"
260
erase.length = filestat.st_size & ~(mtd.erasesize - 1);
261
if (filestat.st_size % mtd.erasesize) erase.length += mtd.erasesize;
262
if (flags & FLAG_VERBOSE)
264
/* if the user wants verbose output, erase 1 block at a time and show him/her what's going on */
265
int blocks = erase.length / mtd.erasesize;
266
erase.length = mtd.erasesize;
267
log_printf (LOG_NORMAL,"Erasing blocks: 0/%d (0%%)",blocks);
268
for (i = 1; i <= blocks; i++)
270
log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks));
271
if (ioctl (dev_fd,MEMERASE,&erase) < 0)
273
log_printf (LOG_NORMAL,"\n");
274
log_printf (LOG_ERROR,
275
"While erasing blocks 0x%.8x-0x%.8x on %s: %m\n",
276
(unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
279
erase.start += mtd.erasesize;
281
log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (100%%)\n",blocks,blocks);
285
/* if not, erase the whole chunk in one shot */
286
if (ioctl (dev_fd,MEMERASE,&erase) < 0)
288
log_printf (LOG_ERROR,
289
"While erasing blocks from 0x%.8x-0x%.8x on %s: %m\n",
290
(unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device);
294
DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size);
296
/**********************************
297
* write the entire file to flash *
298
**********************************/
300
if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%luk (0%%)",KB (filestat.st_size));
301
size = filestat.st_size;
306
if (size < BUFSIZE) i = size;
307
if (flags & FLAG_VERBOSE)
308
log_printf (LOG_NORMAL,"\rWriting data: %dk/%luk (%lu%%)",
310
KB (filestat.st_size),
311
PERCENTAGE (written + i,filestat.st_size));
313
/* read from filename */
314
safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
316
/* write to device */
317
result = write (dev_fd,src,i);
320
if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n");
323
log_printf (LOG_ERROR,
324
"While writing data to 0x%.8x-0x%.8x on %s: %m\n",
325
written,written + i,device);
328
log_printf (LOG_ERROR,
329
"Short write count returned while writing to x%.8x-0x%.8x on %s: %d/%lu bytes written to flash\n",
330
written,written + i,device,written + result,filestat.st_size);
337
if (flags & FLAG_VERBOSE)
338
log_printf (LOG_NORMAL,
339
"\rWriting data: %luk/%luk (100%%)\n",
340
KB (filestat.st_size),
341
KB (filestat.st_size));
342
DEBUG("Wrote %d / %luk bytes\n",written,filestat.st_size);
344
/**********************************
345
* verify that flash == file data *
346
**********************************/
348
safe_rewind (fil_fd,filename);
349
safe_rewind (dev_fd,device);
350
size = filestat.st_size;
353
if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%luk (0%%)",KB (filestat.st_size));
356
if (size < BUFSIZE) i = size;
357
if (flags & FLAG_VERBOSE)
358
log_printf (LOG_NORMAL,
359
"\rVerifying data: %dk/%luk (%lu%%)",
361
KB (filestat.st_size),
362
PERCENTAGE (written + i,filestat.st_size));
364
/* read from filename */
365
safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
367
/* read from device */
368
safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE);
370
/* compare buffers */
371
if (memcmp (src,dest,i))
373
log_printf (LOG_ERROR,
374
"File does not seem to match flash data. First mismatch at 0x%.8x-0x%.8x\n",
375
written,written + i);
382
if (flags & FLAG_VERBOSE)
383
log_printf (LOG_NORMAL,
384
"\rVerifying data: %luk/%luk (100%%)\n",
385
KB (filestat.st_size),
386
KB (filestat.st_size));
387
DEBUG("Verified %d / %luk bytes\n",written,filestat.st_size);