++ .name = "bcm963xx",
++ .size = WINDOW_SIZE,
++ .bankwidth = BUSWIDTH,
++ .phys = WINDOW_ADDR,
++};
++
++
++int parse_cfe_partitions( struct mtd_info *master, struct mtd_partition **pparts)
++{
++ int nrparts = 2, curpart = 0; // CFE and NVRAM always present.
++ struct bcm963xx_cfe_map {
++ unsigned char tagVersion[4]; // Version of the image tag
++ unsigned char sig_1[20]; // Company Line 1
++ unsigned char sig_2[14]; // Company Line 2
++ unsigned char chipid[6]; // Chip this image is for
++ unsigned char boardid[16]; // Board name
++ unsigned char bigEndian[2]; // Map endianness -- 1 BE 0 LE
++ unsigned char totalLength[IMAGE_LEN]; //Total length of image
++ unsigned char cfeAddress[ADDRESS_LEN]; // Address in memory of CFE
++ unsigned char cfeLength[IMAGE_LEN]; // Size of CFE
++ unsigned char rootAddress[ADDRESS_LEN]; // Address in memory of rootfs
++ unsigned char rootLength[IMAGE_LEN]; // Size of rootfs
++ unsigned char kernelAddress[ADDRESS_LEN]; // Address in memory of kernel
++ unsigned char kernelLength[IMAGE_LEN]; // Size of kernel
++ unsigned char dualImage[2]; // Unused at present
++ unsigned char inactiveFlag[2]; // Unused at present
++ unsigned char reserved1[74]; // Reserved area not in use
++ unsigned char imageCRC[4]; // CRC32 of images
++ unsigned char reserved2[16]; // Unused at present
++ unsigned char headerCRC[4]; // CRC32 of header excluding tagVersion
++ unsigned char reserved3[16]; // Unused at present
++ } *buf;
++ struct mtd_partition *parts;
++ int ret;
++ size_t retlen;
++ unsigned int rootfsaddr, kerneladdr, spareaddr;
++ unsigned int rootfslen, kernellen, sparelen, totallen;
++ int namelen = 0;
++ int i;
++ // Allocate memory for buffer
++ buf = vmalloc(sizeof(struct bcm963xx_cfe_map));
++
++ if (!buf)
++ return -ENOMEM;
++
++ // Get the tag
++ ret = master->read(master,master->erasesize,sizeof(struct bcm963xx_cfe_map), &retlen, (void *)buf);
++ if (retlen != sizeof(struct bcm963xx_cfe_map)){
++ vfree(buf);
++ return -EIO;
++ };
++ printk("bcm963xx: CFE boot tag found with version %s and board type %s.\n",buf->tagVersion,buf->boardid);
++ // Get the values and calculate
++ sscanf(buf->rootAddress,"%u", &rootfsaddr);
++ rootfsaddr = rootfsaddr - EXTENDED_SIZE;
++ sscanf(buf->rootLength, "%u", &rootfslen);
++ sscanf(buf->kernelAddress, "%u", &kerneladdr);
++ kerneladdr = kerneladdr - EXTENDED_SIZE;
++ sscanf(buf->kernelLength, "%u", &kernellen);
++ sscanf(buf->totalLength, "%u", &totallen);
++ spareaddr = ROUNDUP(totallen,master->erasesize) + master->erasesize;
++ sparelen = master->size - spareaddr - master->erasesize;
++ // Determine number of partitions
++ namelen = 8;
++ if (rootfslen > 0){
++ nrparts++;
++ namelen =+ 6;
++ };
++ if (kernellen > 0){
++ nrparts++;
++ namelen =+ 6;
++ };
++ if (sparelen > 0){
++ nrparts++;
++ namelen =+ 6;
++ };
++ // Ask kernel for more memory.
++ parts = kmalloc(sizeof(*parts)*nrparts+10*nrparts, GFP_KERNEL);
++ if (!parts){
++ vfree(buf);
++ return -ENOMEM;
++ };
++ memset(parts,0,sizeof(*parts)*nrparts+10*nrparts);
++ // Start building partition list
++ parts[curpart].name = "CFE";
++ parts[curpart].offset = 0;
++ parts[curpart].size = master->erasesize;
++ curpart++;
++ if (kernellen > 0){
++ parts[curpart].name = "Kernel";
++ parts[curpart].offset = kerneladdr;
++ parts[curpart].size = kernellen;
++ curpart++;
++ };
++ if (rootfslen > 0){
++ parts[curpart].name = "Rootfs";
++ parts[curpart].offset = rootfsaddr;
++ parts[curpart].size = rootfslen;
++ curpart++;
++ };
++ if (sparelen > 0){
++ parts[curpart].name = "OpenWrt";
++ parts[curpart].offset = spareaddr;
++ parts[curpart].size = sparelen;
++ curpart++;
++ };
++ parts[curpart].name = "NVRAM";
++ parts[curpart].offset = master->size - master->erasesize;
++ parts[curpart].size = master->erasesize;
++ for (i = 0; i < nrparts; i++) {
++ printk("bcm963xx: Partition %d is %s offset %x and length %x\n", i, parts[i].name, parts[i].offset, parts[i].size);
++ }
++ *pparts = parts;
++ vfree(buf);
++ return nrparts;