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