static struct nvram_header * BCMINITFN(nand_find_nvram)(hndnand_t *nfl, uint32 off) { int blocksize = nfl->blocksize; unsigned char *buf = nflash_nvh; int rlen = sizeof(nflash_nvh); int len; for (; off < NFL_BOOT_SIZE; off += blocksize) { if (hndnand_checkbadb(nfl, off) != 0) continue; len = blocksize; if (len >= rlen) len = rlen; if (hndnand_read(nfl, off, len, buf) == 0) break; buf += len; rlen -= len; if (rlen == 0) return (struct nvram_header *)nflash_nvh; } return NULL; }
static int _nflash_mtd_read(struct mtd_info *mtd, struct mtd_partition *part, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct nflash_mtd *nflash = (struct nflash_mtd *) mtd->priv; int bytes, ret = 0; uint extra = 0; uchar *tmpbuf = NULL; int size; uint offset, blocksize, mask, blk_offset, off; uint skip_bytes = 0, good_bytes = 0, page_size; int blk_idx, i; int need_copy = 0; uchar *ptr = NULL; /* Locate the part */ if (!part) { for (i = 0; nflash_parts[i].name; i++) { if (from >= nflash_parts[i].offset && ((nflash_parts[i+1].name == NULL) || (from < nflash_parts[i+1].offset))) { part = &nflash_parts[i]; break; } } if (!part) return -EINVAL; } /* Check address range */ if (!len) return 0; if ((from + len) > mtd->size) return -EINVAL; offset = from; page_size = nflash->nfl->pagesize; if ((offset & (page_size - 1)) != 0) { extra = offset & (page_size - 1); offset -= extra; len += extra; need_copy = 1; } size = (len + (page_size - 1)) & ~(page_size - 1); if (size != len) need_copy = 1; if (!need_copy) { ptr = buf; } else { NFLASH_UNLOCK(nflash); tmpbuf = (uchar *)kmalloc(size, GFP_KERNEL); NFLASH_LOCK(nflash); ptr = tmpbuf; } blocksize = mtd->erasesize; mask = blocksize - 1; blk_offset = offset & ~mask; good_bytes = part->offset & ~mask; /* Check and skip bad blocks */ for (blk_idx = good_bytes/blocksize; blk_idx < mtd->eraseregions->numblocks; blk_idx++) { if (nflash->map[blk_idx] != 0) { skip_bytes += blocksize; } else { if (good_bytes == blk_offset) break; good_bytes += blocksize; } } if (blk_idx == mtd->eraseregions->numblocks) { ret = -EINVAL; goto done; } blk_offset = blocksize * blk_idx; *retlen = 0; while (len > 0) { off = offset + skip_bytes; /* Check and skip bad blocks */ if (off >= (blk_offset + blocksize)) { blk_offset += blocksize; blk_idx++; while ((nflash->map[blk_idx] != 0) && (blk_offset < mtd->size)) { skip_bytes += blocksize; blk_offset += blocksize; blk_idx++; } if (blk_offset >= mtd->size) { ret = -EINVAL; goto done; } off = offset + skip_bytes; } if ((bytes = hndnand_read(nflash->nfl, off, page_size, ptr)) < 0) { ret = bytes; goto done; } if (bytes > len) bytes = len; offset += bytes; len -= bytes; ptr += bytes; *retlen += bytes; } done: if (tmpbuf) { *retlen -= extra; memcpy(buf, tmpbuf+extra, *retlen); kfree(tmpbuf); } return ret; }
static uint lookup_nflash_rootfs_offset(hndnand_t *nfl, struct mtd_info *mtd, int offset, size_t size) { struct romfs_super_block *romfsb; struct cramfs_super *cramfsb; struct squashfs_super_block *squashfsb; struct trx_header *trx; unsigned char buf[NFL_SECTOR_SIZE]; uint blocksize, mask, blk_offset, off, shift = 0; int ret; romfsb = (struct romfs_super_block *) buf; cramfsb = (struct cramfs_super *) buf; squashfsb = (struct squashfs_super_block *) buf; trx = (struct trx_header *) buf; /* Look at every block boundary till 16MB; higher space is reserved for application data. */ blocksize = mtd->erasesize; printk("lookup_nflash_rootfs_offset: offset = 0x%x\n", offset); for (off = offset; off < NFL_BOOT_OS_SIZE; off += 4096) { mask = blocksize - 1; blk_offset = off & ~mask; if (hndnand_checkbadb(nfl, blk_offset) != 0) continue; memset(buf, 0xe5, sizeof(buf)); if ((ret = hndnand_read(nfl, off, sizeof(buf), buf)) != sizeof(buf)) { printk(KERN_NOTICE "%s: nflash_read return %d\n", mtd->name, ret); continue; } if (le32_to_cpu(trx->magic) == TRX_MAGIC) { printk(KERN_NOTICE "found trx at %X, len =%d\n",off,trx->len); int offset = le32_to_cpu(trx->offsets[2]) ? : le32_to_cpu(trx->offsets[1]); offset+=off; printk(KERN_NOTICE "scan filesys at %X\n",offset); if ((ret = hndnand_read(nfl, offset, sizeof(buf), buf)) != sizeof(buf)) { printk(KERN_NOTICE "%s: nflash_read return %d\n", mtd->name, ret); continue; } if (*((__u32 *) buf) == SQUASHFS_MAGIC) { printk(KERN_NOTICE "%s: squash filesystem with lzma found at offset %d\n", mtd->name, off ); int size = squashfsb->bytes_used; //part->size = part->size + 1024; /* uncomment for belkin v2000 ! */ int len = offset + size; len += (mtd->erasesize - 1); len &= ~(mtd->erasesize - 1); ddwrtoffset = len; ddwrtsize = mtd->size - ddwrtoffset; return offset; } } }