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>
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 
yaffs_bug_fn(const char * fn,int n)43 void yaffs_bug_fn(const char *fn, int n)
44 {
45 	printf("yaffs bug at %s:%d\n", fn, n);
46 }
47 
yaffsfs_malloc(size_t x)48 void *yaffsfs_malloc(size_t x)
49 {
50 	return malloc(x);
51 }
52 
yaffsfs_free(void * x)53 void yaffsfs_free(void *x)
54 {
55 	free(x);
56 }
57 
yaffsfs_SetError(int err)58 void yaffsfs_SetError(int err)
59 {
60 	yaffs_errno = err;
61 }
62 
yaffsfs_GetLastError(void)63 int yaffsfs_GetLastError(void)
64 {
65 	return yaffs_errno;
66 }
67 
68 
yaffsfs_GetError(void)69 int yaffsfs_GetError(void)
70 {
71 	return yaffs_errno;
72 }
73 
yaffsfs_Lock(void)74 void yaffsfs_Lock(void)
75 {
76 }
77 
yaffsfs_Unlock(void)78 void yaffsfs_Unlock(void)
79 {
80 }
81 
yaffsfs_CurrentTime(void)82 __u32 yaffsfs_CurrentTime(void)
83 {
84 	return 0;
85 }
86 
yaffs_malloc(size_t size)87 void *yaffs_malloc(size_t size)
88 {
89 	return malloc(size);
90 }
91 
yaffs_free(void * ptr)92 void yaffs_free(void *ptr)
93 {
94 	free(ptr);
95 }
96 
yaffsfs_LocalInitialisation(void)97 void yaffsfs_LocalInitialisation(void)
98 {
99 	/* No locking used */
100 }
101 
102 
yaffs_file_type_str(struct yaffs_stat * stat)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 
yaffs_error_str(void)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 
cmd_yaffs_tracemask(unsigned set,unsigned mask)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 
yaffs_regions_overlap(int a,int b,int x,int y)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 
cmd_yaffs_devconfig(char * _mp,int flash_dev,int start_block,int end_block)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 
cmd_yaffs_dev_ls(void)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 
make_a_file(char * yaffsName,char bval,int sizeOfFile)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 
read_a_file(char * fn)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 
cmd_yaffs_mount(char * mp)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 
cmd_yaffs_umount(char * mp)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 
cmd_yaffs_write_file(char * yaffsName,char bval,int sizeOfFile)351 void cmd_yaffs_write_file(char *yaffsName, char bval, int sizeOfFile)
352 {
353 	make_a_file(yaffsName, bval, sizeOfFile);
354 }
355 
356 
cmd_yaffs_read_file(char * fn)357 void cmd_yaffs_read_file(char *fn)
358 {
359 	read_a_file(fn);
360 }
361 
362 
cmd_yaffs_mread_file(char * fn,char * addr)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 
cmd_yaffs_mwrite_file(char * fn,char * addr,int size)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 
cmd_yaffs_ls(const char * mountpt,int longlist)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 
cmd_yaffs_mkdir(const char * dir)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 
cmd_yaffs_rmdir(const char * dir)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 
cmd_yaffs_rm(const char * path)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 
cmd_yaffs_mv(const char * oldPath,const char * newPath)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 }
467