blob: f3f70ffbad8caf6037a1ee265de0616901847f8e [file] [log] [blame]
stroese56b9e4f2004-12-16 18:43:13 +00001/*
2 * (C) Copyright 2003-2004
Detlev Zundelf1b3f2b2009-05-13 10:54:10 +02003 * Gary Jennejohn, DENX Software Engineering, garyj@denx.de.
stroese56b9e4f2004-12-16 18:43:13 +00004 * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
5 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
stroese56b9e4f2004-12-16 18:43:13 +00007 */
8
9#include <common.h>
Bartlomiej Sieka582f1a32006-03-05 18:57:33 +010010
stroese56b9e4f2004-12-16 18:43:13 +000011#include <command.h>
12#include <image.h>
13#include <asm/byteorder.h>
stroese56b9e4f2004-12-16 18:43:13 +000014#include <fat.h>
Tom Rini97801672014-11-22 08:11:08 -050015#include <flash.h>
Grant Likelyffc2dd72007-02-20 09:04:34 +010016#include <part.h>
stroese56b9e4f2004-12-16 18:43:13 +000017
18#include "auto_update.h"
19
20#ifdef CONFIG_AUTO_UPDATE
21
Jon Loeliger4ed9ed62007-07-09 18:24:55 -050022#if !defined(CONFIG_CMD_FAT)
Jon Loeliger13f75992007-07-10 10:39:10 -050023#error "must define CONFIG_CMD_FAT"
stroese56b9e4f2004-12-16 18:43:13 +000024#endif
25
26extern au_image_t au_image[];
27extern int N_AU_IMAGES;
28
Matthias Fuchs17dc7612008-04-21 14:42:06 +020029/* where to load files into memory */
30#define LOAD_ADDR ((unsigned char *)0x100000)
31#define MAX_LOADSZ 0x1c00000
stroese56b9e4f2004-12-16 18:43:13 +000032
33/* externals */
Matthias Fuchs17dc7612008-04-21 14:42:06 +020034long do_fat_read (const char *filename, void *buffer,
35 unsigned long maxsize, int dols);
stroese56b9e4f2004-12-16 18:43:13 +000036
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020037extern block_dev_desc_t ide_dev_desc[CONFIG_SYS_IDE_MAXDEVICE];
stroese56b9e4f2004-12-16 18:43:13 +000038
stroese56b9e4f2004-12-16 18:43:13 +000039int au_check_cksum_valid(int i, long nbytes)
40{
41 image_header_t *hdr;
stroese56b9e4f2004-12-16 18:43:13 +000042
43 hdr = (image_header_t *)LOAD_ADDR;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010044#if defined(CONFIG_FIT)
Marian Balakowiczd7c88a42008-02-29 14:58:34 +010045 if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010046 puts ("Non legacy image format not supported\n");
47 return -1;
48 }
49#endif
stroese56b9e4f2004-12-16 18:43:13 +000050
Marian Balakowicz41d71ed2008-01-08 18:14:09 +010051 if ((au_image[i].type == AU_FIRMWARE) &&
52 (au_image[i].size != image_get_data_size (hdr))) {
stroese56b9e4f2004-12-16 18:43:13 +000053 printf ("Image %s has wrong size\n", au_image[i].name);
54 return -1;
55 }
56
Marian Balakowicz41d71ed2008-01-08 18:14:09 +010057 if (nbytes != (image_get_image_size (hdr))) {
stroese56b9e4f2004-12-16 18:43:13 +000058 printf ("Image %s bad total SIZE\n", au_image[i].name);
59 return -1;
60 }
stroese56b9e4f2004-12-16 18:43:13 +000061
Marian Balakowicz41d71ed2008-01-08 18:14:09 +010062 /* check the data CRC */
63 if (!image_check_dcrc (hdr)) {
stroese56b9e4f2004-12-16 18:43:13 +000064 printf ("Image %s bad data checksum\n", au_image[i].name);
65 return -1;
66 }
67 return 0;
68}
69
stroese56b9e4f2004-12-16 18:43:13 +000070int au_check_header_valid(int i, long nbytes)
71{
72 image_header_t *hdr;
stroese56b9e4f2004-12-16 18:43:13 +000073
74 hdr = (image_header_t *)LOAD_ADDR;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010075#if defined(CONFIG_FIT)
Marian Balakowiczd7c88a42008-02-29 14:58:34 +010076 if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010077 puts ("Non legacy image format not supported\n");
78 return -1;
79 }
80#endif
81
stroese56b9e4f2004-12-16 18:43:13 +000082 /* check the easy ones first */
Matthias Fuchs17dc7612008-04-21 14:42:06 +020083 if (nbytes < image_get_header_size ()) {
stroese56b9e4f2004-12-16 18:43:13 +000084 printf ("Image %s bad header SIZE\n", au_image[i].name);
85 return -1;
86 }
Matthias Fuchs17dc7612008-04-21 14:42:06 +020087 if (!image_check_magic (hdr) || !image_check_arch (hdr, IH_ARCH_PPC)) {
stroese56b9e4f2004-12-16 18:43:13 +000088 printf ("Image %s bad MAGIC or ARCH\n", au_image[i].name);
89 return -1;
90 }
Marian Balakowicz41d71ed2008-01-08 18:14:09 +010091 if (!image_check_hcrc (hdr)) {
stroese56b9e4f2004-12-16 18:43:13 +000092 printf ("Image %s bad header checksum\n", au_image[i].name);
93 return -1;
94 }
stroese56b9e4f2004-12-16 18:43:13 +000095
96 /* check the type - could do this all in one gigantic if() */
Matthias Fuchs17dc7612008-04-21 14:42:06 +020097 if (((au_image[i].type & AU_TYPEMASK) == AU_FIRMWARE) &&
98 !image_check_type (hdr, IH_TYPE_FIRMWARE)) {
stroese56b9e4f2004-12-16 18:43:13 +000099 printf ("Image %s wrong type\n", au_image[i].name);
100 return -1;
101 }
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200102 if (((au_image[i].type & AU_TYPEMASK) == AU_SCRIPT) &&
103 !image_check_type (hdr, IH_TYPE_SCRIPT)) {
stroese56b9e4f2004-12-16 18:43:13 +0000104 printf ("Image %s wrong type\n", au_image[i].name);
105 return -1;
106 }
107
stroese56b9e4f2004-12-16 18:43:13 +0000108 return 0;
109}
110
stroese56b9e4f2004-12-16 18:43:13 +0000111int au_do_update(int i, long sz)
112{
113 image_header_t *hdr;
114 char *addr;
115 long start, end;
116 int off, rc;
117 uint nbytes;
118 int k;
stroese56b9e4f2004-12-16 18:43:13 +0000119
120 hdr = (image_header_t *)LOAD_ADDR;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100121#if defined(CONFIG_FIT)
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100122 if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100123 puts ("Non legacy image format not supported\n");
124 return -1;
125 }
126#endif
stroese56b9e4f2004-12-16 18:43:13 +0000127
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200128 switch (au_image[i].type & AU_TYPEMASK) {
stroese56b9e4f2004-12-16 18:43:13 +0000129 case AU_SCRIPT:
130 printf("Executing script %s\n", au_image[i].name);
131
132 /* execute a script */
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100133 if (image_check_type (hdr, IH_TYPE_SCRIPT)) {
134 addr = (char *)((char *)hdr + image_get_header_size ());
stroese56b9e4f2004-12-16 18:43:13 +0000135 /* stick a NULL at the end of the script, otherwise */
136 /* parse_string_outer() runs off the end. */
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100137 addr[image_get_data_size (hdr)] = 0;
stroese56b9e4f2004-12-16 18:43:13 +0000138 addr += 8;
139
140 /*
141 * Replace cr/lf with ;
142 */
143 k = 0;
144 while (addr[k] != 0) {
145 if ((addr[k] == 10) || (addr[k] == 13)) {
146 addr[k] = ';';
147 }
148 k++;
149 }
150
Simon Glassbf8c5b02012-02-14 19:59:21 +0000151 run_command(addr, 0);
stroese56b9e4f2004-12-16 18:43:13 +0000152 return 0;
153 }
154
155 break;
156
157 case AU_FIRMWARE:
158 case AU_NOR:
159 case AU_NAND:
160 start = au_image[i].start;
161 end = au_image[i].start + au_image[i].size - 1;
162
stroesee72a7b72005-03-16 20:58:31 +0000163 /*
164 * do not update firmware when image is already in flash.
165 */
166 if (au_image[i].type == AU_FIRMWARE) {
167 char *orig = (char*)start;
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200168 char *new = (char *)((char *)hdr +
169 image_get_header_size ());
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100170 nbytes = image_get_data_size (hdr);
stroesee72a7b72005-03-16 20:58:31 +0000171
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200172 while (--nbytes) {
stroesee72a7b72005-03-16 20:58:31 +0000173 if (*orig++ != *new++) {
174 break;
175 }
176 }
177 if (!nbytes) {
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200178 printf ("Skipping firmware update - "
179 "images are identical\n");
stroesee72a7b72005-03-16 20:58:31 +0000180 break;
181 }
182 }
183
stroese56b9e4f2004-12-16 18:43:13 +0000184 /* unprotect the address range */
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200185 if (((au_image[i].type & AU_FLAGMASK) == AU_PROTECT) ||
186 (au_image[i].type == AU_FIRMWARE)) {
187 flash_sect_protect (0, start, end);
stroese56b9e4f2004-12-16 18:43:13 +0000188 }
189
190 /*
191 * erase the address range.
192 */
193 if (au_image[i].type != AU_NAND) {
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200194 printf ("Updating NOR FLASH with image %s\n",
195 au_image[i].name);
stroese56b9e4f2004-12-16 18:43:13 +0000196 debug ("flash_sect_erase(%lx, %lx);\n", start, end);
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200197 flash_sect_erase (start, end);
stroese56b9e4f2004-12-16 18:43:13 +0000198 }
199
200 udelay(10000);
201
202 /* strip the header - except for the kernel and ramdisk */
203 if (au_image[i].type != AU_FIRMWARE) {
204 addr = (char *)hdr;
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100205 off = image_get_header_size ();
206 nbytes = image_get_image_size (hdr);
stroese56b9e4f2004-12-16 18:43:13 +0000207 } else {
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100208 addr = (char *)((char *)hdr + image_get_header_size ());
stroese56b9e4f2004-12-16 18:43:13 +0000209 off = 0;
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100210 nbytes = image_get_data_size (hdr);
stroese56b9e4f2004-12-16 18:43:13 +0000211 }
212
213 /*
214 * copy the data from RAM to FLASH
215 */
216 if (au_image[i].type != AU_NAND) {
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200217 debug ("flash_write(%p, %lx, %x)\n",
218 addr, start, nbytes);
219 rc = flash_write ((char *)addr, start,
220 (nbytes + 1) & ~1);
stroese56b9e4f2004-12-16 18:43:13 +0000221 } else {
Matthias Fuchsc0d6f112007-07-09 10:10:04 +0200222 rc = -1;
stroese56b9e4f2004-12-16 18:43:13 +0000223 }
224 if (rc != 0) {
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200225 printf ("Flashing failed due to error %d\n", rc);
stroese56b9e4f2004-12-16 18:43:13 +0000226 return -1;
227 }
228
229 /*
230 * check the dcrc of the copy
231 */
232 if (au_image[i].type != AU_NAND) {
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200233 rc = crc32 (0, (uchar *)(start + off),
234 image_get_data_size (hdr));
stroese56b9e4f2004-12-16 18:43:13 +0000235 }
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100236 if (rc != image_get_dcrc (hdr)) {
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200237 printf ("Image %s Bad Data Checksum After COPY\n",
238 au_image[i].name);
stroese56b9e4f2004-12-16 18:43:13 +0000239 return -1;
240 }
241
242 /* protect the address range */
243 /* this assumes that ONLY the firmware is protected! */
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200244 if (((au_image[i].type & AU_FLAGMASK) == AU_PROTECT) ||
245 (au_image[i].type == AU_FIRMWARE)) {
246 flash_sect_protect (1, start, end);
stroese56b9e4f2004-12-16 18:43:13 +0000247 }
248
249 break;
250
251 default:
252 printf("Wrong image type selected!\n");
253 }
254
255 return 0;
256}
257
stroese56b9e4f2004-12-16 18:43:13 +0000258static void process_macros (const char *input, char *output)
259{
260 char c, prev;
261 const char *varname_start = NULL;
262 int inputcnt = strlen (input);
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200263 int outputcnt = CONFIG_SYS_CBSIZE;
stroese56b9e4f2004-12-16 18:43:13 +0000264 int state = 0; /* 0 = waiting for '$' */
265 /* 1 = waiting for '(' or '{' */
266 /* 2 = waiting for ')' or '}' */
267 /* 3 = waiting for ''' */
268#ifdef DEBUG_PARSER
269 char *output_start = output;
270
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200271 printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n",
272 strlen(input), input);
stroese56b9e4f2004-12-16 18:43:13 +0000273#endif
274
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200275 prev = '\0'; /* previous character */
stroese56b9e4f2004-12-16 18:43:13 +0000276
277 while (inputcnt && outputcnt) {
278 c = *input++;
279 inputcnt--;
280
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200281 if (state != 3) {
stroese56b9e4f2004-12-16 18:43:13 +0000282 /* remove one level of escape characters */
283 if ((c == '\\') && (prev != '\\')) {
284 if (inputcnt-- == 0)
285 break;
286 prev = c;
287 c = *input++;
288 }
289 }
290
291 switch (state) {
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200292 case 0: /* Waiting for (unescaped) $ */
stroese56b9e4f2004-12-16 18:43:13 +0000293 if ((c == '\'') && (prev != '\\')) {
294 state = 3;
295 break;
296 }
297 if ((c == '$') && (prev != '\\')) {
298 state++;
299 } else {
300 *(output++) = c;
301 outputcnt--;
302 }
303 break;
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200304 case 1: /* Waiting for ( */
stroese56b9e4f2004-12-16 18:43:13 +0000305 if (c == '(' || c == '{') {
306 state++;
307 varname_start = input;
308 } else {
309 state = 0;
310 *(output++) = '$';
311 outputcnt--;
312
313 if (outputcnt) {
314 *(output++) = c;
315 outputcnt--;
316 }
317 }
318 break;
319 case 2: /* Waiting for ) */
320 if (c == ')' || c == '}') {
321 int i;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200322 char envname[CONFIG_SYS_CBSIZE], *envval;
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200323 /* Varname # of chars */
324 int envcnt = input - varname_start - 1;
stroese56b9e4f2004-12-16 18:43:13 +0000325
326 /* Get the varname */
327 for (i = 0; i < envcnt; i++) {
328 envname[i] = varname_start[i];
329 }
330 envname[i] = 0;
331
332 /* Get its value */
333 envval = getenv (envname);
334
335 /* Copy into the line if it exists */
336 if (envval != NULL)
337 while ((*envval) && outputcnt) {
338 *(output++) = *(envval++);
339 outputcnt--;
340 }
341 /* Look for another '$' */
342 state = 0;
343 }
344 break;
345 case 3: /* Waiting for ' */
346 if ((c == '\'') && (prev != '\\')) {
347 state = 0;
348 } else {
349 *(output++) = c;
350 outputcnt--;
351 }
352 break;
353 }
354 prev = c;
355 }
356
357 if (outputcnt)
358 *output = 0;
359
360#ifdef DEBUG_PARSER
361 printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200362 strlen (output_start), output_start);
stroese56b9e4f2004-12-16 18:43:13 +0000363#endif
364}
365
stroese56b9e4f2004-12-16 18:43:13 +0000366/*
367 * this is called from board_init() after the hardware has been set up
368 * and is usable. That seems like a good time to do this.
369 * Right now the return value is ignored.
370 */
371int do_auto_update(void)
372{
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200373 block_dev_desc_t *stor_dev = NULL;
stroese56b9e4f2004-12-16 18:43:13 +0000374 long sz;
Wolfgang Denk2ad2fce2014-11-06 14:03:05 +0100375 int i, res, old_ctrlc;
stroese56b9e4f2004-12-16 18:43:13 +0000376 char buffer[32];
377 char str[80];
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200378 int n;
stroese56b9e4f2004-12-16 18:43:13 +0000379
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200380 if (ide_dev_desc[0].type != DEV_TYPE_UNKNOWN) {
381 stor_dev = get_dev ("ide", 0);
382 if (stor_dev == NULL) {
383 debug ("ide: unknown device\n");
384 return -1;
385 }
stroese56b9e4f2004-12-16 18:43:13 +0000386 }
387
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200388 if (fat_register_device (stor_dev, 1) != 0) {
389 debug ("Unable to register ide disk 0:1\n");
stroese56b9e4f2004-12-16 18:43:13 +0000390 return -1;
391 }
stroese56b9e4f2004-12-16 18:43:13 +0000392
393 /*
394 * Check if magic file is present
395 */
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200396 if ((n = do_fat_read (AU_MAGIC_FILE, buffer,
397 sizeof(buffer), LS_NO)) <= 0) {
398 debug ("No auto_update magic file (n=%d)\n", n);
stroese56b9e4f2004-12-16 18:43:13 +0000399 return -1;
400 }
401
402#ifdef CONFIG_AUTO_UPDATE_SHOW
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200403 board_auto_update_show (1);
stroese56b9e4f2004-12-16 18:43:13 +0000404#endif
405 puts("\nAutoUpdate Disk detected! Trying to update system...\n");
406
407 /* make sure that we see CTRL-C and save the old state */
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200408 old_ctrlc = disable_ctrlc (0);
stroese56b9e4f2004-12-16 18:43:13 +0000409
410 /* just loop thru all the possible files */
411 for (i = 0; i < N_AU_IMAGES; i++) {
412 /*
413 * Try to expand the environment var in the fname
414 */
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200415 process_macros (au_image[i].name, str);
416 strcpy (au_image[i].name, str);
stroese56b9e4f2004-12-16 18:43:13 +0000417
418 printf("Reading %s ...", au_image[i].name);
419 /* just read the header */
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200420 sz = do_fat_read (au_image[i].name, LOAD_ADDR,
421 image_get_header_size (), LS_NO);
stroese56b9e4f2004-12-16 18:43:13 +0000422 debug ("read %s sz %ld hdr %d\n",
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100423 au_image[i].name, sz, image_get_header_size ());
424 if (sz <= 0 || sz < image_get_header_size ()) {
stroese56b9e4f2004-12-16 18:43:13 +0000425 puts(" not found\n");
426 continue;
427 }
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200428 if (au_check_header_valid (i, sz) < 0) {
stroese56b9e4f2004-12-16 18:43:13 +0000429 puts(" header not valid\n");
430 continue;
431 }
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200432 sz = do_fat_read (au_image[i].name, LOAD_ADDR,
433 MAX_LOADSZ, LS_NO);
stroese56b9e4f2004-12-16 18:43:13 +0000434 debug ("read %s sz %ld hdr %d\n",
Marian Balakowicz41d71ed2008-01-08 18:14:09 +0100435 au_image[i].name, sz, image_get_header_size ());
436 if (sz <= 0 || sz <= image_get_header_size ()) {
stroese56b9e4f2004-12-16 18:43:13 +0000437 puts(" not found\n");
438 continue;
439 }
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200440 if (au_check_cksum_valid (i, sz) < 0) {
stroese56b9e4f2004-12-16 18:43:13 +0000441 puts(" checksum not valid\n");
442 continue;
443 }
444 puts(" done\n");
445
446 do {
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200447 res = au_do_update (i, sz);
stroese56b9e4f2004-12-16 18:43:13 +0000448 /* let the user break out of the loop */
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200449 if (ctrlc() || had_ctrlc ()) {
450 clear_ctrlc ();
stroese56b9e4f2004-12-16 18:43:13 +0000451 break;
452 }
stroese56b9e4f2004-12-16 18:43:13 +0000453 } while (res < 0);
454 }
455
456 /* restore the old state */
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200457 disable_ctrlc (old_ctrlc);
stroese56b9e4f2004-12-16 18:43:13 +0000458
459 puts("AutoUpdate finished\n\n");
460#ifdef CONFIG_AUTO_UPDATE_SHOW
Matthias Fuchs17dc7612008-04-21 14:42:06 +0200461 board_auto_update_show (0);
stroese56b9e4f2004-12-16 18:43:13 +0000462#endif
463
464 return 0;
465}
466
Wolfgang Denk6262d0212010-06-28 22:00:46 +0200467int auto_update(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
stroese56b9e4f2004-12-16 18:43:13 +0000468{
469 do_auto_update();
470
471 return 0;
472}
473U_BOOT_CMD(
474 autoupd, 1, 1, auto_update,
Peter Tyserdfb72b82009-01-27 18:03:12 -0600475 "Automatically update images",
Wolfgang Denkc54781c2009-05-24 17:06:54 +0200476 ""
stroese56b9e4f2004-12-16 18:43:13 +0000477);
478#endif /* CONFIG_AUTO_UPDATE */