]>
Commit | Line | Data |
---|---|---|
753ac610 CM |
1 | /* |
2 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | |
3 | * | |
4 | * Copyright (C) 2002-2007 Aleph One Ltd. | |
5 | * for Toby Churchill Ltd and Brightstar Engineering | |
6 | * | |
7 | * Created by Charles Manning <charles@aleph1.co.uk> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License version 2 as | |
11 | * published by the Free Software Foundation. | |
12 | */ | |
13 | ||
14 | /* | |
15 | * yaffscfg.c The configuration for the "direct" use of yaffs. | |
16 | * | |
17 | * This is set up for u-boot. | |
18 | * | |
19 | * This version now uses the ydevconfig mechanism to set up partitions. | |
20 | */ | |
21 | ||
22 | #include <common.h> | |
6b44adc2 | 23 | #include <div64.h> |
753ac610 CM |
24 | |
25 | #include <config.h> | |
26 | #include "nand.h" | |
27 | #include "yaffscfg.h" | |
28 | #include "yaffsfs.h" | |
29 | #include "yaffs_packedtags2.h" | |
30 | #include "yaffs_mtdif.h" | |
31 | #include "yaffs_mtdif2.h" | |
32 | #if 0 | |
33 | #include <errno.h> | |
34 | #else | |
35 | #include "malloc.h" | |
36 | #endif | |
37 | ||
38 | unsigned yaffs_trace_mask = 0x0; /* Disable logging */ | |
39 | static int yaffs_errno; | |
40 | ||
41 | ||
42 | void yaffs_bug_fn(const char *fn, int n) | |
43 | { | |
44 | printf("yaffs bug at %s:%d\n", fn, n); | |
45 | } | |
46 | ||
47 | void *yaffsfs_malloc(size_t x) | |
48 | { | |
49 | return malloc(x); | |
50 | } | |
51 | ||
52 | void yaffsfs_free(void *x) | |
53 | { | |
54 | free(x); | |
55 | } | |
56 | ||
57 | void yaffsfs_SetError(int err) | |
58 | { | |
59 | yaffs_errno = err; | |
60 | } | |
61 | ||
62 | int yaffsfs_GetLastError(void) | |
63 | { | |
64 | return yaffs_errno; | |
65 | } | |
66 | ||
67 | ||
68 | int yaffsfs_GetError(void) | |
69 | { | |
70 | return yaffs_errno; | |
71 | } | |
72 | ||
73 | void yaffsfs_Lock(void) | |
74 | { | |
75 | } | |
76 | ||
77 | void yaffsfs_Unlock(void) | |
78 | { | |
79 | } | |
80 | ||
81 | __u32 yaffsfs_CurrentTime(void) | |
82 | { | |
83 | return 0; | |
84 | } | |
85 | ||
86 | void *yaffs_malloc(size_t size) | |
87 | { | |
88 | return malloc(size); | |
89 | } | |
90 | ||
91 | void yaffs_free(void *ptr) | |
92 | { | |
93 | free(ptr); | |
94 | } | |
95 | ||
96 | void yaffsfs_LocalInitialisation(void) | |
97 | { | |
98 | /* No locking used */ | |
99 | } | |
100 | ||
101 | ||
102 | static const char *yaffs_file_type_str(struct yaffs_stat *stat) | |
103 | { | |
104 | switch (stat->st_mode & S_IFMT) { | |
105 | case S_IFREG: return "regular file"; | |
106 | case S_IFDIR: return "directory"; | |
107 | case S_IFLNK: return "symlink"; | |
108 | default: return "unknown"; | |
109 | } | |
110 | } | |
111 | ||
112 | static const char *yaffs_error_str(void) | |
113 | { | |
114 | int error = yaffsfs_GetLastError(); | |
115 | ||
116 | if (error < 0) | |
117 | error = -error; | |
118 | ||
119 | switch (error) { | |
120 | case EBUSY: return "Busy"; | |
121 | case ENODEV: return "No such device"; | |
122 | case EINVAL: return "Invalid parameter"; | |
123 | case ENFILE: return "Too many open files"; | |
124 | case EBADF: return "Bad handle"; | |
125 | case EACCES: return "Wrong permissions"; | |
126 | case EXDEV: return "Not on same device"; | |
127 | case ENOENT: return "No such entry"; | |
128 | case ENOSPC: return "Device full"; | |
129 | case EROFS: return "Read only file system"; | |
130 | case ERANGE: return "Range error"; | |
131 | case ENOTEMPTY: return "Not empty"; | |
132 | case ENAMETOOLONG: return "Name too long"; | |
133 | case ENOMEM: return "Out of memory"; | |
134 | case EFAULT: return "Fault"; | |
135 | case EEXIST: return "Name exists"; | |
136 | case ENOTDIR: return "Not a directory"; | |
137 | case EISDIR: return "Not permitted on a directory"; | |
138 | case ELOOP: return "Symlink loop"; | |
139 | case 0: return "No error"; | |
140 | default: return "Unknown error"; | |
141 | } | |
142 | } | |
143 | ||
144 | extern nand_info_t nand_info[]; | |
145 | ||
146 | void cmd_yaffs_tracemask(unsigned set, unsigned mask) | |
147 | { | |
148 | if (set) | |
149 | yaffs_trace_mask = mask; | |
150 | ||
151 | printf("yaffs trace mask: %08x\n", yaffs_trace_mask); | |
152 | } | |
153 | ||
154 | static int yaffs_regions_overlap(int a, int b, int x, int y) | |
155 | { | |
156 | return (a <= x && x <= b) || | |
157 | (a <= y && y <= b) || | |
158 | (x <= a && a <= y) || | |
159 | (x <= b && b <= y); | |
160 | } | |
161 | ||
162 | void cmd_yaffs_devconfig(char *_mp, int flash_dev, | |
163 | int start_block, int end_block) | |
164 | { | |
165 | struct mtd_info *mtd = NULL; | |
166 | struct yaffs_dev *dev = NULL; | |
167 | struct yaffs_dev *chk; | |
168 | char *mp = NULL; | |
169 | struct nand_chip *chip; | |
170 | ||
171 | dev = calloc(1, sizeof(*dev)); | |
172 | mp = strdup(_mp); | |
173 | ||
174 | mtd = &nand_info[flash_dev]; | |
175 | ||
176 | if (!dev || !mp) { | |
177 | /* Alloc error */ | |
178 | printf("Failed to allocate memory\n"); | |
179 | goto err; | |
180 | } | |
181 | ||
182 | if (flash_dev >= CONFIG_SYS_MAX_NAND_DEVICE) { | |
183 | printf("Flash device invalid\n"); | |
184 | goto err; | |
185 | } | |
186 | ||
187 | if (end_block == 0) | |
6b44adc2 | 188 | end_block = lldiv(mtd->size, mtd->erasesize - 1); |
753ac610 CM |
189 | |
190 | if (end_block < start_block) { | |
191 | printf("Bad start/end\n"); | |
192 | goto err; | |
193 | } | |
194 | ||
195 | chip = mtd->priv; | |
196 | ||
197 | /* Check for any conflicts */ | |
198 | yaffs_dev_rewind(); | |
199 | while (1) { | |
200 | chk = yaffs_next_dev(); | |
201 | if (!chk) | |
202 | break; | |
203 | if (strcmp(chk->param.name, mp) == 0) { | |
204 | printf("Mount point name already used\n"); | |
205 | goto err; | |
206 | } | |
207 | if (chk->driver_context == mtd && | |
208 | yaffs_regions_overlap( | |
209 | chk->param.start_block, chk->param.end_block, | |
210 | start_block, end_block)) { | |
211 | printf("Region overlaps with partition %s\n", | |
212 | chk->param.name); | |
213 | goto err; | |
214 | } | |
215 | ||
216 | } | |
217 | ||
218 | /* Seems sane, so configure */ | |
219 | memset(dev, 0, sizeof(*dev)); | |
220 | dev->param.name = mp; | |
221 | dev->driver_context = mtd; | |
222 | dev->param.start_block = start_block; | |
223 | dev->param.end_block = end_block; | |
224 | dev->param.chunks_per_block = mtd->erasesize / mtd->writesize; | |
225 | dev->param.total_bytes_per_chunk = mtd->writesize; | |
226 | dev->param.is_yaffs2 = 1; | |
227 | dev->param.use_nand_ecc = 1; | |
228 | dev->param.n_reserved_blocks = 5; | |
229 | if (chip->ecc.layout->oobavail < sizeof(struct yaffs_packed_tags2)) | |
230 | dev->param.inband_tags = 1; | |
231 | dev->param.n_caches = 10; | |
232 | dev->param.write_chunk_tags_fn = nandmtd2_write_chunk_tags; | |
233 | dev->param.read_chunk_tags_fn = nandmtd2_read_chunk_tags; | |
234 | dev->param.erase_fn = nandmtd_EraseBlockInNAND; | |
235 | dev->param.initialise_flash_fn = nandmtd_InitialiseNAND; | |
236 | dev->param.bad_block_fn = nandmtd2_MarkNANDBlockBad; | |
237 | dev->param.query_block_fn = nandmtd2_QueryNANDBlock; | |
238 | ||
239 | yaffs_add_device(dev); | |
240 | ||
241 | printf("Configures yaffs mount %s: dev %d start block %d, end block %d %s\n", | |
242 | mp, flash_dev, start_block, end_block, | |
243 | dev->param.inband_tags ? "using inband tags" : ""); | |
244 | return; | |
245 | ||
246 | err: | |
247 | free(dev); | |
248 | free(mp); | |
249 | } | |
250 | ||
251 | void cmd_yaffs_dev_ls(void) | |
252 | { | |
253 | struct yaffs_dev *dev; | |
254 | int flash_dev; | |
255 | int free_space; | |
256 | ||
257 | yaffs_dev_rewind(); | |
258 | ||
259 | while (1) { | |
260 | dev = yaffs_next_dev(); | |
261 | if (!dev) | |
262 | return; | |
263 | flash_dev = | |
264 | ((unsigned) dev->driver_context - (unsigned) nand_info)/ | |
265 | sizeof(nand_info[0]); | |
266 | printf("%-10s %5d 0x%05x 0x%05x %s", | |
267 | dev->param.name, flash_dev, | |
268 | dev->param.start_block, dev->param.end_block, | |
269 | dev->param.inband_tags ? "using inband tags, " : ""); | |
270 | ||
271 | free_space = yaffs_freespace(dev->param.name); | |
272 | if (free_space < 0) | |
273 | printf("not mounted\n"); | |
274 | else | |
275 | printf("free 0x%x\n", free_space); | |
276 | ||
277 | } | |
278 | } | |
279 | ||
280 | void make_a_file(char *yaffsName, char bval, int sizeOfFile) | |
281 | { | |
282 | int outh; | |
283 | int i; | |
284 | unsigned char buffer[100]; | |
285 | ||
286 | outh = yaffs_open(yaffsName, | |
287 | O_CREAT | O_RDWR | O_TRUNC, | |
288 | S_IREAD | S_IWRITE); | |
289 | if (outh < 0) { | |
290 | printf("Error opening file: %d. %s\n", outh, yaffs_error_str()); | |
291 | return; | |
292 | } | |
293 | ||
294 | memset(buffer, bval, 100); | |
295 | ||
296 | do { | |
297 | i = sizeOfFile; | |
298 | if (i > 100) | |
299 | i = 100; | |
300 | sizeOfFile -= i; | |
301 | ||
302 | yaffs_write(outh, buffer, i); | |
303 | ||
304 | } while (sizeOfFile > 0); | |
305 | ||
306 | ||
307 | yaffs_close(outh); | |
308 | } | |
309 | ||
310 | void read_a_file(char *fn) | |
311 | { | |
312 | int h; | |
313 | int i = 0; | |
314 | unsigned char b; | |
315 | ||
316 | h = yaffs_open(fn, O_RDWR, 0); | |
317 | if (h < 0) { | |
318 | printf("File not found\n"); | |
319 | return; | |
320 | } | |
321 | ||
322 | while (yaffs_read(h, &b, 1) > 0) { | |
323 | printf("%02x ", b); | |
324 | i++; | |
325 | if (i > 32) { | |
326 | printf("\n"); | |
327 | i = 0;; | |
328 | } | |
329 | } | |
330 | printf("\n"); | |
331 | yaffs_close(h); | |
332 | } | |
333 | ||
334 | void cmd_yaffs_mount(char *mp) | |
335 | { | |
336 | int retval = yaffs_mount(mp); | |
337 | if (retval < 0) | |
338 | printf("Error mounting %s, return value: %d, %s\n", mp, | |
339 | yaffsfs_GetError(), yaffs_error_str()); | |
340 | } | |
341 | ||
342 | ||
343 | void cmd_yaffs_umount(char *mp) | |
344 | { | |
345 | if (yaffs_unmount(mp) == -1) | |
346 | printf("Error umounting %s, return value: %d, %s\n", mp, | |
347 | yaffsfs_GetError(), yaffs_error_str()); | |
348 | } | |
349 | ||
350 | void cmd_yaffs_write_file(char *yaffsName, char bval, int sizeOfFile) | |
351 | { | |
352 | make_a_file(yaffsName, bval, sizeOfFile); | |
353 | } | |
354 | ||
355 | ||
356 | void cmd_yaffs_read_file(char *fn) | |
357 | { | |
358 | read_a_file(fn); | |
359 | } | |
360 | ||
361 | ||
362 | void cmd_yaffs_mread_file(char *fn, char *addr) | |
363 | { | |
364 | int h; | |
365 | struct yaffs_stat s; | |
366 | ||
367 | yaffs_stat(fn, &s); | |
368 | ||
369 | printf("Copy %s to 0x%p... ", fn, addr); | |
370 | h = yaffs_open(fn, O_RDWR, 0); | |
371 | if (h < 0) { | |
372 | printf("File not found\n"); | |
373 | return; | |
374 | } | |
375 | ||
376 | yaffs_read(h, addr, (int)s.st_size); | |
377 | printf("\t[DONE]\n"); | |
378 | ||
379 | yaffs_close(h); | |
380 | } | |
381 | ||
382 | ||
383 | void cmd_yaffs_mwrite_file(char *fn, char *addr, int size) | |
384 | { | |
385 | int outh; | |
386 | ||
387 | outh = yaffs_open(fn, O_CREAT | O_RDWR | O_TRUNC, S_IREAD | S_IWRITE); | |
388 | if (outh < 0) | |
389 | printf("Error opening file: %d, %s\n", outh, yaffs_error_str()); | |
390 | ||
391 | yaffs_write(outh, addr, size); | |
392 | ||
393 | yaffs_close(outh); | |
394 | } | |
395 | ||
396 | ||
397 | void cmd_yaffs_ls(const char *mountpt, int longlist) | |
398 | { | |
399 | int i; | |
400 | yaffs_DIR *d; | |
401 | struct yaffs_dirent *de; | |
402 | struct yaffs_stat stat; | |
403 | char tempstr[255]; | |
404 | ||
405 | d = yaffs_opendir(mountpt); | |
406 | ||
407 | if (!d) { | |
408 | printf("opendir failed, %s\n", yaffs_error_str()); | |
409 | return; | |
410 | } | |
411 | ||
412 | for (i = 0; (de = yaffs_readdir(d)) != NULL; i++) { | |
413 | if (longlist) { | |
414 | sprintf(tempstr, "%s/%s", mountpt, de->d_name); | |
415 | yaffs_lstat(tempstr, &stat); | |
416 | printf("%-25s\t%7ld", | |
417 | de->d_name, | |
418 | (long)stat.st_size); | |
419 | printf(" %5d %s\n", | |
420 | stat.st_ino, | |
421 | yaffs_file_type_str(&stat)); | |
422 | } else { | |
423 | printf("%s\n", de->d_name); | |
424 | } | |
425 | } | |
426 | ||
427 | yaffs_closedir(d); | |
428 | } | |
429 | ||
430 | ||
431 | void cmd_yaffs_mkdir(const char *dir) | |
432 | { | |
433 | int retval = yaffs_mkdir(dir, 0); | |
434 | ||
435 | if (retval < 0) | |
436 | printf("yaffs_mkdir returning error: %d, %s\n", | |
437 | retval, yaffs_error_str()); | |
438 | } | |
439 | ||
440 | void cmd_yaffs_rmdir(const char *dir) | |
441 | { | |
442 | int retval = yaffs_rmdir(dir); | |
443 | ||
444 | if (retval < 0) | |
445 | printf("yaffs_rmdir returning error: %d, %s\n", | |
446 | retval, yaffs_error_str()); | |
447 | } | |
448 | ||
449 | void cmd_yaffs_rm(const char *path) | |
450 | { | |
451 | int retval = yaffs_unlink(path); | |
452 | ||
453 | if (retval < 0) | |
454 | printf("yaffs_unlink returning error: %d, %s\n", | |
455 | retval, yaffs_error_str()); | |
456 | } | |
457 | ||
458 | void cmd_yaffs_mv(const char *oldPath, const char *newPath) | |
459 | { | |
460 | int retval = yaffs_rename(newPath, oldPath); | |
461 | ||
462 | if (retval < 0) | |
463 | printf("yaffs_unlink returning error: %d, %s\n", | |
464 | retval, yaffs_error_str()); | |
465 | } |