source: trunk/target/linux/brcm47xx/patches-3.2/0017-mtd-bcm47xx-add-bcm47xx-part-parser.patch @ 29756

Last change on this file since 29756 was 29756, checked in by hauke, 4 years ago

brcm47xx: add support for kernel 3.2

File size: 17.2 KB
  • drivers/mtd/Kconfig

    From d50d2d8e3ab5446f791deff0cb78820989ed93e7 Mon Sep 17 00:00:00 2001
    From: Hauke Mehrtens <hauke@hauke-m.de>
    Date: Sun, 17 Jul 2011 14:54:11 +0200
    Subject: [PATCH 06/19] mtd: bcm47xx: add bcm47xx part parser
    
    
    Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
    ---
     drivers/mtd/Kconfig       |    7 +
     drivers/mtd/Makefile      |    1 +
     drivers/mtd/bcm47xxpart.c |  542 +++++++++++++++++++++++++++++++++++++++++++++
     3 files changed, 550 insertions(+), 0 deletions(-)
     create mode 100644 drivers/mtd/bcm47xxpart.c
    
    a b config MTD_MYLOADER_PARTS 
    164164          You will still need the parsing functions to be called by the driver 
    165165          for your particular device. It won't happen automatically. 
    166166 
     167config MTD_BCM47XX_PARTS 
     168        tristate "BCM47XX partitioning support" 
     169        default y 
     170        depends on BCM47XX 
     171        ---help--- 
     172          bcm47XX partitioning support 
     173 
    167174comment "User Modules And Translation Layers" 
    168175 
    169176config MTD_CHAR 
  • drivers/mtd/Makefile

    a b obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdli 
    1212obj-$(CONFIG_MTD_AFS_PARTS)     += afs.o 
    1313obj-$(CONFIG_MTD_AR7_PARTS)     += ar7part.o 
    1414obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o 
     15obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o 
    1516 
    1617# 'Users' - code which presents functionality to userspace. 
    1718obj-$(CONFIG_MTD_CHAR)          += mtdchar.o 
  • new file drivers/mtd/bcm47xxpart.c

    - +  
     1/* 
     2 *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> 
     3 *  Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> 
     4 *  Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) 
     5 * 
     6 *  original functions for finding root filesystem from Mike Baker 
     7 * 
     8 *  This program is free software; you can redistribute  it and/or modify it 
     9 *  under  the terms of  the GNU General  Public License as published by the 
     10 *  Free Software Foundation;  either version 2 of the  License, or (at your 
     11 *  option) any later version. 
     12 * 
     13 *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED 
     14 *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF 
     15 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN 
     16 *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, 
     17 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
     18 *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF 
     19 *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
     20 *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT 
     21 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
     22 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     23 * 
     24 *  You should have received a copy of the  GNU General Public License along 
     25 *  with this program; if not, write  to the Free Software Foundation, Inc., 
     26 *  675 Mass Ave, Cambridge, MA 02139, USA. 
     27 * 
     28 *  Copyright 2001-2003, Broadcom Corporation 
     29 *  All Rights Reserved. 
     30 * 
     31 *  THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 
     32 *  KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 
     33 *  SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 
     34 *  FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 
     35 * 
     36 *  Flash mapping for BCM947XX boards 
     37 */ 
     38 
     39#define pr_fmt(fmt) "bcm47xx_part: " fmt 
     40#include <linux/init.h> 
     41#include <linux/module.h> 
     42#include <linux/types.h> 
     43#include <linux/kernel.h> 
     44#include <linux/sched.h> 
     45#include <linux/wait.h> 
     46#include <linux/mtd/mtd.h> 
     47#include <linux/mtd/partitions.h> 
     48#include <linux/crc32.h> 
     49#include <linux/io.h> 
     50#include <asm/mach-bcm47xx/nvram.h> 
     51#include <asm/mach-bcm47xx/bcm47xx.h> 
     52#include <asm/fw/cfe/cfe_api.h> 
     53 
     54 
     55#define TRX_MAGIC       0x30524448      /* "HDR0" */ 
     56#define TRX_VERSION     1 
     57#define TRX_MAX_LEN     0x3A0000 
     58#define TRX_NO_HEADER   1               /* Do not write TRX header */ 
     59#define TRX_GZ_FILES    0x2     /* Contains up to TRX_MAX_OFFSET individual gzip files */ 
     60#define TRX_MAX_OFFSET  3 
     61 
     62struct trx_header { 
     63        u32 magic;              /* "HDR0" */ 
     64        u32 len;                /* Length of file including header */ 
     65        u32 crc32;              /* 32-bit CRC from flag_version to end of file */ 
     66        u32 flag_version;       /* 0:15 flags, 16:31 version */ 
     67        u32 offsets[TRX_MAX_OFFSET];    /* Offsets of partitions from start of header */ 
     68}; 
     69 
     70/* for Edimax Print servers which use an additional header 
     71 * then the firmware on flash looks like : 
     72 * EDIMAX HEADER | TRX HEADER 
     73 * As this header is 12 bytes long we have to handle it 
     74 * and skip it to find the TRX header 
     75 */ 
     76#define EDIMAX_PS_HEADER_MAGIC  0x36315350 /*  "PS16"  */ 
     77#define EDIMAX_PS_HEADER_LEN    0xc /* 12 bytes long for edimax header */ 
     78 
     79#define NVRAM_SPACE 0x8000 
     80 
     81#define ROUTER_NETGEAR_WGR614L          1 
     82#define ROUTER_NETGEAR_WNR834B          2 
     83#define ROUTER_NETGEAR_WNDR3300         3 
     84#define ROUTER_NETGEAR_WNR3500L         4 
     85#define ROUTER_SIMPLETECH_SIMPLESHARE   5 
     86#define ROUTER_NETGEAR_WNDR3400         6 
     87 
     88static int 
     89find_cfe_size(struct mtd_info *mtd) 
     90{ 
     91        struct trx_header *trx; 
     92        unsigned char buf[512]; 
     93        int off; 
     94        size_t len; 
     95        int blocksize; 
     96 
     97        trx = (struct trx_header *) buf; 
     98 
     99        blocksize = mtd->erasesize; 
     100        if (blocksize < 0x10000) 
     101                blocksize = 0x10000; 
     102 
     103        for (off = (128*1024); off < mtd->size; off += blocksize) { 
     104                memset(buf, 0xe5, sizeof(buf)); 
     105 
     106                /* 
     107                 * Read into buffer 
     108                 */ 
     109                if (mtd->read(mtd, off, sizeof(buf), &len, buf) || 
     110                    len != sizeof(buf)) 
     111                        continue; 
     112 
     113                if (le32_to_cpu(trx->magic) == EDIMAX_PS_HEADER_MAGIC) { 
     114                        if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN, 
     115                            sizeof(buf), &len, buf) || len != sizeof(buf)) { 
     116                                continue; 
     117                        } else { 
     118                                pr_notice("Found edimax header\n"); 
     119                        } 
     120                } 
     121 
     122                /* found a TRX header */ 
     123                if (le32_to_cpu(trx->magic) == TRX_MAGIC) 
     124                        goto found; 
     125        } 
     126 
     127        pr_notice("%s: Couldn't find bootloader size\n", mtd->name); 
     128        return -1; 
     129 
     130 found: 
     131        pr_notice("bootloader size: %d\n", off); 
     132        return off; 
     133 
     134} 
     135 
     136/* 
     137 * Copied from mtdblock.c 
     138 * 
     139 * Cache stuff... 
     140 * 
     141 * Since typical flash erasable sectors are much larger than what Linux's 
     142 * buffer cache can handle, we must implement read-modify-write on flash 
     143 * sectors for each block write requests.  To avoid over-erasing flash sectors 
     144 * and to speed things up, we locally cache a whole flash sector while it is 
     145 * being written to until a different sector is required. 
     146 */ 
     147 
     148static void erase_callback(struct erase_info *done) 
     149{ 
     150        wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; 
     151        wake_up(wait_q); 
     152} 
     153 
     154static int erase_write(struct mtd_info *mtd, unsigned long pos, 
     155                        int len, const char *buf) 
     156{ 
     157        struct erase_info erase; 
     158        DECLARE_WAITQUEUE(wait, current); 
     159        wait_queue_head_t wait_q; 
     160        size_t retlen; 
     161        int ret; 
     162 
     163        /* 
     164         * First, let's erase the flash block. 
     165         */ 
     166 
     167        init_waitqueue_head(&wait_q); 
     168        erase.mtd = mtd; 
     169        erase.callback = erase_callback; 
     170        erase.addr = pos; 
     171        erase.len = len; 
     172        erase.priv = (u_long)&wait_q; 
     173 
     174        set_current_state(TASK_INTERRUPTIBLE); 
     175        add_wait_queue(&wait_q, &wait); 
     176 
     177        ret = mtd->erase(mtd, &erase); 
     178        if (ret) { 
     179                set_current_state(TASK_RUNNING); 
     180                remove_wait_queue(&wait_q, &wait); 
     181                pr_warn("erase of region [0x%lx, 0x%x] on \"%s\" failed\n", 
     182                        pos, len, mtd->name); 
     183                return ret; 
     184        } 
     185 
     186        schedule();  /* Wait for erase to finish. */ 
     187        remove_wait_queue(&wait_q, &wait); 
     188 
     189        /* 
     190         * Next, write data to flash. 
     191         */ 
     192 
     193        ret = mtd->write(mtd, pos, len, &retlen, buf); 
     194        if (ret) 
     195                return ret; 
     196        if (retlen != len) 
     197                return -EIO; 
     198        return 0; 
     199} 
     200 
     201 
     202static int 
     203find_dual_image_off(struct mtd_info *mtd) 
     204{ 
     205        struct trx_header trx; 
     206        int off, blocksize; 
     207        size_t len; 
     208 
     209        blocksize = mtd->erasesize; 
     210        if (blocksize < 0x10000) 
     211                blocksize = 0x10000; 
     212 
     213        for (off = (128*1024); off < mtd->size; off += blocksize) { 
     214                memset(&trx, 0xe5, sizeof(trx)); 
     215                /* 
     216                * Read into buffer 
     217                */ 
     218                if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || 
     219                    len != sizeof(trx)) 
     220                        continue; 
     221                /* found last TRX header */ 
     222                if (le32_to_cpu(trx.magic) == TRX_MAGIC) { 
     223                        if (le32_to_cpu(trx.flag_version >> 16) == 2) { 
     224                                pr_notice("dual image TRX header found\n"); 
     225                                return mtd->size / 2; 
     226                        } else { 
     227                                return 0; 
     228                        } 
     229                } 
     230        } 
     231        return 0; 
     232} 
     233 
     234 
     235static int 
     236find_root(struct mtd_info *mtd, struct mtd_partition *part) 
     237{ 
     238        struct trx_header trx, *trx2; 
     239        unsigned char buf[512], *block; 
     240        int off, blocksize, trxoff = 0; 
     241        u32 i, crc = ~0; 
     242        size_t len; 
     243        bool edimax = false; 
     244 
     245        blocksize = mtd->erasesize; 
     246        if (blocksize < 0x10000) 
     247                blocksize = 0x10000; 
     248 
     249        for (off = (128*1024); off < mtd->size; off += blocksize) { 
     250                memset(&trx, 0xe5, sizeof(trx)); 
     251 
     252                /* 
     253                 * Read into buffer 
     254                 */ 
     255                if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || 
     256                    len != sizeof(trx)) 
     257                        continue; 
     258 
     259                /* found an edimax header */ 
     260                if (le32_to_cpu(trx.magic) == EDIMAX_PS_HEADER_MAGIC) { 
     261                        /* read the correct trx header */ 
     262                        if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN, 
     263                            sizeof(trx), &len, (char *) &trx) || 
     264                            len != sizeof(trx)) { 
     265                                continue; 
     266                        } else { 
     267                                pr_notice("Found an edimax ps header\n"); 
     268                                edimax = true; 
     269                        } 
     270                } 
     271 
     272                /* found a TRX header */ 
     273                if (le32_to_cpu(trx.magic) == TRX_MAGIC) { 
     274                        part->offset = le32_to_cpu(trx.offsets[2]) ? : 
     275                                le32_to_cpu(trx.offsets[1]); 
     276                        part->size = le32_to_cpu(trx.len); 
     277 
     278                        part->size -= part->offset; 
     279                        part->offset += off; 
     280                        if (edimax) { 
     281                                off += EDIMAX_PS_HEADER_LEN; 
     282                                trxoff = EDIMAX_PS_HEADER_LEN; 
     283                        } 
     284 
     285                        goto found; 
     286                } 
     287        } 
     288 
     289        pr_warn("%s: Couldn't find root filesystem\n", 
     290               mtd->name); 
     291        return -1; 
     292 
     293 found: 
     294        pr_notice("TRX offset : %x\n", trxoff); 
     295        if (part->size == 0) 
     296                return 0; 
     297 
     298        if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf)) 
     299                return 0; 
     300 
     301        /* Move the fs outside of the trx */ 
     302        part->size = 0; 
     303 
     304        if (trx.len != part->offset + part->size - off) { 
     305                /* Update the trx offsets and length */ 
     306                trx.len = part->offset + part->size - off; 
     307 
     308                /* Update the trx crc32 */ 
     309                for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) { 
     310                        if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf)) 
     311                                return 0; 
     312                        crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i)); 
     313                } 
     314                trx.crc32 = crc; 
     315 
     316                /* read first eraseblock from the trx */ 
     317                block = kmalloc(mtd->erasesize, GFP_KERNEL); 
     318                trx2 = (struct trx_header *) block; 
     319                if (mtd->read(mtd, off - trxoff, mtd->erasesize, &len, block) || len != mtd->erasesize) { 
     320                        pr_err("Error accessing the first trx eraseblock\n"); 
     321                        return 0; 
     322                } 
     323 
     324                pr_notice("Updating TRX offsets and length:\n"); 
     325                pr_notice("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32); 
     326                pr_notice("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n",   trx.offsets[0],   trx.offsets[1],   trx.offsets[2],   trx.len, trx.crc32); 
     327 
     328                /* Write updated trx header to the flash */ 
     329                memcpy(block + trxoff, &trx, sizeof(trx)); 
     330                if (mtd->unlock) 
     331                        mtd->unlock(mtd, off - trxoff, mtd->erasesize); 
     332                erase_write(mtd, off - trxoff, mtd->erasesize, block); 
     333                if (mtd->sync) 
     334                        mtd->sync(mtd); 
     335                kfree(block); 
     336                pr_notice("Done\n"); 
     337        } 
     338 
     339        return part->size; 
     340} 
     341 
     342static int get_router(void) 
     343{ 
     344        char buf[20]; 
     345        u32 boardnum = 0; 
     346        u16 boardtype = 0; 
     347        u16 boardrev = 0; 
     348        u32 boardflags = 0; 
     349        u16 sdram_init = 0; 
     350        u16 cardbus = 0; 
     351        u16 strev = 0; 
     352 
     353        if (nvram_getenv("boardnum", buf, sizeof(buf)) >= 0) 
     354                boardnum = simple_strtoul(buf, NULL, 0); 
     355        if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) 
     356                boardtype = simple_strtoul(buf, NULL, 0); 
     357        if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) 
     358                boardrev = simple_strtoul(buf, NULL, 0); 
     359        if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0) 
     360                boardflags = simple_strtoul(buf, NULL, 0); 
     361        if (nvram_getenv("sdram_init", buf, sizeof(buf)) >= 0) 
     362                sdram_init = simple_strtoul(buf, NULL, 0); 
     363        if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) 
     364                cardbus = simple_strtoul(buf, NULL, 0); 
     365        if (nvram_getenv("st_rev", buf, sizeof(buf)) >= 0) 
     366                strev = simple_strtoul(buf, NULL, 0); 
     367 
     368        if ((boardnum == 8 || boardnum == 01) 
     369          && boardtype == 0x0472 && cardbus == 1) { 
     370                /* Netgear WNR834B, Netgear WNR834Bv2 */ 
     371                return ROUTER_NETGEAR_WNR834B; 
     372        } 
     373 
     374        if (boardnum == 01 && boardtype == 0x0472 && boardrev == 0x23) { 
     375                /* Netgear WNDR-3300 */ 
     376                return ROUTER_NETGEAR_WNDR3300; 
     377        } 
     378 
     379        if ((boardnum == 83258 || boardnum == 01) 
     380          && boardtype == 0x048e 
     381          && (boardrev == 0x11 || boardrev == 0x10) 
     382          && boardflags == 0x750 
     383          && sdram_init == 0x000A) { 
     384                /* Netgear WGR614v8/L/WW 16MB ram, cfe v1.3 or v1.5 */ 
     385                return ROUTER_NETGEAR_WGR614L; 
     386        } 
     387 
     388        if ((boardnum == 1 || boardnum == 3500) 
     389          && boardtype == 0x04CF 
     390          && (boardrev == 0x1213 || boardrev == 02)) { 
     391                /* Netgear WNR3500v2/U/L */ 
     392                return ROUTER_NETGEAR_WNR3500L; 
     393        } 
     394 
     395        if (boardnum == 1 && boardtype == 0xb4cf && boardrev == 0x1100) { 
     396                /* Netgear WNDR3400 */ 
     397                return ROUTER_NETGEAR_WNDR3400; 
     398        } 
     399 
     400        if (boardtype == 0x042f 
     401          && boardrev == 0x10 
     402          && boardflags == 0 
     403          && strev == 0x11) { 
     404                /* Simpletech Simpleshare */ 
     405                return ROUTER_SIMPLETECH_SIMPLESHARE; 
     406        } 
     407 
     408        return 0; 
     409} 
     410 
     411static int parse_bcm47xx_partitions(struct mtd_info *mtd, 
     412                                    struct mtd_partition **pparts, 
     413                                    struct mtd_part_parser_data *data) 
     414{ 
     415        int cfe_size; 
     416        int dual_image_offset = 0; 
     417        /* e.g Netgear 0x003e0000-0x003f0000 : "board_data", we exclude this 
     418         * part from our mapping to prevent overwriting len/checksum on e.g. 
     419         * Netgear WGR614v8/L/WW 
     420         */ 
     421        int custom_data_size = 0; 
     422        struct mtd_partition *bcm47xx_parts; 
     423 
     424        cfe_size = find_cfe_size(mtd); 
     425        if (cfe_size < 0) 
     426                return 0; 
     427 
     428        bcm47xx_parts = kzalloc(sizeof(struct mtd_partition) * 6, GFP_KERNEL); 
     429 
     430        bcm47xx_parts[0].name = "cfe"; 
     431        bcm47xx_parts[1].name = "linux"; 
     432        bcm47xx_parts[2].name = "rootfs"; 
     433        bcm47xx_parts[3].name = "nvram"; 
     434 
     435        /* boot loader */ 
     436        bcm47xx_parts[0].mask_flags = MTD_WRITEABLE; 
     437        bcm47xx_parts[0].offset = 0; 
     438        bcm47xx_parts[0].size   = cfe_size; 
     439 
     440        /* nvram */ 
     441        if (cfe_size != 384 * 1024) { 
     442 
     443                switch (get_router()) { 
     444                case ROUTER_NETGEAR_WGR614L: 
     445                case ROUTER_NETGEAR_WNR834B: 
     446                case ROUTER_NETGEAR_WNDR3300: 
     447                case ROUTER_NETGEAR_WNR3500L: 
     448                case ROUTER_NETGEAR_WNDR3400: 
     449                        /* Netgear: checksum is @ 0x003AFFF8 for 4M flash or checksum 
     450                         * is @ 0x007AFFF8 for 8M flash 
     451                         */ 
     452                        custom_data_size = mtd->erasesize; 
     453 
     454                        bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize); 
     455                        bcm47xx_parts[3].size   = roundup(NVRAM_SPACE, mtd->erasesize); 
     456 
     457                        /* Place CFE board_data into a partition */ 
     458                        bcm47xx_parts[4].name = "board_data"; 
     459                        bcm47xx_parts[4].offset = bcm47xx_parts[3].offset - custom_data_size; 
     460                        bcm47xx_parts[4].size   =  custom_data_size; 
     461                        break; 
     462 
     463                case ROUTER_SIMPLETECH_SIMPLESHARE: 
     464                        /* Fixup Simpletech Simple share nvram  */ 
     465 
     466                        pr_notice("Setting up simpletech nvram\n"); 
     467                        custom_data_size = mtd->erasesize; 
     468 
     469                        bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize) * 2; 
     470                        bcm47xx_parts[3].size   = roundup(NVRAM_SPACE, mtd->erasesize); 
     471 
     472                        /* Place backup nvram into a partition */ 
     473                        bcm47xx_parts[4].name = "nvram_copy"; 
     474                        bcm47xx_parts[4].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize); 
     475                        bcm47xx_parts[4].size   = roundup(NVRAM_SPACE, mtd->erasesize); 
     476                        break; 
     477 
     478                default: 
     479                        bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize); 
     480                        bcm47xx_parts[3].size   = roundup(NVRAM_SPACE, mtd->erasesize); 
     481                } 
     482 
     483        } else { 
     484                /* nvram (old 128kb config partition on netgear wgt634u) */ 
     485                bcm47xx_parts[3].offset = bcm47xx_parts[0].size; 
     486                bcm47xx_parts[3].size   = roundup(NVRAM_SPACE, mtd->erasesize); 
     487        } 
     488 
     489        /* dual image offset*/ 
     490        pr_notice("Looking for dual image\n"); 
     491        dual_image_offset = find_dual_image_off(mtd); 
     492        /* linux (kernel and rootfs) */ 
     493        if (cfe_size != 384 * 1024) { 
     494                if (get_router() == ROUTER_SIMPLETECH_SIMPLESHARE) { 
     495                        bcm47xx_parts[1].offset = bcm47xx_parts[0].size; 
     496                        bcm47xx_parts[1].size   = bcm47xx_parts[4].offset - dual_image_offset - 
     497                                bcm47xx_parts[1].offset - custom_data_size; 
     498                } else { 
     499                        bcm47xx_parts[1].offset = bcm47xx_parts[0].size; 
     500                        bcm47xx_parts[1].size   = bcm47xx_parts[3].offset - dual_image_offset - 
     501                                bcm47xx_parts[1].offset - custom_data_size; 
     502                } 
     503        } else { 
     504                /* do not count the elf loader, which is on one block */ 
     505                bcm47xx_parts[1].offset = bcm47xx_parts[0].size + 
     506                        bcm47xx_parts[3].size + mtd->erasesize; 
     507                bcm47xx_parts[1].size   = mtd->size - 
     508                        bcm47xx_parts[0].size - 
     509                        (2*bcm47xx_parts[3].size) - 
     510                        mtd->erasesize - custom_data_size; 
     511        } 
     512 
     513        /* find and size rootfs */ 
     514        find_root(mtd, &bcm47xx_parts[2]); 
     515        bcm47xx_parts[2].size = mtd->size - dual_image_offset - 
     516                                bcm47xx_parts[2].offset - 
     517                                bcm47xx_parts[3].size - custom_data_size; 
     518        *pparts = bcm47xx_parts; 
     519        return bcm47xx_parts[4].name == NULL ? 4 : 5; 
     520} 
     521 
     522static struct mtd_part_parser bcm47xx_parser = { 
     523        .owner = THIS_MODULE, 
     524        .parse_fn = parse_bcm47xx_partitions, 
     525        .name = "bcm47xx", 
     526}; 
     527 
     528static int __init bcm47xx_parser_init(void) 
     529{ 
     530        return register_mtd_parser(&bcm47xx_parser); 
     531} 
     532 
     533static void __exit bcm47xx_parser_exit(void) 
     534{ 
     535        deregister_mtd_parser(&bcm47xx_parser); 
     536} 
     537 
     538module_init(bcm47xx_parser_init); 
     539module_exit(bcm47xx_parser_exit); 
     540 
     541MODULE_LICENSE("GPL"); 
     542MODULE_DESCRIPTION("Parsing code for flash partitions on bcm47xx SoCs"); 
Note: See TracBrowser for help on using the repository browser.