~ubuntu-branches/ubuntu/edgy/mtd/edgy

« back to all changes in this revision

Viewing changes to util/flashcp.c

  • Committer: Bazaar Package Importer
  • Author(s): Riku Voipio
  • Date: 2005-01-23 12:56:16 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050123125616-jlum1hlbtsj2sx5f
Tags: 20050122-2
* Fix the version, darn
* Get rid of historic conflict, closes: #160614

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * Copyright (c) 2d3D, Inc.
 
4
 * Written by Abraham vd Merwe <abraham@2d3d.co.za>
 
5
 * All rights reserved.
 
6
 *
 
7
 * $Id: flashcp.c,v 1.4 2004/05/05 20:46:28 gleixner Exp $
 
8
 *
 
9
 * Renamed to flashcp.c to avoid conflicts with fcp from fsh package
 
10
 *
 
11
 * Redistribution and use in source and binary forms, with or without
 
12
 * modification, are permitted provided that the following conditions
 
13
 * are met:
 
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.
 
22
 *
 
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.
 
33
 */
 
34
 
 
35
#include <stdio.h>
 
36
#include <stdarg.h>
 
37
#include <string.h>
 
38
#include <stdlib.h>
 
39
#include <sys/types.h>
 
40
#include <sys/stat.h>
 
41
#include <sys/ioctl.h>
 
42
#include <fcntl.h>
 
43
#include <unistd.h>
 
44
#include <mtd/mtd-user.h>
 
45
#include <getopt.h>
 
46
 
 
47
typedef int bool;
 
48
#define true 1
 
49
#define false 0
 
50
 
 
51
#define EXIT_FAILURE 1
 
52
#define EXIT_SUCCESS 0
 
53
 
 
54
/* for debugging purposes only */
 
55
#ifdef DEBUG
 
56
#undef DEBUG
 
57
#define DEBUG(fmt,args...) { log_printf (LOG_ERROR,"%d: ",__LINE__); log_printf (LOG_ERROR,fmt,## args); }
 
58
#else
 
59
#undef DEBUG
 
60
#define DEBUG(fmt,args...)
 
61
#endif
 
62
 
 
63
#define KB(x) ((x) / 1024)
 
64
#define PERCENTAGE(x,total) (((x) * 100) / (total))
 
65
 
 
66
/* size of read/write buffer */
 
67
#define BUFSIZE (10 * 1024)
 
68
 
 
69
/* cmd-line flags */
 
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
 
75
 
 
76
/* error levels */
 
77
#define LOG_NORMAL      1
 
78
#define LOG_ERROR       2
 
79
 
 
80
static void log_printf (int level,const char *fmt, ...)
 
81
{
 
82
   FILE *fp = level == LOG_NORMAL ? stdout : stderr;
 
83
   va_list ap;
 
84
   va_start (ap,fmt);
 
85
   vfprintf (fp,fmt,ap);
 
86
   va_end (ap);
 
87
   fflush (fp);
 
88
}
 
89
 
 
90
static void showusage (const char *progname,bool error)
 
91
{
 
92
   int level = error ? LOG_ERROR : LOG_NORMAL;
 
93
 
 
94
   log_printf (level,
 
95
                           "\n"
 
96
                           "Flash Copy - Written by Abraham van der Merwe <abraham@2d3d.co.za>\n"
 
97
                           "\n"
 
98
                           "usage: %s [ -v | --verbose ] <filename> <device>\n"
 
99
                           "       %s -h | --help\n"
 
100
                           "\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"
 
105
                           "\n",
 
106
                           progname,progname);
 
107
 
 
108
   exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
 
109
}
 
110
 
 
111
static int safe_open (const char *pathname,int flags)
 
112
{
 
113
   int fd;
 
114
 
 
115
   fd = open (pathname,flags);
 
116
   if (fd < 0)
 
117
         {
 
118
                log_printf (LOG_ERROR,"While trying to open %s",pathname);
 
119
                if (flags & O_RDWR)
 
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");
 
126
                exit (EXIT_FAILURE);
 
127
         }
 
128
 
 
129
   return (fd);
 
130
}
 
131
 
 
132
static void safe_read (int fd,const char *filename,void *buf,size_t count,bool verbose)
 
133
{
 
134
   ssize_t result;
 
135
 
 
136
   result = read (fd,buf,count);
 
137
   if (count != result)
 
138
         {
 
139
                if (verbose) log_printf (LOG_NORMAL,"\n");
 
140
                if (result < 0)
 
141
                  {
 
142
                         log_printf (LOG_ERROR,"While reading data from %s: %m\n",filename);
 
143
                         exit (EXIT_FAILURE);
 
144
                  }
 
145
                log_printf (LOG_ERROR,"Short read count returned while reading from %s\n",filename);
 
146
                exit (EXIT_FAILURE);
 
147
         }
 
148
}
 
149
 
 
150
static void safe_rewind (int fd,const char *filename)
 
151
{
 
152
   if (lseek (fd,0L,SEEK_SET) < 0)
 
153
         {
 
154
                log_printf (LOG_ERROR,"While seeking to start of %s: %m\n",filename);
 
155
                exit (EXIT_FAILURE);
 
156
         }
 
157
}
 
158
 
 
159
/******************************************************************************/
 
160
 
 
161
static int dev_fd = -1,fil_fd = -1;
 
162
 
 
163
static void cleanup (void)
 
164
{
 
165
   if (dev_fd > 0) close (dev_fd);
 
166
   if (fil_fd > 0) close (fil_fd);
 
167
}
 
168
 
 
169
int main (int argc,char *argv[])
 
170
{
 
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];
 
178
 
 
179
   (progname = strrchr (argv[0],'/')) ? progname++ : (progname = argv[0]);
 
180
 
 
181
   /*********************
 
182
        * parse cmd-line 
 
183
        *****************/
 
184
 
 
185
   for (;;) {
 
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'},
 
191
                {0, 0, 0, 0},
 
192
        };
 
193
 
 
194
        int c = getopt_long(argc, argv, short_options,
 
195
                            long_options, &option_index);
 
196
        if (c == EOF) {
 
197
                break;
 
198
        }
 
199
 
 
200
        switch (c) {
 
201
        case 'h':
 
202
                flags |= FLAG_HELP;
 
203
                DEBUG("Got FLAG_HELP\n");
 
204
                break;
 
205
        case 'v':
 
206
                flags |= FLAG_VERBOSE;
 
207
                DEBUG("Got FLAG_VERBOSE\n");
 
208
                break;
 
209
        default:
 
210
                DEBUG("Unknown parameter: %s\n",argv[option_index]);
 
211
                showusage (progname,true);
 
212
        }
 
213
   }
 
214
   if (optind+2 == argc) {
 
215
        flags |= FLAG_FILENAME;
 
216
        filename = argv[optind];
 
217
        DEBUG("Got filename: %s\n",filename);
 
218
 
 
219
        flags |= FLAG_DEVICE;
 
220
        device = argv[optind+1];
 
221
        DEBUG("Got device: %s\n",device);
 
222
   }
 
223
 
 
224
   if (flags & FLAG_HELP || progname == NULL || device == NULL)
 
225
         showusage (progname,flags != FLAG_HELP);
 
226
 
 
227
   atexit (cleanup);
 
228
 
 
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)
 
232
         {
 
233
                DEBUG("ioctl(): %m\n");
 
234
                log_printf (LOG_ERROR,"This doesn't seem to be a valid MTD flash device!\n");
 
235
                exit (EXIT_FAILURE);
 
236
         }
 
237
 
 
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)
 
241
         {
 
242
                log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename);
 
243
                exit (EXIT_FAILURE);
 
244
         }
 
245
 
 
246
   /* does it fit into the device/partition? */
 
247
   if (filestat.st_size > mtd.size)
 
248
         {
 
249
                log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device);
 
250
                exit (EXIT_FAILURE);
 
251
         }
 
252
 
 
253
   /*****************************************************
 
254
        * erase enough blocks so that we can write the file *
 
255
        *****************************************************/
 
256
 
 
257
#warning "Check for smaller erase regions"
 
258
 
 
259
   erase.start = 0;
 
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)
 
263
         {
 
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++)
 
269
                  {
 
270
                         log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks));
 
271
                         if (ioctl (dev_fd,MEMERASE,&erase) < 0)
 
272
                           {
 
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);
 
277
                                  exit (EXIT_FAILURE);
 
278
                           }
 
279
                         erase.start += mtd.erasesize;
 
280
                  }
 
281
                log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (100%%)\n",blocks,blocks);
 
282
         }
 
283
   else
 
284
         {
 
285
                /* if not, erase the whole chunk in one shot */
 
286
                if (ioctl (dev_fd,MEMERASE,&erase) < 0)
 
287
                  {
 
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);
 
291
                         exit (EXIT_FAILURE);
 
292
                  }
 
293
         }
 
294
   DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size);
 
295
 
 
296
   /**********************************
 
297
        * write the entire file to flash *
 
298
        **********************************/
 
299
 
 
300
   if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%luk (0%%)",KB (filestat.st_size));
 
301
   size = filestat.st_size;
 
302
   i = BUFSIZE;
 
303
   written = 0;
 
304
   while (size)
 
305
         {
 
306
                if (size < BUFSIZE) i = size;
 
307
                if (flags & FLAG_VERBOSE)
 
308
                  log_printf (LOG_NORMAL,"\rWriting data: %dk/%luk (%lu%%)",
 
309
                                  KB (written + i),
 
310
                                  KB (filestat.st_size),
 
311
                                  PERCENTAGE (written + i,filestat.st_size));
 
312
 
 
313
                /* read from filename */
 
314
                safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
 
315
 
 
316
                /* write to device */
 
317
                result = write (dev_fd,src,i);
 
318
                if (i != result)
 
319
                  {
 
320
                         if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n");
 
321
                         if (result < 0)
 
322
                           {
 
323
                                  log_printf (LOG_ERROR,
 
324
                                                   "While writing data to 0x%.8x-0x%.8x on %s: %m\n",
 
325
                                                   written,written + i,device);
 
326
                                  exit (EXIT_FAILURE);
 
327
                           }
 
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);
 
331
                         exit (EXIT_FAILURE);
 
332
                  }
 
333
 
 
334
                written += i;
 
335
                size -= i;
 
336
         }
 
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);
 
343
 
 
344
   /**********************************
 
345
        * verify that flash == file data *
 
346
        **********************************/
 
347
 
 
348
   safe_rewind (fil_fd,filename);
 
349
   safe_rewind (dev_fd,device);
 
350
   size = filestat.st_size;
 
351
   i = BUFSIZE;
 
352
   written = 0;
 
353
   if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%luk (0%%)",KB (filestat.st_size));
 
354
   while (size)
 
355
         {
 
356
                if (size < BUFSIZE) i = size;
 
357
                if (flags & FLAG_VERBOSE)
 
358
                  log_printf (LOG_NORMAL,
 
359
                                          "\rVerifying data: %dk/%luk (%lu%%)",
 
360
                                          KB (written + i),
 
361
                                          KB (filestat.st_size),
 
362
                                          PERCENTAGE (written + i,filestat.st_size));
 
363
 
 
364
                /* read from filename */
 
365
                safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE);
 
366
 
 
367
                /* read from device */
 
368
                safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE);
 
369
 
 
370
                /* compare buffers */
 
371
                if (memcmp (src,dest,i))
 
372
                  {
 
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);
 
376
                         exit (EXIT_FAILURE);
 
377
                  }
 
378
 
 
379
                written += i;
 
380
                size -= i;
 
381
         }
 
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);
 
388
 
 
389
   exit (EXIT_SUCCESS);
 
390
}
 
391