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