From 850f912291f1fa013a75040743ca0798ab4def82 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Thu, 2 Jul 2009 01:26:53 +0800 Subject: [PATCH] upgrade driver patches --- .../xburst/patches-2.6.28/200-drivers.patch | 72409 +--------------- 1 file changed, 4207 insertions(+), 68202 deletions(-) diff --git a/target/linux/xburst/patches-2.6.28/200-drivers.patch b/target/linux/xburst/patches-2.6.28/200-drivers.patch index 57fe7cc8a..3dcc97bec 100644 --- a/target/linux/xburst/patches-2.6.28/200-drivers.patch +++ b/target/linux/xburst/patches-2.6.28/200-drivers.patch @@ -3,7 +3,7 @@ @@ -731,6 +731,16 @@ To compile this driver as a module, choose M here: the module will be called rtc. - + +config RTC_PCF8563 + bool 'Philips PCF8563 Real Time Clock (I2C Bus)' + help @@ -19,12 +19,12 @@ depends on SPARC32 && PCI @@ -1046,6 +1056,7 @@ default y - + source "drivers/s390/char/Kconfig" +source "drivers/char/jzchar/Kconfig" - + endmenu - + --- linux-2.6.24.7.old/drivers/char/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/drivers/char/Kconfig.orig 2009-04-12 18:01:55.000000000 +0200 @@ -0,0 +1,1051 @@ @@ -146,7 +146,7 @@ + tristate "Comtrol RocketPort support" + depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) + help -+ This driver supports Comtrol RocketPort and RocketModem PCI boards. ++ This driver supports Comtrol RocketPort and RocketModem PCI boards. + These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or + modems. For information about the RocketPort/RocketModem boards + and this driver read . @@ -1084,7 +1084,7 @@ @@ -98,6 +98,10 @@ obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o - + +obj-$(CONFIG_RTC_PCF8563) += rtc_pcf8563.o +obj-$(CONFIG_RTC_JZ) += rtc_jz.o +obj-$(CONFIG_JZCHAR) += jzchar/ @@ -1259,7 +1259,7 @@ + depends on JZCHAR + +config JZ_TPANEL -+ tristate 'JzSOC touchpanel driver support' ++ tristate 'JzSOC touchpanel driver support' + depends on JZCHAR +# select JZ_SADC if SOC_JZ4740 +# select JZ_TPANEL_AK4182 if SOC_JZ4730 @@ -1289,19 +1289,19 @@ + depends on JZCHAR + +config JZ_POWEROFF -+ tristate 'JZ board poweroff support' ++ tristate 'JZ board poweroff support' + depends on JZCHAR + +config JZ_OW -+ tristate 'JZ One-wire bus support' ++ tristate 'JZ One-wire bus support' + depends on JZCHAR + +config JZ_TCSM -+ tristate 'JZ TCSM support' ++ tristate 'JZ TCSM support' + depends on JZCHAR + +config JZ_TSSI -+ tristate 'JZ MPEG2-TS interface support' ++ tristate 'JZ MPEG2-TS interface support' + depends on JZCHAR && (SOC_JZ4750 || SOC_JZ4750D) + +endmenu @@ -1539,7 +1539,7 @@ + pressureval = (300*xpos*(z2-z1))/(4096*z1); + } + } -+ ++ + return pressureval; +} + @@ -1564,7 +1564,7 @@ + unsigned int v; + int bat_val[5]; + int total = 0, max_bat, min_bat; -+ ++ + v = ak4182_adc_read(0xA7, adcsync); + v = ak4182_adc_read(0xA7, adcsync); + for(v = 0;v <= 4;v++) @@ -1730,7 +1730,7 @@ + return valid; +} + -+ ++ +#define TSMAXX 945 +#define TSMAXY 830 +#define TSMINX 90 @@ -1740,7 +1740,7 @@ +#define SCREEN_Y 272 + +static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x ) -+{ ++{ + + if (ts->minx) + { @@ -1764,18 +1764,18 @@ + { + if (y < ts->miny) y = ts->miny; + if (y > ts->maxy) y = ts->maxy; -+ ++ + return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); + } + else + { + if (y < TSMINY) y = TSMINY; + if (y > TSMAXY) y = TSMAXY; -+ ++ + return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); + } +} -+ ++ +/*------------------ Common routines -------------------*/ + +void ts_enable_irq(void) @@ -1791,7 +1791,7 @@ + disable_irq(TS_IRQ); +} + -+int ts_request_irq(u32 *irq, ++int ts_request_irq(u32 *irq, + irqreturn_t (*handler)(int, void *), + const char *devname, + void *dev_id) @@ -1806,9 +1806,9 @@ + ak4182_ssi_set_normal_mode(); + ak4182_ssi_set_clk_div_ratio(JZ_EXTAL, 200*1000);//DCLK is 1.5M Hz max + ak4182_ssi_set_IRQ(); -+ ++ + ak4182_enable_irq(); -+ ++ + /* enable gpio irq */ + __gpio_as_irq_fall_edge(TS_PIN); + @@ -1863,7 +1863,7 @@ + + if (valid) { + unsigned int x_scr, y_scr; -+ ++ + if(ts->filter) { + x_scr = transform_to_screen_x(ts, x_raw[0]); + y_scr = transform_to_screen_y(ts, y_raw[0]); @@ -1924,7 +1924,7 @@ + int ret; + struct ak4182 *akinfo = pm_dev->data; + -+ if (!akinfo) ++ if (!akinfo) + return -EINVAL; + + @@ -2045,22 +2045,22 @@ +#define ATA2508_SENSOR_MASK 0x1F + +const unsigned char init_data_burst[] = {//Address:0x0D-0x3E -+ 0x04, // BETA -+ 0x27, // AIC_WAIT ++ 0x04, // BETA ++ 0x27, // AIC_WAIT + //0x32, // REF_DELAY + 0x16, // REF_DELAY -+ 0x02, // HYSTERESIS01 ++ 0x02, // HYSTERESIS01 + 0x02, // HYSTERESIS1 + 0x02, // HYSTERESIS2 -+ 0x02, // HYSTERESIS3 -+ 0x02, // HYSTERESIS4 ++ 0x02, // HYSTERESIS3 ++ 0x02, // HYSTERESIS4 + 0x02, // HYSTERESIS51 -+ 0x02, // HYSTERESIS61 -+ 0x02, // HYSTERESIS7 -+ 0x02, // HYSTERESIS8 -+ 0x02, // HYSTERESIS9 -+ 0x02, // HYSTERESIS10 -+ 0x02, // HYSTERESIS11 ++ 0x02, // HYSTERESIS61 ++ 0x02, // HYSTERESIS7 ++ 0x02, // HYSTERESIS8 ++ 0x02, // HYSTERESIS9 ++ 0x02, // HYSTERESIS10 ++ 0x02, // HYSTERESIS11 + 0x64, // STRENGTH_THRESHOLD0 + 0x64, // STRENGTH_THRESHOLD1 + 0x64, // STRENGTH_THRESHOLD2 @@ -2077,40 +2077,40 @@ + 0xC8, // INTEGRATION TIME + 0x0f, // IDLE TIME + 0x00, // SIF_SETUP(RESERVED) -+ 0x01, // MODE -+ 0x00, // GPIO_REG_L -+ 0x00, // GPIO_REG_H ++ 0x01, // MODE ++ 0x00, // GPIO_REG_L ++ 0x00, // GPIO_REG_H + 0x00, // GPIO_CONFIGURATION_L + 0x00, // GPIO_CONFIGURATION_H -+ 0x00, // GPIO_DIR_L -+ 0x00, // GPIO_DIR_H -+ 0x0c, // CONTROL -+ 0x38, // INT_MASK -+ 0x00, // INT_CLEAR -+ 0xFF, // INT_edge -+ 0x02, // CONTROL_2 -+ 0xAF, // BEEP_TIME -+ 0x7F, // BEEP_FREQUENCY -+ 0x30, // CALIBRATION INTERVAL -+ 0x00, // EINT_ENABLE -+ 0x00, // EINT_POL -+ 0x00, // FILTER_PERIOD -+ 0x00, // FILTER_THRESHOLD ++ 0x00, // GPIO_DIR_L ++ 0x00, // GPIO_DIR_H ++ 0x0c, // CONTROL ++ 0x38, // INT_MASK ++ 0x00, // INT_CLEAR ++ 0xFF, // INT_edge ++ 0x02, // CONTROL_2 ++ 0xAF, // BEEP_TIME ++ 0x7F, // BEEP_FREQUENCY ++ 0x30, // CALIBRATION INTERVAL ++ 0x00, // EINT_ENABLE ++ 0x00, // EINT_POL ++ 0x00, // FILTER_PERIOD ++ 0x00, // FILTER_THRESHOLD +}; +const unsigned char init_data_alpha[] = {//Address:0x00-0x0C -+ 0x02, // APIS -+ 0x08, // ALPHA0 -+ 0x08, // ALPHA1 -+ 0x08, // ALPHA2 -+ 0x08, // ALPHA3 -+ 0x08, // ALPHA4 -+ 0x28, // ALPHA5 -+ 0x28, // ALPHA6 ++ 0x02, // APIS ++ 0x08, // ALPHA0 ++ 0x08, // ALPHA1 ++ 0x08, // ALPHA2 ++ 0x08, // ALPHA3 ++ 0x08, // ALPHA4 ++ 0x28, // ALPHA5 ++ 0x28, // ALPHA6 + 0x28, // ALPHA7 -+ 0x28, // ALPHA8 -+ 0x28, // ALPHA9 -+ 0x28, // ALPHA10 -+ 0x28, // ALPHA11 ++ 0x28, // ALPHA8 ++ 0x28, // ALPHA9 ++ 0x28, // ALPHA10 ++ 0x28, // ALPHA11 +}; +static unsigned int i2c_addr = 0x58; +static unsigned int i2c_clk = 100000; @@ -2142,7 +2142,7 @@ +{ + int key_num = 0; + u8 value0, value1; -+ ++ + __gpio_ack_irq(MP4_KEY_TINT); + value0 = read_reg(0x75); + value1 = read_reg(0x76); @@ -2155,7 +2155,7 @@ + value0 >>= 1; + key_num++; + } -+ ++ + printk("\nPress key %d!\n", key_num); + return IRQ_HANDLED; +} @@ -2180,7 +2180,7 @@ + data1 = init_data_alpha[i]; + write_reg(i, data1); + } -+ ++ + for(i=13; i<63; i++) + { + data1 = init_data_burst[i-13]; @@ -2193,7 +2193,7 @@ + printk("REG0x%02x = 0x%02x\n", i, data1); + } +#endif -+ ++ + /* wait for 1 ms*/ + mdelay(1); +#if 0 @@ -2215,7 +2215,7 @@ + write_reg(ADDR_WARM_RESET, 0x00); //ADDR_WARM_RESET=0xFF + + //printk("REG0x68 = %d\n", data1); -+ ++ + /* wait for 1 ~ 10 ms.*/ + mdelay(10); + data1 = read_reg(0x68); @@ -2237,7 +2237,7 @@ + +static void __exit exit_ata2508(void) +{ -+ free_irq(MP4_TINT_IRQ, NULL); ++ free_irq(MP4_TINT_IRQ, NULL); +} + +module_init(init_ata2508); @@ -2331,7 +2331,7 @@ +struct cim_desc { + u32 nextdesc; /* Physical address of next desc */ + u32 framebuf; /* Physical address of frame buffer */ -+ u32 frameid; /* Frame ID */ ++ u32 frameid; /* Frame ID */ + u32 dmacmd; /* DMA command */ +}; + @@ -2450,7 +2450,7 @@ +static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l); +static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); + -+static struct file_operations cim_fops = ++static struct file_operations cim_fops = +{ + open: cim_open, + release: cim_release, @@ -2526,7 +2526,7 @@ + cim_config(&c); + + break; -+ } ++ } + default: + printk("Not supported command: 0x%x\n", cmd); + return -EINVAL; @@ -2588,7 +2588,7 @@ + return ret; + } + -+ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, ++ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, + CIM_NAME, dev))) { + cim_fb_destroy(); + kfree(dev); @@ -2735,7 +2735,7 @@ +static void do_interrupt_mode_test(void); +static void do_cpu_mode_test(void); + -+static struct file_operations ow_fops = ++static struct file_operations ow_fops = +{ + open: ow_open, + release: ow_release, @@ -2753,7 +2753,7 @@ +static int ow_release(struct inode *inode, struct file *filp) +{ + module_put(THIS_MODULE); -+ return 0; ++ return 0; +} + +static ssize_t ow_read(struct file *filp, char *buf, size_t size, loff_t *l) @@ -2826,8 +2826,8 @@ + +static void ow_intcm_read_rom(char *rom) +{ -+ int i; -+ ++ int i; ++ + __owi_select_regular_mode(); + REG_OWI_DIV = 23; + __owi_clr_sts(); @@ -2840,34 +2840,34 @@ + REG_OWI_DAT = 0x33; + do_ow_wrdata(); + sleep_on(&ow_wait_queue); -+ ++ + for(i=0; i<8; i++){ + do_ow_rddata(); + sleep_on(&ow_wait_queue); + rom[i] = REG_OWI_DAT; -+ } ++ } + __intc_mask_irq(IRQ_OWI); +} + +static void ow_intcm_search_rom(void) +{ -+ int i, j; ++ int i, j; + int normal, reverse; +#if 1 + unsigned char rom[8]={0x01, 0xf9, 0x35, 0x53, 0x11, 0x00, 0x00, 0x3e}; +#else + unsigned char rom[8]={0x01, 0xd8, 0x10, 0x02, 0x10, 0x00, 0x00, 0x22}; +#endif -+ __owi_select_regular_mode(); ++ __owi_select_regular_mode(); + REG_OWI_DIV = __cpm_get_extalclk()/1000000 - 1; + __owi_clr_sts(); + __intc_unmask_irq(IRQ_OWI); + __owi_enable_all_interrupts(); -+ ++ + /* reset */ + do_ow_rst(); + sleep_on(&ow_wait_queue); -+ ++ + /* send search ROM command */ + REG_OWI_DAT = 0xf0; + do_ow_wrdata(); @@ -2900,8 +2900,8 @@ + printk("write 0\n"); + do_ow_wr0(); + sleep_on(&ow_wait_queue); -+ } -+ ++ } ++ +#else + if(normal ==0 && reverse ==0){ + if (!((rom[i]>>j) & 1) ){ @@ -2913,9 +2913,9 @@ + printk("write 0\n"); + do_ow_wr0(); + sleep_on(&ow_wait_queue); -+ } ++ } + }else{ -+ ++ + if(normal ==0){ + printk("write 0\n"); + do_ow_wr0(); @@ -2935,14 +2935,14 @@ + + printk("\nSearch rom INTC mode: device found SUCCESSFULLY\n"); + __intc_mask_irq(IRQ_OWI); -+ ++ +} + +static void ow_cpum_read_rom(char *rom) +{ -+ int i; -+ -+ __owi_select_regular_mode(); ++ int i; ++ ++ __owi_select_regular_mode(); + REG_OWI_DIV = __cpm_get_extalclk()/1000000 - 1; + __owi_clr_sts(); + __owi_disable_all_interrupts(); @@ -2952,16 +2952,16 @@ + + if(!__owi_get_sts_pst()) + printk("read rom no device found\n"); -+ ++ + REG_OWI_DAT = 0x33; + do_ow_wrdata(); + __owi_wait_ops_rdy(); -+ ++ + for(i=0; i<8; i++){ + do_ow_rddata(); + __owi_wait_ops_rdy(); + rom[i] = REG_OWI_DAT; -+ } ++ } +} + + @@ -2969,7 +2969,7 @@ +{ + int i; + for(i=0; i<8; i++){ -+ if ( comm & (1<>j) & 1) ){ @@ -3045,9 +3045,9 @@ + printk("write 0\n"); + do_ow_wr0(); + while(!__owi_get_sts_bit_rdy()) ; -+ } ++ } + }else{ -+ ++ + if(normal ==0){ + printk("write 0\n"); + do_ow_wr0(); @@ -3066,15 +3066,15 @@ + } + printk("\nSearch rom CPU mode: device found SUCCESSFULLY\n"); +} -+ ++ +static void do_interrupt_mode_test(void) +{ + int ret, i; + unsigned char rom[8]; -+ ++ + /* interrupt mode */ -+ ret = request_irq(IRQ_OWI, ow_interrupt, IRQF_DISABLED, -+ "JZ_OWI", NULL); ++ ret = request_irq(IRQ_OWI, ow_interrupt, IRQF_DISABLED, ++ "JZ_OWI", NULL); + if(ret) + printk("failed irq \n"); + @@ -3094,7 +3094,7 @@ + +static void do_cpu_mode_test(void) +{ -+ ++ +#if OW_CPU_READ_ROM + int i; + unsigned char rom[8]; @@ -3107,7 +3107,7 @@ +#endif + +#if OW_CPU_SEARCH_ROM -+ ow_cpum_search_rom(); ++ ow_cpum_search_rom(); +#endif +} + @@ -3132,7 +3132,7 @@ + + do_interrupt_mode_test(); + do_cpu_mode_test(); -+ ++ + printk("Ingenic OW driver registered\n"); + + return 0; @@ -3233,7 +3233,7 @@ +{ + unsigned long flags; + int ret; -+ ++ + spin_lock_irqsave(&ts->lock, flags); + ret = ts->event_count; + if (ts->event_count) { @@ -3269,12 +3269,12 @@ + else + ts->irq_enabled = 1; + -+ ++ + if (pen_is_down) + pen_is_down = 0; + else + pen_is_down = 1; -+ ++ + // callback routine to clear irq status + ts_irq_callback(); + @@ -3407,14 +3407,14 @@ + set_current_state(TASK_INTERRUPTIBLE); + err = -EAGAIN; + if (filp->f_flags & O_NONBLOCK) -+ break; ++ break; + schedule(); + } + } -+ ++ + current->state = TASK_RUNNING; + remove_wait_queue(&ts->wait, &wait); -+ ++ + return ptr == buffer ? err : ptr - buffer; +} + @@ -3434,7 +3434,7 @@ + ts->sleeping = 0; + // flush event queue + ts->nextIn = ts->nextOut = ts->event_count = 0; -+ ++ + // Init acquisition timer function + init_timer(&ts->acq_timer); + ts->acq_timer.function = jz_acq_timer; @@ -3477,13 +3477,13 @@ + int minx; + int miny; + int maxx; -+ int maxy; ++ int maxy; + }; + + struct txy ch; + -+ /* -+ * Switch according to the ioctl called ++ /* ++ * Switch according to the ioctl called + */ + switch (ioctl_num) + { @@ -3492,11 +3492,11 @@ + break; + case IOCTL_SET_NUM: + if (copy_from_user((void *)&ch, (void *)ioctl_param, sizeof(ch))) -+ return -EFAULT; ++ return -EFAULT; + jz_ts.minx = ch.minx; + jz_ts.miny = ch.miny; + jz_ts.maxx = ch.maxx; -+ jz_ts.maxy = ch.maxy; ++ jz_ts.maxy = ch.maxy; + break; + } + @@ -3529,7 +3529,7 @@ +static int __init miny_setup(char *str) +{ + int i; -+ if (get_option(&str,&i)) jz_ts.miny = i; ++ if (get_option(&str,&i)) jz_ts.miny = i; + return 1; +} + @@ -3538,7 +3538,7 @@ +static int __init maxx_setup(char *str) +{ + int i; -+ if (get_option(&str,&i)) jz_ts.maxx = i; ++ if (get_option(&str,&i)) jz_ts.maxx = i; + return 1; +} + @@ -3574,7 +3574,7 @@ +{ + struct jz_ts_t *ts = &jz_ts; + int ret; -+ ++ + if ((ret = misc_register(&jz_ts_dev)) < 0) { + err("can't register misc device"); + return ret; @@ -3602,7 +3602,7 @@ +#ifndef __JZ_TS_H__ +#define __JZ_TS_H__ + -+/* ++/* + * IOCTL commands + */ +#define IOCTL_SET_MSG 0 @@ -3744,13 +3744,13 @@ + printk(" DMADBR = 0x%8x\n", REG_DMAC_DMADBR(1)); +} + -+static int tssi_buf_init( struct jz_tssi_buf_ring_t * ring ) ++static int tssi_buf_init( struct jz_tssi_buf_ring_t * ring ) +{ + int i; + struct jz_tssi_buf * bp,* ap, *cp; + + ap = cp = bp = (struct jz_tssi_buf *)kmalloc( sizeof( struct jz_tssi_buf ) ,GFP_KERNEL ); //the first -+ if ( !bp ) { ++ if ( !bp ) { + printk("Can not malloc buffer! \n"); + return -1; + } @@ -3758,14 +3758,14 @@ + for ( i = 0; i < RING_BUF_NUM; i ++ ) { + bp = ap; + bp->buf = (unsigned int *) kmalloc(MPEG2_TS_PACHAGE_SIZE / 4 * sizeof(unsigned int) ,GFP_KERNEL); -+ if ( !bp->buf ) { ++ if ( !bp->buf ) { + printk("Can not malloc buffer! \n"); + return -1; + } + bp->index = i; + bp->pos = 0; + ap = (struct jz_tssi_buf *)kmalloc( sizeof( struct jz_tssi_buf ) ,GFP_KERNEL ); -+ if ( !ap ) { ++ if ( !ap ) { + printk("Can not malloc buffer! \n"); + return -1; + } @@ -3785,7 +3785,7 @@ +{ + int i; + struct jz_tssi_buf * ap; -+ for ( i = 0; i < RING_BUF_NUM; i ++ ) ++ for ( i = 0; i < RING_BUF_NUM; i ++ ) + { + ap = ring->front; + ring->front = ring->front->next; @@ -3807,13 +3807,13 @@ + return; + } +#endif -+ ++ + for ( i = 0; i < 8 ; i ++ ) + { + ring->front->buf[ring->front->pos++] = REG_TSSI_FIFO; + } + -+ if ( ring->front->pos >= MPEG2_TS_PACHAGE_SIZE ) ++ if ( ring->front->pos >= MPEG2_TS_PACHAGE_SIZE ) + { + ring->fu_num ++; + ring->front = ring->front->next; @@ -3864,7 +3864,7 @@ + unsigned int addr ; + int n = pid_num / 2, hl = pid_num % 2; + if ( hl ) //use high pid, pid1 -+ { ++ { + addr = TSSI_PID0 + ( n * 4 ); + REG32( addr ) |= ( (pid & 0x1fff) << 16 ); //13bit + REG_TSSI_PEN |= ( 1 << (16 + n) ); @@ -3978,7 +3978,7 @@ + REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_TSSIIN; + REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; + REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; -+ REG_DMAC_DTCR(dma_chan) = size / 32; ++ REG_DMAC_DTCR(dma_chan) = size / 32; + REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE; + REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; + REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */ @@ -4040,7 +4040,7 @@ + break; + + case IOCTL_TSSI_FLUSHPID : //set all filting pid to false -+ REG_TSSI_PEN = 0x0; ++ REG_TSSI_PEN = 0x0; + REG_TSSI_PID0 = 0x0; + REG_TSSI_PID1 = 0x0; + REG_TSSI_PID2 = 0x0; @@ -4097,7 +4097,7 @@ + return -1; + } + -+ jz_register_chrdev(TSSI_MINOR, TSSI_NAME, &tssi_fops, &jz_tssi_g); ++ jz_register_chrdev(TSSI_MINOR, TSSI_NAME, &tssi_fops, &jz_tssi_g); + + printk("Jz MPEG2-TS interface driver registered %x %d\n",&jz_tssi_g,tssi->dma_chan); + return 0; @@ -4119,7 +4119,7 @@ +#ifndef __JZ_TSSI_H__ +#define __JZ_TSSI_H__ + -+/* ++/* + * IOCTL commands + */ +#define IOCTL_TSSI_ENABLE 0x01 @@ -4138,9 +4138,9 @@ +#define IOCTL_TSSI_ENIRQ_TRIG 0x08 +#define IOCTL_TSSI_DEIRQ_TRIG 0x09 +#define IOCTL_TSSI_ENIRQ_OVRN 0x0a -+#define IOCTL_TSSI_DEIRQ_OVRN 0x0b ++#define IOCTL_TSSI_DEIRQ_OVRN 0x0b +#define IOCTL_TSSI_ENPID0 0x0c -+#define IOCTL_TSSI_DEPID0 0x0d ++#define IOCTL_TSSI_DEPID0 0x0d +#define IOCTL_TSSI_ENPIDN 0x0e +#define IOCTL_TSSI_DEPIDN 0x0f +#define IOCTL_TSSI_SETPIDN 0x10 @@ -4445,7 +4445,7 @@ +MODULE_LICENSE("GPL"); + +#undef DEBUG -+//#define DEBUG ++//#define DEBUG +#ifdef DEBUG +#define dprintk(x...) printk(x) +#else @@ -4475,7 +4475,7 @@ +} while (0) +#endif + -+#ifdef CONFIG_SOC_JZ4740 ++#ifdef CONFIG_SOC_JZ4740 +#define GPIO_PW_I 125 +#define POWEROFF_PIN_DOWN 0 +#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_fall_edge(POWEROFF_PIN) @@ -4487,7 +4487,7 @@ + } + +#define GPIO_DISP_OFF_N 118 -+#define GPIO_PWM 123 ++#define GPIO_PWM 123 +#define __lcd_close_backlight() \ +do { \ +__gpio_as_output(GPIO_PWM); \ @@ -4495,7 +4495,7 @@ +} while (0) +#endif + -+#ifdef CONFIG_SOC_JZ4750 ++#ifdef CONFIG_SOC_JZ4750 +#define GPIO_PW_I GPIO_WAKEUP +#define POWEROFF_PIN_DOWN 0 +#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_fall_edge(POWEROFF_PIN) @@ -4512,12 +4512,12 @@ + +#define POWEROFF_PERIOD 1000 /* unit: ms */ +#define POWEROFF_DELAY 100 /* unit: ms */ -+ ++ +static struct timer_list poweroff_timer; +static struct timer_list poweroff_delaytimer; +static struct work_struct suspend_work; + -+static int poweroff_flag = 0; ++static int poweroff_flag = 0; +static int suspend_flag = 0; +static int num_seconds = 0; + @@ -4535,10 +4535,10 @@ + if (++num_seconds > 3) + { + printk("\nShutdown system now ..\n"); -+ ++ +#ifndef USE_SUSPEND_HOTPLUG + /* Turn off LCD to inform user that the system is shutting down. -+ * But the information of shutting down system will be shown ++ * But the information of shutting down system will be shown + * by userspace program if hotplug is used. + */ + __lcd_close_backlight(); @@ -4546,7 +4546,7 @@ + + /* + * Wait until the power key is up, or the system will reset with -+ * power key down after entering hibernate. ++ * power key down after entering hibernate. + */ + while(__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN); + @@ -4580,7 +4580,7 @@ + suspend_flag = 0; + del_timer(&poweroff_delaytimer); + SET_POWEROFF_PIN_AS_IRQ; -+ __gpio_unmask_irq(POWEROFF_PIN); ++ __gpio_unmask_irq(POWEROFF_PIN); + return; + } + del_timer(&poweroff_delaytimer); @@ -4620,9 +4620,9 @@ + poweroff_delaytimer.function = poweroff_delaytimer_routine; + add_timer(&poweroff_delaytimer); + } -+ else { ++ else { + -+/* ++/* + * If it reaches here without jz_udc_active == 0, then it indicates POWEROFF_PIN was + * changed to WAKEUP key in pm.c for hand is not able to rise up so quickly, so the + * irq handler entered because of WAKEUP key not POWEROFF_PIN. @@ -4665,7 +4665,7 @@ + int ret; + int *poweroff_info = pm_dev->data; + -+ if (!poweroff_info) ++ if (!poweroff_info) + return -EINVAL; + + switch (rqst) { @@ -4721,17 +4721,17 @@ + + envp[i++] = slotnum; + envp[i++] = media; -+ ++ + if (state) + envp[i++] = "ACTION=enter"; + else + envp[i++] = "ACTION=exit"; -+ ++ + envp[i] = 0; + + dprintk("SUSPEND: hotplug path=%s state=%d\n", argv[0], state); + -+ SET_POWEROFF_PIN_AS_IRQ; ++ SET_POWEROFF_PIN_AS_IRQ; + __gpio_unmask_irq(POWEROFF_PIN); /* set it because call hotplug with call_usermodehelper() \ + might failed, especially when using nfsroot */ + @@ -4780,7 +4780,7 @@ + + return 0; +} -+ ++ +static void __exit poweroff_exit(void) +{ + free_irq(POWEROFF_IRQ, NULL); @@ -4862,14 +4862,14 @@ +static unsigned int old_x, old_y; +extern unsigned int (*codec_read_battery)(void); + -+/* ++/* + * set adc clock to 12MHz/div. A/D works at freq between 500KHz to 6MHz. + */ +static void sadc_init_clock(int div) +{ + if (div < 2) div = 2; + if (div > 23) div = 23; -+#if defined(CONFIG_SOC_JZ4740) ++#if defined(CONFIG_SOC_JZ4740) + REG_SADC_CFG &= ~SADC_CFG_CLKDIV_MASK; + REG_SADC_CFG |= (div - 1) << SADC_CFG_CLKDIV_BIT; +#endif @@ -4977,24 +4977,24 @@ + else + x_cal= xp[2] + ((usd2 < usd1) ? xp[0] : xp[1]); + x_cal >>= 1; -+ -+ if ( (usd0 < xMaxError) && (usd1 < xMaxError) && (usd2 < xMaxError) ) ++ ++ if ( (usd0 < xMaxError) && (usd1 < xMaxError) && (usd2 < xMaxError) ) + x_valid = 1; -+ ++ + usd0 = (yp[0] > yp[1]) ? (yp[0] - yp[1]) : (yp[1] - yp[0]); + usd1 = (yp[1] > yp[2]) ? (yp[1] - yp[2]) : (yp[2] - yp[1]); + usd2 = (yp[2] > yp[0]) ? (yp[2] - yp[0]) : (yp[0] - yp[2]); -+ ++ + if ( usd0 < usd1) + y_cal = yp[0] + ((usd2 < usd0) ? yp[2] : yp[1]); + else + y_cal = yp[2] + ((usd2 < usd1) ? yp[0] : yp[1]); -+ ++ + y_cal >>= 1; -+ -+ if ( (usd0 < yMaxError) && (usd1 < yMaxError) && (usd2 < yMaxError) ) ++ ++ if ( (usd0 < yMaxError) && (usd1 < yMaxError) && (usd2 < yMaxError) ) + y_valid = 1; -+ ++ + if( x_valid && y_valid) + valid = 1; + @@ -5048,7 +5048,7 @@ + x_cal /= count; + y_cal /= count; + p_cal /= count; -+ ++ + if (first_time) { + first_time = 0; + last_x = x_cal; @@ -5079,7 +5079,7 @@ +#define SCREEN_Y 272 + +static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x ) -+{ ++{ + + if (ts->minx) + { @@ -5103,14 +5103,14 @@ + { + if (y < ts->minx) y = ts->miny; + if (y > ts->maxx) y = ts->maxy; -+ ++ + return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); + } + else + { + if (y < TSMINX) y = TSMINY; + if (y > TSMAXX) y = TSMAXY; -+ ++ + return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); + } +} @@ -5124,7 +5124,7 @@ +static ssize_t sadc_write(struct file *filp, const char *buf, size_t size, loff_t *l); +static int sadc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); + -+static struct file_operations sadc_fops = ++static struct file_operations sadc_fops = +{ + open: sadc_open, + release: sadc_release, @@ -5203,9 +5203,9 @@ + REG_SADC_CTRL |= SADC_CTRL_PENDM; + REG_SADC_CTRL &= ~SADC_CTRL_PENUM; + p = 1; -+ } ++ } + -+ if (!(REG_SADC_CTRL&SADC_CTRL_PENUM)&&(REG_SADC_STATE & SADC_STATE_PENU)) { ++ if (!(REG_SADC_CTRL&SADC_CTRL_PENUM)&&(REG_SADC_STATE & SADC_STATE_PENU)) { + REG_SADC_STATE = SADC_STATE_PENU; + REG_SADC_CTRL |= SADC_CTRL_PENUM; + REG_SADC_CTRL &= ~SADC_CTRL_PENDM; @@ -5220,7 +5220,7 @@ + return p; +} + -+int ts_request_irq(u32 *irq, ++int ts_request_irq(u32 *irq, + irqreturn_t (*handler)(int, void *), + const char *devname, + void *dev_id) @@ -5231,8 +5231,8 @@ + *irq = IRQ_SADC; + ts_disable_irq(); + /* interrupt mode */ -+ ret = request_irq(IRQ_SADC, handler, IRQF_DISABLED, -+ devname, dev_id); ++ ret = request_irq(IRQ_SADC, handler, IRQF_DISABLED, ++ devname, dev_id); + if(ret) + printk("failed irq \n"); + @@ -5310,7 +5310,7 @@ + + if (valid) { + unsigned int x_scr, y_scr; -+ ++ + if(ts->filter) { + x_scr = transform_to_screen_x(ts, x_raw[0]); + y_scr = transform_to_screen_y(ts, y_raw[0]); @@ -5321,7 +5321,7 @@ + else { + x_scr = x_raw[0]; + y_scr = y_raw[0]; -+ ++ + if (ts->prints) + printk("x_raw=%d y_raw=%d \n", x_raw[0], y_raw[0]); + } @@ -5455,7 +5455,7 @@ +static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l); +static int sensor_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); + -+static struct file_operations sensor_fops = ++static struct file_operations sensor_fops = +{ + open: sensor_open, + release: sensor_release, @@ -5473,7 +5473,7 @@ +static int sensor_release(struct inode *inode, struct file *filp) +{ + module_put(THIS_MODULE); -+ return 0; ++ return 0; +} + +static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l) @@ -5563,7 +5563,7 @@ +/* + * linux/drivers/char/jzchar/tcsm.c + * -+ * Virtual device driver with tricky appoach to manage TCSM ++ * Virtual device driver with tricky appoach to manage TCSM + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * @@ -5611,7 +5611,7 @@ +static ssize_t tcsm_write(struct file *filp, const char *buf, size_t size, loff_t *l); +static int tcsm_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); + -+static struct file_operations tcsm_fops = ++static struct file_operations tcsm_fops = +{ + open: tcsm_open, + release: tcsm_release, @@ -5637,7 +5637,7 @@ + struct pt_regs *info = task_pt_regs(current); + info->cp0_status |= 0x10; + info->cp0_status &= ~0x08000000; // a tricky -+ return 0; ++ return 0; +} + +static ssize_t tcsm_read(struct file *filp, char *buf, size_t size, loff_t *l) @@ -6080,7 +6080,7 @@ + return valid; +} + -+ ++ +#define TSMAXX 945 +#define TSMAXY 830 +#define TSMINX 90 @@ -6090,7 +6090,7 @@ +#define SCREEN_Y 272 + +static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x ) -+{ ++{ + + if (ts->minx) + { @@ -6114,18 +6114,18 @@ + { + if (y < ts->minx) y = ts->miny; + if (y > ts->maxx) y = ts->maxy; -+ ++ + return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); + } + else + { + if (y < TSMINX) y = TSMINY; + if (y > TSMAXX) y = TSMAXY; -+ ++ + return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); + } +} -+ ++ +/*------------------ Common routines -------------------*/ + +void ts_enable_irq(void) @@ -6143,7 +6143,7 @@ + disable_irq(TS_IRQ); +} + -+int ts_request_irq(u32 *irq, ++int ts_request_irq(u32 *irq, + void (*handler)(int, void *, struct pt_regs *), + const char *devname, + void *dev_id) @@ -6423,7 +6423,7 @@ +#define UDC_HOTPLUG_PIN GPIO_UDC_HOTPLUG +#define UDC_HOTPLUG_IRQ (IRQ_GPIO_0 + UDC_HOTPLUG_PIN) + -+#define dprintk(x,...) ++#define dprintk(x,...) + +//simple meaning define +#define NOT_CONNECT 0 @@ -6494,7 +6494,7 @@ + { + dprintk("udc suspend!\n"); + udc_old_state = 0; -+ cur_pnp_stat.protl_stat = NOT_CONNECT; ++ cur_pnp_stat.protl_stat = NOT_CONNECT; + del_timer(&udc_long_timer); + wake_up_process(kudcd_task); + return; @@ -6724,7 +6724,7 @@ + /* Deliver this event to user space in udev model */ + if (cur_pnp_stat.protl_stat) + send_event_udev(EVENT_USB_ADD); -+ else ++ else + send_event_udev(EVENT_POWER_ADD); + cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat; + cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat; @@ -6743,9 +6743,9 @@ + __gpio_as_irq_rise_edge(UDC_HOTPLUG_PIN); + + /* clear interrupt pending status */ -+ __gpio_ack_irq(UDC_HOTPLUG_PIN); ++ __gpio_ack_irq(UDC_HOTPLUG_PIN); + /* unmask interrupt */ -+ __gpio_unmask_irq(UDC_HOTPLUG_PIN); ++ __gpio_unmask_irq(UDC_HOTPLUG_PIN); +} + +static int udc_pnp_thread(void *unused) @@ -6767,11 +6767,11 @@ + +static irqreturn_t udc_pnp_irq(int irq, void *dev_id) +{ -+ ++ + /* clear interrupt pending status */ -+ __gpio_ack_irq(UDC_HOTPLUG_PIN); ++ __gpio_ack_irq(UDC_HOTPLUG_PIN); + /* mask interrupt */ -+ __gpio_mask_irq(UDC_HOTPLUG_PIN); ++ __gpio_mask_irq(UDC_HOTPLUG_PIN); + /* wake up pnp detect thread */ + wake_up_process(kudcd_task); + @@ -6977,7 +6977,7 @@ +#endif +} + -+int ts_request_irq(u32 *irq, ++int ts_request_irq(u32 *irq, + void (*handler)(int, void *, struct pt_regs *), + const char *devname, + void *dev_id) @@ -7058,10 +7058,10 @@ + int i; + + for (i=0; iminx) + { @@ -7120,18 +7120,18 @@ + { + if (y < ts->minx) y = ts->miny; + if (y > ts->maxx) y = ts->maxy; -+ ++ + return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); + } + else + { + if (y < TSMINX) y = TSMINY; + if (y > TSMAXX) y = TSMAXY; -+ ++ + return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); + } +} -+ ++ + +/* + * Acquire Raw pen coodinate data and compute touch screen @@ -7331,7 +7331,7 @@ +} + +static void get_rtc_alm_time(struct rtc_time *alm_tm) -+{ ++{ + unsigned long lval; + struct rtc_time altm; + @@ -7459,7 +7459,7 @@ +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ -+ struct rtc_time wtime; ++ struct rtc_time wtime; + + switch (cmd) { + case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ @@ -7511,7 +7511,7 @@ + * means "don't care" or "match all". Only the tm_hour, + * tm_min, and tm_sec values are filled in. + */ -+ ++ + get_rtc_alm_time(&wtime); + return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; + @@ -7526,7 +7526,7 @@ + printk("invalid time set in Line:%d! \n",__LINE__); + return -EFAULT; + } -+ ++ + return set_rtc_alm_time(&alm_tm); + } + case RTC_RD_TIME: /* Read the time/date from RTC */ @@ -7546,13 +7546,13 @@ + printk("invalid time set in Line:%d! \n",__LINE__); + return -EFAULT; + } -+ ++ + return set_rtc_time(&rtc_tm); + } + case RTC_EPOCH_READ: /* Read the epoch. */ + return put_user (epoch, (unsigned long *)arg); + case RTC_EPOCH_SET: /* Set the epoch. */ -+ /* ++ /* + * There were no RTC clocks before 1900. + */ + if (arg < 1900) @@ -7659,7 +7659,7 @@ + i = 0; + envp[i++] = "HOME=/"; + envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; -+ ++ + /* other stuff we want to pass to /sbin/hotplug */ + + envp[i] = 0; @@ -7720,7 +7720,7 @@ + } + /* clear irq flags */ + __rtc_clear_1Hz_flag(); -+ /* In a alarm reset, we expect a alarm interrupt. ++ /* In a alarm reset, we expect a alarm interrupt. + * We can do something in the interrupt handler. + * So, do not clear alarm flag. + */ @@ -7768,7 +7768,7 @@ + +static void print_rtc_time( struct rtc_time * tm ) +{ -+ printk("%02d%02d-%02d:%02d:%02d-%d\n", tm->tm_mon, tm->tm_mday, ++ printk("%02d%02d-%02d:%02d:%02d-%d\n", tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_year); + printk("sec:\t%d\n", tm->tm_sec); + printk("min:\t%d\n", tm->tm_min); @@ -7784,7 +7784,7 @@ + +static void print_rtc_registers( void ) +{ -+ while ( !__rtc_write_ready() ) ; ++ while ( !__rtc_write_ready() ) ; + printk("REG_RTC_RCR:\t 0x%8.8x\n", REG_RTC_RCR ); + printk("REG_RTC_RSR:\t 0x%8.8x\n", REG_RTC_RSR ); + printk("REG_RTC_RSAR:\t 0x%8.8x\n", REG_RTC_RSAR ); @@ -7873,7 +7873,7 @@ +#define RTC_TIMERCOUNTDOWN 0x0f + + -+/* example: !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ++/* example: !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) + * determines if the following two #defines are needed + */ +#ifndef BCD2BIN @@ -7919,7 +7919,7 @@ + * to make the epoch retain its value across module reload... + */ +static unsigned int epoch = 1900; -+static const unsigned char days_in_mo[] = ++static const unsigned char days_in_mo[] = +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +static unsigned char rtcframe[16]; @@ -7955,14 +7955,14 @@ + return v; +} + -+static void CMOS_WRITE(unsigned char addr, unsigned char val) ++static void CMOS_WRITE(unsigned char addr, unsigned char val) +{ -+ rtcframe[addr] = val; ++ rtcframe[addr] = val; +} + -+static unsigned char CMOS_READ(unsigned char addr) ++static unsigned char CMOS_READ(unsigned char addr) +{ -+ return rtcframe[addr]; ++ return rtcframe[addr]; +} + +static void get_rtc_time(struct rtc_time *rtc_tm) @@ -8009,7 +8009,7 @@ +} + +static void get_rtc_alm_time(struct rtc_time *alm_tm) -+{ ++{ + unsigned char sec, min, hour; + + /* @@ -8032,7 +8032,7 @@ +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ -+ struct rtc_time wtime; ++ struct rtc_time wtime; + switch (cmd) { + case RTC_ALM_READ: /* Read the present alarm time */ + { @@ -8043,7 +8043,7 @@ + */ + + get_rtc_alm_time(&wtime); -+ break; ++ break; + } + case RTC_ALM_SET: /* Store a time into the alarm */ + { @@ -8058,7 +8058,7 @@ + min = alm_tm.tm_min; + sec = alm_tm.tm_sec; + -+ ++ + + if (hrs >= 24) + return -EINVAL; @@ -8078,7 +8078,7 @@ + CMOS_WRITE(RTC_HOURS_ALARM, hrs | 0x80); + CMOS_WRITE(RTC_MINUTES_ALARM, min | 0x80); + -+ CMOS_WRITE(RTC_DAY_ALARM, CMOS_READ(RTC_DAY_ALARM) | 0x80); ++ CMOS_WRITE(RTC_DAY_ALARM, CMOS_READ(RTC_DAY_ALARM) | 0x80); + CMOS_WRITE(RTC_WEEKDAY_ALARM, CMOS_READ(RTC_WEEKDAY_ALARM) | 0x80); + CMOS_WRITE(RTC_STATUS, CMOS_READ(RTC_STATUS) | 0x02);/*open alarm int*/ + write_rtcframe(); @@ -8124,7 +8124,7 @@ + + if (date > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; -+ ++ + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + @@ -8149,7 +8149,7 @@ + mon = BIN2BCD(mon); + yrs = BIN2BCD(yrs); + date = BIN2BCD(date); -+ ++ + read_rtcframe(); + CMOS_WRITE(RTC_SECONDS, sec ); + CMOS_WRITE(RTC_MINUTES, min); @@ -8169,7 +8169,7 @@ + } + case RTC_EPOCH_SET: /* Set the epoch. */ + { -+ /* ++ /* + * There were no RTC clocks before 1900. + */ + if (arg < 1900) @@ -8180,7 +8180,7 @@ + + epoch = arg; + return 0; -+ } ++ } + default: + return -EINVAL; + } @@ -8276,9 +8276,9 @@ --- linux-2.6.24.7.old/drivers/i2c/busses/Kconfig 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/i2c/busses/Kconfig 2009-04-12 18:13:57.000000000 +0200 @@ -4,6 +4,14 @@ - + menu "I2C Hardware Bus support" - + +config I2C_JZ47XX + tristate "JZ47XX I2C Interface support" + depends on SOC_JZ4730 || SOC_JZ4740 @@ -8292,14 +8292,14 @@ depends on PCI --- linux-2.6.24.7.old/drivers/i2c/busses/Makefile 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/i2c/busses/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -2,6 +2,7 @@ - # Makefile for the i2c bus drivers. - # - +@@ -47,6 +47,7 @@ + obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o + obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o + obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o +obj-$(CONFIG_I2C_JZ47XX) += i2c-jz47xx.o - obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o - obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o - obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o + + # External I2C/SMBus adapter drivers + obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o --- linux-2.6.24.7.old/drivers/i2c/busses/i2c-jz47xx.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/drivers/i2c/busses/i2c-jz47xx.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,330 @@ @@ -8467,7 +8467,7 @@ + unsigned char tmpaddr; + + device = (0xa << 3) | ((sub_addr & 0x0700) >> 8); -+ sub_addr = sub_addr & 0xff; ++ sub_addr = sub_addr & 0xff; + + __i2c_send_nack(); /* Master does not send ACK, slave sends it */ + @@ -8494,7 +8494,7 @@ + sub_addr += 8; + goto start_write_page; + } -+ if (i2c_put_data(*tmpbuf) < 0) ++ if (i2c_put_data(*tmpbuf) < 0) + break; + cnt--; + tmpbuf++; @@ -8661,7 +8661,7 @@ @@ -36,8 +36,9 @@ #include #include - + +extern unsigned short sub_addr; +extern int addr_val; static struct i2c_driver i2cdev_driver; @@ -8689,7 +8689,7 @@ @@ -259,9 +259,27 @@ To compile this driver as a module, choose M here: the module will be called aaed2000_kbd. - + +config KEYBOARD_JZ + tristate "JZ keypad support" + depends on JZSOC @@ -8718,309 +8718,22 @@ to GPIO pins of various CPUs (and some other chips). @@ -272,7 +290,7 @@ with configuration data saying which GPIOs are used. - + To compile this driver as a module, choose M here: the - module will be called gpio-keys. + module will be called gpio_keys. - + config KEYBOARD_MAPLE tristate "Maple bus keyboard" --- linux-2.6.24.7.old/drivers/input/keyboard/Makefile 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/input/keyboard/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -19,6 +19,8 @@ - obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o - obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o - obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o +@@ -27,3 +27,5 @@ + obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o + obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o + obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o +obj-$(CONFIG_KEYBOARD_JZ) += jz_keypad.o +obj-$(CONFIG_5x5_KEYBOARD_JZ) += jz_keypad_5x5.o - obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o - obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o - obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o ---- linux-2.6.24.7.old/drivers/input/keyboard/gpio_keys.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/input/keyboard/gpio_keys.c 2009-04-12 18:13:57.000000000 +0200 -@@ -1,7 +1,13 @@ - /* -- * Driver for keys on GPIO lines capable of generating interrupts. -+ * linux/drivers/input/keyboard/gpio_keys.c - * -- * Copyright 2005 Phil Blundell -+ * JZ GPIO Buttons driver for JZ4740 PAVO -+ * -+ * User applications can access to this device via /dev/input/eventX. -+ * -+ * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: Richard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as -@@ -23,26 +29,131 @@ - #include - #include - #include -- - #include -+#include -+ -+ -+#define SCAN_INTERVAL (10) -+ -+/* -+ * GPIO Buttons -+ */ -+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) -+static struct gpio_keys_button pavo_buttons[] = { -+ { -+ .gpio = 96, -+ .code = KEY_1, -+ .desc = "Button 0", -+ .active_low = 1, -+ }, -+ { -+ .gpio = 97, -+ .code = KEY_2, -+ .desc = "Button 1", -+ .active_low = 1, -+ }, -+ { -+ .gpio = 98, -+ .code = KEY_3, -+ .desc = "Button 2", -+ .active_low = 1, -+ }, -+ { -+ .gpio = 99, -+ .code = KEY_4, -+ .desc = "Button 3", -+ .active_low = 1, -+ } -+}; -+ -+static struct timer_list button_timer; -+static spinlock_t gpio_lock; -+static int button_no; -+ -+static struct gpio_keys_platform_data pavo_button_data = { -+ .buttons = pavo_buttons, -+ .nbuttons = ARRAY_SIZE(pavo_buttons), -+}; -+ -+static struct platform_device pavo_button_device = { -+ .name = "gpio-keys", -+ .id = -1, -+ .num_resources = 0, -+ .dev = { -+ .platform_data = &pavo_button_data, -+ } -+}; -+ -+static void __init pavo_add_device_buttons(void) -+{ -+ __gpio_as_input(96); -+ __gpio_as_irq_fall_edge(96); -+ -+ __gpio_as_input(97); -+ __gpio_as_irq_fall_edge(97); -+ -+ __gpio_as_input(98); -+ __gpio_as_irq_fall_edge(98); -+ -+ __gpio_as_input(99); -+ __gpio_as_irq_fall_edge(99); -+ -+ platform_device_register(&pavo_button_device); -+} -+#else -+static void __init pavo_add_device_buttons(void) {} -+#endif -+ -+static void __init pavo_board_init(void) -+{ -+ /* Push Buttons */ -+ pavo_add_device_buttons(); -+} -+ -+static void button_timer_callback(unsigned long data) -+{ -+ unsigned long flags; -+ int gpio = pavo_buttons[button_no].gpio; -+ int code = pavo_buttons[button_no].code; -+ struct platform_device *pdev = (struct platform_device *)data; -+ struct input_dev *input = platform_get_drvdata(pdev); -+ int state; -+ -+ spin_lock_irqsave(&gpio_lock, flags); -+ state = __gpio_get_pin(gpio); -+ -+ if (state == 0) { -+ /* press down */ -+ input_report_key(input, code, 1); -+ input_sync(input); -+ mod_timer(&button_timer, jiffies + SCAN_INTERVAL); -+ } else { -+ /* up */ -+ input_report_key(input, code, 0); -+ input_sync(input); -+ udelay(1000); -+ __gpio_as_irq_fall_edge(gpio); -+ } -+ spin_unlock_irqrestore(&gpio_lock, flags); -+} - - static irqreturn_t gpio_keys_isr(int irq, void *dev_id) - { - int i; - struct platform_device *pdev = dev_id; - struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; -- struct input_dev *input = platform_get_drvdata(pdev); - -+ __gpio_ack_irq(irq - IRQ_GPIO_0); - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - int gpio = button->gpio; - -- if (irq == gpio_to_irq(gpio)) { -- unsigned int type = button->type ?: EV_KEY; -- int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low; -- -- input_event(input, type, button->code, !!state); -- input_sync(input); -+ if (irq == (gpio + IRQ_GPIO_0) ) { -+ /* start timer */ -+ __gpio_as_input(gpio); -+ button_no = i; -+ mod_timer(&button_timer, jiffies + 2 * SCAN_INTERVAL); -+ break; - } - } - -@@ -62,7 +173,7 @@ - - platform_set_drvdata(pdev, input); - -- input->evbit[0] = BIT_MASK(EV_KEY); -+ spin_lock_init(&gpio_lock); - - input->name = pdev->name; - input->phys = "gpio-keys/input0"; -@@ -72,56 +183,42 @@ - input->id.vendor = 0x0001; - input->id.product = 0x0001; - input->id.version = 0x0100; -+ input->evbit[0] = BIT(EV_KEY) | BIT(EV_SYN) | BIT(EV_REP); - - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - int irq; - unsigned int type = button->type ?: EV_KEY; - -- error = gpio_request(button->gpio, button->desc ?: "gpio_keys"); -- if (error < 0) { -- pr_err("gpio-keys: failed to request GPIO %d," -- " error %d\n", button->gpio, error); -- goto fail; -- } -- -- error = gpio_direction_input(button->gpio); -- if (error < 0) { -- pr_err("gpio-keys: failed to configure input" -- " direction for GPIO %d, error %d\n", -- button->gpio, error); -- gpio_free(button->gpio); -- goto fail; -- } -- -- irq = gpio_to_irq(button->gpio); -+ irq = IRQ_GPIO_0 + button->gpio; - if (irq < 0) { - error = irq; - pr_err("gpio-keys: Unable to get irq number" - " for GPIO %d, error %d\n", - button->gpio, error); -- gpio_free(button->gpio); - goto fail; - } - - error = request_irq(irq, gpio_keys_isr, -- IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING | -- IRQF_TRIGGER_FALLING, -+ IRQF_SAMPLE_RANDOM | IRQF_DISABLED, - button->desc ? button->desc : "gpio_keys", - pdev); - if (error) { - pr_err("gpio-keys: Unable to claim irq %d; error %d\n", - irq, error); -- gpio_free(button->gpio); - goto fail; - } - - if (button->wakeup) - wakeup = 1; -- - input_set_capability(input, type, button->code); - } - -+ /* Init timer */ -+ init_timer(&button_timer); -+ button_timer.data = (unsigned long)&pavo_button_device; -+ button_timer.function = button_timer_callback; -+ - error = input_register_device(input); - if (error) { - pr_err("gpio-keys: Unable to register input device, " -@@ -135,8 +232,7 @@ - - fail: - while (--i >= 0) { -- free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev); -- gpio_free(pdata->buttons[i].gpio); -+ free_irq(pdata->buttons[i].gpio + IRQ_GPIO_0 , pdev); - } - - platform_set_drvdata(pdev, NULL); -@@ -154,9 +250,8 @@ - device_init_wakeup(&pdev->dev, 0); - - for (i = 0; i < pdata->nbuttons; i++) { -- int irq = gpio_to_irq(pdata->buttons[i].gpio); -+ int irq = pdata->buttons[i].gpio + IRQ_GPIO_0; - free_irq(irq, pdev); -- gpio_free(pdata->buttons[i].gpio); - } - - input_unregister_device(input); -@@ -175,7 +270,7 @@ - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - if (button->wakeup) { -- int irq = gpio_to_irq(button->gpio); -+ int irq = button->gpio + IRQ_GPIO_0; - enable_irq_wake(irq); - } - } -@@ -193,7 +288,7 @@ - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - if (button->wakeup) { -- int irq = gpio_to_irq(button->gpio); -+ int irq = button->gpio + IRQ_GPIO_0; - disable_irq_wake(irq); - } - } -@@ -218,11 +313,13 @@ - - static int __init gpio_keys_init(void) - { -+ pavo_board_init(); - return platform_driver_register(&gpio_keys_device_driver); - } - - static void __exit gpio_keys_exit(void) - { -+ platform_device_unregister(&pavo_button_device); - platform_driver_unregister(&gpio_keys_device_driver); - } - + --- linux-2.6.24.7.old/drivers/input/keyboard/jz_keypad.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/drivers/input/keyboard/jz_keypad.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,357 @@ @@ -9080,10 +8793,10 @@ + unsigned int keycode[ARRAY_SIZE(jz_kbd_keycode)]; + struct input_dev *input; + char phys[32]; -+ ++ + spinlock_t lock; + struct timer_list timer; -+ ++ + unsigned int suspended; + unsigned long suspend_jiffies; +}; @@ -9102,7 +8815,7 @@ + __gpio_as_input(85); /* row */ + __gpio_as_input(87); /* row */ + __gpio_as_input(91); /* row */ -+ ++ + __gpio_as_input(60); /* col */ + __gpio_as_input(61); /* col */ + __gpio_as_input(62); /* col */ @@ -9152,7 +8865,7 @@ + row = 2;//k6 + col = 1; + goto find_row_col; -+ } ++ } + if (s0[0] == 7 && s0[1] == 5 && s0[2] == 7) { + row = 1;//k5 + col = 1; @@ -9241,17 +8954,17 @@ +{ + struct jz_kbd *jz_kbd = platform_get_drvdata(dev); + jz_kbd->suspended = 1; -+ ++ + return 0; +} + +static int jz_kbd_resume(struct platform_device *dev) +{ + struct jz_kbd *jz_kbd = platform_get_drvdata(dev); -+ ++ + jz_kbd->suspend_jiffies = jiffies; + jz_kbd->suspended = 0; -+ ++ + return 0; +} +#else @@ -9267,16 +8980,16 @@ + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; -+ ++ + platform_set_drvdata(dev, &g_jz_kbd); -+ ++ + strcpy(g_jz_kbd.phys, "input/kbd0"); -+ ++ + spin_lock_init(&g_jz_kbd.lock); -+ ++ + g_jz_kbd.suspend_jiffies = jiffies; + g_jz_kbd.input = input_dev; -+ ++ + input_dev->private = &g_jz_kbd; + input_dev->name = "JZ Keypad"; + input_dev->phys = g_jz_kbd.phys; @@ -9286,7 +8999,7 @@ + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; -+ ++ + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_SYN); + input_dev->keycode = g_jz_kbd.keycode; /* keycode array address */ + input_dev->keycodesize = sizeof(unsigned int); @@ -9296,9 +9009,9 @@ + + for (i = 0; i < ARRAY_SIZE(jz_kbd_keycode); i++) + set_bit(g_jz_kbd.keycode[i], input_dev->keybit); -+ ++ + //clear_bit(0, input_dev->keybit); -+ ++ + __gpio_as_input(85); + __gpio_as_input(87); + __gpio_as_input(91); @@ -9321,16 +9034,16 @@ + "error: %d\n", error); + } + printk("input: JZ Keypad Registered\n"); -+ ++ + return 0; +} + +static int jz_kbd_remove(struct platform_device *dev) +{ + struct jz_kbd *jz_kbd = platform_get_drvdata(dev); -+ ++ + del_timer_sync(&jz_kbd->timer); -+ ++ + __gpio_as_input(85); + __gpio_as_input(87); + __gpio_as_input(91); @@ -9338,7 +9051,7 @@ + /* These pins is conficting with cs8900a's CS RD WE pins on JZ4740-PAVO board */ + __gpio_as_input(60); + __gpio_as_input(61); -+ __gpio_as_input(62); ++ __gpio_as_input(62); + + input_unregister_device(jz_kbd->input); + @@ -9488,7 +9201,7 @@ +static unsigned short pre_scan_result[KB_COLS] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F}; +static unsigned short pre_col, pre_row; + -+/** ++/** + * Scan keypad by reading GPIO pins. + */ +static inline void jz_do_scan(unsigned short *s) @@ -9510,7 +9223,7 @@ + } +} + -+/** ++/** + * Call scan function and handle 'GPIO event'(like key down, key up), + * and report it to upper layer of input subsystem ... if necessary + */ @@ -9611,7 +9324,7 @@ +#define jz_kbd_resume NULL +#endif + -+/** ++/** + * Driver init + */ +static int __init jz_kbd_probe(struct platform_device *dev) @@ -9718,7 +9431,7 @@ @@ -514,6 +514,15 @@ Say Y here to build in support for the Vino video input system found on SGI Indy machines. - + +config VIDEO_JZ_CIM + tristate 'JzSOC Camera Interface Module (CIM) support' + depends on VIDEO_V4L2 @@ -9736,7 +9449,7 @@ @@ -15,6 +15,9 @@ obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o endif - + +obj-$(CONFIG_VIDEO_JZ_CIM) += jz_cim.o +obj-$(CONFIG_VIDEO_JZ_SENSOR) += jz_sensor.o + @@ -9846,7 +9559,7 @@ +struct cim_desc { + u32 nextdesc; /* Physical address of next desc */ + u32 framebuf; /* Physical address of frame buffer */ -+ u32 frameid; /* Frame ID */ ++ u32 frameid; /* Frame ID */ + u32 dmacmd; /* DMA command */ + u32 pagenum; +}; @@ -10024,7 +9737,7 @@ + dprintk("Page_list_head\n"); + desc_list_head = p_desc; + } -+ ++ + else + desc_list_tail->nextdesc = virt_to_phys(p_desc); + @@ -10039,7 +9752,7 @@ + desc_list_tail->dmacmd = ((1 << num) * 4096) >> 2 ; + } + else -+ desc_list_tail->dmacmd = ++ desc_list_tail->dmacmd = + (cim_dev->frame_size - page_nums * 4096) >> 2 ; + dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd); + page_nums += (1 << num); @@ -10051,7 +9764,7 @@ + /* stop after capturing a frame */ + desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT); + dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd); -+ ++ + return desc_list_head; +} + @@ -10086,7 +9799,7 @@ +static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static int cim_mmap(struct file *file, struct vm_area_struct *vma); + -+static struct file_operations cim_fops = ++static struct file_operations cim_fops = +{ + open: cim_open, + release: cim_release, @@ -10109,7 +9822,7 @@ + +static int cim_open(struct inode *inode, struct file *filp) +{ -+ ++ + try_module_get(THIS_MODULE); + return 0; +} @@ -10152,7 +9865,7 @@ + int img_width, img_height, img_bpp; + if (copy_from_user((void *)&i, (void *)arg, sizeof(img_param_t))) + return -EFAULT; -+#if defined(CONFIG_SOC_JZ4750) ++#if defined(CONFIG_SOC_JZ4750) + cim_image_area(&i); +#endif + img_width = i.width; @@ -10194,7 +9907,7 @@ + } + case IOCTL_TEST_CIM_RAM: + { -+ ++ + int i; + volatile unsigned int *ptr; + ptr = (volatile unsigned int *)(CIM_RAM_ADDR); @@ -10345,7 +10058,7 @@ + return ret; + } + -+ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, ++ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, + CIM_NAME, dev))) { + printk(KERN_ERR "request_irq return error, ret=%d\n", ret); + cim_fb_destroy(); @@ -10497,7 +10210,7 @@ +static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l); +static int sensor_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); + -+static struct file_operations sensor_fops = ++static struct file_operations sensor_fops = +{ + open: sensor_open, + release: sensor_release, @@ -10515,7 +10228,7 @@ +static int sensor_release(struct inode *inode, struct file *filp) +{ + module_put(THIS_MODULE); -+ return 0; ++ return 0; +} + +static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l) @@ -10617,7 +10330,7 @@ @@ -225,7 +225,11 @@ brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; - + +#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 + brq.cmd.arg = req->sector + 8192; +#else @@ -10629,11 +10342,11 @@ --- linux-2.6.24.7.old/drivers/mmc/core/mmc.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/mmc/core/mmc.c 2009-04-12 18:13:57.000000000 +0200 @@ -141,8 +141,13 @@ - + e = UNSTUFF_BITS(resp, 47, 3); m = UNSTUFF_BITS(resp, 62, 12); - csd->capacity = (1 + m) << (e + 2); - + +#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 + csd->capacity = (1 + m) << (e + 2); + csd->capacity -= 8192; @@ -10649,20 +10362,20 @@ goto free_card; - - mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); -+ ++ + /* all mmc v4 support 8 bit mmc card */ + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_8); } - + if (!oldcard) --- linux-2.6.24.7.old/drivers/mmc/core/sd.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/mmc/core/sd.c 2009-04-12 18:13:57.000000000 +0200 @@ -110,8 +110,13 @@ - + e = UNSTUFF_BITS(resp, 47, 3); m = UNSTUFF_BITS(resp, 62, 12); - csd->capacity = (1 + m) << (e + 2); - + +#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 + csd->capacity = (1 + m) << (e + 2); + csd->capacity -= 8192; @@ -10674,10 +10387,10 @@ csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); @@ -138,8 +143,13 @@ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); - + m = UNSTUFF_BITS(resp, 48, 22); - csd->capacity = (1 + m) << 10; - + +#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 + csd->capacity = (1 + m) << 10; + csd->capacity -= 8192; @@ -10689,7 +10402,7 @@ csd->write_misalign = 0; @@ -269,9 +279,11 @@ goto out; - + if ((status[16] & 0xF) != 1) { +#if 0 printk(KERN_WARNING "%s: Problem switching card " @@ -10701,20 +10414,20 @@ mmc_set_timing(card->host, MMC_TIMING_SD_HS); @@ -386,6 +398,9 @@ goto free_card; - + mmc_decode_cid(card); + + /* set 24MHz clock again, why?? */ + mmc_set_clock(host, 24000000); } - + /* --- linux-2.6.24.7.old/drivers/mmc/host/Kconfig 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/mmc/host/Kconfig 2009-04-12 18:13:57.000000000 +0200 @@ -4,6 +4,104 @@ - + comment "MMC/SD Host Controller Drivers" - + +config MMC_JZ + tristate "JZ SD/Multimedia Card Interface support" + depends on SOC_JZ4730 || SOC_JZ4740 @@ -10821,7 +10534,7 @@ @@ -6,6 +6,9 @@ EXTRA_CFLAGS += -DDEBUG endif - + +obj-$(CONFIG_MMC_JZ) += jz_mmc.o +obj-$(CONFIG_MSC0_JZ4750) += jz4750_mmc.o +obj-$(CONFIG_MSC1_JZ4750) += jz4750_mmc.o @@ -10868,7 +10581,7 @@ + +#define DRIVER_NAME "jz-mmc" + -+#define USE_DMA ++#define USE_DMA + +static int r_type = 0; +static int rxdmachan = 0; @@ -11097,7 +10810,7 @@ + while (REG_MSC_STAT(MSC_ID) & MSC_STAT_DATA_FIFO_EMPTY) + ; + *buf++ = REG_MSC_RXFIFO(MSC_ID); -+ } ++ } + host->pio.len -= count; + host->pio.offset += count; + @@ -11218,7 +10931,7 @@ +#ifdef CONFIG_JZ4750_MSC0_BUS_1 + if (cmd->opcode == 6) { + /* set 1 bit sd card bus*/ -+ if (cmd->arg ==2) ++ if (cmd->arg ==2) + REG_MSC_ARG(MSC_ID) = 0; + + /* set 1 bit mmc card bus*/ @@ -11231,21 +10944,21 @@ +#elif defined CONFIG_JZ4750_MSC0_BUS_8 + if (cmd->opcode == 6) { + /* set 8 bit mmc card bus*/ -+ if (cmd->arg == 0x3b70101) ++ if (cmd->arg == 0x3b70101) + REG_MSC_ARG(MSC_ID) = 0x3b70201; + else + REG_MSC_ARG(MSC_ID) = cmd->arg; -+ ++ + } else + REG_MSC_ARG(MSC_ID) = cmd->arg; +#else + REG_MSC_ARG(MSC_ID) = cmd->arg; +#endif /* CONFIG_JZ4750_MSC0_BUS_1 */ -+#else ++#else +#ifdef CONFIG_JZ4750_MSC1_BUS_1 + if (cmd->opcode == 6) { + /* set 1 bit sd card bus*/ -+ if (cmd->arg ==2) ++ if (cmd->arg ==2) + REG_MSC_ARG(MSC_ID) = 0; + + /* set 1 bit mmc card bus*/ @@ -11285,7 +10998,7 @@ + } + + if (SD_IO_SEND_OP_COND == cmd->opcode) { -+ /* ++ /* + * Don't support SDIO card currently. + */ + cmd->error = -ETIMEDOUT; @@ -11302,7 +11015,7 @@ + jz_mmc_tx_setup_data(host, host->data); +#else + jz_mmc_send_pio(host); -+ else ++ else + jz_mmc_receive_pio(host); +#endif + } @@ -11439,16 +11152,16 @@ + else { +#ifdef CONFIG_MSC0_JZ4750 +#ifdef CONFIG_JZ4750_MSC0_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; + cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | + MSC_CMDAT_DMA_EN; +#elif defined CONFIG_JZ4750_MSC0_BUS_4 + if(auto_select_bus == MSC_1BIT_BUS) { -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; + cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | + MSC_CMDAT_DMA_EN; + } else { -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; + cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT | MSC_CMDAT_DATA_EN | + MSC_CMDAT_DMA_EN; + } @@ -11457,7 +11170,7 @@ +#endif /* CONFIG_JZ4750_MSC0_BUS_1 */ +#else +#ifdef CONFIG_JZ4750_MSC1_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; + cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | + MSC_CMDAT_DMA_EN; +#else @@ -11480,22 +11193,22 @@ + else { +#ifdef CONFIG_MSC0_JZ4750 +#ifdef CONFIG_JZ4750_MSC0_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; + cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; +#elif defined CONFIG_JZ4750_MSC0_BUS_4 + if(auto_select_bus == MSC_1BIT_BUS) { -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; -+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; + } else { -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; + cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT | MSC_CMDAT_DATA_EN; + } +#else + cmdat |= MSC_CMDAT_DATA_EN; +#endif -+#else ++#else +#ifdef CONFIG_JZ4750_MSC1_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; + cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; +#else + cmdat |= MSC_CMDAT_DATA_EN; @@ -11608,11 +11321,11 @@ + host->cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT; + } + else if (ios->bus_width == MMC_BUS_WIDTH_8) { -+ host->cmdat |= MSC_CMDAT_BUS_WIDTH_8BIT; ++ host->cmdat |= MSC_CMDAT_BUS_WIDTH_8BIT; + auto_select_bus = MSC_8BIT_BUS; + } else { + /* 1 bit bus*/ -+ host->cmdat &= ~MSC_CMDAT_BUS_WIDTH_8BIT; ++ host->cmdat &= ~MSC_CMDAT_BUS_WIDTH_8BIT; + auto_select_bus = MSC_1BIT_BUS; + } +} @@ -11689,7 +11402,7 @@ + MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SD_HIGHSPEED + | MMC_CAP_MMC_HIGHSPEED; + /* -+ *MMC_CAP_4_BIT_DATA (1 << 0) The host can do 4 bit transfers ++ *MMC_CAP_4_BIT_DATA (1 << 0) The host can do 4 bit transfers + * + */ + host->sg_cpu = @@ -11836,7 +11549,7 @@ +static int jz_mmc_pm_callback(struct pm_dev *pm_dev, + pm_request_t req, void *data) +{ -+ struct platform_device *pdev = (struct platform_device *)pm_dev; ++ struct platform_device *pdev = (struct platform_device *)pm_dev; + + switch(req) { + case PM_RESUME: @@ -11892,7 +11605,7 @@ +#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */ +#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */ +#define SD_CLOCK_HIGH 24000000 /* 24 MHz for SD Cards */ -+#define MMC_NO_ERROR 0 ++#define MMC_NO_ERROR 0 + +#define NR_SG 1 + @@ -12018,7 +11731,7 @@ +#if defined(CONFIG_SOC_JZ4725) || defined(CONFIG_SOC_JZ4720) +#undef USE_DMA +#else -+#define USE_DMA ++#define USE_DMA +#endif + +struct jz_mmc_host { @@ -12283,7 +11996,7 @@ + while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY) + ; + *buf++ = REG_MSC_RXFIFO; -+ } ++ } + host->pio.len -= count; + host->pio.offset += count; + @@ -12406,7 +12119,7 @@ +#ifdef CONFIG_JZ_MMC_BUS_1 + if (cmd->opcode == 6) { + /* set 1 bit sd card bus*/ -+ if (cmd->arg ==2) ++ if (cmd->arg ==2) + REG_MSC_ARG = 0; + + /* set 1 bit mmc card bus*/ @@ -12443,7 +12156,7 @@ + } + + if (SD_IO_SEND_OP_COND == cmd->opcode) { -+ /* ++ /* + * Don't support SDIO card currently. + */ + cmd->error = -ETIMEDOUT; @@ -12460,7 +12173,7 @@ + jz_mmc_tx_setup_data(host, host->data); +#else + jz_mmc_send_pio(host); -+ else ++ else + jz_mmc_receive_pio(host); +#endif + } @@ -12601,7 +12314,7 @@ + MSC_CMDAT_DMA_EN; + else { +#ifdef CONFIG_JZ_MMC_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT; ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT; + cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | + MSC_CMDAT_DMA_EN; +#else @@ -12622,7 +12335,7 @@ + cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; + else { +#ifdef CONFIG_JZ_MMC_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT; ++ cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT; + cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; +#else + cmdat |= MSC_CMDAT_DATA_EN; @@ -12722,9 +12435,9 @@ + host->cmdat |= CMDAT_INIT; + } + -+ if ((ios->bus_width == MMC_BUS_WIDTH_4) || (ios->bus_width == MMC_BUS_WIDTH_8)) ++ if ((ios->bus_width == MMC_BUS_WIDTH_4) || (ios->bus_width == MMC_BUS_WIDTH_8)) + host->cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT; -+ else ++ else + host->cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT; +} + @@ -12798,7 +12511,7 @@ + MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SD_HIGHSPEED + | MMC_CAP_MMC_HIGHSPEED; + /* -+ *MMC_CAP_4_BIT_DATA (1 << 0) The host can do 4 bit transfers ++ *MMC_CAP_4_BIT_DATA (1 << 0) The host can do 4 bit transfers + * + */ + host->sg_cpu = @@ -12932,13 +12645,13 @@ + /*for sandisk BB0807011816D and other strange cards*/ + int i; + -+ for(i = 104; i < 110; i++) -+ __gpio_as_input(i); ++ for(i = 104; i < 110; i++) ++ __gpio_as_input(i); + + /* perhaps you should mdelay more */ + mdelay(1000); + __gpio_as_msc(); -+#endif ++#endif + __msc_init_io(); + __msc_enable_power(); + __msc_reset(); @@ -12956,7 +12669,7 @@ +static int jz_mmc_pm_callback(struct pm_dev *pm_dev, + pm_request_t req, void *data) +{ -+ struct platform_device *pdev = (struct platform_device *)pm_dev->data; ++ struct platform_device *pdev = (struct platform_device *)pm_dev->data; + + switch(req) { + case PM_RESUME: @@ -13011,11 +12724,11 @@ +#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */ +#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */ +#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */ -+#define MMC_NO_ERROR 0 ++#define MMC_NO_ERROR 0 +/* Extra MMC commands for state control */ +/* Use negative numbers to disambiguate */ +#define MMC_CIM_RESET -1 -+#define MMC_SET_CLOCK 100 ++#define MMC_SET_CLOCK 100 + +typedef struct jzsoc_dma_desc { + volatile u32 ddadr; /* Points to the next descriptor + flags */ @@ -13070,55791 +12783,15 @@ + + +#endif /* __JZ_MMC_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -3,9 +3,9 @@ - # - - # Core functionality. --obj-$(CONFIG_MTD) += mtd.o - mtd-y := mtdcore.o mtdsuper.o - mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o -+obj-$(CONFIG_MTD) += $(mtd-y) - - obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o - obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o -@@ -15,14 +15,15 @@ - # 'Users' - code which presents functionality to userspace. - obj-$(CONFIG_MTD_CHAR) += mtdchar.o - obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o --obj-$(CONFIG_MTD_BLOCK) += mtdblock.o -+#obj-$(CONFIG_MTD_BLOCK) += mtdblock.o -+obj-$(CONFIG_MTD_BLOCK) += mtdblock-jz.o -+obj-$(CONFIG_UDC_USE_LB_CACHE) += udc_cache.o - obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o - obj-$(CONFIG_FTL) += ftl.o - obj-$(CONFIG_NFTL) += nftl.o - obj-$(CONFIG_INFTL) += inftl.o - obj-$(CONFIG_RFD_FTL) += rfd_ftl.o - obj-$(CONFIG_SSFDC) += ssfdc.o --obj-$(CONFIG_MTD_OOPS) += mtdoops.o - - nftl-objs := nftlcore.o nftlmount.o - inftl-objs := inftlcore.o inftlmount.o -@@ -30,3 +31,6 @@ - obj-y += chips/ maps/ devices/ nand/ onenand/ - - obj-$(CONFIG_MTD_UBI) += ubi/ -+ -+$(obj)/mtdblock-jz.o: $(obj)/mtdblock-jz.uu -+ uudecode $(obj)/mtdblock-jz.uu -o $(obj)/mtdblock-jz.o -\ No newline at end of file ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/HEAD 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/HEAD 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+ref: refs/heads/master ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/config 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/config 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,11 @@ -+[core] -+ repositoryformatversion = 0 -+ filemode = true -+ bare = false -+ logallrefupdates = true -+[remote "origin"] -+ url = git://git.infradead.org/mtd-utils.git -+ fetch = +refs/heads/*:refs/remotes/origin/* -+[branch "master"] -+ remote = origin -+ merge = refs/heads/master ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/description 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/description 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+Unnamed repository; edit this file to name it for gitweb. ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/applypatch-msg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/applypatch-msg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,15 @@ -+#!/bin/sh -+# -+# An example hook script to check the commit log message taken by -+# applypatch from an e-mail message. -+# -+# The hook should exit with non-zero status after issuing an -+# appropriate message if it wants to stop the commit. The hook is -+# allowed to edit the commit message file. -+# -+# To enable this hook, make this file executable. -+ -+. git-sh-setup -+test -x "$GIT_DIR/hooks/commit-msg" && -+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} -+: ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/commit-msg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/commit-msg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,24 @@ -+#!/bin/sh -+# -+# An example hook script to check the commit log message. -+# Called by git-commit with one argument, the name of the file -+# that has the commit message. The hook should exit with non-zero -+# status after issuing an appropriate message if it wants to stop the -+# commit. The hook is allowed to edit the commit message file. -+# -+# To enable this hook, make this file executable. -+ -+# Uncomment the below to add a Signed-off-by line to the message. -+# Doing this in a hook is a bad idea in general, but the prepare-commit-msg -+# hook is more suited to it. -+# -+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" -+ -+# This example catches duplicate Signed-off-by lines. -+ -+test "" = "$(grep '^Signed-off-by: ' "$1" | -+ sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { -+ echo >&2 Duplicate Signed-off-by lines. -+ exit 1 -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/post-commit 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/post-commit 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,8 @@ -+#!/bin/sh -+# -+# An example hook script that is called after a successful -+# commit is made. -+# -+# To enable this hook, make this file executable. -+ -+: Nothing ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/post-receive 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/post-receive 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,16 @@ -+#!/bin/sh -+# -+# An example hook script for the post-receive event -+# -+# This script is run after receive-pack has accepted a pack and the -+# repository has been updated. It is passed arguments in through stdin -+# in the form -+# -+# For example: -+# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master -+# -+# see contrib/hooks/ for an sample, or uncomment the next line (on debian) -+# -+ -+ -+#. /usr/share/doc/git-core/contrib/hooks/post-receive-email ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/post-update 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/post-update 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,8 @@ -+#!/bin/sh -+# -+# An example hook script to prepare a packed repository for use over -+# dumb transports. -+# -+# To enable this hook, make this file executable by "chmod +x post-update". -+ -+exec git-update-server-info ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/pre-applypatch 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/pre-applypatch 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,14 @@ -+#!/bin/sh -+# -+# An example hook script to verify what is about to be committed -+# by applypatch from an e-mail message. -+# -+# The hook should exit with non-zero status after issuing an -+# appropriate message if it wants to stop the commit. -+# -+# To enable this hook, make this file executable. -+ -+. git-sh-setup -+test -x "$GIT_DIR/hooks/pre-commit" && -+ exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} -+: ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/pre-commit 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/pre-commit 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,70 @@ -+#!/bin/sh -+# -+# An example hook script to verify what is about to be committed. -+# Called by git-commit with no arguments. The hook should -+# exit with non-zero status after issuing an appropriate message if -+# it wants to stop the commit. -+# -+# To enable this hook, make this file executable. -+ -+# This is slightly modified from Andrew Morton's Perfect Patch. -+# Lines you introduce should not have trailing whitespace. -+# Also check for an indentation that has SP before a TAB. -+ -+if git-rev-parse --verify HEAD 2>/dev/null -+then -+ git-diff-index -p -M --cached HEAD -- -+else -+ # NEEDSWORK: we should produce a diff with an empty tree here -+ # if we want to do the same verification for the initial import. -+ : -+fi | -+perl -e ' -+ my $found_bad = 0; -+ my $filename; -+ my $reported_filename = ""; -+ my $lineno; -+ sub bad_line { -+ my ($why, $line) = @_; -+ if (!$found_bad) { -+ print STDERR "*\n"; -+ print STDERR "* You have some suspicious patch lines:\n"; -+ print STDERR "*\n"; -+ $found_bad = 1; -+ } -+ if ($reported_filename ne $filename) { -+ print STDERR "* In $filename\n"; -+ $reported_filename = $filename; -+ } -+ print STDERR "* $why (line $lineno)\n"; -+ print STDERR "$filename:$lineno:$line\n"; -+ } -+ while (<>) { -+ if (m|^diff --git a/(.*) b/\1$|) { -+ $filename = $1; -+ next; -+ } -+ if (/^@@ -\S+ \+(\d+)/) { -+ $lineno = $1 - 1; -+ next; -+ } -+ if (/^ /) { -+ $lineno++; -+ next; -+ } -+ if (s/^\+//) { -+ $lineno++; -+ chomp; -+ if (/\s$/) { -+ bad_line("trailing whitespace", $_); -+ } -+ if (/^\s* \t/) { -+ bad_line("indent SP followed by a TAB", $_); -+ } -+ if (/^([<>])\1{6} |^={7}$/) { -+ bad_line("unresolved merge conflict", $_); -+ } -+ } -+ } -+ exit($found_bad); -+' ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/pre-rebase 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/pre-rebase 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,150 @@ -+#!/bin/sh -+# -+# Copyright (c) 2006 Junio C Hamano -+# -+ -+publish=next -+basebranch="$1" -+if test "$#" = 2 -+then -+ topic="refs/heads/$2" -+else -+ topic=`git symbolic-ref HEAD` -+fi -+ -+case "$basebranch,$topic" in -+master,refs/heads/??/*) -+ ;; -+*) -+ exit 0 ;# we do not interrupt others. -+ ;; -+esac -+ -+# Now we are dealing with a topic branch being rebased -+# on top of master. Is it OK to rebase it? -+ -+# Is topic fully merged to master? -+not_in_master=`git-rev-list --pretty=oneline ^master "$topic"` -+if test -z "$not_in_master" -+then -+ echo >&2 "$topic is fully merged to master; better remove it." -+ exit 1 ;# we could allow it, but there is no point. -+fi -+ -+# Is topic ever merged to next? If so you should not be rebasing it. -+only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort` -+only_next_2=`git-rev-list ^master ${publish} | sort` -+if test "$only_next_1" = "$only_next_2" -+then -+ not_in_topic=`git-rev-list "^$topic" master` -+ if test -z "$not_in_topic" -+ then -+ echo >&2 "$topic is already up-to-date with master" -+ exit 1 ;# we could allow it, but there is no point. -+ else -+ exit 0 -+ fi -+else -+ not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"` -+ perl -e ' -+ my $topic = $ARGV[0]; -+ my $msg = "* $topic has commits already merged to public branch:\n"; -+ my (%not_in_next) = map { -+ /^([0-9a-f]+) /; -+ ($1 => 1); -+ } split(/\n/, $ARGV[1]); -+ for my $elem (map { -+ /^([0-9a-f]+) (.*)$/; -+ [$1 => $2]; -+ } split(/\n/, $ARGV[2])) { -+ if (!exists $not_in_next{$elem->[0]}) { -+ if ($msg) { -+ print STDERR $msg; -+ undef $msg; -+ } -+ print STDERR " $elem->[1]\n"; -+ } -+ } -+ ' "$topic" "$not_in_next" "$not_in_master" -+ exit 1 -+fi -+ -+exit 0 -+ -+################################################################ -+ -+This sample hook safeguards topic branches that have been -+published from being rewound. -+ -+The workflow assumed here is: -+ -+ * Once a topic branch forks from "master", "master" is never -+ merged into it again (either directly or indirectly). -+ -+ * Once a topic branch is fully cooked and merged into "master", -+ it is deleted. If you need to build on top of it to correct -+ earlier mistakes, a new topic branch is created by forking at -+ the tip of the "master". This is not strictly necessary, but -+ it makes it easier to keep your history simple. -+ -+ * Whenever you need to test or publish your changes to topic -+ branches, merge them into "next" branch. -+ -+The script, being an example, hardcodes the publish branch name -+to be "next", but it is trivial to make it configurable via -+$GIT_DIR/config mechanism. -+ -+With this workflow, you would want to know: -+ -+(1) ... if a topic branch has ever been merged to "next". Young -+ topic branches can have stupid mistakes you would rather -+ clean up before publishing, and things that have not been -+ merged into other branches can be easily rebased without -+ affecting other people. But once it is published, you would -+ not want to rewind it. -+ -+(2) ... if a topic branch has been fully merged to "master". -+ Then you can delete it. More importantly, you should not -+ build on top of it -- other people may already want to -+ change things related to the topic as patches against your -+ "master", so if you need further changes, it is better to -+ fork the topic (perhaps with the same name) afresh from the -+ tip of "master". -+ -+Let's look at this example: -+ -+ o---o---o---o---o---o---o---o---o---o "next" -+ / / / / -+ / a---a---b A / / -+ / / / / -+ / / c---c---c---c B / -+ / / / \ / -+ / / / b---b C \ / -+ / / / / \ / -+ ---o---o---o---o---o---o---o---o---o---o---o "master" -+ -+ -+A, B and C are topic branches. -+ -+ * A has one fix since it was merged up to "next". -+ -+ * B has finished. It has been fully merged up to "master" and "next", -+ and is ready to be deleted. -+ -+ * C has not merged to "next" at all. -+ -+We would want to allow C to be rebased, refuse A, and encourage -+B to be deleted. -+ -+To compute (1): -+ -+ git-rev-list ^master ^topic next -+ git-rev-list ^master next -+ -+ if these match, topic has not merged in next at all. -+ -+To compute (2): -+ -+ git-rev-list master..topic -+ -+ if this is empty, it is fully merged to "master". ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/prepare-commit-msg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/prepare-commit-msg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,36 @@ -+#!/bin/sh -+# -+# An example hook script to prepare the commit log message. -+# Called by git-commit with the name of the file that has the -+# commit message, followed by the description of the commit -+# message's source. The hook's purpose is to edit the commit -+# message file. If the hook fails with a non-zero status, -+# the commit is aborted. -+# -+# To enable this hook, make this file executable. -+ -+# This hook includes three examples. The first comments out the -+# "Conflicts:" part of a merge commit. -+# -+# The second includes the output of "git diff --name-status -r" -+# into the message, just before the "git status" output. It is -+# commented because it doesn't cope with --amend or with squashed -+# commits. -+# -+# The third example adds a Signed-off-by line to the message, that can -+# still be edited. This is rarely a good idea. -+ -+case "$2 $3" in -+ merge) -+ sed -i '/^Conflicts:/,/#/!b;s/^/# &/;s/^# #/#/' "$1" ;; -+ -+# ""|template) -+# perl -i -pe ' -+# print "\n" . `git diff --cached --name-status -r` -+# if /^#/ && $first++ == 0' "$1" ;; -+ -+ *) ;; -+esac -+ -+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/update 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/update 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,107 @@ -+#!/bin/sh -+# -+# An example hook script to blocks unannotated tags from entering. -+# Called by git-receive-pack with arguments: refname sha1-old sha1-new -+# -+# To enable this hook, make this file executable by "chmod +x update". -+# -+# Config -+# ------ -+# hooks.allowunannotated -+# This boolean sets whether unannotated tags will be allowed into the -+# repository. By default they won't be. -+# hooks.allowdeletetag -+# This boolean sets whether deleting tags will be allowed in the -+# repository. By default they won't be. -+# hooks.allowdeletebranch -+# This boolean sets whether deleting branches will be allowed in the -+# repository. By default they won't be. -+# -+ -+# --- Command line -+refname="$1" -+oldrev="$2" -+newrev="$3" -+ -+# --- Safety check -+if [ -z "$GIT_DIR" ]; then -+ echo "Don't run this script from the command line." >&2 -+ echo " (if you want, you could supply GIT_DIR then run" >&2 -+ echo " $0 )" >&2 -+ exit 1 -+fi -+ -+if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then -+ echo "Usage: $0 " >&2 -+ exit 1 -+fi -+ -+# --- Config -+allowunannotated=$(git config --bool hooks.allowunannotated) -+allowdeletebranch=$(git config --bool hooks.allowdeletebranch) -+allowdeletetag=$(git config --bool hooks.allowdeletetag) -+ -+# check for no description -+projectdesc=$(sed -e '1q' "$GIT_DIR/description") -+if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb." ]; then -+ echo "*** Project description file hasn't been set" >&2 -+ exit 1 -+fi -+ -+# --- Check types -+# if $newrev is 0000...0000, it's a commit to delete a ref. -+if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then -+ newrev_type=delete -+else -+ newrev_type=$(git-cat-file -t $newrev) -+fi -+ -+case "$refname","$newrev_type" in -+ refs/tags/*,commit) -+ # un-annotated tag -+ short_refname=${refname##refs/tags/} -+ if [ "$allowunannotated" != "true" ]; then -+ echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 -+ echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 -+ exit 1 -+ fi -+ ;; -+ refs/tags/*,delete) -+ # delete tag -+ if [ "$allowdeletetag" != "true" ]; then -+ echo "*** Deleting a tag is not allowed in this repository" >&2 -+ exit 1 -+ fi -+ ;; -+ refs/tags/*,tag) -+ # annotated tag -+ ;; -+ refs/heads/*,commit) -+ # branch -+ ;; -+ refs/heads/*,delete) -+ # delete branch -+ if [ "$allowdeletebranch" != "true" ]; then -+ echo "*** Deleting a branch is not allowed in this repository" >&2 -+ exit 1 -+ fi -+ ;; -+ refs/remotes/*,commit) -+ # tracking branch -+ ;; -+ refs/remotes/*,delete) -+ # delete tracking branch -+ if [ "$allowdeletebranch" != "true" ]; then -+ echo "*** Deleting a tracking branch is not allowed in this repository" >&2 -+ exit 1 -+ fi -+ ;; -+ *) -+ # Anything else (is there anything else?) -+ echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 -+ exit 1 -+ ;; -+esac -+ -+# --- Finished -+exit 0 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/info/exclude 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/info/exclude 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,6 @@ -+# git-ls-files --others --exclude-from=.git/info/exclude -+# Lines that start with '#' are comments. -+# For a project mostly in C, the following would be a good set of -+# exclude patterns (uncomment them if you want to use them): -+# *.[oa] -+# *~ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/HEAD 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/HEAD 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 d5f5e57b72289bb5f551a4e17be0132aa8dfb6c4 nancy 1210143725 +0800 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/heads/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/heads/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 d5f5e57b72289bb5f551a4e17be0132aa8dfb6c4 nancy 1210143725 +0800 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 d5f5e57b72289bb5f551a4e17be0132aa8dfb6c4 nancy 1210143724 +0800 clone: from git://git.infradead.org/mtd-utils.git ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/origin 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/origin 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 7afca4241e082c23bb38a4da532cc222457ae719 nancy 1210143724 +0800 clone: from git://git.infradead.org/mtd-utils.git ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/ubi 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/ubi 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 22f90673165489fd50c893a91051a79c1b143d2a nancy 1210143724 +0800 clone: from git://git.infradead.org/mtd-utils.git ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/objects/pack/pack-3aac9dd611b9d9b1367a74ba6217f301d746b650.keep 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/objects/pack/pack-3aac9dd611b9d9b1367a74ba6217f301d746b650.keep 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+fetch-pack 10055 on bogon ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/heads/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/heads/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+d5f5e57b72289bb5f551a4e17be0132aa8dfb6c4 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/HEAD 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/HEAD 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+ref: refs/remotes/origin/master ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+d5f5e57b72289bb5f551a4e17be0132aa8dfb6c4 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/origin 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/origin 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+7afca4241e082c23bb38a4da532cc222457ae719 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/ubi 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/ubi 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+22f90673165489fd50c893a91051a79c1b143d2a ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.gitignore 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.gitignore 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,26 @@ -+# -+# NOTE! Don't add files that are generated in specific -+# subdirectories here. Add them in the ".gitignore" file -+# in that subdirectory instead. -+# -+# Normal rules -+# -+.* -+*.o -+*.a -+*.s -+*.ko -+*.so -+*.mod.c -+*~ -+ -+# -+# Top-level generic files -+# -+ -+# -+# Generated include files -+# -+ -+# stgit generated dirs -+patches-* ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/COPYING 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/COPYING 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,340 @@ -+ GNU GENERAL PUBLIC LICENSE -+ Version 2, June 1991 -+ -+ Copyright (C) 1989, 1991 Free Software Foundation, Inc. -+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ Everyone is permitted to copy and distribute verbatim copies -+ of this license document, but changing it is not allowed. -+ -+ Preamble -+ -+ The licenses for most software are designed to take away your -+freedom to share and change it. By contrast, the GNU General Public -+License is intended to guarantee your freedom to share and change free -+software--to make sure the software is free for all its users. This -+General Public License applies to most of the Free Software -+Foundation's software and to any other program whose authors commit to -+using it. (Some other Free Software Foundation software is covered by -+the GNU Library General Public License instead.) You can apply it to -+your programs, too. -+ -+ When we speak of free software, we are referring to freedom, not -+price. Our General Public Licenses are designed to make sure that you -+have the freedom to distribute copies of free software (and charge for -+this service if you wish), that you receive source code or can get it -+if you want it, that you can change the software or use pieces of it -+in new free programs; and that you know you can do these things. -+ -+ To protect your rights, we need to make restrictions that forbid -+anyone to deny you these rights or to ask you to surrender the rights. -+These restrictions translate to certain responsibilities for you if you -+distribute copies of the software, or if you modify it. -+ -+ For example, if you distribute copies of such a program, whether -+gratis or for a fee, you must give the recipients all the rights that -+you have. You must make sure that they, too, receive or can get the -+source code. And you must show them these terms so they know their -+rights. -+ -+ We protect your rights with two steps: (1) copyright the software, and -+(2) offer you this license which gives you legal permission to copy, -+distribute and/or modify the software. -+ -+ Also, for each author's protection and ours, we want to make certain -+that everyone understands that there is no warranty for this free -+software. If the software is modified by someone else and passed on, we -+want its recipients to know that what they have is not the original, so -+that any problems introduced by others will not reflect on the original -+authors' reputations. -+ -+ Finally, any free program is threatened constantly by software -+patents. We wish to avoid the danger that redistributors of a free -+program will individually obtain patent licenses, in effect making the -+program proprietary. To prevent this, we have made it clear that any -+patent must be licensed for everyone's free use or not licensed at all. -+ -+ The precise terms and conditions for copying, distribution and -+modification follow. -+ -+ GNU GENERAL PUBLIC LICENSE -+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -+ -+ 0. This License applies to any program or other work which contains -+a notice placed by the copyright holder saying it may be distributed -+under the terms of this General Public License. The "Program", below, -+refers to any such program or work, and a "work based on the Program" -+means either the Program or any derivative work under copyright law: -+that is to say, a work containing the Program or a portion of it, -+either verbatim or with modifications and/or translated into another -+language. (Hereinafter, translation is included without limitation in -+the term "modification".) Each licensee is addressed as "you". -+ -+Activities other than copying, distribution and modification are not -+covered by this License; they are outside its scope. The act of -+running the Program is not restricted, and the output from the Program -+is covered only if its contents constitute a work based on the -+Program (independent of having been made by running the Program). -+Whether that is true depends on what the Program does. -+ -+ 1. You may copy and distribute verbatim copies of the Program's -+source code as you receive it, in any medium, provided that you -+conspicuously and appropriately publish on each copy an appropriate -+copyright notice and disclaimer of warranty; keep intact all the -+notices that refer to this License and to the absence of any warranty; -+and give any other recipients of the Program a copy of this License -+along with the Program. -+ -+You may charge a fee for the physical act of transferring a copy, and -+you may at your option offer warranty protection in exchange for a fee. -+ -+ 2. You may modify your copy or copies of the Program or any portion -+of it, thus forming a work based on the Program, and copy and -+distribute such modifications or work under the terms of Section 1 -+above, provided that you also meet all of these conditions: -+ -+ a) You must cause the modified files to carry prominent notices -+ stating that you changed the files and the date of any change. -+ -+ b) You must cause any work that you distribute or publish, that in -+ whole or in part contains or is derived from the Program or any -+ part thereof, to be licensed as a whole at no charge to all third -+ parties under the terms of this License. -+ -+ c) If the modified program normally reads commands interactively -+ when run, you must cause it, when started running for such -+ interactive use in the most ordinary way, to print or display an -+ announcement including an appropriate copyright notice and a -+ notice that there is no warranty (or else, saying that you provide -+ a warranty) and that users may redistribute the program under -+ these conditions, and telling the user how to view a copy of this -+ License. (Exception: if the Program itself is interactive but -+ does not normally print such an announcement, your work based on -+ the Program is not required to print an announcement.) -+ -+These requirements apply to the modified work as a whole. If -+identifiable sections of that work are not derived from the Program, -+and can be reasonably considered independent and separate works in -+themselves, then this License, and its terms, do not apply to those -+sections when you distribute them as separate works. But when you -+distribute the same sections as part of a whole which is a work based -+on the Program, the distribution of the whole must be on the terms of -+this License, whose permissions for other licensees extend to the -+entire whole, and thus to each and every part regardless of who wrote it. -+ -+Thus, it is not the intent of this section to claim rights or contest -+your rights to work written entirely by you; rather, the intent is to -+exercise the right to control the distribution of derivative or -+collective works based on the Program. -+ -+In addition, mere aggregation of another work not based on the Program -+with the Program (or with a work based on the Program) on a volume of -+a storage or distribution medium does not bring the other work under -+the scope of this License. -+ -+ 3. You may copy and distribute the Program (or a work based on it, -+under Section 2) in object code or executable form under the terms of -+Sections 1 and 2 above provided that you also do one of the following: -+ -+ a) Accompany it with the complete corresponding machine-readable -+ source code, which must be distributed under the terms of Sections -+ 1 and 2 above on a medium customarily used for software interchange; or, -+ -+ b) Accompany it with a written offer, valid for at least three -+ years, to give any third party, for a charge no more than your -+ cost of physically performing source distribution, a complete -+ machine-readable copy of the corresponding source code, to be -+ distributed under the terms of Sections 1 and 2 above on a medium -+ customarily used for software interchange; or, -+ -+ c) Accompany it with the information you received as to the offer -+ to distribute corresponding source code. (This alternative is -+ allowed only for noncommercial distribution and only if you -+ received the program in object code or executable form with such -+ an offer, in accord with Subsection b above.) -+ -+The source code for a work means the preferred form of the work for -+making modifications to it. For an executable work, complete source -+code means all the source code for all modules it contains, plus any -+associated interface definition files, plus the scripts used to -+control compilation and installation of the executable. However, as a -+special exception, the source code distributed need not include -+anything that is normally distributed (in either source or binary -+form) with the major components (compiler, kernel, and so on) of the -+operating system on which the executable runs, unless that component -+itself accompanies the executable. -+ -+If distribution of executable or object code is made by offering -+access to copy from a designated place, then offering equivalent -+access to copy the source code from the same place counts as -+distribution of the source code, even though third parties are not -+compelled to copy the source along with the object code. -+ -+ 4. You may not copy, modify, sublicense, or distribute the Program -+except as expressly provided under this License. Any attempt -+otherwise to copy, modify, sublicense or distribute the Program is -+void, and will automatically terminate your rights under this License. -+However, parties who have received copies, or rights, from you under -+this License will not have their licenses terminated so long as such -+parties remain in full compliance. -+ -+ 5. You are not required to accept this License, since you have not -+signed it. However, nothing else grants you permission to modify or -+distribute the Program or its derivative works. These actions are -+prohibited by law if you do not accept this License. Therefore, by -+modifying or distributing the Program (or any work based on the -+Program), you indicate your acceptance of this License to do so, and -+all its terms and conditions for copying, distributing or modifying -+the Program or works based on it. -+ -+ 6. Each time you redistribute the Program (or any work based on the -+Program), the recipient automatically receives a license from the -+original licensor to copy, distribute or modify the Program subject to -+these terms and conditions. You may not impose any further -+restrictions on the recipients' exercise of the rights granted herein. -+You are not responsible for enforcing compliance by third parties to -+this License. -+ -+ 7. If, as a consequence of a court judgment or allegation of patent -+infringement or for any other reason (not limited to patent issues), -+conditions are imposed on you (whether by court order, agreement or -+otherwise) that contradict the conditions of this License, they do not -+excuse you from the conditions of this License. If you cannot -+distribute so as to satisfy simultaneously your obligations under this -+License and any other pertinent obligations, then as a consequence you -+may not distribute the Program at all. For example, if a patent -+license would not permit royalty-free redistribution of the Program by -+all those who receive copies directly or indirectly through you, then -+the only way you could satisfy both it and this License would be to -+refrain entirely from distribution of the Program. -+ -+If any portion of this section is held invalid or unenforceable under -+any particular circumstance, the balance of the section is intended to -+apply and the section as a whole is intended to apply in other -+circumstances. -+ -+It is not the purpose of this section to induce you to infringe any -+patents or other property right claims or to contest validity of any -+such claims; this section has the sole purpose of protecting the -+integrity of the free software distribution system, which is -+implemented by public license practices. Many people have made -+generous contributions to the wide range of software distributed -+through that system in reliance on consistent application of that -+system; it is up to the author/donor to decide if he or she is willing -+to distribute software through any other system and a licensee cannot -+impose that choice. -+ -+This section is intended to make thoroughly clear what is believed to -+be a consequence of the rest of this License. -+ -+ 8. If the distribution and/or use of the Program is restricted in -+certain countries either by patents or by copyrighted interfaces, the -+original copyright holder who places the Program under this License -+may add an explicit geographical distribution limitation excluding -+those countries, so that distribution is permitted only in or among -+countries not thus excluded. In such case, this License incorporates -+the limitation as if written in the body of this License. -+ -+ 9. The Free Software Foundation may publish revised and/or new versions -+of the General Public License from time to time. Such new versions will -+be similar in spirit to the present version, but may differ in detail to -+address new problems or concerns. -+ -+Each version is given a distinguishing version number. If the Program -+specifies a version number of this License which applies to it and "any -+later version", you have the option of following the terms and conditions -+either of that version or of any later version published by the Free -+Software Foundation. If the Program does not specify a version number of -+this License, you may choose any version ever published by the Free Software -+Foundation. -+ -+ 10. If you wish to incorporate parts of the Program into other free -+programs whose distribution conditions are different, write to the author -+to ask for permission. For software which is copyrighted by the Free -+Software Foundation, write to the Free Software Foundation; we sometimes -+make exceptions for this. Our decision will be guided by the two goals -+of preserving the free status of all derivatives of our free software and -+of promoting the sharing and reuse of software generally. -+ -+ NO WARRANTY -+ -+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -+REPAIR OR CORRECTION. -+ -+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -+POSSIBILITY OF SUCH DAMAGES. -+ -+ END OF TERMS AND CONDITIONS -+ -+ How to Apply These Terms to Your New Programs -+ -+ If you develop a new program, and you want it to be of the greatest -+possible use to the public, the best way to achieve this is to make it -+free software which everyone can redistribute and change under these terms. -+ -+ To do so, attach the following notices to the program. It is safest -+to attach them to the start of each source file to most effectively -+convey the exclusion of warranty; and each file should have at least -+the "copyright" line and a pointer to where the full notice is found. -+ -+ -+ Copyright (C) 19yy -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ -+Also add information on how to contact you by electronic and paper mail. -+ -+If the program is interactive, make it output a short notice like this -+when it starts in an interactive mode: -+ -+ Gnomovision version 69, Copyright (C) 19yy name of author -+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -+ This is free software, and you are welcome to redistribute it -+ under certain conditions; type `show c' for details. -+ -+The hypothetical commands `show w' and `show c' should show the appropriate -+parts of the General Public License. Of course, the commands you use may -+be called something other than `show w' and `show c'; they could even be -+mouse-clicks or menu items--whatever suits your program. -+ -+You should also get your employer (if you work as a programmer) or your -+school, if any, to sign a "copyright disclaimer" for the program, if -+necessary. Here is a sample; alter the names: -+ -+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program -+ `Gnomovision' (which makes passes at compilers) written by James Hacker. -+ -+ , 1 April 1989 -+ Ty Coon, President of Vice -+ -+This General Public License does not permit incorporating your program into -+proprietary programs. If your program is a subroutine library, you may -+consider it more useful to permit linking proprietary applications with the -+library. If this is what you want to do, use the GNU Library General -+Public License instead of this License. ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/MAKEDEV 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/MAKEDEV 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,42 @@ -+#!/bin/bash -+ -+function mkftl () { -+ mknod /dev/ftl$1 b 44 $2 -+ for a in `seq 1 15`; do -+ mknod /dev/ftl$1$a b 44 `expr $2 + $a` -+ done -+} -+function mknftl () { -+ mknod /dev/nftl$1 b 93 $2 -+ for a in `seq 1 15`; do -+ mknod /dev/nftl$1$a b 93 `expr $2 + $a` -+ done -+} -+function mkrfd () { -+ mknod /dev/rfd$1 b 256 $2 -+ for a in `seq 1 15`; do -+ mknod /dev/rfd$1$a b 256 `expr $2 + $a` -+ done -+} -+function mkinftl () { -+ mknod /dev/inftl$1 b 96 $2 -+ for a in `seq 1 15`; do -+ mknod /dev/inftl$1$a b 96 `expr $2 + $a` -+ done -+} -+ -+M=0 -+for C in a b c d e f g h i j k l m n o p; do -+ mkftl $C $M -+ mknftl $C $M -+ mkrfd $C $M -+ mkinftl $C $M -+ let M=M+16 -+done -+ -+for a in `seq 0 16` ; do -+ mknod /dev/mtd$a c 90 `expr $a + $a` -+ mknod /dev/mtdr$a c 90 `expr $a + $a + 1` -+ mknod /dev/mtdblock$a b 31 $a -+done -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,102 @@ -+ -+# -*- sh -*- -+ -+OPTFLAGS := -O2 -Wall -+SBINDIR=/usr/sbin -+MANDIR=/usr/share/man -+INCLUDEDIR=/usr/include -+CROSS=mipsel-linux- -+CC := $(CROSS)gcc -+CFLAGS := -I./include $(OPTFLAGS) -+ -+ifeq ($(origin CROSS),undefined) -+ BUILDDIR := . -+else -+# Remove the trailing slash to make the directory name -+ BUILDDIR := .#$(CROSS:-=) -+endif -+ -+ifeq ($(WITHOUT_XATTR), 1) -+ CFLAGS += -DWITHOUT_XATTR -+endif -+ -+#RAWTARGETS = ftl_format flash_erase flash_eraseall nanddump doc_loadbios \ -+# ftl_check mkfs.jffs2 flash_lock flash_unlock flash_info \ -+# flash_otp_info flash_otp_dump mtd_debug flashcp nandwrite nandtest \ -+# jffs2dump \ -+# nftldump nftl_format docfdisk \ -+# rfddump rfdformat \ -+# serve_image recv_image \ -+# sumtool #jffs2reader -+ -+RAWTARGETS = flash_erase flash_eraseall nanddump nanddump_vfat \ -+ flash_info \ -+ flash_otp_info flash_otp_dump nandwrite nandwrite_mlc \ -+ nandtest \ -+ sumtool #jffs2reader -+ -+TARGETS = $(foreach target,$(RAWTARGETS),$(BUILDDIR)/$(target)) -+ -+SYMLINKS = -+ -+%: %.o -+ $(CC) $(CFLAGS) $(LDFLAGS) -g -o $@ $^ -+ -+$(BUILDDIR)/%.o: %.c -+ mkdir -p $(BUILDDIR) -+ $(CC) $(CFLAGS) -g -c -o $@ $< -g -Wp,-MD,$(BUILDDIR)/.$( ${DESTDIR}/${MANDIR}/man1/mkfs.jffs2.1.gz -+ make -C $(BUILDDIR)/ubi-utils install ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/compr.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,538 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2004 Ferenc Havasi , -+ * University of Szeged, Hungary -+ * -+ * For licensing information, see the file 'LICENCE' in this directory -+ * in the jffs2 directory. -+ */ -+ -+#include "compr.h" -+#include -+#include -+#include -+ -+#define FAVOUR_LZO_PERCENT 80 -+ -+extern int page_size; -+ -+/* LIST IMPLEMENTATION (from linux/list.h) */ -+ -+#define LIST_HEAD_INIT(name) { &(name), &(name) } -+ -+#define LIST_HEAD(name) \ -+ struct list_head name = LIST_HEAD_INIT(name) -+ -+static inline void __list_add(struct list_head *new, -+ struct list_head *prev, -+ struct list_head *next) -+{ -+ next->prev = new; -+ new->next = next; -+ new->prev = prev; -+ prev->next = new; -+} -+ -+static inline void list_add(struct list_head *new, struct list_head *head) -+{ -+ __list_add(new, head, head->next); -+} -+ -+static inline void list_add_tail(struct list_head *new, struct list_head *head) -+{ -+ __list_add(new, head->prev, head); -+} -+ -+static inline void __list_del(struct list_head *prev, struct list_head *next) -+{ -+ next->prev = prev; -+ prev->next = next; -+} -+ -+static inline void list_del(struct list_head *entry) -+{ -+ __list_del(entry->prev, entry->next); -+ entry->next = (void *) 0; -+ entry->prev = (void *) 0; -+} -+ -+#define list_entry(ptr, type, member) \ -+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) -+ -+#define list_for_each_entry(pos, head, member) \ -+ for (pos = list_entry((head)->next, typeof(*pos), member); \ -+ &pos->member != (head); \ -+ pos = list_entry(pos->member.next, typeof(*pos), member)) -+ -+ -+/* Available compressors are on this list */ -+static LIST_HEAD(jffs2_compressor_list); -+ -+/* Actual compression mode */ -+static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; -+ -+void jffs2_set_compression_mode(int mode) -+{ -+ jffs2_compression_mode = mode; -+} -+ -+int jffs2_get_compression_mode(void) -+{ -+ return jffs2_compression_mode; -+} -+ -+/* Statistics for blocks stored without compression */ -+static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0; -+ -+/* Compression test stuffs */ -+ -+static int jffs2_compression_check = 0; -+ -+static unsigned char *jffs2_compression_check_buf = NULL; -+ -+void jffs2_compression_check_set(int yesno) -+{ -+ jffs2_compression_check = yesno; -+} -+ -+int jffs2_compression_check_get(void) -+{ -+ return jffs2_compression_check; -+} -+ -+static int jffs2_error_cnt = 0; -+ -+int jffs2_compression_check_errorcnt_get(void) -+{ -+ return jffs2_error_cnt; -+} -+ -+#define JFFS2_BUFFER_FILL 0x55 -+ -+/* Called before compression (if compression_check is setted) to prepare -+ the buffer for buffer overflow test */ -+static void jffs2_decompression_test_prepare(unsigned char *buf, int size) -+{ -+ memset(buf,JFFS2_BUFFER_FILL,size+1); -+} -+ -+/* Called after compression (if compression_check is setted) to test the result */ -+static void jffs2_decompression_test(struct jffs2_compressor *compr, -+ unsigned char *data_in, unsigned char *output_buf, -+ uint32_t cdatalen, uint32_t datalen, uint32_t buf_size) -+{ -+ uint32_t i; -+ -+ /* buffer overflow test */ -+ for (i=buf_size;i>cdatalen;i--) { -+ if (output_buf[i]!=JFFS2_BUFFER_FILL) { -+ fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. " -+ "(bs=%d csize=%d b[%d]=%d)\n", compr->name, -+ buf_size, cdatalen, i, (int)(output_buf[i])); -+ jffs2_error_cnt++; -+ return; -+ } -+ } -+ /* allocing temporary buffer for decompression */ -+ if (!jffs2_compression_check_buf) { -+ jffs2_compression_check_buf = malloc(page_size); -+ if (!jffs2_compression_check_buf) { -+ fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n"); -+ jffs2_compression_check = 0; -+ return; -+ } -+ } -+ /* decompressing */ -+ if (!compr->decompress) { -+ fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name); -+ jffs2_error_cnt++; -+ return; -+ } -+ if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen,NULL)) { -+ fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name); -+ jffs2_error_cnt++; -+ } -+ /* validate decompression */ -+ else { -+ for (i=0;iname, i); -+ jffs2_error_cnt++; -+ break; -+ } -+ } -+ } -+} -+ -+/* -+ * Return 1 to use this compression -+ */ -+static int jffs2_is_best_compression(struct jffs2_compressor *this, -+ struct jffs2_compressor *best, uint32_t size, uint32_t bestsize) -+{ -+ switch (jffs2_compression_mode) { -+ case JFFS2_COMPR_MODE_SIZE: -+ if (bestsize > size) -+ return 1; -+ return 0; -+ case JFFS2_COMPR_MODE_FAVOURLZO: -+ if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size)) -+ return 1; -+ if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size)) -+ return 1; -+ if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100))) -+ return 1; -+ if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size) -+ return 1; -+ -+ return 0; -+ } -+ /* Shouldn't happen */ -+ return 0; -+} -+ -+/* jffs2_compress: -+ * @data: Pointer to uncompressed data -+ * @cdata: Pointer to returned pointer to buffer for compressed data -+ * @datalen: On entry, holds the amount of data available for compression. -+ * On exit, expected to hold the amount of data actually compressed. -+ * @cdatalen: On entry, holds the amount of space available for compressed -+ * data. On exit, expected to hold the actual size of the compressed -+ * data. -+ * -+ * Returns: Lower byte to be stored with data indicating compression type used. -+ * Zero is used to show that the data could not be compressed - the -+ * compressed version was actually larger than the original. -+ * Upper byte will be used later. (soon) -+ * -+ * If the cdata buffer isn't large enough to hold all the uncompressed data, -+ * jffs2_compress should compress as much as will fit, and should set -+ * *datalen accordingly to show the amount of data which were compressed. -+ */ -+uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out, -+ uint32_t *datalen, uint32_t *cdatalen) -+{ -+ int ret = JFFS2_COMPR_NONE; -+ int compr_ret; -+ struct jffs2_compressor *this, *best=NULL; -+ unsigned char *output_buf = NULL, *tmp_buf; -+ uint32_t orig_slen, orig_dlen; -+ uint32_t best_slen=0, best_dlen=0; -+ -+ switch (jffs2_compression_mode) { -+ case JFFS2_COMPR_MODE_NONE: -+ break; -+ case JFFS2_COMPR_MODE_PRIORITY: -+ orig_slen = *datalen; -+ orig_dlen = *cdatalen; -+ output_buf = malloc(orig_dlen+jffs2_compression_check); -+ if (!output_buf) { -+ fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n"); -+ goto out; -+ } -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ /* Skip decompress-only backwards-compatibility and disabled modules */ -+ if ((!this->compress)||(this->disabled)) -+ continue; -+ -+ this->usecount++; -+ -+ if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ -+ jffs2_decompression_test_prepare(output_buf, orig_dlen); -+ -+ *datalen = orig_slen; -+ *cdatalen = orig_dlen; -+ compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); -+ this->usecount--; -+ if (!compr_ret) { -+ ret = this->compr; -+ this->stat_compr_blocks++; -+ this->stat_compr_orig_size += *datalen; -+ this->stat_compr_new_size += *cdatalen; -+ if (jffs2_compression_check) -+ jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, orig_dlen); -+ break; -+ } -+ } -+ if (ret == JFFS2_COMPR_NONE) free(output_buf); -+ break; -+ case JFFS2_COMPR_MODE_FAVOURLZO: -+ case JFFS2_COMPR_MODE_SIZE: -+ orig_slen = *datalen; -+ orig_dlen = *cdatalen; -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ uint32_t needed_buf_size; -+ -+ if (jffs2_compression_mode == JFFS2_COMPR_MODE_FAVOURLZO) -+ needed_buf_size = orig_slen + jffs2_compression_check; -+ else -+ needed_buf_size = orig_dlen + jffs2_compression_check; -+ -+ /* Skip decompress-only backwards-compatibility and disabled modules */ -+ if ((!this->compress)||(this->disabled)) -+ continue; -+ /* Allocating memory for output buffer if necessary */ -+ if ((this->compr_buf_size < needed_buf_size) && (this->compr_buf)) { -+ free(this->compr_buf); -+ this->compr_buf_size=0; -+ this->compr_buf=NULL; -+ } -+ if (!this->compr_buf) { -+ tmp_buf = malloc(needed_buf_size); -+ if (!tmp_buf) { -+ fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. (%d bytes)\n",orig_dlen); -+ continue; -+ } -+ else { -+ this->compr_buf = tmp_buf; -+ this->compr_buf_size = orig_dlen; -+ } -+ } -+ this->usecount++; -+ if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ -+ jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size); -+ *datalen = orig_slen; -+ *cdatalen = orig_dlen; -+ compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); -+ this->usecount--; -+ if (!compr_ret) { -+ if (jffs2_compression_check) -+ jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, this->compr_buf_size); -+ if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen)) -+ && (*cdatalen < *datalen)) { -+ best_dlen = *cdatalen; -+ best_slen = *datalen; -+ best = this; -+ } -+ } -+ } -+ if (best_dlen) { -+ *cdatalen = best_dlen; -+ *datalen = best_slen; -+ output_buf = best->compr_buf; -+ best->compr_buf = NULL; -+ best->compr_buf_size = 0; -+ best->stat_compr_blocks++; -+ best->stat_compr_orig_size += best_slen; -+ best->stat_compr_new_size += best_dlen; -+ ret = best->compr; -+ } -+ break; -+ default: -+ fprintf(stderr,"mkfs.jffs2: unknow compression mode.\n"); -+ } -+out: -+ if (ret == JFFS2_COMPR_NONE) { -+ *cpage_out = data_in; -+ *datalen = *cdatalen; -+ none_stat_compr_blocks++; -+ none_stat_compr_size += *datalen; -+ } -+ else { -+ *cpage_out = output_buf; -+ } -+ return ret; -+} -+ -+ -+int jffs2_register_compressor(struct jffs2_compressor *comp) -+{ -+ struct jffs2_compressor *this; -+ -+ if (!comp->name) { -+ fprintf(stderr,"NULL compressor name at registering JFFS2 compressor. Failed.\n"); -+ return -1; -+ } -+ comp->compr_buf_size=0; -+ comp->compr_buf=NULL; -+ comp->usecount=0; -+ comp->stat_compr_orig_size=0; -+ comp->stat_compr_new_size=0; -+ comp->stat_compr_blocks=0; -+ comp->stat_decompr_blocks=0; -+ -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ if (this->priority < comp->priority) { -+ list_add(&comp->list, this->list.prev); -+ goto out; -+ } -+ } -+ list_add_tail(&comp->list, &jffs2_compressor_list); -+out: -+ return 0; -+} -+ -+int jffs2_unregister_compressor(struct jffs2_compressor *comp) -+{ -+ -+ if (comp->usecount) { -+ fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n"); -+ return -1; -+ } -+ list_del(&comp->list); -+ -+ return 0; -+} -+ -+#define JFFS2_STAT_BUF_SIZE 16000 -+ -+char *jffs2_list_compressors(void) -+{ -+ struct jffs2_compressor *this; -+ char *buf, *act_buf; -+ -+ act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE); -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority); -+ if ((this->disabled)||(!this->compress)) -+ act_buf += sprintf(act_buf,"disabled"); -+ else -+ act_buf += sprintf(act_buf,"enabled"); -+ act_buf += sprintf(act_buf,"\n"); -+ } -+ return buf; -+} -+ -+char *jffs2_stats(void) -+{ -+ struct jffs2_compressor *this; -+ char *buf, *act_buf; -+ -+ act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE); -+ -+ act_buf += sprintf(act_buf,"Compression mode: "); -+ switch (jffs2_compression_mode) { -+ case JFFS2_COMPR_MODE_NONE: -+ act_buf += sprintf(act_buf,"none"); -+ break; -+ case JFFS2_COMPR_MODE_PRIORITY: -+ act_buf += sprintf(act_buf,"priority"); -+ break; -+ case JFFS2_COMPR_MODE_SIZE: -+ act_buf += sprintf(act_buf,"size"); -+ break; -+ case JFFS2_COMPR_MODE_FAVOURLZO: -+ act_buf += sprintf(act_buf, "favourlzo"); -+ break; -+ default: -+ act_buf += sprintf(act_buf,"unkown"); -+ break; -+ } -+ act_buf += sprintf(act_buf,"\nCompressors:\n"); -+ act_buf += sprintf(act_buf,"%10s ","none"); -+ act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks, -+ none_stat_compr_size, none_stat_decompr_blocks); -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ act_buf += sprintf(act_buf,"%10s (prio:%d) ",this->name,this->priority); -+ if ((this->disabled)||(!this->compress)) -+ act_buf += sprintf(act_buf,"- "); -+ else -+ act_buf += sprintf(act_buf,"+ "); -+ act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks, -+ this->stat_compr_new_size, this->stat_compr_orig_size, -+ this->stat_decompr_blocks); -+ act_buf += sprintf(act_buf,"\n"); -+ } -+ return buf; -+} -+ -+int jffs2_set_compression_mode_name(const char *name) -+{ -+ if (!strcmp("none",name)) { -+ jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; -+ return 0; -+ } -+ if (!strcmp("priority",name)) { -+ jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; -+ return 0; -+ } -+ if (!strcmp("size",name)) { -+ jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; -+ return 0; -+ } -+ if (!strcmp("favourlzo", name)) { -+ jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO; -+ return 0; -+ } -+ -+ return 1; -+} -+ -+static int jffs2_compressor_Xable(const char *name, int disabled) -+{ -+ struct jffs2_compressor *this; -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ if (!strcmp(this->name, name)) { -+ this->disabled = disabled; -+ return 0; -+ } -+ } -+ return 1; -+} -+ -+int jffs2_enable_compressor_name(const char *name) -+{ -+ return jffs2_compressor_Xable(name, 0); -+} -+ -+int jffs2_disable_compressor_name(const char *name) -+{ -+ return jffs2_compressor_Xable(name, 1); -+} -+ -+int jffs2_set_compressor_priority(const char *name, int priority) -+{ -+ struct jffs2_compressor *this,*comp; -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ if (!strcmp(this->name, name)) { -+ this->priority = priority; -+ comp = this; -+ goto reinsert; -+ } -+ } -+ fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name); -+ return 1; -+reinsert: -+ /* list is sorted in the order of priority, so if -+ we change it we have to reinsert it into the -+ good place */ -+ list_del(&comp->list); -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ if (this->priority < comp->priority) { -+ list_add(&comp->list, this->list.prev); -+ return 0; -+ } -+ } -+ list_add_tail(&comp->list, &jffs2_compressor_list); -+ return 0; -+} -+ -+ -+int jffs2_compressors_init(void) -+{ -+#ifdef CONFIG_JFFS2_ZLIB -+ jffs2_zlib_init(); -+#endif -+#ifdef CONFIG_JFFS2_RTIME -+ jffs2_rtime_init(); -+#endif -+#ifdef CONFIG_JFFS2_LZO -+ jffs2_lzo_init(); -+#endif -+ return 0; -+} -+ -+int jffs2_compressors_exit(void) -+{ -+#ifdef CONFIG_JFFS2_RTIME -+ jffs2_rtime_exit(); -+#endif -+#ifdef CONFIG_JFFS2_ZLIB -+ jffs2_zlib_exit(); -+#endif -+#ifdef CONFIG_JFFS2_LZO -+ jffs2_lzo_exit(); -+#endif -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/compr.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,119 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2004 Ferenc Havasi , -+ * University of Szeged, Hungary -+ * -+ * For licensing information, see the file 'LICENCE' in the -+ * jffs2 directory. -+ */ -+ -+#ifndef __JFFS2_COMPR_H__ -+#define __JFFS2_COMPR_H__ -+ -+#include -+#include -+#include -+#include "linux/jffs2.h" -+ -+#define CONFIG_JFFS2_ZLIB -+#define CONFIG_JFFS2_RTIME -+#define CONFIG_JFFS2_LZO -+ -+#define JFFS2_RUBINMIPS_PRIORITY 10 -+#define JFFS2_DYNRUBIN_PRIORITY 20 -+#define JFFS2_RTIME_PRIORITY 50 -+#define JFFS2_ZLIB_PRIORITY 60 -+#define JFFS2_LZO_PRIORITY 80 -+ -+#define JFFS2_COMPR_MODE_NONE 0 -+#define JFFS2_COMPR_MODE_PRIORITY 1 -+#define JFFS2_COMPR_MODE_SIZE 2 -+#define JFFS2_COMPR_MODE_FAVOURLZO 3 -+ -+#define kmalloc(a,b) malloc(a) -+#define kfree(a) free(a) -+#ifndef GFP_KERNEL -+#define GFP_KERNEL 0 -+#endif -+ -+#define vmalloc(a) malloc(a) -+#define vfree(a) free(a) -+ -+#define printk(...) fprintf(stderr,__VA_ARGS__) -+ -+#define KERN_EMERG -+#define KERN_ALERT -+#define KERN_CRIT -+#define KERN_ERR -+#define KERN_WARNING -+#define KERN_NOTICE -+#define KERN_INFO -+#define KERN_DEBUG -+ -+struct list_head { -+ struct list_head *next, *prev; -+}; -+ -+void jffs2_set_compression_mode(int mode); -+int jffs2_get_compression_mode(void); -+int jffs2_set_compression_mode_name(const char *mode_name); -+ -+int jffs2_enable_compressor_name(const char *name); -+int jffs2_disable_compressor_name(const char *name); -+ -+int jffs2_set_compressor_priority(const char *name, int priority); -+ -+struct jffs2_compressor { -+ struct list_head list; -+ int priority; /* used by prirority comr. mode */ -+ char *name; -+ char compr; /* JFFS2_COMPR_XXX */ -+ int (*compress)(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *srclen, uint32_t *destlen, void *model); -+ int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, -+ uint32_t cdatalen, uint32_t datalen, void *model); -+ int usecount; -+ int disabled; /* if seted the compressor won't compress */ -+ unsigned char *compr_buf; /* used by size compr. mode */ -+ uint32_t compr_buf_size; /* used by size compr. mode */ -+ uint32_t stat_compr_orig_size; -+ uint32_t stat_compr_new_size; -+ uint32_t stat_compr_blocks; -+ uint32_t stat_decompr_blocks; -+}; -+ -+int jffs2_register_compressor(struct jffs2_compressor *comp); -+int jffs2_unregister_compressor(struct jffs2_compressor *comp); -+ -+int jffs2_compressors_init(void); -+int jffs2_compressors_exit(void); -+ -+uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out, -+ uint32_t *datalen, uint32_t *cdatalen); -+ -+/* If it is setted, a decompress will be called after every compress */ -+void jffs2_compression_check_set(int yesno); -+int jffs2_compression_check_get(void); -+int jffs2_compression_check_errorcnt_get(void); -+ -+char *jffs2_list_compressors(void); -+char *jffs2_stats(void); -+ -+/* Compressor modules */ -+ -+/* These functions will be called by jffs2_compressors_init/exit */ -+#ifdef CONFIG_JFFS2_ZLIB -+int jffs2_zlib_init(void); -+void jffs2_zlib_exit(void); -+#endif -+#ifdef CONFIG_JFFS2_RTIME -+int jffs2_rtime_init(void); -+void jffs2_rtime_exit(void); -+#endif -+#ifdef CONFIG_JFFS2_LZO -+int jffs2_lzo_init(void); -+void jffs2_lzo_exit(void); -+#endif -+ -+#endif /* __JFFS2_COMPR_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr_lzo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/compr_lzo.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,120 @@ -+/* -+ * JFFS2 LZO Compression Interface. -+ * -+ * Copyright (C) 2007 Nokia Corporation. All rights reserved. -+ * -+ * Author: Richard Purdie -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "compr.h" -+ -+extern int page_size; -+ -+static void *lzo_mem; -+static void *lzo_compress_buf; -+ -+/* -+ * Note about LZO compression. -+ * -+ * We want to use the _999_ compression routine which gives better compression -+ * rates at the expense of time. Decompression time is unaffected. We might as -+ * well use the standard lzo library routines for this but they will overflow -+ * the destination buffer since they don't check the destination size. -+ * -+ * We therefore compress to a temporary buffer and copy if it will fit. -+ * -+ */ -+static int jffs2_lzo_cmpr(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *sourcelen, uint32_t *dstlen, void *model) -+{ -+ uint32_t compress_size; -+ int ret; -+ -+ ret = lzo1x_999_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); -+ -+ if (ret != LZO_E_OK) -+ return -1; -+ -+ if (compress_size > *dstlen) -+ return -1; -+ -+ memcpy(cpage_out, lzo_compress_buf, compress_size); -+ *dstlen = compress_size; -+ -+ return 0; -+} -+ -+static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t srclen, uint32_t destlen, void *model) -+{ -+ int ret; -+ uint32_t dl; -+ -+ ret = lzo1x_decompress_safe(data_in,srclen,cpage_out,&dl,NULL); -+ -+ if (ret != LZO_E_OK || dl != destlen) -+ return -1; -+ -+ return 0; -+} -+ -+static struct jffs2_compressor jffs2_lzo_comp = { -+ .priority = JFFS2_LZO_PRIORITY, -+ .name = "lzo", -+ .compr = JFFS2_COMPR_LZO, -+ .compress = &jffs2_lzo_cmpr, -+ .decompress = &jffs2_lzo_decompress, -+ .disabled = 1, -+}; -+ -+int jffs2_lzo_init(void) -+{ -+ int ret; -+ -+ lzo_mem = malloc(LZO1X_999_MEM_COMPRESS); -+ if (!lzo_mem) -+ return -1; -+ -+ /* Worse case LZO compression size from their FAQ */ -+ lzo_compress_buf = malloc(page_size + (page_size / 16) + 64 + 3); -+ if (!lzo_compress_buf) { -+ free(lzo_mem); -+ return -1; -+ } -+ -+ ret = jffs2_register_compressor(&jffs2_lzo_comp); -+ if (ret < 0) { -+ free(lzo_compress_buf); -+ free(lzo_mem); -+ } -+ -+ return ret; -+} -+ -+void jffs2_lzo_exit(void) -+{ -+ jffs2_unregister_compressor(&jffs2_lzo_comp); -+ free(lzo_compress_buf); -+ free(lzo_mem); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr_rtime.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/compr_rtime.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,119 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2001-2003 Red Hat, Inc. -+ * -+ * Created by Arjan van de Ven -+ * -+ * For licensing information, see the file 'LICENCE' in this directory. -+ * -+ * Very simple lz77-ish encoder. -+ * -+ * Theory of operation: Both encoder and decoder have a list of "last -+ * occurrences" for every possible source-value; after sending the -+ * first source-byte, the second byte indicated the "run" length of -+ * matches -+ * -+ * The algorithm is intended to only send "whole bytes", no bit-messing. -+ * -+ */ -+ -+#include -+#include -+#include "compr.h" -+ -+/* _compress returns the compressed size, -1 if bigger */ -+static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *sourcelen, uint32_t *dstlen, void *model) -+{ -+ short positions[256]; -+ int outpos = 0; -+ int pos=0; -+ -+ memset(positions,0,sizeof(positions)); -+ -+ while (pos < (*sourcelen) && outpos <= (*dstlen)-2) { -+ int backpos, runlen=0; -+ unsigned char value; -+ -+ value = data_in[pos]; -+ -+ cpage_out[outpos++] = data_in[pos++]; -+ -+ backpos = positions[value]; -+ positions[value]=pos; -+ -+ while ((backpos < pos) && (pos < (*sourcelen)) && -+ (data_in[pos]==data_in[backpos++]) && (runlen<255)) { -+ pos++; -+ runlen++; -+ } -+ cpage_out[outpos++] = runlen; -+ } -+ -+ if (outpos >= pos) { -+ /* We failed */ -+ return -1; -+ } -+ -+ /* Tell the caller how much we managed to compress, and how much space it took */ -+ *sourcelen = pos; -+ *dstlen = outpos; -+ return 0; -+} -+ -+ -+static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t srclen, uint32_t destlen, void *model) -+{ -+ short positions[256]; -+ int outpos = 0; -+ int pos=0; -+ -+ memset(positions,0,sizeof(positions)); -+ -+ while (outpos= outpos) { -+ while(repeat) { -+ cpage_out[outpos++] = cpage_out[backoffs++]; -+ repeat--; -+ } -+ } else { -+ memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat); -+ outpos+=repeat; -+ } -+ } -+ } -+ return 0; -+} -+ -+ -+static struct jffs2_compressor jffs2_rtime_comp = { -+ .priority = JFFS2_RTIME_PRIORITY, -+ .name = "rtime", -+ .disabled = 0, -+ .compr = JFFS2_COMPR_RTIME, -+ .compress = &jffs2_rtime_compress, -+ .decompress = &jffs2_rtime_decompress, -+}; -+ -+int jffs2_rtime_init(void) -+{ -+ return jffs2_register_compressor(&jffs2_rtime_comp); -+} -+ -+void jffs2_rtime_exit(void) -+{ -+ jffs2_unregister_compressor(&jffs2_rtime_comp); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr_zlib.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/compr_zlib.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,145 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2001 Red Hat, Inc. -+ * -+ * Created by David Woodhouse -+ * -+ * The original JFFS, from which the design for JFFS2 was derived, -+ * was designed and implemented by Axis Communications AB. -+ * -+ * The contents of this file are subject to the Red Hat eCos Public -+ * License Version 1.1 (the "Licence"); you may not use this file -+ * except in compliance with the Licence. You may obtain a copy of -+ * the Licence at http://www.redhat.com/ -+ * -+ * Software distributed under the Licence is distributed on an "AS IS" -+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -+ * See the Licence for the specific language governing rights and -+ * limitations under the Licence. -+ * -+ * The Original Code is JFFS2 - Journalling Flash File System, version 2 -+ * -+ * Alternatively, the contents of this file may be used under the -+ * terms of the GNU General Public License version 2 (the "GPL"), in -+ * which case the provisions of the GPL are applicable instead of the -+ * above. If you wish to allow the use of your version of this file -+ * only under the terms of the GPL and not to allow others to use your -+ * version of this file under the RHEPL, indicate your decision by -+ * deleting the provisions above and replace them with the notice and -+ * other provisions required by the GPL. If you do not delete the -+ * provisions above, a recipient may use your version of this file -+ * under either the RHEPL or the GPL. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "compr.h" -+ -+#define min(x,y) ((x)<(y)?(x):(y)) -+ -+/* Plan: call deflate() with avail_in == *sourcelen, -+ avail_out = *dstlen - 12 and flush == Z_FINISH. -+ If it doesn't manage to finish, call it again with -+ avail_in == 0 and avail_out set to the remaining 12 -+ bytes for it to clean up. -+Q: Is 12 bytes sufficient? -+ */ -+#define STREAM_END_SPACE 12 -+ -+int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *sourcelen, uint32_t *dstlen, void *model) -+{ -+ z_stream strm; -+ int ret; -+ -+ if (*dstlen <= STREAM_END_SPACE) -+ return -1; -+ -+ strm.zalloc = (void *)0; -+ strm.zfree = (void *)0; -+ -+ if (Z_OK != deflateInit(&strm, 3)) { -+ return -1; -+ } -+ strm.next_in = data_in; -+ strm.total_in = 0; -+ -+ strm.next_out = cpage_out; -+ strm.total_out = 0; -+ -+ while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) { -+ strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE); -+ strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out); -+ ret = deflate(&strm, Z_PARTIAL_FLUSH); -+ if (ret != Z_OK) { -+ deflateEnd(&strm); -+ return -1; -+ } -+ } -+ strm.avail_out += STREAM_END_SPACE; -+ strm.avail_in = 0; -+ ret = deflate(&strm, Z_FINISH); -+ if (ret != Z_STREAM_END) { -+ deflateEnd(&strm); -+ return -1; -+ } -+ deflateEnd(&strm); -+ -+ if (strm.total_out >= strm.total_in) -+ return -1; -+ -+ -+ *dstlen = strm.total_out; -+ *sourcelen = strm.total_in; -+ return 0; -+} -+ -+int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t srclen, uint32_t destlen, void *model) -+{ -+ z_stream strm; -+ int ret; -+ -+ strm.zalloc = (void *)0; -+ strm.zfree = (void *)0; -+ -+ if (Z_OK != inflateInit(&strm)) { -+ return 1; -+ } -+ strm.next_in = data_in; -+ strm.avail_in = srclen; -+ strm.total_in = 0; -+ -+ strm.next_out = cpage_out; -+ strm.avail_out = destlen; -+ strm.total_out = 0; -+ -+ while((ret = inflate(&strm, Z_FINISH)) == Z_OK) -+ ; -+ -+ inflateEnd(&strm); -+ return 0; -+} -+ -+static struct jffs2_compressor jffs2_zlib_comp = { -+ .priority = JFFS2_ZLIB_PRIORITY, -+ .name = "zlib", -+ .disabled = 0, -+ .compr = JFFS2_COMPR_ZLIB, -+ .compress = &jffs2_zlib_compress, -+ .decompress = &jffs2_zlib_decompress, -+}; -+ -+int jffs2_zlib_init(void) -+{ -+ return jffs2_register_compressor(&jffs2_zlib_comp); -+} -+ -+void jffs2_zlib_exit(void) -+{ -+ jffs2_unregister_compressor(&jffs2_zlib_comp); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/crc32.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/crc32.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,95 @@ -+/* -+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or -+ * code or tables extracted from it, as desired without restriction. -+ * -+ * First, the polynomial itself and its table of feedback terms. The -+ * polynomial is -+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 -+ * -+ * Note that we take it "backwards" and put the highest-order term in -+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the -+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in -+ * the MSB being 1 -+ * -+ * Note that the usual hardware shift register implementation, which -+ * is what we're using (we're merely optimizing it by doing eight-bit -+ * chunks at a time) shifts bits into the lowest-order term. In our -+ * implementation, that means shifting towards the right. Why do we -+ * do it this way? Because the calculated CRC must be transmitted in -+ * order from highest-order term to lowest-order term. UARTs transmit -+ * characters in order from LSB to MSB. By storing the CRC this way -+ * we hand it to the UART in the order low-byte to high-byte; the UART -+ * sends each low-bit to hight-bit; and the result is transmission bit -+ * by bit from highest- to lowest-order term without requiring any bit -+ * shuffling on our part. Reception works similarly -+ * -+ * The feedback terms table consists of 256, 32-bit entries. Notes -+ * -+ * The table can be generated at runtime if desired; code to do so -+ * is shown later. It might not be obvious, but the feedback -+ * terms simply represent the results of eight shift/xor opera -+ * tions for all combinations of data and CRC register values -+ * -+ * The values must be right-shifted by eight bits by the "updcrc -+ * logic; the shift must be unsigned (bring in zeroes). On some -+ * hardware you could probably optimize the shift in assembler by -+ * using byte-swap instructions -+ * polynomial $edb88320 -+ */ -+ -+#include -+ -+const uint32_t crc32_table[256] = { -+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, -+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, -+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, -+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, -+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, -+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, -+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, -+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, -+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, -+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, -+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, -+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, -+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, -+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, -+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, -+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, -+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, -+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, -+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, -+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, -+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, -+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, -+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, -+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, -+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, -+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, -+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, -+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, -+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, -+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, -+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, -+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, -+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, -+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, -+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, -+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, -+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, -+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, -+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, -+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, -+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, -+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, -+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, -+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, -+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, -+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, -+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, -+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, -+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, -+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, -+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, -+ 0x2d02ef8dL -+}; ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/crc32.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/crc32.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,19 @@ -+#ifndef CRC32_H -+#define CRC32_H -+ -+#include -+ -+extern const uint32_t crc32_table[256]; -+ -+/* Return a 32-bit CRC of the contents of the buffer. */ -+ -+ static inline uint32_t -+crc32(uint32_t val, const void *ss, int len) -+{ -+ const unsigned char *s = ss; -+ while (--len >= 0) -+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); -+ return val; -+} -+ -+#endif ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/device_table.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/device_table.txt 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,129 @@ -+# This is a sample device table file for use with mkfs.jffs2. You can -+# do all sorts of interesting things with a device table file. For -+# example, if you want to adjust the permissions on a particular file -+# you can just add an entry like: -+# /sbin/foobar f 2755 0 0 - - - - - -+# and (assuming the file /sbin/foobar exists) it will be made setuid -+# root (regardless of what its permissions are on the host filesystem. -+# -+# Device table entries take the form of: -+# -+# where name is the file name, type can be one of: -+# f A regular file -+# d Directory -+# c Character special device file -+# b Block special device file -+# p Fifo (named pipe) -+# uid is the user id for the target file, gid is the group id for the -+# target file. The rest of the entried apply only to device special -+# file. -+ -+# When building a target filesystem, it is desirable to not have to -+# become root and then run 'mknod' a thousand times. Using a device -+# table you can create device nodes and directories "on the fly". -+# Furthermore, you can use a single table entry to create a many device -+# minors. For example, if I wanted to create /dev/hda and /dev/hda[0-15] -+# I could just use the following two table entries: -+# /dev/hda b 640 0 0 3 0 0 0 - -+# /dev/hda b 640 0 0 3 1 1 1 15 -+# -+# Have fun -+# -Erik Andersen -+# -+ -+# -+/dev d 755 0 0 - - - - - -+/dev/mem c 640 0 0 1 1 0 0 - -+/dev/kmem c 640 0 0 1 2 0 0 - -+/dev/null c 640 0 0 1 3 0 0 - -+/dev/zero c 640 0 0 1 5 0 0 - -+/dev/random c 640 0 0 1 8 0 0 - -+/dev/urandom c 640 0 0 1 9 0 0 - -+/dev/tty c 666 0 0 5 0 0 0 - -+/dev/tty c 666 0 0 4 0 0 1 6 -+/dev/console c 640 0 0 5 1 0 0 - -+/dev/ram b 640 0 0 1 1 0 0 - -+/dev/ram b 640 0 0 1 0 0 1 4 -+/dev/loop b 640 0 0 7 0 0 1 2 -+/dev/ptmx c 666 0 0 5 2 0 0 - -+#/dev/ttyS c 640 0 0 4 64 0 1 4 -+#/dev/psaux c 640 0 0 10 1 0 0 - -+#/dev/rtc c 640 0 0 10 135 0 0 - -+ -+# Adjust permissions on some normal files -+#/etc/shadow f 600 0 0 - - - - - -+#/bin/tinylogin f 4755 0 0 - - - - - -+ -+# User-mode Linux stuff -+/dev/ubda b 640 0 0 98 0 0 0 - -+/dev/ubda b 640 0 0 98 1 1 1 15 -+ -+# IDE Devices -+/dev/hda b 640 0 0 3 0 0 0 - -+/dev/hda b 640 0 0 3 1 1 1 15 -+/dev/hdb b 640 0 0 3 64 0 0 - -+/dev/hdb b 640 0 0 3 65 1 1 15 -+#/dev/hdc b 640 0 0 22 0 0 0 - -+#/dev/hdc b 640 0 0 22 1 1 1 15 -+#/dev/hdd b 640 0 0 22 64 0 0 - -+#/dev/hdd b 640 0 0 22 65 1 1 15 -+#/dev/hde b 640 0 0 33 0 0 0 - -+#/dev/hde b 640 0 0 33 1 1 1 15 -+#/dev/hdf b 640 0 0 33 64 0 0 - -+#/dev/hdf b 640 0 0 33 65 1 1 15 -+#/dev/hdg b 640 0 0 34 0 0 0 - -+#/dev/hdg b 640 0 0 34 1 1 1 15 -+#/dev/hdh b 640 0 0 34 64 0 0 - -+#/dev/hdh b 640 0 0 34 65 1 1 15 -+ -+# SCSI Devices -+#/dev/sda b 640 0 0 8 0 0 0 - -+#/dev/sda b 640 0 0 8 1 1 1 15 -+#/dev/sdb b 640 0 0 8 16 0 0 - -+#/dev/sdb b 640 0 0 8 17 1 1 15 -+#/dev/sdc b 640 0 0 8 32 0 0 - -+#/dev/sdc b 640 0 0 8 33 1 1 15 -+#/dev/sdd b 640 0 0 8 48 0 0 - -+#/dev/sdd b 640 0 0 8 49 1 1 15 -+#/dev/sde b 640 0 0 8 64 0 0 - -+#/dev/sde b 640 0 0 8 65 1 1 15 -+#/dev/sdf b 640 0 0 8 80 0 0 - -+#/dev/sdf b 640 0 0 8 81 1 1 15 -+#/dev/sdg b 640 0 0 8 96 0 0 - -+#/dev/sdg b 640 0 0 8 97 1 1 15 -+#/dev/sdh b 640 0 0 8 112 0 0 - -+#/dev/sdh b 640 0 0 8 113 1 1 15 -+#/dev/sg c 640 0 0 21 0 0 1 15 -+#/dev/scd b 640 0 0 11 0 0 1 15 -+#/dev/st c 640 0 0 9 0 0 1 8 -+#/dev/nst c 640 0 0 9 128 0 1 8 -+#/dev/st c 640 0 0 9 32 1 1 4 -+#/dev/st c 640 0 0 9 64 1 1 4 -+#/dev/st c 640 0 0 9 96 1 1 4 -+ -+# Floppy disk devices -+#/dev/fd b 640 0 0 2 0 0 1 2 -+#/dev/fd0d360 b 640 0 0 2 4 0 0 - -+#/dev/fd1d360 b 640 0 0 2 5 0 0 - -+#/dev/fd0h1200 b 640 0 0 2 8 0 0 - -+#/dev/fd1h1200 b 640 0 0 2 9 0 0 - -+#/dev/fd0u1440 b 640 0 0 2 28 0 0 - -+#/dev/fd1u1440 b 640 0 0 2 29 0 0 - -+#/dev/fd0u2880 b 640 0 0 2 32 0 0 - -+#/dev/fd1u2880 b 640 0 0 2 33 0 0 - -+ -+# All the proprietary cdrom devices in the world -+#/dev/aztcd b 640 0 0 29 0 0 0 - -+#/dev/bpcd b 640 0 0 41 0 0 0 - -+#/dev/capi20 c 640 0 0 68 0 0 1 2 -+#/dev/cdu31a b 640 0 0 15 0 0 0 - -+#/dev/cdu535 b 640 0 0 24 0 0 0 - -+#/dev/cm206cd b 640 0 0 32 0 0 0 - -+#/dev/sjcd b 640 0 0 18 0 0 0 - -+#/dev/sonycd b 640 0 0 15 0 0 0 - -+#/dev/gscd b 640 0 0 16 0 0 0 - -+#/dev/sbpcd b 640 0 0 25 0 0 0 - -+#/dev/sbpcd b 640 0 0 25 0 0 1 4 -+#/dev/mcd b 640 0 0 23 0 0 0 - -+#/dev/optcd b 640 0 0 17 0 0 0 - -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/doc_loadbios.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/doc_loadbios.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,148 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+unsigned char databuf[512]; -+ -+int main(int argc,char **argv) -+{ -+ mtd_info_t meminfo; -+ int ifd,ofd; -+ struct stat statbuf; -+ erase_info_t erase; -+ unsigned long retlen, ofs, iplsize, ipltailsize; -+ unsigned char *iplbuf; -+ iplbuf = NULL; -+ -+ if (argc < 3) { -+ fprintf(stderr,"You must specify a device," -+ " the source firmware file and the offset\n"); -+ return 1; -+ } -+ -+ // Open and size the device -+ if ((ofd = open(argv[1],O_RDWR)) < 0) { -+ perror("Open flash device"); -+ return 1; -+ } -+ -+ if ((ifd = open(argv[2], O_RDONLY)) < 0) { -+ perror("Open firmware file\n"); -+ close(ofd); -+ return 1; -+ } -+ -+ if (fstat(ifd, &statbuf) != 0) { -+ perror("Stat firmware file"); -+ goto error; -+ } -+ -+#if 0 -+ if (statbuf.st_size > 65536) { -+ printf("Firmware too large (%ld bytes)\n",statbuf.st_size); -+ goto error; -+ } -+#endif -+ -+ if (ioctl(ofd,MEMGETINFO,&meminfo) != 0) { -+ perror("ioctl(MEMGETINFO)"); -+ goto error; -+ } -+ -+ iplsize = (ipltailsize = 0); -+ if (argc >= 4) { -+ /* DoC Millennium has IPL in the first 1K of flash memory */ -+ /* You may want to specify the offset 1024 to store -+ the firmware next to IPL. */ -+ iplsize = strtoul(argv[3], NULL, 0); -+ ipltailsize = iplsize % meminfo.erasesize; -+ } -+ -+ if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) { -+ perror("lseek"); -+ goto error; -+ } -+ -+ if (ipltailsize) { -+ iplbuf = malloc(ipltailsize); -+ if (iplbuf == NULL) { -+ fprintf(stderr, "Not enough memory for IPL tail buffer of" -+ " %lu bytes\n", (unsigned long) ipltailsize); -+ goto error; -+ } -+ printf("Reading IPL%s area of length %lu at offset %lu\n", -+ (iplsize - ipltailsize) ? " tail" : "", -+ (long unsigned) ipltailsize, -+ (long unsigned) (iplsize - ipltailsize)); -+ if (read(ofd, iplbuf, ipltailsize) != ipltailsize) { -+ perror("read"); -+ goto error; -+ } -+ } -+ -+ erase.length = meminfo.erasesize; -+ -+ for (ofs = iplsize - ipltailsize ; -+ ofs < iplsize + statbuf.st_size ; -+ ofs += meminfo.erasesize) { -+ erase.start = ofs; -+ printf("Performing Flash Erase of length %lu at offset %lu\n", -+ (long unsigned) erase.length, (long unsigned) erase.start); -+ -+ if (ioctl(ofd,MEMERASE,&erase) != 0) { -+ perror("ioctl(MEMERASE)"); -+ goto error; -+ } -+ } -+ -+ if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) { -+ perror("lseek"); -+ goto error; -+ } -+ -+ if (ipltailsize) { -+ printf("Writing IPL%s area of length %lu at offset %lu\n", -+ (iplsize - ipltailsize) ? " tail" : "", -+ (long unsigned) ipltailsize, -+ (long unsigned) (iplsize - ipltailsize)); -+ if (write(ofd, iplbuf, ipltailsize) != ipltailsize) { -+ perror("write"); -+ goto error; -+ } -+ } -+ -+ printf("Writing the firmware of length %lu at %lu... ", -+ (unsigned long) statbuf.st_size, -+ (unsigned long) iplsize); -+ do { -+ retlen = read(ifd, databuf, 512); -+ if (retlen < 512) -+ memset(databuf+retlen, 0xff, 512-retlen); -+ if (write(ofd, databuf, 512) != 512) { -+ perror("write"); -+ goto error; -+ } -+ } while (retlen == 512); -+ printf("Done.\n"); -+ -+ if (iplbuf != NULL) -+ free(iplbuf); -+ close(ifd); -+ close(ofd); -+ return 0; -+ -+error: -+ if (iplbuf != NULL) -+ free(iplbuf); -+ close(ifd); -+ close(ofd); -+ return 1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/docfdisk.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/docfdisk.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,317 @@ -+/* -+ * docfdisk.c: Modify INFTL partition tables -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#define _XOPEN_SOURCE 500 /* for pread/pwrite */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+unsigned char *buf; -+ -+mtd_info_t meminfo; -+erase_info_t erase; -+int fd; -+struct INFTLMediaHeader *mh; -+ -+#define MAXSCAN 10 -+ -+void show_header(int mhoffs) { -+ int i, unitsize, numunits, bmbits, numpart; -+ int start, end, num, nextunit; -+ unsigned int flags; -+ struct INFTLPartition *ip; -+ -+ bmbits = le32_to_cpu(mh->BlockMultiplierBits); -+ printf(" bootRecordID = %s\n" -+ " NoOfBootImageBlocks = %d\n" -+ " NoOfBinaryPartitions = %d\n" -+ " NoOfBDTLPartitions = %d\n" -+ " BlockMultiplierBits = %d\n" -+ " FormatFlags = %d\n" -+ " OsakVersion = %d.%d.%d.%d\n" -+ " PercentUsed = %d\n", -+ mh->bootRecordID, le32_to_cpu(mh->NoOfBootImageBlocks), -+ le32_to_cpu(mh->NoOfBinaryPartitions), -+ le32_to_cpu(mh->NoOfBDTLPartitions), -+ bmbits, -+ le32_to_cpu(mh->FormatFlags), -+ ((unsigned char *) &mh->OsakVersion)[0] & 0xf, -+ ((unsigned char *) &mh->OsakVersion)[1] & 0xf, -+ ((unsigned char *) &mh->OsakVersion)[2] & 0xf, -+ ((unsigned char *) &mh->OsakVersion)[3] & 0xf, -+ le32_to_cpu(mh->PercentUsed)); -+ -+ numpart = le32_to_cpu(mh->NoOfBinaryPartitions) + -+ le32_to_cpu(mh->NoOfBDTLPartitions); -+ unitsize = meminfo.erasesize >> bmbits; -+ numunits = meminfo.size / unitsize; -+ nextunit = mhoffs / unitsize; -+ nextunit++; -+ printf("Unitsize is %d bytes. Device has %d units.\n", -+ unitsize, numunits); -+ if (numunits > 32768) { -+ printf("WARNING: More than 32768 units! Unexpectedly small BlockMultiplierBits.\n"); -+ } -+ if (bmbits && (numunits <= 16384)) { -+ printf("NOTICE: Unexpectedly large BlockMultiplierBits.\n"); -+ } -+ for (i = 0; i < 4; i++) { -+ ip = &(mh->Partitions[i]); -+ flags = le32_to_cpu(ip->flags); -+ start = le32_to_cpu(ip->firstUnit); -+ end = le32_to_cpu(ip->lastUnit); -+ num = le32_to_cpu(ip->virtualUnits); -+ if (start < nextunit) { -+ printf("ERROR: Overlapping or misordered partitions!\n"); -+ } -+ if (start > nextunit) { -+ printf(" Unpartitioned space: %d bytes\n" -+ " virtualUnits = %d\n" -+ " firstUnit = %d\n" -+ " lastUnit = %d\n", -+ (start - nextunit) * unitsize, start - nextunit, -+ nextunit, start - 1); -+ } -+ if (flags & INFTL_BINARY) -+ printf(" Partition %d (BDK):", i+1); -+ else -+ printf(" Partition %d (BDTL):", i+1); -+ printf(" %d bytes\n" -+ " virtualUnits = %d\n" -+ " firstUnit = %d\n" -+ " lastUnit = %d\n" -+ " flags = 0x%x\n" -+ " spareUnits = %d\n", -+ num * unitsize, num, start, end, -+ le32_to_cpu(ip->flags), le32_to_cpu(ip->spareUnits)); -+ if (num > (1 + end - start)) { -+ printf("ERROR: virtualUnits not consistent with first/lastUnit!\n"); -+ } -+ end++; -+ if (end > nextunit) -+ nextunit = end; -+ if (flags & INFTL_LAST) -+ break; -+ } -+ if (i >= 4) { -+ printf("Odd. Last partition was not marked with INFTL_LAST.\n"); -+ i--; -+ } -+ if ((i+1) != numpart) { -+ printf("ERROR: Number of partitions != (NoOfBinaryPartitions + NoOfBDTLPartitions)\n"); -+ } -+ if (nextunit > numunits) { -+ printf("ERROR: Partitions appear to extend beyond end of device!\n"); -+ } -+ if (nextunit < numunits) { -+ printf(" Unpartitioned space: %d bytes\n" -+ " virtualUnits = %d\n" -+ " firstUnit = %d\n" -+ " lastUnit = %d\n", -+ (numunits - nextunit) * unitsize, numunits - nextunit, -+ nextunit, numunits - 1); -+ } -+} -+ -+ -+int main(int argc, char **argv) -+{ -+ int ret, i, mhblock, unitsize, block; -+ unsigned int nblocks[4], npart; -+ unsigned int totblocks; -+ struct INFTLPartition *ip; -+ unsigned char *oobbuf; -+ struct mtd_oob_buf oob; -+ char line[20]; -+ int mhoffs; -+ struct INFTLMediaHeader *mh2; -+ -+ if (argc < 2) { -+ printf( -+ "Usage: %s [ [ [ [ 4) { -+ printf("Max 4 partitions allowed.\n"); -+ return 1; -+ } -+ -+ for (i = 0; i < npart; i++) { -+ nblocks[i] = strtoul(argv[2+i], NULL, 0); -+ if (i && !nblocks[i-1]) { -+ printf("No sizes allowed after 0\n"); -+ return 1; -+ } -+ } -+ -+ // Open and size the device -+ if ((fd = open(argv[1], O_RDWR)) < 0) { -+ perror("Open flash device"); -+ return 1; -+ } -+ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("ioctl(MEMGETINFO)"); -+ return 1; -+ } -+ -+ printf("Device size is %d bytes. Erasesize is %d bytes.\n", -+ meminfo.size, meminfo.erasesize); -+ -+ buf = malloc(meminfo.erasesize); -+ oobbuf = malloc((meminfo.erasesize / meminfo.writesize) * meminfo.oobsize); -+ if (!buf || !oobbuf) { -+ printf("Can't malloc block buffer\n"); -+ return 1; -+ } -+ oob.length = meminfo.oobsize; -+ -+ mh = (struct INFTLMediaHeader *) buf; -+ -+ for (mhblock = 0; mhblock < MAXSCAN; mhblock++) { -+ if ((ret = pread(fd, buf, meminfo.erasesize, mhblock * meminfo.erasesize)) < 0) { -+ if (errno == EBADMSG) { -+ printf("ECC error at eraseblock %d\n", mhblock); -+ continue; -+ } -+ perror("Read eraseblock"); -+ return 1; -+ } -+ if (ret != meminfo.erasesize) { -+ printf("Short read!\n"); -+ return 1; -+ } -+ if (!strcmp("BNAND", mh->bootRecordID)) break; -+ } -+ if (mhblock >= MAXSCAN) { -+ printf("Unable to find INFTL Media Header\n"); -+ return 1; -+ } -+ printf("Found INFTL Media Header at block %d:\n", mhblock); -+ mhoffs = mhblock * meminfo.erasesize; -+ -+ oob.ptr = oobbuf; -+ oob.start = mhoffs; -+ for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) { -+ if (ioctl(fd, MEMREADOOB, &oob)) { -+ perror("ioctl(MEMREADOOB)"); -+ return 1; -+ } -+ oob.start += meminfo.writesize; -+ oob.ptr += meminfo.oobsize; -+ } -+ -+ show_header(mhoffs); -+ -+ if (!npart) -+ return 0; -+ -+ printf("\n" -+ "-------------------------------------------------------------------------\n"); -+ -+ unitsize = meminfo.erasesize >> le32_to_cpu(mh->BlockMultiplierBits); -+ totblocks = meminfo.size / unitsize; -+ block = mhoffs / unitsize; -+ block++; -+ -+ mh->NoOfBDTLPartitions = 0; -+ mh->NoOfBinaryPartitions = npart; -+ -+ for (i = 0; i < npart; i++) { -+ ip = &(mh->Partitions[i]); -+ ip->firstUnit = cpu_to_le32(block); -+ if (!nblocks[i]) -+ nblocks[i] = totblocks - block; -+ ip->virtualUnits = cpu_to_le32(nblocks[i]); -+ block += nblocks[i]; -+ ip->lastUnit = cpu_to_le32(block-1); -+ ip->spareUnits = 0; -+ ip->flags = cpu_to_le32(INFTL_BINARY); -+ } -+ if (block > totblocks) { -+ printf("Requested partitions extend beyond end of device.\n"); -+ return 1; -+ } -+ ip->flags = cpu_to_le32(INFTL_BINARY | INFTL_LAST); -+ -+ /* update the spare as well */ -+ mh2 = (struct INFTLMediaHeader *) (buf + 4096); -+ memcpy((void *) mh2, (void *) mh, sizeof(struct INFTLMediaHeader)); -+ -+ printf("\nProposed new Media Header:\n"); -+ show_header(mhoffs); -+ -+ printf("\nReady to update device. Type 'yes' to proceed, anything else to abort: "); -+ fgets(line, sizeof(line), stdin); -+ if (strcmp("yes\n", line)) -+ return 0; -+ printf("Updating MediaHeader...\n"); -+ -+ erase.start = mhoffs; -+ erase.length = meminfo.erasesize; -+ if (ioctl(fd, MEMERASE, &erase)) { -+ perror("ioctl(MEMERASE)"); -+ printf("Your MediaHeader may be hosed. UHOH!\n"); -+ return 1; -+ } -+ -+ oob.ptr = oobbuf; -+ oob.start = mhoffs; -+ for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) { -+ memset(oob.ptr, 0xff, 6); // clear ECC. -+ if (ioctl(fd, MEMWRITEOOB, &oob)) { -+ perror("ioctl(MEMWRITEOOB)"); -+ printf("Your MediaHeader may be hosed. UHOH!\n"); -+ return 1; -+ } -+ if ((ret = pwrite(fd, buf, meminfo.writesize, oob.start)) < 0) { -+ perror("Write page"); -+ printf("Your MediaHeader may be hosed. UHOH!\n"); -+ return 1; -+ } -+ if (ret != meminfo.writesize) { -+ printf("Short write!\n"); -+ printf("Your MediaHeader may be hosed. UHOH!\n"); -+ return 1; -+ } -+ -+ oob.start += meminfo.writesize; -+ oob.ptr += meminfo.oobsize; -+ buf += meminfo.writesize; -+ } -+ -+ printf("Success. REBOOT or unload the diskonchip module to update partitions!\n"); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/feature-removal-schedule.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/feature-removal-schedule.txt 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,9 @@ -+The following is a list of files and features that are going to be -+removed in the mtd-utils source tree. Every entry should contain what -+exactly is going away, why it is happening, and who is going to be doing -+the work. When the feature is removed from the utils, it should also -+be removed from this file. -+ -+--------------------------- -+ -+--------------------------- ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/fec.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/fec.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,917 @@ -+/* -+ * fec.c -- forward error correction based on Vandermonde matrices -+ * 980624 -+ * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it) -+ * -+ * Portions derived from code by Phil Karn (karn@ka9q.ampr.org), -+ * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari -+ * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995 -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND -+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS -+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ */ -+ -+/* -+ * The following parameter defines how many bits are used for -+ * field elements. The code supports any value from 2 to 16 -+ * but fastest operation is achieved with 8 bit elements -+ * This is the only parameter you may want to change. -+ */ -+#ifndef GF_BITS -+#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */ -+#endif -+ -+#include -+#include -+#include -+ -+/* -+ * compatibility stuff -+ */ -+#ifdef MSDOS /* but also for others, e.g. sun... */ -+#define NEED_BCOPY -+#define bcmp(a,b,n) memcmp(a,b,n) -+#endif -+ -+#ifdef NEED_BCOPY -+#define bcopy(s, d, siz) memcpy((d), (s), (siz)) -+#define bzero(d, siz) memset((d), '\0', (siz)) -+#endif -+ -+/* -+ * stuff used for testing purposes only -+ */ -+ -+#ifdef TEST -+#define DEB(x) -+#define DDB(x) x -+#define DEBUG 0 /* minimal debugging */ -+#ifdef MSDOS -+#include -+struct timeval { -+ unsigned long ticks; -+}; -+#define gettimeofday(x, dummy) { (x)->ticks = clock() ; } -+#define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC ) -+typedef unsigned long u_long ; -+typedef unsigned short u_short ; -+#else /* typically, unix systems */ -+#include -+#define DIFF_T(a,b) \ -+ (1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) ) -+#endif -+ -+#define TICK(t) \ -+ {struct timeval x ; \ -+ gettimeofday(&x, NULL) ; \ -+ t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \ -+ } -+#define TOCK(t) \ -+ { u_long t1 ; TICK(t1) ; \ -+ if (t1 < t) t = 256000000 + t1 - t ; \ -+ else t = t1 - t ; \ -+ if (t == 0) t = 1 ;} -+ -+u_long ticks[10]; /* vars for timekeeping */ -+#else -+#define DEB(x) -+#define DDB(x) -+#define TICK(x) -+#define TOCK(x) -+#endif /* TEST */ -+ -+/* -+ * You should not need to change anything beyond this point. -+ * The first part of the file implements linear algebra in GF. -+ * -+ * gf is the type used to store an element of the Galois Field. -+ * Must constain at least GF_BITS bits. -+ * -+ * Note: unsigned char will work up to GF(256) but int seems to run -+ * faster on the Pentium. We use int whenever have to deal with an -+ * index, since they are generally faster. -+ */ -+#if (GF_BITS < 2 && GF_BITS >16) -+#error "GF_BITS must be 2 .. 16" -+#endif -+#if (GF_BITS <= 8) -+typedef unsigned char gf; -+#else -+typedef unsigned short gf; -+#endif -+ -+#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */ -+ -+/* -+ * Primitive polynomials - see Lin & Costello, Appendix A, -+ * and Lee & Messerschmitt, p. 453. -+ */ -+static char *allPp[] = { /* GF_BITS polynomial */ -+ NULL, /* 0 no code */ -+ NULL, /* 1 no code */ -+ "111", /* 2 1+x+x^2 */ -+ "1101", /* 3 1+x+x^3 */ -+ "11001", /* 4 1+x+x^4 */ -+ "101001", /* 5 1+x^2+x^5 */ -+ "1100001", /* 6 1+x+x^6 */ -+ "10010001", /* 7 1 + x^3 + x^7 */ -+ "101110001", /* 8 1+x^2+x^3+x^4+x^8 */ -+ "1000100001", /* 9 1+x^4+x^9 */ -+ "10010000001", /* 10 1+x^3+x^10 */ -+ "101000000001", /* 11 1+x^2+x^11 */ -+ "1100101000001", /* 12 1+x+x^4+x^6+x^12 */ -+ "11011000000001", /* 13 1+x+x^3+x^4+x^13 */ -+ "110000100010001", /* 14 1+x+x^6+x^10+x^14 */ -+ "1100000000000001", /* 15 1+x+x^15 */ -+ "11010000000010001" /* 16 1+x+x^3+x^12+x^16 */ -+}; -+ -+ -+/* -+ * To speed up computations, we have tables for logarithm, exponent -+ * and inverse of a number. If GF_BITS <= 8, we use a table for -+ * multiplication as well (it takes 64K, no big deal even on a PDA, -+ * especially because it can be pre-initialized an put into a ROM!), -+ * otherwhise we use a table of logarithms. -+ * In any case the macro gf_mul(x,y) takes care of multiplications. -+ */ -+ -+static gf gf_exp[2*GF_SIZE]; /* index->poly form conversion table */ -+static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */ -+static gf inverse[GF_SIZE+1]; /* inverse of field elem. */ -+ /* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */ -+ -+/* -+ * modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, -+ * without a slow divide. -+ */ -+static inline gf -+modnn(int x) -+{ -+ while (x >= GF_SIZE) { -+ x -= GF_SIZE; -+ x = (x >> GF_BITS) + (x & GF_SIZE); -+ } -+ return x; -+} -+ -+#define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;} -+ -+/* -+ * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much -+ * faster to use a multiplication table. -+ * -+ * USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying -+ * many numbers by the same constant. In this case the first -+ * call sets the constant, and others perform the multiplications. -+ * A value related to the multiplication is held in a local variable -+ * declared with USE_GF_MULC . See usage in addmul1(). -+ */ -+#if (GF_BITS <= 8) -+static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1]; -+ -+#define gf_mul(x,y) gf_mul_table[x][y] -+ -+#define USE_GF_MULC register gf * __gf_mulc_ -+#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c] -+#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x] -+ -+static void -+init_mul_table() -+{ -+ int i, j; -+ for (i=0; i< GF_SIZE+1; i++) -+ for (j=0; j< GF_SIZE+1; j++) -+ gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j]) ] ; -+ -+ for (j=0; j< GF_SIZE+1; j++) -+ gf_mul_table[0][j] = gf_mul_table[j][0] = 0; -+} -+#else /* GF_BITS > 8 */ -+static inline gf -+gf_mul(x,y) -+{ -+ if ( (x) == 0 || (y)==0 ) return 0; -+ -+ return gf_exp[gf_log[x] + gf_log[y] ] ; -+} -+#define init_mul_table() -+ -+#define USE_GF_MULC register gf * __gf_mulc_ -+#define GF_MULC0(c) __gf_mulc_ = &gf_exp[ gf_log[c] ] -+#define GF_ADDMULC(dst, x) { if (x) dst ^= __gf_mulc_[ gf_log[x] ] ; } -+#endif -+ -+/* -+ * Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] -+ * Lookup tables: -+ * index->polynomial form gf_exp[] contains j= \alpha^i; -+ * polynomial form -> index form gf_log[ j = \alpha^i ] = i -+ * \alpha=x is the primitive element of GF(2^m) -+ * -+ * For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple -+ * multiplication of two numbers can be resolved without calling modnn -+ */ -+ -+/* -+ * i use malloc so many times, it is easier to put checks all in -+ * one place. -+ */ -+static void * -+my_malloc(int sz, char *err_string) -+{ -+ void *p = malloc( sz ); -+ if (p == NULL) { -+ fprintf(stderr, "-- malloc failure allocating %s\n", err_string); -+ exit(1) ; -+ } -+ return p ; -+} -+ -+#define NEW_GF_MATRIX(rows, cols) \ -+ (gf *)my_malloc(rows * cols * sizeof(gf), " ## __LINE__ ## " ) -+ -+/* -+ * initialize the data structures used for computations in GF. -+ */ -+static void -+generate_gf(void) -+{ -+ int i; -+ gf mask; -+ char *Pp = allPp[GF_BITS] ; -+ -+ mask = 1; /* x ** 0 = 1 */ -+ gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */ -+ /* -+ * first, generate the (polynomial representation of) powers of \alpha, -+ * which are stored in gf_exp[i] = \alpha ** i . -+ * At the same time build gf_log[gf_exp[i]] = i . -+ * The first GF_BITS powers are simply bits shifted to the left. -+ */ -+ for (i = 0; i < GF_BITS; i++, mask <<= 1 ) { -+ gf_exp[i] = mask; -+ gf_log[gf_exp[i]] = i; -+ /* -+ * If Pp[i] == 1 then \alpha ** i occurs in poly-repr -+ * gf_exp[GF_BITS] = \alpha ** GF_BITS -+ */ -+ if ( Pp[i] == '1' ) -+ gf_exp[GF_BITS] ^= mask; -+ } -+ /* -+ * now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als -+ * compute its inverse. -+ */ -+ gf_log[gf_exp[GF_BITS]] = GF_BITS; -+ /* -+ * Poly-repr of \alpha ** (i+1) is given by poly-repr of -+ * \alpha ** i shifted left one-bit and accounting for any -+ * \alpha ** GF_BITS term that may occur when poly-repr of -+ * \alpha ** i is shifted. -+ */ -+ mask = 1 << (GF_BITS - 1 ) ; -+ for (i = GF_BITS + 1; i < GF_SIZE; i++) { -+ if (gf_exp[i - 1] >= mask) -+ gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1); -+ else -+ gf_exp[i] = gf_exp[i - 1] << 1; -+ gf_log[gf_exp[i]] = i; -+ } -+ /* -+ * log(0) is not defined, so use a special value -+ */ -+ gf_log[0] = GF_SIZE ; -+ /* set the extended gf_exp values for fast multiply */ -+ for (i = 0 ; i < GF_SIZE ; i++) -+ gf_exp[i + GF_SIZE] = gf_exp[i] ; -+ -+ /* -+ * again special cases. 0 has no inverse. This used to -+ * be initialized to GF_SIZE, but it should make no difference -+ * since noone is supposed to read from here. -+ */ -+ inverse[0] = 0 ; -+ inverse[1] = 1; -+ for (i=2; i<=GF_SIZE; i++) -+ inverse[i] = gf_exp[GF_SIZE-gf_log[i]]; -+} -+ -+/* -+ * Various linear algebra operations that i use often. -+ */ -+ -+/* -+ * addmul() computes dst[] = dst[] + c * src[] -+ * This is used often, so better optimize it! Currently the loop is -+ * unrolled 16 times, a good value for 486 and pentium-class machines. -+ * The case c=0 is also optimized, whereas c=1 is not. These -+ * calls are unfrequent in my typical apps so I did not bother. -+ * -+ * Note that gcc on -+ */ -+#define addmul(dst, src, c, sz) \ -+ if (c != 0) addmul1(dst, src, c, sz) -+ -+#define UNROLL 16 /* 1, 4, 8, 16 */ -+static void -+addmul1(gf *dst1, gf *src1, gf c, int sz) -+{ -+ USE_GF_MULC ; -+ register gf *dst = dst1, *src = src1 ; -+ gf *lim = &dst[sz - UNROLL + 1] ; -+ -+ GF_MULC0(c) ; -+ -+#if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */ -+ for (; dst < lim ; dst += UNROLL, src += UNROLL ) { -+ GF_ADDMULC( dst[0] , src[0] ); -+ GF_ADDMULC( dst[1] , src[1] ); -+ GF_ADDMULC( dst[2] , src[2] ); -+ GF_ADDMULC( dst[3] , src[3] ); -+#if (UNROLL > 4) -+ GF_ADDMULC( dst[4] , src[4] ); -+ GF_ADDMULC( dst[5] , src[5] ); -+ GF_ADDMULC( dst[6] , src[6] ); -+ GF_ADDMULC( dst[7] , src[7] ); -+#endif -+#if (UNROLL > 8) -+ GF_ADDMULC( dst[8] , src[8] ); -+ GF_ADDMULC( dst[9] , src[9] ); -+ GF_ADDMULC( dst[10] , src[10] ); -+ GF_ADDMULC( dst[11] , src[11] ); -+ GF_ADDMULC( dst[12] , src[12] ); -+ GF_ADDMULC( dst[13] , src[13] ); -+ GF_ADDMULC( dst[14] , src[14] ); -+ GF_ADDMULC( dst[15] , src[15] ); -+#endif -+ } -+#endif -+ lim += UNROLL - 1 ; -+ for (; dst < lim; dst++, src++ ) /* final components */ -+ GF_ADDMULC( *dst , *src ); -+} -+ -+/* -+ * computes C = AB where A is n*k, B is k*m, C is n*m -+ */ -+static void -+matmul(gf *a, gf *b, gf *c, int n, int k, int m) -+{ -+ int row, col, i ; -+ -+ for (row = 0; row < n ; row++) { -+ for (col = 0; col < m ; col++) { -+ gf *pa = &a[ row * k ]; -+ gf *pb = &b[ col ]; -+ gf acc = 0 ; -+ for (i = 0; i < k ; i++, pa++, pb += m ) -+ acc ^= gf_mul( *pa, *pb ) ; -+ c[ row * m + col ] = acc ; -+ } -+ } -+} -+ -+#ifdef DEBUG -+/* -+ * returns 1 if the square matrix is identiy -+ * (only for test) -+ */ -+static int -+is_identity(gf *m, int k) -+{ -+ int row, col ; -+ for (row=0; row 1) { -+ fprintf(stderr, "singular matrix\n"); -+ goto fail ; -+ } -+ } -+ } -+ } -+ if (icol == -1) { -+ fprintf(stderr, "XXX pivot not found!\n"); -+ goto fail ; -+ } -+found_piv: -+ ++(ipiv[icol]) ; -+ /* -+ * swap rows irow and icol, so afterwards the diagonal -+ * element will be correct. Rarely done, not worth -+ * optimizing. -+ */ -+ if (irow != icol) { -+ for (ix = 0 ; ix < k ; ix++ ) { -+ SWAP( src[irow*k + ix], src[icol*k + ix], gf) ; -+ } -+ } -+ indxr[col] = irow ; -+ indxc[col] = icol ; -+ pivot_row = &src[icol*k] ; -+ c = pivot_row[icol] ; -+ if (c == 0) { -+ fprintf(stderr, "singular matrix 2\n"); -+ goto fail ; -+ } -+ if (c != 1 ) { /* otherwhise this is a NOP */ -+ /* -+ * this is done often , but optimizing is not so -+ * fruitful, at least in the obvious ways (unrolling) -+ */ -+ DEB( pivswaps++ ; ) -+ c = inverse[ c ] ; -+ pivot_row[icol] = 1 ; -+ for (ix = 0 ; ix < k ; ix++ ) -+ pivot_row[ix] = gf_mul(c, pivot_row[ix] ); -+ } -+ /* -+ * from all rows, remove multiples of the selected row -+ * to zero the relevant entry (in fact, the entry is not zero -+ * because we know it must be zero). -+ * (Here, if we know that the pivot_row is the identity, -+ * we can optimize the addmul). -+ */ -+ id_row[icol] = 1; -+ if (bcmp(pivot_row, id_row, k*sizeof(gf)) != 0) { -+ for (p = src, ix = 0 ; ix < k ; ix++, p += k ) { -+ if (ix != icol) { -+ c = p[icol] ; -+ p[icol] = 0 ; -+ addmul(p, pivot_row, c, k ); -+ } -+ } -+ } -+ id_row[icol] = 0; -+ } /* done all columns */ -+ for (col = k-1 ; col >= 0 ; col-- ) { -+ if (indxr[col] <0 || indxr[col] >= k) -+ fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]); -+ else if (indxc[col] <0 || indxc[col] >= k) -+ fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]); -+ else -+ if (indxr[col] != indxc[col] ) { -+ for (row = 0 ; row < k ; row++ ) { -+ SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ; -+ } -+ } -+ } -+ error = 0 ; -+fail: -+ free(indxc); -+ free(indxr); -+ free(ipiv); -+ free(id_row); -+ free(temp_row); -+ return error ; -+} -+ -+/* -+ * fast code for inverting a vandermonde matrix. -+ * XXX NOTE: It assumes that the matrix -+ * is not singular and _IS_ a vandermonde matrix. Only uses -+ * the second column of the matrix, containing the p_i's. -+ * -+ * Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but -+ * largely revised for my purposes. -+ * p = coefficients of the matrix (p_i) -+ * q = values of the polynomial (known) -+ */ -+ -+int -+invert_vdm(gf *src, int k) -+{ -+ int i, j, row, col ; -+ gf *b, *c, *p; -+ gf t, xx ; -+ -+ if (k == 1) /* degenerate case, matrix must be p^0 = 1 */ -+ return 0 ; -+ /* -+ * c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1 -+ * b holds the coefficient for the matrix inversion -+ */ -+ c = NEW_GF_MATRIX(1, k); -+ b = NEW_GF_MATRIX(1, k); -+ -+ p = NEW_GF_MATRIX(1, k); -+ -+ for ( j=1, i = 0 ; i < k ; i++, j+=k ) { -+ c[i] = 0 ; -+ p[i] = src[j] ; /* p[i] */ -+ } -+ /* -+ * construct coeffs. recursively. We know c[k] = 1 (implicit) -+ * and start P_0 = x - p_0, then at each stage multiply by -+ * x - p_i generating P_i = x P_{i-1} - p_i P_{i-1} -+ * After k steps we are done. -+ */ -+ c[k-1] = p[0] ; /* really -p(0), but x = -x in GF(2^m) */ -+ for (i = 1 ; i < k ; i++ ) { -+ gf p_i = p[i] ; /* see above comment */ -+ for (j = k-1 - ( i - 1 ) ; j < k-1 ; j++ ) -+ c[j] ^= gf_mul( p_i, c[j+1] ) ; -+ c[k-1] ^= p_i ; -+ } -+ -+ for (row = 0 ; row < k ; row++ ) { -+ /* -+ * synthetic division etc. -+ */ -+ xx = p[row] ; -+ t = 1 ; -+ b[k-1] = 1 ; /* this is in fact c[k] */ -+ for (i = k-2 ; i >= 0 ; i-- ) { -+ b[i] = c[i+1] ^ gf_mul(xx, b[i+1]) ; -+ t = gf_mul(xx, t) ^ b[i] ; -+ } -+ for (col = 0 ; col < k ; col++ ) -+ src[col*k + row] = gf_mul(inverse[t], b[col] ); -+ } -+ free(c) ; -+ free(b) ; -+ free(p) ; -+ return 0 ; -+} -+ -+static int fec_initialized = 0 ; -+static void -+init_fec() -+{ -+ TICK(ticks[0]); -+ generate_gf(); -+ TOCK(ticks[0]); -+ DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);) -+ TICK(ticks[0]); -+ init_mul_table(); -+ TOCK(ticks[0]); -+ DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);) -+ fec_initialized = 1 ; -+} -+ -+/* -+ * This section contains the proper FEC encoding/decoding routines. -+ * The encoding matrix is computed starting with a Vandermonde matrix, -+ * and then transforming it into a systematic matrix. -+ */ -+ -+#define FEC_MAGIC 0xFECC0DEC -+ -+struct fec_parms { -+ u_long magic ; -+ int k, n ; /* parameters of the code */ -+ gf *enc_matrix ; -+} ; -+ -+void -+fec_free(struct fec_parms *p) -+{ -+ if (p==NULL || -+ p->magic != ( ( (FEC_MAGIC ^ p->k) ^ p->n) ^ (int)(p->enc_matrix)) ) { -+ fprintf(stderr, "bad parameters to fec_free\n"); -+ return ; -+ } -+ free(p->enc_matrix); -+ free(p); -+} -+ -+/* -+ * create a new encoder, returning a descriptor. This contains k,n and -+ * the encoding matrix. -+ */ -+struct fec_parms * -+fec_new(int k, int n) -+{ -+ int row, col ; -+ gf *p, *tmp_m ; -+ -+ struct fec_parms *retval ; -+ -+ if (fec_initialized == 0) -+ init_fec(); -+ -+ if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n ) { -+ fprintf(stderr, "Invalid parameters k %d n %d GF_SIZE %d\n", -+ k, n, GF_SIZE ); -+ return NULL ; -+ } -+ retval = my_malloc(sizeof(struct fec_parms), "new_code"); -+ retval->k = k ; -+ retval->n = n ; -+ retval->enc_matrix = NEW_GF_MATRIX(n, k); -+ retval->magic = ( ( FEC_MAGIC ^ k) ^ n) ^ (int)(retval->enc_matrix) ; -+ tmp_m = NEW_GF_MATRIX(n, k); -+ /* -+ * fill the matrix with powers of field elements, starting from 0. -+ * The first row is special, cannot be computed with exp. table. -+ */ -+ tmp_m[0] = 1 ; -+ for (col = 1; col < k ; col++) -+ tmp_m[col] = 0 ; -+ for (p = tmp_m + k, row = 0; row < n-1 ; row++, p += k) { -+ for ( col = 0 ; col < k ; col ++ ) -+ p[col] = gf_exp[modnn(row*col)]; -+ } -+ -+ /* -+ * quick code to build systematic matrix: invert the top -+ * k*k vandermonde matrix, multiply right the bottom n-k rows -+ * by the inverse, and construct the identity matrix at the top. -+ */ -+ TICK(ticks[3]); -+ invert_vdm(tmp_m, k); /* much faster than invert_mat */ -+ matmul(tmp_m + k*k, tmp_m, retval->enc_matrix + k*k, n - k, k, k); -+ /* -+ * the upper matrix is I so do not bother with a slow multiply -+ */ -+ bzero(retval->enc_matrix, k*k*sizeof(gf) ); -+ for (p = retval->enc_matrix, col = 0 ; col < k ; col++, p += k+1 ) -+ *p = 1 ; -+ free(tmp_m); -+ TOCK(ticks[3]); -+ -+ DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n", -+ ticks[3]);) -+ DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");) -+ return retval ; -+} -+ -+/* -+ * fec_encode accepts as input pointers to n data packets of size sz, -+ * and produces as output a packet pointed to by fec, computed -+ * with index "index". -+ */ -+void -+fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz) -+{ -+ int i, k = code->k ; -+ gf *p ; -+ -+ if (GF_BITS > 8) -+ sz /= 2 ; -+ -+ if (index < k) -+ bcopy(src[index], fec, sz*sizeof(gf) ) ; -+ else if (index < code->n) { -+ p = &(code->enc_matrix[index*k] ); -+ bzero(fec, sz*sizeof(gf)); -+ for (i = 0; i < k ; i++) -+ addmul(fec, src[i], p[i], sz ) ; -+ } else -+ fprintf(stderr, "Invalid index %d (max %d)\n", -+ index, code->n - 1 ); -+} -+ -+void fec_encode_linear(struct fec_parms *code, gf *src, gf *fec, int index, int sz) -+{ -+ int i, k = code->k ; -+ gf *p ; -+ -+ if (GF_BITS > 8) -+ sz /= 2 ; -+ -+ if (index < k) -+ bcopy(src + (index * sz), fec, sz*sizeof(gf) ) ; -+ else if (index < code->n) { -+ p = &(code->enc_matrix[index*k] ); -+ bzero(fec, sz*sizeof(gf)); -+ for (i = 0; i < k ; i++) -+ addmul(fec, src + (i * sz), p[i], sz ) ; -+ } else -+ fprintf(stderr, "Invalid index %d (max %d)\n", -+ index, code->n - 1 ); -+} -+/* -+ * shuffle move src packets in their position -+ */ -+static int -+shuffle(gf *pkt[], int index[], int k) -+{ -+ int i; -+ -+ for ( i = 0 ; i < k ; ) { -+ if (index[i] >= k || index[i] == i) -+ i++ ; -+ else { -+ /* -+ * put pkt in the right position (first check for conflicts). -+ */ -+ int c = index[i] ; -+ -+ if (index[c] == c) { -+ DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);) -+ return 1 ; -+ } -+ SWAP(index[i], index[c], int) ; -+ SWAP(pkt[i], pkt[c], gf *) ; -+ } -+ } -+ DEB( /* just test that it works... */ -+ for ( i = 0 ; i < k ; i++ ) { -+ if (index[i] < k && index[i] != i) { -+ fprintf(stderr, "shuffle: after\n"); -+ for (i=0; ik ; -+ gf *p, *matrix = NEW_GF_MATRIX(k, k); -+ -+ TICK(ticks[9]); -+ for (i = 0, p = matrix ; i < k ; i++, p += k ) { -+#if 1 /* this is simply an optimization, not very useful indeed */ -+ if (index[i] < k) { -+ bzero(p, k*sizeof(gf) ); -+ p[i] = 1 ; -+ } else -+#endif -+ if (index[i] < code->n ) -+ bcopy( &(code->enc_matrix[index[i]*k]), p, k*sizeof(gf) ); -+ else { -+ fprintf(stderr, "decode: invalid index %d (max %d)\n", -+ index[i], code->n - 1 ); -+ free(matrix) ; -+ return NULL ; -+ } -+ } -+ TICK(ticks[9]); -+ if (invert_mat(matrix, k)) { -+ free(matrix); -+ matrix = NULL ; -+ } -+ TOCK(ticks[9]); -+ return matrix ; -+} -+ -+/* -+ * fec_decode receives as input a vector of packets, the indexes of -+ * packets, and produces the correct vector as output. -+ * -+ * Input: -+ * code: pointer to code descriptor -+ * pkt: pointers to received packets. They are modified -+ * to store the output packets (in place) -+ * index: pointer to packet indexes (modified) -+ * sz: size of each packet -+ */ -+int -+fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz) -+{ -+ gf *m_dec ; -+ gf **new_pkt ; -+ int row, col , k = code->k ; -+ -+ if (GF_BITS > 8) -+ sz /= 2 ; -+ -+ if (shuffle(pkt, index, k)) /* error if true */ -+ return 1 ; -+ m_dec = build_decode_matrix(code, pkt, index); -+ -+ if (m_dec == NULL) -+ return 1 ; /* error */ -+ /* -+ * do the actual decoding -+ */ -+ new_pkt = my_malloc (k * sizeof (gf * ), "new pkt pointers" ); -+ for (row = 0 ; row < k ; row++ ) { -+ if (index[row] >= k) { -+ new_pkt[row] = my_malloc (sz * sizeof (gf), "new pkt buffer" ); -+ bzero(new_pkt[row], sz * sizeof(gf) ) ; -+ for (col = 0 ; col < k ; col++ ) -+ addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz) ; -+ } -+ } -+ /* -+ * move pkts to their final destination -+ */ -+ for (row = 0 ; row < k ; row++ ) { -+ if (index[row] >= k) { -+ bcopy(new_pkt[row], pkt[row], sz*sizeof(gf)); -+ free(new_pkt[row]); -+ } -+ } -+ free(new_pkt); -+ free(m_dec); -+ -+ return 0; -+} -+ -+/*********** end of FEC code -- beginning of test code ************/ -+ -+#if (TEST || DEBUG) -+void -+test_gf() -+{ -+ int i ; -+ /* -+ * test gf tables. Sufficiently tested... -+ */ -+ for (i=0; i<= GF_SIZE; i++) { -+ if (gf_exp[gf_log[i]] != i) -+ fprintf(stderr, "bad exp/log i %d log %d exp(log) %d\n", -+ i, gf_log[i], gf_exp[gf_log[i]]); -+ -+ if (i != 0 && gf_mul(i, inverse[i]) != 1) -+ fprintf(stderr, "bad mul/inv i %d inv %d i*inv(i) %d\n", -+ i, inverse[i], gf_mul(i, inverse[i]) ); -+ if (gf_mul(0,i) != 0) -+ fprintf(stderr, "bad mul table 0,%d\n",i); -+ if (gf_mul(i,0) != 0) -+ fprintf(stderr, "bad mul table %d,0\n",i); -+ } -+} -+#endif /* TEST */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/fectest.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/fectest.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,92 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mcast_image.h" -+#include "crc32.h" -+ -+#define ERASE_SIZE 131072 -+//#define PKT_SIZE 1400 -+#define NR_PKTS ((ERASE_SIZE + PKT_SIZE - 1) / PKT_SIZE) -+#define DROPS 8 -+ -+int main(void) -+{ -+ int i, j; -+ unsigned char buf[NR_PKTS * PKT_SIZE]; -+ unsigned char pktbuf[(NR_PKTS + DROPS) * PKT_SIZE]; -+ struct fec_parms *fec; -+ unsigned char *srcs[NR_PKTS]; -+ unsigned char *pkt[NR_PKTS + DROPS]; -+ int pktnr[NR_PKTS + DROPS]; -+ struct timeval then, now; -+ -+ srand(3453); -+ for (i=0; i < sizeof(buf); i++) -+ if (i < ERASE_SIZE) -+ buf[i] = rand(); -+ else -+ buf[i] = 0; -+ -+ for (i=0; i < NR_PKTS + DROPS; i++) -+ srcs[i] = buf + (i * PKT_SIZE); -+ -+ for (i=0; i < NR_PKTS + DROPS; i++) { -+ pkt[i] = malloc(PKT_SIZE); -+ pktnr[i] = -1; -+ } -+ fec = fec_new(NR_PKTS, NR_PKTS + DROPS); -+ if (!fec) { -+ printf("fec_init() failed\n"); -+ exit(1); -+ } -+ j = 0; -+ for (i=0; i < NR_PKTS + DROPS; i++) { -+#if 1 -+ if (i == 27 || i == 40 || i == 44 || i == 45 || i == 56 ) -+ continue; -+#endif -+ if (i == 69 || i == 93 || i == 103) -+ continue; -+ fec_encode(fec, srcs, pkt[j], i, PKT_SIZE); -+ pktnr[j] = i; -+ j++; -+ } -+ gettimeofday(&then, NULL); -+ if (fec_decode(fec, pkt, pktnr, PKT_SIZE)) { -+ printf("Decode failed\n"); -+ exit(1); -+ } -+ -+ for (i=0; i < NR_PKTS; i++) -+ memcpy(pktbuf + (i*PKT_SIZE), pkt[i], PKT_SIZE); -+ gettimeofday(&now, NULL); -+ now.tv_sec -= then.tv_sec; -+ now.tv_usec -= then.tv_usec; -+ if (now.tv_usec < 0) { -+ now.tv_usec += 1000000; -+ now.tv_sec--; -+ } -+ -+ if (memcmp(pktbuf, buf, ERASE_SIZE)) { -+ int fd; -+ printf("Compare failed\n"); -+ fd = open("before", O_WRONLY|O_TRUNC|O_CREAT, 0644); -+ if (fd >= 0) -+ write(fd, buf, ERASE_SIZE); -+ close(fd); -+ fd = open("after", O_WRONLY|O_TRUNC|O_CREAT, 0644); -+ if (fd >= 0) -+ write(fd, pktbuf, ERASE_SIZE); -+ -+ exit(1); -+ } -+ -+ printf("Decoded in %ld.%06lds\n", now.tv_sec, now.tv_usec); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_erase.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_erase.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,189 @@ -+/* -+ * flash_erase.c -- erase parts of a MTD device -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+int region_erase(int Fd, int start, int count, int unlock, int regcount) -+{ -+ int i, j; -+ region_info_t * reginfo; -+ -+ reginfo = calloc(regcount, sizeof(region_info_t)); -+ -+ for(i = 0; i < regcount; i++) -+ { -+ reginfo[i].regionindex = i; -+ if(ioctl(Fd,MEMGETREGIONINFO,&(reginfo[i])) != 0) -+ return 8; -+ else -+ printf("Region %d is at %d of %d sector and with sector " -+ "size %x\n", i, reginfo[i].offset, reginfo[i].numblocks, -+ reginfo[i].erasesize); -+ } -+ -+ // We have all the information about the chip we need. -+ -+ for(i = 0; i < regcount; i++) -+ { //Loop through the regions -+ region_info_t * r = &(reginfo[i]); -+ -+ if((start >= reginfo[i].offset) && -+ (start < (r->offset + r->numblocks*r->erasesize))) -+ break; -+ } -+ -+ if(i >= regcount) -+ { -+ printf("Starting offset %x not within chip.\n", start); -+ return 8; -+ } -+ -+ //We are now positioned within region i of the chip, so start erasing -+ //count sectors from there. -+ -+ for(j = 0; (j < count)&&(i < regcount); j++) -+ { -+ erase_info_t erase; -+ region_info_t * r = &(reginfo[i]); -+ -+ erase.start = start; -+ erase.length = r->erasesize; -+ -+ if(unlock != 0) -+ { //Unlock the sector first. -+ if(ioctl(Fd, MEMUNLOCK, &erase) != 0) -+ { -+ perror("\nMTD Unlock failure"); -+ close(Fd); -+ return 8; -+ } -+ } -+ printf("\rPerforming Flash Erase of length 0x%llx at offset 0x%llx", -+ erase.length, erase.start); -+ fflush(stdout); -+ if(ioctl(Fd, MEMERASE, &erase) != 0) -+ { -+ perror("\nMTD Erase failure"); -+ close(Fd); -+ return 8; -+ } -+ -+ -+ start += erase.length; -+ if(start >= (r->offset + r->numblocks*r->erasesize)) -+ { //We finished region i so move to region i+1 -+ printf("\nMoving to region %d\n", i+1); -+ i++; -+ } -+ } -+ -+ printf(" done\n"); -+ -+ return 0; -+} -+ -+int non_region_erase(int Fd, int start, int count, int unlock) -+{ -+ mtd_info_t meminfo; -+ -+ if (ioctl(Fd,MEMGETINFO,&meminfo) == 0) -+ { -+ erase_info_t erase; -+ -+ erase.start = start; -+ -+ erase.length = meminfo.erasesize; -+ -+ for (; count > 0; count--) { -+ printf("\rPerforming Flash Erase of length 0x%llx at offset 0x%llx", -+ erase.length, erase.start); -+ fflush(stdout); -+ -+ if(unlock != 0) -+ { -+ //Unlock the sector first. -+ printf("\rPerforming Flash unlock at offset 0x%llx",erase.start); -+ if(ioctl(Fd, MEMUNLOCK, &erase) != 0) -+ { -+ perror("\nMTD Unlock failure"); -+ close(Fd); -+ return 8; -+ } -+ } -+ -+ if (ioctl(Fd,MEMERASE,&erase) != 0) -+ { -+ perror("\nMTD Erase failure"); -+ close(Fd); -+ return 8; -+ } -+ erase.start += meminfo.erasesize; -+ } -+ printf(" done\n"); -+ } -+ return 0; -+} -+ -+int main(int argc,char *argv[]) -+{ -+ int regcount; -+ int Fd; -+ int start; -+ int count; -+ int unlock; -+ int res = 0; -+ -+ if (1 >= argc || !strcmp(argv[1], "-h") || !strcmp (argv[1], "--help") ) { -+ printf("Usage: flash_erase MTD-device [start] [cnt (# erase blocks)] [lock]\n" -+ " flash_erase -h | --help\n") ; -+ return 16 ; -+ } -+ -+ if (argc > 2) -+ start = strtol(argv[2], NULL, 0); -+ else -+ start = 0; -+ -+ if (argc > 3) -+ count = strtol(argv[3], NULL, 0); -+ else -+ count = 1; -+ -+ if(argc > 4) -+ unlock = strtol(argv[4], NULL, 0); -+ else -+ unlock = 0; -+ -+ -+ // Open and size the device -+ if ((Fd = open(argv[1],O_RDWR)) < 0) -+ { -+ fprintf(stderr,"File open error\n"); -+ return 8; -+ } -+ -+ printf("Erase Total %d Units\n", count); -+ -+ if (ioctl(Fd,MEMGETREGIONCOUNT,®count) == 0) -+ { -+ if(regcount == 0) -+ { -+ res = non_region_erase(Fd, start, count, unlock); -+ } -+ else -+ { -+ res = region_erase(Fd, start, count, unlock, regcount); -+ } -+ } -+ -+ return res; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_eraseall.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_eraseall.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,286 @@ -+/* eraseall.c -- erase the whole of a MTD device -+ -+ Copyright (C) 2000 Arcom Control System Ltd -+ -+ Renamed to flash_eraseall.c -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+ -+#include -+#include -+ -+#define PROGRAM "flash_eraseall" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+static const char *exe_name; -+static const char *mtd_device; -+static int quiet; /* true -- don't output progress */ -+static int jffs2; // format for jffs2 usage -+ -+static void process_options (int argc, char *argv[]); -+static void display_help (void); -+static void display_version (void); -+static struct jffs2_unknown_node cleanmarker; -+int target_endian = __BYTE_ORDER; -+ -+int main (int argc, char *argv[]) -+{ -+ mtd_info_t meminfo; -+ int fd, clmpos = 0, clmlen = 8; -+ erase_info_t erase; -+ int isNAND, bbtest = 1; -+ -+ process_options(argc, argv); -+ -+ -+ if ((fd = open(mtd_device, O_RDWR)) < 0) { -+ fprintf(stderr, "%s: %s: %s\n", exe_name, mtd_device, strerror(errno)); -+ exit(1); -+ } -+ -+ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ fprintf(stderr, "%s: %s: unable to get MTD device info\n", exe_name, mtd_device); -+ exit(1); -+ } -+ -+ erase.length = meminfo.erasesize; -+ isNAND = meminfo.type == MTD_NANDFLASH ? 1 : 0; -+ -+ if (jffs2) { -+ cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); -+ cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); -+ if (!isNAND) -+ cleanmarker.totlen = cpu_to_je32 (sizeof (struct jffs2_unknown_node)); -+ else { -+ struct nand_oobinfo oobinfo; -+ -+ if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0) { -+ fprintf(stderr, "%s: %s: unable to get NAND oobinfo\n", exe_name, mtd_device); -+ exit(1); -+ } -+ -+ /* Check for autoplacement */ -+ if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) { -+ /* Get the position of the free bytes */ -+ if (!oobinfo.oobfree[0][1]) { -+ fprintf (stderr, " Eeep. Autoplacement selected and no empty space in oob\n"); -+ exit(1); -+ } -+ clmpos = oobinfo.oobfree[0][0]; -+ clmlen = oobinfo.oobfree[0][1]; -+ if (clmlen > 8) -+ clmlen = 8; -+ } else { -+ /* Legacy mode */ -+ switch (meminfo.oobsize) { -+ case 8: -+ clmpos = 6; -+ clmlen = 2; -+ break; -+ case 16: -+ clmpos = 8; -+ clmlen = 8; -+ break; -+ case 64: -+ clmpos = 16; -+ clmlen = 8; -+ break; -+ } -+ } -+ cleanmarker.totlen = cpu_to_je32(8); -+ } -+ cleanmarker.hdr_crc = cpu_to_je32 (crc32 (0, &cleanmarker, sizeof (struct jffs2_unknown_node) - 4)); -+ } -+ -+ for (erase.start = 0; erase.start < meminfo.size; erase.start += meminfo.erasesize) { -+ if (bbtest) { -+ unsigned long long offset = erase.start; -+ int ret = ioctl(fd, MEMGETBADBLOCK, &offset); -+ if (ret > 0) { -+ if (!quiet) -+ printf ("\nSkipping bad block at 0x%09llx\n", erase.start); -+ continue; -+ } else if (ret < 0) { -+ if (errno == EOPNOTSUPP) { -+ bbtest = 0; -+ if (isNAND) { -+ fprintf(stderr, "%s: %s: Bad block check not available\n", exe_name, mtd_device); -+ exit(1); -+ } -+ } else { -+ fprintf(stderr, "\n%s: %s: MTD get bad block failed: %s\n", exe_name, mtd_device, strerror(errno)); -+ exit(1); -+ } -+ } -+ } -+ -+ if (!quiet) { -+ printf -+ ("\rErasing %d Kibyte @ %llx -- %2u %% complete.", -+ meminfo.erasesize / 1024, erase.start, -+ (unsigned long long) -+ erase.start * 100 / meminfo.size); -+ } -+ fflush(stdout); -+ -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ fprintf(stderr, "\n%s: %s: MTD Erase failure: %s\n", exe_name, mtd_device, strerror(errno)); -+ continue; -+ } -+ -+ /* format for JFFS2 ? */ -+ if (!jffs2) -+ continue; -+ -+ /* write cleanmarker */ -+ if (isNAND) { -+ struct mtd_oob_buf oob; -+ oob.ptr = (unsigned char *) &cleanmarker; -+ oob.start = erase.start + clmpos; -+ oob.length = clmlen; -+ if (ioctl (fd, MEMWRITEOOB, &oob) != 0) { -+ fprintf(stderr, "\n%s: %s: MTD writeoob failure: %s\n", exe_name, mtd_device, strerror(errno)); -+ continue; -+ } -+ } else { -+ if (lseek (fd, erase.start, SEEK_SET) < 0) { -+ fprintf(stderr, "\n%s: %s: MTD lseek failure: %s\n", exe_name, mtd_device, strerror(errno)); -+ continue; -+ } -+ if (write (fd , &cleanmarker, sizeof (cleanmarker)) != sizeof (cleanmarker)) { -+ fprintf(stderr, "\n%s: %s: MTD write failure: %s\n", exe_name, mtd_device, strerror(errno)); -+ continue; -+ } -+ } -+ if (!quiet) -+ printf (" Cleanmarker written at %x.", erase.start); -+ } -+ if (!quiet) -+ printf("\n"); -+ -+ return 0; -+} -+ -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ exe_name = argv[0]; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "jq"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"jffs2", no_argument, 0, 'j'}, -+ {"quiet", no_argument, 0, 'q'}, -+ {"silent", no_argument, 0, 'q'}, -+ -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'q': -+ quiet = 1; -+ break; -+ case 'j': -+ jffs2 = 1; -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ if (optind == argc) { -+ fprintf(stderr, "%s: no MTD device specified\n", exe_name); -+ error = 1; -+ } -+ if (error) { -+ fprintf(stderr, "Try `%s --help' for more information.\n", -+ exe_name); -+ exit(1); -+ } -+ -+ mtd_device = argv[optind]; -+} -+ -+ -+void display_help (void) -+{ -+ printf("Usage: %s [OPTION] MTD_DEVICE\n" -+ "Erases all of the specified MTD device.\n" -+ "\n" -+ " -j, --jffs2 format the device for jffs2\n" -+ " -q, --quiet don't display progress messages\n" -+ " --silent same as --quiet\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n", -+ exe_name); -+ exit(0); -+} -+ -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "Copyright (C) 2000 Arcom Control Systems Ltd\n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_info.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_info.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,55 @@ -+/* -+ * flash_info.c -- print info about a MTD device -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc,char *argv[]) -+{ -+ int regcount; -+ int Fd; -+ -+ if (1 >= argc) -+ { -+ fprintf(stderr,"Usage: flash_info device\n"); -+ return 16; -+ } -+ -+ // Open and size the device -+ if ((Fd = open(argv[1],O_RDONLY)) < 0) -+ { -+ fprintf(stderr,"File open error\n"); -+ return 8; -+ } -+ -+ if (ioctl(Fd,MEMGETREGIONCOUNT,®count) == 0) -+ { -+ int i; -+ region_info_t reginfo; -+ printf("Device %s has %d erase regions\n", argv[1], regcount); -+ for (i = 0; i < regcount; i++) -+ { -+ reginfo.regionindex = i; -+ if(ioctl(Fd, MEMGETREGIONINFO, ®info) == 0) -+ { -+ printf("Region %d is at 0x%x with size 0x%x and " -+ "has 0x%x blocks\n", i, reginfo.offset, -+ reginfo.erasesize, reginfo.numblocks); -+ } -+ else -+ { -+ printf("Strange can not read region %d from a %d region device\n", -+ i, regcount); -+ } -+ } -+ } -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_lock.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_lock.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,84 @@ -+/* -+ * FILE flash_lock.c -+ * -+ * This utility locks one or more sectors of flash device. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc, char *argv[]) -+{ -+ int fd; -+ struct mtd_info_user mtdInfo; -+ struct erase_info_user mtdLockInfo; -+ int num_sectors; -+ int ofs; -+ -+ /* -+ * Parse command line options -+ */ -+ if(argc != 4) -+ { -+ fprintf(stderr, "USAGE: %s \n", argv[0]); -+ exit(1); -+ } -+ else if(strncmp(argv[1], "/dev/mtd", 8) != 0) -+ { -+ fprintf(stderr, "'%s' is not a MTD device. Must specify mtd device: /dev/mtd?\n", argv[1]); -+ exit(1); -+ } -+ -+ fd = open(argv[1], O_RDWR); -+ if(fd < 0) -+ { -+ fprintf(stderr, "Could not open mtd device: %s\n", argv[1]); -+ exit(1); -+ } -+ -+ if(ioctl(fd, MEMGETINFO, &mtdInfo)) -+ { -+ fprintf(stderr, "Could not get MTD device info from %s\n", argv[1]); -+ close(fd); -+ exit(1); -+ } -+ sscanf(argv[2], "%x",&ofs); -+ sscanf(argv[3], "%d",&num_sectors); -+ if(ofs > mtdInfo.size - mtdInfo.erasesize) -+ { -+ fprintf(stderr, "%x is beyond device size %x\n",ofs,(unsigned int)(mtdInfo.size - mtdInfo.erasesize)); -+ exit(1); -+ } -+ -+ if (num_sectors == -1) { -+ num_sectors = mtdInfo.size/mtdInfo.erasesize; -+ } -+ else { -+ if(num_sectors > mtdInfo.size/mtdInfo.erasesize) -+ { -+ fprintf(stderr, "%d are too many sectors, device only has %d\n",num_sectors,(int)(mtdInfo.size/mtdInfo.erasesize)); -+ exit(1); -+ } -+ } -+ -+ mtdLockInfo.start = ofs; -+ mtdLockInfo.length = num_sectors * mtdInfo.erasesize; -+ if(ioctl(fd, MEMLOCK, &mtdLockInfo)) -+ { -+ fprintf(stderr, "Could not lock MTD device: %s\n", argv[1]); -+ close(fd); -+ exit(1); -+ } -+ -+ return 0; -+} -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_dump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_dump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,54 @@ -+/* -+ * flash_otp_dump.c -- display One-Time-Programm data -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc,char *argv[]) -+{ -+ int fd, val, i, offset, ret; -+ unsigned char buf[16]; -+ -+ if (argc != 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) { -+ fprintf(stderr,"Usage: %s [ -f | -u ] \n", argv[0]); -+ return EINVAL; -+ } -+ -+ fd = open(argv[2], O_RDONLY); -+ if (fd < 0) { -+ perror(argv[2]); -+ return errno; -+ } -+ -+ val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER; -+ ret = ioctl(fd, OTPSELECT, &val); -+ if (ret < 0) { -+ perror("OTPSELECT"); -+ return errno; -+ } -+ -+ printf("OTP %s data for %s\n", -+ argv[1][1] == 'f' ? "factory" : "user", argv[2]); -+ offset = 0; -+ while ((ret = read(fd, buf, sizeof(buf)))) { -+ if (ret < 0) { -+ perror("read()"); -+ return errno; -+ } -+ printf("0x%04x:", offset); -+ for (i = 0; i < ret; i++) -+ printf(" %02x", buf[i]); -+ printf("\n"); -+ offset += ret; -+ } -+ -+ close(fd); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_info.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_info.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,63 @@ -+/* -+ * flash_otp_info.c -- print info about One-Time-Programm data -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc,char *argv[]) -+{ -+ int fd, val, i, ret; -+ -+ if (argc != 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) { -+ fprintf(stderr,"Usage: %s [ -f | -u ] \n", argv[0]); -+ return EINVAL; -+ } -+ -+ fd = open(argv[2], O_RDONLY); -+ if (fd < 0) { -+ perror(argv[2]); -+ return errno; -+ } -+ -+ val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER; -+ ret = ioctl(fd, OTPSELECT, &val); -+ if (ret < 0) { -+ perror("OTPSELECT"); -+ return errno; -+ } -+ -+ ret = ioctl(fd, OTPGETREGIONCOUNT, &val); -+ if (ret < 0) { -+ perror("OTPGETREGIONCOUNT"); -+ return errno; -+ } -+ -+ printf("Number of OTP %s blocks on %s: %d\n", -+ argv[1][1] == 'f' ? "factory" : "user", argv[2], val); -+ -+ if (val > 0) { -+ struct otp_info info[val]; -+ -+ ret = ioctl(fd, OTPGETREGIONINFO, &info); -+ if (ret < 0) { -+ perror("OTPGETREGIONCOUNT"); -+ return errno; -+ } -+ -+ for (i = 0; i < val; i++) -+ printf("block %2d: offset = 0x%04x " -+ "size = %2d bytes %s\n", -+ i, info[i].start, info[i].length, -+ info[i].locked ? "[locked]" : "[unlocked]"); -+ } -+ -+ close(fd); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_lock.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_lock.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,70 @@ -+/* -+ * flash_otp_lock.c -- lock area of One-Time-Program data -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc,char *argv[]) -+{ -+ int fd, val, ret, offset, size; -+ char *p, buf[8]; -+ -+ if (argc != 5 || strcmp(argv[1], "-u")) { -+ fprintf(stderr, "Usage: %s -u \n", argv[0]); -+ fprintf(stderr, "offset and size must match on OTP region boundaries\n"); -+ fprintf(stderr, "CAUTION! ONCE LOCKED, OTP REGIONS CAN'T BE UNLOCKED!\n"); -+ return EINVAL; -+ } -+ -+ fd = open(argv[2], O_WRONLY); -+ if (fd < 0) { -+ perror(argv[2]); -+ return errno; -+ } -+ -+ val = MTD_OTP_USER; -+ ret = ioctl(fd, OTPSELECT, &val); -+ if (ret < 0) { -+ perror("OTPSELECT"); -+ return errno; -+ } -+ -+ offset = strtoul(argv[3], &p, 0); -+ if (argv[3][0] == 0 || *p != 0) { -+ fprintf(stderr, "%s: bad offset value\n", argv[0]); -+ return ERANGE; -+ } -+ -+ size = strtoul(argv[4], &p, 0); -+ if (argv[4][0] == 0 || *p != 0) { -+ fprintf(stderr, "%s: bad size value\n", argv[0]); -+ return ERANGE; -+ } -+ -+ printf("About to lock OTP user data on %s from 0x%x to 0x%x\n", -+ argv[2], offset, offset + size); -+ printf("Are you sure (yes|no)? "); -+ if (fgets(buf, sizeof(buf), stdin) && strcmp(buf, "yes\n") == 0) { -+ struct otp_info info; -+ info.start = offset; -+ info.length = size; -+ ret = ioctl(fd, OTPLOCK, &info); -+ if (ret < 0) { -+ perror("OTPLOCK"); -+ return errno; -+ } -+ printf("Done.\n"); -+ } else { -+ printf("Aborted\n"); -+ } -+ -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_write.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_write.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,96 @@ -+/* -+ * flash_otp_write.c -- write One-Time-Program data -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc,char *argv[]) -+{ -+ int fd, val, ret, size, wrote, len; -+ mtd_info_t mtdInfo; -+ off_t offset; -+ char *p, buf[2048]; -+ -+ if (argc != 4 || strcmp(argv[1], "-u")) { -+ fprintf(stderr, "Usage: %s -u \n", argv[0]); -+ fprintf(stderr, "the raw data to write should be provided on stdin\n"); -+ fprintf(stderr, "CAUTION! ONCE SET TO 0, OTP DATA BITS CAN'T BE ERASED!\n"); -+ return EINVAL; -+ } -+ -+ fd = open(argv[2], O_WRONLY); -+ if (fd < 0) { -+ perror(argv[2]); -+ return errno; -+ } -+ -+ val = MTD_OTP_USER; -+ ret = ioctl(fd, OTPSELECT, &val); -+ if (ret < 0) { -+ perror("OTPSELECT"); -+ return errno; -+ } -+ -+ if (ioctl(fd, MEMGETINFO, &mtdInfo)) { -+ perror("MEMGETINFO"); -+ return errno; -+ } -+ -+ offset = strtoul(argv[3], &p, 0); -+ if (argv[3][0] == 0 || *p != 0) { -+ fprintf(stderr, "%s: bad offset value\n", argv[0]); -+ return ERANGE; -+ } -+ -+ if (lseek(fd, offset, SEEK_SET) == (off_t)-1) { -+ perror("lseek()"); -+ return errno; -+ } -+ -+ printf("Writing OTP user data on %s at offset 0x%lx\n", argv[2], offset); -+ -+ if (mtdInfo.type == MTD_NANDFLASH) -+ len = mtdInfo.writesize; -+ else -+ len = 256; -+ -+ wrote = 0; -+ while ((size = read(0, buf, len))) { -+ if (size < 0) { -+ perror("read()"); -+ return errno; -+ } -+ p = buf; -+ while (size > 0) { -+ if (mtdInfo.type == MTD_NANDFLASH) { -+ /* Fill remain buffers with 0xff */ -+ memset(buf + size, 0xff, mtdInfo.writesize - size); -+ size = mtdInfo.writesize; -+ } -+ ret = write(fd, p, size); -+ if (ret < 0) { -+ perror("write()"); -+ return errno; -+ } -+ if (ret == 0) { -+ printf("write() returned 0 after writing %d bytes\n", wrote); -+ return 0; -+ } -+ p += ret; -+ wrote += ret; -+ size -= ret; -+ } -+ } -+ -+ printf("Wrote %d bytes of OTP user data\n", wrote); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_unlock.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_unlock.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,64 @@ -+/* -+ * FILE flash_unlock.c -+ * -+ * This utility unlock all sectors of flash device. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc, char *argv[]) -+{ -+ int fd; -+ struct mtd_info_user mtdInfo; -+ struct erase_info_user mtdLockInfo; -+ -+ /* -+ * Parse command line options -+ */ -+ if(argc != 2) -+ { -+ fprintf(stderr, "USAGE: %s \n", argv[0]); -+ exit(1); -+ } -+ else if(strncmp(argv[1], "/dev/mtd", 8) != 0) -+ { -+ fprintf(stderr, "'%s' is not a MTD device. Must specify mtd device: /dev/mtd?\n", argv[1]); -+ exit(1); -+ } -+ -+ fd = open(argv[1], O_RDWR); -+ if(fd < 0) -+ { -+ fprintf(stderr, "Could not open mtd device: %s\n", argv[1]); -+ exit(1); -+ } -+ -+ if(ioctl(fd, MEMGETINFO, &mtdInfo)) -+ { -+ fprintf(stderr, "Could not get MTD device info from %s\n", argv[1]); -+ close(fd); -+ exit(1); -+ } -+ -+ mtdLockInfo.start = 0; -+ mtdLockInfo.length = mtdInfo.size; -+ if(ioctl(fd, MEMUNLOCK, &mtdLockInfo)) -+ { -+ fprintf(stderr, "Could not unlock MTD device: %s\n", argv[1]); -+ close(fd); -+ exit(1); -+ } -+ -+ return 0; -+} -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flashcp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flashcp.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,389 @@ -+/* -+ * Copyright (c) 2d3D, Inc. -+ * Written by Abraham vd Merwe -+ * All rights reserved. -+ * -+ * Renamed to flashcp.c to avoid conflicts with fcp from fsh package -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. Neither the name of the author nor the names of other contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+typedef int bool; -+#define true 1 -+#define false 0 -+ -+#define EXIT_FAILURE 1 -+#define EXIT_SUCCESS 0 -+ -+/* for debugging purposes only */ -+#ifdef DEBUG -+#undef DEBUG -+#define DEBUG(fmt,args...) { log_printf (LOG_ERROR,"%d: ",__LINE__); log_printf (LOG_ERROR,fmt,## args); } -+#else -+#undef DEBUG -+#define DEBUG(fmt,args...) -+#endif -+ -+#define KB(x) ((x) / 1024) -+#define PERCENTAGE(x,total) (((x) * 100) / (total)) -+ -+/* size of read/write buffer */ -+#define BUFSIZE (10 * 1024) -+ -+/* cmd-line flags */ -+#define FLAG_NONE 0x00 -+#define FLAG_VERBOSE 0x01 -+#define FLAG_HELP 0x02 -+#define FLAG_FILENAME 0x04 -+#define FLAG_DEVICE 0x08 -+ -+/* error levels */ -+#define LOG_NORMAL 1 -+#define LOG_ERROR 2 -+ -+static void log_printf (int level,const char *fmt, ...) -+{ -+ FILE *fp = level == LOG_NORMAL ? stdout : stderr; -+ va_list ap; -+ va_start (ap,fmt); -+ vfprintf (fp,fmt,ap); -+ va_end (ap); -+ fflush (fp); -+} -+ -+static void showusage (const char *progname,bool error) -+{ -+ int level = error ? LOG_ERROR : LOG_NORMAL; -+ -+ log_printf (level, -+ "\n" -+ "Flash Copy - Written by Abraham van der Merwe \n" -+ "\n" -+ "usage: %s [ -v | --verbose ] \n" -+ " %s -h | --help\n" -+ "\n" -+ " -h | --help Show this help message\n" -+ " -v | --verbose Show progress reports\n" -+ " File which you want to copy to flash\n" -+ " Flash device to write to (e.g. /dev/mtd0, /dev/mtd1, etc.)\n" -+ "\n", -+ progname,progname); -+ -+ exit (error ? EXIT_FAILURE : EXIT_SUCCESS); -+} -+ -+static int safe_open (const char *pathname,int flags) -+{ -+ int fd; -+ -+ fd = open (pathname,flags); -+ if (fd < 0) -+ { -+ log_printf (LOG_ERROR,"While trying to open %s",pathname); -+ if (flags & O_RDWR) -+ log_printf (LOG_ERROR," for read/write access"); -+ else if (flags & O_RDONLY) -+ log_printf (LOG_ERROR," for read access"); -+ else if (flags & O_WRONLY) -+ log_printf (LOG_ERROR," for write access"); -+ log_printf (LOG_ERROR,": %m\n"); -+ exit (EXIT_FAILURE); -+ } -+ -+ return (fd); -+} -+ -+static void safe_read (int fd,const char *filename,void *buf,size_t count,bool verbose) -+{ -+ ssize_t result; -+ -+ result = read (fd,buf,count); -+ if (count != result) -+ { -+ if (verbose) log_printf (LOG_NORMAL,"\n"); -+ if (result < 0) -+ { -+ log_printf (LOG_ERROR,"While reading data from %s: %m\n",filename); -+ exit (EXIT_FAILURE); -+ } -+ log_printf (LOG_ERROR,"Short read count returned while reading from %s\n",filename); -+ exit (EXIT_FAILURE); -+ } -+} -+ -+static void safe_rewind (int fd,const char *filename) -+{ -+ if (lseek (fd,0L,SEEK_SET) < 0) -+ { -+ log_printf (LOG_ERROR,"While seeking to start of %s: %m\n",filename); -+ exit (EXIT_FAILURE); -+ } -+} -+ -+/******************************************************************************/ -+ -+static int dev_fd = -1,fil_fd = -1; -+ -+static void cleanup (void) -+{ -+ if (dev_fd > 0) close (dev_fd); -+ if (fil_fd > 0) close (fil_fd); -+} -+ -+int main (int argc,char *argv[]) -+{ -+ const char *progname,*filename = NULL,*device = NULL; -+ int i,flags = FLAG_NONE; -+ ssize_t result; -+ size_t size,written; -+ struct mtd_info_user mtd; -+ struct erase_info_user erase; -+ struct stat filestat; -+ unsigned char src[BUFSIZE],dest[BUFSIZE]; -+ -+ (progname = strrchr (argv[0],'/')) ? progname++ : (progname = argv[0]); -+ -+ /********************* -+ * parse cmd-line -+ *****************/ -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "hv"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 'h'}, -+ {"verbose", no_argument, 0, 'v'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 'h': -+ flags |= FLAG_HELP; -+ DEBUG("Got FLAG_HELP\n"); -+ break; -+ case 'v': -+ flags |= FLAG_VERBOSE; -+ DEBUG("Got FLAG_VERBOSE\n"); -+ break; -+ default: -+ DEBUG("Unknown parameter: %s\n",argv[option_index]); -+ showusage (progname,true); -+ } -+ } -+ if (optind+2 == argc) { -+ flags |= FLAG_FILENAME; -+ filename = argv[optind]; -+ DEBUG("Got filename: %s\n",filename); -+ -+ flags |= FLAG_DEVICE; -+ device = argv[optind+1]; -+ DEBUG("Got device: %s\n",device); -+ } -+ -+ if (flags & FLAG_HELP || progname == NULL || device == NULL) -+ showusage (progname,flags != FLAG_HELP); -+ -+ atexit (cleanup); -+ -+ /* get some info about the flash device */ -+ dev_fd = safe_open (device,O_SYNC | O_RDWR); -+ if (ioctl (dev_fd,MEMGETINFO,&mtd) < 0) -+ { -+ DEBUG("ioctl(): %m\n"); -+ log_printf (LOG_ERROR,"This doesn't seem to be a valid MTD flash device!\n"); -+ exit (EXIT_FAILURE); -+ } -+ -+ /* get some info about the file we want to copy */ -+ fil_fd = safe_open (filename,O_RDONLY); -+ if (fstat (fil_fd,&filestat) < 0) -+ { -+ log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename); -+ exit (EXIT_FAILURE); -+ } -+ -+ /* does it fit into the device/partition? */ -+ if (filestat.st_size > mtd.size) -+ { -+ log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device); -+ exit (EXIT_FAILURE); -+ } -+ -+ /***************************************************** -+ * erase enough blocks so that we can write the file * -+ *****************************************************/ -+ -+#warning "Check for smaller erase regions" -+ -+ erase.start = 0; -+ erase.length = filestat.st_size & ~(mtd.erasesize - 1); -+ if (filestat.st_size % mtd.erasesize) erase.length += mtd.erasesize; -+ if (flags & FLAG_VERBOSE) -+ { -+ /* if the user wants verbose output, erase 1 block at a time and show him/her what's going on */ -+ int blocks = erase.length / mtd.erasesize; -+ erase.length = mtd.erasesize; -+ log_printf (LOG_NORMAL,"Erasing blocks: 0/%d (0%%)",blocks); -+ for (i = 1; i <= blocks; i++) -+ { -+ log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks)); -+ if (ioctl (dev_fd,MEMERASE,&erase) < 0) -+ { -+ log_printf (LOG_NORMAL,"\n"); -+ log_printf (LOG_ERROR, -+ "While erasing blocks 0x%.8x-0x%.8x on %s: %m\n", -+ (unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device); -+ exit (EXIT_FAILURE); -+ } -+ erase.start += mtd.erasesize; -+ } -+ log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (100%%)\n",blocks,blocks); -+ } -+ else -+ { -+ /* if not, erase the whole chunk in one shot */ -+ if (ioctl (dev_fd,MEMERASE,&erase) < 0) -+ { -+ log_printf (LOG_ERROR, -+ "While erasing blocks from 0x%.8x-0x%.8x on %s: %m\n", -+ (unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device); -+ exit (EXIT_FAILURE); -+ } -+ } -+ DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size); -+ -+ /********************************** -+ * write the entire file to flash * -+ **********************************/ -+ -+ if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%luk (0%%)",KB (filestat.st_size)); -+ size = filestat.st_size; -+ i = BUFSIZE; -+ written = 0; -+ while (size) -+ { -+ if (size < BUFSIZE) i = size; -+ if (flags & FLAG_VERBOSE) -+ log_printf (LOG_NORMAL,"\rWriting data: %dk/%luk (%lu%%)", -+ KB (written + i), -+ KB (filestat.st_size), -+ PERCENTAGE (written + i,filestat.st_size)); -+ -+ /* read from filename */ -+ safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE); -+ -+ /* write to device */ -+ result = write (dev_fd,src,i); -+ if (i != result) -+ { -+ if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n"); -+ if (result < 0) -+ { -+ log_printf (LOG_ERROR, -+ "While writing data to 0x%.8x-0x%.8x on %s: %m\n", -+ written,written + i,device); -+ exit (EXIT_FAILURE); -+ } -+ log_printf (LOG_ERROR, -+ "Short write count returned while writing to x%.8x-0x%.8x on %s: %d/%lu bytes written to flash\n", -+ written,written + i,device,written + result,filestat.st_size); -+ exit (EXIT_FAILURE); -+ } -+ -+ written += i; -+ size -= i; -+ } -+ if (flags & FLAG_VERBOSE) -+ log_printf (LOG_NORMAL, -+ "\rWriting data: %luk/%luk (100%%)\n", -+ KB (filestat.st_size), -+ KB (filestat.st_size)); -+ DEBUG("Wrote %d / %luk bytes\n",written,filestat.st_size); -+ -+ /********************************** -+ * verify that flash == file data * -+ **********************************/ -+ -+ safe_rewind (fil_fd,filename); -+ safe_rewind (dev_fd,device); -+ size = filestat.st_size; -+ i = BUFSIZE; -+ written = 0; -+ if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%luk (0%%)",KB (filestat.st_size)); -+ while (size) -+ { -+ if (size < BUFSIZE) i = size; -+ if (flags & FLAG_VERBOSE) -+ log_printf (LOG_NORMAL, -+ "\rVerifying data: %dk/%luk (%lu%%)", -+ KB (written + i), -+ KB (filestat.st_size), -+ PERCENTAGE (written + i,filestat.st_size)); -+ -+ /* read from filename */ -+ safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE); -+ -+ /* read from device */ -+ safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE); -+ -+ /* compare buffers */ -+ if (memcmp (src,dest,i)) -+ { -+ log_printf (LOG_ERROR, -+ "File does not seem to match flash data. First mismatch at 0x%.8x-0x%.8x\n", -+ written,written + i); -+ exit (EXIT_FAILURE); -+ } -+ -+ written += i; -+ size -= i; -+ } -+ if (flags & FLAG_VERBOSE) -+ log_printf (LOG_NORMAL, -+ "\rVerifying data: %luk/%luk (100%%)\n", -+ KB (filestat.st_size), -+ KB (filestat.st_size)); -+ DEBUG("Verified %d / %luk bytes\n",written,filestat.st_size); -+ -+ exit (EXIT_SUCCESS); -+} -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ftl_check.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ftl_check.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,232 @@ -+/* Ported to MTD system. -+ * Based on: -+ */ -+/*====================================================================== -+ -+ Utility to create an FTL partition in a memory region -+ -+ ftl_check.c 1.10 1999/10/25 20:01:35 -+ -+ The contents of this file are subject to the Mozilla Public -+ License Version 1.1 (the "License"); you may not use this file -+ except in compliance with the License. You may obtain a copy of -+ the License at http://www.mozilla.org/MPL/ -+ -+ Software distributed under the License is distributed on an "AS -+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -+ implied. See the License for the specific language governing -+ rights and limitations under the License. -+ -+ The initial developer of the original code is David A. Hinds -+ . Portions created by David A. Hinds -+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. -+ -+ Alternatively, the contents of this file may be used under the -+ terms of the GNU Public License version 2 (the "GPL"), in which -+ case the provisions of the GPL are applicable instead of the -+ above. If you wish to allow the use of your version of this file -+ only under the terms of the GPL and not to allow others to use -+ your version of this file under the MPL, indicate your decision -+ by deleting the provisions above and replace them with the notice -+ and other provisions required by the GPL. If you do not delete -+ the provisions above, a recipient may use your version of this -+ file under either the MPL or the GPL. -+ -+ ======================================================================*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+ -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+# define TO_LE32(x) (x) -+# define TO_LE16(x) (x) -+#elif __BYTE_ORDER == __BIG_ENDIAN -+# define TO_LE32(x) (bswap_32(x)) -+# define TO_LE16(x) (bswap_16(x)) -+#else -+# error cannot detect endianess -+#endif -+ -+#define FROM_LE32(x) TO_LE32(x) -+#define FROM_LE16(x) TO_LE16(x) -+ -+/*====================================================================*/ -+ -+static void print_size(u_int s) -+{ -+ if ((s > 0x100000) && ((s % 0x100000) == 0)) -+ printf("%d mb", s / 0x100000); -+ else if ((s > 0x400) && ((s % 0x400) == 0)) -+ printf("%d kb", s / 0x400); -+ else -+ printf("%d bytes", s); -+} -+ -+/*====================================================================*/ -+ -+static void check_partition(int fd, int verbose) -+{ -+ mtd_info_t mtd; -+ erase_unit_header_t hdr, hdr2; -+ u_int i, j, nbam, *bam; -+ int control, data, free, deleted; -+ -+ /* Get partition size, block size */ -+ if (ioctl(fd, MEMGETINFO, &mtd) != 0) { -+ perror("get info failed"); -+ return; -+ } -+ -+ printf("Memory region info:\n"); -+ printf(" Region size = "); -+ print_size(mtd.size); -+ printf(" Erase block size = "); -+ print_size(mtd.erasesize); -+ printf("\n\n"); -+ -+ for (i = 0; i < mtd.size/mtd.erasesize; i++) { -+ if (lseek(fd, (i * mtd.erasesize), SEEK_SET) == -1) { -+ perror("seek failed"); -+ break; -+ } -+ read(fd, &hdr, sizeof(hdr)); -+ if ((FROM_LE32(hdr.FormattedSize) > 0) && -+ (FROM_LE32(hdr.FormattedSize) <= mtd.size) && -+ (FROM_LE16(hdr.NumEraseUnits) > 0) && -+ (FROM_LE16(hdr.NumEraseUnits) <= mtd.size/mtd.erasesize)) -+ break; -+ } -+ if (i == mtd.size/mtd.erasesize) { -+ fprintf(stderr, "No valid erase unit headers!\n"); -+ return; -+ } -+ -+ printf("Partition header:\n"); -+ printf(" Formatted size = "); -+ print_size(FROM_LE32(hdr.FormattedSize)); -+ printf(", erase units = %d, transfer units = %d\n", -+ FROM_LE16(hdr.NumEraseUnits), hdr.NumTransferUnits); -+ printf(" Erase unit size = "); -+ print_size(1 << hdr.EraseUnitSize); -+ printf(", virtual block size = "); -+ print_size(1 << hdr.BlockSize); -+ printf("\n"); -+ -+ /* Create basic block allocation table for control blocks */ -+ nbam = (mtd.erasesize >> hdr.BlockSize); -+ bam = malloc(nbam * sizeof(u_int)); -+ -+ for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) { -+ if (lseek(fd, (i << hdr.EraseUnitSize), SEEK_SET) == -1) { -+ perror("seek failed"); -+ break; -+ } -+ if (read(fd, &hdr2, sizeof(hdr2)) == -1) { -+ perror("read failed"); -+ break; -+ } -+ printf("\nErase unit %d:\n", i); -+ if ((hdr2.FormattedSize != hdr.FormattedSize) || -+ (hdr2.NumEraseUnits != hdr.NumEraseUnits) || -+ (hdr2.SerialNumber != hdr.SerialNumber)) -+ printf(" Erase unit header is corrupt.\n"); -+ else if (FROM_LE16(hdr2.LogicalEUN) == 0xffff) -+ printf(" Transfer unit, erase count = %d\n", FROM_LE32(hdr2.EraseCount)); -+ else { -+ printf(" Logical unit %d, erase count = %d\n", -+ FROM_LE16(hdr2.LogicalEUN), FROM_LE32(hdr2.EraseCount)); -+ if (lseek(fd, (i << hdr.EraseUnitSize)+FROM_LE32(hdr.BAMOffset), -+ SEEK_SET) == -1) { -+ perror("seek failed"); -+ break; -+ } -+ if (read(fd, bam, nbam * sizeof(u_int)) == -1) { -+ perror("read failed"); -+ break; -+ } -+ free = deleted = control = data = 0; -+ for (j = 0; j < nbam; j++) { -+ if (BLOCK_FREE(FROM_LE32(bam[j]))) -+ free++; -+ else if (BLOCK_DELETED(FROM_LE32(bam[j]))) -+ deleted++; -+ else switch (BLOCK_TYPE(FROM_LE32(bam[j]))) { -+ case BLOCK_CONTROL: control++; break; -+ case BLOCK_DATA: data++; break; -+ default: break; -+ } -+ } -+ printf(" Block allocation: %d control, %d data, %d free," -+ " %d deleted\n", control, data, free, deleted); -+ } -+ } -+} /* format_partition */ -+ -+/* Show usage information */ -+void showusage(char *pname) -+{ -+ fprintf(stderr, "usage: %s [-v] device\n", pname); -+ fprintf(stderr, "-v verbose messages\n"); -+} -+ -+/*====================================================================*/ -+ -+int main(int argc, char *argv[]) -+{ -+ int verbose; -+ int optch, errflg, fd; -+ struct stat buf; -+ -+ errflg = 0; -+ verbose = 0; -+ while ((optch = getopt(argc, argv, "vh")) != -1) { -+ switch (optch) { -+ case 'h': -+ errflg = 1; break; -+ case 'v': -+ verbose = 1; break; -+ default: -+ errflg = -1; break; -+ } -+ } -+ if (errflg || (optind != argc-1)) { -+ showusage(argv[0]); -+ exit(errflg > 0 ? 0 : EXIT_FAILURE); -+ } -+ -+ if (stat(argv[optind], &buf) != 0) { -+ perror("status check failed"); -+ exit(EXIT_FAILURE); -+ } -+ if (!(buf.st_mode & S_IFCHR)) { -+ fprintf(stderr, "%s is not a character special device\n", -+ argv[optind]); -+ exit(EXIT_FAILURE); -+ } -+ fd = open(argv[optind], O_RDONLY); -+ if (fd == -1) { -+ perror("open failed"); -+ exit(EXIT_FAILURE); -+ } -+ -+ check_partition(fd, verbose); -+ close(fd); -+ -+ exit(EXIT_SUCCESS); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ftl_format.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ftl_format.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,342 @@ -+/* Ported to MTD system. -+ * Based on: -+ */ -+/*====================================================================== -+ -+ Utility to create an FTL partition in a memory region -+ -+ ftl_format.c 1.13 1999/10/25 20:01:35 -+ -+ The contents of this file are subject to the Mozilla Public -+ License Version 1.1 (the "License"); you may not use this file -+ except in compliance with the License. You may obtain a copy of -+ the License at http://www.mozilla.org/MPL/ -+ -+ Software distributed under the License is distributed on an "AS -+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -+ implied. See the License for the specific language governing -+ rights and limitations under the License. -+ -+ The initial developer of the original code is David A. Hinds -+ . Portions created by David A. Hinds -+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. -+ -+ Alternatively, the contents of this file may be used under the -+ terms of the GNU Public License version 2 (the "GPL"), in which -+ case the provisions of the GPL are applicable instead of the -+ above. If you wish to allow the use of your version of this file -+ only under the terms of the GPL and not to allow others to use -+ your version of this file under the MPL, indicate your decision -+ by deleting the provisions above and replace them with the notice -+ and other provisions required by the GPL. If you do not delete -+ the provisions above, a recipient may use your version of this -+ file under either the MPL or the GPL. -+ -+ ======================================================================*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+ -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+# define TO_LE32(x) (x) -+# define TO_LE16(x) (x) -+#elif __BYTE_ORDER == __BIG_ENDIAN -+# define TO_LE32(x) (bswap_32(x)) -+# define TO_LE16(x) (bswap_16(x)) -+#else -+# error cannot detect endianess -+#endif -+ -+#define FROM_LE32(x) TO_LE32(x) -+#define FROM_LE16(x) TO_LE16(x) -+ -+/*====================================================================*/ -+ -+static void print_size(u_int s) -+{ -+ if ((s > 0x100000) && ((s % 0x100000) == 0)) -+ printf("%d mb", s / 0x100000); -+ else if ((s > 0x400) && ((s % 0x400) == 0)) -+ printf("%d kb", s / 0x400); -+ else -+ printf("%d bytes", s); -+} -+ -+/*====================================================================*/ -+ -+static const char LinkTarget[] = { -+ 0x13, 0x03, 'C', 'I', 'S' -+}; -+static const char DataOrg[] = { -+ 0x46, 0x39, 0x00, 'F', 'T', 'L', '1', '0', '0', 0x00 -+}; -+ -+static void build_header(erase_unit_header_t *hdr, u_int RegionSize, -+ u_int BlockSize, u_int Spare, int Reserve, -+ u_int BootSize) -+{ -+ u_int i, BootUnits, nbam, __FormattedSize; -+ -+ /* Default everything to the erased state */ -+ memset(hdr, 0xff, sizeof(*hdr)); -+ memcpy(hdr->LinkTargetTuple, LinkTarget, 5); -+ memcpy(hdr->DataOrgTuple, DataOrg, 10); -+ hdr->EndTuple[0] = hdr->EndTuple[1] = 0xff; -+ BootSize = (BootSize + (BlockSize-1)) & ~(BlockSize-1); -+ BootUnits = BootSize / BlockSize; -+ -+ /* We only support 512-byte blocks */ -+ hdr->BlockSize = 9; -+ hdr->EraseUnitSize = 0; -+ for (i = BlockSize; i > 1; i >>= 1) -+ hdr->EraseUnitSize++; -+ hdr->EraseCount = TO_LE32(0); -+ hdr->FirstPhysicalEUN = TO_LE16(BootUnits); -+ hdr->NumEraseUnits = TO_LE16((RegionSize - BootSize) >> hdr->EraseUnitSize); -+ hdr->NumTransferUnits = Spare; -+ __FormattedSize = RegionSize - ((Spare + BootUnits) << hdr->EraseUnitSize); -+ /* Leave a little bit of space between the CIS and BAM */ -+ hdr->BAMOffset = TO_LE32(0x80); -+ /* Adjust size to account for BAM space */ -+ nbam = ((1 << (hdr->EraseUnitSize - hdr->BlockSize)) * sizeof(u_int) -+ + FROM_LE32(hdr->BAMOffset) + (1 << hdr->BlockSize) - 1) >> hdr->BlockSize; -+ -+ __FormattedSize -= -+ (FROM_LE16(hdr->NumEraseUnits) - Spare) * (nbam << hdr->BlockSize); -+ __FormattedSize -= ((__FormattedSize * Reserve / 100) & ~0xfff); -+ -+ hdr->FormattedSize = TO_LE32(__FormattedSize); -+ -+ /* hdr->FirstVMAddress defaults to erased state */ -+ hdr->NumVMPages = TO_LE16(0); -+ hdr->Flags = 0; -+ /* hdr->Code defaults to erased state */ -+ hdr->SerialNumber = TO_LE32(time(NULL)); -+ /* hdr->AltEUHOffset defaults to erased state */ -+ -+} /* build_header */ -+ -+/*====================================================================*/ -+ -+static int format_partition(int fd, int quiet, int interrogate, -+ u_int spare, int reserve, u_int bootsize) -+{ -+ mtd_info_t mtd; -+ erase_info_t erase; -+ erase_unit_header_t hdr; -+ u_int step, lun, i, nbam, *bam; -+ -+ /* Get partition size, block size */ -+ if (ioctl(fd, MEMGETINFO, &mtd) != 0) { -+ perror("get info failed"); -+ return -1; -+ } -+ -+#if 0 -+ /* Intel Series 100 Flash: skip first block */ -+ if ((region.JedecMfr == 0x89) && (region.JedecInfo == 0xaa) && -+ (bootsize == 0)) { -+ if (!quiet) -+ printf("Skipping first block to protect CIS info...\n"); -+ bootsize = 1; -+ } -+#endif -+ -+ /* Create header */ -+ build_header(&hdr, mtd.size, mtd.erasesize, -+ spare, reserve, bootsize); -+ -+ if (!quiet) { -+ printf("Partition size = "); -+ print_size(mtd.size); -+ printf(", erase unit size = "); -+ print_size(mtd.erasesize); -+ printf(", %d transfer units\n", spare); -+ if (bootsize != 0) { -+ print_size(FROM_LE16(hdr.FirstPhysicalEUN) << hdr.EraseUnitSize); -+ printf(" allocated for boot image\n"); -+ } -+ printf("Reserved %d%%, formatted size = ", reserve); -+ print_size(FROM_LE32(hdr.FormattedSize)); -+ printf("\n"); -+ fflush(stdout); -+ } -+ -+ if (interrogate) { -+ char str[3]; -+ printf("This will destroy all data on the target device. " -+ "Confirm (y/n): "); -+ if (fgets(str, 3, stdin) == NULL) -+ return -1; -+ if ((strcmp(str, "y\n") != 0) && (strcmp(str, "Y\n") != 0)) -+ return -1; -+ } -+ -+ /* Create basic block allocation table for control blocks */ -+ nbam = ((mtd.erasesize >> hdr.BlockSize) * sizeof(u_int) -+ + FROM_LE32(hdr.BAMOffset) + (1 << hdr.BlockSize) - 1) >> hdr.BlockSize; -+ bam = malloc(nbam * sizeof(u_int)); -+ for (i = 0; i < nbam; i++) -+ bam[i] = TO_LE32(BLOCK_CONTROL); -+ -+ /* Erase partition */ -+ if (!quiet) { -+ printf("Erasing all blocks...\n"); -+ fflush(stdout); -+ } -+ erase.length = mtd.erasesize; -+ erase.start = mtd.erasesize * FROM_LE16(hdr.FirstPhysicalEUN); -+ for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) { -+ if (ioctl(fd, MEMERASE, &erase) < 0) { -+ if (!quiet) { -+ putchar('\n'); -+ fflush(stdout); -+ } -+ perror("block erase failed"); -+ return -1; -+ } -+ erase.start += erase.length; -+ if (!quiet) { -+ if (mtd.size <= 0x800000) { -+ if (erase.start % 0x100000) { -+ if (!(erase.start % 0x20000)) putchar('-'); -+ } -+ else putchar('+'); -+ } -+ else { -+ if (erase.start % 0x800000) { -+ if (!(erase.start % 0x100000)) putchar('+'); -+ } -+ else putchar('*'); -+ } -+ fflush(stdout); -+ } -+ } -+ if (!quiet) putchar('\n'); -+ -+ /* Prepare erase units */ -+ if (!quiet) { -+ printf("Writing erase unit headers...\n"); -+ fflush(stdout); -+ } -+ lun = 0; -+ /* Distribute transfer units over the entire region */ -+ step = (spare) ? (FROM_LE16(hdr.NumEraseUnits)/spare) : (FROM_LE16(hdr.NumEraseUnits)+1); -+ for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) { -+ u_int ofs = (i + FROM_LE16(hdr.FirstPhysicalEUN)) << hdr.EraseUnitSize; -+ if (lseek(fd, ofs, SEEK_SET) == -1) { -+ perror("seek failed"); -+ break; -+ } -+ /* Is this a transfer unit? */ -+ if (((i+1) % step) == 0) -+ hdr.LogicalEUN = TO_LE16(0xffff); -+ else { -+ hdr.LogicalEUN = TO_LE16(lun); -+ lun++; -+ } -+ if (write(fd, &hdr, sizeof(hdr)) == -1) { -+ perror("write failed"); -+ break; -+ } -+ if (lseek(fd, ofs + FROM_LE32(hdr.BAMOffset), SEEK_SET) == -1) { -+ perror("seek failed"); -+ break; -+ } -+ if (write(fd, bam, nbam * sizeof(u_int)) == -1) { -+ perror("write failed"); -+ break; -+ } -+ } -+ if (i < FROM_LE16(hdr.NumEraseUnits)) -+ return -1; -+ else -+ return 0; -+} /* format_partition */ -+ -+/*====================================================================*/ -+ -+int main(int argc, char *argv[]) -+{ -+ int quiet, interrogate, reserve; -+ int optch, errflg, fd, ret; -+ u_int spare, bootsize; -+ char *s; -+ extern char *optarg; -+ struct stat buf; -+ -+ quiet = 0; -+ interrogate = 0; -+ spare = 1; -+ reserve = 5; -+ errflg = 0; -+ bootsize = 0; -+ -+ while ((optch = getopt(argc, argv, "qir:s:b:")) != -1) { -+ switch (optch) { -+ case 'q': -+ quiet = 1; break; -+ case 'i': -+ interrogate = 1; break; -+ case 's': -+ spare = strtoul(optarg, NULL, 0); break; -+ case 'r': -+ reserve = strtoul(optarg, NULL, 0); break; -+ case 'b': -+ bootsize = strtoul(optarg, &s, 0); -+ if ((*s == 'k') || (*s == 'K')) -+ bootsize *= 1024; -+ break; -+ default: -+ errflg = 1; break; -+ } -+ } -+ if (errflg || (optind != argc-1)) { -+ fprintf(stderr, "usage: %s [-q] [-i] [-s spare-blocks]" -+ " [-r reserve-percent] [-b bootsize] device\n", argv[0]); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (stat(argv[optind], &buf) != 0) { -+ perror("status check failed"); -+ exit(EXIT_FAILURE); -+ } -+ if (!(buf.st_mode & S_IFCHR)) { -+ fprintf(stderr, "%s is not a character special device\n", -+ argv[optind]); -+ exit(EXIT_FAILURE); -+ } -+ fd = open(argv[optind], O_RDWR); -+ if (fd == -1) { -+ perror("open failed"); -+ exit(EXIT_FAILURE); -+ } -+ -+ ret = format_partition(fd, quiet, interrogate, spare, reserve, -+ bootsize); -+ if (!quiet) { -+ if (ret) -+ printf("format failed.\n"); -+ else -+ printf("format successful.\n"); -+ } -+ close(fd); -+ -+ exit((ret) ? EXIT_FAILURE : EXIT_SUCCESS); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/linux/jffs2.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/linux/jffs2.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,218 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2001-2003 Red Hat, Inc. -+ * -+ * Created by David Woodhouse -+ * -+ * For licensing information, see the file 'LICENCE' in the -+ * jffs2 directory. -+ * -+ * $Id: jffs2.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ */ -+ -+#ifndef __LINUX_JFFS2_H__ -+#define __LINUX_JFFS2_H__ -+ -+/* You must include something which defines the C99 uintXX_t types. -+ We don't do it from here because this file is used in too many -+ different environments. */ -+ -+#define JFFS2_SUPER_MAGIC 0x72b6 -+ -+/* Values we may expect to find in the 'magic' field */ -+#define JFFS2_OLD_MAGIC_BITMASK 0x1984 -+#define JFFS2_MAGIC_BITMASK 0x1985 -+#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ -+#define JFFS2_EMPTY_BITMASK 0xffff -+#define JFFS2_DIRTY_BITMASK 0x0000 -+ -+/* Summary node MAGIC marker */ -+#define JFFS2_SUM_MAGIC 0x02851885 -+ -+/* We only allow a single char for length, and 0xFF is empty flash so -+ we don't want it confused with a real length. Hence max 254. -+*/ -+#define JFFS2_MAX_NAME_LEN 254 -+ -+/* How small can we sensibly write nodes? */ -+#define JFFS2_MIN_DATA_LEN 128 -+ -+#define JFFS2_COMPR_NONE 0x00 -+#define JFFS2_COMPR_ZERO 0x01 -+#define JFFS2_COMPR_RTIME 0x02 -+#define JFFS2_COMPR_RUBINMIPS 0x03 -+#define JFFS2_COMPR_COPY 0x04 -+#define JFFS2_COMPR_DYNRUBIN 0x05 -+#define JFFS2_COMPR_ZLIB 0x06 -+#define JFFS2_COMPR_LZO 0x07 -+/* Compatibility flags. */ -+#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ -+#define JFFS2_NODE_ACCURATE 0x2000 -+/* INCOMPAT: Fail to mount the filesystem */ -+#define JFFS2_FEATURE_INCOMPAT 0xc000 -+/* ROCOMPAT: Mount read-only */ -+#define JFFS2_FEATURE_ROCOMPAT 0x8000 -+/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */ -+#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000 -+/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */ -+#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000 -+ -+#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1) -+#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2) -+#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) -+#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) -+ -+#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) -+ -+#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8) -+#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9) -+ -+/* XATTR Related */ -+#define JFFS2_XPREFIX_USER 1 /* for "user." */ -+#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */ -+#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */ -+#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */ -+#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */ -+ -+#define JFFS2_ACL_VERSION 0x0001 -+ -+// Maybe later... -+//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) -+//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) -+ -+ -+#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at -+ mount time, don't wait for it to -+ happen later */ -+#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific -+ compression type */ -+ -+ -+/* These can go once we've made sure we've caught all uses without -+ byteswapping */ -+ -+typedef struct { -+ uint32_t v32; -+} __attribute__((packed)) jint32_t; -+ -+typedef struct { -+ uint32_t m; -+} __attribute__((packed)) jmode_t; -+ -+typedef struct { -+ uint16_t v16; -+} __attribute__((packed)) jint16_t; -+ -+struct jffs2_unknown_node -+{ -+ /* All start like this */ -+ jint16_t magic; -+ jint16_t nodetype; -+ jint32_t totlen; /* So we can skip over nodes we don't grok */ -+ jint32_t hdr_crc; -+} __attribute__((packed)); -+ -+struct jffs2_raw_dirent -+{ -+ jint16_t magic; -+ jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */ -+ jint32_t totlen; -+ jint32_t hdr_crc; -+ jint32_t pino; -+ jint32_t version; -+ jint32_t ino; /* == zero for unlink */ -+ jint32_t mctime; -+ uint8_t nsize; -+ uint8_t type; -+ uint8_t unused[2]; -+ jint32_t node_crc; -+ jint32_t name_crc; -+ uint8_t name[0]; -+} __attribute__((packed)); -+ -+/* The JFFS2 raw inode structure: Used for storage on physical media. */ -+/* The uid, gid, atime, mtime and ctime members could be longer, but -+ are left like this for space efficiency. If and when people decide -+ they really need them extended, it's simple enough to add support for -+ a new type of raw node. -+*/ -+struct jffs2_raw_inode -+{ -+ jint16_t magic; /* A constant magic number. */ -+ jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */ -+ jint32_t totlen; /* Total length of this node (inc data, etc.) */ -+ jint32_t hdr_crc; -+ jint32_t ino; /* Inode number. */ -+ jint32_t version; /* Version number. */ -+ jmode_t mode; /* The file's type or mode. */ -+ jint16_t uid; /* The file's owner. */ -+ jint16_t gid; /* The file's group. */ -+ jint32_t isize; /* Total resultant size of this inode (used for truncations) */ -+ jint32_t atime; /* Last access time. */ -+ jint32_t mtime; /* Last modification time. */ -+ jint32_t ctime; /* Change time. */ -+ jint32_t offset; /* Where to begin to write. */ -+ jint32_t csize; /* (Compressed) data size */ -+ jint32_t dsize; /* Size of the node's data. (after decompression) */ -+ uint8_t compr; /* Compression algorithm used */ -+ uint8_t usercompr; /* Compression algorithm requested by the user */ -+ jint16_t flags; /* See JFFS2_INO_FLAG_* */ -+ jint32_t data_crc; /* CRC for the (compressed) data. */ -+ jint32_t node_crc; /* CRC for the raw inode (excluding data) */ -+ uint8_t data[0]; -+} __attribute__((packed)); -+ -+struct jffs2_raw_xattr { -+ jint16_t magic; -+ jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */ -+ jint32_t totlen; -+ jint32_t hdr_crc; -+ jint32_t xid; /* XATTR identifier number */ -+ jint32_t version; -+ uint8_t xprefix; -+ uint8_t name_len; -+ jint16_t value_len; -+ jint32_t data_crc; -+ jint32_t node_crc; -+ uint8_t data[0]; -+} __attribute__((packed)); -+ -+struct jffs2_raw_xref -+{ -+ jint16_t magic; -+ jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */ -+ jint32_t totlen; -+ jint32_t hdr_crc; -+ jint32_t ino; /* inode number */ -+ jint32_t xid; /* XATTR identifier number */ -+ jint32_t xseqno; /* xref sequencial number */ -+ jint32_t node_crc; -+} __attribute__((packed)); -+ -+struct jffs2_raw_summary -+{ -+ jint16_t magic; -+ jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */ -+ jint32_t totlen; -+ jint32_t hdr_crc; -+ jint32_t sum_num; /* number of sum entries*/ -+ jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */ -+ jint32_t padded; /* sum of the size of padding nodes */ -+ jint32_t sum_crc; /* summary information crc */ -+ jint32_t node_crc; /* node crc */ -+ jint32_t sum[0]; /* inode summary info */ -+} __attribute__((packed)); -+ -+union jffs2_node_union -+{ -+ struct jffs2_raw_inode i; -+ struct jffs2_raw_dirent d; -+ struct jffs2_raw_xattr x; -+ struct jffs2_raw_xref r; -+ struct jffs2_raw_summary s; -+ struct jffs2_unknown_node u; -+}; -+ -+#endif /* __LINUX_JFFS2_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/ftl-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/ftl-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,76 @@ -+/* -+ * $Id: ftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ * Derived from (and probably identical to): -+ * ftl.h 1.7 1999/10/25 20:23:17 -+ * -+ * The contents of this file are subject to the Mozilla Public License -+ * Version 1.1 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License -+ * at http://www.mozilla.org/MPL/ -+ * -+ * Software distributed under the License is distributed on an "AS IS" -+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -+ * the License for the specific language governing rights and -+ * limitations under the License. -+ * -+ * The initial developer of the original code is David A. Hinds -+ * . Portions created by David A. Hinds -+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. -+ * -+ * Alternatively, the contents of this file may be used under the -+ * terms of the GNU General Public License version 2 (the "GPL"), in -+ * which case the provisions of the GPL are applicable instead of the -+ * above. If you wish to allow the use of your version of this file -+ * only under the terms of the GPL and not to allow others to use -+ * your version of this file under the MPL, indicate your decision by -+ * deleting the provisions above and replace them with the notice and -+ * other provisions required by the GPL. If you do not delete the -+ * provisions above, a recipient may use your version of this file -+ * under either the MPL or the GPL. -+ */ -+ -+#ifndef __MTD_FTL_USER_H__ -+#define __MTD_FTL_USER_H__ -+ -+typedef struct erase_unit_header_t { -+ u_int8_t LinkTargetTuple[5]; -+ u_int8_t DataOrgTuple[10]; -+ u_int8_t NumTransferUnits; -+ u_int32_t EraseCount; -+ u_int16_t LogicalEUN; -+ u_int8_t BlockSize; -+ u_int8_t EraseUnitSize; -+ u_int16_t FirstPhysicalEUN; -+ u_int16_t NumEraseUnits; -+ u_int32_t FormattedSize; -+ u_int32_t FirstVMAddress; -+ u_int16_t NumVMPages; -+ u_int8_t Flags; -+ u_int8_t Code; -+ u_int32_t SerialNumber; -+ u_int32_t AltEUHOffset; -+ u_int32_t BAMOffset; -+ u_int8_t Reserved[12]; -+ u_int8_t EndTuple[2]; -+} erase_unit_header_t; -+ -+/* Flags in erase_unit_header_t */ -+#define HIDDEN_AREA 0x01 -+#define REVERSE_POLARITY 0x02 -+#define DOUBLE_BAI 0x04 -+ -+/* Definitions for block allocation information */ -+ -+#define BLOCK_FREE(b) ((b) == 0xffffffff) -+#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe)) -+ -+#define BLOCK_TYPE(b) ((b) & 0x7f) -+#define BLOCK_ADDRESS(b) ((b) & ~0x7f) -+#define BLOCK_NUMBER(b) ((b) >> 9) -+#define BLOCK_CONTROL 0x30 -+#define BLOCK_DATA 0x40 -+#define BLOCK_REPLACEMENT 0x60 -+#define BLOCK_BAD 0x70 -+ -+#endif /* __MTD_FTL_USER_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/inftl-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/inftl-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,91 @@ -+/* -+ * $Id: inftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ * Parts of INFTL headers shared with userspace -+ * -+ */ -+ -+#ifndef __MTD_INFTL_USER_H__ -+#define __MTD_INFTL_USER_H__ -+ -+#define OSAK_VERSION 0x5120 -+#define PERCENTUSED 98 -+ -+#define SECTORSIZE 512 -+ -+/* Block Control Information */ -+ -+struct inftl_bci { -+ uint8_t ECCsig[6]; -+ uint8_t Status; -+ uint8_t Status1; -+} __attribute__((packed)); -+ -+struct inftl_unithead1 { -+ uint16_t virtualUnitNo; -+ uint16_t prevUnitNo; -+ uint8_t ANAC; -+ uint8_t NACs; -+ uint8_t parityPerField; -+ uint8_t discarded; -+} __attribute__((packed)); -+ -+struct inftl_unithead2 { -+ uint8_t parityPerField; -+ uint8_t ANAC; -+ uint16_t prevUnitNo; -+ uint16_t virtualUnitNo; -+ uint8_t NACs; -+ uint8_t discarded; -+} __attribute__((packed)); -+ -+struct inftl_unittail { -+ uint8_t Reserved[4]; -+ uint16_t EraseMark; -+ uint16_t EraseMark1; -+} __attribute__((packed)); -+ -+union inftl_uci { -+ struct inftl_unithead1 a; -+ struct inftl_unithead2 b; -+ struct inftl_unittail c; -+}; -+ -+struct inftl_oob { -+ struct inftl_bci b; -+ union inftl_uci u; -+}; -+ -+ -+/* INFTL Media Header */ -+ -+struct INFTLPartition { -+ __u32 virtualUnits; -+ __u32 firstUnit; -+ __u32 lastUnit; -+ __u32 flags; -+ __u32 spareUnits; -+ __u32 Reserved0; -+ __u32 Reserved1; -+} __attribute__((packed)); -+ -+struct INFTLMediaHeader { -+ char bootRecordID[8]; -+ __u32 NoOfBootImageBlocks; -+ __u32 NoOfBinaryPartitions; -+ __u32 NoOfBDTLPartitions; -+ __u32 BlockMultiplierBits; -+ __u32 FormatFlags; -+ __u32 OsakVersion; -+ __u32 PercentUsed; -+ struct INFTLPartition Partitions[4]; -+} __attribute__((packed)); -+ -+/* Partition flag types */ -+#define INFTL_BINARY 0x20000000 -+#define INFTL_BDTL 0x40000000 -+#define INFTL_LAST 0x80000000 -+ -+#endif /* __MTD_INFTL_USER_H__ */ -+ -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,82 @@ -+/* -+ * $Id: jffs2-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ * JFFS2 definitions for use in user space only -+ */ -+ -+#ifndef __JFFS2_USER_H__ -+#define __JFFS2_USER_H__ -+ -+/* This file is blessed for inclusion by userspace */ -+#include -+#include -+#include -+ -+#undef cpu_to_je16 -+#undef cpu_to_je32 -+#undef cpu_to_jemode -+#undef je16_to_cpu -+#undef je32_to_cpu -+#undef jemode_to_cpu -+ -+extern int target_endian; -+ -+#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); }) -+#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); }) -+ -+#define cpu_to_je16(x) ((jint16_t){t16(x)}) -+#define cpu_to_je32(x) ((jint32_t){t32(x)}) -+#define cpu_to_jemode(x) ((jmode_t){t32(x)}) -+ -+#define je16_to_cpu(x) (t16((x).v16)) -+#define je32_to_cpu(x) (t32((x).v32)) -+#define jemode_to_cpu(x) (t32((x).m)) -+ -+#define le16_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x)) -+#define le32_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x)) -+#define cpu_to_le16(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x)) -+#define cpu_to_le32(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x)) -+ -+/* XATTR/POSIX-ACL related definition */ -+/* Namespaces copied from xattr.h and posix_acl_xattr.h */ -+#define XATTR_USER_PREFIX "user." -+#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1) -+#define XATTR_SECURITY_PREFIX "security." -+#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1) -+#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access" -+#define POSIX_ACL_XATTR_ACCESS_LEN (sizeof (POSIX_ACL_XATTR_ACCESS) - 1) -+#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default" -+#define POSIX_ACL_XATTR_DEFAULT_LEN (sizeof (POSIX_ACL_XATTR_DEFAULT) - 1) -+#define XATTR_TRUSTED_PREFIX "trusted." -+#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1) -+ -+struct jffs2_acl_entry { -+ jint16_t e_tag; -+ jint16_t e_perm; -+ jint32_t e_id; -+}; -+ -+struct jffs2_acl_entry_short { -+ jint16_t e_tag; -+ jint16_t e_perm; -+}; -+ -+struct jffs2_acl_header { -+ jint32_t a_version; -+}; -+ -+/* copied from include/linux/posix_acl_xattr.h */ -+#define POSIX_ACL_XATTR_VERSION 0x0002 -+ -+struct posix_acl_xattr_entry { -+ uint16_t e_tag; -+ uint16_t e_perm; -+ uint32_t e_id; -+}; -+ -+struct posix_acl_xattr_header { -+ uint32_t a_version; -+ struct posix_acl_xattr_entry a_entries[0]; -+}; -+ -+#endif /* __JFFS2_USER_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,170 @@ -+/* -+ * $Id: mtd-abi.h,v 1.1.1.1 2008-10-30 14:29:21 lhhuang Exp $ -+ * -+ * Portions of MTD ABI definition which are shared by kernel and user space -+ */ -+ -+#ifndef __MTD_ABI_H__ -+#define __MTD_ABI_H__ -+ -+#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into -+ separate files was to avoid #ifdef __KERNEL__ */ -+#define __user -+#endif -+ -+typedef unsigned long long size_mtd_t; -+typedef unsigned long long loff_mtd_t; -+ -+struct erase_info_user { -+ uint64_t start; -+ uint64_t length; -+}; -+ -+struct mtd_oob_buf { -+ uint32_t start; -+ uint32_t length; -+ unsigned char __user *ptr; -+}; -+ -+struct mtd_page_buf { -+ uint32_t start; //page start address -+ uint32_t ooblength; -+ uint32_t datlength; -+ unsigned char __user *oobptr; -+ unsigned char __user *datptr; -+}; -+ -+#define MTD_ABSENT 0 -+#define MTD_RAM 1 -+#define MTD_ROM 2 -+#define MTD_NORFLASH 3 -+#define MTD_NANDFLASH 4 -+#define MTD_DATAFLASH 6 -+#define MTD_UBIVOLUME 7 -+ -+#define MTD_WRITEABLE 0x400 /* Device is writeable */ -+#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */ -+#define MTD_NO_ERASE 0x1000 /* No erase necessary */ -+#define MTD_STUPID_LOCK 0x2000 /* Always locked after reset */ -+ -+// Some common devices / combinations of capabilities -+#define MTD_CAP_ROM 0 -+#define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE) -+#define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE) -+#define MTD_CAP_NANDFLASH (MTD_WRITEABLE) -+ -+/* ECC byte placement */ -+#define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended) -+#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode) -+#define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme -+#define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read) -+#define MTD_NANDECC_AUTOPL_USR 4 // Use the given autoplacement scheme rather than using the default -+ -+/* OTP mode selection */ -+#define MTD_OTP_OFF 0 -+#define MTD_OTP_FACTORY 1 -+#define MTD_OTP_USER 2 -+ -+struct mtd_info_user { -+ uint8_t type; -+ uint32_t flags; -+ uint64_t size; // Total size of the MTD -+ uint32_t erasesize; -+ uint32_t writesize; -+ uint32_t oobsize; // Amount of OOB data per block (e.g. 16) -+ /* The below two fields are obsolete and broken, do not use them -+ * (TODO: remove at some point) */ -+ uint32_t ecctype; -+ uint32_t eccsize; -+}; -+ -+struct region_info_user { -+ uint64_t offset; /* At which this region starts, -+ * from the beginning of the MTD */ -+ uint32_t erasesize; /* For this region */ -+ uint32_t numblocks; /* Number of blocks in this region */ -+ uint32_t regionindex; -+}; -+ -+struct otp_info { -+ uint32_t start; -+ uint32_t length; -+ uint32_t locked; -+}; -+ -+#define MEMGETINFO _IOR('M', 1, struct mtd_info_user) -+#define MEMERASE _IOW('M', 2, struct erase_info_user) -+#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf) -+#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf) -+#define MEMLOCK _IOW('M', 5, struct erase_info_user) -+#define MEMUNLOCK _IOW('M', 6, struct erase_info_user) -+#define MEMGETREGIONCOUNT _IOR('M', 7, int) -+#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) -+#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) -+#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo) -+#define MEMGETBADBLOCK _IOW('M', 11, loff_mtd_t) -+#define MEMSETBADBLOCK _IOW('M', 12, loff_mtd_t) -+#define OTPSELECT _IOR('M', 13, int) -+#define OTPGETREGIONCOUNT _IOW('M', 14, int) -+#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info) -+#define OTPLOCK _IOR('M', 16, struct otp_info) -+#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout) -+#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats) -+#define MTDFILEMODE _IO('M', 19) -+#define MEMWRITEPAGE _IOWR('M', 20, struct mtd_page_buf) -+ -+/* -+ * Obsolete legacy interface. Keep it in order not to break userspace -+ * interfaces -+ */ -+struct nand_oobinfo { -+ uint32_t useecc; -+ uint32_t eccbytes; -+ uint32_t oobfree[8][2]; -+ uint32_t eccpos[104]; /* more fields(13*8) are required for -+ * 8-bit BCH ECC and 4KB pagesize nand, by Regen */ -+}; -+ -+struct nand_oobfree { -+ uint32_t offset; -+ uint32_t length; -+}; -+ -+#define MTD_MAX_OOBFREE_ENTRIES 8 -+/* -+ * ECC layout control structure. Exported to userspace for -+ * diagnosis and to allow creation of raw images -+ */ -+struct nand_ecclayout { -+ uint32_t eccbytes; -+ uint32_t eccpos[128]; -+ uint32_t oobavail; -+ struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; -+}; -+ -+/** -+ * struct mtd_ecc_stats - error correction stats -+ * -+ * @corrected: number of corrected bits -+ * @failed: number of uncorrectable errors -+ * @badblocks: number of bad blocks in this partition -+ * @bbtblocks: number of blocks reserved for bad block tables -+ */ -+struct mtd_ecc_stats { -+ uint32_t corrected; -+ uint32_t failed; -+ uint32_t badblocks; -+ uint32_t bbtblocks; -+}; -+ -+/* -+ * Read/write file modes for access to MTD -+ */ -+enum mtd_file_modes { -+ MTD_MODE_NORMAL = MTD_OTP_OFF, -+ MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY, -+ MTD_MODE_OTP_USER = MTD_OTP_USER, -+ MTD_MODE_RAW, -+}; -+ -+#endif /* __MTD_ABI_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/mtd-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/mtd-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,21 @@ -+/* -+ * $Id: mtd-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ * MTD ABI header for use by user space only. -+ */ -+ -+#ifndef __MTD_USER_H__ -+#define __MTD_USER_H__ -+ -+#include -+ -+/* This file is blessed for inclusion by userspace */ -+#include -+ -+typedef struct mtd_info_user mtd_info_t; -+typedef struct erase_info_user erase_info_t; -+typedef struct region_info_user region_info_t; -+typedef struct nand_oobinfo nand_oobinfo_t; -+typedef struct nand_ecclayout nand_ecclayout_t; -+ -+#endif /* __MTD_USER_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/nftl-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/nftl-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,76 @@ -+/* -+ * $Id: nftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ * Parts of NFTL headers shared with userspace -+ * -+ */ -+ -+#ifndef __MTD_NFTL_USER_H__ -+#define __MTD_NFTL_USER_H__ -+ -+/* Block Control Information */ -+ -+struct nftl_bci { -+ unsigned char ECCSig[6]; -+ uint8_t Status; -+ uint8_t Status1; -+}__attribute__((packed)); -+ -+/* Unit Control Information */ -+ -+struct nftl_uci0 { -+ uint16_t VirtUnitNum; -+ uint16_t ReplUnitNum; -+ uint16_t SpareVirtUnitNum; -+ uint16_t SpareReplUnitNum; -+} __attribute__((packed)); -+ -+struct nftl_uci1 { -+ uint32_t WearInfo; -+ uint16_t EraseMark; -+ uint16_t EraseMark1; -+} __attribute__((packed)); -+ -+struct nftl_uci2 { -+ uint16_t FoldMark; -+ uint16_t FoldMark1; -+ uint32_t unused; -+} __attribute__((packed)); -+ -+union nftl_uci { -+ struct nftl_uci0 a; -+ struct nftl_uci1 b; -+ struct nftl_uci2 c; -+}; -+ -+struct nftl_oob { -+ struct nftl_bci b; -+ union nftl_uci u; -+}; -+ -+/* NFTL Media Header */ -+ -+struct NFTLMediaHeader { -+ char DataOrgID[6]; -+ uint16_t NumEraseUnits; -+ uint16_t FirstPhysicalEUN; -+ uint32_t FormattedSize; -+ unsigned char UnitSizeFactor; -+} __attribute__((packed)); -+ -+#define MAX_ERASE_ZONES (8192 - 512) -+ -+#define ERASE_MARK 0x3c69 -+#define SECTOR_FREE 0xff -+#define SECTOR_USED 0x55 -+#define SECTOR_IGNORE 0x11 -+#define SECTOR_DELETED 0x00 -+ -+#define FOLD_MARK_IN_PROGRESS 0x5555 -+ -+#define ZONE_GOOD 0xff -+#define ZONE_BAD_ORIGINAL 0 -+#define ZONE_BAD_MARKED 7 -+ -+ -+#endif /* __MTD_NFTL_USER_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/ubi-header.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/ubi-header.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,372 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Артём) -+ * Thomas Gleixner -+ * Frank Haverkamp -+ * Oliver Lohmann -+ * Andreas Arnez -+ */ -+ -+/* -+ * This file defines the layout of UBI headers and all the other UBI on-flash -+ * data structures. May be included by user-space. -+ */ -+ -+#ifndef __UBI_HEADER_H__ -+#define __UBI_HEADER_H__ -+ -+#include -+ -+/* The version of UBI images supported by this implementation */ -+#define UBI_VERSION 1 -+ -+/* The highest erase counter value supported by this implementation */ -+#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF -+ -+/* The initial CRC32 value used when calculating CRC checksums */ -+#define UBI_CRC32_INIT 0xFFFFFFFFU -+ -+/* Erase counter header magic number (ASCII "UBI#") */ -+#define UBI_EC_HDR_MAGIC 0x55424923 -+/* Volume identifier header magic number (ASCII "UBI!") */ -+#define UBI_VID_HDR_MAGIC 0x55424921 -+ -+/* -+ * Volume type constants used in the volume identifier header. -+ * -+ * @UBI_VID_DYNAMIC: dynamic volume -+ * @UBI_VID_STATIC: static volume -+ */ -+enum { -+ UBI_VID_DYNAMIC = 1, -+ UBI_VID_STATIC = 2 -+}; -+ -+/* -+ * Volume flags used in the volume table record. -+ * -+ * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume -+ * -+ * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume -+ * table. UBI automatically re-sizes the volume which has this flag and makes -+ * the volume to be of largest possible size. This means that if after the -+ * initialization UBI finds out that there are available physical eraseblocks -+ * present on the device, it automatically appends all of them to the volume -+ * (the physical eraseblocks reserved for bad eraseblocks handling and other -+ * reserved physical eraseblocks are not taken). So, if there is a volume with -+ * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical -+ * eraseblocks will be zero after UBI is loaded, because all of them will be -+ * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared -+ * after the volume had been initialized. -+ * -+ * The auto-resize feature is useful for device production purposes. For -+ * example, different NAND flash chips may have different amount of initial bad -+ * eraseblocks, depending of particular chip instance. Manufacturers of NAND -+ * chips usually guarantee that the amount of initial bad eraseblocks does not -+ * exceed certain percent, e.g. 2%. When one creates an UBI image which will be -+ * flashed to the end devices in production, he does not know the exact amount -+ * of good physical eraseblocks the NAND chip on the device will have, but this -+ * number is required to calculate the volume sized and put them to the volume -+ * table of the UBI image. In this case, one of the volumes (e.g., the one -+ * which will store the root file system) is marked as "auto-resizable", and -+ * UBI will adjust its size on the first boot if needed. -+ * -+ * Note, first UBI reserves some amount of physical eraseblocks for bad -+ * eraseblock handling, and then re-sizes the volume, not vice-versa. This -+ * means that the pool of reserved physical eraseblocks will always be present. -+ */ -+enum { -+ UBI_VTBL_AUTORESIZE_FLG = 0x01, -+}; -+ -+/* -+ * Compatibility constants used by internal volumes. -+ * -+ * @UBI_COMPAT_DELETE: delete this internal volume before anything is written -+ * to the flash -+ * @UBI_COMPAT_RO: attach this device in read-only mode -+ * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its -+ * physical eraseblocks, don't allow the wear-leveling unit to move them -+ * @UBI_COMPAT_REJECT: reject this UBI image -+ */ -+enum { -+ UBI_COMPAT_DELETE = 1, -+ UBI_COMPAT_RO = 2, -+ UBI_COMPAT_PRESERVE = 4, -+ UBI_COMPAT_REJECT = 5 -+}; -+ -+/* Sizes of UBI headers */ -+#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr) -+#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr) -+ -+/* Sizes of UBI headers without the ending CRC */ -+#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(uint32_t)) -+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(uint32_t)) -+ -+/** -+ * struct ubi_ec_hdr - UBI erase counter header. -+ * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC) -+ * @version: version of UBI implementation which is supposed to accept this -+ * UBI image -+ * @padding1: reserved for future, zeroes -+ * @ec: the erase counter -+ * @vid_hdr_offset: where the VID header starts -+ * @data_offset: where the user data start -+ * @padding2: reserved for future, zeroes -+ * @hdr_crc: erase counter header CRC checksum -+ * -+ * The erase counter header takes 64 bytes and has a plenty of unused space for -+ * future usage. The unused fields are zeroed. The @version field is used to -+ * indicate the version of UBI implementation which is supposed to be able to -+ * work with this UBI image. If @version is greater then the current UBI -+ * version, the image is rejected. This may be useful in future if something -+ * is changed radically. This field is duplicated in the volume identifier -+ * header. -+ * -+ * The @vid_hdr_offset and @data_offset fields contain the offset of the the -+ * volume identifier header and user data, relative to the beginning of the -+ * physical eraseblock. These values have to be the same for all physical -+ * eraseblocks. -+ */ -+struct ubi_ec_hdr { -+ uint32_t magic; -+ uint8_t version; -+ uint8_t padding1[3]; -+ uint64_t ec; /* Warning: the current limit is 31-bit anyway! */ -+ uint32_t vid_hdr_offset; -+ uint32_t data_offset; -+ uint8_t padding2[36]; -+ uint32_t hdr_crc; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubi_vid_hdr - on-flash UBI volume identifier header. -+ * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC) -+ * @version: UBI implementation version which is supposed to accept this UBI -+ * image (%UBI_VERSION) -+ * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) -+ * @copy_flag: if this logical eraseblock was copied from another physical -+ * eraseblock (for wear-leveling reasons) -+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, -+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) -+ * @vol_id: ID of this volume -+ * @lnum: logical eraseblock number -+ * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be -+ * removed, kept only for not breaking older UBI users) -+ * @data_size: how many bytes of data this logical eraseblock contains -+ * @used_ebs: total number of used logical eraseblocks in this volume -+ * @data_pad: how many bytes at the end of this physical eraseblock are not -+ * used -+ * @data_crc: CRC checksum of the data stored in this logical eraseblock -+ * @padding1: reserved for future, zeroes -+ * @sqnum: sequence number -+ * @padding2: reserved for future, zeroes -+ * @hdr_crc: volume identifier header CRC checksum -+ * -+ * The @sqnum is the value of the global sequence counter at the time when this -+ * VID header was created. The global sequence counter is incremented each time -+ * UBI writes a new VID header to the flash, i.e. when it maps a logical -+ * eraseblock to a new physical eraseblock. The global sequence counter is an -+ * unsigned 64-bit integer and we assume it never overflows. The @sqnum -+ * (sequence number) is used to distinguish between older and newer versions of -+ * logical eraseblocks. -+ * -+ * There are 2 situations when there may be more then one physical eraseblock -+ * corresponding to the same logical eraseblock, i.e., having the same @vol_id -+ * and @lnum values in the volume identifier header. Suppose we have a logical -+ * eraseblock L and it is mapped to the physical eraseblock P. -+ * -+ * 1. Because UBI may erase physical eraseblocks asynchronously, the following -+ * situation is possible: L is asynchronously erased, so P is scheduled for -+ * erasure, then L is written to,i.e. mapped to another physical eraseblock P1, -+ * so P1 is written to, then an unclean reboot happens. Result - there are 2 -+ * physical eraseblocks P and P1 corresponding to the same logical eraseblock -+ * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the -+ * flash. -+ * -+ * 2. From time to time UBI moves logical eraseblocks to other physical -+ * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P -+ * to P1, and an unclean reboot happens before P is physically erased, there -+ * are two physical eraseblocks P and P1 corresponding to L and UBI has to -+ * select one of them when the flash is attached. The @sqnum field says which -+ * PEB is the original (obviously P will have lower @sqnum) and the copy. But -+ * it is not enough to select the physical eraseblock with the higher sequence -+ * number, because the unclean reboot could have happen in the middle of the -+ * copying process, so the data in P is corrupted. It is also not enough to -+ * just select the physical eraseblock with lower sequence number, because the -+ * data there may be old (consider a case if more data was added to P1 after -+ * the copying). Moreover, the unclean reboot may happen when the erasure of P -+ * was just started, so it result in unstable P, which is "mostly" OK, but -+ * still has unstable bits. -+ * -+ * UBI uses the @copy_flag field to indicate that this logical eraseblock is a -+ * copy. UBI also calculates data CRC when the data is moved and stores it at -+ * the @data_crc field of the copy (P1). So when UBI needs to pick one physical -+ * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is -+ * examined. If it is cleared, the situation* is simple and the newer one is -+ * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC -+ * checksum is correct, this physical eraseblock is selected (P1). Otherwise -+ * the older one (P) is selected. -+ * -+ * Note, there is an obsolete @leb_ver field which was used instead of @sqnum -+ * in the past. But it is not used anymore and we keep it in order to be able -+ * to deal with old UBI images. It will be removed at some point. -+ * -+ * There are 2 sorts of volumes in UBI: user volumes and internal volumes. -+ * Internal volumes are not seen from outside and are used for various internal -+ * UBI purposes. In this implementation there is only one internal volume - the -+ * layout volume. Internal volumes are the main mechanism of UBI extensions. -+ * For example, in future one may introduce a journal internal volume. Internal -+ * volumes have their own reserved range of IDs. -+ * -+ * The @compat field is only used for internal volumes and contains the "degree -+ * of their compatibility". It is always zero for user volumes. This field -+ * provides a mechanism to introduce UBI extensions and to be still compatible -+ * with older UBI binaries. For example, if someone introduced a journal in -+ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the -+ * journal volume. And in this case, older UBI binaries, which know nothing -+ * about the journal volume, would just delete this volume and work perfectly -+ * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image -+ * - it just ignores the Ext3fs journal. -+ * -+ * The @data_crc field contains the CRC checksum of the contents of the logical -+ * eraseblock if this is a static volume. In case of dynamic volumes, it does -+ * not contain the CRC checksum as a rule. The only exception is when the -+ * data of the physical eraseblock was moved by the wear-leveling unit, then -+ * the wear-leveling unit calculates the data CRC and stores it in the -+ * @data_crc field. And of course, the @copy_flag is %in this case. -+ * -+ * The @data_size field is used only for static volumes because UBI has to know -+ * how many bytes of data are stored in this eraseblock. For dynamic volumes, -+ * this field usually contains zero. The only exception is when the data of the -+ * physical eraseblock was moved to another physical eraseblock for -+ * wear-leveling reasons. In this case, UBI calculates CRC checksum of the -+ * contents and uses both @data_crc and @data_size fields. In this case, the -+ * @data_size field contains data size. -+ * -+ * The @used_ebs field is used only for static volumes and indicates how many -+ * eraseblocks the data of the volume takes. For dynamic volumes this field is -+ * not used and always contains zero. -+ * -+ * The @data_pad is calculated when volumes are created using the alignment -+ * parameter. So, effectively, the @data_pad field reduces the size of logical -+ * eraseblocks of this volume. This is very handy when one uses block-oriented -+ * software (say, cramfs) on top of the UBI volume. -+ */ -+struct ubi_vid_hdr { -+ uint32_t magic; -+ uint8_t version; -+ uint8_t vol_type; -+ uint8_t copy_flag; -+ uint8_t compat; -+ uint32_t vol_id; -+ uint32_t lnum; -+ uint32_t leb_ver; /* obsolete, to be removed, don't use */ -+ uint32_t data_size; -+ uint32_t used_ebs; -+ uint32_t data_pad; -+ uint32_t data_crc; -+ uint8_t padding1[4]; -+ uint64_t sqnum; -+ uint8_t padding2[12]; -+ uint32_t hdr_crc; -+} __attribute__ ((packed)); -+ -+/* Internal UBI volumes count */ -+#define UBI_INT_VOL_COUNT 1 -+ -+/* -+ * Starting ID of internal volumes. There is reserved room for 4096 internal -+ * volumes. -+ */ -+#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096) -+ -+/* The layout volume contains the volume table */ -+ -+#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START -+#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC -+#define UBI_LAYOUT_VOLUME_ALIGN 1 -+#define UBI_LAYOUT_VOLUME_EBS 2 -+#define UBI_LAYOUT_VOLUME_NAME "layout volume" -+#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT -+ -+/* The maximum number of volumes per one UBI device */ -+#define UBI_MAX_VOLUMES 128 -+ -+/* The maximum volume name length */ -+#define UBI_VOL_NAME_MAX 127 -+ -+/* Size of the volume table record */ -+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record) -+ -+/* Size of the volume table record without the ending CRC */ -+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(uint32_t)) -+ -+/** -+ * struct ubi_vtbl_record - a record in the volume table. -+ * @reserved_pebs: how many physical eraseblocks are reserved for this volume -+ * @alignment: volume alignment -+ * @data_pad: how many bytes are unused at the end of the each physical -+ * eraseblock to satisfy the requested alignment -+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @upd_marker: if volume update was started but not finished -+ * @name_len: volume name length -+ * @name: the volume name -+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) -+ * @padding: reserved, zeroes -+ * @crc: a CRC32 checksum of the record -+ * -+ * The volume table records are stored in the volume table, which is stored in -+ * the layout volume. The layout volume consists of 2 logical eraseblock, each -+ * of which contains a copy of the volume table (i.e., the volume table is -+ * duplicated). The volume table is an array of &struct ubi_vtbl_record -+ * objects indexed by the volume ID. -+ * -+ * If the size of the logical eraseblock is large enough to fit -+ * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES -+ * records. Otherwise, it contains as many records as it can fit (i.e., size of -+ * logical eraseblock divided by sizeof(struct ubi_vtbl_record)). -+ * -+ * The @upd_marker flag is used to implement volume update. It is set to %1 -+ * before update and set to %0 after the update. So if the update operation was -+ * interrupted, UBI knows that the volume is corrupted. -+ * -+ * The @alignment field is specified when the volume is created and cannot be -+ * later changed. It may be useful, for example, when a block-oriented file -+ * system works on top of UBI. The @data_pad field is calculated using the -+ * logical eraseblock size and @alignment. The alignment must be multiple to the -+ * minimal flash I/O unit. If @alignment is 1, all the available space of -+ * the physical eraseblocks is used. -+ * -+ * Empty records contain all zeroes and the CRC checksum of those zeroes. -+ */ -+struct ubi_vtbl_record { -+ uint32_t reserved_pebs; -+ uint32_t alignment; -+ uint32_t data_pad; -+ uint8_t vol_type; -+ uint8_t upd_marker; -+ uint16_t name_len; -+ uint8_t name[UBI_VOL_NAME_MAX+1]; -+ uint8_t flags; -+ uint8_t padding[23]; -+ uint32_t crc; -+} __attribute__ ((packed)); -+ -+#endif /* !__UBI_HEADER_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/ubi-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/ubi-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,284 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Author: Artem Bityutskiy (Битюцкий Артём) -+ */ -+ -+#ifndef __UBI_USER_H__ -+#define __UBI_USER_H__ -+ -+#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into -+ separate files was to avoid #ifdef __KERNEL__ */ -+#define __user -+#endif -+/* -+ * UBI device creation (the same as MTD device attachment) -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI -+ * control device. The caller has to properly fill and pass -+ * &struct ubi_attach_req object - UBI will attach the MTD device specified in -+ * the request and return the newly created UBI device number as the ioctl -+ * return value. -+ * -+ * UBI device deletion (the same as MTD device detachment) -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI -+ * control device. -+ * -+ * UBI volume creation -+ * ~~~~~~~~~~~~~~~~~~~ -+ * -+ * UBI volumes are created via the %UBI_IOCMKVOL IOCTL command of UBI character -+ * device. A &struct ubi_mkvol_req object has to be properly filled and a -+ * pointer to it has to be passed to the IOCTL. -+ * -+ * UBI volume deletion -+ * ~~~~~~~~~~~~~~~~~~~ -+ * -+ * To delete a volume, the %UBI_IOCRMVOL IOCTL command of the UBI character -+ * device should be used. A pointer to the 32-bit volume ID hast to be passed -+ * to the IOCTL. -+ * -+ * UBI volume re-size -+ * ~~~~~~~~~~~~~~~~~~ -+ * -+ * To re-size a volume, the %UBI_IOCRSVOL IOCTL command of the UBI character -+ * device should be used. A &struct ubi_rsvol_req object has to be properly -+ * filled and a pointer to it has to be passed to the IOCTL. -+ * -+ * UBI volume update -+ * ~~~~~~~~~~~~~~~~~ -+ * -+ * Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the -+ * corresponding UBI volume character device. A pointer to a 64-bit update -+ * size should be passed to the IOCTL. After this, UBI expects user to write -+ * this number of bytes to the volume character device. The update is finished -+ * when the claimed number of bytes is passed. So, the volume update sequence -+ * is something like: -+ * -+ * fd = open("/dev/my_volume"); -+ * ioctl(fd, UBI_IOCVOLUP, &image_size); -+ * write(fd, buf, image_size); -+ * close(fd); -+ * -+ * Atomic eraseblock change -+ * ~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL -+ * command of the corresponding UBI volume character device. A pointer to -+ * &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is -+ * expected to write the requested amount of bytes. This is similar to the -+ * "volume update" IOCTL. -+ */ -+ -+/* -+ * When a new UBI volume or UBI device is created, users may either specify the -+ * volume/device number they want to create or to let UBI automatically assign -+ * the number using these constants. -+ */ -+#define UBI_VOL_NUM_AUTO (-1) -+#define UBI_DEV_NUM_AUTO (-1) -+ -+/* Maximum volume name length */ -+#define UBI_MAX_VOLUME_NAME 127 -+ -+/* IOCTL commands of UBI character devices */ -+ -+#define UBI_IOC_MAGIC 'o' -+ -+/* Create an UBI volume */ -+#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req) -+/* Remove an UBI volume */ -+#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t) -+/* Re-size an UBI volume */ -+#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) -+ -+/* IOCTL commands of the UBI control character device */ -+ -+#define UBI_CTRL_IOC_MAGIC 'o' -+ -+/* Attach an MTD device */ -+#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req) -+/* Detach an MTD device */ -+#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t) -+ -+/* IOCTL commands of UBI volume character devices */ -+ -+#define UBI_VOL_IOC_MAGIC 'O' -+ -+/* Start UBI volume update */ -+#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t) -+/* An eraseblock erasure command, used for debugging, disabled by default */ -+#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t) -+/* An atomic eraseblock change command */ -+#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t) -+/* Start UBI leb read */ -+#define UBI_IOCLEBREAD _IOWR(UBI_VOL_IOC_MAGIC, 3, struct ubi_leb) -+ -+/* Maximum MTD device name length supported by UBI */ -+#define MAX_UBI_MTD_NAME_LEN 127 -+ -+/* -+ * UBI data type hint constants. -+ * -+ * UBI_LONGTERM: long-term data -+ * UBI_SHORTTERM: short-term data -+ * UBI_UNKNOWN: data persistence is unknown -+ * -+ * These constants are used when data is written to UBI volumes in order to -+ * help the UBI wear-leveling unit to find more appropriate physical -+ * eraseblocks. -+ */ -+enum { -+ UBI_LONGTERM = 1, -+ UBI_SHORTTERM = 2, -+ UBI_UNKNOWN = 3, -+}; -+ -+/* -+ * UBI volume type constants. -+ * -+ * @UBI_DYNAMIC_VOLUME: dynamic volume -+ * @UBI_STATIC_VOLUME: static volume -+ */ -+enum { -+ UBI_DYNAMIC_VOLUME = 3, -+ UBI_STATIC_VOLUME = 4, -+}; -+ -+/** -+ * struct ubi_attach_req - attach MTD device request. -+ * @ubi_num: UBI device number to create -+ * @mtd_num: MTD device number to attach -+ * @vid_hdr_offset: VID header offset (use defaults if %0) -+ * @padding: reserved for future, not used, has to be zeroed -+ * -+ * This data structure is used to specify MTD device UBI has to attach and the -+ * parameters it has to use. The number which should be assigned to the new UBI -+ * device is passed in @ubi_num. UBI may automatically assign the number if -+ * @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in -+ * @ubi_num. -+ * -+ * Most applications should pass %0 in @vid_hdr_offset to make UBI use default -+ * offset of the VID header within physical eraseblocks. The default offset is -+ * the next min. I/O unit after the EC header. For example, it will be offset -+ * 512 in case of a 512 bytes page NAND flash with no sub-page support. Or -+ * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages. -+ * -+ * But in rare cases, if this optimizes things, the VID header may be placed to -+ * a different offset. For example, the boot-loader might do things faster if the -+ * VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As -+ * the boot-loader would not normally need to read EC headers (unless it needs -+ * UBI in RW mode), it might be faster to calculate ECC. This is weird example, -+ * but it real-life example. So, in this example, @vid_hdr_offer would be -+ * 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes -+ * aligned, which is OK, as UBI is clever enough to realize this is 4th sub-page -+ * of the first page and add needed padding. -+ */ -+struct ubi_attach_req { -+ int32_t ubi_num; -+ int32_t mtd_num; -+ int32_t vid_hdr_offset; -+ uint8_t padding[12]; -+}; -+ -+/** -+ * struct ubi_mkvol_req - volume description data structure used in -+ * volume creation requests. -+ * @vol_id: volume number -+ * @alignment: volume alignment -+ * @bytes: volume size in bytes -+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @padding1: reserved for future, not used, has to be zeroed -+ * @name_len: volume name length -+ * @padding2: reserved for future, not used, has to be zeroed -+ * @name: volume name -+ * -+ * This structure is used by user-space programs when creating new volumes. The -+ * @used_bytes field is only necessary when creating static volumes. -+ * -+ * The @alignment field specifies the required alignment of the volume logical -+ * eraseblock. This means, that the size of logical eraseblocks will be aligned -+ * to this number, i.e., -+ * (UBI device logical eraseblock size) mod (@alignment) = 0. -+ * -+ * To put it differently, the logical eraseblock of this volume may be slightly -+ * shortened in order to make it properly aligned. The alignment has to be -+ * multiple of the flash minimal input/output unit, or %1 to utilize the entire -+ * available space of logical eraseblocks. -+ * -+ * The @alignment field may be useful, for example, when one wants to maintain -+ * a block device on top of an UBI volume. In this case, it is desirable to fit -+ * an integer number of blocks in logical eraseblocks of this UBI volume. With -+ * alignment it is possible to update this volume using plane UBI volume image -+ * BLOBs, without caring about how to properly align them. -+ */ -+struct ubi_mkvol_req { -+ int32_t vol_id; -+ int32_t alignment; -+ int64_t bytes; -+ int8_t vol_type; -+ int8_t padding1; -+ int16_t name_len; -+ int8_t padding2[4]; -+ char name[UBI_MAX_VOLUME_NAME + 1]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubi_rsvol_req - a data structure used in volume re-size requests. -+ * @vol_id: ID of the volume to re-size -+ * @bytes: new size of the volume in bytes -+ * -+ * Re-sizing is possible for both dynamic and static volumes. But while dynamic -+ * volumes may be re-sized arbitrarily, static volumes cannot be made to be -+ * smaller then the number of bytes they bear. To arbitrarily shrink a static -+ * volume, it must be wiped out first (by means of volume update operation with -+ * zero number of bytes). -+ */ -+struct ubi_rsvol_req { -+ int64_t bytes; -+ int32_t vol_id; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubi_leb_change_req - a data structure used in atomic logical -+ * eraseblock change requests. -+ * @lnum: logical eraseblock number to change -+ * @bytes: how many bytes will be written to the logical eraseblock -+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN) -+ * @padding: reserved for future, not used, has to be zeroed -+ */ -+struct ubi_leb_change_req { -+ int32_t lnum; -+ int32_t bytes; -+ uint8_t dtype; -+ uint8_t padding[7]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubi_leb - a data structure describe LEB. -+ * @lnum: logical eraseblock number to dump -+ * @lebbuf: LEB data buffer -+ */ -+struct ubi_leb{ -+ unsigned int lnum; -+ char __user *buf; -+}; -+ -+#endif /* __UBI_USER_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd_swab.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd_swab.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,51 @@ -+#ifndef MTD_SWAB_H -+#define MTD_SWAB_H -+ -+#include -+ -+#define swab16(x) \ -+ ((uint16_t)( \ -+ (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \ -+ (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) )) -+#define swab32(x) \ -+ ((uint32_t)( \ -+ (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \ -+ (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \ -+ (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \ -+ (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) )) -+ -+#define swab64(x) \ -+ ((uint64_t)( \ -+ (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \ -+ (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ -+ (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ -+ (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ -+ (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ -+ (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ -+ (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ -+ (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) )) -+ -+ -+#if __BYTE_ORDER == __BIG_ENDIAN -+#define cpu_to_le16(x) ({ uint16_t _x = x; swab16(_x); }) -+#define cpu_to_le32(x) ({ uint32_t _x = x; swab32(_x); }) -+#define cpu_to_le64(x) ({ uint64_t _x = x; swab64(_x); }) -+#define cpu_to_be16(x) (x) -+#define cpu_to_be32(x) (x) -+#define cpu_to_be64(x) (x) -+#else -+#define cpu_to_le16(x) (x) -+#define cpu_to_le32(x) (x) -+#define cpu_to_le64(x) (x) -+#define cpu_to_be16(x) ({ uint16_t _x = x; swab16(_x); }) -+#define cpu_to_be32(x) ({ uint32_t _x = x; swab32(_x); }) -+#define cpu_to_be64(x) ({ uint64_t _x = x; swab64(_x); }) -+#endif -+#define le16_to_cpu(x) cpu_to_le16(x) -+#define be16_to_cpu(x) cpu_to_be16(x) -+#define le32_to_cpu(x) cpu_to_le32(x) -+#define be32_to_cpu(x) cpu_to_be32(x) -+#define le64_to_cpu(x) cpu_to_le64(x) -+#define be64_to_cpu(x) cpu_to_be64(x) -+ -+#endif ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/jffs-dump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/jffs-dump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,359 @@ -+/* -+ * Dump JFFS filesystem. -+ * Useful when it buggers up. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define BLOCK_SIZE 1024 -+#define JFFS_MAGIC 0x34383931 /* "1984" */ -+#define JFFS_MAX_NAME_LEN 256 -+#define JFFS_MIN_INO 1 -+#define JFFS_TRACE_INDENT 4 -+#define JFFS_ALIGN_SIZE 4 -+#define MAX_CHUNK_SIZE 32768 -+ -+/* How many padding bytes should be inserted between two chunks of data -+ on the flash? */ -+#define JFFS_GET_PAD_BYTES(size) ((JFFS_ALIGN_SIZE \ -+ - ((uint32_t)(size) % JFFS_ALIGN_SIZE)) \ -+ % JFFS_ALIGN_SIZE) -+ -+#define JFFS_EMPTY_BITMASK 0xffffffff -+#define JFFS_MAGIC_BITMASK 0x34383931 -+#define JFFS_DIRTY_BITMASK 0x00000000 -+ -+#define min(x,y) (x) > (y) ? (y) : (x) -+ -+struct jffs_raw_inode -+{ -+ uint32_t magic; /* A constant magic number. */ -+ uint32_t ino; /* Inode number. */ -+ uint32_t pino; /* Parent's inode number. */ -+ uint32_t version; /* Version number. */ -+ uint32_t mode; /* file_type, mode */ -+ uint16_t uid; -+ uint16_t gid; -+ uint32_t atime; -+ uint32_t mtime; -+ uint32_t ctime; -+ uint32_t offset; /* Where to begin to write. */ -+ uint32_t dsize; /* Size of the file data. */ -+ uint32_t rsize; /* How much are going to be replaced? */ -+ uint8_t nsize; /* Name length. */ -+ uint8_t nlink; /* Number of links. */ -+ uint8_t spare : 6; /* For future use. */ -+ uint8_t rename : 1; /* Is this a special rename? */ -+ uint8_t deleted : 1; /* Has this file been deleted? */ -+ uint8_t accurate; /* The inode is obsolete if accurate == 0. */ -+ uint32_t dchksum; /* Checksum for the data. */ -+ uint16_t nchksum; /* Checksum for the name. */ -+ uint16_t chksum; /* Checksum for the raw_inode. */ -+}; -+ -+ -+struct jffs_file -+{ -+ struct jffs_raw_inode inode; -+ char *name; -+ unsigned char *data; -+}; -+ -+ -+char *root_directory_name = NULL; -+int fs_pos = 0; -+int verbose = 0; -+ -+#define ENDIAN_HOST 0 -+#define ENDIAN_BIG 1 -+#define ENDIAN_LITTLE 2 -+int endian = ENDIAN_HOST; -+ -+static uint32_t jffs_checksum(void *data, int size); -+void jffs_print_trace(const char *path, int depth); -+int make_root_dir(FILE *fs, int first_ino, const char *root_dir_path, -+ int depth); -+void write_file(struct jffs_file *f, FILE *fs, struct stat st); -+void read_data(struct jffs_file *f, const char *path, int offset); -+int mkfs(FILE *fs, const char *path, int ino, int parent, int depth); -+ -+ -+ static uint32_t -+jffs_checksum(void *data, int size) -+{ -+ uint32_t sum = 0; -+ uint8_t *ptr = (uint8_t *)data; -+ -+ while (size-- > 0) -+ { -+ sum += *ptr++; -+ } -+ -+ return sum; -+} -+ -+ -+ void -+jffs_print_trace(const char *path, int depth) -+{ -+ int path_len = strlen(path); -+ int out_pos = depth * JFFS_TRACE_INDENT; -+ int pos = path_len - 1; -+ char *out = (char *)alloca(depth * JFFS_TRACE_INDENT + path_len + 1); -+ -+ if (verbose >= 2) -+ { -+ fprintf(stderr, "jffs_print_trace(): path: \"%s\"\n", path); -+ } -+ -+ if (!out) { -+ fprintf(stderr, "jffs_print_trace(): Allocation failed.\n"); -+ fprintf(stderr, " path: \"%s\"\n", path); -+ fprintf(stderr, "depth: %d\n", depth); -+ exit(1); -+ } -+ -+ memset(out, ' ', depth * JFFS_TRACE_INDENT); -+ -+ if (path[pos] == '/') -+ { -+ pos--; -+ } -+ while (path[pos] && (path[pos] != '/')) -+ { -+ pos--; -+ } -+ for (pos++; path[pos] && (path[pos] != '/'); pos++) -+ { -+ out[out_pos++] = path[pos]; -+ } -+ out[out_pos] = '\0'; -+ fprintf(stderr, "%s\n", out); -+} -+ -+ -+/* Print the contents of a raw inode. */ -+ void -+jffs_print_raw_inode(struct jffs_raw_inode *raw_inode) -+{ -+ fprintf(stdout, "jffs_raw_inode: inode number: %u, version %u\n", raw_inode->ino, raw_inode->version); -+ fprintf(stdout, "{\n"); -+ fprintf(stdout, " 0x%08x, /* magic */\n", raw_inode->magic); -+ fprintf(stdout, " 0x%08x, /* ino */\n", raw_inode->ino); -+ fprintf(stdout, " 0x%08x, /* pino */\n", raw_inode->pino); -+ fprintf(stdout, " 0x%08x, /* version */\n", raw_inode->version); -+ fprintf(stdout, " 0x%08x, /* mode */\n", raw_inode->mode); -+ fprintf(stdout, " 0x%04x, /* uid */\n", raw_inode->uid); -+ fprintf(stdout, " 0x%04x, /* gid */\n", raw_inode->gid); -+ fprintf(stdout, " 0x%08x, /* atime */\n", raw_inode->atime); -+ fprintf(stdout, " 0x%08x, /* mtime */\n", raw_inode->mtime); -+ fprintf(stdout, " 0x%08x, /* ctime */\n", raw_inode->ctime); -+ fprintf(stdout, " 0x%08x, /* offset */\n", raw_inode->offset); -+ fprintf(stdout, " 0x%08x, /* dsize */\n", raw_inode->dsize); -+ fprintf(stdout, " 0x%08x, /* rsize */\n", raw_inode->rsize); -+ fprintf(stdout, " 0x%02x, /* nsize */\n", raw_inode->nsize); -+ fprintf(stdout, " 0x%02x, /* nlink */\n", raw_inode->nlink); -+ fprintf(stdout, " 0x%02x, /* spare */\n", -+ raw_inode->spare); -+ fprintf(stdout, " %u, /* rename */\n", -+ raw_inode->rename); -+ fprintf(stdout, " %u, /* deleted */\n", -+ raw_inode->deleted); -+ fprintf(stdout, " 0x%02x, /* accurate */\n", -+ raw_inode->accurate); -+ fprintf(stdout, " 0x%08x, /* dchksum */\n", raw_inode->dchksum); -+ fprintf(stdout, " 0x%04x, /* nchksum */\n", raw_inode->nchksum); -+ fprintf(stdout, " 0x%04x, /* chksum */\n", raw_inode->chksum); -+ fprintf(stdout, "}\n"); -+} -+ -+static void write_val32(uint32_t *adr, uint32_t val) -+{ -+ switch(endian) { -+ case ENDIAN_HOST: -+ *adr = val; -+ break; -+ case ENDIAN_LITTLE: -+ *adr = __cpu_to_le32(val); -+ break; -+ case ENDIAN_BIG: -+ *adr = __cpu_to_be32(val); -+ break; -+ } -+} -+ -+static void write_val16(uint16_t *adr, uint16_t val) -+{ -+ switch(endian) { -+ case ENDIAN_HOST: -+ *adr = val; -+ break; -+ case ENDIAN_LITTLE: -+ *adr = __cpu_to_le16(val); -+ break; -+ case ENDIAN_BIG: -+ *adr = __cpu_to_be16(val); -+ break; -+ } -+} -+ -+static uint32_t read_val32(uint32_t *adr) -+{ -+ uint32_t val; -+ -+ switch(endian) { -+ case ENDIAN_HOST: -+ val = *adr; -+ break; -+ case ENDIAN_LITTLE: -+ val = __le32_to_cpu(*adr); -+ break; -+ case ENDIAN_BIG: -+ val = __be32_to_cpu(*adr); -+ break; -+ } -+ return val; -+} -+ -+static uint16_t read_val16(uint16_t *adr) -+{ -+ uint16_t val; -+ -+ switch(endian) { -+ case ENDIAN_HOST: -+ val = *adr; -+ break; -+ case ENDIAN_LITTLE: -+ val = __le16_to_cpu(*adr); -+ break; -+ case ENDIAN_BIG: -+ val = __be16_to_cpu(*adr); -+ break; -+ } -+ return val; -+} -+ -+ int -+main(int argc, char **argv) -+{ -+ int fs; -+ struct stat sb; -+ uint32_t wordbuf; -+ off_t pos = 0; -+ off_t end; -+ struct jffs_raw_inode ino; -+ unsigned char namebuf[4096]; -+ int myino = -1; -+ -+ if (argc < 2) { -+ printf("no filesystem given\n"); -+ exit(1); -+ } -+ -+ fs = open(argv[1], O_RDONLY); -+ if (fs < 0) { -+ perror("open"); -+ exit(1); -+ } -+ -+ if (argc > 2) { -+ myino = atol(argv[2]); -+ printf("Printing ino #%d\n" , myino); -+ } -+ -+ if (fstat(fs, &sb) < 0) { -+ perror("stat"); -+ close(fs); -+ exit(1); -+ } -+ end = sb.st_size; -+ -+ while (pos < end) { -+ if (pread(fs, &wordbuf, 4, pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ -+ switch(wordbuf) { -+ case JFFS_EMPTY_BITMASK: -+ // printf("0xff started at 0x%lx\n", pos); -+ for (; pos < end && wordbuf == JFFS_EMPTY_BITMASK; pos += 4) { -+ if (pread(fs, &wordbuf, 4, pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ } -+ if (pos < end) -+ pos -= 4; -+ // printf("0xff ended at 0x%lx\n", pos); -+ continue; -+ -+ case JFFS_DIRTY_BITMASK: -+ // printf("0x00 started at 0x%lx\n", pos); -+ for (; pos < end && wordbuf == JFFS_DIRTY_BITMASK; pos += 4) { -+ if (pread(fs, &wordbuf, 4, pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ } -+ if (pos < end) -+ pos -=4; -+ // printf("0x00 ended at 0x%lx\n", pos); -+ continue; -+ -+ default: -+ printf("Argh. Dirty memory at 0x%lx\n", pos); -+ // file_hexdump(fs, pos, 128); -+ for (pos += 4; pos < end; pos += 4) { -+ if (pread(fs, &wordbuf, 4, pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ if (wordbuf == JFFS_MAGIC_BITMASK) -+ break; -+ } -+ -+ case JFFS_MAGIC_BITMASK: -+ if (pread(fs, &ino, sizeof(ino), pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ if (myino == -1 || ino.ino == myino) { -+ printf("Magic found at 0x%lx\n", pos); -+ jffs_print_raw_inode(&ino); -+ } -+ pos += sizeof(ino); -+ -+ if (myino == -1 || ino.ino == myino) { -+ if (ino.nsize) { -+ if (pread(fs, namebuf, min(ino.nsize, 4095), pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ if (ino.nsize < 4095) -+ namebuf[ino.nsize] = 0; -+ else -+ namebuf[4095] = 0; -+ printf("Name: \"%s\"\n", namebuf); -+ } else { -+ printf("No Name\n"); -+ } -+ } -+ pos += (ino.nsize + 3) & ~3; -+ -+ pos += (ino.dsize + 3) & ~3; -+ } -+ -+ -+ -+ } -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/jffs2dump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/jffs2dump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,690 @@ -+/* -+ * dumpjffs2.c -+ * -+ * Copyright (C) 2003 Thomas Gleixner (tglx@linutronix.de) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Overview: -+ * This utility dumps the contents of a binary JFFS2 image -+ * -+ * -+ * Bug/ToDo: -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+#include "summary.h" -+ -+#define PROGRAM "jffs2dump" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+#define PAD(x) (((x)+3)&~3) -+ -+/* For outputting a byte-swapped version of the input image. */ -+#define cnv_e32(x) ((jint32_t){bswap_32(x.v32)}) -+#define cnv_e16(x) ((jint16_t){bswap_16(x.v16)}) -+ -+#define t32_backwards(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?bswap_32(__b):__b; }) -+#define cpu_to_e32(x) ((jint32_t){t32_backwards(x)}) -+ -+// Global variables -+long imglen; // length of image -+char *data; // image data -+ -+void display_help (void) -+{ -+ printf("Usage: dumpjffs2 [OPTION] INPUTFILE\n" -+ "Dumps the contents of a binary JFFS2 image.\n" -+ "\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n" -+ "-b --bigendian image is big endian\n" -+ "-l --littleendian image is little endian\n" -+ "-c --content dump image contents\n" -+ "-e fname --endianconvert=fname convert image endianness, output to file fname\n" -+ "-r --recalccrc recalc name and data crc on endian conversion\n" -+ "-d len --datsize=len size of data chunks, when oob data in binary image (NAND only)\n" -+ "-o len --oobsize=len size of oob data chunk in binary image (NAND only)\n" -+ "-v --verbose verbose output\n"); -+ exit(0); -+} -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "Copyright (C) 2003 Thomas Gleixner \n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} -+ -+// Option variables -+ -+int verbose; // verbose output -+char *img; // filename of image -+int dumpcontent; // dump image content -+int target_endian = __BYTE_ORDER; // image endianess -+int convertendian; // convert endianness -+int recalccrc; // recalc name and data crc's on endian conversion -+char cnvfile[256]; // filename for conversion output -+int datsize; // Size of data chunks, when oob data is inside the binary image -+int oobsize; // Size of oob chunks, when oob data is inside the binary image -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "blce:rd:o:v"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"bigendian", no_argument, 0, 'b'}, -+ {"littleendian", no_argument, 0, 'l'}, -+ {"content", no_argument, 0, 'c'}, -+ {"endianconvert", required_argument, 0, 'e'}, -+ {"datsize", required_argument, 0, 'd'}, -+ {"oobsize", required_argument, 0, 'o'}, -+ {"recalccrc", required_argument, 0, 'r'}, -+ {"verbose", no_argument, 0, 'v'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'v': -+ verbose = 1; -+ break; -+ case 'b': -+ target_endian = __BIG_ENDIAN; -+ break; -+ case 'l': -+ target_endian = __LITTLE_ENDIAN; -+ break; -+ case 'c': -+ dumpcontent = 1; -+ break; -+ case 'd': -+ datsize = atoi(optarg); -+ break; -+ case 'o': -+ oobsize = atoi(optarg); -+ break; -+ case 'e': -+ convertendian = 1; -+ strcpy (cnvfile, optarg); -+ break; -+ case 'r': -+ recalccrc = 1; -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 1 || error) -+ display_help (); -+ -+ img = argv[optind]; -+} -+ -+ -+/* -+ * Dump image contents -+ */ -+void do_dumpcontent (void) -+{ -+ char *p = data, *p_free_begin; -+ union jffs2_node_union *node; -+ int empty = 0, dirty = 0; -+ char name[256]; -+ uint32_t crc; -+ uint16_t type; -+ int bitchbitmask = 0; -+ int obsolete; -+ -+ p_free_begin = NULL; -+ while ( p < (data + imglen)) { -+ node = (union jffs2_node_union*) p; -+ -+ /* Skip empty space */ -+ if (!p_free_begin) -+ p_free_begin = p; -+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) { -+ p += 4; -+ empty += 4; -+ continue; -+ } -+ -+ if (p != p_free_begin) -+ printf("Empty space found from 0x%08x to 0x%08x\n", p_free_begin-data, p-data); -+ p_free_begin = NULL; -+ -+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) { -+ if (!bitchbitmask++) -+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - data, je16_to_cpu (node->u.magic)); -+ p += 4; -+ dirty += 4; -+ continue; -+ } -+ bitchbitmask = 0; -+ -+ type = je16_to_cpu(node->u.nodetype); -+ if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) { -+ obsolete = 1; -+ type |= JFFS2_NODE_ACCURATE; -+ } else -+ obsolete = 0; -+ /* Set accurate for CRC check */ -+ node->u.nodetype = cpu_to_je16(type); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4); -+ if (crc != je32_to_cpu (node->u.hdr_crc)) { -+ printf ("Wrong hdr_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc); -+ p += 4; -+ dirty += 4; -+ continue; -+ } -+ -+ switch(je16_to_cpu(node->u.nodetype)) { -+ -+ case JFFS2_NODETYPE_INODE: -+ printf ("%8s Inode node at 0x%08x, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n", -+ obsolete ? "Obsolete" : "", -+ p - data, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino), -+ je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize), -+ je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset)); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8); -+ if (crc != je32_to_cpu (node->i.node_crc)) { -+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.node_crc), crc); -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ dirty += PAD(je32_to_cpu (node->i.totlen));; -+ continue; -+ } -+ -+ crc = crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize)); -+ if (crc != je32_to_cpu(node->i.data_crc)) { -+ printf ("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.data_crc), crc); -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ dirty += PAD(je32_to_cpu (node->i.totlen));; -+ continue; -+ } -+ -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ memcpy (name, node->d.name, node->d.nsize); -+ name [node->d.nsize] = 0x0; -+ printf ("%8s Dirent node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n", -+ obsolete ? "Obsolete" : "", -+ p - data, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino), -+ je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino), -+ node->d.nsize, name); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8); -+ if (crc != je32_to_cpu (node->d.node_crc)) { -+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.node_crc), crc); -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ dirty += PAD(je32_to_cpu (node->d.totlen));; -+ continue; -+ } -+ -+ crc = crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize); -+ if (crc != je32_to_cpu(node->d.name_crc)) { -+ printf ("Wrong name_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.name_crc), crc); -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ dirty += PAD(je32_to_cpu (node->d.totlen));; -+ continue; -+ } -+ -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_SUMMARY: { -+ -+ int i; -+ struct jffs2_sum_marker * sm; -+ -+ printf("%8s Inode Sum node at 0x%08x, totlen 0x%08x, sum_num %5d, cleanmarker size %5d\n", -+ obsolete ? "Obsolete" : "", -+ p - data, -+ je32_to_cpu (node->s.totlen), -+ je32_to_cpu (node->s.sum_num), -+ je32_to_cpu (node->s.cln_mkr)); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_raw_summary) - 8); -+ if (crc != je32_to_cpu (node->s.node_crc)) { -+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.node_crc), crc); -+ p += PAD(je32_to_cpu (node->s.totlen)); -+ dirty += PAD(je32_to_cpu (node->s.totlen));; -+ continue; -+ } -+ -+ crc = crc32(0, p + sizeof (struct jffs2_raw_summary), je32_to_cpu (node->s.totlen) - sizeof(struct jffs2_raw_summary)); -+ if (crc != je32_to_cpu(node->s.sum_crc)) { -+ printf ("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.sum_crc), crc); -+ p += PAD(je32_to_cpu (node->s.totlen)); -+ dirty += PAD(je32_to_cpu (node->s.totlen));; -+ continue; -+ } -+ -+ if (verbose) { -+ void *sp; -+ sp = (p + sizeof(struct jffs2_raw_summary)); -+ -+ for(i=0; is.sum_num); i++) { -+ -+ switch(je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { -+ case JFFS2_NODETYPE_INODE : { -+ -+ struct jffs2_sum_inode_flash *spi; -+ spi = sp; -+ -+ printf ("%14s #ino %5d, version %5d, offset 0x%08x, totlen 0x%08x\n", -+ "", -+ je32_to_cpu (spi->inode), -+ je32_to_cpu (spi->version), -+ je32_to_cpu (spi->offset), -+ je32_to_cpu (spi->totlen)); -+ -+ sp += JFFS2_SUMMARY_INODE_SIZE; -+ break; -+ } -+ -+ case JFFS2_NODETYPE_DIRENT : { -+ -+ char name[255]; -+ struct jffs2_sum_dirent_flash *spd; -+ spd = sp; -+ -+ memcpy(name,spd->name,spd->nsize); -+ name [spd->nsize] = 0x0; -+ -+ printf ("%14s dirent offset 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s \n", -+ "", -+ je32_to_cpu (spd->offset), -+ je32_to_cpu (spd->totlen), -+ je32_to_cpu (spd->pino), -+ je32_to_cpu (spd->version), -+ je32_to_cpu (spd->ino), -+ spd->nsize, -+ name); -+ -+ sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); -+ break; -+ } -+ -+ default : -+ printf("Unknown summary node!\n"); -+ break; -+ } -+ } -+ -+ sm = (struct jffs2_sum_marker *) ((char *)p + je32_to_cpu(node->s.totlen) - sizeof(struct jffs2_sum_marker)); -+ -+ printf("%14s Sum Node Offset 0x%08x, Magic 0x%08x, Padded size 0x%08x\n", -+ "", -+ je32_to_cpu(sm->offset), -+ je32_to_cpu(sm->magic), -+ je32_to_cpu(node->s.padded)); -+ } -+ -+ p += PAD(je32_to_cpu (node->s.totlen)); -+ break; -+ } -+ -+ case JFFS2_NODETYPE_CLEANMARKER: -+ if (verbose) { -+ printf ("%8s Cleanmarker at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - data, je32_to_cpu (node->u.totlen)); -+ } -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_PADDING: -+ if (verbose) { -+ printf ("%8s Padding node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - data, je32_to_cpu (node->u.totlen)); -+ } -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case 0xffff: -+ p += 4; -+ empty += 4; -+ break; -+ -+ default: -+ if (verbose) { -+ printf ("%8s Unknown node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - data, je32_to_cpu (node->u.totlen)); -+ } -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ dirty += PAD(je32_to_cpu (node->u.totlen)); -+ -+ } -+ } -+ -+ if (verbose) -+ printf ("Empty space: %d, dirty space: %d\n", empty, dirty); -+} -+ -+/* -+ * Convert endianess -+ */ -+void do_endianconvert (void) -+{ -+ char *p = data; -+ union jffs2_node_union *node, newnode; -+ int fd, len; -+ jint32_t mode; -+ uint32_t crc; -+ -+ fd = open (cnvfile, O_WRONLY | O_CREAT, 0644); -+ if (fd < 0) { -+ fprintf (stderr, "Cannot open / create file: %s\n", cnvfile); -+ return; -+ } -+ -+ while ( p < (data + imglen)) { -+ node = (union jffs2_node_union*) p; -+ -+ /* Skip empty space */ -+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) { -+ write (fd, p, 4); -+ p += 4; -+ continue; -+ } -+ -+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) { -+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - data, je16_to_cpu (node->u.magic)); -+ newnode.u.magic = cnv_e16 (node->u.magic); -+ newnode.u.nodetype = cnv_e16 (node->u.nodetype); -+ write (fd, &newnode, 4); -+ p += 4; -+ continue; -+ } -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4); -+ if (crc != je32_to_cpu (node->u.hdr_crc)) { -+ printf ("Wrong hdr_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc); -+ } -+ -+ switch(je16_to_cpu(node->u.nodetype)) { -+ -+ case JFFS2_NODETYPE_INODE: -+ -+ newnode.i.magic = cnv_e16 (node->i.magic); -+ newnode.i.nodetype = cnv_e16 (node->i.nodetype); -+ newnode.i.totlen = cnv_e32 (node->i.totlen); -+ newnode.i.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); -+ newnode.i.ino = cnv_e32 (node->i.ino); -+ newnode.i.version = cnv_e32 (node->i.version); -+ mode.v32 = node->i.mode.m; -+ mode = cnv_e32 (mode); -+ newnode.i.mode.m = mode.v32; -+ newnode.i.uid = cnv_e16 (node->i.uid); -+ newnode.i.gid = cnv_e16 (node->i.gid); -+ newnode.i.isize = cnv_e32 (node->i.isize); -+ newnode.i.atime = cnv_e32 (node->i.atime); -+ newnode.i.mtime = cnv_e32 (node->i.mtime); -+ newnode.i.ctime = cnv_e32 (node->i.ctime); -+ newnode.i.offset = cnv_e32 (node->i.offset); -+ newnode.i.csize = cnv_e32 (node->i.csize); -+ newnode.i.dsize = cnv_e32 (node->i.dsize); -+ newnode.i.compr = node->i.compr; -+ newnode.i.usercompr = node->i.usercompr; -+ newnode.i.flags = cnv_e16 (node->i.flags); -+ if (recalccrc) { -+ len = je32_to_cpu(node->i.csize); -+ newnode.i.data_crc = cpu_to_e32 ( crc32(0, p + sizeof (struct jffs2_raw_inode), len)); -+ } else -+ newnode.i.data_crc = cnv_e32 (node->i.data_crc); -+ -+ newnode.i.node_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_raw_inode) - 8)); -+ -+ write (fd, &newnode, sizeof (struct jffs2_raw_inode)); -+ write (fd, p + sizeof (struct jffs2_raw_inode), PAD (je32_to_cpu (node->i.totlen) - sizeof (struct jffs2_raw_inode))); -+ -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ newnode.d.magic = cnv_e16 (node->d.magic); -+ newnode.d.nodetype = cnv_e16 (node->d.nodetype); -+ newnode.d.totlen = cnv_e32 (node->d.totlen); -+ newnode.d.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); -+ newnode.d.pino = cnv_e32 (node->d.pino); -+ newnode.d.version = cnv_e32 (node->d.version); -+ newnode.d.ino = cnv_e32 (node->d.ino); -+ newnode.d.mctime = cnv_e32 (node->d.mctime); -+ newnode.d.nsize = node->d.nsize; -+ newnode.d.type = node->d.type; -+ newnode.d.unused[0] = node->d.unused[0]; -+ newnode.d.unused[1] = node->d.unused[1]; -+ newnode.d.node_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_raw_dirent) - 8)); -+ if (recalccrc) -+ newnode.d.name_crc = cpu_to_e32 ( crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize)); -+ else -+ newnode.d.name_crc = cnv_e32 (node->d.name_crc); -+ -+ write (fd, &newnode, sizeof (struct jffs2_raw_dirent)); -+ write (fd, p + sizeof (struct jffs2_raw_dirent), PAD (je32_to_cpu (node->d.totlen) - sizeof (struct jffs2_raw_dirent))); -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_CLEANMARKER: -+ case JFFS2_NODETYPE_PADDING: -+ newnode.u.magic = cnv_e16 (node->u.magic); -+ newnode.u.nodetype = cnv_e16 (node->u.nodetype); -+ newnode.u.totlen = cnv_e32 (node->u.totlen); -+ newnode.u.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); -+ -+ write (fd, &newnode, sizeof (struct jffs2_unknown_node)); -+ len = PAD(je32_to_cpu (node->u.totlen) - sizeof (struct jffs2_unknown_node)); -+ if (len > 0) -+ write (fd, p + sizeof (struct jffs2_unknown_node), len); -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_SUMMARY : { -+ struct jffs2_sum_marker *sm_ptr; -+ int i,sum_len; -+ int counter = 0; -+ -+ newnode.s.magic = cnv_e16 (node->s.magic); -+ newnode.s.nodetype = cnv_e16 (node->s.nodetype); -+ newnode.s.totlen = cnv_e32 (node->s.totlen); -+ newnode.s.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); -+ newnode.s.sum_num = cnv_e32 (node->s.sum_num); -+ newnode.s.cln_mkr = cnv_e32 (node->s.cln_mkr); -+ newnode.s.padded = cnv_e32 (node->s.padded); -+ -+ newnode.s.node_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_raw_summary) - 8)); -+ -+ // summary header -+ p += sizeof (struct jffs2_raw_summary); -+ -+ // summary data -+ sum_len = je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary) - sizeof (struct jffs2_sum_marker); -+ -+ for (i=0; is.sum_num); i++) { -+ union jffs2_sum_flash *fl_ptr; -+ -+ fl_ptr = (union jffs2_sum_flash *) p; -+ -+ switch (je16_to_cpu (fl_ptr->u.nodetype)) { -+ case JFFS2_NODETYPE_INODE: -+ -+ fl_ptr->i.nodetype = cnv_e16 (fl_ptr->i.nodetype); -+ fl_ptr->i.inode = cnv_e32 (fl_ptr->i.inode); -+ fl_ptr->i.version = cnv_e32 (fl_ptr->i.version); -+ fl_ptr->i.offset = cnv_e32 (fl_ptr->i.offset); -+ fl_ptr->i.totlen = cnv_e32 (fl_ptr->i.totlen); -+ p += sizeof (struct jffs2_sum_inode_flash); -+ counter += sizeof (struct jffs2_sum_inode_flash); -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ fl_ptr->d.nodetype = cnv_e16 (fl_ptr->d.nodetype); -+ fl_ptr->d.totlen = cnv_e32 (fl_ptr->d.totlen); -+ fl_ptr->d.offset = cnv_e32 (fl_ptr->d.offset); -+ fl_ptr->d.pino = cnv_e32 (fl_ptr->d.pino); -+ fl_ptr->d.version = cnv_e32 (fl_ptr->d.version); -+ fl_ptr->d.ino = cnv_e32 (fl_ptr->d.ino); -+ p += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize; -+ counter += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize; -+ break; -+ -+ default : -+ printf("Unknown node in summary information!!! nodetype(%x)\n", je16_to_cpu (fl_ptr->u.nodetype)); -+ exit(EXIT_FAILURE); -+ break; -+ } -+ -+ } -+ -+ //pad -+ p += sum_len - counter; -+ -+ // summary marker -+ sm_ptr = (struct jffs2_sum_marker *) p; -+ sm_ptr->offset = cnv_e32 (sm_ptr->offset); -+ sm_ptr->magic = cnv_e32 (sm_ptr->magic); -+ p += sizeof (struct jffs2_sum_marker); -+ -+ // generate new crc on sum data -+ newnode.s.sum_crc = cpu_to_e32 ( crc32(0, ((char *) node) + sizeof (struct jffs2_raw_summary), -+ je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary))); -+ -+ // write out new node header -+ write(fd, &newnode, sizeof (struct jffs2_raw_summary)); -+ // write out new summary data -+ write(fd, &node->s.sum, sum_len + sizeof (struct jffs2_sum_marker)); -+ -+ break; -+ } -+ -+ case 0xffff: -+ write (fd, p, 4); -+ p += 4; -+ break; -+ -+ default: -+ printf ("Unknown node type: 0x%04x at 0x%08x, totlen 0x%08x\n", je16_to_cpu (node->u.nodetype), p - data, je32_to_cpu (node->u.totlen)); -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ -+ } -+ } -+ -+ close (fd); -+ -+} -+ -+/* -+ * Main program -+ */ -+int main(int argc, char **argv) -+{ -+ int fd; -+ -+ process_options(argc, argv); -+ -+ /* Open the input file */ -+ if ((fd = open(img, O_RDONLY)) == -1) { -+ perror("open input file"); -+ exit(1); -+ } -+ -+ // get image length -+ imglen = lseek(fd, 0, SEEK_END); -+ lseek (fd, 0, SEEK_SET); -+ -+ data = malloc (imglen); -+ if (!data) { -+ perror("out of memory"); -+ close (fd); -+ exit(1); -+ } -+ -+ if (datsize && oobsize) { -+ int idx = 0; -+ long len = imglen; -+ uint8_t oob[oobsize]; -+ printf ("Peeling data out of combined data/oob image\n"); -+ while (len) { -+ // read image data -+ read (fd, &data[idx], datsize); -+ read (fd, oob, oobsize); -+ idx += datsize; -+ imglen -= oobsize; -+ len -= datsize + oobsize; -+ } -+ -+ } else { -+ // read image data -+ read (fd, data, imglen); -+ } -+ // Close the input file -+ close(fd); -+ -+ if (dumpcontent) -+ do_dumpcontent (); -+ -+ if (convertendian) -+ do_endianconvert (); -+ -+ // free memory -+ free (data); -+ -+ // Return happy -+ exit (0); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/jffs2reader.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/jffs2reader.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,939 @@ -+/* vi: set sw=4 ts=4: */ -+/* -+ * jffs2reader v0.0.18 A jffs2 image reader -+ * -+ * Copyright (c) 2001 Jari Kirma -+ * -+ * This software is provided 'as-is', without any express or implied -+ * warranty. In no event will the author be held liable for any damages -+ * arising from the use of this software. -+ * -+ * Permission is granted to anyone to use this software for any -+ * purpose, including commercial applications, and to alter it and -+ * redistribute it freely, subject to the following restrictions: -+ * -+ * 1. The origin of this software must not be misrepresented; you must -+ * not claim that you wrote the original software. If you use this -+ * software in a product, an acknowledgment in the product -+ * documentation would be appreciated but is not required. -+ * -+ * 2. Altered source versions must be plainly marked as such, and must -+ * not be misrepresented as being the original software. -+ * -+ * 3. This notice may not be removed or altered from any source -+ * distribution. -+ * -+ * -+ ********* -+ * This code was altered September 2001 -+ * Changes are Copyright (c) Erik Andersen -+ * -+ * In compliance with (2) above, this is hereby marked as an altered -+ * version of this software. It has been altered as follows: -+ * *) Listing a directory now mimics the behavior of 'ls -l' -+ * *) Support for recursive listing has been added -+ * *) Without options, does a recursive 'ls' on the whole filesystem -+ * *) option parsing now uses getopt() -+ * *) Now uses printf, and error messages go to stderr. -+ * *) The copyright notice has been cleaned up and reformatted -+ * *) The code has been reformatted -+ * *) Several twisty code paths have been fixed so I can understand them. -+ * -Erik, 1 September 2001 -+ * -+ * *) Made it show major/minor numbers for device nodes -+ * *) Made it show symlink targets -+ * -Erik, 13 September 2001 -+ */ -+ -+ -+/* -+TODO: -+ -+- Add CRC checking code to places marked with XXX. -+- Add support for other node compression types. -+ -+- Test with real life images. -+- Maybe port into bootloader. -+ */ -+ -+/* -+BUGS: -+ -+- Doesn't check CRC checksums. -+ */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define SCRATCH_SIZE (5*1024*1024) -+ -+#ifndef MAJOR -+/* FIXME: I am using illicit insider knowledge of -+ * kernel major/minor representation... */ -+#define MAJOR(dev) (((dev)>>8)&0xff) -+#define MINOR(dev) ((dev)&0xff) -+#endif -+ -+ -+#define DIRENT_INO(dirent) ((dirent)!=NULL?(dirent)->ino:0) -+#define DIRENT_PINO(dirent) ((dirent)!=NULL?(dirent)->pino:0) -+ -+struct dir { -+ struct dir *next; -+ uint8_t type; -+ uint8_t nsize; -+ uint32_t ino; -+ char name[256]; -+}; -+ -+void putblock(char *, size_t, size_t *, struct jffs2_raw_inode *); -+struct dir *putdir(struct dir *, struct jffs2_raw_dirent *); -+void printdir(char *o, size_t size, struct dir *d, char *path, -+ int recurse); -+void freedir(struct dir *); -+ -+struct jffs2_raw_inode *find_raw_inode(char *o, size_t size, uint32_t ino); -+struct jffs2_raw_dirent *resolvedirent(char *, size_t, uint32_t, uint32_t, -+ char *, uint8_t); -+struct jffs2_raw_dirent *resolvename(char *, size_t, uint32_t, char *, uint8_t); -+struct jffs2_raw_dirent *resolveinode(char *, size_t, uint32_t); -+ -+struct jffs2_raw_dirent *resolvepath0(char *, size_t, uint32_t, char *, -+ uint32_t *, int); -+struct jffs2_raw_dirent *resolvepath(char *, size_t, uint32_t, char *, -+ uint32_t *); -+ -+void lsdir(char *, size_t, char *, int); -+void catfile(char *, size_t, char *, char *, size_t, size_t *); -+ -+int main(int, char **); -+ -+/* writes file node into buffer, to the proper position. */ -+/* reading all valid nodes in version order reconstructs the file. */ -+ -+/* -+ b - buffer -+ bsize - buffer size -+ rsize - result size -+ n - node -+ */ -+ -+void putblock(char *b, size_t bsize, size_t * rsize, -+ struct jffs2_raw_inode *n) -+{ -+ uLongf dlen = n->dsize; -+ -+ if (n->isize > bsize || (n->offset + dlen) > bsize) { -+ fprintf(stderr, "File does not fit into buffer!\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (*rsize < n->isize) -+ bzero(b + *rsize, n->isize - *rsize); -+ -+ switch (n->compr) { -+ case JFFS2_COMPR_ZLIB: -+ uncompress((Bytef *) b + n->offset, &dlen, -+ (Bytef *) ((char *) n) + sizeof(struct jffs2_raw_inode), -+ (uLongf) n->csize); -+ break; -+ -+ case JFFS2_COMPR_NONE: -+ memcpy(b + n->offset, -+ ((char *) n) + sizeof(struct jffs2_raw_inode), dlen); -+ break; -+ -+ case JFFS2_COMPR_ZERO: -+ bzero(b + n->offset, dlen); -+ break; -+ -+ /* [DYN]RUBIN support required! */ -+ -+ default: -+ fprintf(stderr, "Unsupported compression method!\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ *rsize = n->isize; -+} -+ -+/* adds/removes directory node into dir struct. */ -+/* reading all valid nodes in version order reconstructs the directory. */ -+ -+/* -+ dd - directory struct being processed -+ n - node -+ -+ return value: directory struct value replacing dd -+ */ -+ -+struct dir *putdir(struct dir *dd, struct jffs2_raw_dirent *n) -+{ -+ struct dir *o, *d, *p; -+ -+ o = dd; -+ -+ if (n->ino) { -+ if (dd == NULL) { -+ d = malloc(sizeof(struct dir)); -+ d->type = n->type; -+ memcpy(d->name, n->name, n->nsize); -+ d->nsize = n->nsize; -+ d->ino = n->ino; -+ d->next = NULL; -+ -+ return d; -+ } -+ -+ while (1) { -+ if (n->nsize == dd->nsize && -+ !memcmp(n->name, dd->name, n->nsize)) { -+ dd->type = n->type; -+ dd->ino = n->ino; -+ -+ return o; -+ } -+ -+ if (dd->next == NULL) { -+ dd->next = malloc(sizeof(struct dir)); -+ dd->next->type = n->type; -+ memcpy(dd->next->name, n->name, n->nsize); -+ dd->next->nsize = n->nsize; -+ dd->next->ino = n->ino; -+ dd->next->next = NULL; -+ -+ return o; -+ } -+ -+ dd = dd->next; -+ } -+ } else { -+ if (dd == NULL) -+ return NULL; -+ -+ if (n->nsize == dd->nsize && !memcmp(n->name, dd->name, n->nsize)) { -+ d = dd->next; -+ free(dd); -+ return d; -+ } -+ -+ while (1) { -+ p = dd; -+ dd = dd->next; -+ -+ if (dd == NULL) -+ return o; -+ -+ if (n->nsize == dd->nsize && -+ !memcmp(n->name, dd->name, n->nsize)) { -+ p->next = dd->next; -+ free(dd); -+ -+ return o; -+ } -+ } -+ } -+} -+ -+ -+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) -+#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) -+ -+/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */ -+static const mode_t SBIT[] = { -+ 0, 0, S_ISUID, -+ 0, 0, S_ISGID, -+ 0, 0, S_ISVTX -+}; -+ -+/* The 9 mode bits to test */ -+static const mode_t MBIT[] = { -+ S_IRUSR, S_IWUSR, S_IXUSR, -+ S_IRGRP, S_IWGRP, S_IXGRP, -+ S_IROTH, S_IWOTH, S_IXOTH -+}; -+ -+static const char MODE1[] = "rwxrwxrwx"; -+static const char MODE0[] = "---------"; -+static const char SMODE1[] = "..s..s..t"; -+static const char SMODE0[] = "..S..S..T"; -+ -+/* -+ * Return the standard ls-like mode string from a file mode. -+ * This is static and so is overwritten on each call. -+ */ -+const char *mode_string(int mode) -+{ -+ static char buf[12]; -+ -+ int i; -+ -+ buf[0] = TYPECHAR(mode); -+ for (i = 0; i < 9; i++) { -+ if (mode & SBIT[i]) -+ buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i]; -+ else -+ buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i]; -+ } -+ return buf; -+} -+ -+/* prints contents of directory structure */ -+ -+/* -+ d - dir struct -+ */ -+ -+void printdir(char *o, size_t size, struct dir *d, char *path, int recurse) -+{ -+ char m; -+ char *filetime; -+ time_t age; -+ struct jffs2_raw_inode *ri; -+ -+ if (!path) -+ return; -+ if (strlen(path) == 1 && *path == '/') -+ path++; -+ -+ while (d != NULL) { -+ switch (d->type) { -+ case DT_REG: -+ m = ' '; -+ break; -+ -+ case DT_FIFO: -+ m = '|'; -+ break; -+ -+ case DT_CHR: -+ m = ' '; -+ break; -+ -+ case DT_BLK: -+ m = ' '; -+ break; -+ -+ case DT_DIR: -+ m = '/'; -+ break; -+ -+ case DT_LNK: -+ m = ' '; -+ break; -+ -+ case DT_SOCK: -+ m = '='; -+ break; -+ -+ default: -+ m = '?'; -+ } -+ ri = find_raw_inode(o, size, d->ino); -+ if (!ri) { -+ fprintf(stderr, "bug: raw_inode missing!\n"); -+ d = d->next; -+ continue; -+ } -+ -+ filetime = ctime((const time_t *) &(ri->ctime)); -+ age = time(NULL) - ri->ctime; -+ printf("%s %-4d %-8d %-8d ", mode_string(ri->mode), -+ 1, ri->uid, ri->gid); -+ if ( d->type==DT_BLK || d->type==DT_CHR ) { -+ dev_t rdev; -+ size_t devsize; -+ putblock((char*)&rdev, sizeof(rdev), &devsize, ri); -+ printf("%4d, %3d ", (int)MAJOR(rdev), (int)MINOR(rdev)); -+ } else { -+ printf("%9ld ", (long)ri->dsize); -+ } -+ d->name[d->nsize]='\0'; -+ if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) { -+ /* hh:mm if less than 6 months old */ -+ printf("%6.6s %5.5s %s/%s%c", filetime + 4, filetime + 11, path, d->name, m); -+ } else { -+ printf("%6.6s %4.4s %s/%s%c", filetime + 4, filetime + 20, path, d->name, m); -+ } -+ if (d->type == DT_LNK) { -+ char symbuf[1024]; -+ size_t symsize; -+ putblock(symbuf, sizeof(symbuf), &symsize, ri); -+ symbuf[symsize] = 0; -+ printf(" -> %s", symbuf); -+ } -+ printf("\n"); -+ -+ if (d->type == DT_DIR && recurse) { -+ char *tmp; -+ tmp = malloc(BUFSIZ); -+ if (!tmp) { -+ fprintf(stderr, "memory exhausted\n"); -+ exit(EXIT_FAILURE); -+ } -+ sprintf(tmp, "%s/%s", path, d->name); -+ lsdir(o, size, tmp, recurse); /* Go recursive */ -+ free(tmp); -+ } -+ -+ d = d->next; -+ } -+} -+ -+/* frees memory used by directory structure */ -+ -+/* -+ d - dir struct -+ */ -+ -+void freedir(struct dir *d) -+{ -+ struct dir *t; -+ -+ while (d != NULL) { -+ t = d->next; -+ free(d); -+ d = t; -+ } -+} -+ -+/* collects directory/file nodes in version order. */ -+ -+/* -+ f - file flag. -+ if zero, collect file, compare ino to inode -+ otherwise, collect directory, compare ino to parent inode -+ o - filesystem image pointer -+ size - size of filesystem image -+ ino - inode to compare against. see f. -+ -+ return value: a jffs2_raw_inode that corresponds the the specified -+ inode, or NULL -+ */ -+ -+struct jffs2_raw_inode *find_raw_inode(char *o, size_t size, uint32_t ino) -+{ -+ /* aligned! */ -+ union jffs2_node_union *n; -+ union jffs2_node_union *e = (union jffs2_node_union *) (o + size); -+ union jffs2_node_union *lr; /* last block position */ -+ union jffs2_node_union *mp = NULL; /* minimum position */ -+ -+ uint32_t vmin, vmint, vmaxt, vmax, vcur, v; -+ -+ vmin = 0; /* next to read */ -+ vmax = ~((uint32_t) 0); /* last to read */ -+ vmint = ~((uint32_t) 0); -+ vmaxt = 0; /* found maximum */ -+ vcur = 0; /* XXX what is smallest version number used? */ -+ /* too low version number can easily result excess log rereading */ -+ -+ n = (union jffs2_node_union *) o; -+ lr = n; -+ -+ do { -+ while (n < e && n->u.magic != JFFS2_MAGIC_BITMASK) -+ ((char *) n) += 4; -+ -+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) { -+ if (n->u.nodetype == JFFS2_NODETYPE_INODE && -+ n->i.ino == ino && (v = n->i.version) > vcur) { -+ /* XXX crc check */ -+ -+ if (vmaxt < v) -+ vmaxt = v; -+ if (vmint > v) { -+ vmint = v; -+ mp = n; -+ } -+ -+ if (v == (vcur + 1)) -+ return (&(n->i)); -+ } -+ -+ ((char *) n) += ((n->u.totlen + 3) & ~3); -+ } else -+ n = (union jffs2_node_union *) o; /* we're at the end, rewind to the beginning */ -+ -+ if (lr == n) { /* whole loop since last read */ -+ vmax = vmaxt; -+ vmin = vmint; -+ vmint = ~((uint32_t) 0); -+ -+ if (vcur < vmax && vcur < vmin) -+ return (&(mp->i)); -+ } -+ } while (vcur < vmax); -+ -+ return NULL; -+} -+ -+/* collects dir struct for selected inode */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ pino - inode of the specified directory -+ d - input directory structure -+ -+ return value: result directory structure, replaces d. -+ */ -+ -+struct dir *collectdir(char *o, size_t size, uint32_t ino, struct dir *d) -+{ -+ /* aligned! */ -+ union jffs2_node_union *n; -+ union jffs2_node_union *e = (union jffs2_node_union *) (o + size); -+ union jffs2_node_union *lr; /* last block position */ -+ union jffs2_node_union *mp = NULL; /* minimum position */ -+ -+ uint32_t vmin, vmint, vmaxt, vmax, vcur, v; -+ -+ vmin = 0; /* next to read */ -+ vmax = ~((uint32_t) 0); /* last to read */ -+ vmint = ~((uint32_t) 0); -+ vmaxt = 0; /* found maximum */ -+ vcur = 0; /* XXX what is smallest version number used? */ -+ /* too low version number can easily result excess log rereading */ -+ -+ n = (union jffs2_node_union *) o; -+ lr = n; -+ -+ do { -+ while (n < e && n->u.magic != JFFS2_MAGIC_BITMASK) -+ ((char *) n) += 4; -+ -+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) { -+ if (n->u.nodetype == JFFS2_NODETYPE_DIRENT && -+ n->d.pino == ino && (v = n->d.version) > vcur) { -+ /* XXX crc check */ -+ -+ if (vmaxt < v) -+ vmaxt = v; -+ if (vmint > v) { -+ vmint = v; -+ mp = n; -+ } -+ -+ if (v == (vcur + 1)) { -+ d = putdir(d, &(n->d)); -+ -+ lr = n; -+ vcur++; -+ vmint = ~((uint32_t) 0); -+ } -+ } -+ -+ ((char *) n) += ((n->u.totlen + 3) & ~3); -+ } else -+ n = (union jffs2_node_union *) o; /* we're at the end, rewind to the beginning */ -+ -+ if (lr == n) { /* whole loop since last read */ -+ vmax = vmaxt; -+ vmin = vmint; -+ vmint = ~((uint32_t) 0); -+ -+ if (vcur < vmax && vcur < vmin) { -+ d = putdir(d, &(mp->d)); -+ -+ lr = n = -+ (union jffs2_node_union *) (((char *) mp) + -+ ((mp->u.totlen + 3) & ~3)); -+ -+ vcur = vmin; -+ } -+ } -+ } while (vcur < vmax); -+ -+ return d; -+} -+ -+ -+ -+/* resolve dirent based on criteria */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ ino - if zero, ignore, -+ otherwise compare against dirent inode -+ pino - if zero, ingore, -+ otherwise compare against parent inode -+ and use name and nsize as extra criteria -+ name - name of wanted dirent, used if pino!=0 -+ nsize - length of name of wanted dirent, used if pino!=0 -+ -+ return value: pointer to relevant dirent structure in -+ filesystem image or NULL -+ */ -+ -+struct jffs2_raw_dirent *resolvedirent(char *o, size_t size, -+ uint32_t ino, uint32_t pino, -+ char *name, uint8_t nsize) -+{ -+ /* aligned! */ -+ union jffs2_node_union *n; -+ union jffs2_node_union *e = (union jffs2_node_union *) (o + size); -+ -+ struct jffs2_raw_dirent *dd = NULL; -+ -+ uint32_t vmax, v; -+ -+ if (!pino && ino <= 1) -+ return dd; -+ -+ vmax = 0; -+ -+ n = (union jffs2_node_union *) o; -+ -+ do { -+ while (n < e && n->u.magic != JFFS2_MAGIC_BITMASK) -+ ((char *) n) += 4; -+ -+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) { -+ if (n->u.nodetype == JFFS2_NODETYPE_DIRENT && -+ (!ino || n->d.ino == ino) && -+ (v = n->d.version) > vmax && -+ (!pino || (n->d.pino == pino && -+ nsize == n->d.nsize && -+ !memcmp(name, n->d.name, nsize)))) { -+ /* XXX crc check */ -+ -+ if (vmax < v) { -+ vmax = v; -+ dd = &(n->d); -+ } -+ } -+ -+ ((char *) n) += ((n->u.totlen + 3) & ~3); -+ } else -+ return dd; -+ } while (1); -+} -+ -+/* resolve name under certain parent inode to dirent */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ pino - requested parent inode -+ name - name of wanted dirent -+ nsize - length of name of wanted dirent -+ -+ return value: pointer to relevant dirent structure in -+ filesystem image or NULL -+ */ -+ -+struct jffs2_raw_dirent *resolvename(char *o, size_t size, uint32_t pino, -+ char *name, uint8_t nsize) -+{ -+ return resolvedirent(o, size, 0, pino, name, nsize); -+} -+ -+/* resolve inode to dirent */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ ino - compare against dirent inode -+ -+ return value: pointer to relevant dirent structure in -+ filesystem image or NULL -+ */ -+ -+struct jffs2_raw_dirent *resolveinode(char *o, size_t size, uint32_t ino) -+{ -+ return resolvedirent(o, size, ino, 0, NULL, 0); -+} -+ -+/* resolve slash-style path into dirent and inode. -+ slash as first byte marks absolute path (root=inode 1). -+ . and .. are resolved properly, and symlinks are followed. -+ */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ ino - root inode, used if path is relative -+ p - path to be resolved -+ inos - result inode, zero if failure -+ recc - recursion count, to detect symlink loops -+ -+ return value: pointer to dirent struct in file system image. -+ note that root directory doesn't have dirent struct -+ (return value is NULL), but it has inode (*inos=1) -+ */ -+ -+struct jffs2_raw_dirent *resolvepath0(char *o, size_t size, uint32_t ino, -+ char *p, uint32_t * inos, int recc) -+{ -+ struct jffs2_raw_dirent *dir = NULL; -+ -+ int d = 1; -+ uint32_t tino; -+ -+ char *next; -+ -+ char *path, *pp; -+ -+ char symbuf[1024]; -+ size_t symsize; -+ -+ if (recc > 16) { -+ /* probably symlink loop */ -+ *inos = 0; -+ return NULL; -+ } -+ -+ pp = path = strdup(p); -+ -+ if (*path == '/') { -+ path++; -+ ino = 1; -+ } -+ -+ if (ino > 1) { -+ dir = resolveinode(o, size, ino); -+ -+ ino = DIRENT_INO(dir); -+ } -+ -+ next = path - 1; -+ -+ while (ino && next != NULL && next[1] != 0 && d) { -+ path = next + 1; -+ next = strchr(path, '/'); -+ -+ if (next != NULL) -+ *next = 0; -+ -+ if (*path == '.' && path[1] == 0) -+ continue; -+ if (*path == '.' && path[1] == '.' && path[2] == 0) { -+ if (DIRENT_PINO(dir) == 1) { -+ ino = 1; -+ dir = NULL; -+ } else { -+ dir = resolveinode(o, size, DIRENT_PINO(dir)); -+ ino = DIRENT_INO(dir); -+ } -+ -+ continue; -+ } -+ -+ dir = resolvename(o, size, ino, path, (uint8_t) strlen(path)); -+ -+ if (DIRENT_INO(dir) == 0 || -+ (next != NULL && -+ !(dir->type == DT_DIR || dir->type == DT_LNK))) { -+ free(pp); -+ -+ *inos = 0; -+ -+ return NULL; -+ } -+ -+ if (dir->type == DT_LNK) { -+ struct jffs2_raw_inode *ri; -+ ri = find_raw_inode(o, size, DIRENT_INO(dir)); -+ putblock(symbuf, sizeof(symbuf), &symsize, ri); -+ symbuf[symsize] = 0; -+ -+ tino = ino; -+ ino = 0; -+ -+ dir = resolvepath0(o, size, tino, symbuf, &ino, ++recc); -+ -+ if (dir != NULL && next != NULL && -+ !(dir->type == DT_DIR || dir->type == DT_LNK)) { -+ free(pp); -+ -+ *inos = 0; -+ return NULL; -+ } -+ } -+ if (dir != NULL) -+ ino = DIRENT_INO(dir); -+ } -+ -+ free(pp); -+ -+ *inos = ino; -+ -+ return dir; -+} -+ -+/* resolve slash-style path into dirent and inode. -+ slash as first byte marks absolute path (root=inode 1). -+ . and .. are resolved properly, and symlinks are followed. -+ */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ ino - root inode, used if path is relative -+ p - path to be resolved -+ inos - result inode, zero if failure -+ -+ return value: pointer to dirent struct in file system image. -+ note that root directory doesn't have dirent struct -+ (return value is NULL), but it has inode (*inos=1) -+ */ -+ -+struct jffs2_raw_dirent *resolvepath(char *o, size_t size, uint32_t ino, -+ char *p, uint32_t * inos) -+{ -+ return resolvepath0(o, size, ino, p, inos, 0); -+} -+ -+/* lists files on directory specified by path */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ p - path to be resolved -+ */ -+ -+void lsdir(char *o, size_t size, char *path, int recurse) -+{ -+ struct jffs2_raw_dirent *dd; -+ struct dir *d = NULL; -+ -+ uint32_t ino; -+ -+ dd = resolvepath(o, size, 1, path, &ino); -+ -+ if (ino == 0 || -+ (dd == NULL && ino == 0) || (dd != NULL && dd->type != DT_DIR)) { -+ fprintf(stderr, "jffs2reader: %s: No such file or directory\n", -+ path); -+ exit(EXIT_FAILURE); -+ } -+ -+ d = collectdir(o, size, ino, d); -+ printdir(o, size, d, path, recurse); -+ freedir(d); -+} -+ -+/* writes file specified by path to the buffer */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ p - path to be resolved -+ b - file buffer -+ bsize - file buffer size -+ rsize - file result size -+ */ -+ -+void catfile(char *o, size_t size, char *path, char *b, size_t bsize, -+ size_t * rsize) -+{ -+ struct jffs2_raw_dirent *dd; -+ struct jffs2_raw_inode *ri; -+ uint32_t ino; -+ -+ dd = resolvepath(o, size, 1, path, &ino); -+ -+ if (ino == 0) { -+ fprintf(stderr, "%s: No such file or directory\n", path); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (dd == NULL || dd->type != DT_REG) { -+ fprintf(stderr, "%s: Not a regular file\n", path); -+ exit(EXIT_FAILURE); -+ } -+ -+ ri = find_raw_inode(o, size, ino); -+ putblock(b, bsize, rsize, ri); -+ -+ write(1, b, *rsize); -+} -+ -+/* usage example */ -+ -+int main(int argc, char **argv) -+{ -+ int fd, opt, recurse = 0; -+ struct stat st; -+ -+ char *scratch, *dir = NULL, *file = NULL; -+ size_t ssize = 0; -+ -+ char *buf; -+ -+ while ((opt = getopt(argc, argv, "rd:f:")) > 0) { -+ switch (opt) { -+ case 'd': -+ dir = optarg; -+ break; -+ case 'f': -+ file = optarg; -+ break; -+ case 'r': -+ recurse++; -+ break; -+ default: -+ fprintf(stderr, -+ "Usage: jffs2reader [-d|-f] < path > \n"); -+ exit(EXIT_FAILURE); -+ } -+ } -+ -+ fd = open(argv[optind], O_RDONLY); -+ if (fd == -1) { -+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno)); -+ exit(2); -+ } -+ -+ if (fstat(fd, &st)) { -+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno)); -+ exit(3); -+ } -+ -+ buf = malloc((size_t) st.st_size); -+ if (buf == NULL) { -+ fprintf(stderr, "%s: memory exhausted\n", argv[optind]); -+ exit(4); -+ } -+ -+ if (read(fd, buf, st.st_size) != (ssize_t) st.st_size) { -+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno)); -+ exit(5); -+ } -+ -+ if (dir) -+ lsdir(buf, st.st_size, dir, recurse); -+ -+ if (file) { -+ scratch = malloc(SCRATCH_SIZE); -+ if (scratch == NULL) { -+ fprintf(stderr, "%s: memory exhausted\n", argv[optind]); -+ exit(6); -+ } -+ -+ catfile(buf, st.st_size, file, scratch, SCRATCH_SIZE, &ssize); -+ free(scratch); -+ } -+ -+ if (!dir && !file) -+ lsdir(buf, st.st_size, "/", 1); -+ -+ -+ free(buf); -+ exit(EXIT_SUCCESS); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/load_nandsim.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/load_nandsim.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,123 @@ -+#!/bin/bash -+ -+# -+# This script inserts NAND simulator module to emulate NAND flash of specified -+# size. -+# -+# Author: Artem Bityutskiy -+# -+ -+# Check if nandsim module is loaded -+function nandsim_loaded() -+{ -+ local NANDSIM=`lsmod | grep nandsim` -+ if [ -n "$NANDSIM" ]; then -+ return 1 -+ fi -+ return 0 -+} -+ -+nandsim_loaded -+if (( $? != 0 )); then -+ echo "Error: nandsim is already loaded" -+ exit 1 -+fi -+ -+if (( $# < 1 )); then -+ echo "Load NAND simulator to simulate flash of a specified size." -+ echo "" -+ echo "Usage: ./load_nandsim.sh " -+ echo " " -+ echo "" -+ echo "Only the first parameter is mandatory. Default eraseblock size" -+ echo "is 16KiB, default NAND page size is 512 bytes." -+ echo "" -+ echo "Only the following combinations are supported:" -+ echo "--------------------------------------------------" -+ echo "| size (MiB) | EB size (KiB) | Page size (bytes) |" -+ echo "--------------------------------------------------" -+ echo "| 16 | 16 | 512 |" -+ echo "| 32 | 16 | 512 |" -+ echo "| 64 | 16 | 512 |" -+ echo "| 128 | 16 | 512 |" -+ echo "| 256 | 16 | 512 |" -+ echo "| 64 | 64 | 2048 |" -+ echo "| 64 | 128 | 2048 |" -+ echo "| 64 | 256 | 2048 |" -+ echo "| 64 | 512 | 2048 |" -+ echo "| 128 | 64 | 2048 |" -+ echo "| 128 | 128 | 2048 |" -+ echo "| 128 | 256 | 2048 |" -+ echo "| 128 | 512 | 2048 |" -+ echo "| 256 | 64 | 2048 |" -+ echo "| 256 | 128 | 2048 |" -+ echo "| 256 | 256 | 2048 |" -+ echo "| 256 | 512 | 2048 |" -+ echo "| 512 | 64 | 2048 |" -+ echo "| 512 | 128 | 2048 |" -+ echo "| 512 | 256 | 2048 |" -+ echo "| 512 | 512 | 2048 |" -+ echo "| 1024 | 64 | 2048 |" -+ echo "| 1024 | 128 | 2048 |" -+ echo "| 1024 | 256 | 2048 |" -+ echo "| 1024 | 512 | 2048 |" -+ echo "--------------------------------------------------" -+ exit 1 -+fi -+ -+SZ=$1 -+EBSZ=$2 -+PGSZ=$3 -+if [[ $# == '1' ]]; then -+ EBSZ=16 -+ PGSZ=512 -+elif [[ $# == '2' ]]; then -+ PGSZ=512 -+fi -+ -+if (( $PGSZ == 512 && $EBSZ != 16 )); then -+ echo "Error: only 16KiB eraseblocks are possible in case of 512 bytes page" -+ exit 1 -+fi -+ -+if (( $PGSZ == 512 )); then -+ case $SZ in -+ 16) modprobe nandsim first_id_byte=0x20 second_id_byte=0x33 ;; -+ 32) modprobe nandsim first_id_byte=0x20 second_id_byte=0x35 ;; -+ 64) modprobe nandsim first_id_byte=0x20 second_id_byte=0x36 ;; -+ 128) modprobe nandsim first_id_byte=0x20 second_id_byte=0x78 ;; -+ 256) modprobe nandsim first_id_byte=0x20 second_id_byte=0x71 ;; -+ *) echo "Flash size ${SZ}MiB is not supported, try 16, 32, 64 or 256" -+ exit 1 ;; -+ esac -+elif (( $PGSZ == 2048 )); then -+ case $EBSZ in -+ 64) FOURTH=0x05 ;; -+ 128) FOURTH=0x15 ;; -+ 256) FOURTH=0x25 ;; -+ 512) FOURTH=0x35 ;; -+ *) echo "Eraseblock ${EBSZ}KiB is not supported" -+ exit 1 -+ esac -+ -+ case $SZ in -+ 64) modprobe nandsim first_id_byte=0x20 second_id_byte=0xa2 third_id_byte=0x00 fourth_id_byte=$FOURTH ;; -+ 128) modprobe nandsim first_id_byte=0xec second_id_byte=0xa1 third_id_byte=0x00 fourth_id_byte=$FOURTH ;; -+ 256) modprobe nandsim first_id_byte=0x20 second_id_byte=0xaa third_id_byte=0x00 fourth_id_byte=$FOURTH ;; -+ 512) modprobe nandsim first_id_byte=0x20 second_id_byte=0xac third_id_byte=0x00 fourth_id_byte=$FOURTH ;; -+ 1024) modprobe nandsim first_id_byte=0xec second_id_byte=0xd3 third_id_byte=0x51 fourth_id_byte=$FOURTH ;; -+ *) echo "Unable to emulate ${SZ}MiB flash with ${EBSZ}KiB eraseblock" -+ exit 1 -+ esac -+else -+ echo "Error: bad NAND page size ${PGSZ}KiB, it has to be either 512 or 2048" -+ exit 1 -+fi -+ -+if (( $? != 0 )); then -+ echo "Error: cannot load nandsim" -+ exit 1 -+fi -+ -+echo "Loaded NAND simulator (${SZ}MiB, ${EBSZ}KiB eraseblock, $PGSZ bytes NAND page)" -+exit 0 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/mcast_image.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/mcast_image.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,54 @@ -+#include -+ -+#define PKT_SIZE 2820 -+ -+struct image_pkt_hdr { -+ uint32_t resend; -+ uint32_t totcrc; -+ uint32_t nr_blocks; -+ uint32_t blocksize; -+ uint32_t block_crc; -+ uint32_t block_nr; -+ uint32_t pkt_sequence; -+ uint16_t pkt_nr; -+ uint16_t nr_pkts; -+ uint32_t thislen; -+ uint32_t thiscrc; -+}; -+ -+struct image_pkt { -+ struct image_pkt_hdr hdr; -+ unsigned char data[PKT_SIZE]; -+}; -+ -+struct fec_parms; -+ -+/* k - number of actual data packets -+ * n - total number of packets including data and redundant packets -+ * (actual packet size isn't relevant here) */ -+struct fec_parms *fec_new(int k, int n); -+void fec_free(struct fec_parms *p); -+ -+/* src - array of (n) pointers to data packets -+ * fec - buffer for packet to be generated -+ * index - index of packet to be generated (0 <= index < n) -+ * sz - data packet size -+ * -+ * _linear version just takes a pointer to the raw data; no -+ * mucking about with packet pointers. -+ */ -+void fec_encode(struct fec_parms *code, unsigned char *src[], -+ unsigned char *fec, int index, int sz); -+void fec_encode_linear(struct fec_parms *code, unsigned char *src, -+ unsigned char *fec, int index, int sz); -+ -+/* data - array of (k) pointers to data packets, in arbitrary order (see i) -+ * i - indices of (data) packets -+ * sz - data packet size -+ * -+ * Will never fail as long as you give it (k) individual data packets. -+ * Will re-order the (data) pointers but not the indices -- data packets -+ * are ordered on return. -+ */ -+int fec_decode(struct fec_parms *code, unsigned char *data[], -+ int i[], int sz); ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/mkfs.jffs2.1 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/mkfs.jffs2.1 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,259 @@ -+.TH MKFS.JFFS2 1 -+.SH NAME -+mkfs.jffs2 \- Create a JFFS2 file system image from directory -+.SH SYNOPSIS -+.B mkfs.jffs2 -+[ -+.B -p,--pad[=SIZE] -+] -+[ -+.B -r,-d,--root -+.I directory -+] -+[ -+.B -s,--pagesize=SIZE -+] -+[ -+.B -e,--eraseblock=SIZE -+] -+[ -+.B -c,--cleanmarker=SIZE -+] -+[ -+.B -n,--no-cleanmarkers -+] -+[ -+.B -o,--output -+.I image.jffs2 -+] -+[ -+.B -l,--little-endian -+] -+[ -+.B -b,--big-endian -+] -+[ -+.B -D,--devtable=FILE -+] -+[ -+.B -f,--faketime -+] -+[ -+.B -q,--squash -+] -+[ -+.B -U,--squash-uids -+] -+[ -+.B -P,--squash-perms -+] -+[ -+.B --with-xattr -+] -+[ -+.B --with-selinux -+] -+[ -+.B --with-posix-acl -+] -+[ -+.B -m,--compression-mode=MODE -+] -+[ -+.B -x,--disable-compressor=NAME -+] -+[ -+.B -X,--enable-compressor=NAME -+] -+[ -+.B -y,--compressor-priority=PRIORITY:NAME -+] -+[ -+.B -L,--list-compressors -+] -+[ -+.B -t,--test-compression -+] -+[ -+.B -h,--help -+] -+[ -+.B -v,--verbose -+] -+[ -+.B -V,--version -+] -+[ -+.B -i,--incremental -+.I image.jffs2 -+] -+ -+.SH DESCRIPTION -+The program -+.B mkfs.jffs2 -+creates a JFFS2 (Second Journalling Flash File System) file system -+image and writes the resulting image to the file specified by the -+.B -o -+option or by default to the standard output, unless the standard -+output is a terminal device in which case mkfs.jffs2 will abort. -+ -+The file system image is created using the files and directories -+contained in the directory specified by the option -+.B -r -+or the present directory, if the -+.B -r -+option is not specified. -+ -+Each block of the files to be placed into the file system image -+are compressed using one of the avaiable compressors depending -+on the selected compression mode. -+ -+File systems are created with the same endianness as the host, -+unless the -+.B -b -+or -+.B -l -+options are specified. JFFS2 driver in the 2.4 Linux kernel only -+supported images having the same endianness as the CPU. As of 2.5.48, -+the kernel can be changed with a #define to accept images of the -+non-native endianness. Full bi-endian support in the kernel is not -+planned. -+ -+It is unlikely that JFFS2 images are useful except in conjuction -+with the MTD (Memory Technology Device) drivers in the Linux -+kernel, since the JFFS2 file system driver in the kernel requires -+MTD devices. -+.SH OPTIONS -+Options that take SIZE arguments can be specified as either -+decimal (e.g., 65536), octal (0200000), or hexidecimal (0x1000). -+.TP -+.B -p, --pad[=SIZE] -+Pad output to SIZE bytes with 0xFF. If SIZE is not specified, -+the output is padded to the end of the final erase block. -+.TP -+.B -r, -d, --root=DIR -+Build file system from directory DIR. The default is the current -+directory. -+.TP -+.B -s, --pagesize=SIZE -+Use page size SIZE. The default is 4 KiB. This size is the -+maximum size of a data node. -+.TP -+.B -e, --eraseblock=SIZE -+Use erase block size SIZE. The default is 64 KiB. If you use a erase -+block size different than the erase block size of the target MTD -+device, JFFS2 may not perform optimally. If the SIZE specified is -+below 4096, the units are assumed to be KiB. -+.TP -+.B -c, --cleanmarker=SIZE -+Write \'CLEANMARKER\' nodes with the size specified. It is not -+normally appropriate to specify a size other than the default 12 -+bytes. -+.TP -+.B -n, --no-cleanmarkers -+Do not write \'CLEANMARKER\' nodes to the beginning of each erase -+block. This option can be useful for creating JFFS2 images for -+use on NAND flash, and for creating images which are to be used -+on a variety of hardware with differing eraseblock sizes. -+.TP -+.B -o, --output=FILE -+Write JFFS2 image to file FILE. Default is the standard output. -+.TP -+.B -l, --little-endian -+Create a little-endian JFFS2 image. Default is to make an image -+with the same endianness as the host. -+.TP -+.B -b, --big-endian -+Create a big-endian JFFS2 image. Default is to make an image -+with the same endianness as the host. -+.TP -+.B -D, --devtable=FILE -+Use the named FILE as a device table file, for including devices and -+changing permissions in the created image when the user does not have -+appropriate permissions to create them on the file system used as -+source. -+.TP -+.B -f, --faketime -+Change all file timestamps to \'0\' for regression testing. -+.TP -+.B -q, --squash -+Squash permissions and owners, making all files be owned by root and -+removing write permission for \'group\' and \'other\'. -+.TP -+.B -U, --squash-uids -+Squash owners making all files be owned by root. -+.TP -+.B -P, --squash-perms -+Squash permissions, removing write permission for \'group\' and \'other\'. -+.TP -+.B --with-xattr -+Enables xattr, stuff all xattr entries into jffs2 image file. -+.TP -+.B --with-selinux -+Enables xattr, stuff only SELinux Labels into jffs2 image file. -+.TP -+.B --with-posix-acl -+Enable xattr, stuff only POSIX ACL entries into jffs2 image file. -+.TP -+.B -m, --compression-mode=MODE -+Set the default compression mode. The default mode is -+.B priority -+which tries the compressors in a predefinied order and chooses the first -+successful one. The alternatives are: -+.B none -+(mkfs will not compress) and -+.B size -+(mkfs will try all compressor and chooses the one which have the smallest result). -+.TP -+.B -x, --disable-compressor=NAME -+Disable a compressor. Use -+.B -L -+to see the list of the avaiable compressors and their default states. -+.TP -+.B -X, --enable-compressor=NAME -+Enable a compressor. Use -+.B -L -+to see the list of the avaiable compressors and their default states. -+.TP -+.B -y, --compressor-priority=PRIORITY:NAME -+Set the priority of a compressor. Use -+.B -L -+to see the list of the avaiable compressors and their default priority. -+Priorities are used by priority compression mode. -+.TP -+.B -L, --list-compressors -+Show the list of the avaiable compressors and their states. -+.TP -+.B -t, --test-compression -+Call decompress after every compress - and compare the result with the original data -, and -+some other check. -+.TP -+.B -h, --help -+Display help text. -+.TP -+.B -v, --verbose -+Verbose operation. -+.TP -+.B -V, --version -+Display version information. -+.TP -+.B -i, --incremental=FILE -+Generate an appendage image for FILE. If FILE is written to flash and flash -+is appended with the output, then it seems as if it was one thing. -+ -+.SH BUGS -+JFFS2 limits device major and minor numbers to 8 bits each. Some -+consider this a bug. -+ -+.B mkfs.jffs2 -+does not properly handle hard links in the input directory structure. -+Currently, hard linked files will be expanded to multiple identical -+files in the output image. -+.SH AUTHORS -+David Woodhouse -+.br -+Manual page written by David Schleef -+.SH SEE ALSO -+.BR mkfs (8), -+.BR mkfs.jffs (1), -+.BR fakeroot (1) ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/mkfs.jffs2.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/mkfs.jffs2.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1902 @@ -+/* vi: set sw=4 ts=4: */ -+/* -+ * Build a JFFS2 image in a file, from a given directory tree. -+ * -+ * Copyright 2001, 2002 Red Hat, Inc. -+ * 2001 David A. Schleef -+ * 2002 Axis Communications AB -+ * 2001, 2002 Erik Andersen -+ * 2004 University of Szeged, Hungary -+ * 2006 KaiGai Kohei -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Cross-endian support added by David Schleef . -+ * -+ * Major architectural rewrite by Erik Andersen -+ * to allow support for making hard links (though hard links support is -+ * not yet implemented), and for munging file permissions and ownership -+ * on the fly using --faketime, --squash, --devtable. And I plugged a -+ * few memory leaks, adjusted the error handling and fixed some little -+ * nits here and there. -+ * -+ * I also added a sample device table file. See device_table.txt -+ * -Erik, September 2001 -+ * -+ * Cleanmarkers support added by Axis Communications AB -+ * -+ * Rewritten again. Cleanly separated host and target filsystem -+ * activities (mainly so I can reuse all the host handling stuff as I -+ * rewrite other mkfs utils). Added a verbose option to list types -+ * and attributes as files are added to the file system. Major cleanup -+ * and scrubbing of the code so it can be read, understood, and -+ * modified by mere mortals. -+ * -+ * -Erik, November 2002 -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifndef WITHOUT_XATTR -+#include -+#include -+#endif -+#include -+#define crc32 __complete_crap -+#include -+#undef crc32 -+#include "crc32.h" -+#include "rbtree.h" -+ -+/* Do not use the weird XPG version of basename */ -+#undef basename -+ -+//#define DMALLOC -+//#define mkfs_debug_msg error_msg -+#define mkfs_debug_msg(a...) { } -+#define min(x,y) ({ typeof((x)) _x = (x); typeof((y)) _y = (y); (_x>_y)?_y:_x; }) -+ -+#define PAD(x) (((x)+3)&~3) -+ -+struct filesystem_entry { -+ char *name; /* Name of this directory (think basename) */ -+ char *path; /* Path of this directory (think dirname) */ -+ char *fullname; /* Full name of this directory (i.e. path+name) */ -+ char *hostname; /* Full path to this file on the host filesystem */ -+ uint32_t ino; /* Inode number of this file in JFFS2 */ -+ struct stat sb; /* Stores directory permissions and whatnot */ -+ char *link; /* Target a symlink points to. */ -+ struct filesystem_entry *parent; /* Parent directory */ -+ struct filesystem_entry *prev; /* Only relevant to non-directories */ -+ struct filesystem_entry *next; /* Only relevant to non-directories */ -+ struct filesystem_entry *files; /* Only relevant to directories */ -+ struct rb_node hardlink_rb; -+}; -+ -+struct rb_root hardlinks; -+static int out_fd = -1; -+static int in_fd = -1; -+static char default_rootdir[] = "."; -+static char *rootdir = default_rootdir; -+static int verbose = 0; -+static int squash_uids = 0; -+static int squash_perms = 0; -+static int fake_times = 0; -+int target_endian = __BYTE_ORDER; -+static const char *const app_name = "mkfs.jffs2"; -+static const char *const memory_exhausted = "memory exhausted"; -+ -+uint32_t find_hardlink(struct filesystem_entry *e) -+{ -+ struct filesystem_entry *f; -+ struct rb_node **n = &hardlinks.rb_node; -+ struct rb_node *parent = NULL; -+ -+ while (*n) { -+ parent = *n; -+ f = rb_entry(parent, struct filesystem_entry, hardlink_rb); -+ -+ if ((f->sb.st_dev < e->sb.st_dev) || -+ (f->sb.st_dev == e->sb.st_dev && -+ f->sb.st_ino < e->sb.st_ino)) -+ n = &parent->rb_left; -+ else if ((f->sb.st_dev > e->sb.st_dev) || -+ (f->sb.st_dev == e->sb.st_dev && -+ f->sb.st_ino > e->sb.st_ino)) { -+ n = &parent->rb_right; -+ } else -+ return f->ino; -+ } -+ -+ rb_link_node(&e->hardlink_rb, parent, n); -+ rb_insert_color(&e->hardlink_rb, &hardlinks); -+ return 0; -+} -+ -+static void verror_msg(const char *s, va_list p) -+{ -+ fflush(stdout); -+ fprintf(stderr, "%s: ", app_name); -+ vfprintf(stderr, s, p); -+} -+static void error_msg(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ verror_msg(s, p); -+ va_end(p); -+ putc('\n', stderr); -+} -+ -+static void error_msg_and_die(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ verror_msg(s, p); -+ va_end(p); -+ putc('\n', stderr); -+ exit(EXIT_FAILURE); -+} -+ -+static void vperror_msg(const char *s, va_list p) -+{ -+ int err = errno; -+ -+ if (s == 0) -+ s = ""; -+ verror_msg(s, p); -+ if (*s) -+ s = ": "; -+ fprintf(stderr, "%s%s\n", s, strerror(err)); -+} -+ -+static void perror_msg(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ vperror_msg(s, p); -+ va_end(p); -+} -+ -+static void perror_msg_and_die(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ vperror_msg(s, p); -+ va_end(p); -+ exit(EXIT_FAILURE); -+} -+ -+#ifndef DMALLOC -+extern void *xmalloc(size_t size) -+{ -+ void *ptr = malloc(size); -+ -+ if (ptr == NULL && size != 0) -+ error_msg_and_die(memory_exhausted); -+ return ptr; -+} -+ -+extern void *xcalloc(size_t nmemb, size_t size) -+{ -+ void *ptr = calloc(nmemb, size); -+ -+ if (ptr == NULL && nmemb != 0 && size != 0) -+ error_msg_and_die(memory_exhausted); -+ return ptr; -+} -+ -+extern void *xrealloc(void *ptr, size_t size) -+{ -+ ptr = realloc(ptr, size); -+ if (ptr == NULL && size != 0) -+ error_msg_and_die(memory_exhausted); -+ return ptr; -+} -+ -+extern char *xstrdup(const char *s) -+{ -+ char *t; -+ -+ if (s == NULL) -+ return NULL; -+ t = strdup(s); -+ if (t == NULL) -+ error_msg_and_die(memory_exhausted); -+ return t; -+} -+#endif -+ -+extern char *xreadlink(const char *path) -+{ -+ static const int GROWBY = 80; /* how large we will grow strings by */ -+ -+ char *buf = NULL; -+ int bufsize = 0, readsize = 0; -+ -+ do { -+ buf = xrealloc(buf, bufsize += GROWBY); -+ readsize = readlink(path, buf, bufsize); /* 1st try */ -+ if (readsize == -1) { -+ perror_msg("%s:%s", app_name, path); -+ return NULL; -+ } -+ } -+ while (bufsize < readsize + 1); -+ -+ buf[readsize] = '\0'; -+ -+ return buf; -+} -+static FILE *xfopen(const char *path, const char *mode) -+{ -+ FILE *fp; -+ if ((fp = fopen(path, mode)) == NULL) -+ perror_msg_and_die("%s", path); -+ return fp; -+} -+ -+static struct filesystem_entry *find_filesystem_entry( -+ struct filesystem_entry *dir, char *fullname, uint32_t type) -+{ -+ struct filesystem_entry *e = dir; -+ -+ if (S_ISDIR(dir->sb.st_mode)) { -+ e = dir->files; -+ } -+ while (e) { -+ /* Only bother to do the expensive strcmp on matching file types */ -+ if (type == (e->sb.st_mode & S_IFMT)) { -+ if (S_ISDIR(e->sb.st_mode)) { -+ int len = strlen(e->fullname); -+ -+ /* Check if we are a parent of the correct path */ -+ if (strncmp(e->fullname, fullname, len) == 0) { -+ /* Is this an _exact_ match? */ -+ if (strcmp(fullname, e->fullname) == 0) { -+ return (e); -+ } -+ /* Looks like we found a parent of the correct path */ -+ if (fullname[len] == '/') { -+ if (e->files) { -+ return (find_filesystem_entry (e, fullname, type)); -+ } else { -+ return NULL; -+ } -+ } -+ } -+ } else { -+ if (strcmp(fullname, e->fullname) == 0) { -+ return (e); -+ } -+ } -+ } -+ e = e->next; -+ } -+ return (NULL); -+} -+ -+static struct filesystem_entry *add_host_filesystem_entry( -+ char *name, char *path, unsigned long uid, unsigned long gid, -+ unsigned long mode, dev_t rdev, struct filesystem_entry *parent) -+{ -+ int status; -+ char *tmp; -+ struct stat sb; -+ time_t timestamp = time(NULL); -+ struct filesystem_entry *entry; -+ -+ memset(&sb, 0, sizeof(struct stat)); -+ status = lstat(path, &sb); -+ -+ if (status >= 0) { -+ /* It is ok for some types of files to not exit on disk (such as -+ * device nodes), but if they _do_ exist the specified mode had -+ * better match the actual file or strange things will happen.... */ -+ if ((mode & S_IFMT) != (sb.st_mode & S_IFMT)) { -+ error_msg_and_die ("%s: file type does not match specified type!", path); -+ } -+ timestamp = sb.st_mtime; -+ } else { -+ /* If this is a regular file, it _must_ exist on disk */ -+ if ((mode & S_IFMT) == S_IFREG) { -+ error_msg_and_die("%s: does not exist!", path); -+ } -+ } -+ -+ /* Squash all permissions so files are owned by root, all -+ * timestamps are _right now_, and file permissions -+ * have group and other write removed */ -+ if (squash_uids) { -+ uid = gid = 0; -+ } -+ if (squash_perms) { -+ if (!S_ISLNK(mode)) { -+ mode &= ~(S_IWGRP | S_IWOTH); -+ mode &= ~(S_ISUID | S_ISGID); -+ } -+ } -+ if (fake_times) { -+ timestamp = 0; -+ } -+ -+ entry = xcalloc(1, sizeof(struct filesystem_entry)); -+ -+ entry->hostname = xstrdup(path); -+ entry->fullname = xstrdup(name); -+ tmp = xstrdup(name); -+ entry->name = xstrdup(basename(tmp)); -+ free(tmp); -+ tmp = xstrdup(name); -+ entry->path = xstrdup(dirname(tmp)); -+ free(tmp); -+ -+ entry->sb.st_ino = sb.st_ino; -+ entry->sb.st_dev = sb.st_dev; -+ entry->sb.st_nlink = sb.st_nlink; -+ -+ entry->sb.st_uid = uid; -+ entry->sb.st_gid = gid; -+ entry->sb.st_mode = mode; -+ entry->sb.st_rdev = rdev; -+ entry->sb.st_atime = entry->sb.st_ctime = -+ entry->sb.st_mtime = timestamp; -+ if (S_ISREG(mode)) { -+ entry->sb.st_size = sb.st_size; -+ } -+ if (S_ISLNK(mode)) { -+ entry->link = xreadlink(path); -+ entry->sb.st_size = strlen(entry->link); -+ } -+ -+ /* This happens only for root */ -+ if (!parent) -+ return (entry); -+ -+ /* Hook the file into the parent directory */ -+ entry->parent = parent; -+ if (!parent->files) { -+ parent->files = entry; -+ } else { -+ struct filesystem_entry *prev; -+ for (prev = parent->files; prev->next; prev = prev->next); -+ prev->next = entry; -+ entry->prev = prev; -+ } -+ -+ return (entry); -+} -+ -+static struct filesystem_entry *recursive_add_host_directory( -+ struct filesystem_entry *parent, char *targetpath, char *hostpath) -+{ -+ int i, n; -+ struct stat sb; -+ char *hpath, *tpath; -+ struct dirent *dp, **namelist; -+ struct filesystem_entry *entry; -+ -+ -+ if (lstat(hostpath, &sb)) { -+ perror_msg_and_die("%s", hostpath); -+ } -+ -+ entry = add_host_filesystem_entry(targetpath, hostpath, -+ sb.st_uid, sb.st_gid, sb.st_mode, 0, parent); -+ -+ n = scandir(hostpath, &namelist, 0, alphasort); -+ if (n < 0) { -+ perror_msg_and_die("opening directory %s", hostpath); -+ } -+ -+ for (i=0; id_name[0] == '.' && (dp->d_name[1] == 0 || -+ (dp->d_name[1] == '.' && dp->d_name[2] == 0))) -+ { -+ free(dp); -+ continue; -+ } -+ -+ asprintf(&hpath, "%s/%s", hostpath, dp->d_name); -+ if (lstat(hpath, &sb)) { -+ perror_msg_and_die("%s", hpath); -+ } -+ if (strcmp(targetpath, "/") == 0) { -+ asprintf(&tpath, "%s%s", targetpath, dp->d_name); -+ } else { -+ asprintf(&tpath, "%s/%s", targetpath, dp->d_name); -+ } -+ -+ switch (sb.st_mode & S_IFMT) { -+ case S_IFDIR: -+ recursive_add_host_directory(entry, tpath, hpath); -+ break; -+ -+ case S_IFREG: -+ case S_IFSOCK: -+ case S_IFIFO: -+ case S_IFLNK: -+ case S_IFCHR: -+ case S_IFBLK: -+ add_host_filesystem_entry(tpath, hpath, sb.st_uid, -+ sb.st_gid, sb.st_mode, sb.st_rdev, entry); -+ break; -+ -+ default: -+ error_msg("Unknown file type %o for %s", sb.st_mode, hpath); -+ break; -+ } -+ free(dp); -+ free(hpath); -+ free(tpath); -+ } -+ free(namelist); -+ return (entry); -+} -+ -+/* the GNU C library has a wonderful scanf("%as", string) which will -+ allocate the string with the right size, good to avoid buffer overruns. -+ the following macros use it if available or use a hacky workaround... -+ */ -+ -+#ifdef __GNUC__ -+#define SCANF_PREFIX "a" -+#define SCANF_STRING(s) (&s) -+#define GETCWD_SIZE 0 -+#else -+#define SCANF_PREFIX "511" -+#define SCANF_STRING(s) (s = malloc(512)) -+#define GETCWD_SIZE -1 -+inline int snprintf(char *str, size_t n, const char *fmt, ...) -+{ -+ int ret; -+ va_list ap; -+ -+ va_start(ap, fmt); -+ ret = vsprintf(str, fmt, ap); -+ va_end(ap); -+ return ret; -+} -+#endif -+ -+/* device table entries take the form of: -+ -+ /dev/mem c 640 0 0 1 1 0 0 - -+ -+ type can be one of: -+ f A regular file -+ d Directory -+ c Character special device file -+ b Block special device file -+ p Fifo (named pipe) -+ -+ I don't bother with symlinks (permissions are irrelevant), hard -+ links (special cases of regular files), or sockets (why bother). -+ -+ Regular files must exist in the target root directory. If a char, -+ block, fifo, or directory does not exist, it will be created. -+ */ -+static int interpret_table_entry(struct filesystem_entry *root, char *line) -+{ -+ char *hostpath; -+ char type, *name = NULL, *tmp, *dir; -+ unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; -+ unsigned long start = 0, increment = 1, count = 0; -+ struct filesystem_entry *parent, *entry; -+ -+ if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu", -+ SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor, -+ &start, &increment, &count) < 0) -+ { -+ return 1; -+ } -+ -+ if (!strcmp(name, "/")) { -+ error_msg_and_die("Device table entries require absolute paths"); -+ } -+ -+ asprintf(&hostpath, "%s%s", rootdir, name); -+ -+ /* Check if this file already exists... */ -+ switch (type) { -+ case 'd': -+ mode |= S_IFDIR; -+ break; -+ case 'f': -+ mode |= S_IFREG; -+ break; -+ case 'p': -+ mode |= S_IFIFO; -+ break; -+ case 'c': -+ mode |= S_IFCHR; -+ break; -+ case 'b': -+ mode |= S_IFBLK; -+ break; -+ default: -+ error_msg_and_die("Unsupported file type"); -+ } -+ entry = find_filesystem_entry(root, name, mode); -+ if (entry) { -+ /* Ok, we just need to fixup the existing entry -+ * and we will be all done... */ -+ entry->sb.st_uid = uid; -+ entry->sb.st_gid = gid; -+ entry->sb.st_mode = mode; -+ if (major && minor) { -+ entry->sb.st_rdev = makedev(major, minor); -+ } -+ } else { -+ /* If parent is NULL (happens with device table entries), -+ * try and find our parent now) */ -+ tmp = strdup(name); -+ dir = dirname(tmp); -+ parent = find_filesystem_entry(root, dir, S_IFDIR); -+ free(tmp); -+ if (parent == NULL) { -+ error_msg ("skipping device_table entry '%s': no parent directory!", name); -+ free(name); -+ free(hostpath); -+ return 1; -+ } -+ -+ switch (type) { -+ case 'd': -+ add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); -+ break; -+ case 'f': -+ add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); -+ break; -+ case 'p': -+ add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); -+ break; -+ case 'c': -+ case 'b': -+ if (count > 0) { -+ dev_t rdev; -+ unsigned long i; -+ char *dname, *hpath; -+ -+ for (i = start; i < count; i++) { -+ asprintf(&dname, "%s%lu", name, i); -+ asprintf(&hpath, "%s/%s%lu", rootdir, name, i); -+ rdev = makedev(major, minor + (i * increment - start)); -+ add_host_filesystem_entry(dname, hpath, uid, gid, -+ mode, rdev, parent); -+ free(dname); -+ free(hpath); -+ } -+ } else { -+ dev_t rdev = makedev(major, minor); -+ add_host_filesystem_entry(name, hostpath, uid, gid, -+ mode, rdev, parent); -+ } -+ break; -+ default: -+ error_msg_and_die("Unsupported file type"); -+ } -+ } -+ free(name); -+ free(hostpath); -+ return 0; -+} -+ -+static int parse_device_table(struct filesystem_entry *root, FILE * file) -+{ -+ char *line; -+ int status = 0; -+ size_t length = 0; -+ -+ /* Turn off squash, since we must ensure that values -+ * entered via the device table are not squashed */ -+ squash_uids = 0; -+ squash_perms = 0; -+ -+ /* Looks ok so far. The general plan now is to read in one -+ * line at a time, check for leading comment delimiters ('#'), -+ * then try and parse the line as a device table. If we fail -+ * to parse things, try and help the poor fool to fix their -+ * device table with a useful error msg... */ -+ line = NULL; -+ while (getline(&line, &length, file) != -1) { -+ /* First trim off any whitespace */ -+ int len = strlen(line); -+ -+ /* trim trailing whitespace */ -+ while (len > 0 && isspace(line[len - 1])) -+ line[--len] = '\0'; -+ /* trim leading whitespace */ -+ memmove(line, &line[strspn(line, " \n\r\t\v")], len); -+ -+ /* How long are we after trimming? */ -+ len = strlen(line); -+ -+ /* If this is NOT a comment line, try to interpret it */ -+ if (len && *line != '#') { -+ if (interpret_table_entry(root, line)) -+ status = 1; -+ } -+ -+ free(line); -+ line = NULL; -+ } -+ fclose(file); -+ -+ return status; -+} -+ -+static void cleanup(struct filesystem_entry *dir) -+{ -+ struct filesystem_entry *e, *prev; -+ -+ e = dir->files; -+ while (e) { -+ if (e->name) -+ free(e->name); -+ if (e->path) -+ free(e->path); -+ if (e->fullname) -+ free(e->fullname); -+ e->next = NULL; -+ e->name = NULL; -+ e->path = NULL; -+ e->fullname = NULL; -+ e->prev = NULL; -+ prev = e; -+ if (S_ISDIR(e->sb.st_mode)) { -+ cleanup(e); -+ } -+ e = e->next; -+ free(prev); -+ } -+} -+ -+/* Here is where we do the actual creation of the file system */ -+#include "mtd/jffs2-user.h" -+ -+#define JFFS2_MAX_FILE_SIZE 0xFFFFFFFF -+#ifndef JFFS2_MAX_SYMLINK_LEN -+#define JFFS2_MAX_SYMLINK_LEN 254 -+#endif -+ -+static uint32_t ino = 0; -+static uint8_t *file_buffer = NULL; /* file buffer contains the actual erase block*/ -+static int out_ofs = 0; -+static int erase_block_size = 65536; -+static int pad_fs_size = 0; -+static int add_cleanmarkers = 1; -+static struct jffs2_unknown_node cleanmarker; -+static int cleanmarker_size = sizeof(cleanmarker); -+static unsigned char ffbuf[16] = -+{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -+ 0xff, 0xff, 0xff, 0xff, 0xff -+}; -+ -+/* We set this at start of main() using sysconf(), -1 means we don't know */ -+/* When building an fs for non-native systems, use --pagesize=SIZE option */ -+int page_size = -1; -+ -+#include "compr.h" -+ -+static void full_write(int fd, const void *buf, int len) -+{ -+ int ret; -+ -+ while (len > 0) { -+ ret = write(fd, buf, len); -+ -+ if (ret < 0) -+ perror_msg_and_die("write"); -+ -+ if (ret == 0) -+ perror_msg_and_die("write returned zero"); -+ -+ len -= ret; -+ buf += ret; -+ out_ofs += ret; -+ } -+} -+ -+static void padblock(void) -+{ -+ while (out_ofs % erase_block_size) { -+ full_write(out_fd, ffbuf, min(sizeof(ffbuf), -+ erase_block_size - (out_ofs % erase_block_size))); -+ } -+} -+ -+static void pad(int req) -+{ -+ while (req) { -+ if (req > sizeof(ffbuf)) { -+ full_write(out_fd, ffbuf, sizeof(ffbuf)); -+ req -= sizeof(ffbuf); -+ } else { -+ full_write(out_fd, ffbuf, req); -+ req = 0; -+ } -+ } -+} -+ -+static inline void padword(void) -+{ -+ if (out_ofs % 4) { -+ full_write(out_fd, ffbuf, 4 - (out_ofs % 4)); -+ } -+} -+ -+static inline void pad_block_if_less_than(int req) -+{ -+ if (add_cleanmarkers) { -+ if ((out_ofs % erase_block_size) == 0) { -+ full_write(out_fd, &cleanmarker, sizeof(cleanmarker)); -+ pad(cleanmarker_size - sizeof(cleanmarker)); -+ padword(); -+ } -+ } -+ if ((out_ofs % erase_block_size) + req > erase_block_size) { -+ padblock(); -+ } -+ if (add_cleanmarkers) { -+ if ((out_ofs % erase_block_size) == 0) { -+ full_write(out_fd, &cleanmarker, sizeof(cleanmarker)); -+ pad(cleanmarker_size - sizeof(cleanmarker)); -+ padword(); -+ } -+ } -+} -+ -+static void write_dirent(struct filesystem_entry *e) -+{ -+ char *name = e->name; -+ struct jffs2_raw_dirent rd; -+ struct stat *statbuf = &(e->sb); -+ static uint32_t version = 0; -+ -+ memset(&rd, 0, sizeof(rd)); -+ -+ rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); -+ rd.totlen = cpu_to_je32(sizeof(rd) + strlen(name)); -+ rd.hdr_crc = cpu_to_je32(crc32(0, &rd, -+ sizeof(struct jffs2_unknown_node) - 4)); -+ rd.pino = cpu_to_je32((e->parent) ? e->parent->ino : 1); -+ rd.version = cpu_to_je32(version++); -+ rd.ino = cpu_to_je32(e->ino); -+ rd.mctime = cpu_to_je32(statbuf->st_mtime); -+ rd.nsize = strlen(name); -+ rd.type = IFTODT(statbuf->st_mode); -+ //rd.unused[0] = 0; -+ //rd.unused[1] = 0; -+ rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd) - 8)); -+ rd.name_crc = cpu_to_je32(crc32(0, name, strlen(name))); -+ -+ pad_block_if_less_than(sizeof(rd) + rd.nsize); -+ full_write(out_fd, &rd, sizeof(rd)); -+ full_write(out_fd, name, rd.nsize); -+ padword(); -+} -+ -+static unsigned int write_regular_file(struct filesystem_entry *e) -+{ -+ int fd, len; -+ uint32_t ver; -+ unsigned int offset; -+ unsigned char *buf, *cbuf, *wbuf; -+ struct jffs2_raw_inode ri; -+ struct stat *statbuf; -+ unsigned int totcomp = 0; -+ -+ statbuf = &(e->sb); -+ if (statbuf->st_size >= JFFS2_MAX_FILE_SIZE) { -+ error_msg("Skipping file \"%s\" too large.", e->path); -+ return -1; -+ } -+ fd = open(e->hostname, O_RDONLY); -+ if (fd == -1) { -+ perror_msg_and_die("%s: open file", e->hostname); -+ } -+ -+ e->ino = ++ino; -+ mkfs_debug_msg("writing file '%s' ino=%lu parent_ino=%lu", -+ e->name, (unsigned long) e->ino, -+ (unsigned long) e->parent->ino); -+ write_dirent(e); -+ -+ buf = xmalloc(page_size); -+ cbuf = NULL; -+ -+ ver = 0; -+ offset = 0; -+ -+ memset(&ri, 0, sizeof(ri)); -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ -+ ri.ino = cpu_to_je32(e->ino); -+ ri.mode = cpu_to_jemode(statbuf->st_mode); -+ ri.uid = cpu_to_je16(statbuf->st_uid); -+ ri.gid = cpu_to_je16(statbuf->st_gid); -+ ri.atime = cpu_to_je32(statbuf->st_atime); -+ ri.ctime = cpu_to_je32(statbuf->st_ctime); -+ ri.mtime = cpu_to_je32(statbuf->st_mtime); -+ ri.isize = cpu_to_je32(statbuf->st_size); -+ -+ while ((len = read(fd, buf, page_size))) { -+ unsigned char *tbuf = buf; -+ -+ if (len < 0) { -+ perror_msg_and_die("read"); -+ } -+ -+ while (len) { -+ uint32_t dsize, space; -+ uint16_t compression; -+ -+ pad_block_if_less_than(sizeof(ri) + JFFS2_MIN_DATA_LEN); -+ -+ dsize = len; -+ space = -+ erase_block_size - (out_ofs % erase_block_size) - -+ sizeof(ri); -+ if (space > dsize) -+ space = dsize; -+ -+ compression = jffs2_compress(tbuf, &cbuf, &dsize, &space); -+ -+ ri.compr = compression & 0xff; -+ ri.usercompr = (compression >> 8) & 0xff; -+ -+ if (ri.compr) { -+ wbuf = cbuf; -+ } else { -+ wbuf = tbuf; -+ dsize = space; -+ } -+ -+ ri.totlen = cpu_to_je32(sizeof(ri) + space); -+ ri.hdr_crc = cpu_to_je32(crc32(0, -+ &ri, sizeof(struct jffs2_unknown_node) - 4)); -+ -+ ri.version = cpu_to_je32(++ver); -+ ri.offset = cpu_to_je32(offset); -+ ri.csize = cpu_to_je32(space); -+ ri.dsize = cpu_to_je32(dsize); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8)); -+ ri.data_crc = cpu_to_je32(crc32(0, wbuf, space)); -+ -+ full_write(out_fd, &ri, sizeof(ri)); -+ totcomp += sizeof(ri); -+ full_write(out_fd, wbuf, space); -+ totcomp += space; -+ padword(); -+ -+ if (tbuf != cbuf) { -+ free(cbuf); -+ cbuf = NULL; -+ } -+ -+ tbuf += dsize; -+ len -= dsize; -+ offset += dsize; -+ -+ } -+ } -+ if (!je32_to_cpu(ri.version)) { -+ /* Was empty file */ -+ pad_block_if_less_than(sizeof(ri)); -+ -+ ri.version = cpu_to_je32(++ver); -+ ri.totlen = cpu_to_je32(sizeof(ri)); -+ ri.hdr_crc = cpu_to_je32(crc32(0, -+ &ri, sizeof(struct jffs2_unknown_node) - 4)); -+ ri.csize = cpu_to_je32(0); -+ ri.dsize = cpu_to_je32(0); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8)); -+ -+ full_write(out_fd, &ri, sizeof(ri)); -+ padword(); -+ } -+ free(buf); -+ close(fd); -+ return totcomp; -+} -+ -+static void write_symlink(struct filesystem_entry *e) -+{ -+ int len; -+ struct stat *statbuf; -+ struct jffs2_raw_inode ri; -+ -+ statbuf = &(e->sb); -+ e->ino = ++ino; -+ mkfs_debug_msg("writing symlink '%s' ino=%lu parent_ino=%lu", -+ e->name, (unsigned long) e->ino, -+ (unsigned long) e->parent->ino); -+ write_dirent(e); -+ -+ len = strlen(e->link); -+ if (len > JFFS2_MAX_SYMLINK_LEN) { -+ error_msg("symlink too large. Truncated to %d chars.", -+ JFFS2_MAX_SYMLINK_LEN); -+ len = JFFS2_MAX_SYMLINK_LEN; -+ } -+ -+ memset(&ri, 0, sizeof(ri)); -+ -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri.totlen = cpu_to_je32(sizeof(ri) + len); -+ ri.hdr_crc = cpu_to_je32(crc32(0, -+ &ri, sizeof(struct jffs2_unknown_node) - 4)); -+ -+ ri.ino = cpu_to_je32(e->ino); -+ ri.mode = cpu_to_jemode(statbuf->st_mode); -+ ri.uid = cpu_to_je16(statbuf->st_uid); -+ ri.gid = cpu_to_je16(statbuf->st_gid); -+ ri.atime = cpu_to_je32(statbuf->st_atime); -+ ri.ctime = cpu_to_je32(statbuf->st_ctime); -+ ri.mtime = cpu_to_je32(statbuf->st_mtime); -+ ri.isize = cpu_to_je32(statbuf->st_size); -+ ri.version = cpu_to_je32(1); -+ ri.csize = cpu_to_je32(len); -+ ri.dsize = cpu_to_je32(len); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8)); -+ ri.data_crc = cpu_to_je32(crc32(0, e->link, len)); -+ -+ pad_block_if_less_than(sizeof(ri) + len); -+ full_write(out_fd, &ri, sizeof(ri)); -+ full_write(out_fd, e->link, len); -+ padword(); -+} -+ -+static void write_pipe(struct filesystem_entry *e) -+{ -+ struct stat *statbuf; -+ struct jffs2_raw_inode ri; -+ -+ statbuf = &(e->sb); -+ e->ino = ++ino; -+ if (S_ISDIR(statbuf->st_mode)) { -+ mkfs_debug_msg("writing dir '%s' ino=%lu parent_ino=%lu", -+ e->name, (unsigned long) e->ino, -+ (unsigned long) (e->parent) ? e->parent->ino : 1); -+ } -+ write_dirent(e); -+ -+ memset(&ri, 0, sizeof(ri)); -+ -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri.totlen = cpu_to_je32(sizeof(ri)); -+ ri.hdr_crc = cpu_to_je32(crc32(0, -+ &ri, sizeof(struct jffs2_unknown_node) - 4)); -+ -+ ri.ino = cpu_to_je32(e->ino); -+ ri.mode = cpu_to_jemode(statbuf->st_mode); -+ ri.uid = cpu_to_je16(statbuf->st_uid); -+ ri.gid = cpu_to_je16(statbuf->st_gid); -+ ri.atime = cpu_to_je32(statbuf->st_atime); -+ ri.ctime = cpu_to_je32(statbuf->st_ctime); -+ ri.mtime = cpu_to_je32(statbuf->st_mtime); -+ ri.isize = cpu_to_je32(0); -+ ri.version = cpu_to_je32(1); -+ ri.csize = cpu_to_je32(0); -+ ri.dsize = cpu_to_je32(0); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8)); -+ ri.data_crc = cpu_to_je32(0); -+ -+ pad_block_if_less_than(sizeof(ri)); -+ full_write(out_fd, &ri, sizeof(ri)); -+ padword(); -+} -+ -+static void write_special_file(struct filesystem_entry *e) -+{ -+ jint16_t kdev; -+ struct stat *statbuf; -+ struct jffs2_raw_inode ri; -+ -+ statbuf = &(e->sb); -+ e->ino = ++ino; -+ write_dirent(e); -+ -+ kdev = cpu_to_je16((major(statbuf->st_rdev) << 8) + -+ minor(statbuf->st_rdev)); -+ -+ memset(&ri, 0, sizeof(ri)); -+ -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri.totlen = cpu_to_je32(sizeof(ri) + sizeof(kdev)); -+ ri.hdr_crc = cpu_to_je32(crc32(0, -+ &ri, sizeof(struct jffs2_unknown_node) - 4)); -+ -+ ri.ino = cpu_to_je32(e->ino); -+ ri.mode = cpu_to_jemode(statbuf->st_mode); -+ ri.uid = cpu_to_je16(statbuf->st_uid); -+ ri.gid = cpu_to_je16(statbuf->st_gid); -+ ri.atime = cpu_to_je32(statbuf->st_atime); -+ ri.ctime = cpu_to_je32(statbuf->st_ctime); -+ ri.mtime = cpu_to_je32(statbuf->st_mtime); -+ ri.isize = cpu_to_je32(statbuf->st_size); -+ ri.version = cpu_to_je32(1); -+ ri.csize = cpu_to_je32(sizeof(kdev)); -+ ri.dsize = cpu_to_je32(sizeof(kdev)); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8)); -+ ri.data_crc = cpu_to_je32(crc32(0, &kdev, sizeof(kdev))); -+ -+ pad_block_if_less_than(sizeof(ri) + sizeof(kdev)); -+ full_write(out_fd, &ri, sizeof(ri)); -+ full_write(out_fd, &kdev, sizeof(kdev)); -+ padword(); -+} -+ -+#ifndef WITHOUT_XATTR -+typedef struct xattr_entry { -+ struct xattr_entry *next; -+ uint32_t xid; -+ int xprefix; -+ char *xname; -+ char *xvalue; -+ int name_len; -+ int value_len; -+} xattr_entry_t; -+ -+#define XATTR_BUFFER_SIZE (64 * 1024) /* 64KB */ -+static uint32_t enable_xattr = 0; -+static uint32_t highest_xid = 0; -+static uint32_t highest_xseqno = 0; -+ -+static struct { -+ int xprefix; -+ char *string; -+ int length; -+} xprefix_tbl[] = { -+ { JFFS2_XPREFIX_USER, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN }, -+ { JFFS2_XPREFIX_SECURITY, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN }, -+ { JFFS2_XPREFIX_ACL_ACCESS, POSIX_ACL_XATTR_ACCESS, POSIX_ACL_XATTR_ACCESS_LEN }, -+ { JFFS2_XPREFIX_ACL_DEFAULT, POSIX_ACL_XATTR_DEFAULT, POSIX_ACL_XATTR_DEFAULT_LEN }, -+ { JFFS2_XPREFIX_TRUSTED, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }, -+ { 0, NULL, 0 } -+}; -+ -+static void formalize_posix_acl(void *xvalue, int *value_len) -+{ -+ struct posix_acl_xattr_header *pacl_header; -+ struct posix_acl_xattr_entry *pent, *plim; -+ struct jffs2_acl_header *jacl_header; -+ struct jffs2_acl_entry *jent; -+ struct jffs2_acl_entry_short *jent_s; -+ char buffer[XATTR_BUFFER_SIZE]; -+ int offset = 0; -+ -+ pacl_header = xvalue;; -+ pent = pacl_header->a_entries; -+ plim = xvalue + *value_len; -+ -+ jacl_header = (struct jffs2_acl_header *)buffer; -+ offset += sizeof(struct jffs2_acl_header); -+ jacl_header->a_version = cpu_to_je32(JFFS2_ACL_VERSION); -+ -+ while (pent < plim) { -+ switch(le16_to_cpu(pent->e_tag)) { -+ case ACL_USER_OBJ: -+ case ACL_GROUP_OBJ: -+ case ACL_MASK: -+ case ACL_OTHER: -+ jent_s = (struct jffs2_acl_entry_short *)(buffer + offset); -+ offset += sizeof(struct jffs2_acl_entry_short); -+ jent_s->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag)); -+ jent_s->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm)); -+ break; -+ case ACL_USER: -+ case ACL_GROUP: -+ jent = (struct jffs2_acl_entry *)(buffer + offset); -+ offset += sizeof(struct jffs2_acl_entry); -+ jent->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag)); -+ jent->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm)); -+ jent->e_id = cpu_to_je32(le32_to_cpu(pent->e_id)); -+ break; -+ default: -+ printf("%04x : Unknown XATTR entry tag.\n", le16_to_cpu(pent->e_tag)); -+ exit(1); -+ } -+ pent++; -+ } -+ if (offset > *value_len) { -+ printf("Length of JFFS2 ACL expression(%u) is longer than general one(%u).\n", -+ offset, *value_len); -+ exit(1); -+ } -+ memcpy(xvalue, buffer, offset); -+ *value_len = offset; -+} -+ -+static xattr_entry_t *create_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len) -+{ -+ xattr_entry_t *xe; -+ struct jffs2_raw_xattr rx; -+ int name_len; -+ -+ /* create xattr entry */ -+ name_len = strlen(xname); -+ xe = xcalloc(1, sizeof(xattr_entry_t) + name_len + 1 + value_len); -+ xe->next = NULL; -+ xe->xid = ++highest_xid; -+ xe->xprefix = xprefix; -+ xe->xname = ((char *)xe) + sizeof(xattr_entry_t); -+ xe->xvalue = xe->xname + name_len + 1; -+ xe->name_len = name_len; -+ xe->value_len = value_len; -+ strcpy(xe->xname, xname); -+ memcpy(xe->xvalue, xvalue, value_len); -+ -+ /* write xattr node */ -+ memset(&rx, 0, sizeof(rx)); -+ rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR); -+ rx.totlen = cpu_to_je32(PAD(sizeof(rx) + xe->name_len + 1 + xe->value_len)); -+ rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4)); -+ -+ rx.xid = cpu_to_je32(xe->xid); -+ rx.version = cpu_to_je32(1); /* initial version */ -+ rx.xprefix = xprefix; -+ rx.name_len = xe->name_len; -+ rx.value_len = cpu_to_je16(xe->value_len); -+ rx.data_crc = cpu_to_je32(crc32(0, xe->xname, xe->name_len + 1 + xe->value_len)); -+ rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(rx) - 4)); -+ -+ pad_block_if_less_than(sizeof(rx) + xe->name_len + 1 + xe->value_len); -+ full_write(out_fd, &rx, sizeof(rx)); -+ full_write(out_fd, xe->xname, xe->name_len + 1 + xe->value_len); -+ padword(); -+ -+ return xe; -+} -+ -+#define XATTRENTRY_HASHSIZE 57 -+static xattr_entry_t *find_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len) -+{ -+ static xattr_entry_t **xentry_hash = NULL; -+ xattr_entry_t *xe; -+ int index, name_len; -+ -+ /* create hash table */ -+ if (!xentry_hash) -+ xentry_hash = xcalloc(1, sizeof(xe) * XATTRENTRY_HASHSIZE); -+ -+ if (xprefix == JFFS2_XPREFIX_ACL_ACCESS -+ || xprefix == JFFS2_XPREFIX_ACL_DEFAULT) -+ formalize_posix_acl(xvalue, &value_len); -+ -+ name_len = strlen(xname); -+ index = (crc32(0, xname, name_len) ^ crc32(0, xvalue, value_len)) % XATTRENTRY_HASHSIZE; -+ for (xe = xentry_hash[index]; xe; xe = xe->next) { -+ if (xe->xprefix == xprefix -+ && xe->value_len == value_len -+ && !strcmp(xe->xname, xname) -+ && !memcmp(xe->xvalue, xvalue, value_len)) -+ break; -+ } -+ if (!xe) { -+ xe = create_xattr_entry(xprefix, xname, xvalue, value_len); -+ xe->next = xentry_hash[index]; -+ xentry_hash[index] = xe; -+ } -+ return xe; -+} -+ -+static void write_xattr_entry(struct filesystem_entry *e) -+{ -+ struct jffs2_raw_xref ref; -+ struct xattr_entry *xe; -+ char xlist[XATTR_BUFFER_SIZE], xvalue[XATTR_BUFFER_SIZE]; -+ char *xname, *prefix_str; -+ int i, xprefix, prefix_len; -+ int list_sz, offset, name_len, value_len; -+ -+ if (!enable_xattr) -+ return; -+ -+ list_sz = llistxattr(e->hostname, xlist, XATTR_BUFFER_SIZE); -+ if (list_sz < 0) { -+ if (verbose) -+ printf("llistxattr('%s') = %d : %s\n", -+ e->hostname, errno, strerror(errno)); -+ return; -+ } -+ -+ for (offset = 0; offset < list_sz; offset += name_len) { -+ xname = xlist + offset; -+ name_len = strlen(xname) + 1; -+ -+ for (i = 0; (xprefix = xprefix_tbl[i].xprefix); i++) { -+ prefix_str = xprefix_tbl[i].string; -+ prefix_len = xprefix_tbl[i].length; -+ if (prefix_str[prefix_len - 1] == '.') { -+ if (!strncmp(xname, prefix_str, prefix_len - 1)) -+ break; -+ } else { -+ if (!strcmp(xname, prefix_str)) -+ break; -+ } -+ } -+ if (!xprefix) { -+ if (verbose) -+ printf("%s: xattr '%s' is not supported.\n", -+ e->hostname, xname); -+ continue; -+ } -+ if ((enable_xattr & (1 << xprefix)) == 0) -+ continue; -+ -+ value_len = lgetxattr(e->hostname, xname, xvalue, XATTR_BUFFER_SIZE); -+ if (value_len < 0) { -+ if (verbose) -+ printf("lgetxattr('%s', '%s') = %d : %s\n", -+ e->hostname, xname, errno, strerror(errno)); -+ continue; -+ } -+ xe = find_xattr_entry(xprefix, xname + prefix_len, xvalue, value_len); -+ if (!xe) { -+ if (verbose) -+ printf("%s : xattr '%s' was ignored.\n", -+ e->hostname, xname); -+ continue; -+ } -+ -+ memset(&ref, 0, sizeof(ref)); -+ ref.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ref.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF); -+ ref.totlen = cpu_to_je32(sizeof(ref)); -+ ref.hdr_crc = cpu_to_je32(crc32(0, &ref, sizeof(struct jffs2_unknown_node) - 4)); -+ ref.ino = cpu_to_je32(e->ino); -+ ref.xid = cpu_to_je32(xe->xid); -+ ref.xseqno = cpu_to_je32(highest_xseqno += 2); -+ ref.node_crc = cpu_to_je32(crc32(0, &ref, sizeof(ref) - 4)); -+ -+ pad_block_if_less_than(sizeof(ref)); -+ full_write(out_fd, &ref, sizeof(ref)); -+ padword(); -+ } -+} -+ -+#else /* WITHOUT_XATTR */ -+#define write_xattr_entry(x) -+#endif -+ -+static void recursive_populate_directory(struct filesystem_entry *dir) -+{ -+ struct filesystem_entry *e; -+ unsigned int wrote; -+ -+ if (verbose) { -+ printf("%s\n", dir->fullname); -+ } -+ write_xattr_entry(dir); /* for '/' */ -+ -+ e = dir->files; -+ while (e) { -+ if (e->sb.st_nlink >= 1 && -+ (e->ino = find_hardlink(e))) { -+ -+ write_dirent(e); -+ if (verbose) { -+ printf("\tL %04o %9lu %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, (unsigned long) e->ino, -+ (int) (e->sb.st_uid), (int) (e->sb.st_gid), -+ e->name); -+ } -+ } else switch (e->sb.st_mode & S_IFMT) { -+ case S_IFDIR: -+ if (verbose) { -+ printf("\td %04o %9lu %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, e->sb.st_size, -+ (int) (e->sb.st_uid), (int) (e->sb.st_gid), -+ e->name); -+ } -+ write_pipe(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFSOCK: -+ if (verbose) { -+ printf("\ts %04o %9lu %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, e->sb.st_size, -+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name); -+ } -+ write_pipe(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFIFO: -+ if (verbose) { -+ printf("\tp %04o %9lu %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, e->sb.st_size, -+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name); -+ } -+ write_pipe(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFCHR: -+ if (verbose) { -+ printf("\tc %04o %4d,%4d %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev), -+ minor(e->sb.st_rdev), (int) e->sb.st_uid, -+ (int) e->sb.st_gid, e->name); -+ } -+ write_special_file(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFBLK: -+ if (verbose) { -+ printf("\tb %04o %4d,%4d %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev), -+ minor(e->sb.st_rdev), (int) e->sb.st_uid, -+ (int) e->sb.st_gid, e->name); -+ } -+ write_special_file(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFLNK: -+ if (verbose) { -+ printf("\tl %04o %9lu %5d:%-3d %s -> %s\n", -+ e->sb.st_mode & ~S_IFMT, e->sb.st_size, -+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name, -+ e->link); -+ } -+ write_symlink(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFREG: -+ wrote = write_regular_file(e); -+ write_xattr_entry(e); -+ if (verbose) { -+ printf("\tf %04o %9lu (%9u) %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, e->sb.st_size, wrote, -+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name); -+ } -+ break; -+ default: -+ error_msg("Unknown mode %o for %s", e->sb.st_mode, -+ e->fullname); -+ break; -+ } -+ e = e->next; -+ } -+ -+ e = dir->files; -+ while (e) { -+ if (S_ISDIR(e->sb.st_mode)) { -+ if (e->files) { -+ recursive_populate_directory(e); -+ } else if (verbose) { -+ printf("%s\n", e->fullname); -+ } -+ } -+ e = e->next; -+ } -+} -+ -+static void create_target_filesystem(struct filesystem_entry *root) -+{ -+ cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); -+ cleanmarker.totlen = cpu_to_je32(cleanmarker_size); -+ cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4)); -+ -+ if (ino == 0) -+ ino = 1; -+ -+ root->ino = 1; -+ recursive_populate_directory(root); -+ -+ if (pad_fs_size == -1) { -+ padblock(); -+ } else { -+ if (pad_fs_size && add_cleanmarkers){ -+ padblock(); -+ while (out_ofs < pad_fs_size) { -+ full_write(out_fd, &cleanmarker, sizeof(cleanmarker)); -+ pad(cleanmarker_size - sizeof(cleanmarker)); -+ padblock(); -+ } -+ } else { -+ while (out_ofs < pad_fs_size) { -+ full_write(out_fd, ffbuf, min(sizeof(ffbuf), pad_fs_size - out_ofs)); -+ } -+ -+ } -+ } -+} -+ -+static struct option long_options[] = { -+ {"pad", 2, NULL, 'p'}, -+ {"root", 1, NULL, 'r'}, -+ {"pagesize", 1, NULL, 's'}, -+ {"eraseblock", 1, NULL, 'e'}, -+ {"output", 1, NULL, 'o'}, -+ {"help", 0, NULL, 'h'}, -+ {"verbose", 0, NULL, 'v'}, -+ {"version", 0, NULL, 'V'}, -+ {"big-endian", 0, NULL, 'b'}, -+ {"little-endian", 0, NULL, 'l'}, -+ {"no-cleanmarkers", 0, NULL, 'n'}, -+ {"cleanmarker", 1, NULL, 'c'}, -+ {"squash", 0, NULL, 'q'}, -+ {"squash-uids", 0, NULL, 'U'}, -+ {"squash-perms", 0, NULL, 'P'}, -+ {"faketime", 0, NULL, 'f'}, -+ {"devtable", 1, NULL, 'D'}, -+ {"compression-mode", 1, NULL, 'm'}, -+ {"disable-compressor", 1, NULL, 'x'}, -+ {"test-compression", 0, NULL, 't'}, -+ {"compressor-priority", 1, NULL, 'y'}, -+ {"incremental", 1, NULL, 'i'}, -+#ifndef WITHOUT_XATTR -+ {"with-xattr", 0, NULL, 1000 }, -+ {"with-selinux", 0, NULL, 1001 }, -+ {"with-posix-acl", 0, NULL, 1002 }, -+#endif -+ {NULL, 0, NULL, 0} -+}; -+ -+static char *helptext = -+"Usage: mkfs.jffs2 [OPTIONS]\n" -+"Make a JFFS2 file system image from an existing directory tree\n\n" -+"Options:\n" -+" -p, --pad[=SIZE] Pad output to SIZE bytes with 0xFF. If SIZE is\n" -+" not specified, the output is padded to the end of\n" -+" the final erase block\n" -+" -r, -d, --root=DIR Build file system from directory DIR (default: cwd)\n" -+" -s, --pagesize=SIZE Use page size (max data node size) SIZE (default: 4KiB)\n" -+" -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)\n" -+" -c, --cleanmarker=SIZE Size of cleanmarker (default 12)\n" -+" -m, --compr-mode=MODE Select compression mode (default: priortiry)\n" -+" -x, --disable-compressor=COMPRESSOR_NAME\n" -+" Disable a compressor\n" -+" -X, --enable-compressor=COMPRESSOR_NAME\n" -+" Enable a compressor\n" -+" -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME\n" -+" Set the priority of a compressor\n" -+" -L, --list-compressors Show the list of the avaiable compressors\n" -+" -t, --test-compression Call decompress and compare with the original (for test)\n" -+" -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock\n" -+" -o, --output=FILE Output to FILE (default: stdout)\n" -+" -l, --little-endian Create a little-endian filesystem\n" -+" -b, --big-endian Create a big-endian filesystem\n" -+" -D, --devtable=FILE Use the named FILE as a device table file\n" -+" -f, --faketime Change all file times to '0' for regression testing\n" -+" -q, --squash Squash permissions and owners making all files be owned by root\n" -+" -U, --squash-uids Squash owners making all files be owned by root\n" -+" -P, --squash-perms Squash permissions on all files\n" -+#ifndef WITHOUT_XATTR -+" --with-xattr stuff all xattr entries into image\n" -+" --with-selinux stuff only SELinux Labels into jffs2 image\n" -+" --with-posix-acl stuff only POSIX ACL entries into jffs2 image\n" -+#endif -+" -h, --help Display this help text\n" -+" -v, --verbose Verbose operation\n" -+" -V, --version Display version information\n" -+" -i, --incremental=FILE Parse FILE and generate appendage output for it\n\n"; -+ -+static char *revtext = "1.60"; -+ -+int load_next_block() { -+ -+ int ret; -+ ret = read(in_fd, file_buffer, erase_block_size); -+ -+ if(verbose) -+ printf("Load next block : %d bytes read\n",ret); -+ -+ return ret; -+} -+ -+void process_buffer(int inp_size) { -+ uint8_t *p = file_buffer; -+ union jffs2_node_union *node; -+ uint16_t type; -+ int bitchbitmask = 0; -+ int obsolete; -+ -+ char name[256]; -+ -+ while ( p < (file_buffer + inp_size)) { -+ -+ node = (union jffs2_node_union *) p; -+ -+ /* Skip empty space */ -+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) { -+ p += 4; -+ continue; -+ } -+ -+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) { -+ if (!bitchbitmask++) -+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic)); -+ p += 4; -+ continue; -+ } -+ -+ bitchbitmask = 0; -+ -+ type = je16_to_cpu(node->u.nodetype); -+ if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) { -+ obsolete = 1; -+ type |= JFFS2_NODE_ACCURATE; -+ } else -+ obsolete = 0; -+ -+ node->u.nodetype = cpu_to_je16(type); -+ -+ switch(je16_to_cpu(node->u.nodetype)) { -+ -+ case JFFS2_NODETYPE_INODE: -+ if(verbose) -+ printf ("%8s Inode node at 0x%08x, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino), -+ je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize), -+ je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset)); -+ -+ if ( je32_to_cpu (node->i.ino) > ino ) -+ ino = je32_to_cpu (node->i.ino); -+ -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ memcpy (name, node->d.name, node->d.nsize); -+ name [node->d.nsize] = 0x0; -+ -+ if(verbose) -+ printf ("%8s Dirent node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino), -+ je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino), -+ node->d.nsize, name); -+ -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_CLEANMARKER: -+ if (verbose) { -+ printf ("%8s Cleanmarker at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_PADDING: -+ if (verbose) { -+ printf ("%8s Padding node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case 0xffff: -+ p += 4; -+ break; -+ -+ default: -+ if (verbose) { -+ printf ("%8s Unknown node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ } -+ } -+} -+ -+void parse_image(){ -+ int ret; -+ -+ file_buffer = malloc(erase_block_size); -+ -+ if (!file_buffer) { -+ perror("out of memory"); -+ close (in_fd); -+ close (out_fd); -+ exit(1); -+ } -+ -+ while ((ret = load_next_block())) { -+ process_buffer(ret); -+ } -+ -+ if (file_buffer) -+ free(file_buffer); -+ -+ close(in_fd); -+} -+ -+int main(int argc, char **argv) -+{ -+ int c, opt; -+ char *cwd; -+ struct stat sb; -+ FILE *devtable = NULL; -+ struct filesystem_entry *root; -+ char *compr_name = NULL; -+ int compr_prior = -1; -+ int warn_page_size = 0; -+ -+ page_size = sysconf(_SC_PAGESIZE); -+ if (page_size < 0) /* System doesn't know so ... */ -+ page_size = 4096; /* ... we make an educated guess */ -+ if (page_size != 4096) -+ warn_page_size = 1; /* warn user if page size not 4096 */ -+ -+ jffs2_compressors_init(); -+ -+ while ((opt = getopt_long(argc, argv, -+ "D:d:r:s:o:qUPfh?vVe:lbp::nc:m:x:X:Lty:i:", long_options, &c)) >= 0) -+ { -+ switch (opt) { -+ case 'D': -+ devtable = xfopen(optarg, "r"); -+ if (fstat(fileno(devtable), &sb) < 0) -+ perror_msg_and_die(optarg); -+ if (sb.st_size < 10) -+ error_msg_and_die("%s: not a proper device table file", optarg); -+ break; -+ -+ case 'r': -+ case 'd': /* for compatibility with mkfs.jffs, genext2fs, etc... */ -+ if (rootdir != default_rootdir) { -+ error_msg_and_die("root directory specified more than once"); -+ } -+ rootdir = xstrdup(optarg); -+ break; -+ -+ case 's': -+ page_size = strtol(optarg, NULL, 0); -+ warn_page_size = 0; /* set by user, so don't need to warn */ -+ break; -+ -+ case 'o': -+ if (out_fd != -1) { -+ error_msg_and_die("output filename specified more than once"); -+ } -+ out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644); -+ if (out_fd == -1) { -+ perror_msg_and_die("open output file"); -+ } -+ break; -+ -+ case 'q': -+ squash_uids = 1; -+ squash_perms = 1; -+ break; -+ -+ case 'U': -+ squash_uids = 1; -+ break; -+ -+ case 'P': -+ squash_perms = 1; -+ break; -+ -+ case 'f': -+ fake_times = 1; -+ break; -+ -+ case 'h': -+ case '?': -+ error_msg_and_die(helptext); -+ -+ case 'v': -+ verbose = 1; -+ break; -+ -+ case 'V': -+ error_msg_and_die("revision %s\n", revtext); -+ -+ case 'e': { -+ char *next; -+ unsigned units = 0; -+ erase_block_size = strtol(optarg, &next, 0); -+ if (!erase_block_size) -+ error_msg_and_die("Unrecognisable erase size\n"); -+ -+ if (*next) { -+ if (!strcmp(next, "KiB")) { -+ units = 1024; -+ } else if (!strcmp(next, "MiB")) { -+ units = 1024 * 1024; -+ } else { -+ error_msg_and_die("Unknown units in erasesize\n"); -+ } -+ } else { -+ if (erase_block_size < 0x1000) -+ units = 1024; -+ else -+ units = 1; -+ } -+ erase_block_size *= units; -+ -+ /* If it's less than 8KiB, they're not allowed */ -+ if (erase_block_size < 0x2000) { -+ fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n", -+ erase_block_size); -+ erase_block_size = 0x2000; -+ } -+ break; -+ } -+ -+ case 'l': -+ target_endian = __LITTLE_ENDIAN; -+ break; -+ -+ case 'b': -+ target_endian = __BIG_ENDIAN; -+ break; -+ -+ case 'p': -+ if (optarg) -+ pad_fs_size = strtol(optarg, NULL, 0); -+ else -+ pad_fs_size = -1; -+ break; -+ case 'n': -+ add_cleanmarkers = 0; -+ break; -+ case 'c': -+ cleanmarker_size = strtol(optarg, NULL, 0); -+ if (cleanmarker_size < sizeof(cleanmarker)) { -+ error_msg_and_die("cleanmarker size must be >= 12"); -+ } -+ if (cleanmarker_size >= erase_block_size) { -+ error_msg_and_die("cleanmarker size must be < eraseblock size"); -+ } -+ break; -+ case 'm': -+ if (jffs2_set_compression_mode_name(optarg)) { -+ error_msg_and_die("Unknown compression mode %s", optarg); -+ } -+ break; -+ case 'x': -+ if (jffs2_disable_compressor_name(optarg)) { -+ error_msg_and_die("Unknown compressor name %s",optarg); -+ } -+ break; -+ case 'X': -+ if (jffs2_enable_compressor_name(optarg)) { -+ error_msg_and_die("Unknown compressor name %s",optarg); -+ } -+ break; -+ case 'L': -+ error_msg_and_die("\n%s",jffs2_list_compressors()); -+ break; -+ case 't': -+ jffs2_compression_check_set(1); -+ break; -+ case 'y': -+ compr_name = malloc(strlen(optarg)); -+ sscanf(optarg,"%d:%s",&compr_prior,compr_name); -+ if ((compr_prior>=0)&&(compr_name)) { -+ if (jffs2_set_compressor_priority(compr_name, compr_prior)) -+ exit(EXIT_FAILURE); -+ } -+ else { -+ error_msg_and_die("Cannot parse %s",optarg); -+ } -+ free(compr_name); -+ break; -+ case 'i': -+ if (in_fd != -1) { -+ error_msg_and_die("(incremental) filename specified more than once"); -+ } -+ in_fd = open(optarg, O_RDONLY); -+ if (in_fd == -1) { -+ perror_msg_and_die("cannot open (incremental) file"); -+ } -+ break; -+#ifndef WITHOUT_XATTR -+ case 1000: /* --with-xattr */ -+ enable_xattr |= (1 << JFFS2_XPREFIX_USER) -+ | (1 << JFFS2_XPREFIX_SECURITY) -+ | (1 << JFFS2_XPREFIX_ACL_ACCESS) -+ | (1 << JFFS2_XPREFIX_ACL_DEFAULT) -+ | (1 << JFFS2_XPREFIX_TRUSTED); -+ break; -+ case 1001: /* --with-selinux */ -+ enable_xattr |= (1 << JFFS2_XPREFIX_SECURITY); -+ break; -+ case 1002: /* --with-posix-acl */ -+ enable_xattr |= (1 << JFFS2_XPREFIX_ACL_ACCESS) -+ | (1 << JFFS2_XPREFIX_ACL_DEFAULT); -+ break; -+#endif -+ } -+ } -+ if (warn_page_size) { -+ error_msg("Page size for this system is by default %d", page_size); -+ error_msg("Use the --pagesize=SIZE option if this is not what you want"); -+ } -+ if (out_fd == -1) { -+ if (isatty(1)) { -+ error_msg_and_die(helptext); -+ } -+ out_fd = 1; -+ } -+ if (lstat(rootdir, &sb)) { -+ perror_msg_and_die("%s", rootdir); -+ } -+ if (chdir(rootdir)) -+ perror_msg_and_die("%s", rootdir); -+ -+ if (!(cwd = getcwd(0, GETCWD_SIZE))) -+ perror_msg_and_die("getcwd failed"); -+ -+ if(in_fd != -1) -+ parse_image(); -+ -+ root = recursive_add_host_directory(NULL, "/", cwd); -+ -+ if (devtable) -+ parse_device_table(root, devtable); -+ -+ create_target_filesystem(root); -+ -+ cleanup(root); -+ -+ if (rootdir != default_rootdir) -+ free(rootdir); -+ -+ close(out_fd); -+ -+ if (verbose) { -+ char *s = jffs2_stats(); -+ fprintf(stderr,"\n\n%s",s); -+ free(s); -+ } -+ if ((verbose)||(jffs2_compression_check_get()&&(jffs2_compression_check_errorcnt_get()))) { -+ fprintf(stderr,"Compression errors: %d\n",jffs2_compression_check_errorcnt_get()); -+ } -+ -+ jffs2_compressors_exit(); -+ -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/mtd-utils.spec 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/mtd-utils.spec 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,40 @@ -+Summary: Tools for maintaining Memory Technology Devices -+Name: mtd-utils -+Version: 1.0 -+Release: 1 -+License: GPL -+Group: Applications/System -+URL: http://www.linux-mtd.infradead.org/ -+Source0: %{name}-%{version}.tar.gz -+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root -+ -+%description -+This package contains tools for erasing and formatting flash devices, -+including JFFS2, M-Systems DiskOnChip devices, etc. -+ -+%prep -+%setup -q -+ -+%build -+make -C util -+ -+%install -+rm -rf $RPM_BUILD_ROOT -+make DESTDIR=$RPM_BUILD_ROOT -C util install -+ -+%clean -+rm -rf $RPM_BUILD_ROOT -+ -+ -+%files -+%defattr(-,root,root,-) -+/usr/sbin -+/usr/man/man1/mkfs.jffs2.1.gz -+/usr/include/mtd -+%doc -+ -+ -+%changelog -+* Wed May 5 2004 - 1.0 -+- Initial build. -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/mtd_debug.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/mtd_debug.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,418 @@ -+/* -+ * Copyright (c) 2d3D, Inc. -+ * Written by Abraham vd Merwe -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. Neither the name of the author nor the names of other contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * MEMGETINFO -+ */ -+static int getmeminfo (int fd,struct mtd_info_user *mtd) -+{ -+ return (ioctl (fd,MEMGETINFO,mtd)); -+} -+ -+/* -+ * MEMERASE -+ */ -+static int memerase (int fd,struct erase_info_user *erase) -+{ -+ return (ioctl (fd,MEMERASE,erase)); -+} -+ -+/* -+ * MEMGETREGIONCOUNT -+ * MEMGETREGIONINFO -+ */ -+static int getregions (int fd,struct region_info_user *regions,int *n) -+{ -+ int i,err; -+ err = ioctl (fd,MEMGETREGIONCOUNT,n); -+ if (err) return (err); -+ for (i = 0; i < *n; i++) -+ { -+ regions[i].regionindex = i; -+ err = ioctl (fd,MEMGETREGIONINFO,®ions[i]); -+ if (err) return (err); -+ } -+ return (0); -+} -+ -+int erase_flash (int fd,u_int32_t offset,u_int32_t bytes) -+{ -+ int err; -+ struct erase_info_user erase; -+ erase.start = offset; -+ erase.length = bytes; -+ err = memerase (fd,&erase); -+ if (err < 0) -+ { -+ perror ("MEMERASE"); -+ return (1); -+ } -+ fprintf (stderr,"Erased %d bytes from address 0x%.8x in flash\n",bytes,offset); -+ return (0); -+} -+ -+void printsize (u_int32_t x) -+{ -+ int i; -+ static const char *flags = "KMGT"; -+ printf ("%u ",x); -+ for (i = 0; x >= 1024 && flags[i] != '\0'; i++) x /= 1024; -+ i--; -+ if (i >= 0) printf ("(%u%c)",x,flags[i]); -+} -+ -+int flash_to_file (int fd,u_int32_t offset,size_t len,const char *filename) -+{ -+ u_int8_t *buf = NULL; -+ int outfd,err; -+ int size = len * sizeof (u_int8_t); -+ int n = len; -+ -+ if (offset != lseek (fd,offset,SEEK_SET)) -+ { -+ perror ("lseek()"); -+ goto err0; -+ } -+ outfd = creat (filename,O_WRONLY); -+ if (outfd < 0) -+ { -+ perror ("creat()"); -+ goto err1; -+ } -+ -+retry: -+ if ((buf = (u_int8_t *) malloc (size)) == NULL) -+ { -+#define BUF_SIZE (64 * 1024 * sizeof (u_int8_t)) -+ fprintf (stderr, "%s: malloc(%#x)\n", __FUNCTION__, size); -+ if (size != BUF_SIZE) { -+ size = BUF_SIZE; -+ fprintf (stderr, "%s: trying buffer size %#x\n", __FUNCTION__, size); -+ goto retry; -+ } -+ perror ("malloc()"); -+ goto err0; -+ } -+ do { -+ if (n <= size) -+ size = n; -+ err = read (fd,buf,size); -+ if (err < 0) -+ { -+ fprintf (stderr, "%s: read, size %#x, n %#x\n", __FUNCTION__, size, n); -+ perror ("read()"); -+ goto err2; -+ } -+ err = write (outfd,buf,size); -+ if (err < 0) -+ { -+ fprintf (stderr, "%s: write, size %#x, n %#x\n", __FUNCTION__, size, n); -+ perror ("write()"); -+ goto err2; -+ } -+ if (err != size) -+ { -+ fprintf (stderr,"Couldn't copy entire buffer to %s. (%d/%d bytes copied)\n",filename,err,size); -+ goto err2; -+ } -+ n -= size; -+ } while (n > 0); -+ -+ if (buf != NULL) -+ free (buf); -+ close (outfd); -+ printf ("Copied %d bytes from address 0x%.8x in flash to %s\n",len,offset,filename); -+ return (0); -+ -+err2: -+ close (outfd); -+err1: -+ if (buf != NULL) -+ free (buf); -+err0: -+ return (1); -+} -+ -+int file_to_flash (int fd,u_int32_t offset,u_int32_t len,const char *filename) -+{ -+ u_int8_t *buf = NULL; -+ FILE *fp; -+ int err; -+ int size = len * sizeof (u_int8_t); -+ int n = len; -+ -+ if (offset != lseek (fd,offset,SEEK_SET)) -+ { -+ perror ("lseek()"); -+ return (1); -+ } -+ if ((fp = fopen (filename,"r")) == NULL) -+ { -+ perror ("fopen()"); -+ return (1); -+ } -+retry: -+ if ((buf = (u_int8_t *) malloc (size)) == NULL) -+ { -+ fprintf (stderr, "%s: malloc(%#x) failed\n", __FUNCTION__, size); -+ if (size != BUF_SIZE) { -+ size = BUF_SIZE; -+ fprintf (stderr, "%s: trying buffer size %#x\n", __FUNCTION__, size); -+ goto retry; -+ } -+ perror ("malloc()"); -+ fclose (fp); -+ return (1); -+ } -+ do { -+ if (n <= size) -+ size = n; -+ if (fread (buf,size,1,fp) != 1 || ferror (fp)) -+ { -+ fprintf (stderr, "%s: fread, size %#x, n %#x\n", __FUNCTION__, size, n); -+ perror ("fread()"); -+ free (buf); -+ fclose (fp); -+ return (1); -+ } -+ err = write (fd,buf,size); -+ if (err < 0) -+ { -+ fprintf (stderr, "%s: write, size %#x, n %#x\n", __FUNCTION__, size, n); -+ perror ("write()"); -+ free (buf); -+ fclose (fp); -+ return (1); -+ } -+ n -= size; -+ } while (n > 0); -+ -+ if (buf != NULL) -+ free (buf); -+ fclose (fp); -+ printf ("Copied %d bytes from %s to address 0x%.8x in flash\n",len,filename,offset); -+ return (0); -+} -+ -+int showinfo (int fd) -+{ -+ int i,err,n; -+ struct mtd_info_user mtd; -+ static struct region_info_user region[1024]; -+ -+ err = getmeminfo (fd,&mtd); -+ if (err < 0) -+ { -+ perror ("MEMGETINFO"); -+ return (1); -+ } -+ -+ err = getregions (fd,region,&n); -+ if (err < 0) -+ { -+ perror ("MEMGETREGIONCOUNT"); -+ return (1); -+ } -+ -+ printf ("mtd.type = "); -+ switch (mtd.type) -+ { -+ case MTD_ABSENT: -+ printf ("MTD_ABSENT"); -+ break; -+ case MTD_RAM: -+ printf ("MTD_RAM"); -+ break; -+ case MTD_ROM: -+ printf ("MTD_ROM"); -+ break; -+ case MTD_NORFLASH: -+ printf ("MTD_NORFLASH"); -+ break; -+ case MTD_NANDFLASH: -+ printf ("MTD_NANDFLASH"); -+ break; -+ case MTD_DATAFLASH: -+ printf ("MTD_DATAFLASH"); -+ break; -+ case MTD_UBIVOLUME: -+ printf ("MTD_UBIVOLUME"); -+ default: -+ printf ("(unknown type - new MTD API maybe?)"); -+ } -+ -+ printf ("\nmtd.flags = "); -+ if (mtd.flags == MTD_CAP_ROM) -+ printf ("MTD_CAP_ROM"); -+ else if (mtd.flags == MTD_CAP_RAM) -+ printf ("MTD_CAP_RAM"); -+ else if (mtd.flags == MTD_CAP_NORFLASH) -+ printf ("MTD_CAP_NORFLASH"); -+ else if (mtd.flags == MTD_CAP_NANDFLASH) -+ printf ("MTD_CAP_NANDFLASH"); -+ else if (mtd.flags == MTD_WRITEABLE) -+ printf ("MTD_WRITEABLE"); -+ else -+ { -+ int first = 1; -+ static struct -+ { -+ const char *name; -+ int value; -+ } flags[] = -+ { -+ { "MTD_WRITEABLE", MTD_WRITEABLE }, -+ { "MTD_BIT_WRITEABLE", MTD_BIT_WRITEABLE }, -+ { "MTD_NO_ERASE", MTD_NO_ERASE }, -+ { "MTD_STUPID_LOCK", MTD_STUPID_LOCK }, -+ { NULL, -1 } -+ }; -+ for (i = 0; flags[i].name != NULL; i++) -+ if (mtd.flags & flags[i].value) -+ { -+ if (first) -+ { -+ printf (flags[i].name); -+ first = 0; -+ } -+ else printf (" | %s",flags[i].name); -+ } -+ } -+ -+ printf ("\nmtd.size = "); -+ printsize (mtd.size); -+ -+ printf ("\nmtd.erasesize = "); -+ printsize (mtd.erasesize); -+ -+ printf ("\nmtd.writesize = "); -+ printsize (mtd.writesize); -+ -+ printf ("\nmtd.oobsize = "); -+ printsize (mtd.oobsize); -+ -+ printf ("\n" -+ "regions = %d\n" -+ "\n", -+ n); -+ -+ for (i = 0; i < n; i++) -+ { -+ printf ("region[%d].offset = 0x%.8x\n" -+ "region[%d].erasesize = ", -+ i,region[i].offset,i); -+ printsize (region[i].erasesize); -+ printf ("\nregion[%d].numblocks = %d\n" -+ "region[%d].regionindex = %d\n", -+ i,region[i].numblocks, -+ i,region[i].regionindex); -+ } -+ return (0); -+} -+ -+void showusage (const char *progname) -+{ -+ fprintf (stderr, -+ "usage: %s info \n" -+ " %s read \n" -+ " %s write \n" -+ " %s erase \n", -+ progname, -+ progname, -+ progname, -+ progname); -+ exit (1); -+} -+ -+#define OPT_INFO 1 -+#define OPT_READ 2 -+#define OPT_WRITE 3 -+#define OPT_ERASE 4 -+ -+int main (int argc,char *argv[]) -+{ -+ const char *progname; -+ int err = 0,fd,option = OPT_INFO; -+ int open_flag; -+ (progname = strrchr (argv[0],'/')) ? progname++ : (progname = argv[0]); -+ -+ /* parse command-line options */ -+ if (argc == 3 && !strcmp (argv[1],"info")) -+ option = OPT_INFO; -+ else if (argc == 6 && !strcmp (argv[1],"read")) -+ option = OPT_READ; -+ else if (argc == 6 && !strcmp (argv[1],"write")) -+ option = OPT_WRITE; -+ else if (argc == 5 && !strcmp (argv[1],"erase")) -+ option = OPT_ERASE; -+ else -+ showusage (progname); -+ -+ /* open device */ -+ open_flag = (option==OPT_INFO || option==OPT_READ) ? O_RDONLY : O_RDWR; -+ if ((fd = open (argv[2],O_SYNC | open_flag)) < 0) -+ { -+ perror ("open()"); -+ exit (1); -+ } -+ -+ switch (option) -+ { -+ case OPT_INFO: -+ showinfo (fd); -+ break; -+ case OPT_READ: -+ err = flash_to_file (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0),argv[5]); -+ break; -+ case OPT_WRITE: -+ err = file_to_flash (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0),argv[5]); -+ break; -+ case OPT_ERASE: -+ err = erase_flash (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0)); -+ break; -+ } -+ -+ /* close device */ -+ if (close (fd) < 0) -+ perror ("close()"); -+ -+ exit (err); -+} -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nanddump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nanddump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,403 @@ -+/* -+ * nanddump.c -+ * -+ * Copyright (C) 2000 David Woodhouse (dwmw2@infradead.org) -+ * Steven J. Hill (sjhill@realitydiluted.com) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Overview: -+ * This utility dumps the contents of raw NAND chips or NAND -+ * chips contained in DoC devices. -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define PROGRAM "nanddump" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+struct nand_oobinfo none_oobinfo = { -+ .useecc = MTD_NANDECC_OFF, -+}; -+ -+void display_help (void) -+{ -+ printf("Usage: nanddump [OPTIONS] MTD-device\n" -+ "Dumps the contents of a nand mtd partition.\n" -+ "\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n" -+ "-f file --file=file dump to file\n" -+ "-i --ignoreerrors ignore errors\n" -+ "-l length --length=length length\n" -+ "-n --noecc read without error correction\n" -+ "-o --omitoob omit oob data\n" -+ "-b --omitbad omit bad blocks from the dump\n" -+ "-p --prettyprint print nice (hexdump)\n" -+ "-s addr --startaddress=addr start address\n"); -+ exit(0); -+} -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} -+ -+// Option variables -+ -+int ignoreerrors; // ignore errors -+int pretty_print; // print nice in ascii -+int noecc; // don't error correct -+int omitoob; // omit oob data -+unsigned long start_addr; // start address -+unsigned long length; // dump length -+char *mtddev; // mtd device name -+char *dumpfile; // dump file name -+int omitbad; -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "bs:f:il:opn"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"file", required_argument, 0, 'f'}, -+ {"ignoreerrors", no_argument, 0, 'i'}, -+ {"prettyprint", no_argument, 0, 'p'}, -+ {"omitoob", no_argument, 0, 'o'}, -+ {"omitbad", no_argument, 0, 'b'}, -+ {"startaddress", required_argument, 0, 's'}, -+ {"length", required_argument, 0, 'l'}, -+ {"noecc", no_argument, 0, 'n'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'b': -+ omitbad = 1; -+ break; -+ case 's': -+ start_addr = strtol(optarg, NULL, 0); -+ break; -+ case 'f': -+ if (!(dumpfile = strdup(optarg))) { -+ perror("stddup"); -+ exit(1); -+ } -+ break; -+ case 'i': -+ ignoreerrors = 1; -+ break; -+ case 'l': -+ length = strtol(optarg, NULL, 0); -+ break; -+ case 'o': -+ omitoob = 1; -+ break; -+ case 'p': -+ pretty_print = 1; -+ break; -+ case 'n': -+ noecc = 1; -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 1 || error) -+ display_help (); -+ -+ mtddev = argv[optind]; -+} -+ -+/* -+ * Buffers for reading data from flash -+ */ -+unsigned char readbuf[8192]; -+unsigned char oobbuf[256]; -+ -+/* -+ * Main program -+ */ -+int main(int argc, char **argv) -+{ -+ unsigned long ofs, end_addr = 0; -+ unsigned long long blockstart = 1; -+ int ret, i, fd, ofd, bs, badblock = 0; -+ struct mtd_oob_buf oob = {0, 16, oobbuf}; -+ mtd_info_t meminfo; -+ char pretty_buf[80]; -+ int oobinfochanged = 0 ; -+ struct nand_oobinfo old_oobinfo; -+ struct mtd_ecc_stats stat1, stat2; -+ int eccstats = 0; -+ -+ process_options(argc, argv); -+ -+ /* Open MTD device */ -+ if ((fd = open(mtddev, O_RDONLY)) == -1) { -+ perror("open flash"); -+ exit (1); -+ } -+ -+ /* Fill in MTD device capability structure */ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("MEMGETINFO"); -+ close(fd); -+ exit (1); -+ } -+ -+ /* Make sure device page sizes are valid */ -+ if (!(meminfo.oobsize == 256 && meminfo.writesize == 8192) && -+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096) && -+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) && -+ !(meminfo.oobsize == 32 && meminfo.writesize == 1024) && -+ !(meminfo.oobsize == 16 && meminfo.writesize == 512) && -+ !(meminfo.oobsize == 8 && meminfo.writesize == 256)) { -+ fprintf(stderr, "Unknown flash (not normal NAND)\n"); -+ close(fd); -+ exit(1); -+ } -+ /* Read the real oob length */ -+ oob.length = meminfo.oobsize; -+ -+ if (noecc) { -+ ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW); -+ if (ret == 0) { -+ oobinfochanged = 2; -+ } else { -+ switch (errno) { -+ case ENOTTY: -+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMGETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ oobinfochanged = 1; -+ break; -+ default: -+ perror ("MTDFILEMODE"); -+ close (fd); -+ exit (1); -+ } -+ } -+ } else { -+ -+ /* check if we can read ecc stats */ -+ if (!ioctl(fd, ECCGETSTATS, &stat1)) { -+ eccstats = 1; -+ fprintf(stderr, "ECC failed: %d\n", stat1.failed); -+ fprintf(stderr, "ECC corrected: %d\n", stat1.corrected); -+ fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks); -+ fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks); -+ } else -+ perror("No ECC status information available"); -+ } -+ -+ /* Open output file for writing. If file name is "-", write to standard -+ * output. */ -+ if (!dumpfile) { -+ ofd = STDOUT_FILENO; -+ } else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) { -+ perror ("open outfile"); -+ close(fd); -+ exit(1); -+ } -+ -+ /* Initialize start/end addresses and block size */ -+ if (length) -+ end_addr = start_addr + length; -+ if (!length || end_addr > meminfo.size) -+ end_addr = meminfo.size; -+ -+ bs = meminfo.writesize; -+ -+ /* Print informative message */ -+ fprintf(stderr, "Block size %u, page size %u, OOB size %u\n", -+ meminfo.erasesize, meminfo.writesize, meminfo.oobsize); -+ fprintf(stderr, -+ "Dumping data starting at 0x%08x and ending at 0x%08x...\n", -+ (unsigned int) start_addr, (unsigned int) end_addr); -+ -+ /* Dump the flash contents */ -+ for (ofs = start_addr; ofs < end_addr ; ofs+=bs) { -+ -+ // new eraseblock , check for bad block -+ if (blockstart != (ofs & (~meminfo.erasesize + 1))) { -+ blockstart = ofs & (~meminfo.erasesize + 1); -+ if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) { -+ perror("ioctl(MEMGETBADBLOCK)"); -+ goto closeall; -+ } -+ } -+ -+ if (badblock) { -+ if (omitbad) -+ continue; -+ memset (readbuf, 0xff, bs); -+ } else { -+ /* Read page data and exit on failure */ -+ if (pread(fd, readbuf, bs, ofs) != bs) { -+ perror("pread"); -+ goto closeall; -+ } -+ } -+ -+ /* ECC stats available ? */ -+ if (eccstats) { -+ if (ioctl(fd, ECCGETSTATS, &stat2)) { -+ perror("ioctl(ECCGETSTATS)"); -+ goto closeall; -+ } -+ if (stat1.failed != stat2.failed) -+ fprintf(stderr, "ECC: %d uncorrectable bitflip(s)" -+ " at offset 0x%08lx\n", -+ stat2.failed - stat1.failed, ofs); -+ if (stat1.corrected != stat2.corrected) -+ fprintf(stderr, "ECC: %d corrected bitflip(s) at" -+ " offset 0x%08lx\n", -+ stat2.corrected - stat1.corrected, ofs); -+ stat1 = stat2; -+ } -+ -+ /* Write out page data */ -+ if (pretty_print) { -+ for (i = 0; i < bs; i += 16) { -+ sprintf(pretty_buf, -+ "0x%08x: %02x %02x %02x %02x %02x %02x %02x " -+ "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n", -+ (unsigned int) (ofs + i), readbuf[i], -+ readbuf[i+1], readbuf[i+2], -+ readbuf[i+3], readbuf[i+4], -+ readbuf[i+5], readbuf[i+6], -+ readbuf[i+7], readbuf[i+8], -+ readbuf[i+9], readbuf[i+10], -+ readbuf[i+11], readbuf[i+12], -+ readbuf[i+13], readbuf[i+14], -+ readbuf[i+15]); -+ write(ofd, pretty_buf, 60); -+ } -+ } else -+ write(ofd, readbuf, bs); -+ -+ -+ -+ if (omitoob) -+ continue; -+ -+ if (badblock) { -+ memset (readbuf, 0xff, meminfo.oobsize); -+ } else { -+ /* Read OOB data and exit on failure */ -+ oob.start = ofs; -+ if (ioctl(fd, MEMREADOOB, &oob) != 0) { -+ perror("ioctl(MEMREADOOB)"); -+ goto closeall; -+ } -+ } -+ -+ /* Write out OOB data */ -+ if (pretty_print) { -+ if (meminfo.oobsize < 16) { -+ sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x " -+ "%02x %02x\n", -+ oobbuf[0], oobbuf[1], oobbuf[2], -+ oobbuf[3], oobbuf[4], oobbuf[5], -+ oobbuf[6], oobbuf[7]); -+ write(ofd, pretty_buf, 48); -+ continue; -+ } -+ -+ for (i = 0; i < meminfo.oobsize; i += 16) { -+ sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x " -+ "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", -+ oobbuf[i], oobbuf[i+1], oobbuf[i+2], -+ oobbuf[i+3], oobbuf[i+4], oobbuf[i+5], -+ oobbuf[i+6], oobbuf[i+7], oobbuf[i+8], -+ oobbuf[i+9], oobbuf[i+10], oobbuf[i+11], -+ oobbuf[i+12], oobbuf[i+13], oobbuf[i+14], -+ oobbuf[i+15]); -+ write(ofd, pretty_buf, 60); -+ } -+ } else -+ write(ofd, oobbuf, meminfo.oobsize); -+ } -+ -+ /* reset oobinfo */ -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close(fd); -+ close(ofd); -+ return 1; -+ } -+ } -+ /* Close the output file and MTD device */ -+ close(fd); -+ close(ofd); -+ -+ /* Exit happy */ -+ return 0; -+ -+closeall: -+ /* The new mode change is per file descriptor ! */ -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ } -+ } -+ close(fd); -+ close(ofd); -+ exit(1); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nanddump_vfat.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nanddump_vfat.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,365 @@ -+/* -+ * nanddump.c -+ * -+ * Copyright (C) 2000 David Woodhouse (dwmw2@infradead.org) -+ * Steven J. Hill (sjhill@realitydiluted.com) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Overview: -+ * This utility dumps the contents of raw NAND chips or NAND -+ * chips contained in DoC devices. -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define PROGRAM "nanddump" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+struct nand_oobinfo none_oobinfo = { -+ .useecc = MTD_NANDECC_OFF, -+}; -+ -+void display_help (void) -+{ -+ printf("Usage: nanddump [OPTIONS] MTD-device\n" -+ "Dumps the contents of a nand mtd partition.\n" -+ "\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n" -+ "-f file --file=file dump to file\n" -+ "-i --ignoreerrors ignore errors\n" -+ "-l length --length=length length\n" -+ "-n --noecc read without error correction\n" -+ "-o --omitoob omit oob data\n" -+ "-b --omitbad omit bad blocks from the dump\n" -+ "-p --prettyprint print nice (hexdump)\n" -+ "-s addr --startaddress=addr start address\n"); -+ exit(0); -+} -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} -+ -+// Option variables -+ -+int ignoreerrors; // ignore errors -+int pretty_print; // print nice in ascii -+int noecc; // don't error correct -+int omitoob; // omit oob data -+unsigned long start_addr; // start address -+unsigned long length; // dump length -+char *mtddev; // mtd device name -+char *dumpfile; // dump file name -+int omitbad; -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "bs:f:il:opn"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"file", required_argument, 0, 'f'}, -+ {"ignoreerrors", no_argument, 0, 'i'}, -+ {"prettyprint", no_argument, 0, 'p'}, -+ {"omitoob", no_argument, 0, 'o'}, -+ {"omitbad", no_argument, 0, 'b'}, -+ {"startaddress", required_argument, 0, 's'}, -+ {"length", required_argument, 0, 'l'}, -+ {"noecc", no_argument, 0, 'n'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'b': -+ omitbad = 1; -+ break; -+ case 's': -+ start_addr = strtol(optarg, NULL, 0); -+ break; -+ case 'f': -+ if (!(dumpfile = strdup(optarg))) { -+ perror("stddup"); -+ exit(1); -+ } -+ break; -+ case 'i': -+ ignoreerrors = 1; -+ break; -+ case 'l': -+ length = strtol(optarg, NULL, 0); -+ break; -+ case 'o': -+ omitoob = 1; -+ break; -+ case 'p': -+ pretty_print = 1; -+ break; -+ case 'n': -+ noecc = 1; -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 1 || error) -+ display_help (); -+ -+ mtddev = argv[optind]; -+} -+ -+/* -+ * Buffers for reading data from flash -+ */ -+unsigned char readbuf[8192]; -+unsigned char oobbuf[256]; -+ -+/* -+ * Main program -+ */ -+int main(int argc, char **argv) -+{ -+ unsigned long ofs, end_addr = 0; -+ unsigned long long blockstart = 1; -+ int ret, fd, ofd, bs, badblock = 0; -+ struct mtd_oob_buf oob = {0, 16, oobbuf}; -+ mtd_info_t meminfo; -+ int oobinfochanged = 0 ; -+ struct nand_oobinfo old_oobinfo; -+ struct mtd_ecc_stats stat1, stat2; -+ int eccstats = 0; -+ -+ process_options(argc, argv); -+ -+ /* Open MTD device */ -+ if ((fd = open(mtddev, O_RDONLY)) == -1) { -+ perror("open flash"); -+ exit (1); -+ } -+ -+ /* Fill in MTD device capability structure */ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("MEMGETINFO"); -+ close(fd); -+ exit (1); -+ } -+ -+ /* Make sure device page sizes are valid */ -+ if (!(meminfo.oobsize == 256 && meminfo.writesize == 8192) && -+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096) && -+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) && -+ !(meminfo.oobsize == 32 && meminfo.writesize == 1024) && -+ !(meminfo.oobsize == 16 && meminfo.writesize == 512) && -+ !(meminfo.oobsize == 8 && meminfo.writesize == 256)) { -+ fprintf(stderr, "Unknown flash (not normal NAND)\n"); -+ close(fd); -+ exit(1); -+ } -+ /* Read the real oob length */ -+ oob.length = meminfo.oobsize; -+ -+ if (noecc) { -+ ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW); -+ if (ret == 0) { -+ oobinfochanged = 2; -+ } else { -+ switch (errno) { -+ case ENOTTY: -+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMGETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ oobinfochanged = 1; -+ break; -+ default: -+ perror ("MTDFILEMODE"); -+ close (fd); -+ exit (1); -+ } -+ } -+ } else { -+ -+ /* check if we can read ecc stats */ -+ if (!ioctl(fd, ECCGETSTATS, &stat1)) { -+ eccstats = 1; -+ fprintf(stderr, "ECC failed: %d\n", stat1.failed); -+ fprintf(stderr, "ECC corrected: %d\n", stat1.corrected); -+ fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks); -+ fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks); -+ } else -+ perror("No ECC status information available"); -+ } -+ -+ /* Open output file for writing. If file name is "-", write to standard -+ * output. */ -+ if (!dumpfile) { -+ ofd = STDOUT_FILENO; -+ } else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) { -+ perror ("open outfile"); -+ close(fd); -+ exit(1); -+ } -+ -+ /* Initialize start/end addresses and block size */ -+ if (length) -+ end_addr = start_addr + length; -+ if (!length || end_addr > meminfo.size) -+ end_addr = meminfo.size; -+ -+ bs = meminfo.writesize; -+ -+ /* Print informative message */ -+ fprintf(stderr, "Block size %u, page size %u, OOB size %u\n", -+ meminfo.erasesize, meminfo.writesize, meminfo.oobsize); -+ fprintf(stderr, -+ "Dumping data starting at 0x%08x and ending at 0x%08x...\n", -+ (unsigned int) start_addr, (unsigned int) end_addr); -+ -+ /* Dump the flash contents */ -+ for (ofs = start_addr; ofs < end_addr ; ofs+=bs) { -+ -+ // new eraseblock , check for bad block -+ if (blockstart != (ofs & (~meminfo.erasesize + 1))) { -+ blockstart = ofs & (~meminfo.erasesize + 1); -+ if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) { -+ perror("ioctl(MEMGETBADBLOCK)"); -+ goto closeall; -+ } -+ } -+ -+ if (badblock) { -+ //skip bad block; -+ ofs += meminfo.erasesize - bs; -+ continue; -+ } else { -+ /* Read page data and exit on failure */ -+ if (pread(fd, readbuf, bs, ofs) != bs) { -+ perror("pread"); -+ goto closeall; -+ } -+ } -+ -+ /* ECC stats available ? */ -+ if (eccstats) { -+ if (ioctl(fd, ECCGETSTATS, &stat2)) { -+ perror("ioctl(ECCGETSTATS)"); -+ goto closeall; -+ } -+ if (stat1.failed != stat2.failed) -+ fprintf(stderr, "ECC: %d uncorrectable bitflip(s)" -+ " at offset 0x%08lx\n", -+ stat2.failed - stat1.failed, ofs); -+ if (stat1.corrected != stat2.corrected) -+ fprintf(stderr, "ECC: %d corrected bitflip(s) at" -+ " offset 0x%08lx\n", -+ stat2.corrected - stat1.corrected, ofs); -+ stat1 = stat2; -+ } -+ -+ if (badblock) { -+ memset (readbuf, 0xff, meminfo.oobsize); -+ } else { -+ /* Read OOB data and exit on failure */ -+ oob.start = ofs; -+ if (ioctl(fd, MEMREADOOB, &oob) != 0) { -+ perror("ioctl(MEMREADOOB)"); -+ goto closeall; -+ } -+ if(oobbuf[2]==0xff && oobbuf[3]==0xff && oobbuf[4]==0xff && oobbuf[5]==0xff){ -+ //skip free block; -+ ofs += meminfo.erasesize - bs; -+ continue; -+ } -+ } -+ -+ /* Write out page data */ -+ write(ofd, readbuf, bs); -+ -+ if (omitoob) -+ continue; -+ -+ /* Write out OOB data */ -+ write(ofd, oobbuf, meminfo.oobsize); -+ } -+ -+ /* reset oobinfo */ -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close(fd); -+ close(ofd); -+ return 1; -+ } -+ } -+ /* Close the output file and MTD device */ -+ close(fd); -+ close(ofd); -+ -+ /* Exit happy */ -+ return 0; -+ -+closeall: -+ /* The new mode change is per file descriptor ! */ -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ } -+ } -+ close(fd); -+ close(ofd); -+ exit(1); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nandtest.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nandtest.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,284 @@ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "mtd/mtd-user.h" -+ -+void usage(void) -+{ -+ fprintf(stderr, "usage: nandtest [OPTIONS] \n\n" -+ " -h, --help Display this help output\n" -+ " -m, --markbad Mark blocks bad if they appear so\n" -+ " -s, --seed Supply random seed\n" -+ " -p, --passes Number of passes\n" -+ " -o, --offset Start offset on flash\n" -+ " -l, --length Length of flash to test\n" -+ " -k, --keep Restore existing contents after test\n" -+ "Warning: it is just used for SLC NAND!\n"); -+ -+ exit(1); -+} -+ -+struct mtd_info_user meminfo; -+struct mtd_ecc_stats oldstats, newstats; -+int fd; -+int markbad=0; -+int seed; -+ -+int erase_and_write(loff_mtd_t ofs, unsigned char *data, unsigned char *rbuf) -+{ -+ struct erase_info_user er; -+ ssize_t len; -+ int i; -+ -+ printf("\r%09llx: erasing... ", (loff_mtd_t)ofs); -+ fflush(stdout); -+ -+ er.start = ofs; -+ er.length = meminfo.erasesize; -+ -+ if (ioctl(fd, MEMERASE, &er)) { -+ perror("MEMERASE"); -+ if (markbad) { -+ printf("Mark block bad at %09llx\n", (loff_mtd_t)ofs); -+ ioctl(fd, MEMSETBADBLOCK, &ofs); -+ } -+ return 1; -+ } -+ -+ printf("\r%09llx: writing...", (loff_mtd_t)ofs); -+ fflush(stdout); -+ -+ len = pwrite(fd, data, meminfo.erasesize, ofs); -+ if (len < 0) { -+ printf("\n"); -+ perror("write"); -+ if (markbad) { -+ printf("Mark block bad at %09llx\n", (loff_mtd_t)ofs); -+ ioctl(fd, MEMSETBADBLOCK, &ofs); -+ } -+ return 1; -+ } -+ if (len < meminfo.erasesize) { -+ printf("\n"); -+ fprintf(stderr, "Short write (%d bytes)\n", len); -+ exit(1); -+ } -+ -+ printf("\r%09llx: reading...", (loff_mtd_t)ofs); -+ fflush(stdout); -+ -+ len = pread(fd, rbuf, meminfo.erasesize, ofs); -+ if (len < meminfo.erasesize) { -+ printf("\n"); -+ if (len) -+ fprintf(stderr, "Short read (%d bytes)\n", len); -+ else -+ perror("read"); -+ exit(1); -+ } -+ -+ if (ioctl(fd, ECCGETSTATS, &newstats)) { -+ printf("\n"); -+ perror("ECCGETSTATS"); -+ close(fd); -+ exit(1); -+ } -+ -+ if (newstats.corrected > oldstats.corrected) { -+ printf("\nECC corrected at %09llx\n", (loff_mtd_t) ofs); -+ oldstats.corrected = newstats.corrected; -+ } -+ if (newstats.failed > oldstats.failed) { -+ printf("\nECC failed at %09llx\n", (loff_mtd_t) ofs); -+ oldstats.corrected = newstats.corrected; -+ } -+ if (len < meminfo.erasesize) -+ exit(1); -+ -+ printf("\r%09llx: checking...", (loff_mtd_t)ofs); -+ fflush(stdout); -+ -+ if (memcmp(data, rbuf, meminfo.erasesize)) { -+ printf("\n"); -+ fprintf(stderr, "compare failed. seed %d\n", seed); -+ for (i=0; i meminfo.size) { -+ fprintf(stderr, "Length %09llx + offset %09llx exceeds device size %09llx\n", -+ length, offset, meminfo.size); -+ exit(1); -+ } -+ -+ wbuf = malloc(meminfo.erasesize * 3); -+ if (!wbuf) { -+ fprintf(stderr, "Could not allocate %d bytes for buffer\n", -+ meminfo.erasesize * 2); -+ exit(1); -+ } -+ rbuf = wbuf + meminfo.erasesize; -+ kbuf = rbuf + meminfo.erasesize; -+ -+ if (ioctl(fd, ECCGETSTATS, &oldstats)) { -+ perror("ECCGETSTATS"); -+ close(fd); -+ exit(1); -+ } -+ -+ printf("ECC corrections: %d\n", oldstats.corrected); -+ printf("ECC failures : %d\n", oldstats.failed); -+ printf("Bad blocks : %d\n", oldstats.badblocks); -+ printf("BBT blocks : %d\n", oldstats.bbtblocks); -+ -+ for (pass = 0; pass < nr_passes; pass++) { -+ loff_mtd_t test_ofs; -+ -+ for (test_ofs = offset; test_ofs < offset+length; test_ofs += meminfo.erasesize) { -+ ssize_t len; -+ -+ seed = rand(); -+ srand(seed); -+ -+ if (ioctl(fd, MEMGETBADBLOCK, &test_ofs)) { -+ printf("\rBad block at 0x%09llx\n", test_ofs); -+ continue; -+ } -+ -+ for (i=0; i -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "mtd/mtd-user.h" -+ -+#define PROGRAM "nandwrite" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+#define MAX_PAGE_SIZE 4096 -+#define MAX_OOB_SIZE 128 -+ -+/* -+ * Buffer array used for writing data -+ */ -+unsigned char writebuf[MAX_PAGE_SIZE]; -+unsigned char oobbuf[MAX_OOB_SIZE]; -+unsigned char oobreadbuf[MAX_OOB_SIZE]; -+ -+// oob layouts to pass into the kernel as default -+struct nand_oobinfo none_oobinfo = { -+ .useecc = MTD_NANDECC_OFF, -+}; -+ -+struct nand_oobinfo jffs2_oobinfo = { -+ .useecc = MTD_NANDECC_PLACE, -+ .eccbytes = 6, -+ .eccpos = { 0, 1, 2, 3, 6, 7 } -+}; -+ -+struct nand_oobinfo yaffs_oobinfo = { -+ .useecc = MTD_NANDECC_PLACE, -+ .eccbytes = 6, -+ .eccpos = { 8, 9, 10, 13, 14, 15} -+}; -+ -+struct nand_oobinfo autoplace_oobinfo = { -+ .useecc = MTD_NANDECC_AUTOPLACE -+}; -+ -+void display_help (void) -+{ -+ printf("Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILE\n" -+ "Writes to the specified MTD device.\n" -+ "\n" -+ " -a, --autoplace Use auto oob layout\n" -+ " -j, --jffs2 force jffs2 oob layout (legacy support)\n" -+ " -y, --yaffs force yaffs oob layout (legacy support)\n" -+ " -f, --forcelegacy force legacy support on autoplacement enabled mtd device\n" -+ " -m, --markbad mark blocks bad if write fails\n" -+ " -n, --noecc write without ecc\n" -+ " -o, --oob image contains oob data\n" -+ " -s addr, --start=addr set start address (default is 0)\n" -+ " -p, --pad pad to page size\n" -+ " -b, --blockalign=1|2|4 set multiple of eraseblocks to align to\n" -+ " -q, --quiet don't display progress messages\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n"); -+ exit(0); -+} -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "Copyright (C) 2003 Thomas Gleixner \n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} -+ -+char *mtd_device, *img; -+int mtdoffset = 0; -+int quiet = 0; -+int writeoob = 0; -+int markbad = 0; -+int autoplace = 0; -+int forcejffs2 = 0; -+int forceyaffs = 0; -+int forcelegacy = 0; -+int noecc = 0; -+int pad = 0; -+int blockalign = 1; /*default to using 16K block size */ -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "ab:fjmnopqs:y"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"autoplace", no_argument, 0, 'a'}, -+ {"blockalign", required_argument, 0, 'b'}, -+ {"forcelegacy", no_argument, 0, 'f'}, -+ {"jffs2", no_argument, 0, 'j'}, -+ {"markbad", no_argument, 0, 'm'}, -+ {"noecc", no_argument, 0, 'n'}, -+ {"oob", no_argument, 0, 'o'}, -+ {"pad", no_argument, 0, 'p'}, -+ {"quiet", no_argument, 0, 'q'}, -+ {"start", required_argument, 0, 's'}, -+ {"yaffs", no_argument, 0, 'y'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'q': -+ quiet = 1; -+ break; -+ case 'a': -+ autoplace = 1; -+ break; -+ case 'j': -+ forcejffs2 = 1; -+ break; -+ case 'y': -+ forceyaffs = 1; -+ break; -+ case 'f': -+ forcelegacy = 1; -+ break; -+ case 'n': -+ noecc = 1; -+ break; -+ case 'm': -+ markbad = 1; -+ break; -+ case 'o': -+ writeoob = 1; -+ break; -+ case 'p': -+ pad = 1; -+ break; -+ case 's': -+ mtdoffset = strtol (optarg, NULL, 0); -+ break; -+ case 'b': -+ blockalign = atoi (optarg); -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 2 || error) -+ display_help (); -+ -+ mtd_device = argv[optind++]; -+ img = argv[optind]; -+} -+ -+/* -+ * Main program -+ */ -+int main(int argc, char **argv) -+{ -+ int cnt, fd, ifd, imglen = 0, pagelen, baderaseblock, blockstart = -1; -+ struct mtd_info_user meminfo; -+ struct mtd_oob_buf oob; -+ loff_mtd_t offs; -+ int ret, readlen; -+ int oobinfochanged = 0; -+ struct nand_oobinfo old_oobinfo; -+ -+ printf("Warning: nandwrite_mlc instead of nandwrite is used for MLC NAND!\n"); -+ -+ process_options(argc, argv); -+ -+ memset(oobbuf, 0xff, sizeof(oobbuf)); -+ -+ if (pad && writeoob) { -+ fprintf(stderr, "Can't pad when oob data is present.\n"); -+ exit(1); -+ } -+ -+ /* Open the device */ -+ if ((fd = open(mtd_device, O_RDWR)) == -1) { -+ perror("open flash"); -+ exit(1); -+ } -+ -+ /* Fill in MTD device capability structure */ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("MEMGETINFO"); -+ close(fd); -+ exit(1); -+ } -+ -+ /* Set erasesize to specified number of blocks - to match jffs2 -+ * (virtual) block size */ -+ meminfo.erasesize *= blockalign; -+ -+ /* Make sure device page sizes are valid */ -+ if (!(meminfo.oobsize == 16 && meminfo.writesize == 512) && -+ !(meminfo.oobsize == 8 && meminfo.writesize == 256) && -+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) && -+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096)) { -+ fprintf(stderr, "Unknown flash (not normal NAND)\n"); -+ close(fd); -+ exit(1); -+ } -+ -+ if (autoplace) { -+ /* Read the current oob info */ -+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMGETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ -+ // autoplace ECC ? -+ if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) { -+ -+ if (ioctl (fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ oobinfochanged = 1; -+ } -+ } -+ -+ if (noecc) { -+ ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW); -+ if (ret == 0) { -+ oobinfochanged = 2; -+ } else { -+ switch (errno) { -+ case ENOTTY: -+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMGETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ oobinfochanged = 1; -+ break; -+ default: -+ perror ("MTDFILEMODE"); -+ close (fd); -+ exit (1); -+ } -+ } -+ } -+ -+ /* -+ * force oob layout for jffs2 or yaffs ? -+ * Legacy support -+ */ -+ if (forcejffs2 || forceyaffs) { -+ struct nand_oobinfo *oobsel = forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo; -+ -+ if (autoplace) { -+ fprintf(stderr, "Autoplacement is not possible for legacy -j/-y options\n"); -+ goto restoreoob; -+ } -+ if ((old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) && !forcelegacy) { -+ fprintf(stderr, "Use -f option to enforce legacy placement on autoplacement enabled mtd device\n"); -+ goto restoreoob; -+ } -+ if (meminfo.oobsize == 8) { -+ if (forceyaffs) { -+ fprintf (stderr, "YAFSS cannot operate on 256 Byte page size"); -+ goto restoreoob; -+ } -+ /* Adjust number of ecc bytes */ -+ jffs2_oobinfo.eccbytes = 3; -+ } -+ -+ if (ioctl (fd, MEMSETOOBSEL, oobsel) != 0) { -+ perror ("MEMSETOOBSEL"); -+ goto restoreoob; -+ } -+ } -+ -+ oob.length = meminfo.oobsize; -+ oob.ptr = noecc ? oobreadbuf : oobbuf; -+ -+ /* Open the input file */ -+ if ((ifd = open(img, O_RDONLY)) == -1) { -+ perror("open input file"); -+ goto restoreoob; -+ } -+ -+ // get image length -+ imglen = lseek(ifd, 0, SEEK_END); -+ lseek (ifd, 0, SEEK_SET); -+ -+ pagelen = meminfo.writesize + ((writeoob == 1) ? meminfo.oobsize : 0); -+ -+ // Check, if file is pagealigned -+ if ((!pad) && ((imglen % pagelen) != 0)) { -+ fprintf (stderr, "Input file is not page aligned\n"); -+ goto closeall; -+ } -+ -+ // Check, if length fits into device -+ if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) { -+ fprintf (stderr, "Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %llu bytes\n", -+ imglen, pagelen, meminfo.writesize, meminfo.size); -+ perror ("Input file does not fit into device"); -+ goto closeall; -+ } -+ -+ /* Get data from input and write to the device */ -+ while (imglen && (mtdoffset < meminfo.size)) { -+ // new eraseblock , check for bad block(s) -+ // Stay in the loop to be sure if the mtdoffset changes because -+ // of a bad block, that the next block that will be written to -+ // is also checked. Thus avoiding errors if the block(s) after the -+ // skipped block(s) is also bad (number of blocks depending on -+ // the blockalign -+ while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) { -+ blockstart = mtdoffset & (~meminfo.erasesize + 1); -+ offs = blockstart; -+ baderaseblock = 0; -+ if (!quiet) -+ fprintf (stdout, "Writing data to block %x\n", blockstart); -+ -+ /* Check all the blocks in an erase block for bad blocks */ -+ do { -+ if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) { -+ perror("ioctl(MEMGETBADBLOCK)"); -+ goto closeall; -+ } -+ -+ if (ret == 1) { -+ baderaseblock = 1; -+ if (!quiet) -+ fprintf (stderr, "Bad block at %x, %u block(s) " -+ "from %x will be skipped\n", -+ (int) offs, blockalign, blockstart); -+ } -+ -+ if (baderaseblock) { -+ mtdoffset = blockstart + meminfo.erasesize; -+ } -+ offs += meminfo.erasesize / blockalign ; -+ } while ( offs < blockstart + meminfo.erasesize ); -+ -+ } -+ -+ readlen = meminfo.writesize; -+ if (pad && (imglen < readlen)) -+ { -+ readlen = imglen; -+ memset(writebuf + readlen, 0xff, meminfo.writesize - readlen); -+ } -+ -+ /* Read Page Data from input file */ -+ if ((cnt = read(ifd, writebuf, readlen)) != readlen) { -+ if (cnt == 0) // EOF -+ break; -+ perror ("File I/O error on input file"); -+ goto closeall; -+ } -+ -+ if (writeoob) { -+ /* Read OOB data from input file, exit on failure */ -+ if ((cnt = read(ifd, oobreadbuf, meminfo.oobsize)) != meminfo.oobsize) { -+ perror ("File I/O error on input file"); -+ goto closeall; -+ } -+ if (!noecc) { -+ int i, start, len; -+ /* -+ * We use autoplacement and have the oobinfo with the autoplacement -+ * information from the kernel available -+ * -+ * Modified to support out of order oobfree segments, -+ * such as the layout used by diskonchip.c -+ */ -+ if (!oobinfochanged && (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE)) { -+ for (i = 0;old_oobinfo.oobfree[i][1]; i++) { -+ /* Set the reserved bytes to 0xff */ -+ start = old_oobinfo.oobfree[i][0]; -+ len = old_oobinfo.oobfree[i][1]; -+ memcpy(oobbuf + start, -+ oobreadbuf + start, -+ len); -+ } -+ } else { -+ /* Set at least the ecc byte positions to 0xff */ -+ start = old_oobinfo.eccbytes; -+ len = meminfo.oobsize - start; -+ memcpy(oobbuf + start, -+ oobreadbuf + start, -+ len); -+ } -+ } -+ /* Write OOB data first, as ecc will be placed in there*/ -+ oob.start = mtdoffset; -+ if (ioctl(fd, MEMWRITEOOB, &oob) != 0) { -+ perror ("ioctl(MEMWRITEOOB)"); -+ goto closeall; -+ } -+ imglen -= meminfo.oobsize; -+ } -+ -+ /* Write out the Page data */ -+ if (pwrite(fd, writebuf, meminfo.writesize, mtdoffset) != meminfo.writesize) { -+ int rewind_blocks; -+ off_t rewind_bytes; -+ erase_info_t erase; -+ -+ perror ("pwrite"); -+ /* Must rewind to blockstart if we can */ -+ rewind_blocks = (mtdoffset - blockstart) / meminfo.writesize; /* Not including the one we just attempted */ -+ rewind_bytes = (rewind_blocks * meminfo.writesize) + readlen; -+ if (writeoob) -+ rewind_bytes += (rewind_blocks + 1) * meminfo.oobsize; -+ if (lseek(ifd, -rewind_bytes, SEEK_CUR) == -1) { -+ perror("lseek"); -+ fprintf(stderr, "Failed to seek backwards to recover from write error\n"); -+ goto closeall; -+ } -+ erase.start = blockstart; -+ erase.length = meminfo.erasesize; -+ fprintf(stderr, "Erasing failed write from 0x%09llx-0x%09llx\n", -+ erase.start, erase.start+erase.length-1); -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ perror("MEMERASE"); -+ goto closeall; -+ } -+ -+ if (markbad) { -+ loff_mtd_t bad_addr = mtdoffset & (~(meminfo.erasesize / blockalign) + 1); -+ fprintf(stderr, "Marking block at %09llx bad\n", (long long)bad_addr); -+ if (ioctl(fd, MEMSETBADBLOCK, &bad_addr)) { -+ perror("MEMSETBADBLOCK"); -+ /* But continue anyway */ -+ } -+ } -+ mtdoffset = blockstart + meminfo.erasesize; -+ imglen += rewind_blocks * meminfo.writesize; -+ -+ continue; -+ } -+ imglen -= readlen; -+ mtdoffset += meminfo.writesize; -+ } -+ -+closeall: -+ close(ifd); -+ -+restoreoob: -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ } -+ -+ close(fd); -+ -+ if (imglen > 0) { -+ perror ("Data was only partially written due to error\n"); -+ exit (1); -+ } -+ -+ /* Return happy */ -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nandwrite_mlc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nandwrite_mlc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,446 @@ -+/* -+ * nandwrite.c -+ * -+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) -+ * 2003 Thomas Gleixner (tglx@linutronix.de) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Overview: -+ * This utility writes a binary image directly to a NAND flash -+ * chip or NAND chips contained in DoC devices. This is the -+ * "inverse operation" of nanddump. -+ * -+ * tglx: Major rewrite to handle bad blocks, write data with or without ECC -+ * write oob data only on request -+ * -+ * Bug/ToDo: -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "mtd/mtd-user.h" -+ -+#define PROGRAM "nandwrite" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+#define MAX_PAGE_SIZE 8192 -+#define MAX_OOB_SIZE 256 -+/* -+ * Buffer array used for writing data -+ */ -+unsigned char writebuf[MAX_PAGE_SIZE]; -+unsigned char oobreadbuf[MAX_OOB_SIZE]; -+ -+// oob layouts to pass into the kernel as default -+struct nand_oobinfo none_oobinfo = { -+ .useecc = MTD_NANDECC_OFF, -+}; -+ -+struct nand_oobinfo jffs2_oobinfo = { -+ .useecc = MTD_NANDECC_PLACE, -+ .eccbytes = 6, -+ .eccpos = { 0, 1, 2, 3, 6, 7 } -+}; -+ -+struct nand_oobinfo yaffs_oobinfo = { -+ .useecc = MTD_NANDECC_PLACE, -+ .eccbytes = 6, -+ .eccpos = { 8, 9, 10, 13, 14, 15} -+}; -+ -+struct nand_oobinfo autoplace_oobinfo = { -+ .useecc = MTD_NANDECC_AUTOPLACE, -+ .eccbytes = 36 -+}; -+ -+void display_help (void) -+{ -+ printf("Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILE\n" -+ "Writes to the specified MTD device.\n" -+ "\n" -+ " -a, --autoplace Use auto oob layout\n" -+ " -j, --jffs2 force jffs2 oob layout (legacy support)\n" -+ " -y, --yaffs force yaffs oob layout (legacy support)\n" -+ " -f, --forcelegacy force legacy support on autoplacement enabled mtd device\n" -+ " -m, --markbad mark blocks bad if write fails\n" -+ " -n, --noecc write without ecc\n" -+ " -o, --oob image contains oob data\n" -+ " -s addr, --start=addr set start address (default is 0)\n" -+ " -p, --pad pad to page size\n" -+ " -b, --blockalign=1|2|4 set multiple of eraseblocks to align to\n" -+ " -q, --quiet don't display progress messages\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n"); -+ exit(0); -+} -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "Copyright (C) 2003 Thomas Gleixner \n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} -+ -+char *mtd_device, *img; -+unsigned long long mtdoffset = 0; -+int quiet = 0; -+int writeoob = 0; -+int markbad = 1; -+int autoplace = 0; -+int forcejffs2 = 0; -+int forceyaffs = 0; -+int forcelegacy = 0; -+int noecc = 0; -+int pad = 0; -+int blockalign = 1; /*default to using 16K block size */ -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "ab:fjmnopqs:y"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"autoplace", no_argument, 0, 'a'}, -+ {"blockalign", required_argument, 0, 'b'}, -+ {"forcelegacy", no_argument, 0, 'f'}, -+ {"jffs2", no_argument, 0, 'j'}, -+ {"markbad", no_argument, 0, 'm'}, -+ {"noecc", no_argument, 0, 'n'}, -+ {"oob", no_argument, 0, 'o'}, -+ {"pad", no_argument, 0, 'p'}, -+ {"quiet", no_argument, 0, 'q'}, -+ {"start", required_argument, 0, 's'}, -+ {"yaffs", no_argument, 0, 'y'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'q': -+ quiet = 1; -+ break; -+ case 'a': -+ autoplace = 1; -+ break; -+ case 'j': -+ forcejffs2 = 1; -+ break; -+ case 'y': -+ forceyaffs = 1; -+ break; -+ case 'f': -+ forcelegacy = 1; -+ break; -+ case 'n': -+ noecc = 1; -+ break; -+ case 'm': -+ markbad = 1; -+ break; -+ case 'o': -+ writeoob = 1; -+ break; -+ case 'p': -+ pad = 1; -+ break; -+ case 's': -+ mtdoffset = strtol (optarg, NULL, 0); -+ break; -+ case 'b': -+ blockalign = atoi (optarg); -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 2 || error) -+ display_help (); -+ -+ mtd_device = argv[optind++]; -+ img = argv[optind]; -+} -+ -+/* -+ * Main program -+ */ -+int main(int argc, char **argv) -+{ -+ int cnt, fd, ifd, imglen = 0, pagelen, baderaseblock, blockstart = -1; -+ struct mtd_info_user meminfo; -+ struct mtd_page_buf oob; -+ loff_mtd_t offs; -+ int ret, readlen; -+ int oobinfochanged = 0; -+ struct nand_oobinfo old_oobinfo; -+ int i; -+ -+ process_options(argc, argv); -+ -+ if (pad && writeoob) { -+ fprintf(stderr, "Can't pad when oob data is present.\n"); -+ exit(1); -+ } -+ -+ /* Open the device */ -+ if ((fd = open(mtd_device, O_RDWR)) == -1) { -+ perror("open flash"); -+ exit(1); -+ } -+ -+ /* Fill in MTD device capability structure */ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("MEMGETINFO"); -+ close(fd); -+ exit(1); -+ } -+ -+ /* Set erasesize to specified number of blocks - to match jffs2 -+ * (virtual) block size */ -+ meminfo.erasesize *= blockalign; -+ -+ /* Make sure device page sizes are valid */ -+ if (!(meminfo.oobsize == 16 && meminfo.writesize == 512) && -+ !(meminfo.oobsize == 8 && meminfo.writesize == 256) && -+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) && -+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096) && -+ !(meminfo.oobsize == 256 && meminfo.writesize == 8192)) { -+ fprintf(stderr, "Unknown flash (not normal NAND)\n"); -+ close(fd); -+ exit(1); -+ } -+ -+ if (autoplace) { -+ /* Read the current oob info */ -+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMGETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ -+ // autoplace ECC ? -+ if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) { -+ -+ if (ioctl (fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ oobinfochanged = 1; -+ } -+ } -+ -+ memset(oobreadbuf, 0xff, MAX_OOB_SIZE); -+ -+ if (autoplace) { -+ oob.ooblength = meminfo.oobsize-old_oobinfo.eccbytes; /* Get ooblength from kernel */ -+ printf("oobsize=%d eccbytes=%d\n", meminfo.oobsize, old_oobinfo.eccbytes); -+ } else { -+ oob.ooblength = meminfo.oobsize-autoplace_oobinfo.eccbytes; -+ printf("oobsize=%d eccbytes=%d\n", meminfo.oobsize, autoplace_oobinfo.eccbytes); -+ } -+ -+ oob.oobptr = oobreadbuf; -+ oob.datptr = writebuf; -+ -+ /* Open the input file */ -+ if ((ifd = open(img, O_RDONLY)) == -1) { -+ perror("open input file"); -+ goto restoreoob; -+ } -+ -+ // get image length -+ imglen = lseek(ifd, 0, SEEK_END); -+ lseek (ifd, 0, SEEK_SET); -+ -+ pagelen = meminfo.writesize + ((writeoob == 1) ? meminfo.oobsize : 0); -+ -+ // Check, if file is pagealigned -+ if ((!pad) && ((imglen % pagelen) != 0)) { -+ fprintf (stderr, "Input file is not page aligned\n"); -+ goto closeall; -+ } -+ -+ // Check, if length fits into device -+ if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) { -+ fprintf (stderr, "Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %lld bytes\n", -+ imglen, pagelen, meminfo.writesize, meminfo.size); -+ perror ("Input file does not fit into device"); -+ goto closeall; -+ } -+ -+ /* Get data from input and write to the device */ -+ while (imglen && (mtdoffset < meminfo.size)) { -+ // new eraseblock , check for bad block(s) -+ // Stay in the loop to be sure if the mtdoffset changes because -+ // of a bad block, that the next block that will be written to -+ // is also checked. Thus avoiding errors if the block(s) after the -+ // skipped block(s) is also bad (number of blocks depending on -+ // the blockalign -+ while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) { -+ blockstart = mtdoffset & (~meminfo.erasesize + 1); -+ offs = blockstart; -+ baderaseblock = 0; -+ i=0; -+ if (!quiet) -+ fprintf (stdout, "Writing data to block 0x%x\n", blockstart); -+ -+ /* Check all the blocks in an erase block for bad blocks */ -+ do { -+ if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) { -+ perror("ioctl(MEMGETBADBLOCK)"); -+ goto closeall; -+ } -+ if (ret == 1) { -+ baderaseblock = 1; -+ if (!quiet) -+ fprintf (stderr, "Bad block at 0x%llx, %u block(s) " -+ "from 0x%x will be skipped\n", -+ offs, blockalign, blockstart); -+ } -+ -+ if (baderaseblock) { -+ mtdoffset = blockstart + meminfo.erasesize; -+ } -+ offs += meminfo.erasesize / blockalign ; -+ } while ( offs < blockstart + meminfo.erasesize ); -+ -+ } -+ -+ readlen = meminfo.writesize; -+ if (pad && (imglen < readlen)) -+ { -+ readlen = imglen; -+ memset(writebuf + readlen, 0xff, meminfo.writesize - readlen); -+ } -+ -+ /* Read Page Data from input file */ -+ if ((cnt = read(ifd, writebuf, readlen)) != readlen) { -+ if (cnt == 0) // EOF -+ break; -+ perror ("File I/O error 1 on input file"); -+ goto closeall; -+ } -+ -+ /* Read OOB data from input file, exit on failure */ -+ if(writeoob) { -+ if ((cnt = read(ifd, oobreadbuf, meminfo.oobsize)) != meminfo.oobsize) { -+ perror ("File I/O error 2 on input file"); -+ goto closeall; -+ } -+ } -+ oob.start = mtdoffset; -+ -+ // write a page include its oob to nand -+ ioctl(fd, MEMWRITEPAGE, &oob); -+ if(oob.datlength != meminfo.writesize){ -+ perror ("ioctl(MEMWRITEPAGE)"); -+ -+ int rewind_blocks; -+ off_t rewind_bytes; -+ erase_info_t erase; -+ -+ /* Must rewind to blockstart if we can */ -+ rewind_blocks = (mtdoffset - blockstart) / meminfo.writesize; /* Not including the one we just attempted */ -+ rewind_bytes = (rewind_blocks * meminfo.writesize) + readlen; -+ if (writeoob) -+ rewind_bytes += (rewind_blocks + 1) * meminfo.oobsize; -+ if (lseek(ifd, -rewind_bytes, SEEK_CUR) == -1) { -+ perror("lseek"); -+ fprintf(stderr, "Failed to seek backwards to recover from write error\n"); -+ goto closeall; -+ } -+ erase.start = blockstart; -+ erase.length = meminfo.erasesize; -+ fprintf(stderr, "Erasing failed write from 0x%09llx-0x%09llx\n", -+ erase.start, erase.start+erase.length-1); -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ perror("MEMERASE"); -+ goto closeall; -+ } -+ -+ if (markbad) { -+ loff_mtd_t bad_addr = mtdoffset & (~(meminfo.erasesize / blockalign) + 1); -+ fprintf(stderr, "Marking block at %09llx bad\n", (long long)bad_addr); -+ if (ioctl(fd, MEMSETBADBLOCK, &bad_addr)) { -+ perror("MEMSETBADBLOCK"); -+ /* But continue anyway */ -+ } -+ } -+ mtdoffset = blockstart + meminfo.erasesize; -+ imglen += rewind_blocks * meminfo.writesize; -+ -+ continue; -+ } -+ if(writeoob) -+ imglen -= meminfo.oobsize; -+ imglen -= readlen; -+ mtdoffset += meminfo.writesize; -+ } -+ -+closeall: -+ close(ifd); -+ -+restoreoob: -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ } -+ -+ close(fd); -+ -+ if (imglen > 0) { -+ perror ("Data was only partially written due to error\n"); -+ exit (1); -+ } -+ -+ /* Return happy */ -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nftl_format.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nftl_format.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,419 @@ -+/* -+ * nftl_format.c: Creating a NFTL/INFTL partition on an MTD device -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * ToDo: -+ * 1. UnitSizeFactor != 0xFF cases -+ * 2. test, test, and test !!! -+ */ -+ -+#define _XOPEN_SOURCE 500 /* for pread/pwrite */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+unsigned char BadUnitTable[MAX_ERASE_ZONES]; -+unsigned char *readbuf; -+unsigned char *writebuf[4]; -+ -+mtd_info_t meminfo; -+erase_info_t erase; -+int fd; -+struct NFTLMediaHeader *NFTLhdr; -+struct INFTLMediaHeader *INFTLhdr; -+ -+static int do_oobcheck = 1; -+static int do_rwecheck = 1; -+ -+static unsigned char check_block_1(unsigned long block) -+{ -+ unsigned char oobbuf[16]; -+ struct mtd_oob_buf oob = { 0, 16, oobbuf }; -+ -+ oob.start = block * meminfo.erasesize; -+ if (ioctl(fd, MEMREADOOB, &oob)) -+ return ZONE_BAD_ORIGINAL; -+ -+ if(oobbuf[5] == 0) -+ return ZONE_BAD_ORIGINAL; -+ -+ oob.start = block * meminfo.erasesize + 512 /* FIXME */; -+ if (ioctl(fd, MEMREADOOB, &oob)) -+ return ZONE_BAD_ORIGINAL; -+ -+ if(oobbuf[5] == 0) -+ return ZONE_BAD_ORIGINAL; -+ -+ return ZONE_GOOD; -+} -+ -+static unsigned char check_block_2(unsigned long block) -+{ -+ unsigned long ofs = block * meminfo.erasesize; -+ unsigned long blockofs; -+ -+ /* Erase test */ -+ erase.start = ofs; -+ -+ for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) { -+ pread(fd, readbuf, 512, ofs + blockofs); -+ if (memcmp(readbuf, writebuf[0], 512)) { -+ /* Block wasn't 0xff after erase */ -+ printf(": Block not 0xff after erase\n"); -+ return ZONE_BAD_ORIGINAL; -+ } -+ -+ pwrite(fd, writebuf[1], 512, blockofs + ofs); -+ pread(fd, readbuf, 512, blockofs + ofs); -+ if (memcmp(readbuf, writebuf[1], 512)) { -+ printf(": Block not zero after clearing\n"); -+ return ZONE_BAD_ORIGINAL; -+ } -+ } -+ -+ /* Write test */ -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ printf(": Second erase failed (%s)\n", strerror(errno)); -+ return ZONE_BAD_ORIGINAL; -+ } -+ for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) { -+ pwrite(fd, writebuf[2], 512, blockofs + ofs); -+ pread(fd, readbuf, 512, blockofs + ofs); -+ if (memcmp(readbuf, writebuf[2], 512)) { -+ printf(": Block not 0x5a after writing\n"); -+ return ZONE_BAD_ORIGINAL; -+ } -+ } -+ -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ printf(": Third erase failed (%s)\n", strerror(errno)); -+ return ZONE_BAD_ORIGINAL; -+ } -+ for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) { -+ pwrite(fd, writebuf[3], 512, blockofs + ofs); -+ pread(fd, readbuf, 512, blockofs + ofs); -+ if (memcmp(readbuf, writebuf[3], 512)) { -+ printf(": Block not 0xa5 after writing\n"); -+ return ZONE_BAD_ORIGINAL; -+ } -+ } -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ printf(": Fourth erase failed (%s)\n", strerror(errno)); -+ return ZONE_BAD_ORIGINAL; -+ } -+ return ZONE_GOOD; -+} -+ -+static unsigned char erase_block(unsigned long block) -+{ -+ unsigned char status; -+ int ret; -+ -+ status = (do_oobcheck) ? check_block_1(block) : ZONE_GOOD; -+ erase.start = block * meminfo.erasesize; -+ -+ if (status != ZONE_GOOD) { -+ printf("\rSkipping bad zone (factory marked) #%ld @ 0x%x\n", block, erase.start); -+ fflush(stdout); -+ return status; -+ } -+ -+ printf("\r\t Erasing Zone #%ld @ 0x%x", block, erase.start); -+ fflush(stdout); -+ -+ if ((ret=ioctl(fd, MEMERASE, &erase)) != 0) { -+ printf(": Erase failed (%s)\n", strerror(errno)); -+ return ZONE_BAD_ORIGINAL; -+ } -+ -+ if (do_rwecheck) { -+ printf("\r\tChecking Zone #%ld @ 0x%x", block, erase.start); -+ fflush(stdout); -+ status = check_block_2(block); -+ if (status != ZONE_GOOD) { -+ printf("\rSkipping bad zone (RWE test failed) #%ld @ 0x%x\n", block, erase.start); -+ fflush(stdout); -+ } -+ } -+ return status; -+} -+ -+static int checkbbt(void) -+{ -+ unsigned char bbt[512]; -+ unsigned char bits; -+ int i, addr; -+ -+ if (pread(fd, bbt, 512, 0x800) < 0) { -+ printf("nftl_format: failed to read BBT, errno=%d\n", errno); -+ return (-1); -+ } -+ -+ -+ for (i = 0; (i < 512); i++) { -+ addr = i / 4; -+ bits = 0x3 << ((i % 4) * 2); -+ if ((bbt[addr] & bits) == 0) { -+ BadUnitTable[i] = ZONE_BAD_ORIGINAL; -+ } -+ } -+ -+ return (0); -+} -+ -+void usage(int rc) -+{ -+ fprintf(stderr, "Usage: nftl_format [-ib] [ []]\n"); -+ exit(rc); -+} -+ -+int main(int argc, char **argv) -+{ -+ unsigned long startofs = 0, part_size = 0; -+ unsigned long ezones = 0, ezone = 0, bad_zones = 0; -+ unsigned char unit_factor = 0xFF; -+ long MediaUnit1 = -1, MediaUnit2 = -1; -+ long MediaUnitOff1 = 0, MediaUnitOff2 = 0; -+ unsigned char oobbuf[16]; -+ struct mtd_oob_buf oob = {0, 16, oobbuf}; -+ char *mtddevice, *nftl; -+ int c, do_inftl = 0, do_bbt = 0; -+ -+ -+ printf("version 1.24 2005/11/07 11:15:13 gleixner\n"); -+ -+ if (argc < 2) -+ usage(1); -+ -+ nftl = "NFTL"; -+ -+ while ((c = getopt(argc, argv, "?hib")) > 0) { -+ switch (c) { -+ case 'i': -+ nftl = "INFTL"; -+ do_inftl = 1; -+ break; -+ case 'b': -+ do_bbt = 1; -+ break; -+ case 'h': -+ case '?': -+ usage(0); -+ break; -+ default: -+ usage(1); -+ break; -+ } -+ } -+ -+ mtddevice = argv[optind++]; -+ if (argc > optind) { -+ startofs = strtoul(argv[optind++], NULL, 0); -+ } -+ if (argc > optind) { -+ part_size = strtoul(argv[optind++], NULL, 0); -+ } -+ -+ // Open and size the device -+ if ((fd = open(mtddevice, O_RDWR)) < 0) { -+ perror("Open flash device"); -+ return 1; -+ } -+ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("ioctl(MEMGETINFO)"); -+ close(fd); -+ return 1; -+ } -+ -+ switch (meminfo.erasesize) { -+ case 0x1000: -+ case 0x2000: -+ case 0x4000: -+ case 0x8000: -+ break; -+ default: -+ printf("Unrecognized Erase size, 0x%x - I'm confused\n", -+ meminfo.erasesize); -+ close(fd); -+ return 1; -+ } -+ writebuf[0] = malloc(meminfo.erasesize * 5); -+ if (!writebuf[0]) { -+ printf("Malloc failed\n"); -+ close(fd); -+ return 1; -+ } -+ writebuf[1] = writebuf[0] + meminfo.erasesize; -+ writebuf[2] = writebuf[1] + meminfo.erasesize; -+ writebuf[3] = writebuf[2] + meminfo.erasesize; -+ readbuf = writebuf[3] + meminfo.erasesize; -+ memset(writebuf[0], 0xff, meminfo.erasesize); -+ memset(writebuf[1], 0x00, meminfo.erasesize); -+ memset(writebuf[2], 0x5a, meminfo.erasesize); -+ memset(writebuf[3], 0xa5, meminfo.erasesize); -+ memset(BadUnitTable, ZONE_GOOD, MAX_ERASE_ZONES); -+ -+ if (part_size == 0 || (part_size > meminfo.size - startofs)) -+ /* the user doest not or incorrectly specify NFTL partition size */ -+ part_size = meminfo.size - startofs; -+ -+ erase.length = meminfo.erasesize; -+ ezones = part_size / meminfo.erasesize; -+ -+ if (ezones > MAX_ERASE_ZONES) { -+ /* Ought to change the UnitSizeFactor. But later. */ -+ part_size = meminfo.erasesize * MAX_ERASE_ZONES; -+ ezones = MAX_ERASE_ZONES; -+ unit_factor = 0xFF; -+ } -+ -+ /* If using device BBT then parse that now */ -+ if (do_bbt) { -+ checkbbt(); -+ do_oobcheck = 0; -+ do_rwecheck = 0; -+ } -+ -+ /* Phase 1. Erasing and checking each erase zones in the NFTL partition. -+ N.B. Erase Zones not used by the NFTL partition are untouched and marked ZONE_GOOD */ -+ printf("Phase 1. Checking and erasing Erase Zones from 0x%08lx to 0x%08lx\n", -+ startofs, startofs + part_size); -+ for (ezone = startofs / meminfo.erasesize; -+ ezone < (ezones + startofs / meminfo.erasesize); ezone++) { -+ if (BadUnitTable[ezone] != ZONE_GOOD) -+ continue; -+ if ((BadUnitTable[ezone] = erase_block(ezone)) == ZONE_GOOD) { -+ if (MediaUnit1 == -1) { -+ MediaUnit1 = ezone; -+ } else if (MediaUnit2 == -1) { -+ MediaUnit2 = ezone; -+ } -+ } else { -+ bad_zones++; -+ } -+ } -+ printf("\n"); -+ -+ /* N.B. from dump of M-System original chips, NumEraseUnits counts the 2 Erase Unit used -+ by MediaHeader and the FirstPhysicalEUN starts from the MediaHeader */ -+ if (do_inftl) { -+ unsigned long maxzones, pezstart, pezend, numvunits; -+ -+ INFTLhdr = (struct INFTLMediaHeader *) (writebuf[0]); -+ strcpy(INFTLhdr->bootRecordID, "BNAND"); -+ INFTLhdr->NoOfBootImageBlocks = cpu_to_le32(0); -+ INFTLhdr->NoOfBinaryPartitions = cpu_to_le32(0); -+ INFTLhdr->NoOfBDTLPartitions = cpu_to_le32(1); -+ INFTLhdr->BlockMultiplierBits = cpu_to_le32(0); -+ INFTLhdr->FormatFlags = cpu_to_le32(0); -+ INFTLhdr->OsakVersion = cpu_to_le32(OSAK_VERSION); -+ INFTLhdr->PercentUsed = cpu_to_le32(PERCENTUSED); -+ /* -+ * Calculate number of virtual units we will have to work -+ * with. I am calculating out the known bad units here, not -+ * sure if that is what M-Systems do... -+ */ -+ MediaUnit2 = MediaUnit1; -+ MediaUnitOff2 = 4096; -+ maxzones = meminfo.size / meminfo.erasesize; -+ pezstart = startofs / meminfo.erasesize + 1; -+ pezend = startofs / meminfo.erasesize + ezones - 1; -+ numvunits = (ezones - 2) * PERCENTUSED / 100; -+ for (ezone = pezstart; ezone < maxzones; ezone++) { -+ if (BadUnitTable[ezone] != ZONE_GOOD) { -+ if (numvunits > 1) -+ numvunits--; -+ } -+ } -+ -+ INFTLhdr->Partitions[0].virtualUnits = cpu_to_le32(numvunits); -+ INFTLhdr->Partitions[0].firstUnit = cpu_to_le32(pezstart); -+ INFTLhdr->Partitions[0].lastUnit = cpu_to_le32(pezend); -+ INFTLhdr->Partitions[0].flags = cpu_to_le32(INFTL_BDTL); -+ INFTLhdr->Partitions[0].spareUnits = cpu_to_le32(0); -+ INFTLhdr->Partitions[0].Reserved0 = INFTLhdr->Partitions[0].firstUnit; -+ INFTLhdr->Partitions[0].Reserved1 = cpu_to_le32(0); -+ -+ } else { -+ -+ NFTLhdr = (struct NFTLMediaHeader *) (writebuf[0]); -+ strcpy(NFTLhdr->DataOrgID, "ANAND"); -+ NFTLhdr->NumEraseUnits = cpu_to_le16(part_size / meminfo.erasesize); -+ NFTLhdr->FirstPhysicalEUN = cpu_to_le16(MediaUnit1); -+ /* N.B. we reserve 2 more Erase Units for "folding" of Virtual Unit Chain */ -+ NFTLhdr->FormattedSize = cpu_to_le32(part_size - ( (5+bad_zones) * meminfo.erasesize)); -+ NFTLhdr->UnitSizeFactor = unit_factor; -+ } -+ -+ /* Phase 2. Writing NFTL Media Headers and Bad Unit Table */ -+ printf("Phase 2.a Writing %s Media Header and Bad Unit Table\n", nftl); -+ pwrite(fd, writebuf[0], 512, MediaUnit1 * meminfo.erasesize + MediaUnitOff1); -+ for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) { -+ pwrite(fd, BadUnitTable + ezone, 512, -+ (MediaUnit1 * meminfo.erasesize) + 512 * (1 + ezone / 512)); -+ } -+ -+#if 0 -+ printf(" MediaHeader contents:\n"); -+ printf(" NumEraseUnits: %d\n", le16_to_cpu(NFTLhdr->NumEraseUnits)); -+ printf(" FirstPhysicalEUN: %d\n", le16_to_cpu(NFTLhdr->FirstPhysicalEUN)); -+ printf(" FormattedSize: %d (%d sectors)\n", le32_to_cpu(NFTLhdr->FormattedSize), -+ le32_to_cpu(NFTLhdr->FormattedSize)/512); -+#endif -+ printf("Phase 2.b Writing Spare %s Media Header and Spare Bad Unit Table\n", nftl); -+ pwrite(fd, writebuf[0], 512, MediaUnit2 * meminfo.erasesize + MediaUnitOff2); -+ for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) { -+ pwrite(fd, BadUnitTable + ezone, 512, -+ (MediaUnit2 * meminfo.erasesize + MediaUnitOff2) + 512 * (1 + ezone / 512)); -+ } -+ -+ /* UCI #1 for newly erased Erase Unit */ -+ memset(oobbuf, 0xff, 16); -+ oobbuf[11] = oobbuf[10] = oobbuf[9] = 0; -+ oobbuf[8] = (do_inftl) ? 0x00 : 0x03; -+ oobbuf[12] = oobbuf[14] = 0x69; -+ oobbuf[13] = oobbuf[15] = 0x3c; -+ -+ /* N.B. The Media Header and Bad Erase Unit Table are considered as Free Erase Unit -+ by M-System i.e. their Virtual Unit Number == 0xFFFF in the Unit Control Information #0, -+ but their Block Status is BLOCK_USED (0x5555) in their Block Control Information */ -+ /* Phase 3. Writing Unit Control Information for each Erase Unit */ -+ printf("Phase 3. Writing Unit Control Information to each Erase Unit\n"); -+ for (ezone = MediaUnit1; ezone < (ezones + startofs / meminfo.erasesize); ezone++) { -+ /* write UCI #1 to each Erase Unit */ -+ if (BadUnitTable[ezone] != ZONE_GOOD) -+ continue; -+ oob.start = (ezone * meminfo.erasesize) + 512 + (do_inftl * 512); -+ if (ioctl(fd, MEMWRITEOOB, &oob)) -+ printf("MEMWRITEOOB at %lx: %s\n", (unsigned long)oob.start, strerror(errno)); -+ } -+ -+ exit(0); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nftldump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nftldump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,281 @@ -+/* -+ * nftldump.c: Dumping the content of NFTL partitions on a "Physical Disk" -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * ToDo: -+ * 1. UnitSizeFactor != 0xFF cases -+ * 2. test, test, and test !!! -+ */ -+ -+#define _XOPEN_SOURCE 500 /* For pread */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+static struct NFTLMediaHeader MedHead[2]; -+static mtd_info_t meminfo; -+ -+static struct nftl_oob oobbuf; -+static struct mtd_oob_buf oob = {0, 16, (unsigned char *)&oobbuf}; -+ -+static int fd, ofd = -1;; -+static int NumMedHeads; -+ -+static unsigned char BadUnitTable[MAX_ERASE_ZONES]; -+ -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+#define SWAP16(x) do { ; } while(0) -+#define SWAP32(x) do { ; } while(0) -+#else -+#define SWAP16(x) do { x = swab16(x); } while(0) -+#define SWAP32(x) do { x = swab32(x); } while(0) -+#endif -+ -+/* VUCtable, store the Erase Unit Number of the first Erase Unit in the chain */ -+static unsigned short *VUCtable; -+ -+/* FixMe: make this dynamic allocated */ -+#define ERASESIZE 0x2000 -+#define NUMVUNITS ((40*1024*1024) / ERASESIZE) -+static union nftl_uci UCItable[NUMVUNITS][3]; -+ -+static unsigned short nextEUN(unsigned short curEUN) -+{ -+ return UCItable[curEUN][0].a.ReplUnitNum; -+} -+ -+static unsigned int find_media_headers(void) -+{ -+ int i; -+ static unsigned long ofs = 0; -+ -+ NumMedHeads = 0; -+ while (ofs < meminfo.size) { -+ pread(fd, &MedHead[NumMedHeads], sizeof(struct NFTLMediaHeader), ofs); -+ if (!strncmp(MedHead[NumMedHeads].DataOrgID, "ANAND", 6)) { -+ SWAP16(MedHead[NumMedHeads].NumEraseUnits); -+ SWAP16(MedHead[NumMedHeads].FirstPhysicalEUN); -+ SWAP32(MedHead[NumMedHeads].FormattedSize); -+ -+ if (NumMedHeads == 0) { -+ printf("NFTL Media Header found at offset 0x%08lx:\n", ofs); -+ printf("NumEraseUnits: %d\n", -+ MedHead[NumMedHeads].NumEraseUnits); -+ printf("FirstPhysicalEUN: %d\n", -+ MedHead[NumMedHeads].FirstPhysicalEUN); -+ printf("Formatted Size: %d\n", -+ MedHead[NumMedHeads].FormattedSize); -+ printf("UnitSizeFactor: 0x%x\n", -+ MedHead[NumMedHeads].UnitSizeFactor); -+ -+ /* read BadUnitTable, I don't know why pread() does not work for -+ larger (7680 bytes) chunks */ -+ for (i = 0; i < MAX_ERASE_ZONES; i += 512) -+ pread(fd, &BadUnitTable[i], 512, ofs + 512 + i); -+ } else -+ printf("Second NFTL Media Header found at offset 0x%08lx\n",ofs); -+ NumMedHeads++; -+ } -+ -+ ofs += meminfo.erasesize; -+ if (NumMedHeads == 2) { -+ if (strncmp((char *)&MedHead[0], (char *)&MedHead[1], sizeof(struct NFTLMediaHeader)) != 0) { -+ printf("warning: NFTL Media Header is not consistent with " -+ "Spare NFTL Media Header\n"); -+ } -+ break; -+ } -+ } -+ -+ /* allocate Virtual Unit Chain table for this NFTL partition */ -+ VUCtable = calloc(MedHead[0].NumEraseUnits, sizeof(unsigned short)); -+ return NumMedHeads; -+} -+ -+static void dump_erase_units(void) -+{ -+ int i, j; -+ unsigned long ofs; -+ -+ for (i = MedHead[0].FirstPhysicalEUN; i < MedHead[0].FirstPhysicalEUN + -+ MedHead[0].NumEraseUnits; i++) { -+ /* For each Erase Unit */ -+ ofs = i * meminfo.erasesize; -+ -+ /* read the Unit Control Information */ -+ for (j = 0; j < 3; j++) { -+ oob.start = ofs + (j * 512); -+ if (ioctl(fd, MEMREADOOB, &oob)) -+ printf("MEMREADOOB at %lx: %s\n", -+ (unsigned long) oob.start, strerror(errno)); -+ memcpy(&UCItable[i][j], &oobbuf.u, 8); -+ } -+ if (UCItable[i][1].b.EraseMark != cpu_to_le16(0x3c69)) { -+ printf("EraseMark not present in unit %d: %x\n", -+ i, UCItable[i][1].b.EraseMark); -+ } else { -+ /* a properly formatted unit */ -+ SWAP16(UCItable[i][0].a.VirtUnitNum); -+ SWAP16(UCItable[i][0].a.ReplUnitNum); -+ SWAP16(UCItable[i][0].a.SpareVirtUnitNum); -+ SWAP16(UCItable[i][0].a.SpareReplUnitNum); -+ SWAP32(UCItable[i][1].b.WearInfo); -+ SWAP16(UCItable[i][1].b.EraseMark); -+ SWAP16(UCItable[i][1].b.EraseMark1); -+ SWAP16(UCItable[i][2].c.FoldMark); -+ SWAP16(UCItable[i][2].c.FoldMark1); -+ -+ if (!(UCItable[i][0].a.VirtUnitNum & 0x8000)) { -+ /* If this is the first in a chain, store the EUN in the VUC table */ -+ if (VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]) { -+ printf("Duplicate start of chain for VUC %d: " -+ "Unit %d replaces Unit %d\n", -+ UCItable[i][0].a.VirtUnitNum & 0x7fff, -+ i, VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]); -+ } -+ VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff] = i; -+ } -+ } -+ -+ switch (BadUnitTable[i]) { -+ case ZONE_BAD_ORIGINAL: -+ printf("Unit %d is marked as ZONE_BAD_ORIGINAL\n", i); -+ continue; -+ case ZONE_BAD_MARKED: -+ printf("Unit %d is marked as ZONE_BAD_MARKED\n", i); -+ continue; -+ } -+ -+ /* ZONE_GOOD */ -+ if (UCItable[i][0].a.VirtUnitNum == 0xffff) -+ printf("Unit %d is free\n", i); -+ else -+ printf("Unit %d is in chain %d and %s a replacement\n", i, -+ UCItable[i][0].a.VirtUnitNum & 0x7fff, -+ UCItable[i][0].a.VirtUnitNum & 0x8000 ? "is" : "is not"); -+ } -+} -+ -+static void dump_virtual_units(void) -+{ -+ int i, j; -+ char readbuf[512]; -+ -+ for (i = 0; i < (MedHead[0].FormattedSize / meminfo.erasesize); i++) { -+ unsigned short curEUN = VUCtable[i]; -+ -+ printf("Virtual Unit #%d: ", i); -+ if (!curEUN) { -+ printf("Not present\n"); -+ continue; -+ } -+ printf("%d", curEUN); -+ -+ /* walk through the Virtual Unit Chain */ -+ while ((curEUN = nextEUN(curEUN)) != 0xffff) { -+ printf(", %d", curEUN & 0x7fff); -+ } -+ printf("\n"); -+ -+ if (ofd != -1) { -+ /* Actually write out the data */ -+ for (j = 0; j < meminfo.erasesize / 512; j++) { -+ /* For each sector in the block */ -+ unsigned short lastgoodEUN = 0xffff, thisEUN = VUCtable[i]; -+ unsigned int status; -+ -+ if (thisEUN == 0xffff) thisEUN = 0; -+ -+ while (thisEUN && (thisEUN & 0x7fff) != 0x7fff) { -+ oob.start = (thisEUN * ERASESIZE) + (j * 512); -+ ioctl(fd, MEMREADOOB, &oob); -+ status = oobbuf.b.Status | oobbuf.b.Status1; -+ -+ switch (status) { -+ case SECTOR_FREE: -+ /* This is still free. Don't look any more */ -+ thisEUN = 0; -+ break; -+ -+ case SECTOR_USED: -+ /* SECTOR_USED. This is a good one. */ -+ lastgoodEUN = thisEUN; -+ break; -+ } -+ -+ /* Find the next erase unit in this chain, if any */ -+ if (thisEUN) -+ thisEUN = nextEUN(thisEUN) & 0x7fff; -+ } -+ -+ if (lastgoodEUN == 0xffff) -+ memset(readbuf, 0, 512); -+ else -+ pread(fd, readbuf, 512, -+ (lastgoodEUN * ERASESIZE) + (j * 512)); -+ -+ write(ofd, readbuf, 512); -+ } -+ -+ } -+ } -+} -+ -+int main(int argc, char **argv) -+{ -+ if (argc < 2) { -+ printf("Usage: %s []\n", argv[0]); -+ exit(1); -+ } -+ fd = open(argv[1], O_RDONLY); -+ if (fd == -1) { -+ perror("open flash"); -+ exit (1); -+ } -+ -+ if (argc > 2) { -+ ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644); -+ if (ofd == -1) -+ perror ("open outfile"); -+ } -+ -+ /* get size information of the MTD device */ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("ioctl(MEMGETINFO)"); -+ close(fd); -+ return 1; -+ } -+ -+ while (find_media_headers() != 0) { -+ dump_erase_units(); -+ dump_virtual_units(); -+ free(VUCtable); -+ } -+ -+ exit(0); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/rbtree.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/rbtree.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,390 @@ -+/* -+ Red Black Trees -+ (C) 1999 Andrea Arcangeli -+ (C) 2002 David Woodhouse -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ linux/lib/rbtree.c -+*/ -+ -+#include -+#include "rbtree.h" -+ -+static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) -+{ -+ struct rb_node *right = node->rb_right; -+ struct rb_node *parent = rb_parent(node); -+ -+ if ((node->rb_right = right->rb_left)) -+ rb_set_parent(right->rb_left, node); -+ right->rb_left = node; -+ -+ rb_set_parent(right, parent); -+ -+ if (parent) -+ { -+ if (node == parent->rb_left) -+ parent->rb_left = right; -+ else -+ parent->rb_right = right; -+ } -+ else -+ root->rb_node = right; -+ rb_set_parent(node, right); -+} -+ -+static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) -+{ -+ struct rb_node *left = node->rb_left; -+ struct rb_node *parent = rb_parent(node); -+ -+ if ((node->rb_left = left->rb_right)) -+ rb_set_parent(left->rb_right, node); -+ left->rb_right = node; -+ -+ rb_set_parent(left, parent); -+ -+ if (parent) -+ { -+ if (node == parent->rb_right) -+ parent->rb_right = left; -+ else -+ parent->rb_left = left; -+ } -+ else -+ root->rb_node = left; -+ rb_set_parent(node, left); -+} -+ -+void rb_insert_color(struct rb_node *node, struct rb_root *root) -+{ -+ struct rb_node *parent, *gparent; -+ -+ while ((parent = rb_parent(node)) && rb_is_red(parent)) -+ { -+ gparent = rb_parent(parent); -+ -+ if (parent == gparent->rb_left) -+ { -+ { -+ register struct rb_node *uncle = gparent->rb_right; -+ if (uncle && rb_is_red(uncle)) -+ { -+ rb_set_black(uncle); -+ rb_set_black(parent); -+ rb_set_red(gparent); -+ node = gparent; -+ continue; -+ } -+ } -+ -+ if (parent->rb_right == node) -+ { -+ register struct rb_node *tmp; -+ __rb_rotate_left(parent, root); -+ tmp = parent; -+ parent = node; -+ node = tmp; -+ } -+ -+ rb_set_black(parent); -+ rb_set_red(gparent); -+ __rb_rotate_right(gparent, root); -+ } else { -+ { -+ register struct rb_node *uncle = gparent->rb_left; -+ if (uncle && rb_is_red(uncle)) -+ { -+ rb_set_black(uncle); -+ rb_set_black(parent); -+ rb_set_red(gparent); -+ node = gparent; -+ continue; -+ } -+ } -+ -+ if (parent->rb_left == node) -+ { -+ register struct rb_node *tmp; -+ __rb_rotate_right(parent, root); -+ tmp = parent; -+ parent = node; -+ node = tmp; -+ } -+ -+ rb_set_black(parent); -+ rb_set_red(gparent); -+ __rb_rotate_left(gparent, root); -+ } -+ } -+ -+ rb_set_black(root->rb_node); -+} -+ -+static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, -+ struct rb_root *root) -+{ -+ struct rb_node *other; -+ -+ while ((!node || rb_is_black(node)) && node != root->rb_node) -+ { -+ if (parent->rb_left == node) -+ { -+ other = parent->rb_right; -+ if (rb_is_red(other)) -+ { -+ rb_set_black(other); -+ rb_set_red(parent); -+ __rb_rotate_left(parent, root); -+ other = parent->rb_right; -+ } -+ if ((!other->rb_left || rb_is_black(other->rb_left)) && -+ (!other->rb_right || rb_is_black(other->rb_right))) -+ { -+ rb_set_red(other); -+ node = parent; -+ parent = rb_parent(node); -+ } -+ else -+ { -+ if (!other->rb_right || rb_is_black(other->rb_right)) -+ { -+ struct rb_node *o_left; -+ if ((o_left = other->rb_left)) -+ rb_set_black(o_left); -+ rb_set_red(other); -+ __rb_rotate_right(other, root); -+ other = parent->rb_right; -+ } -+ rb_set_color(other, rb_color(parent)); -+ rb_set_black(parent); -+ if (other->rb_right) -+ rb_set_black(other->rb_right); -+ __rb_rotate_left(parent, root); -+ node = root->rb_node; -+ break; -+ } -+ } -+ else -+ { -+ other = parent->rb_left; -+ if (rb_is_red(other)) -+ { -+ rb_set_black(other); -+ rb_set_red(parent); -+ __rb_rotate_right(parent, root); -+ other = parent->rb_left; -+ } -+ if ((!other->rb_left || rb_is_black(other->rb_left)) && -+ (!other->rb_right || rb_is_black(other->rb_right))) -+ { -+ rb_set_red(other); -+ node = parent; -+ parent = rb_parent(node); -+ } -+ else -+ { -+ if (!other->rb_left || rb_is_black(other->rb_left)) -+ { -+ register struct rb_node *o_right; -+ if ((o_right = other->rb_right)) -+ rb_set_black(o_right); -+ rb_set_red(other); -+ __rb_rotate_left(other, root); -+ other = parent->rb_left; -+ } -+ rb_set_color(other, rb_color(parent)); -+ rb_set_black(parent); -+ if (other->rb_left) -+ rb_set_black(other->rb_left); -+ __rb_rotate_right(parent, root); -+ node = root->rb_node; -+ break; -+ } -+ } -+ } -+ if (node) -+ rb_set_black(node); -+} -+ -+void rb_erase(struct rb_node *node, struct rb_root *root) -+{ -+ struct rb_node *child, *parent; -+ int color; -+ -+ if (!node->rb_left) -+ child = node->rb_right; -+ else if (!node->rb_right) -+ child = node->rb_left; -+ else -+ { -+ struct rb_node *old = node, *left; -+ -+ node = node->rb_right; -+ while ((left = node->rb_left) != NULL) -+ node = left; -+ child = node->rb_right; -+ parent = rb_parent(node); -+ color = rb_color(node); -+ -+ if (child) -+ rb_set_parent(child, parent); -+ if (parent == old) { -+ parent->rb_right = child; -+ parent = node; -+ } else -+ parent->rb_left = child; -+ -+ node->rb_parent_color = old->rb_parent_color; -+ node->rb_right = old->rb_right; -+ node->rb_left = old->rb_left; -+ -+ if (rb_parent(old)) -+ { -+ if (rb_parent(old)->rb_left == old) -+ rb_parent(old)->rb_left = node; -+ else -+ rb_parent(old)->rb_right = node; -+ } else -+ root->rb_node = node; -+ -+ rb_set_parent(old->rb_left, node); -+ if (old->rb_right) -+ rb_set_parent(old->rb_right, node); -+ goto color; -+ } -+ -+ parent = rb_parent(node); -+ color = rb_color(node); -+ -+ if (child) -+ rb_set_parent(child, parent); -+ if (parent) -+ { -+ if (parent->rb_left == node) -+ parent->rb_left = child; -+ else -+ parent->rb_right = child; -+ } -+ else -+ root->rb_node = child; -+ -+ color: -+ if (color == RB_BLACK) -+ __rb_erase_color(child, parent, root); -+} -+ -+/* -+ * This function returns the first node (in sort order) of the tree. -+ */ -+struct rb_node *rb_first(struct rb_root *root) -+{ -+ struct rb_node *n; -+ -+ n = root->rb_node; -+ if (!n) -+ return NULL; -+ while (n->rb_left) -+ n = n->rb_left; -+ return n; -+} -+ -+struct rb_node *rb_last(struct rb_root *root) -+{ -+ struct rb_node *n; -+ -+ n = root->rb_node; -+ if (!n) -+ return NULL; -+ while (n->rb_right) -+ n = n->rb_right; -+ return n; -+} -+ -+struct rb_node *rb_next(struct rb_node *node) -+{ -+ struct rb_node *parent; -+ -+ if (rb_parent(node) == node) -+ return NULL; -+ -+ /* If we have a right-hand child, go down and then left as far -+ as we can. */ -+ if (node->rb_right) { -+ node = node->rb_right; -+ while (node->rb_left) -+ node=node->rb_left; -+ return node; -+ } -+ -+ /* No right-hand children. Everything down and left is -+ smaller than us, so any 'next' node must be in the general -+ direction of our parent. Go up the tree; any time the -+ ancestor is a right-hand child of its parent, keep going -+ up. First time it's a left-hand child of its parent, said -+ parent is our 'next' node. */ -+ while ((parent = rb_parent(node)) && node == parent->rb_right) -+ node = parent; -+ -+ return parent; -+} -+ -+struct rb_node *rb_prev(struct rb_node *node) -+{ -+ struct rb_node *parent; -+ -+ if (rb_parent(node) == node) -+ return NULL; -+ -+ /* If we have a left-hand child, go down and then right as far -+ as we can. */ -+ if (node->rb_left) { -+ node = node->rb_left; -+ while (node->rb_right) -+ node=node->rb_right; -+ return node; -+ } -+ -+ /* No left-hand children. Go up till we find an ancestor which -+ is a right-hand child of its parent */ -+ while ((parent = rb_parent(node)) && node == parent->rb_left) -+ node = parent; -+ -+ return parent; -+} -+ -+void rb_replace_node(struct rb_node *victim, struct rb_node *new, -+ struct rb_root *root) -+{ -+ struct rb_node *parent = rb_parent(victim); -+ -+ /* Set the surrounding nodes to point to the replacement */ -+ if (parent) { -+ if (victim == parent->rb_left) -+ parent->rb_left = new; -+ else -+ parent->rb_right = new; -+ } else { -+ root->rb_node = new; -+ } -+ if (victim->rb_left) -+ rb_set_parent(victim->rb_left, new); -+ if (victim->rb_right) -+ rb_set_parent(victim->rb_right, new); -+ -+ /* Copy the pointers/colour from the victim to the replacement */ -+ *new = *victim; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/rbtree.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/rbtree.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,168 @@ -+/* -+ Red Black Trees -+ (C) 1999 Andrea Arcangeli -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ linux/include/linux/rbtree.h -+ -+ To use rbtrees you'll have to implement your own insert and search cores. -+ This will avoid us to use callbacks and to drop drammatically performances. -+ I know it's not the cleaner way, but in C (not in C++) to get -+ performances and genericity... -+ -+ Some example of insert and search follows here. The search is a plain -+ normal search over an ordered tree. The insert instead must be implemented -+ int two steps: as first thing the code must insert the element in -+ order as a red leaf in the tree, then the support library function -+ rb_insert_color() must be called. Such function will do the -+ not trivial work to rebalance the rbtree if necessary. -+ -+----------------------------------------------------------------------- -+static inline struct page * rb_search_page_cache(struct inode * inode, -+ unsigned long offset) -+{ -+ struct rb_node * n = inode->i_rb_page_cache.rb_node; -+ struct page * page; -+ -+ while (n) -+ { -+ page = rb_entry(n, struct page, rb_page_cache); -+ -+ if (offset < page->offset) -+ n = n->rb_left; -+ else if (offset > page->offset) -+ n = n->rb_right; -+ else -+ return page; -+ } -+ return NULL; -+} -+ -+static inline struct page * __rb_insert_page_cache(struct inode * inode, -+ unsigned long offset, -+ struct rb_node * node) -+{ -+ struct rb_node ** p = &inode->i_rb_page_cache.rb_node; -+ struct rb_node * parent = NULL; -+ struct page * page; -+ -+ while (*p) -+ { -+ parent = *p; -+ page = rb_entry(parent, struct page, rb_page_cache); -+ -+ if (offset < page->offset) -+ p = &(*p)->rb_left; -+ else if (offset > page->offset) -+ p = &(*p)->rb_right; -+ else -+ return page; -+ } -+ -+ rb_link_node(node, parent, p); -+ -+ return NULL; -+} -+ -+static inline struct page * rb_insert_page_cache(struct inode * inode, -+ unsigned long offset, -+ struct rb_node * node) -+{ -+ struct page * ret; -+ if ((ret = __rb_insert_page_cache(inode, offset, node))) -+ goto out; -+ rb_insert_color(node, &inode->i_rb_page_cache); -+ out: -+ return ret; -+} -+----------------------------------------------------------------------- -+*/ -+ -+#ifndef _LINUX_RBTREE_H -+#define _LINUX_RBTREE_H -+ -+#include -+#include -+ -+struct rb_node -+{ -+ unsigned long rb_parent_color; -+#define RB_RED 0 -+#define RB_BLACK 1 -+ struct rb_node *rb_right; -+ struct rb_node *rb_left; -+} __attribute__((aligned(sizeof(long)))); -+ /* The alignment might seem pointless, but allegedly CRIS needs it */ -+ -+struct rb_root -+{ -+ struct rb_node *rb_node; -+}; -+ -+ -+#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) -+#define rb_color(r) ((r)->rb_parent_color & 1) -+#define rb_is_red(r) (!rb_color(r)) -+#define rb_is_black(r) rb_color(r) -+#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) -+#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) -+ -+static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) -+{ -+ rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p; -+} -+static inline void rb_set_color(struct rb_node *rb, int color) -+{ -+ rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; -+} -+ -+#define RB_ROOT (struct rb_root) { NULL, } -+ -+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -+ -+#define container_of(ptr, type, member) ({ \ -+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ -+ (type *)( (char *)__mptr - offsetof(type,member) );}) -+ -+#define rb_entry(ptr, type, member) container_of(ptr, type, member) -+ -+#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) -+#define RB_EMPTY_NODE(node) (rb_parent(node) == node) -+#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) -+ -+extern void rb_insert_color(struct rb_node *, struct rb_root *); -+extern void rb_erase(struct rb_node *, struct rb_root *); -+ -+/* Find logical next and previous nodes in a tree */ -+extern struct rb_node *rb_next(struct rb_node *); -+extern struct rb_node *rb_prev(struct rb_node *); -+extern struct rb_node *rb_first(struct rb_root *); -+extern struct rb_node *rb_last(struct rb_root *); -+ -+/* Fast replacement of a single node without remove/rebalance/add/rebalance */ -+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, -+ struct rb_root *root); -+ -+static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, -+ struct rb_node ** rb_link) -+{ -+ node->rb_parent_color = (unsigned long )parent; -+ node->rb_left = node->rb_right = NULL; -+ -+ *rb_link = node; -+} -+ -+#endif /* _LINUX_RBTREE_H */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/recv_image.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/recv_image.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,484 @@ -+ -+#define _XOPEN_SOURCE 500 -+#define _USE_MISC -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+#include "mtd/mtd-user.h" -+#include "mcast_image.h" -+ -+#define min(x,y) ( (x)>(y)?(y):(x) ) -+ -+#define WBUF_SIZE 4096 -+struct eraseblock { -+ uint32_t flash_offset; -+ unsigned char wbuf[WBUF_SIZE]; -+ int wbuf_ofs; -+ int nr_pkts; -+ int *pkt_indices; -+ uint32_t crc; -+}; -+ -+int main(int argc, char **argv) -+{ -+ struct addrinfo *ai; -+ struct addrinfo hints; -+ struct addrinfo *runp; -+ int ret; -+ int sock; -+ size_t len; -+ int flfd; -+ struct mtd_info_user meminfo; -+ unsigned char *eb_buf, *decode_buf, **src_pkts; -+ int nr_blocks = 0; -+ int pkts_per_block; -+ int block_nr = -1; -+ uint32_t image_crc; -+ int total_pkts = 0; -+ int ignored_pkts = 0; -+ loff_t mtdoffset = 0; -+ int badcrcs = 0; -+ int duplicates = 0; -+ int file_mode = 0; -+ struct fec_parms *fec; -+ int i; -+ struct eraseblock *eraseblocks = NULL; -+ uint32_t start_seq; -+ struct timeval start, now; -+ unsigned long fec_time = 0, flash_time = 0, crc_time = 0, -+ rflash_time = 0, erase_time = 0, net_time = 0; -+ -+ if (argc != 4) { -+ fprintf(stderr, "usage: %s \n", -+ (strrchr(argv[0], '/')?:argv[0]-1)+1); -+ exit(1); -+ } -+ /* Open the device */ -+ flfd = open(argv[3], O_RDWR); -+ -+ if (flfd >= 0) { -+ /* Fill in MTD device capability structure */ -+ if (ioctl(flfd, MEMGETINFO, &meminfo) != 0) { -+ perror("MEMGETINFO"); -+ close(flfd); -+ flfd = -1; -+ } else { -+ printf("Receive to MTD device %s with erasesize %d\n", -+ argv[3], meminfo.erasesize); -+ } -+ } -+ if (flfd == -1) { -+ /* Try again, as if it's a file */ -+ flfd = open(argv[3], O_CREAT|O_TRUNC|O_RDWR, 0644); -+ if (flfd < 0) { -+ perror("open"); -+ exit(1); -+ } -+ meminfo.erasesize = 131072; -+ file_mode = 1; -+ printf("Receive to file %s with (assumed) erasesize %d\n", -+ argv[3], meminfo.erasesize); -+ } -+ -+ pkts_per_block = (meminfo.erasesize + PKT_SIZE - 1) / PKT_SIZE; -+ -+ eb_buf = malloc(pkts_per_block * PKT_SIZE); -+ decode_buf = malloc(pkts_per_block * PKT_SIZE); -+ if (!eb_buf && !decode_buf) { -+ fprintf(stderr, "No memory for eraseblock buffer\n"); -+ exit(1); -+ } -+ src_pkts = malloc(sizeof(unsigned char *) * pkts_per_block); -+ if (!src_pkts) { -+ fprintf(stderr, "No memory for decode packet pointers\n"); -+ exit(1); -+ } -+ -+ memset(&hints, 0, sizeof(hints)); -+ hints.ai_flags = AI_ADDRCONFIG; -+ hints.ai_socktype = SOCK_DGRAM; -+ -+ ret = getaddrinfo(argv[1], argv[2], &hints, &ai); -+ if (ret) { -+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret)); -+ exit(1); -+ } -+ runp = ai; -+ for (runp = ai; runp; runp = runp->ai_next) { -+ sock = socket(runp->ai_family, runp->ai_socktype, -+ runp->ai_protocol); -+ if (sock == -1) { -+ perror("socket"); -+ continue; -+ } -+ if (runp->ai_family == AF_INET && -+ IN_MULTICAST( ntohl(((struct sockaddr_in *)runp->ai_addr)->sin_addr.s_addr))) { -+ struct ip_mreq rq; -+ rq.imr_multiaddr = ((struct sockaddr_in *)runp->ai_addr)->sin_addr; -+ rq.imr_interface.s_addr = INADDR_ANY; -+ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &rq, sizeof(rq))) { -+ perror("IP_ADD_MEMBERSHIP"); -+ close(sock); -+ continue; -+ } -+ -+ } else if (runp->ai_family == AF_INET6 && -+ ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr.s6_addr[0] == 0xff) { -+ struct ipv6_mreq rq; -+ rq.ipv6mr_multiaddr = ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr; -+ rq.ipv6mr_interface = 0; -+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &rq, sizeof(rq))) { -+ perror("IPV6_ADD_MEMBERSHIP"); -+ close(sock); -+ continue; -+ } -+ } -+ if (bind(sock, runp->ai_addr, runp->ai_addrlen)) { -+ perror("bind"); -+ close(sock); -+ continue; -+ } -+ break; -+ } -+ if (!runp) -+ exit(1); -+ -+ while (1) { -+ struct image_pkt thispkt; -+ -+ len = read(sock, &thispkt, sizeof(thispkt)); -+ -+ if (len < 0) { -+ perror("read socket"); -+ break; -+ } -+ if (len < sizeof(thispkt)) { -+ fprintf(stderr, "Wrong length %d bytes (expected %d)\n", -+ len, sizeof(thispkt)); -+ continue; -+ } -+ if (!eraseblocks) { -+ image_crc = thispkt.hdr.totcrc; -+ start_seq = ntohl(thispkt.hdr.pkt_sequence); -+ -+ if (meminfo.erasesize != ntohl(thispkt.hdr.blocksize)) { -+ fprintf(stderr, "Erasesize mismatch (0x%x not 0x%x)\n", -+ ntohl(thispkt.hdr.blocksize), meminfo.erasesize); -+ exit(1); -+ } -+ nr_blocks = ntohl(thispkt.hdr.nr_blocks); -+ -+ fec = fec_new(pkts_per_block, ntohs(thispkt.hdr.nr_pkts)); -+ -+ eraseblocks = malloc(nr_blocks * sizeof(*eraseblocks)); -+ if (!eraseblocks) { -+ fprintf(stderr, "No memory for block map\n"); -+ exit(1); -+ } -+ for (i = 0; i < nr_blocks; i++) { -+ eraseblocks[i].pkt_indices = malloc(sizeof(int) * pkts_per_block); -+ if (!eraseblocks[i].pkt_indices) { -+ fprintf(stderr, "Failed to allocate packet indices\n"); -+ exit(1); -+ } -+ eraseblocks[i].nr_pkts = 0; -+ if (!file_mode) { -+ if (mtdoffset >= meminfo.size) { -+ fprintf(stderr, "Run out of space on flash\n"); -+ exit(1); -+ } -+#if 1 /* Deliberately use bad blocks... test write failures */ -+ while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) { -+ printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset); -+ mtdoffset += meminfo.erasesize; -+ } -+#endif -+ } -+ eraseblocks[i].flash_offset = mtdoffset; -+ mtdoffset += meminfo.erasesize; -+ eraseblocks[i].wbuf_ofs = 0; -+ } -+ gettimeofday(&start, NULL); -+ } -+ if (image_crc != thispkt.hdr.totcrc) { -+ fprintf(stderr, "\nImage CRC changed from 0x%x to 0x%x. Aborting\n", -+ ntohl(image_crc), ntohl(thispkt.hdr.totcrc)); -+ exit(1); -+ } -+ -+ block_nr = ntohl(thispkt.hdr.block_nr); -+ if (block_nr >= nr_blocks) { -+ fprintf(stderr, "\nErroneous block_nr %d (> %d)\n", -+ block_nr, nr_blocks); -+ exit(1); -+ } -+ for (i=0; i= pkts_per_block) { -+ /* We have a block which we didn't really need */ -+ eraseblocks[block_nr].nr_pkts++; -+ ignored_pkts++; -+ continue; -+ } -+ -+ if (crc32(-1, thispkt.data, PKT_SIZE) != ntohl(thispkt.hdr.thiscrc)) { -+ printf("\nDiscard %08x pkt %d with bad CRC (%08x not %08x)\n", -+ block_nr * meminfo.erasesize, ntohs(thispkt.hdr.pkt_nr), -+ crc32(-1, thispkt.data, PKT_SIZE), -+ ntohl(thispkt.hdr.thiscrc)); -+ badcrcs++; -+ continue; -+ } -+ pkt_again: -+ eraseblocks[block_nr].pkt_indices[eraseblocks[block_nr].nr_pkts++] = -+ ntohs(thispkt.hdr.pkt_nr); -+ total_pkts++; -+ if (!(total_pkts % 50) || total_pkts == pkts_per_block * nr_blocks) { -+ uint32_t pkts_sent = ntohl(thispkt.hdr.pkt_sequence) - start_seq + 1; -+ long time_msec; -+ gettimeofday(&now, NULL); -+ -+ time_msec = ((now.tv_usec - start.tv_usec) / 1000) + -+ (now.tv_sec - start.tv_sec) * 1000; -+ -+ printf("\rReceived %d/%d (%d%%) in %lds @%ldKiB/s, %d lost (%d%%), %d dup/xs ", -+ total_pkts, nr_blocks * pkts_per_block, -+ total_pkts * 100 / nr_blocks / pkts_per_block, -+ time_msec / 1000, -+ total_pkts * PKT_SIZE / 1024 * 1000 / time_msec, -+ pkts_sent - total_pkts - duplicates - ignored_pkts, -+ (pkts_sent - total_pkts - duplicates - ignored_pkts) * 100 / pkts_sent, -+ duplicates + ignored_pkts); -+ fflush(stdout); -+ } -+ -+ if (eraseblocks[block_nr].wbuf_ofs + PKT_SIZE < WBUF_SIZE) { -+ /* New packet doesn't full the wbuf */ -+ memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs, -+ thispkt.data, PKT_SIZE); -+ eraseblocks[block_nr].wbuf_ofs += PKT_SIZE; -+ } else { -+ int fits = WBUF_SIZE - eraseblocks[block_nr].wbuf_ofs; -+ ssize_t wrotelen; -+ static int faked = 1; -+ -+ memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs, -+ thispkt.data, fits); -+ wrotelen = pwrite(flfd, eraseblocks[block_nr].wbuf, WBUF_SIZE, -+ eraseblocks[block_nr].flash_offset); -+ -+ if (wrotelen < WBUF_SIZE || (block_nr == 5 && eraseblocks[block_nr].nr_pkts == 5 && !faked)) { -+ faked = 1; -+ if (wrotelen < 0) -+ perror("\npacket write"); -+ else -+ fprintf(stderr, "\nshort write of packet wbuf\n"); -+ -+ if (!file_mode) { -+ struct erase_info_user erase; -+ /* FIXME: Perhaps we should store pkt crcs and try -+ to recover data from the offending eraseblock */ -+ -+ /* We have increased nr_pkts but not yet flash_offset */ -+ erase.start = eraseblocks[block_nr].flash_offset & -+ ~(meminfo.erasesize - 1); -+ erase.length = meminfo.erasesize; -+ -+ printf("Will erase at %08lx len %08lx (bad write was at %08lx)\n", -+ erase.start, erase.length, eraseblocks[block_nr].flash_offset); -+ if (ioctl(flfd, MEMERASE, &erase)) { -+ perror("MEMERASE"); -+ exit(1); -+ } -+ if (mtdoffset >= meminfo.size) { -+ fprintf(stderr, "Run out of space on flash\n"); -+ exit(1); -+ } -+ while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) { -+ printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset); -+ mtdoffset += meminfo.erasesize; -+ if (mtdoffset >= meminfo.size) { -+ fprintf(stderr, "Run out of space on flash\n"); -+ exit(1); -+ } -+ } -+ eraseblocks[block_nr].flash_offset = mtdoffset; -+ printf("Block #%d will now be at %08lx\n", block_nr, (long)mtdoffset); -+ total_pkts -= eraseblocks[block_nr].nr_pkts; -+ eraseblocks[block_nr].nr_pkts = 0; -+ eraseblocks[block_nr].wbuf_ofs = 0; -+ mtdoffset += meminfo.erasesize; -+ goto pkt_again; -+ } -+ else /* Usually nothing we can do in file mode */ -+ exit(1); -+ } -+ eraseblocks[block_nr].flash_offset += WBUF_SIZE; -+ /* Copy the remainder into the wbuf */ -+ memcpy(eraseblocks[block_nr].wbuf, &thispkt.data[fits], PKT_SIZE - fits); -+ eraseblocks[block_nr].wbuf_ofs = PKT_SIZE - fits; -+ } -+ -+ if (eraseblocks[block_nr].nr_pkts == pkts_per_block) { -+ eraseblocks[block_nr].crc = ntohl(thispkt.hdr.block_crc); -+ -+ if (total_pkts == nr_blocks * pkts_per_block) -+ break; -+ } -+ } -+ printf("\n"); -+ gettimeofday(&now, NULL); -+ net_time = (now.tv_usec - start.tv_usec) / 1000; -+ net_time += (now.tv_sec - start.tv_sec) * 1000; -+ close(sock); -+ for (block_nr = 0; block_nr < nr_blocks; block_nr++) { -+ ssize_t rwlen; -+ gettimeofday(&start, NULL); -+ eraseblocks[block_nr].flash_offset -= meminfo.erasesize; -+ rwlen = pread(flfd, eb_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset); -+ -+ gettimeofday(&now, NULL); -+ rflash_time += (now.tv_usec - start.tv_usec) / 1000; -+ rflash_time += (now.tv_sec - start.tv_sec) * 1000; -+ if (rwlen < 0) { -+ perror("read"); -+ /* Argh. Perhaps we could go back and try again, but if the flash is -+ going to fail to read back what we write to it, and the whole point -+ in this program is to write to it, what's the point? */ -+ fprintf(stderr, "Packets we wrote to flash seem to be unreadable. Aborting\n"); -+ exit(1); -+ } -+ -+ memcpy(eb_buf + meminfo.erasesize, eraseblocks[block_nr].wbuf, -+ eraseblocks[block_nr].wbuf_ofs); -+ -+ for (i=0; i < pkts_per_block; i++) -+ src_pkts[i] = &eb_buf[i * PKT_SIZE]; -+ -+ gettimeofday(&start, NULL); -+ if (fec_decode(fec, src_pkts, eraseblocks[block_nr].pkt_indices, PKT_SIZE)) { -+ /* Eep. This cannot happen */ -+ printf("The world is broken. fec_decode() returned error\n"); -+ exit(1); -+ } -+ gettimeofday(&now, NULL); -+ fec_time += (now.tv_usec - start.tv_usec) / 1000; -+ fec_time += (now.tv_sec - start.tv_sec) * 1000; -+ -+ for (i=0; i < pkts_per_block; i++) -+ memcpy(&decode_buf[i*PKT_SIZE], src_pkts[i], PKT_SIZE); -+ -+ /* Paranoia */ -+ gettimeofday(&start, NULL); -+ if (crc32(-1, decode_buf, meminfo.erasesize) != eraseblocks[block_nr].crc) { -+ printf("\nCRC mismatch for block #%d: want %08x got %08x\n", -+ block_nr, eraseblocks[block_nr].crc, -+ crc32(-1, decode_buf, meminfo.erasesize)); -+ exit(1); -+ } -+ gettimeofday(&now, NULL); -+ crc_time += (now.tv_usec - start.tv_usec) / 1000; -+ crc_time += (now.tv_sec - start.tv_sec) * 1000; -+ start = now; -+ -+ if (!file_mode) { -+ struct erase_info_user erase; -+ -+ erase.start = eraseblocks[block_nr].flash_offset; -+ erase.length = meminfo.erasesize; -+ -+ printf("\rErasing block at %08x...", erase.start); -+ -+ if (ioctl(flfd, MEMERASE, &erase)) { -+ perror("MEMERASE"); -+ /* This block has dirty data on it. If the erase failed, we're screwed */ -+ fprintf(stderr, "Erase to clean FEC data from flash failed. Aborting\n"); -+ exit(1); -+ } -+ gettimeofday(&now, NULL); -+ erase_time += (now.tv_usec - start.tv_usec) / 1000; -+ erase_time += (now.tv_sec - start.tv_sec) * 1000; -+ start = now; -+ } -+ else printf("\r"); -+ write_again: -+ rwlen = pwrite(flfd, decode_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset); -+ if (rwlen < meminfo.erasesize) { -+ if (rwlen < 0) { -+ perror("\ndecoded data write"); -+ } else -+ fprintf(stderr, "\nshort write of decoded data\n"); -+ -+ if (!file_mode) { -+ struct erase_info_user erase; -+ erase.start = eraseblocks[block_nr].flash_offset; -+ erase.length = meminfo.erasesize; -+ -+ printf("Erasing failed block at %08x\n", -+ eraseblocks[block_nr].flash_offset); -+ -+ if (ioctl(flfd, MEMERASE, &erase)) { -+ perror("MEMERASE"); -+ exit(1); -+ } -+ if (mtdoffset >= meminfo.size) { -+ fprintf(stderr, "Run out of space on flash\n"); -+ exit(1); -+ } -+ while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) { -+ printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset); -+ mtdoffset += meminfo.erasesize; -+ if (mtdoffset >= meminfo.size) { -+ fprintf(stderr, "Run out of space on flash\n"); -+ exit(1); -+ } -+ } -+ printf("Will try again at %08lx...", (long)mtdoffset); -+ eraseblocks[block_nr].flash_offset = mtdoffset; -+ -+ goto write_again; -+ } -+ else /* Usually nothing we can do in file mode */ -+ exit(1); -+ } -+ gettimeofday(&now, NULL); -+ flash_time += (now.tv_usec - start.tv_usec) / 1000; -+ flash_time += (now.tv_sec - start.tv_sec) * 1000; -+ -+ printf("wrote image block %08x (%d pkts) ", -+ block_nr * meminfo.erasesize, eraseblocks[block_nr].nr_pkts); -+ fflush(stdout); -+ } -+ close(flfd); -+ printf("Net rx %ld.%03lds\n", net_time / 1000, net_time % 1000); -+ printf("flash rd %ld.%03lds\n", rflash_time / 1000, rflash_time % 1000); -+ printf("FEC time %ld.%03lds\n", fec_time / 1000, fec_time % 1000); -+ printf("CRC time %ld.%03lds\n", crc_time / 1000, crc_time % 1000); -+ printf("flash wr %ld.%03lds\n", flash_time / 1000, flash_time % 1000); -+ printf("flash er %ld.%03lds\n", erase_time / 1000, erase_time % 1000); -+ -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/rfddump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/rfddump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,336 @@ -+/* -+ * rfddump.c -+ * -+ * Copyright (C) 2005 Sean Young -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#define _XOPEN_SOURCE 500 /* For pread */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* next is an array of mapping for each corresponding sector */ -+#define RFD_MAGIC 0x9193 -+#define HEADER_MAP_OFFSET 3 -+#define SECTOR_DELETED 0x0000 -+#define SECTOR_ZERO 0xfffe -+#define SECTOR_FREE 0xffff -+ -+#define SECTOR_SIZE 512 -+ -+#define SECTORS_PER_TRACK 63 -+ -+ -+struct rfd { -+ int block_size; -+ int block_count; -+ int header_sectors; -+ int data_sectors; -+ int header_size; -+ uint16_t *header; -+ int sector_count; -+ int *sector_map; -+ const char *mtd_filename; -+ const char *out_filename; -+ int verbose; -+}; -+ -+#define PROGRAM "rfddump" -+#define VERSION "$Revision 1.0 $" -+ -+void display_help(void) -+{ -+ printf("Usage: " PROGRAM " [OPTIONS] MTD-device filename\n" -+ "Dumps the contents of a resident flash disk\n" -+ "\n" -+ "-h --help display this help and exit\n" -+ "-V --version output version information and exit\n" -+ "-v --verbose Be verbose\n" -+ "-b size --blocksize Block size (defaults to erase unit)\n"); -+ exit(0); -+} -+ -+void display_version(void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "This is free software; see the source for copying conditions. There is NO\n" -+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); -+ -+ exit(0); -+} -+ -+void process_options(int argc, char *argv[], struct rfd *rfd) -+{ -+ int error = 0; -+ -+ rfd->block_size = 0; -+ rfd->verbose = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "hvVb:"; -+ static const struct option long_options[] = { -+ { "help", no_argument, 0, 'h' }, -+ { "version", no_argument, 0, 'V', }, -+ { "blocksize", required_argument, 0, 'b' }, -+ { "verbose", no_argument, 0, 'v' }, -+ { NULL, 0, 0, 0 } -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) -+ break; -+ -+ switch (c) { -+ case 'h': -+ display_help(); -+ break; -+ case 'V': -+ display_version(); -+ break; -+ case 'v': -+ rfd->verbose = 1; -+ break; -+ case 'b': -+ rfd->block_size = atoi(optarg); -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 2 || error) -+ display_help(); -+ -+ rfd->mtd_filename = argv[optind]; -+ rfd->out_filename = argv[optind + 1]; -+} -+ -+int build_block_map(struct rfd *rfd, int fd, int block) -+{ -+ int i; -+ int sectors; -+ -+ if (pread(fd, rfd->header, rfd->header_size, block * rfd->block_size) -+ != rfd->header_size) { -+ return -1; -+ } -+ -+ if (le16_to_cpu(rfd->header[0]) != RFD_MAGIC) { -+ if (rfd->verbose) -+ printf("Block #%02d: Magic missing\n", block); -+ -+ return 0; -+ } -+ -+ sectors = 0; -+ for (i=0; idata_sectors; i++) { -+ uint16_t entry = le16_to_cpu(rfd->header[i + HEADER_MAP_OFFSET]); -+ -+ if (entry == SECTOR_FREE || entry == SECTOR_DELETED) -+ continue; -+ -+ if (entry == SECTOR_ZERO) -+ entry = 0; -+ -+ if (entry >= rfd->sector_count) { -+ fprintf(stderr, "%s: warning: sector %d out of range\n", -+ rfd->mtd_filename, entry); -+ continue; -+ } -+ -+ if (rfd->sector_map[entry] != -1) { -+ fprintf(stderr, "%s: warning: more than one entry " -+ "for sector %d\n", rfd->mtd_filename, entry); -+ continue; -+ } -+ -+ rfd->sector_map[entry] = rfd->block_size * block + -+ (i + rfd->header_sectors) * SECTOR_SIZE; -+ sectors++; -+ } -+ -+ if (rfd->verbose) -+ printf("Block #%02d: %d sectors\n", block, sectors); -+ -+ return 1; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int fd, sectors_per_block; -+ mtd_info_t mtd_info; -+ struct rfd rfd; -+ int i, blocks_found; -+ int out_fd = 0; -+ uint8_t sector[512]; -+ int blank, rc, cylinders; -+ -+ process_options(argc, argv, &rfd); -+ -+ fd = open(rfd.mtd_filename, O_RDONLY); -+ if (fd == -1) { -+ perror(rfd.mtd_filename); -+ return 1; -+ } -+ -+ if (rfd.block_size == 0) { -+ if (ioctl(fd, MEMGETINFO, &mtd_info)) { -+ perror(rfd.mtd_filename); -+ close(fd); -+ return 1; -+ } -+ -+ if (mtd_info.type != MTD_NORFLASH) { -+ fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename); -+ close(fd); -+ return 2; -+ } -+ -+ sectors_per_block = mtd_info.erasesize / SECTOR_SIZE; -+ -+ rfd.block_size = mtd_info.erasesize; -+ rfd.block_count = mtd_info.size / mtd_info.erasesize; -+ } else { -+ struct stat st; -+ -+ if (fstat(fd, &st) == -1) { -+ perror(rfd.mtd_filename); -+ close(fd); -+ return 1; -+ } -+ -+ if (st.st_size % SECTOR_SIZE) -+ fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename); -+ -+ sectors_per_block = rfd.block_size / SECTOR_SIZE; -+ -+ if (st.st_size % rfd.block_size) -+ fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename); -+ -+ rfd.block_count = st.st_size / rfd.block_size; -+ -+ if (!rfd.block_count) { -+ fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename); -+ close(fd); -+ return 2; -+ } -+ } -+ -+ rfd.header_sectors = -+ ((HEADER_MAP_OFFSET + sectors_per_block) * -+ sizeof(uint16_t) + SECTOR_SIZE - 1) / SECTOR_SIZE; -+ rfd.data_sectors = sectors_per_block - rfd.header_sectors; -+ cylinders = ((rfd.block_count - 1) * rfd.data_sectors - 1) -+ / SECTORS_PER_TRACK; -+ rfd.sector_count = cylinders * SECTORS_PER_TRACK; -+ rfd.header_size = -+ (HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t); -+ -+ rfd.header = malloc(rfd.header_size); -+ if (!rfd.header) { -+ perror(PROGRAM); -+ close(fd); -+ return 2; -+ } -+ rfd.sector_map = malloc(rfd.sector_count * sizeof(int)); -+ if (!rfd.sector_map) { -+ perror(PROGRAM); -+ close(fd); -+ free(rfd.sector_map); -+ return 2; -+ } -+ -+ rfd.mtd_filename = rfd.mtd_filename; -+ -+ for (i=0; i 0) -+ blocks_found++; -+ if (rc < 0) -+ goto err; -+ } -+ -+ if (!blocks_found) { -+ fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename); -+ goto err; -+ } -+ -+ for (i=0; i -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This is very easy: just erase all the blocks and put the magic at -+ * the beginning of each block. -+ */ -+ -+#define _XOPEN_SOURCE 500 /* For pread/pwrite */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define PROGRAM "rfdformat" -+#define VERSION "$Revision 1.0 $" -+ -+void display_help(void) -+{ -+ printf("Usage: " PROGRAM " [OPTIONS] MTD-device\n" -+ "Formats NOR flash for resident flash disk\n" -+ "\n" -+ "-h --help display this help and exit\n" -+ "-V --version output version information and exit\n"); -+ exit(0); -+} -+ -+void display_version(void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "This is free software; see the source for copying conditions. There is NO\n" -+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); -+ -+ exit(0); -+} -+ -+void process_options(int argc, char *argv[], const char **mtd_filename) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "hV"; -+ static const struct option long_options[] = { -+ { "help", no_argument, 0, 'h' }, -+ { "version", no_argument, 0, 'V', }, -+ { NULL, 0, 0, 0 } -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) -+ break; -+ -+ switch (c) { -+ case 'h': -+ display_help(); -+ break; -+ case 'V': -+ display_version(); -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 1 || error) -+ display_help(); -+ -+ *mtd_filename = argv[optind]; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ static const uint8_t magic[] = { 0x93, 0x91 }; -+ int fd, block_count, i; -+ struct mtd_info_user mtd_info; -+ char buf[512]; -+ const char *mtd_filename; -+ -+ process_options(argc, argv, &mtd_filename); -+ -+ fd = open(mtd_filename, O_RDWR); -+ if (fd == -1) { -+ perror(mtd_filename); -+ return 1; -+ } -+ -+ if (ioctl(fd, MEMGETINFO, &mtd_info)) { -+ perror(mtd_filename); -+ close(fd); -+ return 1; -+ } -+ -+ if (mtd_info.type != MTD_NORFLASH) { -+ fprintf(stderr, "%s: not NOR flash\n", mtd_filename); -+ close(fd); -+ return 2; -+ } -+ -+ if (mtd_info.size > 32*1024*1024) { -+ fprintf(stderr, "%s: flash larger than 32MiB not supported\n", -+ mtd_filename); -+ close(fd); -+ return 2; -+ } -+ -+ block_count = mtd_info.size / mtd_info.erasesize; -+ -+ if (block_count < 2) { -+ fprintf(stderr, "%s: at least two erase units required\n", -+ mtd_filename); -+ close(fd); -+ return 2; -+ } -+ -+ for (i=0; i -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+#include "mcast_image.h" -+ -+int tx_rate = 80000; -+int pkt_delay; -+ -+#undef RANDOMDROP -+ -+int main(int argc, char **argv) -+{ -+ struct addrinfo *ai; -+ struct addrinfo hints; -+ struct addrinfo *runp; -+ int ret; -+ int sock; -+ struct image_pkt pktbuf; -+ int rfd; -+ struct stat st; -+ int writeerrors = 0; -+ uint32_t erasesize; -+ unsigned char *image, *blockptr = NULL; -+ uint32_t block_nr, pkt_nr; -+ int nr_blocks; -+ struct timeval then, now, nextpkt; -+ long time_msecs; -+ int pkts_per_block; -+ int total_pkts_per_block; -+ struct fec_parms *fec; -+ unsigned char *last_block; -+ uint32_t *block_crcs; -+ long tosleep; -+ uint32_t sequence = 0; -+ -+ if (argc == 6) { -+ tx_rate = atol(argv[5]) * 1024; -+ if (tx_rate < PKT_SIZE || tx_rate > 20000000) { -+ fprintf(stderr, "Bogus TX rate %d KiB/s\n", tx_rate); -+ exit(1); -+ } -+ argc = 5; -+ } -+ if (argc != 5) { -+ fprintf(stderr, "usage: %s []\n", -+ (strrchr(argv[0], '/')?:argv[0]-1)+1); -+ exit(1); -+ } -+ pkt_delay = (sizeof(pktbuf) * 1000000) / tx_rate; -+ printf("Inter-packet delay (avg): %dµs\n", pkt_delay); -+ printf("Transmit rate: %d KiB/s\n", tx_rate / 1024); -+ -+ erasesize = atol(argv[4]); -+ if (!erasesize) { -+ fprintf(stderr, "erasesize cannot be zero\n"); -+ exit(1); -+ } -+ -+ pkts_per_block = (erasesize + PKT_SIZE - 1) / PKT_SIZE; -+ total_pkts_per_block = pkts_per_block * 3 / 2; -+ -+ /* We have to pad it with zeroes, so can't use it in-place */ -+ last_block = malloc(pkts_per_block * PKT_SIZE); -+ if (!last_block) { -+ fprintf(stderr, "Failed to allocate last-block buffer\n"); -+ exit(1); -+ } -+ -+ fec = fec_new(pkts_per_block, total_pkts_per_block); -+ if (!fec) { -+ fprintf(stderr, "Error initialising FEC\n"); -+ exit(1); -+ } -+ -+ memset(&hints, 0, sizeof(hints)); -+ hints.ai_flags = AI_ADDRCONFIG; -+ hints.ai_socktype = SOCK_DGRAM; -+ -+ ret = getaddrinfo(argv[1], argv[2], &hints, &ai); -+ if (ret) { -+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret)); -+ exit(1); -+ } -+ runp = ai; -+ for (runp = ai; runp; runp = runp->ai_next) { -+ sock = socket(runp->ai_family, runp->ai_socktype, -+ runp->ai_protocol); -+ if (sock == -1) { -+ perror("socket"); -+ continue; -+ } -+ if (connect(sock, runp->ai_addr, runp->ai_addrlen) == 0) -+ break; -+ perror("connect"); -+ close(sock); -+ } -+ if (!runp) -+ exit(1); -+ -+ rfd = open(argv[3], O_RDONLY); -+ if (rfd < 0) { -+ perror("open"); -+ exit(1); -+ } -+ -+ if (fstat(rfd, &st)) { -+ perror("fstat"); -+ exit(1); -+ } -+ -+ if (st.st_size % erasesize) { -+ fprintf(stderr, "Image size %ld bytes is not a multiple of erasesize %d bytes\n", -+ st.st_size, erasesize); -+ exit(1); -+ } -+ image = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, rfd, 0); -+ if (image == MAP_FAILED) { -+ perror("mmap"); -+ exit(1); -+ } -+ -+ nr_blocks = st.st_size / erasesize; -+ -+ block_crcs = malloc(nr_blocks * sizeof(uint32_t)); -+ if (!block_crcs) { -+ fprintf(stderr, "Failed to allocate memory for CRCs\n"); -+ exit(1); -+ } -+ -+ memcpy(last_block, image + (nr_blocks - 1) * erasesize, erasesize); -+ memset(last_block + erasesize, 0, (PKT_SIZE * pkts_per_block) - erasesize); -+ -+ printf("Checking CRC...."); -+ fflush(stdout); -+ -+ pktbuf.hdr.resend = 0; -+ pktbuf.hdr.totcrc = htonl(crc32(-1, image, st.st_size)); -+ pktbuf.hdr.nr_blocks = htonl(nr_blocks); -+ pktbuf.hdr.blocksize = htonl(erasesize); -+ pktbuf.hdr.thislen = htonl(PKT_SIZE); -+ pktbuf.hdr.nr_pkts = htons(total_pkts_per_block); -+ -+ printf("%08x\n", ntohl(pktbuf.hdr.totcrc)); -+ printf("Checking block CRCs...."); -+ fflush(stdout); -+ for (block_nr=0; block_nr < nr_blocks; block_nr++) { -+ printf("\rChecking block CRCS.... %d/%d", -+ block_nr + 1, nr_blocks); -+ fflush(stdout); -+ block_crcs[block_nr] = crc32(-1, image + (block_nr * erasesize), erasesize); -+ } -+ -+ printf("\nImage size %ld KiB (0x%08lx). %d blocks at %d pkts/block\n" -+ "Estimated transmit time per cycle: %ds\n", -+ (long)st.st_size / 1024, (long) st.st_size, -+ nr_blocks, pkts_per_block, -+ nr_blocks * pkts_per_block * pkt_delay / 1000000); -+ gettimeofday(&then, NULL); -+ nextpkt = then; -+ -+#ifdef RANDOMDROP -+ srand((unsigned)then.tv_usec); -+ printf("Random seed %u\n", (unsigned)then.tv_usec); -+#endif -+ while (1) for (pkt_nr=0; pkt_nr < total_pkts_per_block; pkt_nr++) { -+ -+ if (blockptr && pkt_nr == 0) { -+ unsigned long amt_sent = total_pkts_per_block * nr_blocks * sizeof(pktbuf); -+ gettimeofday(&now, NULL); -+ -+ time_msecs = (now.tv_sec - then.tv_sec) * 1000; -+ time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000; -+ printf("\n%ld KiB sent in %ldms (%ld KiB/s)\n", -+ amt_sent / 1024, time_msecs, -+ amt_sent / 1024 * 1000 / time_msecs); -+ then = now; -+ } -+ -+ for (block_nr = 0; block_nr < nr_blocks; block_nr++) { -+ -+ int actualpkt; -+ -+ /* Calculating the redundant FEC blocks is expensive; -+ the first $pkts_per_block are cheap enough though -+ because they're just copies. So alternate between -+ simple and complex stuff, so that we don't start -+ to choke and fail to keep up with the expected -+ bitrate in the second half of the sequence */ -+ if (block_nr & 1) -+ actualpkt = pkt_nr; -+ else -+ actualpkt = total_pkts_per_block - 1 - pkt_nr; -+ -+ blockptr = image + (erasesize * block_nr); -+ if (block_nr == nr_blocks - 1) -+ blockptr = last_block; -+ -+ fec_encode_linear(fec, blockptr, pktbuf.data, actualpkt, PKT_SIZE); -+ -+ pktbuf.hdr.thiscrc = htonl(crc32(-1, pktbuf.data, PKT_SIZE)); -+ pktbuf.hdr.block_crc = htonl(block_crcs[block_nr]); -+ pktbuf.hdr.block_nr = htonl(block_nr); -+ pktbuf.hdr.pkt_nr = htons(actualpkt); -+ pktbuf.hdr.pkt_sequence = htonl(sequence++); -+ -+ printf("\rSending data block %08x packet %3d/%d", -+ block_nr * erasesize, -+ pkt_nr, total_pkts_per_block); -+ -+ if (pkt_nr && !block_nr) { -+ unsigned long amt_sent = pkt_nr * nr_blocks * sizeof(pktbuf); -+ -+ gettimeofday(&now, NULL); -+ -+ time_msecs = (now.tv_sec - then.tv_sec) * 1000; -+ time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000; -+ printf(" (%ld KiB/s) ", -+ amt_sent / 1024 * 1000 / time_msecs); -+ } -+ -+ fflush(stdout); -+ -+#ifdef RANDOMDROP -+ if ((rand() % 1000) < 20) { -+ printf("\nDropping packet %d of block %08x\n", pkt_nr+1, block_nr * erasesize); -+ continue; -+ } -+#endif -+ gettimeofday(&now, NULL); -+#if 1 -+ tosleep = nextpkt.tv_usec - now.tv_usec + -+ (1000000 * (nextpkt.tv_sec - now.tv_sec)); -+ -+ /* We need hrtimers for this to actually work */ -+ if (tosleep > 0) { -+ struct timespec req; -+ -+ req.tv_nsec = (tosleep % 1000000) * 1000; -+ req.tv_sec = tosleep / 1000000; -+ -+ nanosleep(&req, NULL); -+ } -+#else -+ while (now.tv_sec < nextpkt.tv_sec || -+ (now.tv_sec == nextpkt.tv_sec && -+ now.tv_usec < nextpkt.tv_usec)) { -+ gettimeofday(&now, NULL); -+ } -+#endif -+ nextpkt.tv_usec += pkt_delay; -+ if (nextpkt.tv_usec >= 1000000) { -+ nextpkt.tv_sec += nextpkt.tv_usec / 1000000; -+ nextpkt.tv_usec %= 1000000; -+ } -+ -+ /* If the time for the next packet has already -+ passed (by some margin), then we've lost time -+ Adjust our expected timings accordingly. If -+ we're only a little way behind, don't slip yet */ -+ if (now.tv_usec > (now.tv_usec + (5 * pkt_delay) + -+ 1000000 * (nextpkt.tv_sec - now.tv_sec))) { -+ nextpkt = now; -+ } -+ -+ if (write(sock, &pktbuf, sizeof(pktbuf)) < 0) { -+ perror("write"); -+ writeerrors++; -+ if (writeerrors > 10) { -+ fprintf(stderr, "Too many consecutive write errors\n"); -+ exit(1); -+ } -+ } else -+ writeerrors = 0; -+ -+ -+ -+ } -+ } -+ munmap(image, st.st_size); -+ close(rfd); -+ close(sock); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/summary.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/summary.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,178 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2004 Ferenc Havasi , -+ * Zoltan Sogor , -+ * Patrik Kluba , -+ * University of Szeged, Hungary -+ * -+ * For licensing information, see the file 'LICENCE' in this directory. -+ */ -+ -+#ifndef JFFS2_SUMMARY_H -+#define JFFS2_SUMMARY_H -+ -+#include -+#include -+ -+#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ -+ c->free_size -= _x; c->dirty_size += _x; \ -+ jeb->free_size -= _x ; jeb->dirty_size += _x; \ -+}while(0) -+#define USED_SPACE(x) do { typeof(x) _x = (x); \ -+ c->free_size -= _x; c->used_size += _x; \ -+ jeb->free_size -= _x ; jeb->used_size += _x; \ -+}while(0) -+#define WASTED_SPACE(x) do { typeof(x) _x = (x); \ -+ c->free_size -= _x; c->wasted_size += _x; \ -+ jeb->free_size -= _x ; jeb->wasted_size += _x; \ -+}while(0) -+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \ -+ c->free_size -= _x; c->unchecked_size += _x; \ -+ jeb->free_size -= _x ; jeb->unchecked_size += _x; \ -+}while(0) -+ -+#define BLK_STATE_ALLFF 0 -+#define BLK_STATE_CLEAN 1 -+#define BLK_STATE_PARTDIRTY 2 -+#define BLK_STATE_CLEANMARKER 3 -+#define BLK_STATE_ALLDIRTY 4 -+#define BLK_STATE_BADBLOCK 5 -+ -+#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff -+#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash)) -+#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x)) -+#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash)) -+#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash)) -+ -+/* Summary structures used on flash */ -+ -+struct jffs2_sum_unknown_flash -+{ -+ jint16_t nodetype; /* node type */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_inode_flash -+{ -+ jint16_t nodetype; /* node type */ -+ jint32_t inode; /* inode number */ -+ jint32_t version; /* inode version */ -+ jint32_t offset; /* offset on jeb */ -+ jint32_t totlen; /* record length */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_dirent_flash -+{ -+ jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ -+ jint32_t totlen; /* record length */ -+ jint32_t offset; /* ofset on jeb */ -+ jint32_t pino; /* parent inode */ -+ jint32_t version; /* dirent version */ -+ jint32_t ino; /* == zero for unlink */ -+ uint8_t nsize; /* dirent name size */ -+ uint8_t type; /* dirent type */ -+ uint8_t name[0]; /* dirent name */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_xattr_flash -+{ -+ jint16_t nodetype; /* == JFFS2_NODETYPE_XATR */ -+ jint32_t xid; /* xattr identifier */ -+ jint32_t version; /* version number */ -+ jint32_t offset; /* offset on jeb */ -+ jint32_t totlen; /* node length */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_xref_flash -+{ -+ jint16_t nodetype; /* == JFFS2_NODETYPE_XREF */ -+ jint32_t offset; /* offset on jeb */ -+} __attribute__((packed)); -+ -+union jffs2_sum_flash -+{ -+ struct jffs2_sum_unknown_flash u; -+ struct jffs2_sum_inode_flash i; -+ struct jffs2_sum_dirent_flash d; -+ struct jffs2_sum_xattr_flash x; -+ struct jffs2_sum_xref_flash r; -+}; -+ -+/* Summary structures used in the memory */ -+ -+struct jffs2_sum_unknown_mem -+{ -+ union jffs2_sum_mem *next; -+ jint16_t nodetype; /* node type */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_inode_mem -+{ -+ union jffs2_sum_mem *next; -+ jint16_t nodetype; /* node type */ -+ jint32_t inode; /* inode number */ -+ jint32_t version; /* inode version */ -+ jint32_t offset; /* offset on jeb */ -+ jint32_t totlen; /* record length */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_dirent_mem -+{ -+ union jffs2_sum_mem *next; -+ jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ -+ jint32_t totlen; /* record length */ -+ jint32_t offset; /* ofset on jeb */ -+ jint32_t pino; /* parent inode */ -+ jint32_t version; /* dirent version */ -+ jint32_t ino; /* == zero for unlink */ -+ uint8_t nsize; /* dirent name size */ -+ uint8_t type; /* dirent type */ -+ uint8_t name[0]; /* dirent name */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_xattr_mem -+{ -+ union jffs2_sum_mem *next; -+ jint16_t nodetype; -+ jint32_t xid; -+ jint32_t version; -+ jint32_t offset; -+ jint32_t totlen; -+} __attribute__((packed)); -+ -+struct jffs2_sum_xref_mem -+{ -+ union jffs2_sum_mem *next; -+ jint16_t nodetype; -+ jint32_t offset; -+} __attribute__((packed)); -+ -+union jffs2_sum_mem -+{ -+ struct jffs2_sum_unknown_mem u; -+ struct jffs2_sum_inode_mem i; -+ struct jffs2_sum_dirent_mem d; -+ struct jffs2_sum_xattr_mem x; -+ struct jffs2_sum_xref_mem r; -+}; -+ -+struct jffs2_summary -+{ -+ uint32_t sum_size; -+ uint32_t sum_num; -+ uint32_t sum_padded; -+ union jffs2_sum_mem *sum_list_head; -+ union jffs2_sum_mem *sum_list_tail; -+}; -+ -+/* Summary marker is stored at the end of every sumarized erase block */ -+ -+struct jffs2_sum_marker -+{ -+ jint32_t offset; /* offset of the summary node in the jeb */ -+ jint32_t magic; /* == JFFS2_SUM_MAGIC */ -+}; -+ -+#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker)) -+ -+#endif ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/sumtool.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/sumtool.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,951 @@ -+/* -+ * sumtool.c -+ * -+ * Copyright (C) 2004 Zoltan Sogor , -+ * Ferenc Havasi -+ * University of Szeged, Hungary -+ * 2006 KaiGai Kohei -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Overview: -+ * This is a utility insert summary information into JFFS2 image for -+ * faster mount time -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+#include "summary.h" -+ -+#define PAD(x) (((x)+3)&~3) -+ -+static const char *const app_name = "sumtool"; -+ -+static struct jffs2_summary *sum_collected = NULL; -+ -+static int verbose = 0; -+static int padto = 0; /* pad the output with 0xFF to the end of the final eraseblock */ -+static int add_cleanmarkers = 1; /* add cleanmarker to output */ -+static int use_input_cleanmarker_size = 1; /* use input file's cleanmarker size (default) */ -+static int found_cleanmarkers = 0; /* cleanmarker found in input file */ -+static struct jffs2_unknown_node cleanmarker; -+static int cleanmarker_size = sizeof(cleanmarker); -+static const char *short_options = "o:i:e:hvVblnc:p"; -+static int erase_block_size = 65536; -+static int out_fd = -1; -+static int in_fd = -1; -+ -+static uint8_t *data_buffer = NULL; /* buffer for inodes */ -+static unsigned int data_ofs = 0; /* inode buffer offset */ -+ -+static uint8_t *file_buffer = NULL; /* file buffer contains the actual erase block*/ -+static unsigned int file_ofs = 0; /* position in the buffer */ -+ -+int target_endian = __BYTE_ORDER; -+ -+static struct option long_options[] = { -+ {"output", 1, NULL, 'o'}, -+ {"input", 1, NULL, 'i'}, -+ {"eraseblock", 1, NULL, 'e'}, -+ {"help", 0, NULL, 'h'}, -+ {"verbose", 0, NULL, 'v'}, -+ {"version", 0, NULL, 'V'}, -+ {"bigendian", 0, NULL, 'b'}, -+ {"littleendian", 0, NULL, 'l'}, -+ {"no-cleanmarkers", 0, NULL, 'n'}, -+ {"cleanmarker", 1, NULL, 'c'}, -+ {"pad", 0, NULL, 'p'}, -+ {NULL, 0, NULL, 0} -+}; -+ -+static char *helptext = -+"Usage: sumtool [OPTIONS] -i inputfile -o outputfile\n\n" -+"Convert the input JFFS2 image to a summarized JFFS2 image\n" -+"Summary makes mounting faster - if summary support enabled in your kernel\n\n" -+"Options:\n" -+" -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)\n" -+" (usually 16KiB on NAND)\n" -+" -c, --cleanmarker=SIZE Size of cleanmarker (default 12).\n" -+" (usually 16 bytes on NAND, and will be set to\n" -+" this value if left at the default 12). Will be\n" -+" stored in OOB after each physical page composing\n" -+" a physical eraseblock.\n" -+" -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock\n" -+" -o, --output=FILE Output to FILE \n" -+" -i, --input=FILE Input from FILE \n" -+" -b, --bigendian Image is big endian\n" -+" -l --littleendian Image is little endian\n" -+" -h, --help Display this help text\n" -+" -v, --verbose Verbose operation\n" -+" -V, --version Display version information\n" -+" -p, --pad Pad the OUTPUT with 0xFF to the end of the final\n" -+" eraseblock\n\n"; -+ -+ -+static char *revtext = "$Revision: 1.1.1.1 $"; -+ -+static unsigned char ffbuf[16] = { -+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -+}; -+ -+static void verror_msg(const char *s, va_list p) -+{ -+ fflush(stdout); -+ fprintf(stderr, "%s: ", app_name); -+ vfprintf(stderr, s, p); -+} -+ -+static void error_msg_and_die(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ verror_msg(s, p); -+ va_end(p); -+ putc('\n', stderr); -+ exit(EXIT_FAILURE); -+} -+ -+static void vperror_msg(const char *s, va_list p) -+{ -+ int err = errno; -+ -+ if (s == 0) -+ s = ""; -+ verror_msg(s, p); -+ if (*s) -+ s = ": "; -+ fprintf(stderr, "%s%s\n", s, strerror(err)); -+} -+ -+static void perror_msg_and_die(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ vperror_msg(s, p); -+ va_end(p); -+ exit(EXIT_FAILURE); -+} -+ -+ -+ -+static void full_write(void *target_buff, const void *buf, int len); -+ -+void setup_cleanmarker() -+{ -+ cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); -+ cleanmarker.totlen = cpu_to_je32(cleanmarker_size); -+ cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4)); -+} -+ -+void process_options (int argc, char **argv) -+{ -+ int opt,c; -+ -+ while ((opt = getopt_long(argc, argv, short_options, long_options, &c)) >= 0) { -+ switch (opt) { -+ case 'o': -+ if (out_fd != -1) -+ error_msg_and_die("output filename specified more than once"); -+ out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644); -+ if (out_fd == -1) -+ perror_msg_and_die("open output file"); -+ break; -+ -+ case 'i': -+ if (in_fd != -1) -+ error_msg_and_die("input filename specified more than once"); -+ in_fd = open(optarg, O_RDONLY); -+ if (in_fd == -1) -+ perror_msg_and_die("open input file"); -+ break; -+ case 'b': -+ target_endian = __BIG_ENDIAN; -+ break; -+ case 'l': -+ target_endian = __LITTLE_ENDIAN; -+ break; -+ case 'h': -+ case '?': -+ error_msg_and_die(helptext); -+ case 'v': -+ verbose = 1; -+ break; -+ -+ case 'V': -+ error_msg_and_die("revision %.*s\n", -+ (int) strlen(revtext) - 13, revtext + 11); -+ -+ case 'e': { -+ char *next; -+ unsigned units = 0; -+ erase_block_size = strtol(optarg, &next, 0); -+ if (!erase_block_size) -+ error_msg_and_die("Unrecognisable erase size\n"); -+ -+ if (*next) { -+ if (!strcmp(next, "KiB")) { -+ units = 1024; -+ } else if (!strcmp(next, "MiB")) { -+ units = 1024 * 1024; -+ } else { -+ error_msg_and_die("Unknown units in erasesize\n"); -+ } -+ } else { -+ if (erase_block_size < 0x1000) -+ units = 1024; -+ else -+ units = 1; -+ } -+ erase_block_size *= units; -+ -+ /* If it's less than 8KiB, they're not allowed */ -+ if (erase_block_size < 0x2000) { -+ fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n", -+ erase_block_size); -+ erase_block_size = 0x2000; -+ } -+ break; -+ } -+ -+ case 'n': -+ add_cleanmarkers = 0; -+ break; -+ case 'c': -+ cleanmarker_size = strtol(optarg, NULL, 0); -+ -+ if (cleanmarker_size < sizeof(cleanmarker)) { -+ error_msg_and_die("cleanmarker size must be >= 12"); -+ } -+ if (cleanmarker_size >= erase_block_size) { -+ error_msg_and_die("cleanmarker size must be < eraseblock size"); -+ } -+ -+ use_input_cleanmarker_size = 0; -+ found_cleanmarkers = 1; -+ setup_cleanmarker(); -+ -+ break; -+ case 'p': -+ padto = 1; -+ break; -+ } -+ } -+} -+ -+ -+void init_buffers() -+{ -+ data_buffer = malloc(erase_block_size); -+ -+ if (!data_buffer) { -+ perror("out of memory"); -+ close (in_fd); -+ close (out_fd); -+ exit(1); -+ } -+ -+ file_buffer = malloc(erase_block_size); -+ -+ if (!file_buffer) { -+ perror("out of memory"); -+ close (in_fd); -+ close (out_fd); -+ exit(1); -+ } -+} -+ -+void init_sumlist() -+{ -+ sum_collected = (struct jffs2_summary *) malloc (sizeof(struct jffs2_summary)); -+ -+ if (!sum_collected) -+ error_msg_and_die("Can't allocate memory for jffs2_summary!\n"); -+ -+ memset(sum_collected, 0, sizeof(struct jffs2_summary)); -+} -+ -+void clean_buffers() -+{ -+ if (data_buffer) -+ free(data_buffer); -+ if (file_buffer) -+ free(file_buffer); -+} -+ -+void clean_sumlist() -+{ -+ union jffs2_sum_mem *temp; -+ -+ if (sum_collected) { -+ -+ while (sum_collected->sum_list_head) { -+ temp = sum_collected->sum_list_head; -+ sum_collected->sum_list_head = sum_collected->sum_list_head->u.next; -+ free(temp); -+ sum_collected->sum_num--; -+ } -+ -+ if (sum_collected->sum_num != 0) -+ printf("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???"); -+ -+ free(sum_collected); -+ } -+} -+ -+int load_next_block() -+{ -+ int ret; -+ ret = read(in_fd, file_buffer, erase_block_size); -+ file_ofs = 0; -+ -+ if (verbose) -+ printf("Load next block : %d bytes read\n",ret); -+ -+ return ret; -+} -+ -+void write_buff_to_file() -+{ -+ int ret; -+ int len = data_ofs; -+ -+ uint8_t *buf = NULL; -+ -+ buf = data_buffer; -+ while (len > 0) { -+ ret = write(out_fd, buf, len); -+ -+ if (ret < 0) -+ perror_msg_and_die("write"); -+ -+ if (ret == 0) -+ perror_msg_and_die("write returned zero"); -+ -+ len -= ret; -+ buf += ret; -+ } -+ -+ data_ofs = 0; -+} -+ -+void dump_sum_records() -+{ -+ -+ struct jffs2_raw_summary isum; -+ struct jffs2_sum_marker *sm; -+ union jffs2_sum_mem *temp; -+ jint32_t offset; -+ jint32_t *tpage; -+ void *wpage; -+ int datasize, infosize, padsize; -+ jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC); -+ -+ if (!sum_collected->sum_num || !sum_collected->sum_list_head) -+ return; -+ -+ datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker); -+ infosize = sizeof(struct jffs2_raw_summary) + datasize; -+ padsize = erase_block_size - data_ofs - infosize; -+ infosize += padsize; datasize += padsize; -+ offset = cpu_to_je32(data_ofs); -+ -+ tpage = (jint32_t *) malloc(datasize); -+ -+ if(!tpage) -+ error_msg_and_die("Can't allocate memory to dump summary information!\n"); -+ -+ memset(tpage, 0xff, datasize); -+ memset(&isum, 0, sizeof(isum)); -+ -+ isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY); -+ isum.totlen = cpu_to_je32(infosize); -+ isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4)); -+ isum.padded = cpu_to_je32(0); -+ -+ if (add_cleanmarkers && found_cleanmarkers) { -+ isum.cln_mkr = cpu_to_je32(cleanmarker_size); -+ } else { -+ isum.cln_mkr = cpu_to_je32(0); -+ } -+ -+ isum.sum_num = cpu_to_je32(sum_collected->sum_num); -+ wpage = tpage; -+ -+ while (sum_collected->sum_num) { -+ switch(je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) { -+ -+ case JFFS2_NODETYPE_INODE : { -+ struct jffs2_sum_inode_flash *sino_ptr = wpage; -+ -+ sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype; -+ sino_ptr->inode = sum_collected->sum_list_head->i.inode; -+ sino_ptr->version = sum_collected->sum_list_head->i.version; -+ sino_ptr->offset = sum_collected->sum_list_head->i.offset; -+ sino_ptr->totlen = sum_collected->sum_list_head->i.totlen; -+ -+ wpage += JFFS2_SUMMARY_INODE_SIZE; -+ break; -+ } -+ -+ case JFFS2_NODETYPE_DIRENT : { -+ struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage; -+ -+ sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype; -+ sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen; -+ sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset; -+ sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino; -+ sdrnt_ptr->version = sum_collected->sum_list_head->d.version; -+ sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino; -+ sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize; -+ sdrnt_ptr->type = sum_collected->sum_list_head->d.type; -+ -+ memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name, -+ sum_collected->sum_list_head->d.nsize); -+ -+ wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize); -+ break; -+ } -+ -+ case JFFS2_NODETYPE_XATTR: { -+ struct jffs2_sum_xattr_flash *sxattr_ptr = wpage; -+ -+ sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype; -+ sxattr_ptr->xid = sum_collected->sum_list_head->x.xid; -+ sxattr_ptr->version = sum_collected->sum_list_head->x.version; -+ sxattr_ptr->offset = sum_collected->sum_list_head->x.offset; -+ sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen; -+ -+ wpage += JFFS2_SUMMARY_XATTR_SIZE; -+ break; -+ } -+ -+ case JFFS2_NODETYPE_XREF: { -+ struct jffs2_sum_xref_flash *sxref_ptr = wpage; -+ -+ sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype; -+ sxref_ptr->offset = sum_collected->sum_list_head->r.offset; -+ -+ wpage += JFFS2_SUMMARY_XREF_SIZE; -+ break; -+ } -+ -+ default : { -+ printf("Unknown node type!\n"); -+ } -+ } -+ -+ temp = sum_collected->sum_list_head; -+ sum_collected->sum_list_head = sum_collected->sum_list_head->u.next; -+ free(temp); -+ -+ sum_collected->sum_num--; -+ } -+ -+ sum_collected->sum_size = 0; -+ sum_collected->sum_num = 0; -+ sum_collected->sum_list_tail = NULL; -+ -+ wpage += padsize; -+ -+ sm = wpage; -+ sm->offset = offset; -+ sm->magic = magic; -+ -+ isum.sum_crc = cpu_to_je32(crc32(0, tpage, datasize)); -+ isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8)); -+ -+ full_write(data_buffer + data_ofs, &isum, sizeof(isum)); -+ full_write(data_buffer + data_ofs, tpage, datasize); -+ -+ free(tpage); -+} -+ -+static void full_write(void *target_buff, const void *buf, int len) -+{ -+ memcpy(target_buff, buf, len); -+ data_ofs += len; -+} -+ -+static void pad(int req) -+{ -+ while (req) { -+ if (req > sizeof(ffbuf)) { -+ full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf)); -+ req -= sizeof(ffbuf); -+ } else { -+ full_write(data_buffer + data_ofs, ffbuf, req); -+ req = 0; -+ } -+ } -+} -+ -+static inline void padword() -+{ -+ if (data_ofs % 4) -+ full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4)); -+} -+ -+ -+static inline void pad_block_if_less_than(int req,int plus) -+{ -+ -+ int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8; -+ datasize += (4 - (datasize % 4)) % 4; -+ -+ if (data_ofs + req > erase_block_size - datasize) { -+ dump_sum_records(); -+ write_buff_to_file(); -+ } -+ -+ if (add_cleanmarkers && found_cleanmarkers) { -+ if (!data_ofs) { -+ full_write(data_buffer, &cleanmarker, sizeof(cleanmarker)); -+ pad(cleanmarker_size - sizeof(cleanmarker)); -+ padword(); -+ } -+ } -+} -+ -+void flush_buffers() -+{ -+ -+ if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */ -+ if (data_ofs != cleanmarker_size) { /* INODE BUFFER */ -+ -+ int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8; -+ datasize += (4 - (datasize % 4)) % 4; -+ -+ /* If we have a full inode buffer, then write out inode and summary data */ -+ if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) { -+ dump_sum_records(); -+ write_buff_to_file(); -+ } else { /* else just write out inode data */ -+ if (padto) -+ pad(erase_block_size - data_ofs); -+ write_buff_to_file(); -+ } -+ } -+ } else { /* NO CLEANMARKER */ -+ if (data_ofs != 0) { /* INODE BUFFER */ -+ -+ int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8; -+ datasize += (4 - (datasize % 4)) % 4; -+ -+ /* If we have a full inode buffer, then write out inode and summary data */ -+ if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) { -+ dump_sum_records(); -+ write_buff_to_file(); -+ } else { /* Else just write out inode data */ -+ if(padto) -+ pad(erase_block_size - data_ofs); -+ write_buff_to_file(); -+ } -+ } -+ } -+} -+ -+int add_sum_mem(union jffs2_sum_mem *item) -+{ -+ -+ if (!sum_collected->sum_list_head) -+ sum_collected->sum_list_head = (union jffs2_sum_mem *) item; -+ if (sum_collected->sum_list_tail) -+ sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item; -+ sum_collected->sum_list_tail = (union jffs2_sum_mem *) item; -+ -+ switch (je16_to_cpu(item->u.nodetype)) { -+ case JFFS2_NODETYPE_INODE: -+ sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE; -+ sum_collected->sum_num++; -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize); -+ sum_collected->sum_num++; -+ break; -+ -+ case JFFS2_NODETYPE_XATTR: -+ sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE; -+ sum_collected->sum_num++; -+ break; -+ -+ case JFFS2_NODETYPE_XREF: -+ sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE; -+ sum_collected->sum_num++; -+ break; -+ -+ default: -+ error_msg_and_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype)); -+ } -+ return 0; -+} -+ -+void add_sum_inode_mem(union jffs2_node_union *node) -+{ -+ struct jffs2_sum_inode_mem *temp = (struct jffs2_sum_inode_mem *) malloc(sizeof(struct jffs2_sum_inode_mem)); -+ -+ if (!temp) -+ error_msg_and_die("Can't allocate memory for summary information!\n"); -+ -+ temp->nodetype = node->i.nodetype; -+ temp->inode = node->i.ino; -+ temp->version = node->i.version; -+ temp->offset = cpu_to_je32(data_ofs); -+ temp->totlen = node->i.totlen; -+ temp->next = NULL; -+ -+ add_sum_mem((union jffs2_sum_mem *) temp); -+} -+ -+void add_sum_dirent_mem(union jffs2_node_union *node) -+{ -+ struct jffs2_sum_dirent_mem *temp = (struct jffs2_sum_dirent_mem *) -+ malloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize); -+ -+ if (!temp) -+ error_msg_and_die("Can't allocate memory for summary information!\n"); -+ -+ temp->nodetype = node->d.nodetype; -+ temp->totlen = node->d.totlen; -+ temp->offset = cpu_to_je32(data_ofs); -+ temp->pino = node->d.pino; -+ temp->version = node->d.version; -+ temp->ino = node->d.ino; -+ temp->nsize = node->d.nsize; -+ temp->type = node->d.type; -+ temp->next = NULL; -+ -+ memcpy(temp->name,node->d.name,node->d.nsize); -+ add_sum_mem((union jffs2_sum_mem *) temp); -+} -+ -+void add_sum_xattr_mem(union jffs2_node_union *node) -+{ -+ struct jffs2_sum_xattr_mem *temp = (struct jffs2_sum_xattr_mem *) -+ malloc(sizeof(struct jffs2_sum_xattr_mem)); -+ if (!temp) -+ error_msg_and_die("Can't allocate memory for summary information!\n"); -+ -+ temp->nodetype = node->x.nodetype; -+ temp->xid = node->x.xid; -+ temp->version = node->x.version; -+ temp->offset = cpu_to_je32(data_ofs); -+ temp->totlen = node->x.totlen; -+ temp->next = NULL; -+ -+ add_sum_mem((union jffs2_sum_mem *) temp); -+} -+ -+void add_sum_xref_mem(union jffs2_node_union *node) -+{ -+ struct jffs2_sum_xref_mem *temp = (struct jffs2_sum_xref_mem *) -+ malloc(sizeof(struct jffs2_sum_xref_mem)); -+ if (!temp) -+ error_msg_and_die("Can't allocate memory for summary information!\n"); -+ -+ temp->nodetype = node->r.nodetype; -+ temp->offset = cpu_to_je32(data_ofs); -+ temp->next = NULL; -+ -+ add_sum_mem((union jffs2_sum_mem *) temp); -+} -+ -+void write_dirent_to_buff(union jffs2_node_union *node) -+{ -+ pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize)); -+ add_sum_dirent_mem(node); -+ full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen)); -+ padword(); -+} -+ -+ -+void write_inode_to_buff(union jffs2_node_union *node) -+{ -+ pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE); -+ add_sum_inode_mem(node); /* Add inode summary mem to summary list */ -+ full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen)); /* Write out the inode to inode_buffer */ -+ padword(); -+} -+ -+void write_xattr_to_buff(union jffs2_node_union *node) -+{ -+ pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE); -+ add_sum_xattr_mem(node); /* Add xdatum summary mem to summary list */ -+ full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen)); -+ padword(); -+} -+ -+void write_xref_to_buff(union jffs2_node_union *node) -+{ -+ pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE); -+ add_sum_xref_mem(node); /* Add xref summary mem to summary list */ -+ full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen)); -+ padword(); -+} -+ -+void create_summed_image(int inp_size) -+{ -+ uint8_t *p = file_buffer; -+ union jffs2_node_union *node; -+ uint32_t crc, length; -+ uint16_t type; -+ int bitchbitmask = 0; -+ int obsolete; -+ char name[256]; -+ -+ while ( p < (file_buffer + inp_size)) { -+ -+ node = (union jffs2_node_union *) p; -+ -+ /* Skip empty space */ -+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) { -+ p += 4; -+ continue; -+ } -+ -+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) { -+ if (!bitchbitmask++) -+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic)); -+ p += 4; -+ continue; -+ } -+ -+ bitchbitmask = 0; -+ -+ type = je16_to_cpu(node->u.nodetype); -+ if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) { -+ obsolete = 1; -+ type |= JFFS2_NODE_ACCURATE; -+ } else { -+ obsolete = 0; -+ } -+ -+ node->u.nodetype = cpu_to_je16(type); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4); -+ if (crc != je32_to_cpu (node->u.hdr_crc)) { -+ printf ("Wrong hdr_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc); -+ p += 4; -+ continue; -+ } -+ -+ switch(je16_to_cpu(node->u.nodetype)) { -+ case JFFS2_NODETYPE_INODE: -+ if (verbose) -+ printf ("%8s Inode node at 0x%08x, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino), -+ je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize), -+ je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset)); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8); -+ if (crc != je32_to_cpu (node->i.node_crc)) { -+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.node_crc), crc); -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ continue; -+ } -+ -+ crc = crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize)); -+ if (crc != je32_to_cpu(node->i.data_crc)) { -+ printf ("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.data_crc), crc); -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ continue; -+ } -+ -+ write_inode_to_buff(node); -+ -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ memcpy (name, node->d.name, node->d.nsize); -+ name [node->d.nsize] = 0x0; -+ -+ if (verbose) -+ printf ("%8s Dirent node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino), -+ je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino), -+ node->d.nsize, name); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8); -+ if (crc != je32_to_cpu (node->d.node_crc)) { -+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.node_crc), crc); -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ continue; -+ } -+ -+ crc = crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize); -+ if (crc != je32_to_cpu(node->d.name_crc)) { -+ printf ("Wrong name_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.name_crc), crc); -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ continue; -+ } -+ -+ write_dirent_to_buff(node); -+ -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_XATTR: -+ if (je32_to_cpu(node->x.node_crc) == 0xffffffff) -+ obsolete = 1; -+ if (verbose) -+ printf("%8s Xdatum node at 0x%08x, totlen 0x%08x, " -+ "#xid %5u, version %5u\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->x.totlen), -+ je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version)); -+ crc = crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4); -+ if (crc != je32_to_cpu(node->x.node_crc)) { -+ printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", -+ p - file_buffer, je32_to_cpu(node->x.node_crc), crc); -+ p += PAD(je32_to_cpu (node->x.totlen)); -+ continue; -+ } -+ length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len); -+ crc = crc32(0, node->x.data, length); -+ if (crc != je32_to_cpu(node->x.data_crc)) { -+ printf("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n", -+ p - file_buffer, je32_to_cpu(node->x.data_crc), crc); -+ p += PAD(je32_to_cpu (node->x.totlen)); -+ continue; -+ } -+ -+ write_xattr_to_buff(node); -+ p += PAD(je32_to_cpu (node->x.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_XREF: -+ if (je32_to_cpu(node->r.node_crc) == 0xffffffff) -+ obsolete = 1; -+ if (verbose) -+ printf("%8s Xref node at 0x%08x, totlen 0x%08x, " -+ "#ino %5u, xid %5u\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu(node->r.totlen), -+ je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid)); -+ crc = crc32(0, node, sizeof (struct jffs2_raw_xref) - 4); -+ if (crc != je32_to_cpu(node->r.node_crc)) { -+ printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", -+ p - file_buffer, je32_to_cpu(node->r.node_crc), crc); -+ p += PAD(je32_to_cpu (node->r.totlen)); -+ continue; -+ } -+ -+ write_xref_to_buff(node); -+ p += PAD(je32_to_cpu (node->r.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_CLEANMARKER: -+ if (verbose) { -+ printf ("%8s Cleanmarker at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ -+ if (!found_cleanmarkers) { -+ found_cleanmarkers = 1; -+ -+ if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){ -+ cleanmarker_size = je32_to_cpu (node->u.totlen); -+ setup_cleanmarker(); -+ } -+ } -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_PADDING: -+ if (verbose) { -+ printf ("%8s Padding node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case 0xffff: -+ p += 4; -+ break; -+ -+ default: -+ if (verbose) { -+ printf ("%8s Unknown node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ } -+ } -+} -+ -+int main(int argc, char **argv) -+{ -+ int ret; -+ -+ process_options(argc,argv); -+ -+ if ((in_fd == -1) || (out_fd == -1)) { -+ if(in_fd != -1) -+ close(in_fd); -+ if(out_fd != -1) -+ close(out_fd); -+ fprintf(stderr,helptext); -+ error_msg_and_die("You must specify input and output files!\n"); -+ } -+ -+ init_buffers(); -+ init_sumlist(); -+ -+ while ((ret = load_next_block())) { -+ create_summed_image(ret); -+ } -+ -+ flush_buffers(); -+ clean_buffers(); -+ clean_sumlist(); -+ -+ if (in_fd != -1) -+ close(in_fd); -+ if (out_fd != -1) -+ close(out_fd); -+ -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,14 @@ -+ -+all: checkfs makefiles -+ -+checkfs: checkfs.c Makefile common.h comm.o -+ gcc -g -Wall checkfs.c comm.o -o checkfs -+ -+comm.o: comm.c Makefile -+ gcc -g -Wall -c comm.c -o comm.o -+ -+makefiles: makefiles.c Makefile common.h -+ gcc -g -Wall makefiles.c -o makefiles -+ -+clean: -+ rm -f makefiles checkfs *~ *.o ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/README 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,173 @@ -+$Id: README,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+$Log: not supported by cvs2svn $ -+Revision 1.2 2001/06/21 23:07:06 dwmw2 -+Initial import to MTD CVS -+ -+Revision 1.1 2001/06/11 19:34:40 vipin -+Added README file to dir. -+ -+ -+This is the README file for the "checkfs" power fail test program. -+By: Vipin Malik -+ -+NOTE: This program requires an external "power cycling box" -+connected to one of the com ports of the system under test. -+This power cycling box should wait for a random amount of time -+after it receives a "ok to power me down" message over the -+serial port, and then yank power to the system under test. -+(The box that I rigged up tested with waits anywhere from -+0 to ~40 seconds). -+ -+ -+It should then restore power after a few seconds and wait for the -+message again. -+ -+ -+ABOUT: -+ -+This program's primary purpose it to test the reliiability -+of various file systems under Linux. -+ -+SETUP: -+ -+You need to setup the file system you want to test and run the -+"makefiles" program ONCE. This creates a set of files that are -+required by the "checkfs" program. -+ -+Also copy the "checkfs" executable program to the same dir. -+ -+Then you need to make sure that the program "checkfs" is called -+automatically on startup. You can customise the operation of -+the "checkfs" program by passing it various cmd line arguments. -+run "checkfs -?" for more details. -+ -+****NOTE******* -+Make sure that you call the checkfs program only after you have -+mounted the file system you want to test (this is obvious), but -+also after you have run any "scan" utilities to check for and -+fix any file systems errors. The e2fsck is one utility for the -+ext2 file system. For an automated setup you of course need to -+provide these scan programs to run in standalone mode (-f -y -+flags for e2fsck for example). -+ -+File systems like JFFS and JFFS2 do not have any such external -+utilities and you may call "checkfs" right after you have mounted -+the respective file system under test. -+ -+There are two ways you can mount the file system under test: -+ -+1. Mount your root fs on a "standard" fs like ext2 and then -+mount the file system under test (which may be ext2 on another -+partition or device) and then run "checkfs" on this mounted -+partition OR -+ -+2. Make your fs AND device that you have put this fs as your -+root fs and run "checkfs" on the root device (i.e. "/"). -+You can of course still run checkfs under a separate dir -+under your "/" root dir. -+ -+I have found the second method to be a particularly stringent -+arrangement (and thus preferred when you are trying to break -+something). -+ -+Using this arrangement I was able to find that JFFS clobbered -+some "sister" files on the root fs even though "checkfs" would -+run fine through all its own check files. -+ -+(I found this out when one of the clobbered sister file happened -+to be /bin/bash. The system refused to run rc.local thus -+preventing my "checkfs" program from being launched :) -+ -+"checkfs": -+ -+The "formatting" reliability of the fs as well as the file data integrity -+of files on the fs can be checked using this program. -+ -+"formatiing" reliability can only be checked via an indirect method. -+If there is severe formatting reliability issues with the file system, -+it will most likely cause other system failures that will prevent this -+program from running successfully on a power up. This will prevent -+a "ok to power me down" message from going out to the power cycling -+black box and prevent power being turned off again. -+ -+File data reliability is checked more directly. A fixed number of -+files are created in the current dir (using the program "makefiles"). -+ -+Each file has a random number of bytes in it (set by using the -+-s cmd line flag). The number of "ints" in the file is stored as the -+first "int" in it (note: 0 length files are not allowed). Each file -+is then filled with random data and a 16 bit CRC appended at the end. -+ -+When "checkfs" is run, it runs through all files (with predetermined -+file names)- one at a time- and checks for the number of "int's" -+in it as well as the ending CRC. -+ -+The program exits if the numbers of files that are corrupt are greater -+that a user specified parameter (set by using the -e cmd line flag). -+ -+If the number of corrupt files is less than this parameter, the corrupt -+files are repaired and operation resumes as explained below. -+ -+The idea behind allowing a user specified amount of corrupt files is as -+follows: -+ -+If you are testing for "formatting" reliability of a fs, and for -+the data reliability of "other" files present of the fs, use -e 1. -+"other" files are defined as sister files on the fs, not being written to -+by the "checkfs" test program. -+ -+As mentioned, in this case you would set -e 1, or allow at most 1 file -+to be corrupt each time after a power fail. This would be the file -+that was probably being written to when power failed (and CRC was not -+updated to reflect the new data being written). You would check file -+systems like ext2 etc. with such a configuration. -+(As you have no hope that these file systems provide for either your -+new data or old data to be present in the file if power failed during -+the write. This is called "roll back and recover".) -+ -+With JFFS2 I tested for such "roll back and recover" file data reliability -+by setting -e 0 and making sure that all writes to the file being -+updated are done in a *single* write(). -+ -+This is how I found that JFFS2 (yet) does NOT support this functionality. -+(There was a great debate if this was a bug or a feature that was lacking -+or even an issue at all. See the mtd archives for more details). -+ -+In other words, JFFS2 will partially update a file on FLASH even before -+the write() command has completed, thus leaving part old data part new -+data in your file if power failed in the middle of a write(). -+ -+This is bad functionality if you are updating a binary structure or a -+CRC protected file (as in our case). -+ -+ -+If All Files Check Out OK: -+ -+On the startup scan, if there are less errors than specified by the "-e flag" -+a "ok to power me down message" is sent via the specified com port. -+ -+The actual format of this message will depend on the format expected -+by the power cycling box that will receive this message. One may customise -+the actual message that goes out in the "do_pwr_dn)" routine in "comm.c". -+ -+This file is called with an open file descriptor to the comm port that -+this message needs to go out over and the count of the current power -+cycle (in case your power cycling box can display/log this count). -+ -+After this message has been sent out, the checkfs program goes into -+a while(1) loop of writing new data (with CRC), one at a time, into -+all the "check files" in the dir. -+ -+Its life comes to a sudden end when power is asynchronously pulled from -+under its feet (by your external power cycling box). -+ -+It comes back to life when power is restored and the system boots and -+checkfs is called from the rc.local script file. -+ -+The cycle then repeats till a problem is detected, at which point -+the "ok to power me down" message is not sent and the cycle stops -+waiting for the user to examine the system. -+ -+ -+ -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,695 @@ -+/* -+ -+ * Copyright Daniel Industries. -+ * -+ * Created by: Vipin Malik (vipin.malik@daniel.com) -+ * -+ * This code is released under the GPL version 2. See the file COPYING -+ * for more details. -+ * -+ * Software distributed under the Licence is distributed on an "AS IS" -+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -+ * See the Licence for the specific language governing rights and -+ * limitations under the Licence. -+ -+ This program opens files in progression (file00001, file00002 etc), -+ upto MAX_NUM_FILES and checks their CRC. If a file is not found or the -+ CRC does not match it stops it's operation. -+ -+ Everything is logged in a logfile called './logfile'. -+ -+ If everything is ok this program sends a signal, via com1, to the remote -+ power control box to power cycle this computer. -+ -+ This program then proceeds to create new files file0....file -+ in a endless loop and checksum each before closing them. -+ -+ STRUCTURE OF THE FILES: -+ The fist int is the size of the file in bytes. -+ The last 2 bytes are the CRC for the entire file. -+ There is random data in between. -+ -+ The files are opened in the current dir. -+ -+ $Id: checkfs.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Log: not supported by cvs2svn $ -+ Revision 1.8 2005/11/07 11:15:17 gleixner -+ [MTD / JFFS2] Clean up trailing white spaces -+ -+ Revision 1.7 2001/06/21 23:04:17 dwmw2 -+ Initial import to MTD CVS -+ -+ Revision 1.6 2001/06/08 22:26:05 vipin -+ Split the modbus comm part of the program (that sends the ok to pwr me down -+ message) into another file "comm.c" -+ -+ Revision 1.5 2001/06/08 21:29:56 vipin -+ fixed small issue with write() checking for < 0 instead of < (bytes to be written). -+ Now it does the latter (as it should). -+ -+ Revision 1.4 2001/05/11 22:29:40 vipin -+ Added a test to check and err out if the first int in file (which tells us -+ how many bytes there are in the file) is zero. This will prevent a corrupt -+ file with zero's in it from passing the crc test. -+ -+ Revision 1.3 2001/05/11 21:33:54 vipin -+ Changed to use write() rather than fwrite() when creating new file. Additionally, -+ and more important, it now does a single write() for the entire data. This will -+ enable us to use this program to test for power fail *data* reliability when -+ writing over an existing file, specially on powr fail "safe" file systems as -+ jffs/jffs2. Also added a new cmdline parameter "-e" that specifies the max # of -+ errors that can be tolerated. This should be set to ZERO to test for the above, -+ as old data should be reliabily maintained if the newer write never "took" before -+ power failed. If the write did succeed, then the newer data will have its own -+ CRC in place when it gets checked => hence no error. In theory at least! -+ -+ -+ Revision 1.2 2001/05/11 19:27:33 vipin -+ Added cmd line args to change serial port, and specify max size of -+ random files created. Some cleanup. Added -Wall to Makefile. -+ -+ Revision 1.1 2001/05/11 16:06:28 vipin -+ Importing checkfs (the power fail test program) into CVS. This was -+ originally done for NEWS. NEWS had a lot of version, this is -+ based off the last one done for NEWS. The "makefiles" program -+ is run once initially to create the files in the current dir. -+ "checkfs" is then run on every powerup to check consistancy -+ of the files. See checkfs.c for more details. -+ -+ -+*/ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "common.h" -+ -+ -+ -+extern int do_pwr_dn(int fd, int cycleCnt); -+ -+#define CMDLINE_PORT "-p" -+#define CMDLINE_MAXFILEBYTES "-s" -+#define CMDLINE_MAXERROR "-e" -+#define CMDLINE_HELPSHORT "-?" -+#define CMDLINE_HELPLONG "--help" -+ -+ -+int CycleCount; -+ -+char SerialDevice[255] = "/dev/ttyS0"; /* default, can be changed -+ through cmd line. */ -+ -+#define MAX_INTS_ALLOW 100000 /* max # of int's in the file written. -+ Statis limit to size struct. */ -+float FileSizeMax = 1024.0; /*= (file size in bytes), MUST be float*/ -+ -+int MaxErrAllowed = 1; /* default, can ge changed thru cmd line*/ -+ -+ -+/* Needed for CRC generation/checking */ -+static const unsigned short crc_ccitt_table[] = { -+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, -+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, -+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, -+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, -+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, -+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, -+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, -+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, -+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, -+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, -+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, -+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, -+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, -+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, -+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, -+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, -+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, -+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, -+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, -+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, -+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, -+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, -+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, -+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, -+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, -+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, -+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, -+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, -+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, -+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, -+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, -+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -+}; -+ -+ -+/* -+ Set's up the Linux serial port. Must be passed string to device to -+ open. Parameters are fixed to 9600,e,1 -+ -+ [A possible enhancement to this program would be to pass these -+ parameters via the command line.] -+ -+ Returns file descriptor to open port. Use this fd to write to port -+ and close it later, when done. -+*/ -+int setupSerial (const char *dev) { -+ int i, fd; -+ struct termios tios; -+ -+ fd = open(dev,O_RDWR | O_NDELAY ); -+ if (fd < 0) { -+ fprintf(stderr, "%s: %s\n", dev, sys_errlist[errno]); -+ exit(1); -+ } -+ if (tcgetattr(fd, &tios) < 0) { -+ fprintf(stderr,"Could not get terminal attributes: %s",sys_errlist[errno]); -+ exit(1); -+ } -+ -+ tios.c_cflag = -+ CS7 | -+ CREAD | // Enable Receiver -+ HUPCL | // Hangup after close -+ CLOCAL | // Ignore modem control lines -+ PARENB; // Enable parity (even by default) -+ -+ -+ -+ tios.c_iflag = IGNBRK; // Ignore break -+ tios.c_oflag = 0; -+ tios.c_lflag = 0; -+ for(i = 0; i < NCCS; i++) { -+ tios.c_cc[i] = '\0'; // no special characters -+ } -+ tios.c_cc[VMIN] = 1; -+ tios.c_cc[VTIME] = 0; -+ -+ cfsetospeed (&tios, B9600); -+ cfsetispeed (&tios, B9600); -+ -+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { -+ fprintf(stderr,"Could not set attributes: ,%s",sys_errlist[errno]); -+ exit(1); -+ } -+ return fd; -+} -+ -+ -+ -+ -+ -+//A portion of this code was taken from the AX.25 HDLC packet driver -+//in LINUX. Once I test and have a better understanding of what -+//it is doing, it will be better commented. -+ -+//For now one can speculate that the CRC routine always expects the -+//CRC to calculate out to 0xf0b8 (the hardcoded value at the end) -+//and returns TRUE if it is and FALSE if it doesn't. -+//Why don't people document better!!!! -+int check_crc_ccitt(char *filename) -+{ -+ FILE *fp; -+ FILE *logfp; -+ unsigned short crc = 0xffff; -+ int len; -+ char dataByte; -+ int retry; -+ char done; -+ -+ fp = fopen(filename,"rb"); -+ if(!fp){ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ fprintf(logfp, "Verify checksum:Error! Cannot open filename passed for verify checksum: %s\n",filename); -+ fclose(logfp); -+ return FALSE; -+ } -+ -+ -+ /*the first int contains an int that is the length of the file in long.*/ -+ if(fread(&len, sizeof(int), 1, fp) != 1){ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ fprintf(logfp, "verify checksum:Error reading from file: %s\n", filename); -+ fclose(fp); -+ fclose(logfp); -+ return FALSE; -+ } -+ -+ /* printf("Checking %i bytes for CRC in \"%s\".\n", len, filename); */ -+ -+ /* Make sure that we did not read 0 as the number of bytes in file. This -+ check prevents a corrupt file with zero's in it from passing the -+ CRC test. A good file will always have some data in it. */ -+ if(len == 0) -+ { -+ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ fprintf(logfp, "verify checksum: first int claims there are 0 data in file. Error!: %s\n", filename); -+ fclose(fp); -+ fclose(logfp); -+ return FALSE; -+ } -+ -+ -+ rewind(fp); -+ len+=2; /*the file has two extra bytes at the end, it's checksum. Those -+ two MUST also be included in the checksum calculation. -+ */ -+ -+ for (;len>0;len--){ -+ retry=5; /*retry 5 times*/ -+ done = FALSE; -+ while(!done){ -+ if(fread(&dataByte, sizeof(char), 1, fp) != 1){ -+ retry--; -+ }else{ -+ done = TRUE; -+ } -+ if(retry == 0){ -+ done = TRUE; -+ } -+ } -+ if(!retry){ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ fprintf(logfp, "Unexpected end of file: %s\n", filename); -+ fprintf(logfp, "...bytes left to be read %i.\n",len); -+ fclose(logfp); -+ fclose(fp); -+ return FALSE; -+ } -+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff]; -+ } -+ fclose(fp); -+ if( (crc & 0xffff) != 0xf0b8){ -+ /*printf("The CRC of read file:%x\n", crc); */ -+ return FALSE; -+ } -+ return TRUE; -+}/*end check_crc_ccitt() */ -+ -+ -+ -+/* -+ Sends "OK to power me down" message to the remote -+ power cycling box, via the serial port. -+ Also updates the num power cycle count in a local -+ file. -+ This file "./cycleCnt" must be present. This is -+ initially (and once) created by the separate "makefiles.c" -+ program. -+*/ -+void send_pwrdn_ok(void){ -+ -+ int fd; -+ FILE *cyclefp; -+ int cycle_fd; -+ -+ cyclefp = fopen("cycleCnt","rb"); -+ if(!cyclefp){ -+ printf("expecting file \"cycleCnt\". Cannot continue.\n"); -+ exit(1); -+ } -+ if(fread(&CycleCount, sizeof(CycleCount),1,cyclefp) != 1){ -+ fprintf(stderr, "Error! Unexpected end of file cycleCnt.\n"); -+ exit(1); -+ } -+ fclose(cyclefp); -+ -+ CycleCount++; -+ -+ /*now write this puppy back*/ -+ cyclefp = fopen("cycleCnt","wb"); -+ cycle_fd = fileno(cyclefp); -+ if(!cyclefp){ -+ fprintf(stderr, "Error! cannot open file for write:\"cycleCnt\". Cannot continue.\n"); -+ exit(1); -+ } -+ if(fwrite(&CycleCount, sizeof(CycleCount), 1,cyclefp) !=1){ -+ fprintf(stderr, "Error writing to file cycleCnt. Cannot continue.\n"); -+ exit(1); -+ } -+ if(fdatasync(cycle_fd)){ -+ fprintf(stderr, "Error! cannot sync file buffer with disk.\n"); -+ exit(1); -+ } -+ -+ fclose(cyclefp); -+ (void)sync(); -+ -+ printf("\n\n Sending Power down command to the remote box.\n"); -+ fd = setupSerial(SerialDevice); -+ -+ if(do_pwr_dn(fd, CycleCount) < 0) -+ { -+ fprintf(stderr, "Error sending power down command.\n"); -+ exit(1); -+ } -+ -+ close(fd); -+}//end send_pwrnd_ok() -+ -+ -+ -+ -+/* -+ Appends 16bit CRC at the end of numBytes long buffer. -+ Make sure buf, extends at least 2 bytes beyond. -+ */ -+void appendChecksum(char *buf, int numBytes){ -+ -+ unsigned short crc = 0xffff; -+ int index = 0; -+ -+ /* printf("Added CRC (2 bytes) to %i bytes.\n", numBytes); */ -+ -+ for (; numBytes > 0; numBytes--){ -+ -+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ buf[index++]) & 0xff]; -+ } -+ crc ^= 0xffff; -+ /*printf("The CRC: %x\n\n", crc);*/ -+ -+ buf[index++] = crc; -+ buf[index++] = crc >> 8; -+ -+ -+ -+}/*end checksum()*/ -+ -+ -+ -+ -+ -+/* -+ This guy make a new "random data file" with the filename -+ passed to it. This file is checksummed with the checksum -+ stored at the end. The first "int" in the file is the -+ number of int's in it (this is needed to know how much -+ data to read and checksum later). -+*/ -+void make_new_file(char *filename){ -+ -+ -+ int dfd; /* data file descriptor */ -+ int rand_data; -+ int data_size; -+ int temp_size; -+ int dataIndex = 0; -+ int err; -+ -+ -+ struct { -+ int sizeInBytes; /* must be int */ -+ int dataInt[MAX_INTS_ALLOW+1]; /* how many int's can we write? */ -+ }__attribute((packed)) dataBuf; -+ -+ -+ fprintf(stderr, "Creating File:%s. ", filename); -+ -+ if((dfd = open(filename, O_RDWR | O_CREAT | O_SYNC)) <= 0) -+ { -+ printf("Error! Cannot open file: %s\n",filename); -+ perror("Error"); -+ exit(1); -+ } -+ -+ /*now write a bunch of random binary data to the file*/ -+ /*first figure out how much data to write. That is random also.*/ -+ -+ /*file should not be less than 5 ints long. (so that we have decent length files, -+ that's all)*/ -+ while( -+ ((data_size = (int)(1+(int)((FileSizeMax/sizeof(int))*rand()/(RAND_MAX+1.0)))) < 5) -+ ); -+ -+ /* printf("Writing %i ints to the file.\n", data_size); */ -+ -+ temp_size = data_size * sizeof(int); -+ -+ /* Make sure that all data is written in one go! This is important to -+ check for reliability of file systems like JFFS/JFFS that purport to -+ have "reliable" writes during powre fail. -+ */ -+ -+ dataBuf.sizeInBytes = temp_size; -+ -+ data_size--; /*one alrady written*/ -+ dataIndex = 0; -+ -+ while(data_size--){ -+ rand_data = (int)(1 + (int)(10000.0*rand()/(RAND_MAX+1.0))); -+ -+ dataBuf.dataInt[dataIndex++] = rand_data; -+ -+ } -+ -+ /*now calculate the file checksum and append it to the end*/ -+ appendChecksum((char *)&dataBuf, dataBuf.sizeInBytes); -+ -+ /* Don't forget to increase the size of data written by the 2 chars of CRC at end. -+ These 2 bytes are NOT included in the sizeInBytes field. */ -+ if((err = write(dfd, (void *)&dataBuf, dataBuf.sizeInBytes + sizeof(short))) < -+ (dataBuf.sizeInBytes + sizeof(short)) -+ ) -+ { -+ printf("Error writing data buffer to file. Written %i bytes rather than %i bytes.", -+ err, dataBuf.sizeInBytes); -+ perror("Error"); -+ exit(1); -+ } -+ -+ /* Now that the data is (hopefully) safely written. I can truncate the file to the new -+ length so that I can reclaim any unused space, if the older file was larger. -+ */ -+ if(ftruncate(dfd, dataBuf.sizeInBytes + sizeof(short)) < 0) -+ { -+ perror("Error: Unable to truncate file."); -+ exit(1); -+ } -+ -+ -+ close(dfd); -+ -+ -+}//end make_new_file() -+ -+ -+ -+/* -+ Show's help on stdout -+ */ -+void printHelp(char **argv) -+{ -+ printf("Usage:%s \n", argv[0]); -+ printf("%s : Set com port to send ok to pwr dn msg on\n", -+ CMDLINE_PORT); -+ printf("%s : Set Max size in bytes of each file to be created.\n", -+ CMDLINE_MAXFILEBYTES); -+ printf("%s : Set Max errors allowed when checking all files for CRC on start.\n", -+ CMDLINE_MAXERROR); -+ printf("%s or %s: This Help screen.\n", CMDLINE_HELPSHORT, -+ CMDLINE_HELPLONG); -+ -+}/* end printHelp()*/ -+ -+ -+ -+void processCmdLine(int argc, char **argv) -+{ -+ -+ int cnt; -+ -+ /* skip past name of this program, process rest */ -+ for(cnt = 1; cnt < argc; cnt++) -+ { -+ if(strcmp(argv[cnt], CMDLINE_PORT) == 0) -+ { -+ strncpy(SerialDevice, argv[++cnt], sizeof(SerialDevice)); -+ continue; -+ }else -+ if(strcmp(argv[cnt], CMDLINE_MAXFILEBYTES) == 0) -+ { -+ FileSizeMax = (float)atoi(argv[++cnt]); -+ if(FileSizeMax > (MAX_INTS_ALLOW*sizeof(int))) -+ { -+ printf("Max file size allowd is %i.\n", -+ MAX_INTS_ALLOW*sizeof(int)); -+ exit(0); -+ } -+ -+ continue; -+ }else -+ if(strcmp(argv[cnt], CMDLINE_HELPSHORT) == 0) -+ { -+ printHelp(argv); -+ exit(0); -+ -+ }else -+ if(strcmp(argv[cnt], CMDLINE_HELPLONG) == 0) -+ { -+ printHelp(argv); -+ exit(0); -+ }else -+ -+ if(strcmp(argv[cnt], CMDLINE_MAXERROR) == 0) -+ { -+ MaxErrAllowed = atoi(argv[++cnt]); -+ } -+ else -+ { -+ printf("Unknown cmd line option:%s\n", argv[cnt]); -+ printHelp(argv); -+ exit(0); -+ -+ } -+ } -+ -+ -+}/* end processCmdLine() */ -+ -+ -+ -+ -+ -+int main(int argc, char **argv){ -+ -+ FILE *logfp; -+ int log_fd; -+ char filename[30]; -+ short filenameCounter = 0; -+ unsigned short counter; -+ unsigned short numberFiles; -+ char error = FALSE; -+ short errorCnt = 0; -+ time_t timep; -+ char * time_string; -+ unsigned int seed; -+ -+ -+ numberFiles = MAX_NUM_FILES; -+ -+ if(argc >= 1) -+ { -+ processCmdLine(argc, argv); -+ } -+ -+ -+ /* -+ First open MAX_NUM_FILES and make sure that the checksum is ok. -+ Also make an intry into the logfile. -+ */ -+ /* timestamp! */ -+ time(&timep); -+ time_string = (char *)ctime((time_t *)&timep); -+ -+ /*start a new check, make a log entry and continue*/ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ log_fd = fileno(logfp); -+ fprintf(logfp,"%s", time_string); -+ fprintf(logfp,"Starting new check.\n"); -+ if(fdatasync(log_fd) == -1){ -+ fprintf(stderr,"Error! Cannot sync file data with disk.\n"); -+ exit(1); -+ } -+ -+ fclose(logfp); -+ (void)sync(); -+ -+ /* -+ Now check all random data files in this dir. -+ */ -+ for(counter=0;counter MaxErrAllowed){ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ log_fd = fileno(logfp); -+ fprintf(logfp,"\nMax Error count exceed. Stopping!\n"); -+ if(fdatasync(log_fd) == -1){ -+ fprintf(stderr,"Error! Cannot sync file data with disk.\n"); -+ exit(1); -+ } -+ fclose(logfp); -+ (void)sync(); -+ -+ fprintf(stderr, "Too many errors. See \"logfile\".\n"); -+ exit(1); -+ }/* if too many errors */ -+ -+ /*we have decided to continue, however first repair this file -+ so that we do not cumulate errors across power cycles.*/ -+ make_new_file(filename); -+ } -+ }//for -+ -+ /*all files checked, make a log entry and continue*/ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ log_fd = fileno(logfp); -+ fprintf(logfp,"All files checked. Total errors found: %i\n\n", errorCnt); -+ if(fdatasync(log_fd)){ -+ fprintf(stderr, "Error! cannot sync file buffer with disk.\n"); -+ exit(1); -+ } -+ -+ fclose(logfp); -+ (void)sync(); -+ -+ /*now send a message to the remote power box and have it start a random -+ pwer down timer after which power will be killed to this unit. -+ */ -+ send_pwrdn_ok(); -+ -+ /*now go into a forever loop of writing to files and CRC'ing them on -+ a continious basis.*/ -+ -+ /*start from a random file #*/ -+ /*seed rand based on the current time*/ -+ seed = (unsigned int)time(NULL); -+ srand(seed); -+ -+ filenameCounter=(int)(1+(int)((float)(MAX_NUM_FILES-1)*rand()/(RAND_MAX+1.0))); -+ -+ while(1){ -+ -+ for(;filenameCounter -+#include -+#include -+ -+ -+ -+/* -+ This is the routine that forms and -+ sends the "ok to pwr me down" message -+ to the remote power cycling "black box". -+ -+ */ -+int do_pwr_dn(int fd, int cycleCnt) -+{ -+ -+ char buf[200]; -+ -+ sprintf(buf, "ok to power me down!\nCount = %i\n", cycleCnt); -+ -+ if(write(fd, buf, strlen(buf)) < strlen(buf)) -+ { -+ perror("write error"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/common.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/common.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,7 @@ -+/* $Id: common.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ */ -+//this .h file is common to both the file creation utility and -+//the file checking utility. -+#define TRUE 1 -+#define FALSE 0 -+ -+#define MAX_NUM_FILES 100 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,264 @@ -+/* -+ -+ * Copyright Daniel Industries. -+ -+ * Created by: Vipin Malik (vipin.malik@daniel.com) -+ * -+ * This is GPL code. See the file COPYING for more details -+ * -+ * Software distributed under the Licence is distributed on an "AS IS" -+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -+ * See the Licence for the specific language governing rights and -+ * limitations under the Licence. -+ -+ * $Id: makefiles.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ -+This program creates MAX_NUM_FILES files (file00001, file00002 etc) and -+fills them with random numbers till they are a random length. Then it checksums -+the files (with the checksum as the last two bytes) and closes the file. -+ -+The fist int is the size of the file in bytes. -+ -+It then opens another file and the process continues. -+ -+The files are opened in the current dir. -+ -+*/ -+#include -+#include -+#include -+#include -+#include -+#include "common.h" -+ -+#define FILESIZE_MAX 20000.0 /* for each file in sizeof(int). Must be a float # -+ Hence, 20000.0 = 20000*4 = 80KB max file size -+ */ -+ -+static const unsigned short crc_ccitt_table[] = { -+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, -+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, -+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, -+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, -+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, -+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, -+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, -+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, -+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, -+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, -+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, -+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, -+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, -+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, -+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, -+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, -+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, -+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, -+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, -+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, -+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, -+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, -+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, -+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, -+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, -+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, -+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, -+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, -+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, -+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, -+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, -+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -+}; -+ -+//This code was taken from the AX.25 HDLC packet driver -+//in LINUX. Once I test and have a better understanding of what -+//it is doing, it will be better commented. -+ -+//For now one can speculate that the CRC routine always expects the -+//CRC to calculate out to 0xf0b8 (the hardcoded value at the end) -+//and returns TRUE if it is and FALSE if it doesn't. -+//Why don't people document better!!!! -+void check_crc_ccitt(char *filename) -+{ -+ FILE *fp; -+ unsigned short crc = 0xffff; -+ int len; -+ char dataByte; -+ int retry; -+ -+ fp = fopen(filename,"rb"); -+ if(!fp){ -+ printf("Verify checksum:Error! Cannot open filename passed for verify checksum: %s\n",filename); -+ exit(1); -+ } -+ /*the first int contains an int that is the length of the file in long.*/ -+ if(fread(&len, sizeof(int), 1, fp) != 1){ -+ printf("verify checksum:Error reading from file: %s", filename); -+ fclose(fp); -+ exit(1); -+ } -+ rewind(fp); -+ len+=2; /*the file has two extra bytes at the end, it's checksum. Those -+ two MUST also be included in the checksum calculation. -+ */ -+ -+ for (;len>0;len--){ -+ retry=5; /*retry 5 times*/ -+ while(!fread(&dataByte, sizeof(char), 1, fp) && retry--); -+ if(!retry){ -+ printf("Unexpected error reading from file: %s\n", filename); -+ printf("...bytes left to be read %i.\n\n",len); -+ fclose(fp); -+ exit(1); -+ } -+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff]; -+ } -+ fclose(fp); -+ if( (crc & 0xffff) != 0xf0b8){ -+ printf("Verify checksum: Error in file %s.\n\n",filename); -+ exit(1); -+ } -+}//end check_crc_ccitt() -+ -+ -+ -+/*this routine opens a file 'filename' and checksumn's the entire -+ contents, and then appends the checksum at the end of the file, -+ closes the file and returns. -+*/ -+void checksum(char *filename){ -+ -+ FILE *fp; -+ unsigned short crc = 0xffff; -+ int len; -+ char dataByte; -+ int retry; -+ -+ fp = fopen(filename,"rb"); -+ if(!fp){ -+ printf("Error! Cannot open filename passed for checksum: %s\n",filename); -+ exit(1); -+ } -+ /*the first int contains an int that is the length of the file in longs.*/ -+ if(fread(&len, sizeof(int), 1, fp) != 1){ -+ printf("Error reading from file: %s", filename); -+ fclose(fp); -+ exit(1); -+ } -+ printf("Calculating checksum on %i bytes.\n",len); -+ rewind(fp); /*the # of bytes int is also included in the checksum.*/ -+ -+ for (;len>0;len--){ -+ retry=5; /*retry 5 times*/ -+ while(!fread(&dataByte, sizeof(char), 1, fp) && retry--); -+ if(!retry){ -+ printf("Unexpected error reading from file: %s\n", filename); -+ printf("...bytes left to be read %i.\n\n",len); -+ fclose(fp); -+ exit(1); -+ } -+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff]; -+ } -+ crc ^= 0xffff; -+ printf("The CRC: %x\n\n", crc); -+ -+ /*the CRC has been calculated. now close the file and open it in append mode*/ -+ fclose(fp); -+ -+ fp = fopen(filename,"ab"); /*open in append mode. CRC goes at the end.*/ -+ if(!fp){ -+ printf("Error! Cannot open filename to update checksum: %s\n",filename); -+ exit(1); -+ } -+ if(fwrite(&crc, sizeof(crc), 1, fp) != 1){ -+ printf("error! unable to update the file for checksum.\n"); -+ fclose(fp); -+ exit(1); -+ } -+ fflush(fp); -+ fclose(fp); -+ -+ -+}/*end checksum()*/ -+ -+ -+ -+int main(void){ -+ -+ FILE *fp, *cyclefp; -+ int cycleCount; -+ int rand_data; -+ int data_size; -+ int temp_size; -+ char filename[30]; -+ short filenameCounter = 0; -+ unsigned short counter; -+ unsigned short numberFiles; -+ -+ numberFiles = MAX_NUM_FILES; -+ -+ for(counter=0;counter -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+/* Structures to store data written to the test file system, -+ so that we can check whether the file system is correct. */ -+ -+struct write_info /* Record of random data written into a file */ -+{ -+ struct write_info *next; -+ off_t offset; /* Where in the file the data was written */ -+ size_t size; /* Number of bytes written */ -+ unsigned random_seed; /* Seed for rand() to create random data */ -+ off_t random_offset; /* Call rand() this number of times first */ -+}; -+ -+struct file_info /* Each file has one of these */ -+{ -+ char *name; -+ struct dir_info *parent; /* Parent directory */ -+ struct write_info *writes; /* Record accumulated writes to the file */ -+ struct write_info *raw_writes; -+ /* Record in order all writes to the file */ -+ struct fd_info *fds; /* All open file descriptors for this file */ -+ off_t length; -+ int deleted; /* File has been deleted but is still open */ -+ int no_space_error; /* File has incurred a ENOSPC error */ -+}; -+ -+struct dir_info /* Each directory has one of these */ -+{ -+ char *name; -+ struct dir_info *parent; /* Parent directory or null -+ for our top directory */ -+ unsigned number_of_entries; -+ struct dir_entry_info *first; -+}; -+ -+struct dir_entry_info /* Each entry in a directory has one of these */ -+{ -+ struct dir_entry_info *next; -+ char type; /* f => file, d=> dir */ -+ int checked; /* Temporary flag used when checking */ -+ union entry_ -+ { -+ struct file_info *file; -+ struct dir_info *dir; -+ } entry; -+}; -+ -+struct fd_info /* We keep a number of files open */ -+{ -+ struct fd_info *next; -+ struct file_info *file; -+ int fd; -+}; -+ -+struct open_file_info /* We keep a list of open files */ -+{ -+ struct open_file_info *next; -+ struct fd_info *fdi; -+}; -+ -+static struct dir_info *top_dir = NULL; /* Our top directory */ -+ -+static struct open_file_info *open_files = NULL; /* We keep a list of -+ open files */ -+static size_t open_files_count = 0; -+ -+static int grow = 1; /* Should we try to grow files and directories */ -+static int shrink = 0; /* Should we try to shrink files and directories */ -+static int full = 0; /* Flag that the file system is full */ -+static uint64_t operation_count = 0; /* Number of operations used to fill -+ up the file system */ -+static uint64_t initial_free_space = 0; /* Free space on file system when -+ test starts */ -+static unsigned log10_initial_free_space = 0; /* log10 of initial_free_space */ -+ -+static char *copy_string(const char *s) -+{ -+ char *str; -+ -+ if (!s) -+ return NULL; -+ str = (char *) malloc(strlen(s) + 1); -+ CHECK(str != NULL); -+ strcpy(str, s); -+ return str; -+} -+ -+static char *cat_strings(const char *a, const char *b) -+{ -+ char *str; -+ size_t sz; -+ -+ if (a && !b) -+ return copy_string(a); -+ if (b && !a) -+ return copy_string(b); -+ if (!a && !b) -+ return NULL; -+ sz = strlen(a) + strlen(b) + 1; -+ str = (char *) malloc(sz); -+ CHECK(str != NULL); -+ strcpy(str, a); -+ strcat(str, b); -+ return str; -+} -+ -+static char *cat_paths(const char *a, const char *b) -+{ -+ char *str; -+ size_t sz; -+ int as, bs; -+ size_t na, nb; -+ -+ if (a && !b) -+ return copy_string(a); -+ if (b && !a) -+ return copy_string(b); -+ if (!a && !b) -+ return NULL; -+ -+ as = 0; -+ bs = 0; -+ na = strlen(a); -+ nb = strlen(b); -+ if (na && a[na - 1] == '/') -+ as = 1; -+ if (nb && b[0] == '/') -+ bs = 1; -+ if ((as && !bs) || (!as && bs)) -+ return cat_strings(a, b); -+ if (as && bs) -+ return cat_strings(a, b + 1); -+ -+ sz = na + nb + 2; -+ str = (char *) malloc(sz); -+ CHECK(str != NULL); -+ strcpy(str, a); -+ strcat(str, "/"); -+ strcat(str, b); -+ return str; -+} -+ -+static char *dir_path(struct dir_info *parent, const char *name) -+{ -+ char *parent_path; -+ char *path; -+ -+ if (!parent) -+ return cat_paths(tests_file_system_mount_dir, name); -+ parent_path = dir_path(parent->parent, parent->name); -+ path = cat_paths(parent_path, name); -+ free(parent_path); -+ return path; -+} -+ -+static struct dir_entry_info *dir_entry_new(void) -+{ -+ struct dir_entry_info *entry; -+ size_t sz; -+ -+ sz = sizeof(struct dir_entry_info); -+ entry = (struct dir_entry_info *) malloc(sz); -+ CHECK(entry != NULL); -+ memset(entry, 0, sz); -+ return entry; -+} -+ -+static void open_file_add(struct fd_info *fdi) -+{ -+ struct open_file_info *ofi; -+ size_t sz; -+ -+ sz = sizeof(struct open_file_info); -+ ofi = (struct open_file_info *) malloc(sz); -+ CHECK(ofi != NULL); -+ memset(ofi, 0, sz); -+ ofi->next = open_files; -+ ofi->fdi = fdi; -+ open_files = ofi; -+ open_files_count += 1; -+} -+ -+static void open_file_remove(struct fd_info *fdi) -+{ -+ struct open_file_info *ofi; -+ struct open_file_info **prev; -+ -+ prev = &open_files; -+ for (ofi = open_files; ofi; ofi = ofi->next) { -+ if (ofi->fdi == fdi) { -+ *prev = ofi->next; -+ free(ofi); -+ open_files_count -= 1; -+ return; -+ } -+ prev = &ofi->next; -+ } -+ CHECK(0); /* We are trying to remove something that is not there */ -+} -+ -+static struct fd_info *fd_new(struct file_info *file, int fd) -+{ -+ struct fd_info *fdi; -+ size_t sz; -+ -+ sz = sizeof(struct fd_info); -+ fdi = (struct fd_info *) malloc(sz); -+ CHECK(fdi != NULL); -+ memset(fdi, 0, sz); -+ fdi->next = file->fds; -+ fdi->file = file; -+ fdi->fd = fd; -+ file->fds = fdi; -+ open_file_add(fdi); -+ return fdi; -+} -+ -+static struct dir_info *dir_new(struct dir_info *parent, const char *name) -+{ -+ struct dir_info *dir; -+ size_t sz; -+ char *path; -+ -+ path = dir_path(parent, name); -+ if (mkdir(path, 0777) == -1) { -+ CHECK(errno == ENOSPC); -+ full = 1; -+ free(path); -+ return NULL; -+ } -+ free(path); -+ -+ sz = sizeof(struct dir_info); -+ dir = (struct dir_info *) malloc(sz); -+ CHECK(dir != NULL); -+ memset(dir, 0, sz); -+ dir->name = copy_string(name); -+ dir->parent = parent; -+ if (parent) { -+ struct dir_entry_info *entry; -+ -+ entry = dir_entry_new(); -+ entry->type = 'd'; -+ entry->entry.dir = dir; -+ entry->next = parent->first; -+ parent->first = entry; -+ parent->number_of_entries += 1; -+ } -+ return dir; -+} -+ -+static void file_delete(struct file_info *file); -+ -+static void dir_remove(struct dir_info *dir) -+{ -+ char *path; -+ struct dir_entry_info *entry; -+ struct dir_entry_info **prev; -+ int found; -+ -+ /* Remove directory contents */ -+ while (dir->first) { -+ struct dir_entry_info *entry; -+ -+ entry = dir->first; -+ if (entry->type == 'd') -+ dir_remove(entry->entry.dir); -+ else if (entry->type == 'f') -+ file_delete(entry->entry.file); -+ else -+ CHECK(0); /* Invalid struct dir_entry_info */ -+ } -+ /* Remove entry from parent directory */ -+ found = 0; -+ prev = &dir->parent->first; -+ for (entry = dir->parent->first; entry; entry = entry->next) { -+ if (entry->type == 'd' && entry->entry.dir == dir) { -+ dir->parent->number_of_entries -= 1; -+ *prev = entry->next; -+ free(entry); -+ found = 1; -+ break; -+ } -+ prev = &entry->next; -+ } -+ CHECK(found); /* Check the file is in the parent directory */ -+ /* Remove directory itself */ -+ path = dir_path(dir->parent, dir->name); -+ CHECK(rmdir(path) != -1); -+} -+ -+static struct file_info *file_new(struct dir_info *parent, const char *name) -+{ -+ struct file_info *file = NULL; -+ char *path; -+ mode_t mode; -+ int fd; -+ size_t sz; -+ struct dir_entry_info *entry; -+ -+ CHECK(parent != NULL); -+ -+ path = dir_path(parent, name); -+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; -+ fd = open(path, O_CREAT | O_EXCL | O_RDWR, mode); -+ if (fd == -1) { -+ CHECK(errno == ENOSPC); -+ free(path); -+ full = 1; -+ return NULL; -+ } -+ free(path); -+ -+ sz = sizeof(struct file_info); -+ file = (struct file_info *) malloc(sz); -+ CHECK(file != NULL); -+ memset(file, 0, sz); -+ file->name = copy_string(name); -+ file->parent = parent; -+ -+ fd_new(file, fd); -+ -+ entry = dir_entry_new(); -+ entry->type = 'f'; -+ entry->entry.file = file; -+ entry->next = parent->first; -+ parent->first = entry; -+ parent->number_of_entries += 1; -+ -+ return file; -+} -+ -+static void file_delete(struct file_info *file) -+{ -+ char *path; -+ struct dir_entry_info *entry; -+ struct dir_entry_info **prev; -+ int found; -+ -+ /* Remove file entry from parent directory */ -+ found = 0; -+ prev = &file->parent->first; -+ for (entry = file->parent->first; entry; entry = entry->next) { -+ if (entry->type == 'f' && entry->entry.file == file) { -+ file->parent->number_of_entries -= 1; -+ *prev = entry->next; -+ free(entry); -+ found = 1; -+ break; -+ } -+ prev = &entry->next; -+ } -+ CHECK(found); /* Check the file is in the parent directory */ -+ -+ /* Delete the file */ -+ path = dir_path(file->parent, file->name); -+ CHECK(unlink(path) != -1); -+ free(path); -+ -+ /* Free struct file_info if file is not open */ -+ if (!file->fds) { -+ struct write_info *w, *next; -+ -+ free(file->name); -+ w = file->writes; -+ while (w) { -+ next = w->next; -+ free(w); -+ w = next; -+ } -+ free(file); -+ } else -+ file->deleted = 1; -+} -+ -+static void file_info_display(struct file_info *file) -+{ -+ struct write_info *w; -+ unsigned wcnt; -+ -+ fprintf(stderr, "File Info:\n"); -+ fprintf(stderr, " Name: %s\n", file->name); -+ fprintf(stderr, " Directory: %s\n", file->parent->name); -+ fprintf(stderr, " Length: %u\n", (unsigned) file->length); -+ fprintf(stderr, " File was open: %s\n", -+ (file->fds == NULL) ? "false" : "true"); -+ fprintf(stderr, " File was deleted: %s\n", -+ (file->deleted == 0) ? "false" : "true"); -+ fprintf(stderr, " File was out of space: %s\n", -+ (file->no_space_error == 0) ? "false" : "true"); -+ fprintf(stderr, " Write Info:\n"); -+ wcnt = 0; -+ w = file->writes; -+ while (w) { -+ fprintf(stderr, " Offset: %u Size: %u Seed: %u" -+ " R.Off: %u\n", -+ (unsigned) w->offset, -+ (unsigned) w->size, -+ (unsigned) w->random_seed, -+ (unsigned) w->random_offset); -+ wcnt += 1; -+ w = w->next; -+ } -+ fprintf(stderr, " %u writes\n", wcnt); -+ fprintf(stderr, " ============================================\n"); -+ fprintf(stderr, " Raw Write Info:\n"); -+ wcnt = 0; -+ w = file->raw_writes; -+ while (w) { -+ fprintf(stderr, " Offset: %u Size: %u Seed: %u" -+ " R.Off: %u\n", -+ (unsigned) w->offset, -+ (unsigned) w->size, -+ (unsigned) w->random_seed, -+ (unsigned) w->random_offset); -+ wcnt += 1; -+ w = w->next; -+ } -+ fprintf(stderr, " %u writes\n", wcnt); -+ fprintf(stderr, " ============================================\n"); -+} -+ -+static struct fd_info *file_open(struct file_info *file) -+{ -+ int fd; -+ char *path; -+ -+ path = dir_path(file->parent, file->name); -+ fd = open(path, O_RDWR); -+ CHECK(fd != -1); -+ free(path); -+ return fd_new(file, fd); -+} -+ -+#define BUFFER_SIZE 32768 -+ -+static size_t file_write_data( struct file_info *file, -+ int fd, -+ off_t offset, -+ size_t size, -+ unsigned seed) -+{ -+ size_t remains, actual, block; -+ ssize_t written; -+ char buf[BUFFER_SIZE]; -+ -+ srand(seed); -+ CHECK(lseek(fd, offset, SEEK_SET) != (off_t) -1); -+ remains = size; -+ actual = 0; -+ written = BUFFER_SIZE; -+ while (remains) { -+ /* Fill up buffer with random data */ -+ if (written < BUFFER_SIZE) -+ memmove(buf, buf + written, BUFFER_SIZE - written); -+ else -+ written = 0; -+ for (; written < BUFFER_SIZE; ++written) -+ buf[written] = rand(); -+ /* Write a block of data */ -+ if (remains > BUFFER_SIZE) -+ block = BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written < 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ full = 1; -+ file->no_space_error = 1; -+ break; -+ } -+ remains -= written; -+ actual += written; -+ } -+ return actual; -+} -+ -+static void file_write_info(struct file_info *file, -+ off_t offset, -+ size_t size, -+ unsigned seed) -+{ -+ struct write_info *new_write, *w, **prev, *tmp; -+ int inserted; -+ size_t sz; -+ off_t end, chg; -+ -+ /* Create struct write_info */ -+ sz = sizeof(struct write_info); -+ new_write = (struct write_info *) malloc(sz); -+ CHECK(new_write != NULL); -+ memset(new_write, 0, sz); -+ new_write->offset = offset; -+ new_write->size = size; -+ new_write->random_seed = seed; -+ -+ w = (struct write_info *) malloc(sz); -+ CHECK(w != NULL); -+ memset(w, 0, sz); -+ w->next = file->raw_writes; -+ w->offset = offset; -+ w->size = size; -+ w->random_seed = seed; -+ file->raw_writes = w; -+ -+ /* Insert it into file->writes */ -+ inserted = 0; -+ end = offset + size; -+ w = file->writes; -+ prev = &file->writes; -+ while (w) { -+ if (w->offset >= end) { -+ /* w comes after new_write, so insert before it */ -+ new_write->next = w; -+ *prev = new_write; -+ inserted = 1; -+ break; -+ } -+ /* w does not come after new_write */ -+ if (w->offset + w->size > offset) { -+ /* w overlaps new_write */ -+ if (w->offset < offset) { -+ /* w begins before new_write begins */ -+ if (w->offset + w->size <= end) -+ /* w ends before new_write ends */ -+ w->size = offset - w->offset; -+ else { -+ /* w ends after new_write ends */ -+ /* Split w */ -+ tmp = (struct write_info *) malloc(sz); -+ CHECK(tmp != NULL); -+ *tmp = *w; -+ chg = end - tmp->offset; -+ tmp->offset += chg; -+ tmp->random_offset += chg; -+ tmp->size -= chg; -+ w->size = offset - w->offset; -+ /* Insert new struct write_info */ -+ w->next = new_write; -+ new_write->next = tmp; -+ inserted = 1; -+ break; -+ } -+ } else { -+ /* w begins after new_write begins */ -+ if (w->offset + w->size <= end) { -+ /* w is completely overlapped, -+ so remove it */ -+ *prev = w->next; -+ tmp = w; -+ w = w->next; -+ free(tmp); -+ continue; -+ } -+ /* w ends after new_write ends */ -+ chg = end - w->offset; -+ w->offset += chg; -+ w->random_offset += chg; -+ w->size -= chg; -+ continue; -+ } -+ } -+ prev = &w->next; -+ w = w->next; -+ } -+ if (!inserted) -+ *prev = new_write; -+ /* Update file length */ -+ if (end > file->length) -+ file->length = end; -+} -+ -+/* Randomly select offset and and size to write in a file */ -+static void get_offset_and_size(struct file_info *file, -+ off_t *offset, -+ size_t *size) -+{ -+ size_t r, n; -+ -+ r = tests_random_no(100); -+ if (r == 0 && grow) -+ /* 1 time in 100, when growing, write off the end of the file */ -+ *offset = file->length + tests_random_no(10000000); -+ else if (r < 4) -+ /* 3 (or 4) times in 100, write at the beginning of file */ -+ *offset = 0; -+ else if (r < 52 || !grow) -+ /* 48 times in 100, write into the file */ -+ *offset = tests_random_no(file->length); -+ else -+ /* 48 times in 100, write at the end of the file */ -+ *offset = file->length; -+ /* Distribute the size logarithmically */ -+ if (tests_random_no(1000) == 0) -+ r = tests_random_no(log10_initial_free_space + 2); -+ else -+ r = tests_random_no(log10_initial_free_space); -+ n = 1; -+ while (r--) -+ n *= 10; -+ *size = tests_random_no(n); -+ if (!grow && *offset + *size > file->length) -+ *size = file->length - *offset; -+ if (*size == 0) -+ *size = 1; -+} -+ -+static void file_truncate_info(struct file_info *file, size_t new_length); -+static void file_close(struct fd_info *fdi); -+ -+static int file_ftruncate(struct file_info *file, int fd, off_t new_length) -+{ -+ if (ftruncate(fd, new_length) == -1) { -+ CHECK(errno = ENOSPC); -+ file->no_space_error = 1; -+ /* Delete errored files */ -+ if (!file->deleted) { -+ struct fd_info *fdi; -+ -+ fdi = file->fds; -+ while (fdi) { -+ file_close(fdi); -+ fdi = file->fds; -+ } -+ file_delete(file); -+ } -+ return 0; -+ } -+ return 1; -+} -+ -+static void file_write(struct file_info *file, int fd) -+{ -+ off_t offset; -+ size_t size, actual; -+ unsigned seed; -+ int truncate = 0; -+ -+ get_offset_and_size(file, &offset, &size); -+ seed = tests_random_no(10000000); -+ actual = file_write_data(file, fd, offset, size, seed); -+ -+ if (offset + actual <= file->length && shrink) -+ /* 1 time in 100, when shrinking -+ truncate after the write */ -+ if (tests_random_no(100) == 0) -+ truncate = 1; -+ -+ if (actual != 0) -+ file_write_info(file, offset, actual, seed); -+ -+ /* Delete errored files */ -+ if (file->no_space_error) { -+ if (!file->deleted) { -+ struct fd_info *fdi; -+ -+ fdi = file->fds; -+ while (fdi) { -+ file_close(fdi); -+ fdi = file->fds; -+ } -+ file_delete(file); -+ } -+ return; -+ } -+ -+ if (truncate) { -+ size_t new_length = offset + actual; -+ if (file_ftruncate(file, fd, new_length)) -+ file_truncate_info(file, new_length); -+ } -+} -+ -+static void file_write_file(struct file_info *file) -+{ -+ int fd; -+ char *path; -+ -+ path = dir_path(file->parent, file->name); -+ fd = open(path, O_WRONLY); -+ CHECK(fd != -1); -+ file_write(file, fd); -+ CHECK(close(fd) != -1); -+ free(path); -+} -+ -+static void file_truncate_info(struct file_info *file, size_t new_length) -+{ -+ struct write_info *w, **prev, *tmp; -+ -+ /* Remove / truncate file->writes */ -+ w = file->writes; -+ prev = &file->writes; -+ while (w) { -+ if (w->offset >= new_length) { -+ /* w comes after eof, so remove it */ -+ *prev = w->next; -+ tmp = w; -+ w = w->next; -+ free(tmp); -+ continue; -+ } -+ if (w->offset + w->size > new_length) -+ w->size = new_length - w->offset; -+ prev = &w->next; -+ w = w->next; -+ } -+ /* Update file length */ -+ file->length = new_length; -+} -+ -+static void file_truncate(struct file_info *file, int fd) -+{ -+ size_t new_length; -+ -+ new_length = tests_random_no(file->length); -+ -+ if (file_ftruncate(file, fd, new_length)) -+ file_truncate_info(file, new_length); -+} -+ -+static void file_truncate_file(struct file_info *file) -+{ -+ int fd; -+ char *path; -+ -+ path = dir_path(file->parent, file->name); -+ fd = open(path, O_WRONLY); -+ CHECK(fd != -1); -+ file_truncate(file, fd); -+ CHECK(close(fd) != -1); -+ free(path); -+} -+ -+static void file_close(struct fd_info *fdi) -+{ -+ struct file_info *file; -+ struct fd_info *fdp; -+ struct fd_info **prev; -+ -+ /* Close file */ -+ CHECK(close(fdi->fd) != -1); -+ /* Remove struct fd_info */ -+ open_file_remove(fdi); -+ file = fdi->file; -+ prev = &file->fds; -+ for (fdp = file->fds; fdp; fdp = fdp->next) { -+ if (fdp == fdi) { -+ *prev = fdi->next; -+ free(fdi); -+ if (file->deleted && !file->fds) { -+ /* Closing deleted file */ -+ struct write_info *w, *next; -+ -+ w = file->writes; -+ while (w) { -+ next = w->next; -+ free(w); -+ w = next; -+ } -+ free(file->name); -+ free(file); -+ } -+ return; -+ } -+ prev = &fdp->next; -+ } -+ CHECK(0); /* Didn't find struct fd_info */ -+} -+ -+static void file_rewrite_data(int fd, struct write_info *w, char *buf) -+{ -+ size_t remains, block; -+ ssize_t written; -+ off_t r; -+ -+ srand(w->random_seed); -+ for (r = 0; r < w->random_offset; ++r) -+ rand(); -+ CHECK(lseek(fd, w->offset, SEEK_SET) != (off_t) -1); -+ remains = w->size; -+ written = BUFFER_SIZE; -+ while (remains) { -+ /* Fill up buffer with random data */ -+ if (written < BUFFER_SIZE) -+ memmove(buf, buf + written, BUFFER_SIZE - written); -+ else -+ written = 0; -+ for (; written < BUFFER_SIZE; ++written) -+ buf[written] = rand(); -+ /* Write a block of data */ -+ if (remains > BUFFER_SIZE) -+ block = BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ CHECK(written == block); -+ remains -= written; -+ } -+} -+ -+static void save_file(int fd, struct file_info *file) -+{ -+ int w_fd; -+ struct write_info *w; -+ char buf[BUFFER_SIZE]; -+ char name[256]; -+ -+ /* Open file to save contents to */ -+ strcpy(name, "/tmp/"); -+ strcat(name, file->name); -+ strcat(name, ".integ.sav.read"); -+ fprintf(stderr, "Saving %s\n", name); -+ w_fd = open(name, O_CREAT | O_WRONLY, 0777); -+ CHECK(w_fd != -1); -+ -+ /* Start at the beginning */ -+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1); -+ -+ for (;;) { -+ ssize_t r = read(fd, buf, BUFFER_SIZE); -+ CHECK(r != -1); -+ if (!r) -+ break; -+ CHECK(write(w_fd, buf, r) == r); -+ } -+ CHECK(close(w_fd) != -1); -+ -+ /* Open file to save contents to */ -+ strcpy(name, "/tmp/"); -+ strcat(name, file->name); -+ strcat(name, ".integ.sav.written"); -+ fprintf(stderr, "Saving %s\n", name); -+ w_fd = open(name, O_CREAT | O_WRONLY, 0777); -+ CHECK(w_fd != -1); -+ -+ for (w = file->writes; w; w = w->next) -+ file_rewrite_data(w_fd, w, buf); -+ -+ CHECK(close(w_fd) != -1); -+} -+ -+static void file_check_hole( struct file_info *file, -+ int fd, off_t offset, -+ size_t size) -+{ -+ size_t remains, block, i; -+ char buf[BUFFER_SIZE]; -+ -+ CHECK(lseek(fd, offset, SEEK_SET) != (off_t) -1); -+ remains = size; -+ while (remains) { -+ if (remains > BUFFER_SIZE) -+ block = BUFFER_SIZE; -+ else -+ block = remains; -+ CHECK(read(fd, buf, block) == block); -+ for (i = 0; i < block; ++i) { -+ if (buf[i] != 0) { -+ fprintf(stderr, "file_check_hole failed at %u " -+ "checking hole at %u size %u\n", -+ (unsigned) (size - remains + i), -+ (unsigned) offset, -+ (unsigned) size); -+ file_info_display(file); -+ save_file(fd, file); -+ } -+ CHECK(buf[i] == 0); -+ } -+ remains -= block; -+ } -+} -+ -+static void file_check_data( struct file_info *file, -+ int fd, -+ struct write_info *w) -+{ -+ size_t remains, block, i; -+ off_t r; -+ char buf[BUFFER_SIZE]; -+ -+ srand(w->random_seed); -+ for (r = 0; r < w->random_offset; ++r) -+ rand(); -+ CHECK(lseek(fd, w->offset, SEEK_SET) != (off_t) -1); -+ remains = w->size; -+ while (remains) { -+ if (remains > BUFFER_SIZE) -+ block = BUFFER_SIZE; -+ else -+ block = remains; -+ CHECK(read(fd, buf, block) == block); -+ for (i = 0; i < block; ++i) { -+ char c = (char) rand(); -+ if (buf[i] != c) { -+ fprintf(stderr, "file_check_data failed at %u " -+ "checking data at %u size %u\n", -+ (unsigned) (w->size - remains + i), -+ (unsigned) w->offset, -+ (unsigned) w->size); -+ file_info_display(file); -+ save_file(fd, file); -+ } -+ CHECK(buf[i] == c); -+ } -+ remains -= block; -+ } -+} -+ -+static void file_check(struct file_info *file, int fd) -+{ -+ int open_and_close = 0; -+ char *path = NULL; -+ off_t pos; -+ struct write_info *w; -+ -+ /* Do not check files that have errored */ -+ if (file->no_space_error) -+ return; -+ if (fd == -1) -+ open_and_close = 1; -+ if (open_and_close) { -+ /* Open file */ -+ path = dir_path(file->parent, file->name); -+ fd = open(path, O_RDONLY); -+ CHECK(fd != -1); -+ } -+ /* Check length */ -+ pos = lseek(fd, 0, SEEK_END); -+ if (pos != file->length) { -+ fprintf(stderr, "file_check failed checking length " -+ "expected %u actual %u\n", -+ (unsigned) file->length, -+ (unsigned) pos); -+ file_info_display(file); -+ save_file(fd, file); -+ } -+ CHECK(pos == file->length); -+ /* Check each write */ -+ pos = 0; -+ for (w = file->writes; w; w = w->next) { -+ if (w->offset > pos) -+ file_check_hole(file, fd, pos, w->offset - pos); -+ file_check_data(file, fd, w); -+ pos = w->offset + w->size; -+ } -+ if (file->length > pos) -+ file_check_hole(file, fd, pos, file->length - pos); -+ if (open_and_close) { -+ CHECK(close(fd) != -1); -+ free(path); -+ } -+} -+ -+static const char *dir_entry_name(const struct dir_entry_info *entry) -+{ -+ CHECK(entry != NULL); -+ if (entry->type == 'd') -+ return entry->entry.dir->name; -+ else if (entry->type == 'f') -+ return entry->entry.file->name; -+ else { -+ CHECK(0); -+ return NULL; -+ } -+} -+ -+static int search_comp(const void *pa, const void *pb) -+{ -+ const struct dirent *a = (const struct dirent *) pa; -+ const struct dir_entry_info *b = * (const struct dir_entry_info **) pb; -+ return strcmp(a->d_name, dir_entry_name(b)); -+} -+ -+static void dir_entry_check(struct dir_entry_info **entry_array, -+ size_t number_of_entries, -+ struct dirent *ent) -+{ -+ struct dir_entry_info **found; -+ struct dir_entry_info *entry; -+ size_t sz; -+ -+ sz = sizeof(struct dir_entry_info *); -+ found = bsearch(ent, entry_array, number_of_entries, sz, search_comp); -+ CHECK(found != NULL); -+ entry = *found; -+ CHECK(!entry->checked); -+ entry->checked = 1; -+} -+ -+static int sort_comp(const void *pa, const void *pb) -+{ -+ const struct dir_entry_info *a = * (const struct dir_entry_info **) pa; -+ const struct dir_entry_info *b = * (const struct dir_entry_info **) pb; -+ return strcmp(dir_entry_name(a), dir_entry_name(b)); -+} -+ -+static void dir_check(struct dir_info *dir) -+{ -+ struct dir_entry_info **entry_array, **p; -+ size_t sz, n; -+ struct dir_entry_info *entry; -+ DIR *d; -+ struct dirent *ent; -+ unsigned checked = 0; -+ char *path; -+ -+ /* Create an array of entries */ -+ sz = sizeof(struct dir_entry_info *); -+ n = dir->number_of_entries; -+ entry_array = (struct dir_entry_info **) malloc(sz * n); -+ CHECK(entry_array != NULL); -+ -+ entry = dir->first; -+ p = entry_array; -+ while (entry) { -+ *p++ = entry; -+ entry->checked = 0; -+ entry = entry->next; -+ } -+ -+ /* Sort it by name */ -+ qsort(entry_array, n, sz, sort_comp); -+ -+ /* Go through directory on file system checking entries match */ -+ path = dir_path(dir->parent, dir->name); -+ d = opendir(path); -+ CHECK(d != NULL); -+ for (;;) { -+ errno = 0; -+ ent = readdir(d); -+ if (ent) { -+ if (strcmp(".",ent->d_name) != 0 && -+ strcmp("..",ent->d_name) != 0) { -+ dir_entry_check(entry_array, n, ent); -+ checked += 1; -+ } -+ } else { -+ CHECK(errno == 0); -+ break; -+ } -+ } -+ CHECK(closedir(d) != -1); -+ CHECK(checked == dir->number_of_entries); -+ free(path); -+ -+ /* Now check each entry */ -+ entry = dir->first; -+ while (entry) { -+ if (entry->type == 'd') -+ dir_check(entry->entry.dir); -+ else if (entry->type == 'f') -+ file_check(entry->entry.file, -1); -+ else -+ CHECK(0); -+ entry = entry->next; -+ } -+ -+ free(entry_array); -+} -+ -+static void check_deleted_files(void) -+{ -+ struct open_file_info *ofi; -+ -+ for (ofi = open_files; ofi; ofi = ofi->next) -+ if (ofi->fdi->file->deleted) -+ file_check(ofi->fdi->file, ofi->fdi->fd); -+} -+ -+static void close_open_files(void) -+{ -+ struct open_file_info *ofi; -+ -+ for (ofi = open_files; ofi; ofi = open_files) -+ file_close(ofi->fdi); -+} -+ -+static char *make_name(struct dir_info *dir) -+{ -+ static char name[256]; -+ struct dir_entry_info *entry; -+ int found; -+ -+ do { -+ found = 0; -+ sprintf(name, "%u", (unsigned) tests_random_no(1000000)); -+ for (entry = dir->first; entry; entry = entry->next) { -+ if (strcmp(dir_entry_name(entry), name) == 0) { -+ found = 1; -+ break; -+ } -+ } -+ } while (found); -+ return name; -+} -+ -+static void operate_on_dir(struct dir_info *dir); -+static void operate_on_file(struct file_info *file); -+ -+/* Randomly select something to do with a directory entry */ -+static void operate_on_entry(struct dir_entry_info *entry) -+{ -+ /* If shrinking, 1 time in 50, remove a directory */ -+ if (entry->type == 'd') { -+ if (shrink && tests_random_no(50) == 0) { -+ dir_remove(entry->entry.dir); -+ return; -+ } -+ operate_on_dir(entry->entry.dir); -+ } -+ /* If shrinking, 1 time in 10, remove a file */ -+ if (entry->type == 'f') { -+ if (shrink && tests_random_no(10) == 0) { -+ file_delete(entry->entry.file); -+ return; -+ } -+ operate_on_file(entry->entry.file); -+ } -+} -+ -+/* Randomly select something to do with a directory */ -+static void operate_on_dir(struct dir_info *dir) -+{ -+ size_t r; -+ struct dir_entry_info *entry; -+ -+ r = tests_random_no(12); -+ if (r == 0 && grow) -+ /* When growing, 1 time in 12 create a file */ -+ file_new(dir, make_name(dir)); -+ else if (r == 1 && grow) -+ /* When growing, 1 time in 12 create a directory */ -+ dir_new(dir, make_name(dir)); -+ else { -+ /* Otherwise randomly select an entry to operate on */ -+ r = tests_random_no(dir->number_of_entries); -+ entry = dir->first; -+ while (entry && r) { -+ entry = entry->next; -+ --r; -+ } -+ if (entry) -+ operate_on_entry(entry); -+ } -+} -+ -+/* Randomly select something to do with a file */ -+static void operate_on_file(struct file_info *file) -+{ -+ /* Try to keep at least 10 files open */ -+ if (open_files_count < 10) { -+ file_open(file); -+ return; -+ } -+ /* Try to keep about 20 files open */ -+ if (open_files_count < 20 && tests_random_no(2) == 0) { -+ file_open(file); -+ return; -+ } -+ /* Try to keep up to 40 files open */ -+ if (open_files_count < 40 && tests_random_no(20) == 0) { -+ file_open(file); -+ return; -+ } -+ /* Occasionly truncate */ -+ if (shrink && tests_random_no(100) == 0) { -+ file_truncate_file(file); -+ return; -+ } -+ /* Mostly just write */ -+ file_write_file(file); -+} -+ -+/* Randomly select something to do with an open file */ -+static void operate_on_open_file(struct fd_info *fdi) -+{ -+ size_t r; -+ -+ r = tests_random_no(1000); -+ if (shrink && r == 0) -+ file_truncate(fdi->file, fdi->fd); -+ else if (r < 21) -+ file_close(fdi); -+ else if (shrink && r < 121 && !fdi->file->deleted) -+ file_delete(fdi->file); -+ else -+ file_write(fdi->file, fdi->fd); -+} -+ -+/* Select an open file at random */ -+static void operate_on_an_open_file(void) -+{ -+ size_t r; -+ struct open_file_info *ofi; -+ -+ /* Close any open files that have errored */ -+ ofi = open_files; -+ while (ofi) { -+ if (ofi->fdi->file->no_space_error) { -+ struct fd_info *fdi; -+ -+ fdi = ofi->fdi; -+ ofi = ofi->next; -+ file_close(fdi); -+ } else -+ ofi = ofi->next; -+ } -+ r = tests_random_no(open_files_count); -+ for (ofi = open_files; ofi; ofi = ofi->next, --r) -+ if (!r) { -+ operate_on_open_file(ofi->fdi); -+ return; -+ } -+} -+ -+static void do_an_operation(void) -+{ -+ /* Half the time operate on already open files */ -+ if (tests_random_no(100) < 50) -+ operate_on_dir(top_dir); -+ else -+ operate_on_an_open_file(); -+} -+ -+static void create_test_data(void) -+{ -+ uint64_t i; -+ -+ grow = 1; -+ shrink = 0; -+ full = 0; -+ operation_count = 0; -+ while (!full) { -+ do_an_operation(); -+ ++operation_count; -+ } -+ grow = 0; -+ shrink = 1; -+ /* Drop to less than 90% full */ -+ for (;;) { -+ uint64_t free; -+ uint64_t total; -+ for (i = 0; i < 10; ++i) -+ do_an_operation(); -+ free = tests_get_free_space(); -+ total = tests_get_total_space(); -+ if ((free * 100) / total >= 10) -+ break; -+ } -+ grow = 0; -+ shrink = 0; -+ full = 0; -+ for (i = 0; i < operation_count * 2; ++i) -+ do_an_operation(); -+} -+ -+static void update_test_data(void) -+{ -+ uint64_t i; -+ -+ grow = 1; -+ shrink = 0; -+ full = 0; -+ while (!full) -+ do_an_operation(); -+ grow = 0; -+ shrink = 1; -+ /* Drop to less than 50% full */ -+ for (;;) { -+ uint64_t free; -+ uint64_t total; -+ for (i = 0; i < 10; ++i) -+ do_an_operation(); -+ free = tests_get_free_space(); -+ total = tests_get_total_space(); -+ if ((free * 100) / total >= 50) -+ break; -+ } -+ grow = 0; -+ shrink = 0; -+ full = 0; -+ for (i = 0; i < operation_count * 2; ++i) -+ do_an_operation(); -+} -+ -+void integck(void) -+{ -+ pid_t pid; -+ int64_t rpt; -+ uint64_t z; -+ char dir_name[256]; -+ -+ /* Make our top directory */ -+ pid = getpid(); -+ printf("pid is %u\n", (unsigned) pid); -+ tests_cat_pid(dir_name, "integck_test_dir_", pid); -+ if (chdir(dir_name) != -1) { -+ /* Remove it if it is already there */ -+ tests_clear_dir("."); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+ } -+ initial_free_space = tests_get_free_space(); -+ log10_initial_free_space = 0; -+ for (z = initial_free_space; z >= 10; z /= 10) -+ ++log10_initial_free_space; -+ top_dir = dir_new(NULL, dir_name); -+ -+ if (!top_dir) -+ return; -+ -+ srand(pid); -+ -+ create_test_data(); -+ -+ if (!tests_fs_is_rootfs()) { -+ close_open_files(); -+ tests_remount(); /* Requires root access */ -+ } -+ -+ /* Check everything */ -+ dir_check(top_dir); -+ check_deleted_files(); -+ -+ for (rpt = 0; tests_repeat_parameter == 0 || -+ rpt < tests_repeat_parameter; ++rpt) { -+ update_test_data(); -+ -+ if (!tests_fs_is_rootfs()) { -+ close_open_files(); -+ tests_remount(); /* Requires root access */ -+ } -+ -+ /* Check everything */ -+ dir_check(top_dir); -+ check_deleted_files(); -+ } -+ -+ /* Tidy up by removing everything */ -+ close_open_files(); -+ tests_clear_dir(dir_name); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *integck_get_title(void) -+{ -+ return "Test file system integrity"; -+} -+ -+/* Description of this test */ -+ -+const char *integck_get_description(void) -+{ -+ return -+ "Create a directory named integck_test_dir_pid " \ -+ "where pid is the process id. " \ -+ "Randomly create and delete files and directories. " \ -+ "Randomly write to and truncate files. " \ -+ "Un-mount and re-mount test file " \ -+ "system (if it is not the root file system ). " \ -+ "Check data. Make more random changes. " \ -+ "Un-mount and re-mount again. Check again. " \ -+ "Repeat some number of times. " -+ "The repeat count is set by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, integck_get_title(), -+ integck_get_description(), "n"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ integck(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,18 @@ -+ -+ifeq ($(origin CC),default) -+CC = gcc -+endif -+ -+CFLAGS := $(CFLAGS) -Wall -g -O2 -+ -+LDFLAGS := $(LDFLAGS) -+ -+all: tests.o -+ -+tests.o: tests.h -+ -+clean: -+ rm -f *.o -+ -+tests: -+ echo ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1091 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+char *tests_file_system_mount_dir = TESTS_DEFAULT_FILE_SYSTEM_MOUNT_DIR; -+ -+char *tests_file_system_type = TESTS_DEFAULT_FILE_SYSTEM_TYPE; -+ -+int tests_ok_to_sync = 0; /* Whether to use fsync */ -+ -+/* General purpose test parameter to specify some aspect of test size. -+ May be used by different tests in different ways or not at all. -+ Set by the -z or --size option. */ -+int64_t tests_size_parameter = 0; -+ -+/* General purpose test parameter to specify some aspect of test repetition. -+ May be used by different tests in different ways or not at all. -+ Set by the -n, --repeat options. */ -+int64_t tests_repeat_parameter = 0; -+ -+/* General purpose test parameter to specify some aspect of test sleeping. -+ May be used by different tests in different ways or not at all. -+ Set by the -p, --sleep options. */ -+int64_t tests_sleep_parameter = 0; -+ -+/* Program name from argv[0] */ -+char *program_name = "unknown"; -+ -+/* General purpose test parameter to specify a file should be unlinked. -+ May be used by different tests in different ways or not at all. */ -+int tests_unlink_flag = 0; -+ -+/* General purpose test parameter to specify a file should be closed. -+ May be used by different tests in different ways or not at all. */ -+int tests_close_flag = 0; -+ -+/* General purpose test parameter to specify a file should be deleted. -+ May be used by different tests in different ways or not at all. */ -+int tests_delete_flag = 0; -+ -+/* General purpose test parameter to specify a file have a hole. -+ May be used by different tests in different ways or not at all. */ -+int tests_hole_flag = 0; -+ -+/* Whether it is ok to test on the root file system */ -+static int rootok = 0; -+ -+/* Function invoked by the CHECK macro */ -+void tests_test(int test,const char *msg,const char *file,unsigned line) -+{ -+ int eno; -+ time_t t; -+ -+ if (test) -+ return; -+ eno = errno; -+ time(&t); -+ fprintf(stderr, "Test failed: %s on %s" -+ "Test failed: %s in %s at line %u\n", -+ program_name, ctime(&t), msg, file, line); -+ if (eno) { -+ fprintf(stderr,"errno = %d\n",eno); -+ fprintf(stderr,"strerror = %s\n",strerror(eno)); -+ } -+ exit(1); -+} -+ -+static int is_zero(const char *p) -+{ -+ for (;*p;++p) -+ if (*p != '0') -+ return 0; -+ return 1; -+} -+ -+static void fold(const char *text, int width) -+{ -+ int pos, bpos = 0; -+ const char *p; -+ char line[1024]; -+ -+ if (width > 1023) { -+ printf("%s\n", text); -+ return; -+ } -+ p = text; -+ pos = 0; -+ while (p[pos]) { -+ while (!isspace(p[pos])) { -+ line[pos] = p[pos]; -+ if (!p[pos]) -+ break; -+ ++pos; -+ if (pos == width) { -+ line[pos] = '\0'; -+ printf("%s\n", line); -+ p += pos; -+ pos = 0; -+ } -+ } -+ while (pos < width) { -+ line[pos] = p[pos]; -+ if (!p[pos]) { -+ bpos = pos; -+ break; -+ } -+ if (isspace(p[pos])) -+ bpos = pos; -+ ++pos; -+ } -+ line[bpos] = '\0'; -+ printf("%s\n", line); -+ p += bpos; -+ pos = 0; -+ while (p[pos] && isspace(p[pos])) -+ ++p; -+ } -+} -+ -+/* Handle common program options */ -+int tests_get_args(int argc, -+ char *argv[], -+ const char *title, -+ const char *desc, -+ const char *opts) -+{ -+ int run_test = 0; -+ int display_help = 0; -+ int display_title = 0; -+ int display_description = 0; -+ int i; -+ char *s; -+ -+ program_name = argv[0]; -+ -+ s = getenv("TEST_FILE_SYSTEM_MOUNT_DIR"); -+ if (s) -+ tests_file_system_mount_dir = strdup(s); -+ s = getenv("TEST_FILE_SYSTEM_TYPE"); -+ if (s) -+ tests_file_system_type = strdup(s); -+ -+ run_test = 1; -+ rootok = 1; -+ for (i = 1; i < argc; ++i) { -+ if (strcmp(argv[i], "--help") == 0 || -+ strcmp(argv[i], "-h") == 0) -+ display_help = 1; -+ else if (strcmp(argv[i], "--title") == 0 || -+ strcmp(argv[i], "-t") == 0) -+ display_title = 1; -+ else if (strcmp(argv[i], "--description") == 0 || -+ strcmp(argv[i], "-d") == 0) -+ display_description = 1; -+ else if (strcmp(argv[i], "--sync") == 0 || -+ strcmp(argv[i], "-s") == 0) -+ tests_ok_to_sync = 1; -+ else if (strncmp(argv[i], "--size", 6) == 0 || -+ strncmp(argv[i], "-z", 2) == 0) { -+ int64_t n; -+ char *p; -+ if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1])) -+ ++i; -+ p = argv[i]; -+ while (*p && !isdigit(*p)) -+ ++p; -+ n = atoll(p); -+ if (n) -+ tests_size_parameter = n; -+ else { -+ int all_zero = 1; -+ for (; all_zero && *p; ++p) -+ if (*p != '0') -+ all_zero = 0; -+ if (all_zero) -+ tests_size_parameter = 0; -+ else -+ display_help = 1; -+ } -+ } else if (strncmp(argv[i], "--repeat", 8) == 0 || -+ strncmp(argv[i], "-n", 2) == 0) { -+ int64_t n; -+ char *p; -+ if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1])) -+ ++i; -+ p = argv[i]; -+ while (*p && !isdigit(*p)) -+ ++p; -+ n = atoll(p); -+ if (n || is_zero(p)) -+ tests_repeat_parameter = n; -+ else -+ display_help = 1; -+ } else if (strncmp(argv[i], "--sleep", 7) == 0 || -+ strncmp(argv[i], "-p", 2) == 0) { -+ int64_t n; -+ char *p; -+ if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1])) -+ ++i; -+ p = argv[i]; -+ while (*p && !isdigit(*p)) -+ ++p; -+ n = atoll(p); -+ if (n || is_zero(p)) -+ tests_sleep_parameter = n; -+ else -+ display_help = 1; -+ } else if (strcmp(argv[i], "--unlink") == 0 || -+ strcmp(argv[i], "-u") == 0) -+ tests_unlink_flag = 1; -+ else if (strcmp(argv[i], "--hole") == 0 || -+ strcmp(argv[i], "-o") == 0) -+ tests_hole_flag = 1; -+ else if (strcmp(argv[i], "--close") == 0 || -+ strcmp(argv[i], "-c") == 0) -+ tests_close_flag = 1; -+ else if (strcmp(argv[i], "--delete") == 0 || -+ strcmp(argv[i], "-e") == 0) -+ tests_delete_flag = 1; -+ else -+ display_help = 1; -+ } -+ -+ if (display_help) { -+ run_test = 0; -+ display_title = 0; -+ display_description = 0; -+ if (!opts) -+ opts = ""; -+ printf("File System Test Program\n\n"); -+ printf("Test Title: %s\n\n", title); -+ printf("Usage is: %s [ options ]\n",argv[0]); -+ printf(" Options are:\n"); -+ printf(" -h, --help "); -+ printf("Display this help\n"); -+ printf(" -t, --title "); -+ printf("Display the test title\n"); -+ printf(" -d, --description "); -+ printf("Display the test description\n"); -+ if (strchr(opts, 's')) { -+ printf(" -s, --sync "); -+ printf("Make use of fsync\n"); -+ } -+ if (strchr(opts, 'z')) { -+ printf(" -z, --size "); -+ printf("Set size parameter\n"); -+ } -+ if (strchr(opts, 'n')) { -+ printf(" -n, --repeat "); -+ printf("Set repeat parameter\n"); -+ } -+ if (strchr(opts, 'p')) { -+ printf(" -p, --sleep "); -+ printf("Set sleep parameter\n"); -+ } -+ if (strchr(opts, 'u')) { -+ printf(" -u, --unlink "); -+ printf("Unlink file\n"); -+ } -+ if (strchr(opts, 'o')) { -+ printf(" -o, --hole "); -+ printf("Create a hole in a file\n"); -+ } -+ if (strchr(opts, 'c')) { -+ printf(" -c, --close "); -+ printf("Close file\n"); -+ } -+ if (strchr(opts, 'e')) { -+ printf(" -e, --delete "); -+ printf("Delete file\n"); -+ } -+ printf("\nBy default, testing is done in directory "); -+ printf("/mnt/test_file_system. To change this\nuse "); -+ printf("environmental variable "); -+ printf("TEST_FILE_SYSTEM_MOUNT_DIR. By default, "); -+ printf("the file\nsystem tested is jffs2. To change this "); -+ printf("set TEST_FILE_SYSTEM_TYPE.\n\n"); -+ printf("Test Description:\n"); -+ fold(desc, 80); -+ } else { -+ if (display_title) -+ printf("%s\n", title); -+ if (display_description) -+ printf("%s\n", desc); -+ if (display_title || display_description) -+ if (argc == 2 || (argc == 3 && -+ display_title && -+ display_description)) -+ run_test = 0; -+ } -+ return run_test; -+} -+ -+/* Return the number of files (or directories) in the given directory */ -+unsigned tests_count_files_in_dir(const char *dir_name) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ unsigned count = 0; -+ -+ dir = opendir(dir_name); -+ CHECK(dir != NULL); -+ for (;;) { -+ errno = 0; -+ entry = readdir(dir); -+ if (entry) { -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) -+ ++count; -+ } else { -+ CHECK(errno == 0); -+ break; -+ } -+ } -+ CHECK(closedir(dir) != -1); -+ return count; -+} -+ -+/* Change to the file system mount directory, check that it is empty, -+ matches the file system type, and is not the root file system */ -+void tests_check_test_file_system(void) -+{ -+ struct statfs fs_info; -+ struct stat f_info; -+ struct stat root_f_info; -+ -+ if (chdir(tests_file_system_mount_dir) == -1 || -+ statfs(tests_file_system_mount_dir, &fs_info) == -1) { -+ fprintf(stderr, "Invalid test file system mount directory:" -+ " %s\n", tests_file_system_mount_dir); -+ fprintf(stderr, "Use environment variable " -+ "TEST_FILE_SYSTEM_MOUNT_DIR\n"); -+ CHECK(0); -+ } -+ if (strcmp(tests_file_system_type, "jffs2") == 0 && -+ fs_info.f_type != JFFS2_SUPER_MAGIC) { -+ fprintf(stderr, "File system type is not jffs2\n"); -+ CHECK(0); -+ } -+ /* Check that the test file system is not the root file system */ -+ if (!rootok) { -+ CHECK(stat(tests_file_system_mount_dir, &f_info) != -1); -+ CHECK(stat("/", &root_f_info) != -1); -+ CHECK(f_info.st_dev != root_f_info.st_dev); -+ } -+} -+ -+/* Get the free space for the file system of the current directory */ -+uint64_t tests_get_free_space(void) -+{ -+ struct statvfs fs_info; -+ -+ CHECK(statvfs(tests_file_system_mount_dir, &fs_info) != -1); -+ return (uint64_t) fs_info.f_bavail * (uint64_t) fs_info.f_frsize; -+} -+ -+/* Get the total space for the file system of the current directory */ -+uint64_t tests_get_total_space(void) -+{ -+ struct statvfs fs_info; -+ -+ CHECK(statvfs(tests_file_system_mount_dir, &fs_info) != -1); -+ return (uint64_t) fs_info.f_blocks * (uint64_t) fs_info.f_frsize; -+} -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+static char write_buffer[WRITE_BUFFER_SIZE]; -+ -+static void init_write_buffer() -+{ -+ static int init = 0; -+ -+ if (!init) { -+ int i, d; -+ uint64_t u; -+ -+ u = RAND_MAX; -+ u += 1; -+ u /= 256; -+ d = (int) u; -+ srand(1); -+ for (i = 0; i < WRITE_BUFFER_SIZE; ++i) -+ write_buffer[i] = rand() / d; -+ init = 1; -+ } -+} -+ -+/* Write size random bytes into file descriptor fd at the current position, -+ returning the number of bytes actually written */ -+uint64_t tests_fill_file(int fd, uint64_t size) -+{ -+ ssize_t written; -+ size_t sz; -+ unsigned start = 0, length; -+ uint64_t remains; -+ uint64_t actual_size = 0; -+ -+ init_write_buffer(); -+ remains = size; -+ while (remains > 0) { -+ length = WRITE_BUFFER_SIZE - start; -+ if (remains > length) -+ sz = length; -+ else -+ sz = (size_t) remains; -+ written = write(fd, write_buffer + start, sz); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ actual_size += written; -+ if (written == sz) -+ start = 0; -+ else -+ start += written; -+ } -+ tests_maybe_sync(fd); -+ return actual_size; -+} -+ -+/* Write size random bytes into file descriptor fd at offset, -+ returning the number of bytes actually written */ -+uint64_t tests_write_filled_file(int fd, off_t offset, uint64_t size) -+{ -+ ssize_t written; -+ size_t sz; -+ unsigned start = 0, length; -+ uint64_t remains; -+ uint64_t actual_size = 0; -+ -+ CHECK(lseek(fd, offset, SEEK_SET) == offset); -+ -+ init_write_buffer(); -+ remains = size; -+ start = offset % WRITE_BUFFER_SIZE; -+ while (remains > 0) { -+ length = WRITE_BUFFER_SIZE - start; -+ if (remains > length) -+ sz = length; -+ else -+ sz = (size_t) remains; -+ written = write(fd, write_buffer + start, sz); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ actual_size += written; -+ if (written == sz) -+ start = 0; -+ else -+ start += written; -+ } -+ tests_maybe_sync(fd); -+ return actual_size; -+} -+ -+/* Check that a file written using tests_fill_file() and/or -+ tests_write_filled_file() and/or tests_create_file() -+ contains the expected random data */ -+void tests_check_filled_file_fd(int fd) -+{ -+ ssize_t sz; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ CHECK(lseek(fd, 0, SEEK_SET) == 0); -+ do { -+ sz = read(fd, buf, WRITE_BUFFER_SIZE); -+ CHECK(sz >= 0); -+ CHECK(memcmp(buf, write_buffer, sz) == 0); -+ } while (sz); -+} -+ -+/* Check that a file written using tests_fill_file() and/or -+ tests_write_filled_file() and/or tests_create_file() -+ contains the expected random data */ -+void tests_check_filled_file(const char *file_name) -+{ -+ int fd; -+ -+ fd = open(file_name, O_RDONLY); -+ CHECK(fd != -1); -+ tests_check_filled_file_fd(fd); -+ CHECK(close(fd) != -1); -+} -+ -+void tests_sync_directory(const char *file_name) -+{ -+ char *path; -+ char *dir; -+ int fd; -+ -+ if (!tests_ok_to_sync) -+ return; -+ -+ path = strdup(file_name); -+ dir = dirname(path); -+ fd = open(dir,O_RDONLY | tests_maybe_sync_flag()); -+ CHECK(fd != -1); -+ CHECK(fsync(fd) != -1); -+ CHECK(close(fd) != -1); -+ free(path); -+} -+ -+/* Delete a file */ -+void tests_delete_file(const char *file_name) -+{ -+ CHECK(unlink(file_name) != -1); -+ tests_sync_directory(file_name); -+} -+ -+/* Create a file of size file_size */ -+uint64_t tests_create_file(const char *file_name, uint64_t file_size) -+{ -+ int fd; -+ int flags; -+ mode_t mode; -+ uint64_t actual_size; /* Less than size if the file system is full */ -+ -+ flags = O_CREAT | O_TRUNC | O_WRONLY | tests_maybe_sync_flag(); -+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; -+ fd = open(file_name, flags, mode); -+ if (fd == -1 && errno == ENOSPC) { -+ errno = 0; -+ return 0; /* File system full */ -+ } -+ CHECK(fd != -1); -+ actual_size = tests_fill_file(fd, file_size); -+ CHECK(close(fd) != -1); -+ if (file_size != 0 && actual_size == 0) -+ tests_delete_file(file_name); -+ else -+ tests_sync_directory(file_name); -+ return actual_size; -+} -+ -+/* Calculate: free_space * numerator / denominator */ -+uint64_t tests_get_big_file_size(unsigned numerator, unsigned denominator) -+{ -+ if (denominator == 0) -+ denominator = 1; -+ if (numerator > denominator) -+ numerator = denominator; -+ return numerator * (tests_get_free_space() / denominator); -+} -+ -+/* Create file "fragment_n" where n is the file_number, and unlink it */ -+int tests_create_orphan(unsigned file_number) -+{ -+ int fd; -+ int flags; -+ mode_t mode; -+ char file_name[256]; -+ -+ sprintf(file_name, "fragment_%u", file_number); -+ flags = O_CREAT | O_TRUNC | O_RDWR | tests_maybe_sync_flag(); -+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; -+ fd = open(file_name, flags, mode); -+ if (fd == -1 && (errno == ENOSPC || errno == EMFILE)) -+ return fd; /* File system full or too many open files */ -+ CHECK(fd != -1); -+ tests_sync_directory(file_name); -+ CHECK(unlink(file_name) != -1); -+ return fd; -+} -+ -+/* Write size bytes at offset to the file "fragment_n" where n is the -+ file_number and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_write_fragment_file(unsigned file_number, -+ int fd, -+ off_t offset, -+ unsigned size) -+{ -+ int i, d; -+ uint64_t u; -+ ssize_t written; -+ off_t pos; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ if (size > WRITE_BUFFER_SIZE) -+ size = WRITE_BUFFER_SIZE; -+ -+ pos = lseek(fd, 0, SEEK_END); -+ CHECK(pos != (off_t) -1); -+ if (offset > pos) -+ offset = pos; -+ -+ pos = lseek(fd, offset, SEEK_SET); -+ CHECK(pos != (off_t) -1); -+ CHECK(pos == offset); -+ -+ srand(file_number); -+ while (offset--) -+ rand(); -+ -+ u = RAND_MAX; -+ u += 1; -+ u /= 256; -+ d = (int) u; -+ for (i = 0; i < size; ++i) -+ buf[i] = rand() / d; -+ -+ written = write(fd, buf, size); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ written = 0; -+ } -+ tests_maybe_sync(fd); -+ return (unsigned) written; -+} -+ -+/* Write size bytes to the end of file descriptor fd using file_number -+ to determine the random data written i.e. seed for random numbers */ -+unsigned tests_fill_fragment_file(unsigned file_number, int fd, unsigned size) -+{ -+ off_t offset; -+ -+ offset = lseek(fd, 0, SEEK_END); -+ CHECK(offset != (off_t) -1); -+ -+ return tests_write_fragment_file(file_number, fd, offset, size); -+} -+ -+/* Write size bytes to the end of file "fragment_n" where n is the file_number -+ and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_append_to_fragment_file(unsigned file_number, -+ unsigned size, -+ int create) -+{ -+ int fd; -+ int flags; -+ mode_t mode; -+ unsigned actual_growth; -+ char file_name[256]; -+ -+ sprintf(file_name, "fragment_%u", file_number); -+ if (create) -+ flags = O_CREAT | O_EXCL | O_WRONLY | tests_maybe_sync_flag(); -+ else -+ flags = O_WRONLY | tests_maybe_sync_flag(); -+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; -+ fd = open(file_name, flags, mode); -+ if (fd == -1 && errno == ENOSPC) { -+ errno = 0; -+ return 0; /* File system full */ -+ } -+ CHECK(fd != -1); -+ actual_growth = tests_fill_fragment_file(file_number, fd, size); -+ CHECK(close(fd) != -1); -+ if (create && !actual_growth) -+ tests_delete_fragment_file(file_number); -+ return actual_growth; -+} -+ -+/* Write size bytes at offset to the file "fragment_n" where n is the -+ file_number and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_overwite_fragment_file( unsigned file_number, -+ off_t offset, -+ unsigned size) -+{ -+ int fd; -+ unsigned actual_size; -+ char file_name[256]; -+ -+ sprintf(file_name, "fragment_%u", file_number); -+ fd = open(file_name, O_RDWR | tests_maybe_sync_flag()); -+ if (fd == -1 && errno == ENOSPC) { -+ errno = 0; -+ return 0; /* File system full */ -+ } -+ CHECK(fd != -1); -+ actual_size = tests_write_fragment_file(file_number, -+ fd, offset, size); -+ CHECK(close(fd) != -1); -+ return actual_size; -+} -+ -+/* Delete file "fragment_n" where n is the file_number */ -+void tests_delete_fragment_file(unsigned file_number) -+{ -+ char file_name[256]; -+ -+ sprintf(file_name, "fragment_%u", file_number); -+ tests_delete_file(file_name); -+} -+ -+/* Check the random data in file "fragment_n" is what is expected */ -+void tests_check_fragment_file_fd(unsigned file_number, int fd) -+{ -+ ssize_t sz, i; -+ int d; -+ uint64_t u; -+ char buf[8192]; -+ -+ CHECK(lseek(fd, 0, SEEK_SET) == 0); -+ srand(file_number); -+ u = RAND_MAX; -+ u += 1; -+ u /= 256; -+ d = (int) u; -+ for (;;) { -+ sz = read(fd, buf, 8192); -+ if (sz == 0) -+ break; -+ CHECK(sz >= 0); -+ for (i = 0; i < sz; ++i) -+ CHECK(buf[i] == (char) (rand() / d)); -+ } -+} -+ -+/* Check the random data in file "fragment_n" is what is expected */ -+void tests_check_fragment_file(unsigned file_number) -+{ -+ int fd; -+ ssize_t sz, i; -+ int d; -+ uint64_t u; -+ char file_name[256]; -+ char buf[8192]; -+ -+ sprintf(file_name, "fragment_%u", file_number); -+ fd = open(file_name, O_RDONLY); -+ CHECK(fd != -1); -+ srand(file_number); -+ u = RAND_MAX; -+ u += 1; -+ u /= 256; -+ d = (int) u; -+ for (;;) { -+ sz = read(fd, buf, 8192); -+ if (sz == 0) -+ break; -+ CHECK(sz >= 0); -+ for (i = 0; i < sz; ++i) -+ CHECK(buf[i] == (char) (rand() / d)); -+ } -+ CHECK(close(fd) != -1); -+} -+ -+/* Central point to decide whether to use fsync */ -+void tests_maybe_sync(int fd) -+{ -+ if (tests_ok_to_sync) -+ CHECK(fsync(fd) != -1); -+} -+ -+/* Return O_SYNC if ok to sync otherwise return 0 */ -+int tests_maybe_sync_flag(void) -+{ -+ if (tests_ok_to_sync) -+ return O_SYNC; -+ return 0; -+} -+ -+/* Return random number from 0 to n - 1 */ -+size_t tests_random_no(size_t n) -+{ -+ uint64_t a, b; -+ -+ if (!n) -+ return 0; -+ if (n - 1 <= RAND_MAX) { -+ a = rand(); -+ b = RAND_MAX; -+ b += 1; -+ } else { -+ const uint64_t u = 1 + (uint64_t) RAND_MAX; -+ a = rand(); -+ a *= u; -+ a += rand(); -+ b = u * u; -+ CHECK(n <= b); -+ } -+ if (RAND_MAX <= UINT32_MAX && n <= UINT32_MAX) -+ return a * n / b; -+ else /*if (RAND_MAX <= UINT64_MAX && n <= UINT64_MAX)*/ { -+ uint64_t x, y; -+ if (a < n) { -+ x = a; -+ y = n; -+ } else { -+ x = n; -+ y = a; -+ } -+ return (x * (y / b)) + ((x * (y % b)) / b); -+ } -+} -+ -+/* Make a directory empty */ -+void tests_clear_dir(const char *dir_name) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ char buf[4096]; -+ -+ dir = opendir(dir_name); -+ CHECK(dir != NULL); -+ CHECK(getcwd(buf, 4096) != NULL); -+ CHECK(chdir(dir_name) != -1); -+ for (;;) { -+ errno = 0; -+ entry = readdir(dir); -+ if (entry) { -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) { -+ if (entry->d_type == DT_DIR) { -+ tests_clear_dir(entry->d_name); -+ CHECK(rmdir(entry->d_name) != -1); -+ } else -+ CHECK(unlink(entry->d_name) != -1); -+ } -+ } else { -+ CHECK(errno == 0); -+ break; -+ } -+ } -+ CHECK(chdir(buf) != -1); -+ CHECK(closedir(dir) != -1); -+} -+ -+/* Create an empty sub-directory or small file in the current directory */ -+int64_t tests_create_entry(char *return_name) -+{ -+ int fd; -+ char name[256]; -+ -+ for (;;) { -+ sprintf(name, "%u", (unsigned) tests_random_no(10000000)); -+ fd = open(name, O_RDONLY); -+ if (fd == -1) -+ break; -+ close(fd); -+ } -+ if (return_name) -+ strcpy(return_name, name); -+ if (tests_random_no(2)) { -+ return tests_create_file(name, tests_random_no(4096)); -+ } else { -+ if (mkdir(name, 0777) == -1) { -+ CHECK(errno == ENOSPC); -+ errno = 0; -+ return 0; -+ } -+ return TESTS_EMPTY_DIR_SIZE; -+ } -+} -+ -+/* Remove a random file of empty sub-directory from the current directory */ -+int64_t tests_remove_entry(void) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ unsigned count = 0, pos; -+ int64_t result = 0; -+ -+ dir = opendir("."); -+ CHECK(dir != NULL); -+ for (;;) { -+ errno = 0; -+ entry = readdir(dir); -+ if (entry) { -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) -+ ++count; -+ } else { -+ CHECK(errno == 0); -+ break; -+ } -+ } -+ pos = tests_random_no(count); -+ count = 0; -+ rewinddir(dir); -+ for (;;) { -+ errno = 0; -+ entry = readdir(dir); -+ if (!entry) { -+ CHECK(errno == 0); -+ break; -+ } -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) { -+ if (count == pos) { -+ if (entry->d_type == DT_DIR) { -+ tests_clear_dir(entry->d_name); -+ CHECK(rmdir(entry->d_name) != -1); -+ result = TESTS_EMPTY_DIR_SIZE; -+ } else { -+ struct stat st; -+ CHECK(stat(entry->d_name, &st) != -1); -+ result = st.st_size; -+ CHECK(unlink(entry->d_name) != -1); -+ } -+ } -+ ++count; -+ } -+ } -+ CHECK(closedir(dir) != -1); -+ return result; -+} -+ -+/* Read mount information from /proc/mounts or /etc/mtab */ -+int tests_get_mount_info(struct mntent *info) -+{ -+ FILE *f; -+ struct mntent *entry; -+ int found = 0; -+ -+ f = fopen("/proc/mounts", "rb"); -+ if (!f) -+ f = fopen("/etc/mtab", "rb"); -+ CHECK(f != NULL); -+ while (!found) { -+ entry = getmntent(f); -+ if (entry) { -+ if (strcmp(entry->mnt_dir, -+ tests_file_system_mount_dir) == 0) { -+ found = 1; -+ *info = *entry; -+ } -+ } else -+ break; -+ } -+ CHECK(fclose(f) == 0); -+ return found; -+} -+ -+/* Un-mount and re-mount test file system */ -+void tests_remount(void) -+{ -+ struct mntent mount_info; -+ char *source; -+ char *target; -+ char *filesystemtype; -+ unsigned long mountflags; -+ void *data; -+ char cwd[4096]; -+ -+ CHECK(tests_get_mount_info(&mount_info)); -+ -+ if (strcmp(mount_info.mnt_dir,"/") == 0) -+ return; -+ -+ CHECK(getcwd(cwd, 4096) != NULL); -+ CHECK(chdir("/") != -1); -+ -+ CHECK(umount(tests_file_system_mount_dir) != -1); -+ -+ source = mount_info.mnt_fsname; -+ target = tests_file_system_mount_dir; -+ filesystemtype = tests_file_system_type; -+ mountflags = 0; -+ data = NULL; -+ -+ CHECK(mount(source, target, filesystemtype, mountflags, data) != -1); -+ -+ CHECK(chdir(cwd) != -1); -+} -+ -+/* Check whether the test file system is also the root file system */ -+int tests_fs_is_rootfs(void) -+{ -+ struct stat f_info; -+ struct stat root_f_info; -+ -+ CHECK(stat(tests_file_system_mount_dir, &f_info) != -1); -+ CHECK(stat("/", &root_f_info) != -1); -+ if (f_info.st_dev == root_f_info.st_dev) -+ return 1; -+ else -+ return 0; -+} -+ -+/* Try to make a directory empty */ -+void tests_try_to_clear_dir(const char *dir_name) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ char buf[4096]; -+ -+ dir = opendir(dir_name); -+ if (dir == NULL) -+ return; -+ if (getcwd(buf, 4096) == NULL || chdir(dir_name) == -1) { -+ closedir(dir); -+ return; -+ } -+ for (;;) { -+ errno = 0; -+ entry = readdir(dir); -+ if (entry) { -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) { -+ if (entry->d_type == DT_DIR) { -+ tests_try_to_clear_dir(entry->d_name); -+ rmdir(entry->d_name); -+ } else -+ unlink(entry->d_name); -+ } -+ } else { -+ CHECK(errno == 0); -+ break; -+ } -+ } -+ chdir(buf); -+ closedir(dir); -+} -+ -+/* Check whether the test file system is also the current file system */ -+int tests_fs_is_currfs(void) -+{ -+ struct stat f_info; -+ struct stat curr_f_info; -+ -+ CHECK(stat(tests_file_system_mount_dir, &f_info) != -1); -+ CHECK(stat(".", &curr_f_info) != -1); -+ if (f_info.st_dev == curr_f_info.st_dev) -+ return 1; -+ else -+ return 0; -+} -+ -+#define PID_BUF_SIZE 64 -+ -+/* Concatenate a pid to a string in a signal safe way */ -+void tests_cat_pid(char *buf, const char *name, pid_t pid) -+{ -+ char *p; -+ unsigned x; -+ const char digits[] = "0123456789"; -+ char pid_buf[PID_BUF_SIZE]; -+ -+ x = (unsigned) pid; -+ p = pid_buf + PID_BUF_SIZE; -+ *--p = '\0'; -+ if (x) -+ while (x) { -+ *--p = digits[x % 10]; -+ x /= 10; -+ } -+ else -+ *--p = '0'; -+ buf[0] = '\0'; -+ strcat(buf, name); -+ strcat(buf, p); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,199 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#ifndef included_tests_tests_h__ -+#define included_tests_tests_h__ -+ -+#include -+ -+/* Main macro for testing */ -+#define CHECK(x) tests_test((x),__func__,__FILE__,__LINE__) -+ -+/* The default directory in which tests are conducted */ -+#define TESTS_DEFAULT_FILE_SYSTEM_MOUNT_DIR "/mnt/test_file_system" -+ -+/* The default file system type to test */ -+#define TESTS_DEFAULT_FILE_SYSTEM_TYPE "jffs2" -+ -+/* Estimated size of an empty directory */ -+#define TESTS_EMPTY_DIR_SIZE 128 -+ -+/* Function invoked by the CHECK macro */ -+void tests_test(int test,const char *msg,const char *file,unsigned line); -+ -+/* Handle common program options */ -+int tests_get_args(int argc, -+ char *argv[], -+ const char *title, -+ const char *desc, -+ const char *opts); -+ -+/* Return the number of files (or directories) in the given directory */ -+unsigned tests_count_files_in_dir(const char *dir_name); -+ -+/* Change to the file system mount directory, check that it is empty, -+ matches the file system type, and is not the root file system */ -+void tests_check_test_file_system(void); -+ -+/* Get the free space for the file system of the current directory */ -+uint64_t tests_get_free_space(void); -+ -+/* Get the total space for the file system of the current directory */ -+uint64_t tests_get_total_space(void); -+ -+/* Write size random bytes into file descriptor fd at the current position, -+ returning the number of bytes actually written */ -+uint64_t tests_fill_file(int fd, uint64_t size); -+ -+/* Write size random bytes into file descriptor fd at offset, -+ returning the number of bytes actually written */ -+uint64_t tests_write_filled_file(int fd, off_t offset, uint64_t size); -+ -+/* Check that a file written using tests_fill_file() and/or -+ tests_write_filled_file() and/or tests_create_file() -+ contains the expected random data */ -+void tests_check_filled_file_fd(int fd); -+ -+/* Check that a file written using tests_fill_file() and/or -+ tests_write_filled_file() and/or tests_create_file() -+ contains the expected random data */ -+void tests_check_filled_file(const char *file_name); -+ -+/* Delete a file */ -+void tests_delete_file(const char *file_name); -+ -+/* Create a file of size file_size */ -+uint64_t tests_create_file(const char *file_name, uint64_t file_size); -+ -+/* Calculate: free_space * numerator / denominator */ -+uint64_t tests_get_big_file_size(unsigned numerator, unsigned denominator); -+ -+/* Create file "fragment_n" where n is the file_number, and unlink it */ -+int tests_create_orphan(unsigned file_number); -+ -+/* Write size bytes at offset to the file "fragment_n" where n is the -+ file_number and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_write_fragment_file(unsigned file_number, -+ int fd, -+ off_t offset, -+ unsigned size); -+ -+/* Write size bytes to the end of file descriptor fd using file_number -+ to determine the random data written i.e. seed for random numbers */ -+unsigned tests_fill_fragment_file(unsigned file_number, -+ int fd, -+ unsigned size); -+ -+/* Write size bytes to the end of file "fragment_n" where n is the file_number -+ and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_append_to_fragment_file(unsigned file_number, -+ unsigned size, -+ int create); -+ -+/* Write size bytes at offset to the file "fragment_n" where n is the -+ file_number and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_overwite_fragment_file( unsigned file_number, -+ off_t offset, -+ unsigned size); -+ -+/* Delete file "fragment_n" where n is the file_number */ -+void tests_delete_fragment_file(unsigned file_number); -+ -+/* Check the random data in file "fragment_n" is what is expected */ -+void tests_check_fragment_file_fd(unsigned file_number, int fd); -+ -+/* Check the random data in file "fragment_n" is what is expected */ -+void tests_check_fragment_file(unsigned file_number); -+ -+/* Central point to decide whether to use fsync */ -+void tests_maybe_sync(int fd); -+ -+/* Return O_SYNC if ok to sync otherwise return 0 */ -+int tests_maybe_sync_flag(void); -+ -+/* Return random number from 0 to n - 1 */ -+size_t tests_random_no(size_t n); -+ -+/* Make a directory empty */ -+void tests_clear_dir(const char *dir_name); -+ -+/* Create an empty sub-directory or small file in the current directory */ -+int64_t tests_create_entry(char *return_name); -+ -+/* Remove a random file of empty sub-directory from the current directory */ -+int64_t tests_remove_entry(void); -+ -+/* Un-mount and re-mount test file system */ -+void tests_remount(void); -+ -+/* Check whether the test file system is also the root file system */ -+int tests_fs_is_rootfs(void); -+ -+/* Try to make a directory empty */ -+void tests_try_to_clear_dir(const char *dir_name); -+ -+/* Check whether the test file system is also the current file system */ -+int tests_fs_is_currfs(void); -+ -+/* Concatenate a pid to a string in a signal safe way */ -+void tests_cat_pid(char *buf, const char *name, pid_t pid); -+ -+extern char *tests_file_system_mount_dir; -+ -+extern char *tests_file_system_type; -+ -+/* General purpose test parameter to specify some aspect of test size. -+ May be used by different tests in different ways. -+ Set by the -z, --size options. */ -+extern int64_t tests_size_parameter; -+ -+/* General purpose test parameter to specify some aspect of test repetition. -+ May be used by different tests in different ways. -+ Set by the -n, --repeat options. */ -+extern int64_t tests_repeat_parameter; -+ -+/* General purpose test parameter to specify some aspect of test sleeping. -+ May be used by different tests in different ways. -+ Set by the -p, --sleep options. */ -+extern int64_t tests_sleep_parameter; -+ -+/* General purpose test parameter to specify a file should be unlinked. -+ May be used by different tests in different ways or not at all. */ -+extern int tests_unlink_flag; -+ -+/* General purpose test parameter to specify a file should be closed. -+ May be used by different tests in different ways or not at all. */ -+extern int tests_close_flag; -+ -+/* General purpose test parameter to specify a file should be deleted. -+ May be used by different tests in different ways or not at all. */ -+extern int tests_delete_flag; -+ -+/* General purpose test parameter to specify a file have a hole. -+ May be used by different tests in different ways or not at all. */ -+extern int tests_hole_flag; -+ -+/* Program name from argv[0] */ -+extern char *program_name; -+ -+#endif ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,49 @@ -+#!/bin/sh -+ -+TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR -+if test -z "$TEST_DIR"; -+then -+ TEST_DIR="/mnt/test_file_system" -+fi -+ -+rm -rf ${TEST_DIR}/* -+ -+./simple/test_1 || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./simple/test_2 || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./integrity/integck || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./stress/atoms/rndrm00 -z0 || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./stress/atoms/rmdir00 -z0 || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./stress/atoms/stress_1 -z10000000 -e || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./stress/atoms/stress_2 -z10000000 || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./stress/atoms/stress_3 -z1000000000 -e || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+cd stress || exit 1 -+ -+./stress00.sh 3600 || exit 1 -+ -+./stress01.sh 3600 || exit 1 -+ -+cd .. || exit 1 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,28 @@ -+ -+ifeq ($(origin CC),default) -+CC = gcc -+endif -+ -+CFLAGS := $(CFLAGS) -Wall -g -O2 -I../lib -+ -+LDFLAGS := $(LDFLAGS) -+ -+TARGETS = test_1 \ -+ test_2 \ -+ ftrunc \ -+ orph -+ -+all: $(TARGETS) -+ -+$(TARGETS): ../lib/tests.o -+ -+../lib/tests.o: ../lib/tests.h -+ -+clean: -+ rm -f *.o $(TARGETS) -+ -+tests: all -+ ./test_1 --sync -+ ./test_2 --sync -+ ./ftrunc -+ ./orph --sync ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,111 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+void ftrunc(void) -+{ -+ int fd, i; -+ pid_t pid; -+ ssize_t written; -+ int64_t remains; -+ size_t block; -+ char *file_name; -+ off_t actual; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ file_name = "ftrunc_test_file"; -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ pid = getpid(); -+ srand(pid); -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ remains = tests_size_parameter; -+ actual = 0; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ actual += written; -+ } -+ CHECK(ftruncate(fd, (actual ? actual - 1 : actual)) != -1); -+ CHECK(close(fd) != -1); -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *ftrunc_get_title(void) -+{ -+ return "Truncate a large test file"; -+} -+ -+/* Description of this test */ -+ -+const char *ftrunc_get_description(void) -+{ -+ return -+ "Create a file named ftrunc_test_file. " \ -+ "Truncate the file to reduce its length by 1. " \ -+ "Then remove the truncated file. " -+ "The size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, ftrunc_get_title(), -+ ftrunc_get_description(), "z"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ ftrunc(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,184 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define MAX_ORPHANS 1000000 -+ -+void orph(void) -+{ -+ pid_t pid; -+ unsigned i, j, k, n; -+ int fd, done, full; -+ int64_t repeat; -+ ssize_t sz; -+ char dir_name[256]; -+ int fds[MAX_ORPHANS]; -+ -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "orph_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ -+ repeat = tests_repeat_parameter; -+ for (;;) { -+ full = 0; -+ done = 0; -+ n = 0; -+ while (n + 100 < MAX_ORPHANS && !done) { -+ /* Make 100 more orphans */ -+ for (i = 0; i < 100; i++) { -+ fd = tests_create_orphan(n + i); -+ if (fd < 0) { -+ done = 1; -+ if (errno == ENOSPC) -+ full = 1; -+ else if (errno != EMFILE) -+ CHECK(0); -+ errno = 0; -+ break; -+ } -+ fds[n + i] = fd; -+ } -+ if (!full) { -+ /* Write to orphans just created */ -+ k = i; -+ for (i = 0; i < k; i++) { -+ if (tests_write_fragment_file(n + i, -+ fds[n+i], -+ 0, 1000) -+ != 1000) { -+ /* -+ * Out of space, so close -+ * remaining files -+ */ -+ for (j = i; j < k; j++) -+ CHECK(close(fds[n + j]) -+ != -1); -+ done = 1; -+ break; -+ } -+ } -+ } -+ if (!done) -+ CHECK(tests_count_files_in_dir(".") == 0); -+ n += i; -+ } -+ /* Check the data in the files */ -+ for (i = 0; i < n; i++) -+ tests_check_fragment_file_fd(i, fds[i]); -+ if (!full && n) { -+ /* Ensure the file system is full */ -+ n -= 1; -+ do { -+ sz = write(fds[n], fds, 4096); -+ if (sz == -1 && errno == ENOSPC) { -+ errno = 0; -+ break; -+ } -+ CHECK(sz >= 0); -+ } while (sz == 4096); -+ CHECK(close(fds[n]) != -1); -+ } -+ /* Check the data in the files */ -+ for (i = 0; i < n; i++) -+ tests_check_fragment_file_fd(i, fds[i]); -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ /* Close orphans */ -+ for (i = 0; i < n; i++) -+ CHECK(close(fds[i]) != -1); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ } -+ CHECK(tests_count_files_in_dir(".") == 0); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *orph_get_title(void) -+{ -+ return "Create many open unlinked files"; -+} -+ -+/* Description of this test */ -+ -+const char *orph_get_description(void) -+{ -+ return -+ "Create a directory named orph_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, " \ -+ "create files and keep them open and unlink them. " \ -+ "Create as many files as possible until the file system is " \ -+ "full or the maximum allowed open files is reached. " \ -+ "If a sleep value is specified, the process sleeps. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " \ -+ "Sleep is specified in milliseconds. " \ -+ "Then close the files. " \ -+ "If a repeat count is specified, then the task repeats " \ -+ "that number of times. " \ -+ "The repeat count is given by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "Finally remove the directory."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, orph_get_title(), -+ orph_get_description(), "nps"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ orph(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,150 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+void test_1(void) -+{ -+ int fd; -+ pid_t pid; -+ uint64_t i; -+ uint64_t block; -+ uint64_t actual_size; -+ char name[256]; -+ char old[16]; -+ char buf[16]; -+ off_t old_len; -+ char dir_name[256]; -+ -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "test_1_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ /* Create a file that fills half the free space on the file system */ -+ tests_create_file("big_file", tests_get_big_file_size(1,2)); -+ CHECK(tests_count_files_in_dir(".") == 1); -+ fd = open("big_file", O_RDWR | tests_maybe_sync_flag()); -+ CHECK(fd != -1); -+ CHECK(read(fd, old, 5) == 5); -+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1); -+ CHECK(write(fd,"start", 5) == 5); -+ CHECK(lseek(fd,0,SEEK_END) != (off_t) -1); -+ CHECK(write(fd, "end", 3) == 3); -+ tests_maybe_sync(fd); -+ /* Delete the file while it is still open */ -+ tests_delete_file("big_file"); -+ CHECK(tests_count_files_in_dir(".") == 0); -+ /* Create files to file up the file system */ -+ for (block = 1000000, i = 1; ; block /= 10) { -+ while (i != 0) { -+ sprintf(name, "fill_up_%llu", i); -+ actual_size = tests_create_file(name, block); -+ if (actual_size != 0) -+ ++i; -+ if (actual_size != block) -+ break; -+ } -+ if (block == 1) -+ break; -+ } -+ /* Check the big file */ -+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1); -+ CHECK(read(fd, buf, 5) == 5); -+ CHECK(strncmp(buf, "start", 5) == 0); -+ CHECK(lseek(fd, -3, SEEK_END) != (off_t) -1); -+ CHECK(read(fd, buf, 3) == 3); -+ CHECK(strncmp(buf, "end", 3) == 0); -+ /* Check the other files and delete them */ -+ i -= 1; -+ CHECK(tests_count_files_in_dir(".") == i); -+ for (; i > 0; --i) { -+ sprintf(name, "fill_up_%llu", i); -+ tests_check_filled_file(name); -+ tests_delete_file(name); -+ } -+ CHECK(tests_count_files_in_dir(".") == 0); -+ /* Check the big file again */ -+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1); -+ CHECK(read(fd, buf, 5) == 5); -+ CHECK(strncmp(buf, "start", 5) == 0); -+ CHECK(lseek(fd, -3, SEEK_END) != (off_t) -1); -+ CHECK(read(fd, buf, 3) == 3); -+ CHECK(strncmp(buf, "end", 3) == 0); -+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1); -+ CHECK(write(fd,old, 5) == 5); -+ old_len = lseek(fd, -3, SEEK_END); -+ CHECK(old_len != (off_t) -1); -+ CHECK(ftruncate(fd,old_len) != -1); -+ tests_check_filled_file_fd(fd); -+ /* Close the big file*/ -+ CHECK(close(fd) != -1); -+ CHECK(tests_count_files_in_dir(".") == 0); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *test_1_get_title(void) -+{ -+ return "Fill file system while holding deleted big file descriptor"; -+} -+ -+/* Description of this test */ -+ -+const char *test_1_get_description(void) -+{ -+ return -+ "Create a directory named test_1_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, " \ -+ "create a big file (approx. half the file system in size), " \ -+ "open it, and unlink it. " \ -+ "Create many smaller files until the file system is full. " \ -+ "Check the big file is ok. " \ -+ "Delete all the smaller files. " \ -+ "Check the big file again. " \ -+ "Finally delete the big file and directory."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, test_1_get_title(), -+ test_1_get_description(), "s"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ test_1(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,201 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+void test_2(void) -+{ -+ pid_t pid; -+ int create, full; -+ unsigned i, number_of_files; -+ unsigned growth; -+ unsigned size; -+ uint64_t big_file_size; -+ int fd; -+ off_t offset; -+ char dir_name[256]; -+ -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "test_2_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ /* Create up to 1000 files appending 400 bytes at a time to each file */ -+ /* until the file system is full.*/ -+ create = 1; -+ full = 0; -+ number_of_files = 1000; -+ while (!full) { -+ for (i = 0; i < number_of_files; ++i) { -+ growth = tests_append_to_fragment_file(i, 400, create); -+ if (!growth) { -+ full = 1; -+ if (create) -+ number_of_files = i; -+ break; -+ } -+ } -+ create = 0; -+ } -+ /* Check the files */ -+ CHECK(tests_count_files_in_dir(".") == number_of_files); -+ for (i = 0; i < number_of_files; ++i) -+ tests_check_fragment_file(i); -+ /* Delete half of them */ -+ for (i = 1; i < number_of_files; i += 2) -+ tests_delete_fragment_file(i); -+ /* Check them again */ -+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2); -+ /* Create a big file that fills two thirds of the free space */ -+ big_file_size = tests_get_big_file_size(2,3); -+ /* Check the big file */ -+ tests_create_file("big_file", big_file_size); -+ CHECK(tests_count_files_in_dir(".") == 1 + (number_of_files + 1) / 2); -+ tests_check_filled_file("big_file"); -+ /* Open the big file */ -+ fd = open("big_file",O_RDWR | tests_maybe_sync_flag()); -+ CHECK(fd != -1); -+ /* Delete the big file while it is still open */ -+ tests_delete_file("big_file"); -+ /* Check the big file again */ -+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2); -+ tests_check_filled_file_fd(fd); -+ -+ /* Write parts of the files and check them */ -+ -+ offset = 100; /* Offset to write at, in the small files */ -+ size = 200; /* Number of bytes to write at the offset */ -+ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_overwite_fragment_file(i, offset, size); -+ /* Rewrite the big file entirely */ -+ tests_write_filled_file(fd, 0, big_file_size); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ tests_check_filled_file_fd(fd); -+ -+ offset = 300; /* Offset to write at, in the small files */ -+ size = 400; /* Number of bytes to write at the offset */ -+ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_overwite_fragment_file(i, offset, size); -+ /* Rewrite the big file entirely */ -+ tests_write_filled_file(fd, 0, big_file_size); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ tests_check_filled_file_fd(fd); -+ -+ offset = 110; /* Offset to write at, in the small files */ -+ size = 10; /* Number of bytes to write at the offset */ -+ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_overwite_fragment_file(i, offset, size); -+ /* Rewrite the big file entirely */ -+ tests_write_filled_file(fd, 0, big_file_size); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ tests_check_filled_file_fd(fd); -+ -+ offset = 10; /* Offset to write at, in the small files */ -+ size = 1000; /* Number of bytes to write at the offset */ -+ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_overwite_fragment_file(i, offset, size); -+ /* Rewrite the big file entirely */ -+ tests_write_filled_file(fd, 0, big_file_size); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ tests_check_filled_file_fd(fd); -+ -+ offset = 0; /* Offset to write at, in the small files */ -+ size = 100000; /* Number of bytes to write at the offset */ -+ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_overwite_fragment_file(i, offset, size); -+ /* Rewrite the big file entirely */ -+ tests_write_filled_file(fd, 0, big_file_size); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ tests_check_filled_file_fd(fd); -+ -+ /* Close the big file*/ -+ CHECK(close(fd) != -1); -+ /* Check the small files */ -+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ /* Delete the small files */ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_delete_fragment_file(i); -+ CHECK(tests_count_files_in_dir(".") == 0); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *test_2_get_title(void) -+{ -+ return "Repeated write many small files and one big deleted file"; -+} -+ -+/* Description of this test */ -+ -+const char *test_2_get_description(void) -+{ -+ return -+ "Create a directory named test_2_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, " \ -+ "create about 1000 files. Append 400 bytes to each until " \ -+ "the file system is full. Then delete half of them. Then " \ -+ "create a big file that uses about 2/3 of the remaining free " \ -+ "space. Get a file descriptor for the big file, and delete " \ -+ "the big file. Then repeatedly write to the small files " \ -+ "and the big file. " \ -+ "Finally delete the big file and directory."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, test_2_get_title(), -+ test_2_get_description(), "s"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ test_2(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,11 @@ -+ -+SUBDIRS = atoms -+ -+all tests: $(SUBDIRS) -+ -+clean: $(SUBDIRS) -+ rm -rf run_pdf_test_file_* -+ -+.PHONY: $(SUBDIRS) -+$(SUBDIRS): -+ $(MAKE) -C $@ $(MAKECMDGOALS) ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,40 @@ -+ -+ifeq ($(origin CC),default) -+CC = gcc -+endif -+ -+CFLAGS := $(CFLAGS) -Wall -g -O2 -I../../lib -+ -+LDFLAGS := $(LDFLAGS) -+ -+TARGETS = stress_1 \ -+ stress_2 \ -+ stress_3 \ -+ pdfrun \ -+ rndwrite00 \ -+ fwrite00 \ -+ rmdir00 \ -+ rndrm00 \ -+ rndrm99 \ -+ gcd_hupper -+ -+all: $(TARGETS) -+ -+$(TARGETS): ../../lib/tests.o -+ -+../lib/tests.o: ../../lib/tests.h -+ -+clean: -+ rm -f *.o $(TARGETS) run_pdf_test_file -+ -+tests: all -+ ./stress_1 -e -+ ./stress_2 -+ ./stress_3 -e -+ ./pdfrun -+ ./rndwrite00 -e -+ ./fwrite00 -+ ./rmdir00 -+ ./rndrm00 -+ ./rndrm99 -+ ./gcd_hupper ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,209 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+#define HOLE_BLOCK_SIZE 10000000 -+ -+void filestress00(void) -+{ -+ int fd, i, deleted; -+ pid_t pid; -+ ssize_t written; -+ int64_t remains; -+ int64_t repeat; -+ size_t block; -+ char file_name[256]; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ fd = -1; -+ deleted = 1; -+ pid = getpid(); -+ tests_cat_pid(file_name, "filestress00_test_file_", pid); -+ srand(pid); -+ repeat = tests_repeat_parameter; -+ for (;;) { -+ /* Open the file */ -+ if (fd == -1) { -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ deleted = 0; -+ if (tests_unlink_flag) { -+ CHECK(unlink(file_name) != -1); -+ deleted = 1; -+ } -+ } -+ /* Get a different set of random data */ -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ if (tests_hole_flag) { -+ /* Make a hole */ -+ CHECK(lseek(fd, tests_size_parameter, SEEK_SET) != -1); -+ written = write(fd, "!", 1); -+ if (written <= 0) { -+ /* File system full */ -+ CHECK(errno == ENOSPC); -+ errno = 0; -+ } -+ CHECK(lseek(fd, 0, SEEK_SET) != -1); -+ /* Write at set points into the hole */ -+ remains = tests_size_parameter; -+ while (remains > HOLE_BLOCK_SIZE) { -+ CHECK(lseek(fd, HOLE_BLOCK_SIZE, -+ SEEK_CUR) != -1); -+ written = write(fd, "!", 1); -+ remains -= HOLE_BLOCK_SIZE; -+ if (written <= 0) { -+ /* File system full */ -+ CHECK(errno == ENOSPC); -+ errno = 0; -+ break; -+ } -+ } -+ } else { -+ /* Write data into the file */ -+ CHECK(lseek(fd, 0, SEEK_SET) != -1); -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ /* File system full */ -+ CHECK(errno == ENOSPC); -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ } -+ } -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ /* Close if tests_close_flag */ -+ if (tests_close_flag) { -+ CHECK(close(fd) != -1); -+ fd = -1; -+ } -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ /* Delete if tests_delete flag */ -+ if (!deleted && tests_delete_flag) { -+ CHECK(unlink(file_name) != -1); -+ deleted = 1; -+ } -+ } -+ CHECK(close(fd) != -1); -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ /* Tidy up */ -+ if (!deleted) -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *filestress00_get_title(void) -+{ -+ return "File stress test 00"; -+} -+ -+/* Description of this test */ -+ -+const char *filestress00_get_description(void) -+{ -+ return -+ "Create a file named filestress00_test_file_pid, where " \ -+ "pid is the process id. If the unlink option " \ -+ "(-u or --unlink) is specified, " \ -+ "unlink the file while holding the open file descriptor. " \ -+ "If the hole option (-o or --hole) is specified, " \ -+ "write a single character at the end of the file, creating a " \ -+ "hole. " \ -+ "Write a single character in the hole every 10 million " \ -+ "bytes. " \ -+ "If the hole option is not specified, then the file is " \ -+ "filled with random data. " \ -+ "If the close option (-c or --close) is specified the file " \ -+ "is closed. " \ -+ "If a sleep value is specified, the process sleeps. " \ -+ "If the delete option (-e or --delete) is specified, then " \ -+ "the file is deleted. " \ -+ "If a repeat count is specified, then the task repeats " \ -+ "that number of times. " \ -+ "The repeat count is given by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The file size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " \ -+ "Sleep is specified in milliseconds."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, filestress00_get_title(), -+ filestress00_get_description(), "znpuoce"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ filestress00(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,259 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define MAX_NAME_SIZE 1024 -+ -+struct gcd_pid -+{ -+ struct gcd_pid *next; -+ int pid; -+ char *name; -+ int mtd_index; -+}; -+ -+struct gcd_pid *gcd_pid_list = NULL; -+ -+int add_gcd_pid(const char *number) -+{ -+ int pid; -+ FILE *f; -+ char file_name[MAX_NAME_SIZE]; -+ char program_name[MAX_NAME_SIZE]; -+ -+ pid = atoi(number); -+ if (pid <= 0) -+ return 0; -+ snprintf(file_name, MAX_NAME_SIZE, "/proc/%s/stat", number); -+ f = fopen(file_name, "r"); -+ if (f == NULL) -+ return 0; -+ if (fscanf(f, "%d %s", &pid, program_name) != 2) { -+ fclose(f); -+ return 0; -+ } -+ if (strncmp(program_name, "(jffs2_gcd_mtd", 14) != 0) -+ pid = 0; -+ if (pid) { -+ size_t sz; -+ struct gcd_pid *g; -+ -+ sz = sizeof(struct gcd_pid); -+ g = (struct gcd_pid *) malloc(sz); -+ g->pid = pid; -+ g->name = (char *) malloc(strlen(program_name) + 1); -+ if (g->name) -+ strcpy(g->name, program_name); -+ else -+ exit(1); -+ g->mtd_index = atoi(program_name + 14); -+ g->next = gcd_pid_list; -+ gcd_pid_list = g; -+ } -+ fclose(f); -+ return pid; -+} -+ -+int get_pid_list(void) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ -+ dir = opendir("/proc"); -+ if (dir == NULL) -+ return 1; -+ for (;;) { -+ entry = readdir(dir); -+ if (entry) { -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) -+ add_gcd_pid(entry->d_name); -+ } else -+ break; -+ } -+ closedir(dir); -+ return 0; -+} -+ -+int parse_index_number(const char *name) -+{ -+ const char *p, *q; -+ int all_zero; -+ int index; -+ -+ p = name; -+ while (*p && !isdigit(*p)) -+ ++p; -+ if (!*p) -+ return -1; -+ all_zero = 1; -+ for (q = p; *q; ++q) { -+ if (!isdigit(*q)) -+ return -1; -+ if (*q != '0') -+ all_zero = 0; -+ } -+ if (all_zero) -+ return 0; -+ index = atoi(p); -+ if (index <= 0) -+ return -1; -+ return index; -+} -+ -+int get_mtd_index(void) -+{ -+ FILE *f; -+ struct mntent *entry; -+ struct stat f_info; -+ struct stat curr_f_info; -+ int found; -+ int mtd_index = -1; -+ -+ if (stat(tests_file_system_mount_dir, &f_info) == -1) -+ return -1; -+ f = fopen("/proc/mounts", "rb"); -+ if (!f) -+ f = fopen("/etc/mtab", "rb"); -+ if (f == NULL) -+ return -1; -+ found = 0; -+ for (;;) { -+ entry = getmntent(f); -+ if (!entry) -+ break; -+ if (stat(entry->mnt_dir, &curr_f_info) == -1) -+ continue; -+ if (f_info.st_dev == curr_f_info.st_dev) { -+ int i; -+ -+ i = parse_index_number(entry->mnt_fsname); -+ if (i != -1) { -+ if (found && i != mtd_index) -+ return -1; -+ found = 1; -+ mtd_index = i; -+ } -+ } -+ } -+ fclose(f); -+ return mtd_index; -+} -+ -+int get_gcd_pid() -+{ -+ struct gcd_pid *g; -+ int mtd_index; -+ -+ if (get_pid_list()) -+ return 0; -+ mtd_index = get_mtd_index(); -+ if (mtd_index == -1) -+ return 0; -+ for (g = gcd_pid_list; g; g = g->next) -+ if (g->mtd_index == mtd_index) -+ return g->pid; -+ return 0; -+} -+ -+void gcd_hupper(void) -+{ -+ int64_t repeat; -+ int pid; -+ -+ pid = get_gcd_pid(); -+ CHECK(pid != 0); -+ repeat = tests_repeat_parameter; -+ for (;;) { -+ CHECK(kill(pid, SIGHUP) != -1); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ } -+} -+ -+/* Title of this test */ -+ -+const char *gcd_hupper_get_title(void) -+{ -+ return "Send HUP signals to gcd"; -+} -+ -+/* Description of this test */ -+ -+const char *gcd_hupper_get_description(void) -+{ -+ return -+ "Determine the PID of the gcd process. " \ -+ "Send it SIGHUP (may require root privileges). " \ -+ "If a sleep value is specified, the process sleeps. " \ -+ "If a repeat count is specified, then the task repeats " \ -+ "that number of times. " \ -+ "The repeat count is given by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 1. " -+ "Sleep is specified in milliseconds."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 1; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, gcd_hupper_get_title(), -+ gcd_hupper_get_description(), "np"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ gcd_hupper(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,143 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+void adjust_size(void) -+{ -+ char dummy[1024]; -+ unsigned long total_memory; -+ FILE *f; -+ -+ total_memory = 0; -+ f = fopen("/proc/meminfo", "r"); -+ fscanf(f, "%s %lu", dummy, &total_memory); -+ fclose(f); -+ if (total_memory > 0 && tests_size_parameter > total_memory / 2) -+ tests_size_parameter = total_memory / 2; -+} -+ -+void run_pdf(void) -+{ -+ int fd, i; -+ pid_t pid; -+ int64_t repeat; -+ ssize_t written; -+ int64_t remains; -+ size_t block; -+ char file_name[256]; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ if (tests_fs_is_currfs()) -+ return; -+ adjust_size(); -+ pid = getpid(); -+ tests_cat_pid(file_name, "run_pdf_test_file_", pid); -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ pid = getpid(); -+ srand(pid); -+ repeat = tests_repeat_parameter; -+ for (;;) { -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ } -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ CHECK(lseek(fd, 0, SEEK_SET) == 0); -+ } -+ CHECK(close(fd) != -1); -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *run_pdf_get_title(void) -+{ -+ return "Create / overwrite a large file in the current directory"; -+} -+ -+/* Description of this test */ -+ -+const char *run_pdf_get_description(void) -+{ -+ return -+ "Create a file named run_pdf_test_file_pid, " \ -+ "where pid is the process id. The file is created " \ -+ "in the current directory, " \ -+ "if the current directory is NOT on the test " \ -+ "file system, otherwise no action is taken. " \ -+ "If a repeat count is specified, then the task repeats " \ -+ "that number of times. " \ -+ "The repeat count is given by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "The size is adjusted so that it is not more than " \ -+ "half the size of total memory."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, run_pdf_get_title(), -+ run_pdf_get_description(), "zn"); -+ if (!run_test) -+ return 1; -+ /* Do the actual test */ -+ run_pdf(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,133 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+void rmdir00(void) -+{ -+ int64_t repeat; -+ int64_t size, this_size; -+ pid_t pid; -+ char dir_name[256]; -+ -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "rmdir00_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ /* Repeat loop */ -+ repeat = tests_repeat_parameter; -+ size = 0; -+ for (;;) { -+ /* Remove everything in the directory */ -+ tests_clear_dir("."); -+ /* Fill with sub-dirs and small files */ -+ do { -+ this_size = tests_create_entry(NULL); -+ if (!this_size) -+ break; -+ size += this_size; -+ } while (this_size && -+ (tests_size_parameter == 0 || -+ size < tests_size_parameter)); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ } -+ /* Tidy up by removing everything */ -+ tests_clear_dir("."); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *rmdir00_get_title(void) -+{ -+ return "Create and remove directories and files"; -+} -+ -+/* Description of this test */ -+ -+const char *rmdir00_get_description(void) -+{ -+ return -+ "Create a directory named rmdir00_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, create " \ -+ "a number of sub-directories and small files. " \ -+ "The total size of all sub-directories and files " \ -+ "is specified by the size parameter. " \ -+ "The size parameter is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "A size of zero fills the file system until there is no " -+ "space left. " \ -+ "The task repeats, sleeping in between each iteration, " \ -+ "and then removing the sub-directories and files created " \ -+ "during the last iteration. " \ -+ "The repeat count is set by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " -+ "Sleep is specified in milliseconds."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, rmdir00_get_title(), -+ rmdir00_get_description(), "znp"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ rmdir00(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,157 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+void rndrm00(void) -+{ -+ int64_t repeat; -+ int64_t size, this_size; -+ pid_t pid; -+ char dir_name[256]; -+ -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "rndrm00_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ /* Repeat loop */ -+ repeat = tests_repeat_parameter; -+ size = 0; -+ for (;;) { -+ /* Create and remove sub-dirs and small files, */ -+ /* but tending to grow */ -+ do { -+ if (tests_random_no(3)) { -+ this_size = tests_create_entry(NULL); -+ if (!this_size) -+ break; -+ size += this_size; -+ } else { -+ this_size = tests_remove_entry(); -+ size -= this_size; -+ if (size < 0) -+ size = 0; -+ if (!this_size) -+ this_size = 1; -+ } -+ } while (this_size && -+ (tests_size_parameter == 0 || -+ size < tests_size_parameter)); -+ /* Create and remove sub-dirs and small files, but */ -+ /* but tending to shrink */ -+ do { -+ if (!tests_random_no(3)) { -+ this_size = tests_create_entry(NULL); -+ size += this_size; -+ } else { -+ this_size = tests_remove_entry(); -+ size -= this_size; -+ if (size < 0) -+ size = 0; -+ } -+ } while ((tests_size_parameter != 0 && -+ size > tests_size_parameter / 10) || -+ (tests_size_parameter == 0 && size > 100000)); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ } -+ /* Tidy up by removing everything */ -+ tests_clear_dir("."); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *rndrm00_get_title(void) -+{ -+ return "Randomly create and remove directories and files"; -+} -+ -+/* Description of this test */ -+ -+const char *rndrm00_get_description(void) -+{ -+ return -+ "Create a directory named rndrm00_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, " \ -+ "randomly create and remove " \ -+ "a number of sub-directories and small files, " \ -+ "but do more creates than removes. " \ -+ "When the total size of all sub-directories and files " \ -+ "is greater than the size specified by the size parameter, " \ -+ "start to do more removes than creates. " \ -+ "The size parameter is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "A size of zero fills the file system until there is no " -+ "space left. " \ -+ "The task repeats, sleeping in between each iteration. " \ -+ "The repeat count is set by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " -+ "Sleep is specified in milliseconds."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, rndrm00_get_title(), -+ rndrm00_get_description(), "znp"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ rndrm00(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,431 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+uint32_t files_created = 0; -+uint32_t files_removed = 0; -+uint32_t dirs_created = 0; -+uint32_t dirs_removed = 0; -+int64_t *size_ptr = 0; -+ -+void display_stats(void) -+{ -+ printf( "\nrndrm99 stats:\n" -+ "\tNumber of files created = %u\n" -+ "\tNumber of files deleted = %u\n" -+ "\tNumber of directories created = %u\n" -+ "\tNumber of directories deleted = %u\n" -+ "\tCurrent net size of creates and deletes = %lld\n", -+ (unsigned) files_created, -+ (unsigned) files_removed, -+ (unsigned) dirs_created, -+ (unsigned) dirs_removed, -+ (long long) (size_ptr ? *size_ptr : 0)); -+ fflush(stdout); -+} -+ -+struct timeval tv_before; -+struct timeval tv_after; -+ -+void before(void) -+{ -+ CHECK(gettimeofday(&tv_before, NULL) != -1); -+} -+ -+void after(const char *msg) -+{ -+ time_t diff; -+ CHECK(gettimeofday(&tv_after, NULL) != -1); -+ diff = tv_after.tv_sec - tv_before.tv_sec; -+ if (diff >= 8) { -+ printf("\nrndrm99: the following fn took more than 8 seconds: %s (took %u secs)\n",msg,(unsigned) diff); -+ fflush(stdout); -+ display_stats(); -+ } -+} -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+static char write_buffer[WRITE_BUFFER_SIZE]; -+ -+static void init_write_buffer() -+{ -+ static int init = 0; -+ -+ if (!init) { -+ int i, d; -+ uint64_t u; -+ -+ u = RAND_MAX; -+ u += 1; -+ u /= 256; -+ d = (int) u; -+ srand(1); -+ for (i = 0; i < WRITE_BUFFER_SIZE; ++i) -+ write_buffer[i] = rand() / d; -+ init = 1; -+ } -+} -+ -+/* Write size random bytes into file descriptor fd at the current position, -+ returning the number of bytes actually written */ -+uint64_t fill_file(int fd, uint64_t size) -+{ -+ ssize_t written; -+ size_t sz; -+ unsigned start = 0, length; -+ uint64_t remains; -+ uint64_t actual_size = 0; -+ -+ init_write_buffer(); -+ remains = size; -+ while (remains > 0) { -+ length = WRITE_BUFFER_SIZE - start; -+ if (remains > length) -+ sz = length; -+ else -+ sz = (size_t) remains; -+ before(); -+ written = write(fd, write_buffer + start, sz); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ after("write"); -+ fprintf(stderr,"\nrndrm99: write failed with ENOSPC\n");fflush(stderr); -+ display_stats(); -+ break; -+ } -+ after("write"); -+ remains -= written; -+ actual_size += written; -+ if ((size_t) written == sz) -+ start = 0; -+ else -+ start += written; -+ } -+ return actual_size; -+} -+ -+/* Create a file of size file_size */ -+uint64_t create_file(const char *file_name, uint64_t file_size) -+{ -+ int fd; -+ int flags; -+ mode_t mode; -+ uint64_t actual_size; /* Less than size if the file system is full */ -+ -+ flags = O_CREAT | O_TRUNC | O_WRONLY; -+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; -+ before(); -+ fd = open(file_name, flags, mode); -+ if (fd == -1 && errno == ENOSPC) { -+ errno = 0; -+ after("open"); -+ fprintf(stderr,"\nrndrm99: open failed with ENOSPC\n");fflush(stderr); -+ display_stats(); -+ return 0; /* File system full */ -+ } -+ CHECK(fd != -1); -+ after("open"); -+ actual_size = fill_file(fd, file_size); -+ before(); -+ CHECK(close(fd) != -1); -+ after("close"); -+ if (file_size != 0 && actual_size == 0) { -+ printf("\nrndrm99: unlinking zero size file\n");fflush(stdout); -+ before(); -+ CHECK(unlink(file_name) != -1); -+ after("unlink (create_file)"); -+ } -+ return actual_size; -+} -+ -+/* Create an empty sub-directory or small file in the current directory */ -+int64_t create_entry(char *return_name) -+{ -+ int fd; -+ char name[256]; -+ int64_t res; -+ -+ for (;;) { -+ sprintf(name, "%u", (unsigned) tests_random_no(10000000)); -+ before(); -+ fd = open(name, O_RDONLY); -+ after("open (create_entry)"); -+ if (fd == -1) -+ break; -+ before(); -+ close(fd); -+ after("close (create_entry)"); -+ } -+ if (return_name) -+ strcpy(return_name, name); -+ if (tests_random_no(2)) { -+ res = create_file(name, tests_random_no(4096)); -+ if (res > 0) -+ files_created += 1; -+ return res; -+ } else { -+ before(); -+ if (mkdir(name, 0777) == -1) { -+ CHECK(errno == ENOSPC); -+ after("mkdir"); -+ errno = 0; -+ fprintf(stderr,"\nrndrm99: mkdir failed with ENOSPC\n");fflush(stderr); -+ display_stats(); -+ return 0; -+ } -+ after("mkdir"); -+ dirs_created += 1; -+ return TESTS_EMPTY_DIR_SIZE; -+ } -+} -+ -+/* Remove a random file of empty sub-directory from the current directory */ -+int64_t remove_entry(void) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ unsigned count = 0, pos; -+ int64_t result = 0; -+ -+ before(); -+ dir = opendir("."); -+ CHECK(dir != NULL); -+ after("opendir"); -+ for (;;) { -+ errno = 0; -+ before(); -+ entry = readdir(dir); -+ if (entry) { -+ after("readdir 1"); -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) -+ ++count; -+ } else { -+ CHECK(errno == 0); -+ after("readdir 1"); -+ break; -+ } -+ } -+ pos = tests_random_no(count); -+ count = 0; -+ before(); -+ rewinddir(dir); -+ after("rewinddir"); -+ for (;;) { -+ errno = 0; -+ before(); -+ entry = readdir(dir); -+ if (!entry) { -+ CHECK(errno == 0); -+ after("readdir 2"); -+ break; -+ } -+ after("readdir 2"); -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) { -+ if (count == pos) { -+ if (entry->d_type == DT_DIR) { -+ before(); -+ tests_clear_dir(entry->d_name); -+ after("tests_clear_dir"); -+ before(); -+ CHECK(rmdir(entry->d_name) != -1); -+ after("rmdir"); -+ result = TESTS_EMPTY_DIR_SIZE; -+ dirs_removed += 1; -+ } else { -+ struct stat st; -+ before(); -+ CHECK(stat(entry->d_name, &st) != -1); -+ after("stat"); -+ result = st.st_size; -+ before(); -+ CHECK(unlink(entry->d_name) != -1); -+ after("unlink"); -+ files_removed += 1; -+ } -+ } -+ ++count; -+ } -+ } -+ before(); -+ CHECK(closedir(dir) != -1); -+ after("closedir"); -+ return result; -+} -+ -+void rndrm99(void) -+{ -+ int64_t repeat, loop_cnt; -+ int64_t size, this_size; -+ pid_t pid; -+ char dir_name[256]; -+ -+ size_ptr = &size; -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "rndrm99_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ /* Repeat loop */ -+ repeat = tests_repeat_parameter; -+ size = 0; -+ for (;;) { -+ /* Create and remove sub-dirs and small files, */ -+ /* but tending to grow */ -+ printf("\nrndrm99: growing\n");fflush(stdout); -+ loop_cnt = 0; -+ do { -+ if (loop_cnt++ % 2000 == 0) -+ display_stats(); -+ if (tests_random_no(3)) { -+ this_size = create_entry(NULL); -+ if (!this_size) -+ break; -+ size += this_size; -+ } else { -+ this_size = remove_entry(); -+ size -= this_size; -+ if (size < 0) -+ size = 0; -+ if (!this_size) -+ this_size = 1; -+ } -+ } while (this_size && -+ (tests_size_parameter == 0 || -+ size < tests_size_parameter)); -+ /* Create and remove sub-dirs and small files, but */ -+ /* but tending to shrink */ -+ printf("\nrndrm99: shrinking\n");fflush(stdout); -+ loop_cnt = 0; -+ do { -+ if (loop_cnt++ % 2000 == 0) -+ display_stats(); -+ if (!tests_random_no(3)) { -+ this_size = create_entry(NULL); -+ size += this_size; -+ } else { -+ this_size = remove_entry(); -+ size -= this_size; -+ if (size < 0) -+ size = 0; -+ } -+ } while ((tests_size_parameter != 0 && -+ size > tests_size_parameter / 10) || -+ (tests_size_parameter == 0 && size > 100000)); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ printf("\nrndrm99: sleeping\n");fflush(stdout); -+ usleep(s); -+ } -+ } -+ printf("\nrndrm99: tidying\n");fflush(stdout); -+ display_stats(); -+ /* Tidy up by removing everything */ -+ tests_clear_dir("."); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+ size_ptr = 0; -+} -+ -+/* Title of this test */ -+ -+const char *rndrm99_get_title(void) -+{ -+ return "Randomly create and remove directories and files"; -+} -+ -+/* Description of this test */ -+ -+const char *rndrm99_get_description(void) -+{ -+ return -+ "Create a directory named rndrm99_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, " \ -+ "randomly create and remove " \ -+ "a number of sub-directories and small files, " \ -+ "but do more creates than removes. " \ -+ "When the total size of all sub-directories and files " \ -+ "is greater than the size specified by the size parameter, " \ -+ "start to do more removes than creates. " \ -+ "The size parameter is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "A size of zero fills the file system until there is no " -+ "space left. " \ -+ "The task repeats, sleeping in between each iteration. " \ -+ "The repeat count is set by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " -+ "Sleep is specified in milliseconds."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, rndrm99_get_title(), -+ rndrm99_get_description(), "znp"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ rndrm99(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,201 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define BLOCK_SIZE 32768 -+#define BUFFER_SIZE 32768 -+ -+static void check_file(int fd, char *data, size_t length) -+{ -+ size_t n, i; -+ char buf[BUFFER_SIZE]; -+ -+ CHECK(lseek(fd, 0, SEEK_SET) != -1); -+ n = 0; -+ for (;;) { -+ i = read(fd, buf, BUFFER_SIZE); -+ CHECK(i >= 0); -+ if (i == 0) -+ break; -+ CHECK(memcmp(buf, data + n, i) == 0); -+ n += i; -+ } -+ CHECK(n == length); -+} -+ -+void rndwrite00(void) -+{ -+ int fd; -+ pid_t pid; -+ ssize_t written; -+ size_t remains; -+ size_t block; -+ size_t actual_size; -+ size_t check_every; -+ char *data, *p, *q; -+ off_t offset; -+ size_t size; -+ int64_t repeat; -+ char file_name[256]; -+ char buf[4096]; -+ -+ /* Create file */ -+ pid = getpid(); -+ tests_cat_pid(file_name, "rndwrite00_test_file_", pid); -+ fd = open(file_name, O_CREAT | O_RDWR | O_TRUNC, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ /* Allocate memory to hold file data */ -+ CHECK(tests_size_parameter > 0); -+ CHECK(tests_size_parameter <= SIZE_MAX); -+ data = (char *) malloc(tests_size_parameter); -+ CHECK(data != NULL); -+ /* Fill with random data */ -+ srand(pid); -+ for (p = data, q = data + tests_size_parameter; p != q; ++p) -+ *p = rand(); -+ /* Write to file */ -+ p = data; -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > BLOCK_SIZE) -+ block = BLOCK_SIZE; -+ else -+ block = remains; -+ written = write(fd, p, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ p += written; -+ } -+ actual_size = p - data; -+ /* Repeating bit */ -+ repeat = tests_repeat_parameter; -+ check_every = actual_size / 8192; -+ for (;;) { -+ offset = tests_random_no(actual_size); -+ size = tests_random_no(4096); -+ /* Don't change the file size */ -+ if (offset + size > actual_size) -+ size = actual_size - offset; -+ if (!size) -+ continue; -+ for (p = buf, q = p + size; p != q; ++p) -+ *p = rand(); -+ CHECK(lseek(fd, offset, SEEK_SET) != -1); -+ written = write(fd, buf, size); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ } else -+ memcpy(data + offset, buf, written); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ if (repeat % check_every == 0) -+ check_file(fd, data, actual_size); -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ } -+ /* Check and close file */ -+ check_file(fd, data, actual_size); -+ CHECK(close(fd) != -1); -+ if (tests_delete_flag) -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *rndwrite00_get_title(void) -+{ -+ return "Randomly write a large test file"; -+} -+ -+/* Description of this test */ -+ -+const char *rndwrite00_get_description(void) -+{ -+ return -+ "Create a file named rndwrite00_test_file_pid, where " \ -+ "pid is the process id. " \ -+ "The file is filled with random data. " \ -+ "The size of the file is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "Then a randomly sized block of random data is written at a " \ -+ "random location in the file. "\ -+ "The block size is always in the range 1 to 4095. " \ -+ "If a sleep value is specified, the process sleeps. " \ -+ "The number of writes is given by the repeat count. " \ -+ "The repeat count is set by the -n or --repeat option, " \ -+ "otherwise it defaults to 10000. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " -+ "Sleep is specified in milliseconds. " \ -+ "Periodically the data in the file is checked with a copy " \ -+ "held in memory. " \ -+ "If the delete option is specified the file is finally " \ -+ "deleted."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 10000; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, rndwrite00_get_title(), -+ rndwrite00_get_description(), "zne"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ rndwrite00(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,109 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+void stress_1(void) -+{ -+ int fd, i; -+ pid_t pid; -+ ssize_t written; -+ int64_t remains; -+ size_t block; -+ char file_name[256]; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ pid = getpid(); -+ tests_cat_pid(file_name, "stress_1_test_file_", pid); -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ srand(pid); -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ } -+ CHECK(close(fd) != -1); -+ if (tests_delete_flag) -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *stress_1_get_title(void) -+{ -+ return "Create / overwrite a large file"; -+} -+ -+/* Description of this test */ -+ -+const char *stress_1_get_description(void) -+{ -+ return -+ "Create a file named stress_1_test_file_pid, " \ -+ "where pid is the process id. " \ -+ "The size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "The file will be deleted if the delete option " \ -+ "is specified. "; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, stress_1_get_title(), -+ stress_1_get_description(), "ze"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ stress_1(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,120 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+void stress_2(void) -+{ -+ int fd, i; -+ pid_t pid; -+ ssize_t written; -+ int64_t remains; -+ int64_t repeat; -+ size_t block; -+ char *file_name; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ file_name = "stress_2_test_file"; -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ CHECK(unlink(file_name) != -1); -+ pid = getpid(); -+ srand(pid); -+ repeat = tests_repeat_parameter; -+ for (;;) { -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ CHECK(lseek(fd, 0, SEEK_SET) != -1); -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ } -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ } -+ CHECK(close(fd) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *stress_2_get_title(void) -+{ -+ return "Create / overwrite a large deleted file"; -+} -+ -+/* Description of this test */ -+ -+const char *stress_2_get_description(void) -+{ -+ return -+ "Create a file named stress_2_test_file. " \ -+ "Open it, delete it while holding the open file descriptor, " \ -+ "then fill it with random data. " \ -+ "Repeated re-write the file some number of times. " \ -+ "The repeat count is given by the -n or --repeat option, " \ -+ "otherwise it defaults to 10. " \ -+ "The file size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 10; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, stress_2_get_title(), -+ stress_2_get_description(), "zn"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ stress_2(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,122 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+void stress_3(void) -+{ -+ int fd, i; -+ pid_t pid; -+ ssize_t written; -+ int64_t remains; -+ size_t block; -+ char file_name[256]; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ pid = getpid(); -+ tests_cat_pid(file_name, "stress_3_test_file_", pid); -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ pid = getpid(); -+ srand(pid); -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ CHECK(lseek(fd, tests_size_parameter, SEEK_SET) != -1); -+ CHECK(write(fd, "!", 1) == 1); -+ CHECK(lseek(fd, 0, SEEK_SET) != -1); -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ } -+ if (ftruncate(fd, 0) == -1) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ } -+ CHECK(close(fd) != -1); -+ if (tests_delete_flag) -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *stress_3_get_title(void) -+{ -+ return "Create a file with a large hole and fill it"; -+} -+ -+/* Description of this test */ -+ -+const char *stress_3_get_description(void) -+{ -+ return -+ "Create a file named stress_3_test_file_pid, " \ -+ "where pid is the process id. " \ -+ "Write a single character past the end of the file, " \ -+ "based on the specified file size, " \ -+ "which creates a hole in the file. " -+ "Fill the hole with random data. " \ -+ "Then truncate the file length to zero. " \ -+ "The size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "The file will be deleted if the delete option " \ -+ "is specified."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, stress_3_get_title(), -+ stress_3_get_description(), "ze"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ stress_3(); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,52 @@ -+#!/bin/sh -+ -+TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR -+if test -z "$TEST_DIR"; -+then -+ TEST_DIR="/mnt/test_file_system" -+fi -+ -+FREESPACE=`../utils/free_space "$TEST_DIR"` -+ -+if test -z "$FREESPACE"; -+then -+ echo "Failed to determine free space" -+ exit 1 -+fi -+ -+if test -n "$1"; -+then -+ DURATION="-d$1"; -+else -+ DURATION=""; -+fi -+ -+FWRITE00=atoms/fwrite00 -+RNDWR=atoms/rndwrite00 -+GCHUP=atoms/gcd_hupper -+PDFLUSH=atoms/pdfrun -+FSIZE=$(( $FREESPACE/15 )); -+ -+../utils/fstest_monitor $DURATION \ -+"$FWRITE00 -z $FSIZE -n0 -p 20" \ -+"$FWRITE00 -z $FSIZE -n0 -p 10 -s" \ -+"$FWRITE00 -z $FSIZE -n0 -p 20 -u" \ -+"$FWRITE00 -z $FSIZE -n0 -p 70 -o" \ -+"$FWRITE00 -z $FSIZE -n0 -p 15 -s -o -u" \ -+"$FWRITE00 -z $FSIZE -n0 -p 10 -u -c" \ -+"$FWRITE00 -z $FSIZE -n0 -p 10 -u -o -c" \ -+"$FWRITE00 -z $FSIZE -n0 -p 10 -o -c" \ -+"$FWRITE00 -z $FSIZE -n0 -p 100 -o -u" \ -+"$FWRITE00 -z $FSIZE -n0 -p 100 -s -o -u -c" \ -+"$FWRITE00 -z $FSIZE -n0 -p 100 -o -u" \ -+"$FWRITE00 -z $FSIZE -n0 -p 100 -u" \ -+"$FWRITE00 -z $FSIZE -n0 -p 100 -s -o" \ -+"$RNDWR -z $FSIZE -n0 -p 10 -e" \ -+"$RNDWR -z $FSIZE -n0 -p 100 -e" \ -+"$PDFLUSH -z 1073741824 -n0" -+ -+STATUS=$? -+ -+rm -rf ${TEST_DIR}/* -+ -+exit $STATUS ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,40 @@ -+#!/bin/sh -+ -+TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR -+if test -z "$TEST_DIR"; -+then -+ TEST_DIR="/mnt/test_file_system" -+fi -+ -+FREESPACE=`../utils/free_space "$TEST_DIR"` -+ -+if test -z "$FREESPACE"; -+then -+ echo "Failed to determine free space" -+ exit 1 -+fi -+ -+if test -n "$1"; -+then -+ DURATION="-d$1"; -+else -+ DURATION=""; -+fi -+ -+FWRITE00=atoms/fwrite00 -+RNDWR=atoms/rndwrite00 -+PDFLUSH=atoms/pdfrun -+FSIZE=$(( $FREESPACE/15 )); -+ -+../utils/fstest_monitor $DURATION \ -+"$FWRITE00 -z $FSIZE -n0 -p 300" \ -+"$FWRITE00 -z $FSIZE -n0 -u" \ -+"$FWRITE00 -z $FSIZE -n0 -u -c" \ -+"$FWRITE00 -z $FSIZE -n0 -s -o" \ -+"$RNDWR -z $FSIZE -n0 -e" -+ -+STATUS=$? -+ -+rm -rf ${TEST_DIR}/* -+ -+exit $STATUS ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,19 @@ -+ -+ifeq ($(origin CC),default) -+CC = gcc -+endif -+ -+CFLAGS := $(CFLAGS) -Wall -g -O2 -I../lib -+ -+LDFLAGS := $(LDFLAGS) -+ -+TARGETS = fstest_monitor free_space -+ -+all: $(TARGETS) -+ -+clean: -+ rm -f *.o $(TARGETS) -+ -+tests: all -+ ./fstest_monitor -+ ./free_space > /dev/null ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,56 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+ -+int main(int argc, char *argv[]) -+{ -+ char *dir_name = "."; -+ uint64_t free_space; -+ struct statvfs fs_info; -+ -+ if (argc > 1) { -+ if (strncmp(argv[1], "--help", 6) == 0 || -+ strncmp(argv[1], "-h", 2) == 0) { -+ printf( "Usage is: " -+ "free_space [directory]\n" -+ "\n" -+ "Display the free space of the file system " -+ "of the directory given\n" -+ "or the current directory if no " -+ "directory is given.\nThe value output is " -+ "in bytes.\n" -+ ); -+ return 1; -+ } -+ dir_name = argv[1]; -+ } -+ if (statvfs(dir_name, &fs_info) == -1) -+ return 1; -+ -+ free_space = (uint64_t) fs_info.f_bavail * (uint64_t) fs_info.f_frsize; -+ -+ printf("%llu\n", (unsigned long long) free_space); -+ -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,281 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct child_info { -+ struct child_info *next; -+ pid_t pid; -+ int terminated; -+ int killed; -+ int gone; -+}; -+ -+struct child_info *children = 0; -+ -+void kill_children(void) -+{ -+ struct child_info *child; -+ -+ child = children; -+ while (child) { -+ if (!child->gone) { -+ if (!child->terminated) { -+ child->terminated = 1; -+ kill(child->pid, SIGTERM); -+ } /*else if (!child->killed) { -+ child->killed = 1; -+ kill(child->pid, SIGKILL); -+ }*/ -+ } -+ child = child->next; -+ } -+} -+ -+void add_child(pid_t child_pid) -+{ -+ struct child_info *child; -+ size_t sz; -+ -+ sz = sizeof(struct child_info); -+ child = (struct child_info *) malloc(sz); -+ memset(child, 0, sz); -+ child->pid = child_pid; -+ child->next = children; -+ children = child; -+} -+ -+void mark_child_gone(pid_t child_pid) -+{ -+ struct child_info *child; -+ -+ child = children; -+ while (child) { -+ if (child->pid == child_pid) { -+ child->gone = 1; -+ break; -+ } -+ child = child->next; -+ } -+} -+ -+int have_children(void) -+{ -+ struct child_info *child; -+ -+ child = children; -+ while (child) { -+ if (!child->gone) -+ return 1; -+ child = child->next; -+ } -+ return 0; -+} -+ -+int parse_command_line(char *cmdline, int *pargc, char ***pargv) -+{ -+ char **tmp; -+ char *p, *v, *q; -+ size_t sz; -+ int argc = 0; -+ int state = 0; -+ char *argv[1024]; -+ -+ if (!cmdline) -+ return 1; -+ q = v = (char *) malloc(strlen(cmdline) + 1024); -+ if (!v) -+ return 1; -+ p = cmdline; -+ for (;;) { -+ char c = *p++; -+ if (!c) { -+ *v++ = 0; -+ break; -+ } -+ switch (state) { -+ case 0: /* Between args */ -+ if (isspace(c)) -+ break; -+ argv[argc++] = v; -+ if (c == '"') { -+ state = 2; -+ break; -+ } else if (c == '\'') { -+ state = 3; -+ break; -+ } -+ state = 1; -+ case 1: /* Not quoted */ -+ if (c == '\\') { -+ if (*p) -+ *v++ = *p; -+ } else if (isspace(c)) { -+ *v++ = 0; -+ state = 0; -+ } else -+ *v++ = c; -+ break; -+ case 2: /* Double quoted */ -+ if (c == '\\' && *p == '"') { -+ *v++ = '"'; -+ ++p; -+ } else if (c == '"') { -+ *v++ = 0; -+ state = 0; -+ } else -+ *v++ = c; -+ break; -+ case 3: /* Single quoted */ -+ if (c == '\'') { -+ *v++ = 0; -+ state = 0; -+ } else -+ *v++ = c; -+ break; -+ } -+ } -+ argv[argc] = 0; -+ sz = sizeof(char *) * (argc + 1); -+ tmp = (char **) malloc(sz); -+ if (!tmp) { -+ free(q); -+ return 1; -+ } -+ if (argc == 0) -+ free(q); -+ memcpy(tmp, argv, sz); -+ *pargc = argc; -+ *pargv = tmp; -+ return 0; -+} -+ -+void signal_handler(int signum) -+{ -+ kill_children(); -+} -+ -+int result = 0; -+int alarm_gone_off = 0; -+ -+void alarm_handler(int signum) -+{ -+ if (!result) -+ alarm_gone_off = 1; -+ kill_children(); -+} -+ -+int main(int argc, char *argv[], char **env) -+{ -+ int p; -+ pid_t child_pid; -+ int status; -+ int duration = 0; -+ -+ p = 1; -+ if (argc > 1) { -+ if (strncmp(argv[p], "--help", 6) == 0 || -+ strncmp(argv[p], "-h", 2) == 0) { -+ printf( "Usage is: " -+ "fstest_monitor options programs...\n" -+ " Options are:\n" -+ " -h, --help " -+ "This help message\n" -+ " -d, --duration arg " -+ "Stop after arg seconds\n" -+ "\n" -+ "Run programs and wait for them." -+ " If duration is specified,\n" -+ "kill all programs" -+ " after that number of seconds have elapsed.\n" -+ "Example: " -+ "fstest_monitor \"/bin/ls -l\" /bin/date\n" -+ ); -+ return 1; -+ } -+ if (strncmp(argv[p], "--duration", 10) == 0 || -+ strncmp(argv[p], "-d", 2) == 0) { -+ char *s; -+ if (p+1 < argc && !isdigit(argv[p][strlen(argv[p])-1])) -+ ++p; -+ s = argv[p]; -+ while (*s && !isdigit(*s)) -+ ++s; -+ duration = atoi(s); -+ ++p; -+ } -+ } -+ -+ signal(SIGTERM, signal_handler); -+ signal(SIGINT, signal_handler); -+ for (; p < argc; ++p) { -+ child_pid = fork(); -+ if (child_pid) { -+ /* Parent */ -+ if (child_pid == (pid_t) -1) { -+ kill_children(); -+ result = 1; -+ break; -+ } -+ add_child(child_pid); -+ } else { -+ /* Child */ -+ int cargc; -+ char **cargv; -+ -+ if (parse_command_line(argv[p], &cargc, &cargv)) -+ return 1; -+ execve(cargv[0], cargv, env); -+ return 1; -+ } -+ } -+ if (!result && duration > 0) { -+ signal(SIGALRM, alarm_handler); -+ alarm(duration); -+ } -+ while (have_children()) { -+ status = 0; -+ child_pid = wait(&status); -+ if (child_pid == (pid_t) -1) { -+ if (errno == EINTR) -+ continue; -+ kill_children(); -+ return 1; -+ } -+ mark_child_gone(child_pid); -+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { -+ result = 1; -+ kill_children(); -+ } -+ } -+ -+ if (alarm_gone_off) -+ return 0; -+ -+ return result; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/COPYING 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/COPYING 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,340 @@ -+ GNU GENERAL PUBLIC LICENSE -+ Version 2, June 1991 -+ -+ Copyright (C) 1989, 1991 Free Software Foundation, Inc. -+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ Everyone is permitted to copy and distribute verbatim copies -+ of this license document, but changing it is not allowed. -+ -+ Preamble -+ -+ The licenses for most software are designed to take away your -+freedom to share and change it. By contrast, the GNU General Public -+License is intended to guarantee your freedom to share and change free -+software--to make sure the software is free for all its users. This -+General Public License applies to most of the Free Software -+Foundation's software and to any other program whose authors commit to -+using it. (Some other Free Software Foundation software is covered by -+the GNU Library General Public License instead.) You can apply it to -+your programs, too. -+ -+ When we speak of free software, we are referring to freedom, not -+price. Our General Public Licenses are designed to make sure that you -+have the freedom to distribute copies of free software (and charge for -+this service if you wish), that you receive source code or can get it -+if you want it, that you can change the software or use pieces of it -+in new free programs; and that you know you can do these things. -+ -+ To protect your rights, we need to make restrictions that forbid -+anyone to deny you these rights or to ask you to surrender the rights. -+These restrictions translate to certain responsibilities for you if you -+distribute copies of the software, or if you modify it. -+ -+ For example, if you distribute copies of such a program, whether -+gratis or for a fee, you must give the recipients all the rights that -+you have. You must make sure that they, too, receive or can get the -+source code. And you must show them these terms so they know their -+rights. -+ -+ We protect your rights with two steps: (1) copyright the software, and -+(2) offer you this license which gives you legal permission to copy, -+distribute and/or modify the software. -+ -+ Also, for each author's protection and ours, we want to make certain -+that everyone understands that there is no warranty for this free -+software. If the software is modified by someone else and passed on, we -+want its recipients to know that what they have is not the original, so -+that any problems introduced by others will not reflect on the original -+authors' reputations. -+ -+ Finally, any free program is threatened constantly by software -+patents. We wish to avoid the danger that redistributors of a free -+program will individually obtain patent licenses, in effect making the -+program proprietary. To prevent this, we have made it clear that any -+patent must be licensed for everyone's free use or not licensed at all. -+ -+ The precise terms and conditions for copying, distribution and -+modification follow. -+ -+ GNU GENERAL PUBLIC LICENSE -+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -+ -+ 0. This License applies to any program or other work which contains -+a notice placed by the copyright holder saying it may be distributed -+under the terms of this General Public License. The "Program", below, -+refers to any such program or work, and a "work based on the Program" -+means either the Program or any derivative work under copyright law: -+that is to say, a work containing the Program or a portion of it, -+either verbatim or with modifications and/or translated into another -+language. (Hereinafter, translation is included without limitation in -+the term "modification".) Each licensee is addressed as "you". -+ -+Activities other than copying, distribution and modification are not -+covered by this License; they are outside its scope. The act of -+running the Program is not restricted, and the output from the Program -+is covered only if its contents constitute a work based on the -+Program (independent of having been made by running the Program). -+Whether that is true depends on what the Program does. -+ -+ 1. You may copy and distribute verbatim copies of the Program's -+source code as you receive it, in any medium, provided that you -+conspicuously and appropriately publish on each copy an appropriate -+copyright notice and disclaimer of warranty; keep intact all the -+notices that refer to this License and to the absence of any warranty; -+and give any other recipients of the Program a copy of this License -+along with the Program. -+ -+You may charge a fee for the physical act of transferring a copy, and -+you may at your option offer warranty protection in exchange for a fee. -+ -+ 2. You may modify your copy or copies of the Program or any portion -+of it, thus forming a work based on the Program, and copy and -+distribute such modifications or work under the terms of Section 1 -+above, provided that you also meet all of these conditions: -+ -+ a) You must cause the modified files to carry prominent notices -+ stating that you changed the files and the date of any change. -+ -+ b) You must cause any work that you distribute or publish, that in -+ whole or in part contains or is derived from the Program or any -+ part thereof, to be licensed as a whole at no charge to all third -+ parties under the terms of this License. -+ -+ c) If the modified program normally reads commands interactively -+ when run, you must cause it, when started running for such -+ interactive use in the most ordinary way, to print or display an -+ announcement including an appropriate copyright notice and a -+ notice that there is no warranty (or else, saying that you provide -+ a warranty) and that users may redistribute the program under -+ these conditions, and telling the user how to view a copy of this -+ License. (Exception: if the Program itself is interactive but -+ does not normally print such an announcement, your work based on -+ the Program is not required to print an announcement.) -+ -+These requirements apply to the modified work as a whole. If -+identifiable sections of that work are not derived from the Program, -+and can be reasonably considered independent and separate works in -+themselves, then this License, and its terms, do not apply to those -+sections when you distribute them as separate works. But when you -+distribute the same sections as part of a whole which is a work based -+on the Program, the distribution of the whole must be on the terms of -+this License, whose permissions for other licensees extend to the -+entire whole, and thus to each and every part regardless of who wrote it. -+ -+Thus, it is not the intent of this section to claim rights or contest -+your rights to work written entirely by you; rather, the intent is to -+exercise the right to control the distribution of derivative or -+collective works based on the Program. -+ -+In addition, mere aggregation of another work not based on the Program -+with the Program (or with a work based on the Program) on a volume of -+a storage or distribution medium does not bring the other work under -+the scope of this License. -+ -+ 3. You may copy and distribute the Program (or a work based on it, -+under Section 2) in object code or executable form under the terms of -+Sections 1 and 2 above provided that you also do one of the following: -+ -+ a) Accompany it with the complete corresponding machine-readable -+ source code, which must be distributed under the terms of Sections -+ 1 and 2 above on a medium customarily used for software interchange; or, -+ -+ b) Accompany it with a written offer, valid for at least three -+ years, to give any third party, for a charge no more than your -+ cost of physically performing source distribution, a complete -+ machine-readable copy of the corresponding source code, to be -+ distributed under the terms of Sections 1 and 2 above on a medium -+ customarily used for software interchange; or, -+ -+ c) Accompany it with the information you received as to the offer -+ to distribute corresponding source code. (This alternative is -+ allowed only for noncommercial distribution and only if you -+ received the program in object code or executable form with such -+ an offer, in accord with Subsection b above.) -+ -+The source code for a work means the preferred form of the work for -+making modifications to it. For an executable work, complete source -+code means all the source code for all modules it contains, plus any -+associated interface definition files, plus the scripts used to -+control compilation and installation of the executable. However, as a -+special exception, the source code distributed need not include -+anything that is normally distributed (in either source or binary -+form) with the major components (compiler, kernel, and so on) of the -+operating system on which the executable runs, unless that component -+itself accompanies the executable. -+ -+If distribution of executable or object code is made by offering -+access to copy from a designated place, then offering equivalent -+access to copy the source code from the same place counts as -+distribution of the source code, even though third parties are not -+compelled to copy the source along with the object code. -+ -+ 4. You may not copy, modify, sublicense, or distribute the Program -+except as expressly provided under this License. Any attempt -+otherwise to copy, modify, sublicense or distribute the Program is -+void, and will automatically terminate your rights under this License. -+However, parties who have received copies, or rights, from you under -+this License will not have their licenses terminated so long as such -+parties remain in full compliance. -+ -+ 5. You are not required to accept this License, since you have not -+signed it. However, nothing else grants you permission to modify or -+distribute the Program or its derivative works. These actions are -+prohibited by law if you do not accept this License. Therefore, by -+modifying or distributing the Program (or any work based on the -+Program), you indicate your acceptance of this License to do so, and -+all its terms and conditions for copying, distributing or modifying -+the Program or works based on it. -+ -+ 6. Each time you redistribute the Program (or any work based on the -+Program), the recipient automatically receives a license from the -+original licensor to copy, distribute or modify the Program subject to -+these terms and conditions. You may not impose any further -+restrictions on the recipients' exercise of the rights granted herein. -+You are not responsible for enforcing compliance by third parties to -+this License. -+ -+ 7. If, as a consequence of a court judgment or allegation of patent -+infringement or for any other reason (not limited to patent issues), -+conditions are imposed on you (whether by court order, agreement or -+otherwise) that contradict the conditions of this License, they do not -+excuse you from the conditions of this License. If you cannot -+distribute so as to satisfy simultaneously your obligations under this -+License and any other pertinent obligations, then as a consequence you -+may not distribute the Program at all. For example, if a patent -+license would not permit royalty-free redistribution of the Program by -+all those who receive copies directly or indirectly through you, then -+the only way you could satisfy both it and this License would be to -+refrain entirely from distribution of the Program. -+ -+If any portion of this section is held invalid or unenforceable under -+any particular circumstance, the balance of the section is intended to -+apply and the section as a whole is intended to apply in other -+circumstances. -+ -+It is not the purpose of this section to induce you to infringe any -+patents or other property right claims or to contest validity of any -+such claims; this section has the sole purpose of protecting the -+integrity of the free software distribution system, which is -+implemented by public license practices. Many people have made -+generous contributions to the wide range of software distributed -+through that system in reliance on consistent application of that -+system; it is up to the author/donor to decide if he or she is willing -+to distribute software through any other system and a licensee cannot -+impose that choice. -+ -+This section is intended to make thoroughly clear what is believed to -+be a consequence of the rest of this License. -+ -+ 8. If the distribution and/or use of the Program is restricted in -+certain countries either by patents or by copyrighted interfaces, the -+original copyright holder who places the Program under this License -+may add an explicit geographical distribution limitation excluding -+those countries, so that distribution is permitted only in or among -+countries not thus excluded. In such case, this License incorporates -+the limitation as if written in the body of this License. -+ -+ 9. The Free Software Foundation may publish revised and/or new versions -+of the General Public License from time to time. Such new versions will -+be similar in spirit to the present version, but may differ in detail to -+address new problems or concerns. -+ -+Each version is given a distinguishing version number. If the Program -+specifies a version number of this License which applies to it and "any -+later version", you have the option of following the terms and conditions -+either of that version or of any later version published by the Free -+Software Foundation. If the Program does not specify a version number of -+this License, you may choose any version ever published by the Free Software -+Foundation. -+ -+ 10. If you wish to incorporate parts of the Program into other free -+programs whose distribution conditions are different, write to the author -+to ask for permission. For software which is copyrighted by the Free -+Software Foundation, write to the Free Software Foundation; we sometimes -+make exceptions for this. Our decision will be guided by the two goals -+of preserving the free status of all derivatives of our free software and -+of promoting the sharing and reuse of software generally. -+ -+ NO WARRANTY -+ -+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -+REPAIR OR CORRECTION. -+ -+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -+POSSIBILITY OF SUCH DAMAGES. -+ -+ END OF TERMS AND CONDITIONS -+ -+ How to Apply These Terms to Your New Programs -+ -+ If you develop a new program, and you want it to be of the greatest -+possible use to the public, the best way to achieve this is to make it -+free software which everyone can redistribute and change under these terms. -+ -+ To do so, attach the following notices to the program. It is safest -+to attach them to the start of each source file to most effectively -+convey the exclusion of warranty; and each file should have at least -+the "copyright" line and a pointer to where the full notice is found. -+ -+ -+ Copyright (C) 19yy -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ -+Also add information on how to contact you by electronic and paper mail. -+ -+If the program is interactive, make it output a short notice like this -+when it starts in an interactive mode: -+ -+ Gnomovision version 69, Copyright (C) 19yy name of author -+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -+ This is free software, and you are welcome to redistribute it -+ under certain conditions; type `show c' for details. -+ -+The hypothetical commands `show w' and `show c' should show the appropriate -+parts of the General Public License. Of course, the commands you use may -+be called something other than `show w' and `show c'; they could even be -+mouse-clicks or menu items--whatever suits your program. -+ -+You should also get your employer (if you work as a programmer) or your -+school, if any, to sign a "copyright disclaimer" for the program, if -+necessary. Here is a sample; alter the names: -+ -+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program -+ `Gnomovision' (which makes passes at compilers) written by James Hacker. -+ -+ , 1 April 1989 -+ Ty Coon, President of Vice -+ -+This General Public License does not permit incorporating your program into -+proprietary programs. If your program is a subroutine library, you may -+consider it more useful to permit linking proprietary applications with the -+library. If this is what you want to do, use the GNU Library General -+Public License instead of this License. ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1044 @@ -+/*********************************************************************** -+ * -+ * Copyright: Daniel Measurement and Control, Inc. -+ * 9753 Pine Lake Drive -+ * Houston, TX 77055 -+ * -+ * Created by: Vipin Malik and Gail Murray -+ * Released under GPL by permission of Daniel Industries. -+ * -+ * This software is licensed under the GPL version 2. Plese see the file -+ * COPYING for details on the license. -+ * -+ * NO WARRANTY: Absolutely no claims of warranty or fitness of purpose -+ * are made in this software. Please use at your own risk. -+ * -+ * Filename: JitterTest.c -+ * -+ * Description: Program to be used to measure wake jitter. -+ * See README file for more info. -+ * -+ * -+ * Revision History: -+ * $Id: JitterTest.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * $Log: not supported by cvs2svn $ -+ * Revision 1.13 2005/11/07 11:15:20 gleixner -+ * [MTD / JFFS2] Clean up trailing white spaces -+ * -+ * Revision 1.12 2001/08/10 19:23:11 vipin -+ * Ready to be released under GPL! Added proper headers etc. -+ * -+ * Revision 1.11 2001/07/09 15:35:50 vipin -+ * Couple of new features:1. The program runs by default as a "regular" -+ * (SCHED_OTHER) task by default, unless the -p n cmd line parameter is -+ * specified. It then runs as SCHED_RR at that priority. -+ * 2. Added ability to send SIGSTOP/SIGCONT to a specified PID. This -+ * would presumably be the PID of the JFFS2 GC task. SIGSTOP is sent -+ * before writing to the fs, and a SIGCONT after the write is done. -+ * 3. The "pad" data now written to the file on the "fs under test" is -+ * random, not sequential as previously. -+ * -+ * Revision 1.10 2001/06/27 19:14:24 vipin -+ * Now console file to log at can be specified from cmd line. This can enable -+ * you to run two instances of the program- one logging to the /dev/console -+ * and another to a regular file (if you want the data) or /dev/null if you don't. -+ * -+ * Revision 1.9 2001/06/25 20:21:31 vipin -+ * This is the latest version, NOT the one last checked in! -+ * -+ * Revision 1.7 2001/06/18 22:36:19 vipin -+ * Fix minor typo that excluded '\n' from msg on console. -+ * -+ * Revision 1.6 2001/06/18 21:17:50 vipin -+ * Added option to specify the amount of data written to outfile each period. -+ * The regular info is written, but is then padded to the requested size. -+ * This will enable testing of different sized writes to JFFS fs. -+ * -+ * Revision 1.5 2001/06/08 19:36:23 vipin -+ * All write() are now checked for return err code. -+ * -+ * Revision 1.4 2001/06/06 23:10:31 vipin -+ * Added README file. -+ * In JitterTest.c: Changed operation of periodic timer to one shot. The timer is now -+ * reset when the task wakes. This way every "jitter" is from the last time and -+ * jitters from previous times are not accumulated and screw aroud with our display. -+ * -+ * All jitter is now +ve. (as it should be). Also added a "read file" functionality -+ * to test for jitter in task if we have to read from JFFS fs. -+ * The program now also prints data to console- where it can be logged, interspersed with -+ * other "interesting" printk's from the kernel and drivers (flash sector erases etc.) -+ * -+ * Revision 1.3 2001/03/01 19:20:39 gmurray -+ * Add priority scheduling. Shortened name of default output file. -+ * Changed default interrupt period. Output delta time and jitter -+ * instead of time of day. -+ * -+ * Revision 1.2 2001/02/28 16:20:19 vipin -+ * Added version control Id and log fields. -+ * -+ ***********************************************************************/ -+/*************************** Included Files ***************************/ -+#include /* fopen, printf, fprintf, fclose */ -+#include /* strcpy, strcmp */ -+#include /* exit, atol, atoi */ -+#include /* setitimer, settimeofday, gettimeofday */ -+#include /* signal */ -+#include /* sched_setscheduler, sched_get_priority_min,*/ -+/* sched_get_priority_max */ -+#include /* gettimeofday, sleep */ -+#include -+#include -+#include -+#include -+ -+ -+ -+/**************************** Enumerations ****************************/ -+enum timerActions -+ { -+ ONESHOT, -+ AUTORESETTING -+ }; -+ -+ -+ -+/****************************** Constants *****************************/ -+/* Exit error codes */ -+#define EXIT_FILE_OPEN_ERR (1) /* error opening output file*/ -+#define EXIT_REG_SIGALRM_ERR (2) /* error registering SIGALRM*/ -+#define EXIT_REG_SIGINT_ERR (3) /* error registering SIGINT */ -+#define EXIT_INV_INT_PERIOD (4) /* error invalid int. period*/ -+#define EXIT_MIN_PRIORITY_ERR (5) /* error, minimum priority */ -+#define EXIT_MAX_PRIORITY_ERR (6) /* error, maximum priority */ -+#define EXIT_INV_SCHED_PRIORITY (7) /* error, invalid priority */ -+#define EXIT_SET_SCHEDULER_ERR (8) /* error, set scheduler */ -+#define EXIT_PREV_TIME_OF_DAY_ERR (9) /* error, init. prev. */ -+/* time of day */ -+ -+#define MAX_FILE_NAME_LEN (32) /* maximum file name length */ -+ -+#define STRINGS_EQUAL ((int) 0) /* strcmp value if equal */ -+ -+#define MIN_INT_PERIOD_MILLISEC ( 5L) /* minimum interrupt period */ -+#define MAX_INT_PERIOD_MILLISEC (5000L) /* maximum interrupt period */ -+#define DEF_INT_PERIOD_MILLISEC ( 10L) /* default interrupt period */ -+ -+#define READ_FILE_MESSAGE "This is a junk file. Must contain at least 1 byte though!\n" -+ -+/* The user can specify that the program pad out the write file to -+ a given number of bytes. But a minimum number needs to be written. This -+ will contain the jitter info. -+*/ -+#define MIN_WRITE_BYTES 30 -+#define DEFAULT_WRITE_BYTES 30 -+#define MAX_WRITE_BYTES 4096 -+ -+/* used for gen a printable ascii random # between spc and '~' */ -+#define MIN_ASCII 32 /* can be char*/ -+#define MAX_ASCII 126.0 /* needs to be float. See man rand() */ -+ -+/*---------------------------------------------------------------------- -+ * It appears that the preprocessor can't handle multi-line #if -+ * statements. Thus, the check on the default is divided into two -+ * #if statements. -+ *---------------------------------------------------------------------*/ -+#if (DEF_INT_PERIOD_MILLISEC < MIN_INT_PERIOD_MILLISEC) -+#error *** Invalid default interrupt period. *** -+#endif -+ -+#if (DEF_INT_PERIOD_MILLISEC > MAX_INT_PERIOD_MILLISEC) -+#error *** Invalid default interrupt period. *** -+#endif -+ -+ -+#define TRUE 1 /* Boolean true value */ -+#define FALSE 0 -+ -+/* Time conversion constants. */ -+#define MILLISEC_PER_SEC (1000L) /* milliseconds per second */ -+#define MICROSEC_PER_MILLISEC (1000L) /* microsecs per millisec */ -+#define MICROSEC_PER_SEC (1000000L) /* microsecs per second */ -+ -+#define PRIORITY_POLICY ((int) SCHED_RR) /* If specified iwth "-p" */ -+ -+ -+ -+/************************** Module Variables **************************/ -+/* version identifier (value supplied by CVS)*/ -+static const char Version[] = "$Id: JitterTest.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $"; -+ -+static char OutFileName[MAX_FILE_NAME_LEN+1]; /* output file name */ -+static char LogFile[MAX_FILE_NAME_LEN+1] = "/dev/console"; /* default */ -+static char ReadFile[MAX_FILE_NAME_LEN+1]; /* This file is read. Should -+ contain at least 1 byte */ -+ -+static int WriteBytes = DEFAULT_WRITE_BYTES; /* pad out file to these many bytes. */ -+static int Fd1; /* fd where the above buffer if o/p */ -+static int Cfd; /* fd to console (or file specified) */ -+static int Fd2; /* fd for the ReadFile */ -+static int DoRead = FALSE; /* should we attempt to ReadFile?*/ -+static long InterruptPeriodMilliSec; /* interrupt period, millisec */ -+static int MinPriority; /* minimum scheduler priority */ -+static int MaxPriority; /* maximum scheduler priority */ -+static int RequestedPriority; /* requested priority */ -+static struct itimerval ITimer; /* interrupt timer structure */ -+static struct timeval PrevTimeVal; /* previous time structure */ -+static struct timeval CurrTimeVal; /* current time structure */ -+static long LastMaxDiff = 0; /* keeps track of worst jitter encountered */ -+ -+static int GrabKProfile = FALSE; /* To help determine system bottle necks -+ this parameter can be set. This causes -+ the /proc/profile file to be read and -+ stored in unique filenames in current -+ dir, and indication to be o/p on the -+ /dev/console also. -+ */ -+static long ProfileTriggerMSecs = 15000l; /* Jitter time in seconds that triggers -+ a snapshot of the profile to be taken -+ -+ */ -+static int SignalGCTask = FALSE; /* should be signal SIGSTOP/SIGCONT to gc task?*/ -+static int GCTaskPID; -+ -+static int RunAsRTTask = FALSE; /* default action unless priority is -+ specified on cmd line */ -+ -+ -+/********************* Local Function Prototypes **********************/ -+void HandleCmdLineArgs(int argc, char *argv[]); -+void SetFileName(char * pFileName); -+void SetInterruptPeriod(char * pASCIIInterruptPeriodMilliSec); -+void SetSchedulerPriority(char * pASCIISchedulerPriority); -+ -+void PrintVersionInfo(void); -+void PrintHelpInfo(void); -+ -+int Write(int fd, void *buf, size_t bytes, int lineNo); -+ -+void InitITimer(struct itimerval * pITimer, int action); -+ -+/* For catching timer interrupts (SIGALRM). */ -+void AlarmHandler(int sigNum); -+ -+/* For catching Ctrl+C SIGINT. */ -+void SignalHandler(int sigNum); -+ -+ -+ -+/*********************************************************************** -+ * main function -+ * return: exit code -+ ***********************************************************************/ -+int main( -+ int argc, -+ char *argv[]) -+{ -+ struct sched_param schedParam; -+ -+ int mypri; -+ char tmpBuf[200]; -+ -+ -+ strcpy(OutFileName,"jitter.dat"); -+ InterruptPeriodMilliSec = MIN_INT_PERIOD_MILLISEC; -+ -+ /* Get the minimum and maximum priorities. */ -+ MinPriority = sched_get_priority_min(PRIORITY_POLICY); -+ MaxPriority = sched_get_priority_max(PRIORITY_POLICY); -+ if (MinPriority == -1) { -+ printf("\n*** Unable to get minimum priority. ***\n"); -+ exit(EXIT_MIN_PRIORITY_ERR); -+ } -+ if (MaxPriority == -1) { -+ printf("\n*** Unable to get maximum priority. ***\n"); -+ exit(EXIT_MAX_PRIORITY_ERR); -+ } -+ -+ /* Set requested priority to minimum value as default. */ -+ RequestedPriority = MinPriority; -+ -+ HandleCmdLineArgs(argc, argv); -+ -+ if(mlockall(MCL_CURRENT|MCL_FUTURE) < 0){ -+ printf("Could not lock task into memory. Bye\n"); -+ perror("Error"); -+ } -+ -+ if(RunAsRTTask){ -+ -+ /* Set the priority. */ -+ schedParam.sched_priority = RequestedPriority; -+ if (sched_setscheduler( -+ 0, -+ PRIORITY_POLICY, -+ &schedParam) != (int) 0) { -+ printf("Exiting: Unsuccessful sched_setscheduler.\n"); -+ close(Fd1); -+ exit(EXIT_SET_SCHEDULER_ERR); -+ } -+ -+ -+ /* Double check as I have some doubts that it's really -+ running at realtime priority! */ -+ if((mypri = sched_getscheduler(0)) != RequestedPriority) -+ { -+ printf("Not running with request priority %i. running with priority %i instead!\n", -+ RequestedPriority, mypri); -+ }else -+ { -+ printf("Running with %i priority. Good!\n", mypri); -+ } -+ -+ } -+ -+ /*------------------------- Initializations --------------------------*/ -+ if((Fd1 = open(OutFileName, O_RDWR|O_CREAT|O_SYNC)) <= 0) -+ { -+ perror("Cannot open outfile for write:"); -+ exit(1); -+ } -+ -+ /* If a request is made to read from a specified file, then create that -+ file and fill with junk data so that there is something there to read. -+ */ -+ if(DoRead) -+ { -+ -+ if((Fd2 = open(ReadFile, O_RDWR|O_CREAT|O_SYNC|O_TRUNC)) <= 0) -+ { -+ perror("cannot open read file:"); -+ exit(1); -+ }else -+ { -+ -+ /* Don't really care how much we write here */ -+ if(write(Fd2, READ_FILE_MESSAGE, strlen(READ_FILE_MESSAGE)) < 0) -+ { -+ perror("Problems writing to readfile:"); -+ exit(1); -+ } -+ lseek(Fd2, 0, SEEK_SET); /* position back to byte #0 */ -+ } -+ } -+ -+ -+ -+ /* Also log output to console. This way we can capture it -+ on a serial console to a log file. -+ */ -+ if((Cfd = open(LogFile, O_WRONLY|O_SYNC)) <= 0) -+ { -+ perror("cannot open o/p logfile:"); -+ exit(1); -+ } -+ -+ -+ /* Set-up handler for periodic interrupt. */ -+ if (signal(SIGALRM, &AlarmHandler) == SIG_ERR) { -+ printf("Couldn't register signal handler for SIGALRM.\n"); -+ sprintf(tmpBuf, -+ "Couldn't register signal handler for SIGALRM.\n"); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ close(Fd1); -+ exit(EXIT_REG_SIGALRM_ERR); -+ } -+ -+ /* Set-up handler for Ctrl+C to exit the program. */ -+ if (signal(SIGINT, &SignalHandler) == SIG_ERR) { -+ printf("Couldn't register signal handler for SIGINT.\n"); -+ sprintf(tmpBuf, -+ "Couldn't register signal handler for SIGINT.\n"); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ close(Fd1); -+ exit(EXIT_REG_SIGINT_ERR); -+ } -+ -+ printf("Press Ctrl+C to exit the program.\n"); -+ printf("Output File: %s\n", OutFileName); -+ printf("Scheduler priority: %d\n", RequestedPriority); -+ sprintf(tmpBuf, "\nScheduler priority: %d\n", -+ RequestedPriority); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ printf("Interrupt period: %ld milliseconds\n", -+ InterruptPeriodMilliSec); -+ sprintf(tmpBuf, "Interrupt period: %ld milliseconds\n", -+ InterruptPeriodMilliSec); -+ -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ -+ fflush(0); -+ -+ -+ -+ /* Initialize the periodic timer. */ -+ InitITimer(&ITimer, ONESHOT); -+ -+ /* Initialize "previous" time. */ -+ if (gettimeofday(&PrevTimeVal, NULL) != (int) 0) { -+ printf("Exiting - "); -+ printf("Unable to initialize previous time of day.\n"); -+ sprintf(tmpBuf, "Exiting - "); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ sprintf(tmpBuf, -+ "Unable to initialize previous time of day.\n"); -+ -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ } -+ -+ /* Start the periodic timer. */ -+ setitimer(ITIMER_REAL, &ITimer, NULL); -+ -+ -+ while(TRUE) { /* Intentional infinite loop. */ -+ /* Sleep for one second. */ -+ sleep((unsigned int) 1); -+ } -+ -+ /* Just in case. File should be closed in SignalHandler. */ -+ close(Fd1); -+ close(Cfd); -+ -+ return 0; -+} -+ -+ -+ -+ -+/*********************************************************************** -+ * SignalHandler -+ * This is a handler for the SIGINT signal. It is assumed that the -+ * SIGINT is due to the user pressing Ctrl+C to halt the program. -+ * output: N/A -+ ***********************************************************************/ -+void SignalHandler( -+ int sigNum) -+{ -+ -+ char tmpBuf[200]; -+ -+ /* Note sigNum not used. */ -+ printf("Ctrl+C detected. Worst Jitter time was:%fms.\nJitterTest exiting.\n", -+ (float)LastMaxDiff/1000.0); -+ -+ sprintf(tmpBuf, -+ "\nCtrl+C detected. Worst Jitter time was:%fms\nJitterTest exiting.\n", -+ (float)LastMaxDiff/1000.0); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ close(Fd1); -+ close(Cfd); -+ exit(0); -+} -+ -+ -+ -+ -+ -+/* -+ A snapshot of the /proc/profile needs to be taken. -+ This is stored as a new file every time, and the -+ stats reset by doing a (any) write to the /proc/profile -+ file. -+ */ -+void doGrabKProfile(int jitterusec, char *fileName) -+{ -+ int fdSnapshot; -+ int fdProfile; -+ int readBytes; -+ char readBuf[4096]; -+ -+ if((fdSnapshot = open(fileName, O_WRONLY | O_CREAT)) <= 0) -+ { -+ fprintf(stderr, "Could not open file %s.\n", fileName); -+ perror("Error:"); -+ return; -+ } -+ -+ if((fdProfile = open("/proc/profile", O_RDWR)) <= 0) -+ { -+ fprintf(stderr, "Could not open file /proc/profile. Make sure you booted with profile=2\n"); -+ close(fdSnapshot); -+ return; -+ } -+ -+ while((readBytes = read(fdProfile, readBuf, sizeof(readBuf))) > 0) -+ { -+ write(fdSnapshot, readBuf, readBytes); -+ } -+ -+ close(fdSnapshot); -+ -+ if(write(fdProfile, readBuf, 1) != 1) -+ { -+ perror("Could Not clear profile by writing to /proc/profile:"); -+ } -+ -+ close(fdProfile); -+ -+ -+ -+}/* end doGrabKProfile()*/ -+ -+ -+/* -+ Call this routine to clear the kernel profiling buffer /proc/profile -+*/ -+void clearProfileBuf(void){ -+ -+ -+ int fdProfile; -+ char readBuf[10]; -+ -+ -+ if((fdProfile = open("/proc/profile", O_RDWR)) <= 0) -+ { -+ fprintf(stderr, "Could not open file /proc/profile. Make sure you booted with profile=2\n"); -+ return; -+ } -+ -+ -+ if(write(fdProfile, readBuf, 1) != 1) -+ { -+ perror("Could Not clear profile by writing to /proc/profile:"); -+ } -+ -+ close(fdProfile); -+ -+ -+}/* end clearProfileBuf() */ -+ -+ -+ -+ -+ -+/*********************************************************************** -+ * AlarmHandler -+ * This is a handler for the SIGALRM signal (due to the periodic -+ * timer interrupt). It prints the time (seconds) to -+ * the output file. -+ * output: N/A -+ ***********************************************************************/ -+void AlarmHandler( -+ int sigNum) /* signal number (not used) */ -+{ -+ -+ long timeDiffusec; /* diff time in micro seconds */ -+ long intervalusec; -+ -+ -+ char tmpBuf[MAX_WRITE_BYTES]; -+ int cntr; -+ char padChar; -+ -+ static int profileFileNo = 0; -+ char profileFileName[150]; -+ -+ static int seedStarter = 0; /* carries over rand info to next time -+ where time() will be the same as this time -+ if invoked < 1sec apart. -+ */ -+ -+ if (gettimeofday(&CurrTimeVal, NULL) == (int) 0) { -+ -+ /*---------------------------------------------------------------- -+ * Compute the elapsed time between the current and previous -+ * time of day values and store the result. -+ * -+ * Print the elapsed time to the output file. -+ *---------------------------------------------------------------*/ -+ -+ timeDiffusec = (long)(((((long long)CurrTimeVal.tv_sec) * 1000000L) + CurrTimeVal.tv_usec) - -+ (((long long)PrevTimeVal.tv_sec * 1000000L) + PrevTimeVal.tv_usec)); -+ -+ sprintf(tmpBuf," %f ms ", (float)timeDiffusec/1000.0); -+ -+ intervalusec = InterruptPeriodMilliSec * 1000L; -+ -+ timeDiffusec = timeDiffusec - intervalusec; -+ -+ sprintf(&tmpBuf[strlen(tmpBuf)]," %f ms", (float)timeDiffusec/1000.0); -+ -+ -+ /* should we send a SIGSTOP/SIGCONT to the specified PID? */ -+ if(SignalGCTask){ -+ -+ if(kill(GCTaskPID, SIGSTOP) < 0){ -+ -+ perror("error:"); -+ } -+ } -+ -+ -+ /* Store some historical #'s */ -+ if(abs(timeDiffusec) > LastMaxDiff) -+ { -+ LastMaxDiff = abs(timeDiffusec); -+ sprintf(&tmpBuf[strlen(tmpBuf)],"!"); -+ -+ if((GrabKProfile == TRUE) && (ProfileTriggerMSecs < (abs(timeDiffusec)/1000))) -+ { -+ sprintf(profileFileName, "JitterTest.profilesnap-%i", profileFileNo); -+ -+ /* go and grab the kernel performance profile. */ -+ doGrabKProfile(timeDiffusec, profileFileName); -+ profileFileNo++; /* unique name next time */ -+ -+ /* Say so on the console so that a marker gets put in the console log */ -+ sprintf(&tmpBuf[strlen(tmpBuf)],"", -+ profileFileName); -+ -+ } -+ -+ } -+ -+ -+ -+ -+ sprintf(&tmpBuf[strlen(tmpBuf)],"\n"); /* CR for the data going out of the console */ -+ -+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ -+ /* The "-1" below takes out the '\n' at the end that we appended for the msg printed on -+ the console.*/ -+ sprintf(&tmpBuf[strlen(tmpBuf)-1]," PadBytes:"); -+ -+ /* Now pad the output file if requested by user. */ -+ if(WriteBytes > MIN_WRITE_BYTES) -+ { -+ -+ /* start from a new place every time */ -+ srand(time(NULL) + seedStarter); -+ -+ /* already written MIN_WRITE_BYTES by now */ -+ for(cntr = strlen(tmpBuf); cntr < WriteBytes - 1 ; cntr++) /* "-1" adj for '\n' at end */ -+ { -+ /* don't accept any # < 'SPACE' */ -+ padChar = (char)(MIN_ASCII+(int)((MAX_ASCII-(float)MIN_ASCII)*rand()/(RAND_MAX+1.0))); -+ -+ -+ /* -+ padChar = (cntr % (126-33)) + 33; -+ */ -+ -+ tmpBuf[cntr] = padChar; -+ } -+ -+ seedStarter = tmpBuf[cntr-1]; /* save for next time */ -+ -+ tmpBuf[cntr] = '\n'; /* CR for the data going into the outfile. */ -+ tmpBuf[cntr+1] = '\0'; /* NULL terminate the string */ -+ } -+ -+ /* write out the entire line to the output file. */ -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ -+ /* Read a byte from the specified file */ -+ if(DoRead) -+ { -+ -+ read(Fd2, tmpBuf, 1); -+ lseek(Fd2, 0, SEEK_SET); /* back to start */ -+ } -+ -+ -+ /* Start the periodic timer again. */ -+ setitimer(ITIMER_REAL, &ITimer, NULL); -+ -+ -+ /* Update previous time with current time. */ -+ PrevTimeVal.tv_sec = CurrTimeVal.tv_sec; -+ PrevTimeVal.tv_usec = CurrTimeVal.tv_usec; -+ } -+ -+ else { -+ sprintf(tmpBuf, "gettimeofday error \n"); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ printf("gettimeofday error \n"); -+ } -+ -+ /* now clear the profiling buffer */ -+ if(GrabKProfile == TRUE){ -+ -+ clearProfileBuf(); -+ } -+ -+ /* should we send a SIGSTOP/SIGCONT to the specified PID? */ -+ if(SignalGCTask){ -+ -+ if(kill(GCTaskPID, SIGCONT) < 0){ -+ -+ perror("error:"); -+ } -+ } -+ -+ -+ return; -+} -+ -+ -+ -+/*********************************************************************** -+ * InitITimer -+ * This function initializes the 'struct itimerval' structure whose -+ * address is passed to interrupt every InterruptPeriodMilliSec. -+ * output: N/A -+ ***********************************************************************/ -+void InitITimer( -+ struct itimerval * pITimer, /* pointer to interrupt timer struct*/ -+ int action) /* ONESHOT or autosetting? */ -+{ -+ long seconds; /* seconds portion of int. period */ -+ long microSeconds; /* microsec. portion of int. period */ -+ -+ /*-------------------------------------------------------------------- -+ * Divide the desired interrupt period into its seconds and -+ * microseconds components. -+ *-------------------------------------------------------------------*/ -+ if (InterruptPeriodMilliSec < MILLISEC_PER_SEC) { -+ seconds = 0L; -+ microSeconds = InterruptPeriodMilliSec * MICROSEC_PER_MILLISEC; -+ } -+ else { -+ seconds = InterruptPeriodMilliSec / MILLISEC_PER_SEC; -+ microSeconds = -+ (InterruptPeriodMilliSec - (seconds * MILLISEC_PER_SEC)) * -+ MICROSEC_PER_MILLISEC; -+ } -+ -+ /* Initialize the interrupt period structure. */ -+ pITimer->it_value.tv_sec = seconds; -+ pITimer->it_value.tv_usec = microSeconds; -+ -+ if(action == ONESHOT) -+ { -+ /* This will (should) prevent the timer from restarting itself */ -+ pITimer->it_interval.tv_sec = 0; -+ pITimer->it_interval.tv_usec = 0; -+ }else -+ { -+ pITimer->it_interval.tv_sec = seconds; -+ pITimer->it_interval.tv_usec = microSeconds; -+ -+ } -+ -+ return; -+} -+ -+ -+/*********************************************************************** -+ * HandleCmdLineArgs -+ * This function handles the command line arguments. -+ * output: stack size -+ ***********************************************************************/ -+void HandleCmdLineArgs( -+ int argc, /* number of command-line arguments */ -+ char *argv[]) /* ptrs to command-line arguments */ -+{ -+ int argNum; /* argument number */ -+ -+ if (argc > (int) 1) { -+ -+ for (argNum = (int) 1; argNum < argc; argNum++) { -+ -+ /* The command line contains an argument. */ -+ -+ if ((strcmp(argv[argNum],"--version") == STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-v") == STRINGS_EQUAL)) { -+ /* Print version information and exit. */ -+ PrintVersionInfo(); -+ exit(0); -+ } -+ -+ else if ((strcmp(argv[argNum],"--help") == STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-h") == STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-?") == STRINGS_EQUAL)) { -+ /* Print help information and exit. */ -+ PrintHelpInfo(); -+ exit(0); -+ } -+ -+ else if ((strcmp(argv[argNum],"--file") == STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-f") == STRINGS_EQUAL)) { -+ /* Set the name of the output file. */ -+ ++argNum; -+ if (argNum < argc) { -+ SetFileName(argv[argNum]); -+ } -+ else { -+ printf("*** Output file name not specified. ***\n"); -+ printf("Default output file name will be used.\n"); -+ } -+ } -+ -+ else if ((strcmp(argv[argNum],"--time") == STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-t") == STRINGS_EQUAL)) { -+ /* Set the interrupt period. */ -+ ++argNum; -+ if (argNum < argc) { -+ SetInterruptPeriod(argv[argNum]); -+ } -+ else { -+ printf("*** Interrupt period not specified. ***\n"); -+ printf("Default interrupt period will be used.\n"); -+ } -+ -+ } -+ -+ else if ((strcmp(argv[argNum],"--priority") == -+ STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-p") == STRINGS_EQUAL)) { -+ /* Set the scheduler priority. */ -+ ++argNum; -+ if (argNum < argc) { -+ SetSchedulerPriority(argv[argNum]); -+ } -+ else { -+ printf("*** Scheduler priority not specified. ***\n"); -+ printf("Default scheduler priority will be used.\n"); -+ } -+ -+ } -+ -+ else if ((strcmp(argv[argNum],"--readfile") == -+ STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-r") == STRINGS_EQUAL)) { -+ /* Set the file to read*/ -+ ++argNum; -+ -+ strncpy(ReadFile, argv[argNum], sizeof(ReadFile)); -+ DoRead = TRUE; -+ } -+ -+ else if ((strcmp(argv[argNum],"--write_bytes") == -+ STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-w") == STRINGS_EQUAL)) { -+ /* Set the file to read*/ -+ ++argNum; -+ -+ WriteBytes = atoi(argv[argNum]); -+ -+ if(WriteBytes < MIN_WRITE_BYTES) -+ { -+ printf("Writing less than %i bytes is not allowed. Bye.\n", -+ MIN_WRITE_BYTES); -+ exit(0); -+ } -+ -+ -+ } -+ -+ else if ((strcmp(argv[argNum],"--consolefile") == -+ STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-c") == STRINGS_EQUAL)) { -+ /* Set the file to log console log on. */ -+ ++argNum; -+ -+ strncpy(LogFile, argv[argNum], sizeof(LogFile)); -+ } -+ -+ else if ((strcmp(argv[argNum],"--grab_kprofile") == -+ STRINGS_EQUAL)) -+ { -+ /* We will read the /proc/profile file on configurable timeout */ -+ GrabKProfile = TRUE; -+ -+ ++argNum; -+ -+ /* If the jittter is > this #, then the profile is grabbed. */ -+ ProfileTriggerMSecs = (long) atoi(argv[argNum]); -+ -+ if(ProfileTriggerMSecs <= 0){ -+ -+ printf("Illegal value for profile trigger threshold.\n"); -+ exit(0); -+ } -+ } -+ -+ else if ((strcmp(argv[argNum],"--siggc") == -+ STRINGS_EQUAL)) -+ { -+ /* We will SIGSTOP/SIGCONT the specified pid */ -+ SignalGCTask = TRUE; -+ -+ ++argNum; -+ -+ GCTaskPID = atoi(argv[argNum]); -+ -+ if(ProfileTriggerMSecs <= 0){ -+ -+ printf("Illegal value for JFFS(2) GC task pid.\n"); -+ exit(0); -+ } -+ } -+ -+ -+ else { -+ /* Unknown argument. Print help information and exit. */ -+ printf("Invalid option %s\n", argv[argNum]); -+ printf("Try 'JitterTest --help' for more information.\n"); -+ exit(0); -+ } -+ } -+ } -+ -+ return; -+} -+ -+ -+/*********************************************************************** -+ * SetFileName -+ * This function sets the output file name. -+ * output: N/A -+ ***********************************************************************/ -+void SetFileName( -+ char * pFileName) /* ptr to desired output file name */ -+{ -+ size_t fileNameLen; /* file name length (bytes) */ -+ -+ /* Check file name length. */ -+ fileNameLen = strlen(pFileName); -+ if (fileNameLen > (size_t) MAX_FILE_NAME_LEN) { -+ printf("File name %s exceeds maximum length %d.\n", -+ pFileName, MAX_FILE_NAME_LEN); -+ exit(0); -+ } -+ -+ /* File name length is OK so save the file name. */ -+ strcpy(OutFileName, pFileName); -+ -+ return; -+} -+ -+ -+/*********************************************************************** -+ * SetInterruptPeriod -+ * This function sets the interrupt period. -+ * output: N/A -+ ***********************************************************************/ -+void SetInterruptPeriod( -+ char * /* ptr to desired interrupt period */ -+ pASCIIInterruptPeriodMilliSec) -+{ -+ long period; /* interrupt period */ -+ -+ period = atol(pASCIIInterruptPeriodMilliSec); -+ if ((period < MIN_INT_PERIOD_MILLISEC) || -+ (period > MAX_INT_PERIOD_MILLISEC)) { -+ printf("Invalid interrupt period: %ld ms.\n", period); -+ exit(EXIT_INV_INT_PERIOD); -+ } -+ else { -+ InterruptPeriodMilliSec = period; -+ } -+ return; -+} -+ -+ -+/*********************************************************************** -+ * SetSchedulerPriority -+ * This function sets the desired scheduler priority. -+ * output: N/A -+ ***********************************************************************/ -+void SetSchedulerPriority( -+ char * pASCIISchedulerPriority) /* ptr to desired scheduler priority*/ -+{ -+ int priority; /* desired scheduler priority value */ -+ -+ priority = atoi(pASCIISchedulerPriority); -+ if ((priority < MinPriority) || -+ (priority > MaxPriority)) { -+ printf("Scheduler priority %d outside of range [%d, %d]\n", -+ priority, MinPriority, MaxPriority); -+ exit(EXIT_INV_SCHED_PRIORITY); -+ } -+ else { -+ RequestedPriority = priority; -+ RunAsRTTask = TRUE; /* We shall run as a POSIX real time task */ -+ } -+ return; -+} -+ -+ -+/*********************************************************************** -+ * PrintVersionInfo -+ * This function prints version information. -+ * output: N/A -+ ***********************************************************************/ -+void PrintVersionInfo(void) -+{ -+ printf("JitterTest version %s\n", Version); -+ printf("Copyright (c) 2001, Daniel Industries, Inc.\n"); -+ return; -+} -+ -+ -+/*********************************************************************** -+ * PrintHelpInfo -+ * This function prints help information. -+ * output: N/A -+ ***********************************************************************/ -+void PrintHelpInfo(void) -+{ -+ printf("Usage: JitterTest [options]\n"); -+ printf(" *** Requires root privileges. ***\n"); -+ printf("Option:\n"); -+ printf(" [-h, --help, -?] Print this message and exit.\n"); -+ printf(" [-v, --version] "); -+ printf( "Print the version number of JitterTest and exit.\n"); -+ printf(" [-f FILE, --file FILE] Set output file name to FILE. Typically you would put this on the fs under test\n"); -+ printf(" [-c FILE, --consolefile] Set device or file to write the console log to.\n\tTypically you would set this to /dev/console and save it on another computer.\n"); -+ printf(" [-w BYTES, --write_bytes BYTES Write BYTES to FILE each period.\n"); -+ printf(" [-r FILE, --readfile FILE] Also read 1 byte every cycle from FILE. FILE will be created and filled with data.\n"); -+ printf(" [-t , --time ] "); -+ printf( "Set interrupt period to milliseconds.\n"); -+ printf(" "); -+ printf( "Range: [%ld, %ld] milliseconds.\n", -+ MIN_INT_PERIOD_MILLISEC, MAX_INT_PERIOD_MILLISEC); -+ printf(" [-p , --priority ] "); -+ printf( "Set scheduler priority to .\n"); -+ printf(" "); -+ printf( "Range: [%d, %d] (higher number = higher priority)\n", -+ MinPriority, MaxPriority); -+ printf(" [--grab_kprofile ] Read the /proc/profile if jitter is > THRESHOLD and store in file.\n"); -+ printf(" [--siggc ] Before writing to fs send SIGSTOP to PID. After write send SIGCONT\n"); -+ return; -+ -+} -+ -+ -+/* A common write that checks for write errors and exits. Pass it __LINE__ for lineNo */ -+int Write(int fd, void *buf, size_t bytes, int lineNo) -+{ -+ -+ int err; -+ -+ err = write(fd, buf, bytes); -+ -+ if(err < bytes) -+ { -+ -+ printf("Write Error at line %i! Wanted to write %i bytes, but wrote only %i bytes.\n", -+ lineNo, bytes, err); -+ perror("Write did not complete. Error. Bye:"); /* show error from errno. */ -+ exit(1); -+ -+ } -+ -+ return err; -+ -+}/* end Write*/ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,46 @@ -+CC=gcc -+# uncomment following for performance -+CCFLAGS=-O3 -Wall -m486 -fomit-frame-pointer -+ -+# uncomment following for debugging. Uncomment either this or the one above. Not both. -+# CCFLAGS=-Wall -g -+ -+ -+all: JitterTest plotJittervsFill -+ -+JitterTest: JitterTest.c Makefile -+ gcc $(CCFLAGS) -lm JitterTest.c -o JitterTest -+ -+plotJittervsFill: plotJittervsFill.c Makefile -+ gcc $(CCFLAGS) plotJittervsFill.c -o plotJittervsFill -+ -+clean: -+ rm -rf *~ -+ rm -rf core -+ rm -rf *.o -+ rm -rf JitterTest -+ -+ -+dep: -+ makedepend -I./ *.c -+# DO NOT DELETE -+ -+JitterTest.o: /usr/include/stdio.h /usr/include/features.h -+JitterTest.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h -+JitterTest.o: /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stddef.h -+JitterTest.o: /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stdarg.h -+JitterTest.o: /usr/include/bits/types.h /usr/include/libio.h -+JitterTest.o: /usr/include/_G_config.h /usr/include/bits/stdio_lim.h -+JitterTest.o: /usr/include/string.h /usr/include/stdlib.h -+JitterTest.o: /usr/include/sys/types.h /usr/include/time.h -+JitterTest.o: /usr/include/endian.h /usr/include/bits/endian.h -+JitterTest.o: /usr/include/sys/select.h /usr/include/bits/select.h -+JitterTest.o: /usr/include/bits/sigset.h /usr/include/sys/sysmacros.h -+JitterTest.o: /usr/include/alloca.h /usr/include/sys/time.h -+JitterTest.o: /usr/include/bits/time.h /usr/include/signal.h -+JitterTest.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h -+JitterTest.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h -+JitterTest.o: /usr/include/asm/sigcontext.h /usr/include/bits/sigstack.h -+JitterTest.o: /usr/include/sched.h /usr/include/bits/sched.h -+JitterTest.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h -+JitterTest.o: /usr/include/bits/confname.h /usr/include/getopt.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/README 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,197 @@ -+$Id: README,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ -+This is the README file for the JitterTest (and friends) -+program. -+ -+This program is used to measure what the jitter of a -+real time task would be under "standard" Linux. -+ -+More particularly, what is the effect of running -+a real time task under Linux with background -+JFFS file system activity. -+ -+The jitter is measured in milli seconds (ms) from -+the expected time of arrival of a signal from a -+periodic timer (set by the task) to when the -+task actually gets the signal. -+ -+This jitter is then stored in a file specified -+(or the default output file "jitter.dat"). -+ -+The data may also be sent out to the console by -+writing to /dev/console (See help options. This is -+highly desirable specially if you have redirected -+your console to the serial port and are storing it -+as a minicom log on another computer for later analysis -+using some tools provided here). -+ -+This is particularly useful if you have a serial -+console and are outputting "interesting" info -+from inside some kernel task or driver. -+(or something as simple as a "df" program running -+periodically and redirecting o/p to the console). -+ -+One "interesting" thing that I have measured -+is the effect of FLASH chip erases on the jitter -+of a real time task. -+ -+One can do that by putting a printk at the -+beginning of the flash erase routine in the MTD -+flash chip driver. -+ -+Now you will get jitter data interspersed with -+flash sector erase events. Other printk's can also -+be placed at suspected jitter causing locations in -+the system. -+ -+ -+ -+EXECUTING THE PROGRAM "JitterTest" -+ -+You may specify a file to be read by the -+program every time it wakes up (every cycle). -+This file is created and filled with some junk -+data. The purpose of this is to test the jitter -+of the program if it were reading from- say -+a JFFS (Journaling Flash File System) file system. -+ -+By specifying the complete paths of the read and write -+(o/p) files you can test the jitter a POSIX type -+real time task will experience under Linux, under -+various conditions. -+ -+These can be as follows: -+ -+1. O/P file on ram file system, no i/p file. -+ -+ In this case you would presumably generate other -+"typical" background activity for your system and -+examine the worst case jitter experienced by -+a task that is neither reading nor writing to -+a file system. -+ -+Other cases could be: -+ -+2. O/P to ram fs, I/P from JFFS (type) fs: -+ -+ This is specially useful to test the proper -+operation of erase suspend type of operation -+in JFFS file systems (with an MTD layer that -+supports it). -+ -+ In this test you would generate some background -+write/erase type activity that would generate -+chip erases. Since this program is reading from -+the same file system, you contrast the latencies -+with those obtained with writes going to the same -+fs. -+ -+3. Both read and writes to (or just write to) JFFS -+file system: -+ -+ Here you would test for latencies experienced by -+a program if it were writing (and optionally also -+reading) from a JFFS fs. -+ -+ -+ -+ -+Grabing a kernel profile: -+ -+This program can also conditionally grab a kernel profile. -+Specify --grab_kprofile on the cmd line as well as -+a "threshold" parameter (see help options by -?). -+ -+Any jitter greater than this "threshold" will cause the -+program to read the /proc/profile file and dump it in -+a local file with increasing file numbers. It will also -+output the filename at that time to the console file specified. -+This will allow you to corelate later in time the various profiles -+with data in your console file and what was going on at that time. -+ -+These profile files may then be later examined by running them through -+ksymoops. -+ -+Make sure you specify "profile=2" on the kernel command line -+when you boot the kernel if you want to use this functionality. -+ -+ -+ -+Signalling the JFFS[2] GC task: -+ -+You can also force this program to send a SIGSTOP/SIGCONT to the -+JFFS (or JFFS2) gc task by specifing --siggc on the cmd line. -+ -+This will let you investigate the effect of forcing the gc task to -+wake up and do its thing when you are not writing to the fs and to -+force it to sleep when you want to write to the fs. -+ -+These are just various tools to investigate the possibility of -+achieving minimal read/write latency when using JFFS[2]. -+ -+You need to manually do a "ps aux" and look up the PID of the gc -+thread and provide it to the program. -+ -+ -+ -+ -+EXECUTING THE PROGRAM "plotJittervsFill" -+ -+This program is a post processing tool that will extract the jitter -+times as printed by the JitterTest program in its console log file -+as well as the data printed by the "df" command. -+ -+This "df" data happens to be in the console log because you will -+run the shell file fillJffs2.sh on a console when you are doing -+your jitter test. -+ -+This shell script copies a specified file to another specified file -+every programmable seconds. It also does a "df" and redirects output -+to /dev/console where it is mixed with the output from JitterTest. -+ -+All this console data is stored on another computer, as all this data -+is being outputted to the serial port as you have redirected the console -+to the serial port (that is the only guaranteed way to not loose any -+console log or printk data). -+ -+You can then run this saved console log through this program and it -+will output a very nice text file with the %fill in one col and -+corrosponding jitter values in the second. gnuplot then does a -+beautifull plot of this resulting file showing you graphically the -+jitters encountered at different fill % of your JFFS[2] fs. -+ -+ -+ -+OTHER COMMENTS: -+ -+Use the "-w BYTES" cmd line parameter to simulate your test case. -+Not everyone has the same requirements. Someone may want to measure -+the jitter of JFFS2 with 500 bytes being written every 500ms. Others -+may want to measure the system performance writing 2048 bytes every -+5 seconds. -+ -+RUNNING MULTIPLE INSTANCES: -+ -+Things get real interesting when you run multiple instances of this -+program *at the same time*. -+ -+You could have one version running as a real time task (by specifing -+the priority with the -p cmd line parameter), not interacting with -+any fs or at the very least not reading and writing to JFFS[2]. -+ -+At the same time you could have another version running as a regular -+task (by not specifing any priority) but reading and writing to JFFS[2]. -+ -+This way you can easily measure the blocking performance of the real time -+task while another non-real time task interacts with JFFS[2] in the back ground. -+ -+You get the idea. -+ -+ -+WATCH OUT! -+ -+Be particularly careful of running this program as a real time task AND -+writing to JFFS[2]. Any blocks will cause your whole system to block till -+any garbage collect initiated by writes by this task complete. I have measured -+these blocks to be of the order of 40-50 seconds on a reasonably powerful -+32 bit embedded system. ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,16 @@ -+#!/bin/bash -+ -+# Pass following cmd line: -+# 1st - file to copy -+# 2nd - file to copy to -+# 3rd - time to sleep between copies -+ -+while [ $(( 1 )) -gt $(( 0 )) ] -+do -+ cp $1 $2 -+ rm $2 -+ df |grep mtd > /dev/console -+ echo "sleeping $3" -+ sleep $3 -+done -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,312 @@ -+/* -+ *********************************************************************** -+ * -+ * Copyright: Daniel Measurement and Control, Inc. -+ * 9753 Pine Lake Drive -+ * Houston, TX 77055 -+ * -+ * Created by: Vipin Malik -+ * Released under GPL by permission of Daniel Industries. -+ * -+ * This software is licensed under the GPL version 2. Plese see the file -+ * COPYING for details on the license. -+ * -+ * NO WARRANTY: Absolutely no claims of warranty or fitness of purpose -+ * are made in this software. Please use at your own risk. -+ * -+ File: plotJittervsFill.c -+ By: Vipin Malik -+ -+ About: This program reads in a jitter log file as created -+ by the JitterTest.c program and extracts all the jitters -+ in the file that are greater than a threshold specified -+ as a parameter on the cmd line. It also extracts the -+ amount of disk space at (form the "df" out that should also -+ be present in the log file) after the jitter extracted. -+ -+ It writes the data to the stderr (where you may redirect it). -+ It is suitable for plotting, as the data is written as -+ COL1=UsedSpace COL2=Jitter -+ -+ $Id: plotJittervsFill.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Log: not supported by cvs2svn $ -+ Revision 1.6 2005/11/07 11:15:21 gleixner -+ [MTD / JFFS2] Clean up trailing white spaces -+ -+ Revision 1.5 2001/08/10 19:23:11 vipin -+ Ready to be released under GPL! Added proper headers etc. -+ -+ Revision 1.4 2001/07/02 22:25:40 vipin -+ Fixed couple of minor cosmetic typos. -+ -+ Revision 1.3 2001/07/02 14:46:46 vipin -+ Added a debug option where it o/p's line numbers to debug funky values. -+ -+ Revision 1.2 2001/06/26 19:48:57 vipin -+ Now prints out jitter values found at end of log file, after which -+ no new "df" disk usage values were encountered. The last "df" disk usage -+ encountered is printed for these orphaned values. -+ -+ Revision 1.1 2001/06/25 19:13:55 vipin -+ Added new file- plotJittervsFill.c- that mines the data log file -+ outputed from the fillFlash.sh script file and JitterTest.c file -+ and produces output suitable to be plotted. -+ This output plot may be examined to see visually the relationship -+ of the Jitter vs disk usage of the fs under test. -+ -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+static char Version_string[] = "$Id: plotJittervsFill.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $"; -+static char LogFile[250] = "InputLogFile.log"; -+ -+static int JitterThreshold_ms = 1000; -+static int Debug = 0; /* Debug level. Each "-d" on the cmd line increases the level */ -+ -+#define TRUE 1 -+#define FALSE 0 -+ -+#define MIN_JITTER_THRESHOLD 1 /* ms minimum jitter threshold */ -+ -+void PrintHelpInfo(void) -+{ -+ printf("Usage: plotJittervsFill [options] -f [--file] -t [--jitter_threshold] \n"); -+ printf("[options]:\n-v [--version] Print version and exit\n"); -+ printf("-d Debug. Prints input file line number for each data point picked up.\n"); -+ printf("-h [--help] [-?] Print this help screen and exit.\n"); -+} -+ -+ -+ -+/*********************************************************************** -+ * HandleCmdLineArgs -+ * This function handles the command line arguments. -+ * output: stack size -+ ***********************************************************************/ -+void HandleCmdLineArgs( -+ int argc, /* number of command-line arguments */ -+ char *argv[]) /* ptrs to command-line arguments */ -+{ -+ int argNum; /* argument number */ -+ -+ if (argc > (int) 1) { -+ -+ for (argNum = (int) 1; argNum < argc; argNum++) { -+ -+ /* The command line contains an argument. */ -+ -+ if ((strcmp(argv[argNum],"--version") == 0) || -+ (strcmp(argv[argNum],"-v") == 0)) { -+ /* Print version information and exit. */ -+ printf("%s\n", Version_string); -+ exit(0); -+ } -+ -+ else if ((strcmp(argv[argNum],"--help") == 0) || -+ (strcmp(argv[argNum],"-h") == 0) || -+ (strcmp(argv[argNum],"-?") == 0)) { -+ /* Print help information and exit. */ -+ PrintHelpInfo(); -+ exit(0); -+ } -+ -+ else if ((strcmp(argv[argNum],"--file") == 0) || -+ (strcmp(argv[argNum],"-f") == 0)) { -+ /* Set the name of the output file. */ -+ ++argNum; -+ if (argNum < argc) { -+ strncpy(LogFile, argv[argNum], sizeof(LogFile)); -+ } -+ else { -+ printf("*** Input file name not specified. ***\n"); -+ exit(0); -+ } -+ } -+ -+ else if ((strcmp(argv[argNum],"--jitter_threshold") == 0) || -+ (strcmp(argv[argNum],"-t") == 0)) { -+ /* Set the file to read*/ -+ ++argNum; -+ -+ JitterThreshold_ms = atoi(argv[argNum]); -+ -+ if(JitterThreshold_ms < MIN_JITTER_THRESHOLD) -+ { -+ printf("A jitter threshold less than %i ms is not allowed. Bye.\n", -+ MIN_JITTER_THRESHOLD); -+ exit(0); -+ } -+ } -+ -+ else if ((strcmp(argv[argNum],"-d") == 0)) -+ { -+ /* Increment debug level */ -+ -+ Debug++; -+ } -+ -+ else { -+ /* Unknown argument. Print help information and exit. */ -+ printf("Invalid option %s\n", argv[argNum]); -+ printf("Try 'plotJittervsFill --help' for more information.\n"); -+ exit(0); -+ } -+ } -+ } -+ -+ return; -+} -+ -+ -+ -+ -+ -+int main( -+ int argc, -+ char *argv[]) -+{ -+ -+ char lineBuf[1024]; /* how long a single line be? */ -+ int converted; -+ int lineNo = 0; -+ int cnt; -+ -+ FILE *fp; -+ -+ int junkInt1, junkInt2, junkInt3; -+ float junkFloat1; -+ float jitter_ms; -+ -+#define MAX_SAVE_BUFFER 1000 /* How many values will be picked up while searching for -+ a % disk full line (i.e. before they can be printed out) -+ */ -+ int saveJitter[MAX_SAVE_BUFFER]; /* lets us record multiple jitter values that exceed -+ our threshold till we find a "df" field- which is when -+ we can o/p all these values. -+ */ -+ int dataLineNo[MAX_SAVE_BUFFER]; /* The saved line #'s for the above. Printed if debug specified. */ -+ -+ int saveJitterCnt = 0; -+ int lookFor_df = FALSE; -+ int dfPercent = -1; /* will be >= 0 if at least one found. The init value is a flag. */ -+ -+ char junkStr1[500], junkStr2[500]; -+ -+ HandleCmdLineArgs(argc, argv); -+ -+ if((fp = fopen(LogFile, "r")) == NULL) -+ { -+ printf("Unable to open input log file %s for read.\b", LogFile); -+ perror("Error:"); -+ exit(1); -+ } -+ -+ -+ -+ while(fgets(lineBuf, sizeof(lineBuf), fp) != NULL) -+ { -+ lineNo++; -+ -+ -+ /* Are we looking for a "df" o/p line? (to see how full -+ the flash is?)*/ -+ -+ /* is there a "%" in this line? */ -+ if((strstr(lineBuf, "%") != NULL) && (lookFor_df)) -+ { -+ converted = sscanf(lineBuf, "%s %i %i %i %i\n", -+ junkStr1, &junkInt1, &junkInt2, &junkInt3, &dfPercent); -+ if(converted < 5) -+ { -+ printf("Line %i contains \"%%\", but expected fileds not found. Skipping.\n", lineNo); -+ }else -+ { -+ /* Now print out the saved jitter values (in col2) with this dfPercent value as the col1. */ -+ for(cnt = 0; cnt < saveJitterCnt; cnt++) -+ { -+ if(Debug) -+ { -+ fprintf(stderr, "%i\t%i\t%i\n", (int)dataLineNo[cnt], -+ dfPercent, (int)saveJitter[cnt]); -+ }else -+ { -+ fprintf(stderr, "%i\t%i\n", dfPercent, (int)saveJitter[cnt]); -+ } -+ -+ -+ } -+ -+ saveJitterCnt = 0; /* all flushed. Reset for next saves. */ -+ lookFor_df = FALSE; -+ } -+ -+ } -+ -+ -+ /* is there a "ms" in this line?*/ -+ if(strstr(lineBuf, "ms") == NULL) -+ { -+ continue; -+ } -+ -+ /* grab the ms jitter value */ -+ converted = sscanf(lineBuf, "%f %s %f %s\n", &junkFloat1, junkStr1, &jitter_ms, junkStr2); -+ if(converted < 4) -+ { -+ printf("Line %i contains \"ms\", but expected fileds not found. Converted %i, Skipping.", -+ lineNo, converted); -+ printf("1=%i, 2=%s.\n", junkInt1, junkStr1); -+ continue; /* not our jitter line*/ -+ } -+ -+ /* Is the jitter value > threshold value? */ -+ if(abs(jitter_ms) > JitterThreshold_ms) -+ { -+ /* Found a jitter line that matches our crietrion. -+ Now set flag to be on the look out for the next -+ "df" output so that we can see how full the flash is. -+ */ -+ -+ if(saveJitterCnt < MAX_SAVE_BUFFER) -+ { -+ saveJitter[saveJitterCnt] = (int)abs(jitter_ms); /* why keep the (ms) jitter in float */ -+ dataLineNo[saveJitterCnt] = lineNo; -+ saveJitterCnt++; -+ lookFor_df = TRUE; -+ } -+ else -+ { -+ printf("Oops! I've run out of buffer space before I found a %% use line. Dropping itter value. Increase MAX_SAVE_BUFFER and recompile.\n"); -+ } -+ -+ -+ } -+ -+ } -+ -+ -+ /* Now print out any saved jitter values that were not printed out because we did not find -+ and "df" after these were picked up. Only print if a "df" disk usage was ever found. -+ */ -+ if(lookFor_df && (dfPercent >= 0)) -+ { -+ /* Now print out the saved jitter values (in col2) with this dfPercent value as the col1. */ -+ for(cnt = 0; cnt < saveJitterCnt; cnt++) -+ { -+ fprintf(stderr, "%i\t%i\n", dfPercent, (int)saveJitter[cnt]); -+ } -+ } -+ -+ return 0; -+ -+ -+}/* end main() */ -+ -+ -+ -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,48 @@ -+LIBUBI_PATH=../../ubi-utils/new-utils/ -+LIBUBI_SRC_PATH=../../ubi-utils/new-utils/src/ -+LIBUBI_HEADER_PATH=../../ubi-utils/new-utils/include -+UBI_HEADERS_PATH=../../include/ -+UBIUTILS_PATH=../../ubi-utils/new-utils/ -+ -+CC := $(CROSS)gcc -+ -+TESTS=io_update volrefcnt integ io_paral io_read io_basic \ -+ mkvol_basic mkvol_bad mkvol_paral rsvol -+ -+HELPER_NAMES=ubiupdatevol -+HELPERS=$(addprefix helpers/, $(HELPER_NAMES)) -+ -+# Because of implicite rules we use make treats .o files as intermediate, thus -+# it removes the. If you want to prevent the removal, uncomment the below -+#.SECONDARY: $(addsuffix .o, $(TESTS)) $(addsuffix .o, $(HELPERS)) -+ -+CFLAGS += -Wall -I$(LIBUBI_HEADER_PATH) -I $(UBI_HEADERS_PATH) -L. -O2 -+ -+all: ubi-utils libubi $(TESTS) $(HELPERS) -+ -+# Compile ubilib with the udevsettle hack -+libubi: $(LIBUBI_SRC_PATH)/libubi.c $(LIBUBI_HEADER_PATH)/libubi.h $(LIBUBI_SRC_PATH)/libubi_int.h -+ $(CC) $(CFLAGS) -I $(LIBUBI_SRC_PATH) -I../../include -DUDEV_SETTLE_HACK -c $(LIBUBI_SRC_PATH)/libubi.c -o libubi.o -+ ar cr libubi.a libubi.o -+ -+# The below cancels existing implicite rule to make programs from .c files, -+# in order to force make using our rule defined below -+%: %.c -+ -+# The below is the rule to get an .o file from a .c file -+%.o: %.c -+ $(CC) $(CFLAGS) $< -c -o $@ -+ -+# And the below is the rule to get final test executable from its .o and common.o -+%: %.o common.o -+ $(CC) $(CFLAGS) $^ -lubi -o $@ -+ -+# *paral tests require libpthread, thus the below rule for them -+%paral: %paral.o common.o -+ $(CC) $(CFLAGS) $^ -lubi -lpthread -o $@ -+ -+ubi-utils: -+ make -C $(UBIUTILS_PATH) -+ -+clean: -+ rm -f $(TESTS) $(addsuffix .o, $(TESTS)) libubi.* $(HELPERS) $(addsuffix .o, $(HELPERS)) ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,25 @@ -+There is a problem with udev: when a volume is created, there is a delay -+before corresponding /dev/ubiX_Y device node is created by udev, so some -+tests fail because of this. The symptom is error messages like -+"cannot open /dev/ubi0_0". -+ -+One possible solution of this problem is to pre-create UBI device and volume -+nodes. There is even a script which may be used for this in ubi-utils/scripts/. -+But this is not enough because udev will still remove and re-create the nodes -+and tests will still fail. So you need to stop removing device nodes using -+the following udev rule: -+ -+ KERNEL=="ubi*_*", ACTION=="remove", OPTIONS+="ignore_device" -+ -+In our Ubuntu distribution we put that to new file: -+/etc/udev/rules.d/50-local.rules -+ -+Another possibility is to call udevsettle utility in libubi after the volume -+has been created See src/libubi.c - the call is compiled in only if -+UDEV_SETTLE_HACK is defined. This is anyway an ugly hack, but works, although -+makes the tests slower. Suggestions are welcome. -+ -+So, if you have udevsettel unility in your system, you do not have to do -+anyting, and the tests should work, because we compile libubi with -+UDEV_SETTLE_HACK. Otherwise, you should remove -D UDEV_SETTLE_HACK -+from the makefile and pre-create UBI device nodes. ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/common.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/common.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,336 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * The stuff which is common for many tests. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#include "common.h" -+ -+/** -+ * __initial_check - check that common prerequisites which are required to run -+ * tests. -+ * -+ * @test test name -+ * @argc count of command-line arguments -+ * @argv command-line arguments -+ * -+ * This function returns %0 if all is fine and test may be run and %-1 if not. -+ */ -+int __initial_check(const char *test, int argc, char * const argv[]) -+{ -+ libubi_t libubi; -+ struct ubi_dev_info dev_info; -+ -+ /* -+ * All tests require UBI character device name as the first parameter, -+ * check this. -+ */ -+ if (argc < 2) { -+ __err_msg(test, __FUNCTION__, __LINE__, -+ "UBI character device node is not specified"); -+ return -1; -+ } -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ __failed(test, __FUNCTION__, __LINE__, "libubi_open"); -+ return -1; -+ } -+ -+ if (ubi_get_dev_info(libubi, argv[1], &dev_info)) { -+ __failed(test, __FUNCTION__, __LINE__, "ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (dev_info.avail_lebs < MIN_AVAIL_EBS) { -+ __err_msg(test, __FUNCTION__, __LINE__, -+ "insufficient available eraseblocks %d on UBI " -+ "device, required %d", -+ dev_info.avail_lebs, MIN_AVAIL_EBS); -+ goto close; -+ } -+ -+ if (dev_info.vol_count != 0) { -+ __err_msg(test, __FUNCTION__, __LINE__, -+ "device %s is not empty", argv[1]); -+ goto close; -+ } -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return -1; -+} -+ -+/** -+ * __err_msg - print a message to stderr. -+ * -+ * @test test name -+ * @func function name -+ * @line line number -+ * @fmt format string -+ */ -+void __err_msg(const char *test, const char *func, int line, -+ const char *fmt, ...) -+{ -+ va_list args; -+ -+ fprintf(stderr, "[%s] %s():%d: ", test, func, line); -+ va_start(args, fmt); -+ vfprintf(stderr, fmt, args); -+ fprintf(stderr, "\n"); -+ va_end(args); -+} -+ -+/** -+ * __failed - print function fail message. -+ * -+ * @test test name -+ * @func calling function name -+ * @line line number -+ * @failed failed function name -+ */ -+void __failed(const char *test, const char *func, int line, -+ const char *failed) -+{ -+ fprintf(stderr, "[%s] %s():%d: function %s() failed with error %d (%s)\n", -+ test, func, line, failed, errno, strerror(errno)); -+} -+ -+/** -+ * __check_volume - check volume information. -+ * -+ * @libubi libubi descriptor -+ * @dev_info UBI device description -+ * @test test name -+ * @func function name -+ * @line line number -+ * @vol_id ID of existing volume to check -+ * @req volume creation request to compare with -+ * -+ * This function checks if a volume created using @req request has exactly the -+ * requested characteristics. Returns 0 in case of success and %-1 in case of -+ * error. -+ */ -+int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info, -+ const char *test, const char *func, int line, int vol_id, -+ const struct ubi_mkvol_request *req) -+{ -+ int ret; -+ struct ubi_vol_info vol_info; -+ int leb_size; -+ long long rsvd_bytes; -+ -+ ret = ubi_get_vol_info1(libubi, dev_info->dev_num, vol_id, &vol_info); -+ if (ret) { -+ __failed(test, func, line, "ubi_get_vol_info"); -+ return -1; -+ } -+ -+ if (req->alignment != vol_info.alignment) { -+ __err_msg(test, func, line, -+ "bad alignment: requested %d, got %d", -+ req->alignment, vol_info.alignment); -+ return -1; -+ } -+ if (req->vol_type != vol_info.type) { -+ __err_msg(test, func, line, "bad type: requested %d, got %d", -+ req->vol_type, vol_info.type); -+ return -1; -+ } -+ if (strlen(req->name) != strlen(vol_info.name) || -+ strcmp(req->name, vol_info.name) != 0) { -+ __err_msg(test, func, line, -+ "bad name: requested \"%s\", got \"%s\"", -+ req->name, vol_info.name); -+ return -1; -+ } -+ if (vol_info.corrupted) { -+ __err_msg(test, func, line, "corrupted new volume"); -+ return -1; -+ } -+ -+ leb_size = dev_info->leb_size - (dev_info->leb_size % req->alignment); -+ if (leb_size != vol_info.leb_size) { -+ __err_msg(test, func, line, -+ "bad usable LEB size %d, should be %d", -+ vol_info.leb_size, leb_size); -+ return -1; -+ } -+ -+ rsvd_bytes = req->bytes; -+ if (rsvd_bytes % leb_size) -+ rsvd_bytes += leb_size - (rsvd_bytes % leb_size); -+ -+ if (rsvd_bytes != vol_info.rsvd_bytes) { -+ __err_msg(test, func, line, -+ "bad reserved bytes %lld, should be %lld", -+ vol_info.rsvd_bytes, rsvd_bytes); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+/** -+ * __check_vol_patt - check that volume contains certain data -+ * -+ * @libubi libubi descriptor -+ * @dev_info UBI device description -+ * @test test name -+ * @func function name -+ * @line line number -+ * @node volume character device node -+ * @byte data pattern to check -+ * -+ * This function returns %0 if the volume contains only @byte bytes, and %-1 if -+ * not. -+ */ -+int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info, -+ const char *test, const char *func, int line, -+ const char *node, uint8_t byte) -+{ -+ int ret, fd; -+ long long bytes = 0; -+ struct ubi_vol_info vol_info; -+ unsigned char buf[512]; -+ -+ fd = open(node, O_RDONLY); -+ if (fd == -1) { -+ __failed(test, func, line, "open"); -+ __err_msg(test, func, line, "cannot open \"%s\"\n", node); -+ return -1; -+ } -+ -+ ret = ubi_get_vol_info(libubi, node, &vol_info); -+ if (ret) { -+ __failed(test, func, line, "ubi_get_vol_info"); -+ goto close; -+ } -+ -+ while (bytes < vol_info.data_bytes) { -+ int i; -+ -+ memset(buf, ~byte, 512); -+ ret = read(fd, buf, 512); -+ if (ret == -1) { -+ __failed(test, func, line, "read"); -+ __err_msg(test, func, line, "bytes = %lld, ret = %d", -+ bytes, ret); -+ goto close; -+ } -+ -+ if (ret == 0 && bytes + ret < vol_info.data_bytes) { -+ __err_msg(test, func, line, -+ "EOF, but read only %lld bytes of %lld", -+ bytes + ret, vol_info.data_bytes); -+ goto close; -+ } -+ -+ for (i = 0; i < ret; i++) -+ if (buf[i] != byte) { -+ __err_msg(test, func, line, -+ "byte at %lld is not %#x but %#x", -+ bytes + i, byte, (int)buf[i]); -+ goto close; -+ } -+ -+ bytes += ret; -+ } -+ -+ close(fd); -+ return 0; -+ -+close: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * __update_vol_patt - update volume using a certain byte pattern -+ * -+ * @libubi libubi descriptor -+ * @dev_info UBI device description -+ * @test test name -+ * @func function name -+ * @line line number -+ * @node volume character device node -+ * @byte data pattern to check -+ * -+ * This function returns %0 in case of success, and %-1 if in case of failure. -+ */ -+int __update_vol_patt(libubi_t libubi, const char *test, const char *func, -+ int line, const char *node, long long bytes, uint8_t byte) -+{ -+ int ret, fd; -+ long long written = 0; -+ unsigned char buf[512]; -+ -+ fd = open(node, O_RDWR); -+ if (fd == -1) { -+ __failed(test, func, line, "open"); -+ __err_msg(test, func, line, "cannot open \"%s\"\n", node); -+ return -1; -+ } -+ -+ if (ubi_update_start(libubi, fd, bytes)) { -+ __failed(test, func, line, "ubi_update_start"); -+ __err_msg(test, func, line, "bytes = %lld", bytes); -+ goto close; -+ } -+ -+ memset(buf, byte, 512); -+ -+ while (written != bytes) { -+ ret = write(fd, buf, 512); -+ if (ret == -1) { -+ __failed(test, func, line, "write"); -+ __err_msg(test, func, line, "written = %lld, ret = %d", -+ written, ret); -+ goto close; -+ } -+ written += ret; -+ -+ if (written > bytes) { -+ __err_msg(test, func, line, "update length %lld bytes, " -+ "but %lld bytes are already written", -+ bytes, written); -+ goto close; -+ } -+ } -+ -+ close(fd); -+ return 0; -+ -+close: -+ close(fd); -+ return -1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/common.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/common.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,103 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * The stuff which is common for many tests. -+ */ -+ -+#ifndef __COMMON_H__ -+#define __COMMON_H__ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#define UBI_VOLUME_PATTERN "/dev/ubi%d_%d" -+#define MIN_AVAIL_EBS 5 -+#define PAGE_SIZE 4096 -+ -+#define min(a, b) ((a) < (b) ? (a) : (b)) -+ -+#define err_msg(fmt, ...) \ -+ __err_msg(TESTNAME, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) -+ -+#define failed(name) \ -+ __failed(TESTNAME, __FUNCTION__, __LINE__, name) -+ -+#define initial_check(argc, argv) \ -+ __initial_check(TESTNAME, argc, argv) -+ -+#define check_volume(vol_id, req) \ -+ __check_volume(libubi, &dev_info, TESTNAME, __FUNCTION__, \ -+ __LINE__, vol_id, req) -+ -+#define check_vol_patt(node, byte) \ -+ __check_vol_patt(libubi, &dev_info, TESTNAME, __FUNCTION__, __LINE__, \ -+ node, byte) -+ -+#define update_vol_patt(node, bytes, byte) \ -+ __update_vol_patt(libubi, TESTNAME, __FUNCTION__, __LINE__, \ -+ node, bytes, byte) -+ -+#define check_failed(ret, error, func, fmt, ...) ({ \ -+ int __ret; \ -+ \ -+ if (!ret) { \ -+ err_msg("%s() returned success but should have failed", func); \ -+ err_msg(fmt, ##__VA_ARGS__); \ -+ __ret = -1; \ -+ } \ -+ if (errno != (error)) { \ -+ err_msg("%s failed with error %d (%s), expected %d (%s)", \ -+ func, errno, strerror(errno), error, strerror(error)); \ -+ err_msg(fmt, ##__VA_ARGS__); \ -+ __ret = -1; \ -+ } \ -+ __ret = 0; \ -+}) -+ -+/* Alignments to test, @s is eraseblock size */ -+#define ALIGNMENTS(s) \ -+ {3, 5, 27, 666, 512, 1024, 2048, (s)/2-3, (s)/2-2, (s)/2-1, (s)/2+1, \ -+ (s)/2+2, (s)/2+3, (s)/3-3, (s)/3-2, (s)/3-1, (s)/3+1, (s)/3+2, \ -+ (s)/3+3, (s)/4-3, (s)/4-2, (s)/4-1, (s)/4+1, (s)/4+2, (s)/4+3, \ -+ (s)/5-3, (s)/5-2, (s)/5-1, (s)/5+1, (s)/5+2, (s)/5+3, (s)-17, (s)-9, \ -+ (s)-8, (s)-6, (s)-4, (s)-1, (s)}; -+ -+extern void __err_msg(const char *test, const char *func, int line, -+ const char *fmt, ...); -+void __failed(const char *test, const char *func, int line, -+ const char *failed); -+int __initial_check(const char *test, int argc, char * const argv[]); -+int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info, -+ const char *test, const char *func, int line, int vol_id, -+ const struct ubi_mkvol_request *req); -+int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info, -+ const char *test, const char *func, int line, -+ const char *node, uint8_t byte); -+int __update_vol_patt(libubi_t libubi, const char *test, const char *func, -+ int line, const char *node, long long bytes, -+ uint8_t byte); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__COMMON_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,783 @@ -+#define _LARGEFILE64_SOURCE -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "libubi.h" -+ -+struct erase_block_info; -+struct volume_info; -+struct ubi_device_info; -+ -+struct write_info -+{ -+ struct write_info *next; -+ struct erase_block_info *erase_block; -+ int offset_within_block; /* Offset within erase block */ -+ off64_t offset; /* Offset within volume */ -+ int size; -+ int random_seed; -+}; -+ -+struct erase_block_info -+{ -+ struct volume_info *volume; -+ int block_number; -+ off64_t offset; /* Offset within volume */ -+ off64_t top_of_data; -+ int touched; /* Have we done anything at all with this erase block */ -+ int erased; /* This erased block is currently erased */ -+ struct write_info *writes; -+}; -+ -+struct volume_fd -+{ -+ struct volume_fd *next; -+ struct volume_info *volume; -+ int fd; -+}; -+ -+struct volume_info -+{ -+ struct volume_info *next; -+ struct ubi_device_info *ubi_device; -+ struct volume_fd *fds; -+ struct erase_block_info *erase_blocks; -+ const char *device_file_name; -+ struct ubi_vol_info info; -+}; -+ -+struct ubi_device_info -+{ -+ struct volume_info *volumes; -+ const char *device_file_name; -+ struct ubi_dev_info info; -+}; -+ -+struct open_volume_fd -+{ -+ struct open_volume_fd *next; -+ struct volume_fd *vol_fd; -+}; -+ -+#define MAX_UBI_DEVICES 64 -+ -+static libubi_t libubi; -+ -+static struct ubi_info info; -+static struct ubi_device_info ubi_array[MAX_UBI_DEVICES]; -+ -+static uint64_t total_written = 0; -+static uint64_t total_space = 0; -+ -+static struct open_volume_fd *open_volumes; -+static size_t open_volume_count = 0; -+ -+static const char *ubi_module_load_string; -+ -+static unsigned char *write_buffer = NULL; -+static unsigned char *read_buffer = NULL; -+ -+static long long max_ebs_per_vol = 0; /* max number of ebs per vol (zero => no max) */ -+ -+static unsigned long next_seed = 1; -+ -+static unsigned get_next_seed() -+{ -+ next_seed = next_seed * 1103515245 + 12345; -+ return ((unsigned) (next_seed / 65536) % 32768); -+} -+ -+static void error_exit(const char *msg) -+{ -+ int eno = errno; -+ fprintf(stderr,"UBI Integrity Test Error: %s\n",msg); -+ if (eno) { -+ fprintf(stderr, "errno = %d\n", eno); -+ fprintf(stderr, "strerror = %s\n", strerror(eno)); -+ } -+ exit(1); -+} -+ -+static void *allocate(size_t n) -+{ -+ void *p = malloc(n); -+ if (!p) -+ error_exit("Memory allocation failure"); -+ memset(p, 0, n); -+ return p; -+} -+ -+static unsigned get_random_number(unsigned n) -+{ -+ uint64_t r, b; -+ -+ if (n < 1) -+ return 0; -+ r = rand(); -+ r *= n; -+ b = RAND_MAX; -+ b += 1; -+ r /= b; -+ return r; -+} -+ -+static struct volume_fd *open_volume(struct volume_info *vol) -+{ -+ struct volume_fd *s; -+ struct open_volume_fd *ofd; -+ int fd; -+ -+ if (vol->fds) { -+ /* If already open dup it */ -+ fd = dup(vol->fds->fd); -+ if (fd == -1) -+ error_exit("Failed to dup volume device file des"); -+ } else { -+ fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE); -+ if (fd == -1) -+ error_exit("Failed to open volume device file"); -+ } -+ s = allocate(sizeof(*s)); -+ s->fd = fd; -+ s->volume = vol; -+ s->next = vol->fds; -+ vol->fds = s; -+ /* Add to open volumes list */ -+ ofd = allocate(sizeof(*ofd)); -+ ofd->vol_fd = s; -+ ofd->next = open_volumes; -+ open_volumes = ofd; -+ open_volume_count += 1; -+ return 0; -+} -+ -+static void close_volume(struct volume_fd *vol_fd) -+{ -+ struct volume_fd *vfd, *vfd_last; -+ struct open_volume_fd *ofd, *ofd_last; -+ int fd = vol_fd->fd; -+ -+ /* Remove from open volumes list */ -+ ofd_last = NULL; -+ ofd = open_volumes; -+ while (ofd) { -+ if (ofd->vol_fd == vol_fd) { -+ if (ofd_last) -+ ofd_last->next = ofd->next; -+ else -+ open_volumes = ofd->next; -+ free(ofd); -+ open_volume_count -= 1; -+ break; -+ } -+ ofd_last = ofd; -+ ofd = ofd->next; -+ } -+ /* Remove from volume fd list */ -+ vfd_last = NULL; -+ vfd = vol_fd->volume->fds; -+ while (vfd) { -+ if (vfd == vol_fd) { -+ if (vfd_last) -+ vfd_last->next = vfd->next; -+ else -+ vol_fd->volume->fds = vfd->next; -+ free(vfd); -+ break; -+ } -+ vfd_last = vfd; -+ vfd = vfd->next; -+ } -+ /* Close volume device file */ -+ if (close(fd) == -1) -+ error_exit("Failed to close volume file descriptor"); -+} -+ -+static void set_random_data(unsigned seed, unsigned char *buf, int size) -+{ -+ int i; -+ unsigned r; -+ -+ r = rand(); -+ srand(seed); -+ for (i = 0; i < size; ++i) -+ buf[i] = rand(); -+ srand(r); -+} -+ -+#if 0 -+static void print_write_info(struct write_info *w) -+{ -+ printf("Offset: %lld Size:%d Seed:%u\n", w->offset, w->size, w->random_seed); -+ fflush(stdout); -+} -+#endif -+ -+static void check_erase_block(struct erase_block_info *erase_block, int fd) -+{ -+ struct write_info *w; -+ off64_t gap_end; -+ int leb_size = erase_block->volume->info.leb_size; -+ ssize_t bytes_read; -+ -+ w = erase_block->writes; -+ gap_end = erase_block->offset + leb_size; -+ while (w) { -+ if (w->offset + w->size < gap_end) { -+ /* There is a gap. Check all 0xff */ -+ off64_t gap_start = w->offset + w->size; -+ size_t size = gap_end - gap_start; -+ if (lseek64(fd, gap_start, SEEK_SET) != gap_start) -+ error_exit("lseek64 failed"); -+ memset(read_buffer, 0 , size); -+ errno = 0; -+ bytes_read = read(fd, read_buffer, size); -+ if (bytes_read != size) -+ error_exit("read failed in gap"); -+ while (size) -+ if (read_buffer[--size] != 0xff) { -+ fprintf(stderr, "block no. = %d\n" , erase_block->block_number); -+ fprintf(stderr, "offset = %lld\n" , (long long) gap_start); -+ fprintf(stderr, "size = %ld\n" , (long) bytes_read); -+ error_exit("verify 0xff failed"); -+ } -+ } -+ if (lseek64(fd, w->offset, SEEK_SET) != w->offset) -+ error_exit("lseek64 failed"); -+ memset(read_buffer, 0 , w->size); -+ errno = 0; -+ bytes_read = read(fd, read_buffer, w->size); -+ if (bytes_read != w->size) { -+ fprintf(stderr, "offset = %lld\n" , (long long) w->offset); -+ fprintf(stderr, "size = %ld\n" , (long) w->size); -+ fprintf(stderr, "bytes_read = %ld\n" , (long) bytes_read); -+ error_exit("read failed"); -+ } -+ set_random_data(w->random_seed, write_buffer, w->size); -+ if (memcmp(read_buffer, write_buffer, w->size)) -+ error_exit("verify failed"); -+ gap_end = w->offset; -+ w = w->next; -+ } -+ if (gap_end > erase_block->offset) { -+ /* Check all 0xff */ -+ off64_t gap_start = erase_block->offset; -+ size_t size = gap_end - gap_start; -+ if (lseek64(fd, gap_start, SEEK_SET) != gap_start) -+ error_exit("lseek64 failed"); -+ memset(read_buffer, 0 , size); -+ errno = 0; -+ bytes_read = read(fd, read_buffer, size); -+ if (bytes_read != size) -+ error_exit("read failed in gap"); -+ while (size) -+ if (read_buffer[--size] != 0xff) { -+ fprintf(stderr, "block no. = %d\n" , erase_block->block_number); -+ fprintf(stderr, "offset = %lld\n" , (long long) gap_start); -+ fprintf(stderr, "size = %ld\n" , (long) bytes_read); -+ error_exit("verify 0xff failed!"); -+ } -+ } -+} -+ -+static int write_to_erase_block(struct erase_block_info *erase_block, int fd) -+{ -+ int page_size = erase_block->volume->ubi_device->info.min_io_size; -+ int leb_size = erase_block->volume->info.leb_size; -+ int next_offset = 0; -+ int space, size; -+ off64_t offset; -+ unsigned seed; -+ struct write_info *w; -+ -+ if (erase_block->writes) -+ next_offset = erase_block->writes->offset_within_block + erase_block->writes->size; -+ space = leb_size - next_offset; -+ if (space <= 0) -+ return 0; /* No space */ -+ if (!get_random_number(10)) { -+ /* 1 time in 10 leave a gap */ -+ next_offset += get_random_number(space); -+ next_offset = (next_offset / page_size) * page_size; -+ space = leb_size - next_offset; -+ } -+ if (get_random_number(2)) -+ size = 1 * page_size; -+ else if (get_random_number(2)) -+ size = 2 * page_size; -+ else if (get_random_number(2)) -+ size = 3 * page_size; -+ else if (get_random_number(2)) -+ size = 4 * page_size; -+ else { -+ if (get_random_number(4)) -+ size = get_random_number(space); -+ else -+ size = space; -+ size = (size / page_size) * page_size; -+ } -+ if (size == 0 || size > space) -+ size = page_size; -+ if (next_offset + size > leb_size) -+ error_exit("internal error"); -+ offset = erase_block->offset + next_offset; -+ if (offset < erase_block->top_of_data) -+ error_exit("internal error!"); -+ if (lseek64(fd, offset, SEEK_SET) != offset) -+ error_exit("lseek64 failed"); -+ /* Do write */ -+ seed = get_next_seed(); -+ if (!seed) -+ seed = 1; -+ set_random_data(seed, write_buffer, size); -+ if (write(fd, write_buffer, size) != size) -+ error_exit("write failed"); -+ erase_block->top_of_data = offset + size; -+ /* Make write info and add to eb */ -+ w = allocate(sizeof(*w)); -+ w->offset_within_block = next_offset; -+ w->offset = offset; -+ w->size = size; -+ w->random_seed = seed; -+ w->next = erase_block->writes; -+ erase_block->writes = w; -+ erase_block->touched = 1; -+ erase_block->erased = 0; -+ total_written += size; -+ return 1; -+} -+ -+static void erase_erase_block(struct erase_block_info *erase_block, int fd) -+{ -+ struct write_info *w; -+ uint32_t eb_no; -+ int res; -+ -+ eb_no = erase_block->block_number; -+ res = ioctl(fd, UBI_IOCEBER, &eb_no); -+ if (res) -+ error_exit("Failed to erase an erase block"); -+ /* Remove writes from this eb */ -+ while (erase_block->writes) { -+ w = erase_block->writes; -+ erase_block->writes = erase_block->writes->next; -+ free(w); -+ } -+ erase_block->erased = 1; -+ erase_block->touched = 1; -+ erase_block->top_of_data = erase_block->offset; -+} -+ -+static void operate_on_erase_block(struct erase_block_info *erase_block, int fd) -+{ -+ /* -+ Possible operations: -+ read from it and verify -+ write to it -+ erase it -+ */ -+ int work_done = 1; -+ static int no_work_done_count = 0; -+ -+ if (!get_random_number(10) && no_work_done_count <= 5) { -+ check_erase_block(erase_block, fd); -+ work_done = 0; -+ } else if (get_random_number(100)) { -+ if (!write_to_erase_block(erase_block, fd)) { -+ /* The erase block was full */ -+ if (get_random_number(2) || no_work_done_count > 5) -+ erase_erase_block(erase_block, fd); -+ else -+ work_done = 0; -+ } -+ } else -+ erase_erase_block(erase_block, fd); -+ if (work_done) -+ no_work_done_count = 0; -+ else -+ no_work_done_count += 1; -+} -+ -+static void operate_on_open_volume(struct volume_fd *vol_fd) -+{ -+ /* -+ Possible operations: -+ operate on an erase block -+ close volume -+ */ -+ if (get_random_number(100) == 0) -+ close_volume(vol_fd); -+ else { -+ /* Pick an erase block at random */ -+ int eb_no = get_random_number(vol_fd->volume->info.rsvd_lebs); -+ operate_on_erase_block(&vol_fd->volume->erase_blocks[eb_no], vol_fd->fd); -+ } -+} -+ -+static void operate_on_volume(struct volume_info *vol) -+{ -+ /* -+ Possible operations: -+ open it -+ resize it (must close fd's first) <- TODO -+ delete it (must close fd's first) <- TODO -+ */ -+ open_volume(vol); -+} -+ -+static int ubi_major(const char *device_file_name) -+{ -+ struct stat buf; -+ static int maj = 0; -+ -+ if (maj) -+ return maj; -+ if (stat(device_file_name, &buf) == -1) -+ error_exit("Failed to stat ubi device file"); -+ maj = major(buf.st_rdev); -+ return maj; -+} -+ -+static void operate_on_ubi_device(struct ubi_device_info *ubi_device) -+{ -+ /* -+ TODO: -+ Possible operations: -+ create a new volume -+ operate on existing volume -+ */ -+ /* -+ Simplified operation (i.e. only have 1 volume): -+ If there are no volumes create 1 volumne -+ Then operate on the volume -+ */ -+ if (ubi_device->info.vol_count == 0) { -+ /* Create the one-and-only volume we will use */ -+ char dev_name[1024]; -+ int i, n, maj, fd; -+ struct volume_info *s; -+ struct ubi_mkvol_request req; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; /* TODO: What is this? */ -+ req.bytes = ubi_device->info.leb_size * max_ebs_per_vol; -+ if (req.bytes == 0 || req.bytes > ubi_device->info.avail_bytes) -+ req.bytes = ubi_device->info.avail_bytes; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = "integ-test-vol"; -+ if (ubi_mkvol(libubi, ubi_device->device_file_name, &req)) -+ error_exit("ubi_mkvol failed"); -+ s = allocate(sizeof(*s)); -+ s->ubi_device = ubi_device; -+ if (ubi_get_vol_info1(libubi, ubi_device->info.dev_num, req.vol_id, &s->info)) -+ error_exit("ubi_get_vol_info failed"); -+ n = s->info.rsvd_lebs; -+ s->erase_blocks = allocate(sizeof(struct erase_block_info) * n); -+ for (i = 0; i < n; ++i) { -+ s->erase_blocks[i].volume = s; -+ s->erase_blocks[i].block_number = i; -+ s->erase_blocks[i].offset = i * (off64_t) s->info.leb_size; -+ s->erase_blocks[i].top_of_data = s->erase_blocks[i].offset; -+ } -+ /* FIXME: Correctly get device file name */ -+ sprintf(dev_name, "%s_%d", ubi_device->device_file_name, req.vol_id); -+ s->device_file_name = strdup(dev_name); -+ ubi_device->volumes = s; -+ ubi_device->info.vol_count += 1; -+ sleep(1); -+ fd = open(s->device_file_name, O_RDONLY); -+ if (fd == -1) { -+ /* FIXME: Correctly make node */ -+ maj = ubi_major(ubi_device->device_file_name); -+ sprintf(dev_name, "mknod %s c %d %d", s->device_file_name, maj, req.vol_id + 1); -+ system(dev_name); -+ } else if (close(fd) == -1) -+ error_exit("Failed to close volume device file"); -+ } -+ operate_on_volume(ubi_device->volumes); -+} -+ -+static void do_an_operation(void) -+{ -+ int too_few = (open_volume_count < info.dev_count * 3); -+ int too_many = (open_volume_count > info.dev_count * 5); -+ -+ if (too_many || (!too_few && get_random_number(1000) > 0)) { -+ /* Operate on an open volume */ -+ size_t pos; -+ struct open_volume_fd *ofd; -+ pos = get_random_number(open_volume_count); -+ for (ofd = open_volumes; pos && ofd && ofd->next; --pos) -+ ofd = ofd->next; -+ operate_on_open_volume(ofd->vol_fd); -+ } else if (info.dev_count > 0) { -+ /* Operate on a ubi device */ -+ size_t ubi_pos = 0; -+ if (info.dev_count > 1) -+ ubi_pos = get_random_number(info.dev_count - 1); -+ operate_on_ubi_device(&ubi_array[ubi_pos]); -+ } else -+ error_exit("Internal error"); -+} -+ -+static void get_ubi_devices_info(void) -+{ -+ int i, ubi_pos = 0; -+ char dev_name[1024]; -+ size_t buf_size = 1024 * 128; -+ -+ if (ubi_get_info(libubi, &info)) -+ error_exit("ubi_get_info failed"); -+ if (info.dev_count > MAX_UBI_DEVICES) -+ error_exit("Too many ubi devices"); -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; ++i) { -+ struct ubi_device_info *s; -+ s = &ubi_array[ubi_pos++]; -+ if (ubi_get_dev_info1(libubi, i, &s->info)) -+ error_exit("ubi_get_dev_info1 failed"); -+ if (s->info.vol_count) -+ error_exit("There are existing volumes"); -+ /* FIXME: Correctly get device file name */ -+ sprintf(dev_name, "/dev/ubi%d", i); -+ s->device_file_name = strdup(dev_name); -+ if (buf_size < s->info.leb_size) -+ buf_size = s->info.leb_size; -+ if (max_ebs_per_vol && s->info.leb_size * max_ebs_per_vol < s->info.avail_bytes) -+ total_space += s->info.leb_size * max_ebs_per_vol; -+ else -+ total_space += s->info.avail_bytes; -+ } -+ write_buffer = allocate(buf_size); -+ read_buffer = allocate(buf_size); -+} -+ -+static void load_ubi(void) -+{ -+ system("rmmod ubi"); -+ if (system(ubi_module_load_string) != 0) -+ error_exit("Failed to load UBI module"); -+ sleep(1); -+} -+ -+static void do_some_operations(void) -+{ -+ unsigned i = 0; -+ total_written = 0; -+ printf("Total space: %llu\n", (unsigned long long) total_space); -+ while (total_written < total_space * 3) { -+ do_an_operation(); -+ if (i++ % 10000 == 0) -+ printf("Total written: %llu\n", (unsigned long long) total_written); -+ } -+ printf("Total written: %llu\n", (unsigned long long) total_written); -+} -+ -+static void reload_ubi(void) -+{ -+ /* Remove module */ -+ if (system("rmmod ubi") != 0) -+ error_exit("Failed to remove UBI module"); -+ /* Install module */ -+ if (system(ubi_module_load_string) != 0) -+ error_exit("Failed to load UBI module"); -+ sleep(1); -+} -+ -+static void check_volume(struct volume_info *vol) -+{ -+ struct erase_block_info *eb = vol->erase_blocks; -+ int pos; -+ int fd; -+ -+ fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE); -+ if (fd == -1) -+ error_exit("Failed to open volume device file"); -+ for (pos = 0; pos < vol->info.rsvd_lebs; ++pos) -+ check_erase_block(eb++, fd); -+ if (close(fd) == -1) -+ error_exit("Failed to close volume device file"); -+} -+ -+static void check_ubi_device(struct ubi_device_info *ubi_device) -+{ -+ struct volume_info *vol; -+ -+ vol = ubi_device->volumes; -+ while (vol) { -+ check_volume(vol); -+ vol = vol->next; -+ } -+} -+ -+static void check_ubi(void) -+{ -+ int i; -+ -+ for (i = 0; i < info.dev_count; ++i) -+ check_ubi_device(&ubi_array[i]); -+} -+ -+static int is_all_digits(const char *s) -+{ -+ const char *digits = "0123456789"; -+ if (!s || !*s) -+ return 0; -+ for (;*s;++s) -+ if (!strchr(digits,*s)) -+ return 0; -+ return 1; -+} -+ -+static int get_short_arg(int *pos,const char *name,long long *result,int argc,char *argv[]) -+{ -+ const char *p = NULL; -+ int i = *pos; -+ size_t n = strlen(name); -+ -+ if (strlen(argv[i]) > n) -+ p = argv[i] + n; -+ else if (++i < argc) -+ p = argv[i]; -+ if (!is_all_digits(p)) -+ return 1; -+ *result = atoll(p); -+ *pos = i; -+ return 0; -+} -+ -+static int get_long_arg(int *pos,const char *name,long long *result,int argc,char *argv[]) -+{ -+ const char *p = NULL; -+ int i = *pos; -+ size_t n = strlen(name); -+ -+ if (strlen(argv[i]) > n) -+ p = argv[i] + n; -+ else if (++i < argc) -+ p = argv[i]; -+ if (p && *p == '=') { -+ p += 1; -+ if (!*p && ++i < argc) -+ p = argv[i]; -+ } -+ if (!is_all_digits(p)) -+ return 1; -+ *result = atoll(p); -+ *pos = i; -+ return 0; -+} -+ -+static int remove_all_volumes(void) -+{ -+ int i; -+ -+ for (i = 0; i < info.dev_count; ++i) { -+ struct ubi_device_info *ubi_device = &ubi_array[i]; -+ struct volume_info *vol; -+ vol = ubi_device->volumes; -+ while (vol) { -+ int res = ubi_rmvol(libubi, -+ ubi_device->device_file_name, -+ vol->info.vol_id); -+ if (res) -+ return res; -+ vol = vol->next; -+ } -+ } -+ return 0; -+} -+ -+int main(int argc,char *argv[]) -+{ -+ int i; -+ long long r, repeat = 1; -+ int initial_seed = 1, args_ok = 1; -+ -+ printf("UBI Integrity Test\n"); -+ -+ /* Get arguments */ -+ ubi_module_load_string = 0; -+ for (i = 1; i < argc; ++i) { -+ if (strncmp(argv[i], "-h", 2) == 0) -+ args_ok = 0; -+ else if (strncmp(argv[i], "--help", 6) == 0) -+ args_ok = 0; -+ else if (strncmp(argv[i], "-n", 2) == 0) { -+ if (get_short_arg(&i, "-n", &repeat, argc, argv)) -+ args_ok = 0; -+ } else if (strncmp(argv[i], "--repeat", 8) == 0) { -+ if (get_long_arg(&i, "--repeat", &repeat, argc, argv)) -+ args_ok = 0; -+ } else if (strncmp(argv[i], "-m", 2) == 0) { -+ if (get_short_arg(&i,"-m", &max_ebs_per_vol, argc, argv)) -+ args_ok = 0; -+ } else if (strncmp(argv[i], "--maxebs", 8) == 0) { -+ if (get_long_arg(&i, "--maxebs", &max_ebs_per_vol, argc, argv)) -+ args_ok = 0; -+ } else if (!ubi_module_load_string) -+ ubi_module_load_string = argv[i]; -+ else -+ args_ok = 0; -+ } -+ if (!args_ok || !ubi_module_load_string) { -+ fprintf(stderr, "Usage is: ubi_integ [] \n"); -+ fprintf(stderr, " Options: \n"); -+ fprintf(stderr, " -h, --help Help\n"); -+ fprintf(stderr, " -n arg, --repeat=arg Repeat test arg times\n"); -+ fprintf(stderr, " -m arg, --maxebs=arg Max no. of erase blocks\n"); -+ return 1; -+ } -+ -+ initial_seed = getpid(); -+ printf("Initial seed = %u\n", (unsigned) initial_seed); -+ next_seed = initial_seed; -+ srand(initial_seed); -+ load_ubi(); -+ -+ libubi = libubi_open(); -+ if (!libubi) -+ error_exit("Failed to open libubi"); -+ -+ get_ubi_devices_info(); -+ -+ r = 0; -+ while (repeat == 0 || r++ < repeat) { -+ printf("Cycle %lld\n", r); -+ do_some_operations(); -+ -+ /* Close all volumes */ -+ while (open_volumes) -+ close_volume(open_volumes->vol_fd); -+ -+ check_ubi(); -+ -+ libubi_close(libubi); -+ -+ reload_ubi(); -+ -+ libubi = libubi_open(); -+ if (!libubi) -+ error_exit("Failed to open libubi"); -+ -+ check_ubi(); -+ } -+ -+ if (remove_all_volumes()) -+ error_exit("Failed to remove all volumes"); -+ -+ libubi_close(libubi); -+ -+ printf("UBI Integrity Test completed ok\n"); -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,179 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test basic UBI volume I/O capabilities. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "io_basic" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+ -+/** -+ * test_basic - check basic volume read and update capabilities. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_basic(int type) -+{ -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":test_basic()"; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = type; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); -+ -+ /* Make sure newly created volume contains only 0xFF bytes */ -+ if (check_vol_patt(vol_node, 0xFF)) -+ goto remove; -+ -+ /* Write 0xA5 bytes to the volume */ -+ if (update_vol_patt(vol_node, dev_info.avail_bytes, 0xA5)) -+ goto remove; -+ if (check_vol_patt(vol_node, 0xA5)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+/** -+ * test_aligned - test volume alignment feature. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_aligned(int type) -+{ -+ int i, ebsz; -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":test_aligned()"; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ int alignments[] = ALIGNMENTS(dev_info.leb_size); -+ -+ req.vol_type = type; -+ req.name = name; -+ -+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ -+ req.alignment = alignments[i]; -+ req.alignment -= req.alignment % dev_info.min_io_size; -+ if (req.alignment == 0) -+ req.alignment = dev_info.min_io_size; -+ -+ ebsz = dev_info.leb_size - dev_info.leb_size % req.alignment; -+ req.bytes = MIN_AVAIL_EBS * ebsz; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); -+ -+ /* Make sure newly created volume contains only 0xFF bytes */ -+ if (check_vol_patt(vol_node, 0xFF)) -+ goto remove; -+ -+ /* Write 0xA5 bytes to the volume */ -+ if (update_vol_patt(vol_node, req.bytes, 0xA5)) -+ goto remove; -+ if (check_vol_patt(vol_node, 0xA5)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (test_basic(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_basic(UBI_STATIC_VOLUME)) -+ goto close; -+ if (test_aligned(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_aligned(UBI_STATIC_VOLUME)) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,249 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * This test does a lot of I/O to volumes in parallel. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "io_paral" -+#include "common.h" -+ -+#define THREADS_NUM 3 -+#define ITERATIONS 10 -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+static int iterations = ITERATIONS; -+int total_bytes; -+ -+static long long memory_limit(void) -+{ -+ long long result = 0; -+ FILE *f; -+ -+ f = fopen("/proc/meminfo", "r"); -+ if (!f) -+ return 0; -+ fscanf(f, "%*s %lld", &result); -+ fclose(f); -+ return result * 1024 / 4; -+} -+ -+/** -+ * the_thread - the testing thread. -+ * -+ * @ptr thread number -+ */ -+static void * the_thread(void *ptr) -+{ -+ int fd, iter = iterations, vol_id = (int)ptr; -+ unsigned char *wbuf, *rbuf; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ -+ wbuf = malloc(total_bytes); -+ rbuf = malloc(total_bytes); -+ if (!wbuf || !rbuf) { -+ failed("malloc"); -+ goto free; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, vol_id); -+ -+ while (iter--) { -+ int i, ret, written = 0, rd = 0; -+ int bytes = (random() % (total_bytes - 1)) + 1; -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ goto free; -+ } -+ -+ for (i = 0; i < bytes; i++) -+ wbuf[i] = random() % 255; -+ memset(rbuf, '\0', bytes); -+ -+ do { -+ ret = ubi_update_start(libubi, fd, bytes); -+ if (ret && errno != EBUSY) { -+ failed("ubi_update_start"); -+ err_msg("vol_id %d", vol_id); -+ goto close; -+ } -+ } while (ret); -+ -+ while (written < bytes) { -+ int to_write = random() % (bytes - written); -+ -+ if (to_write == 0) -+ to_write = 1; -+ -+ ret = write(fd, wbuf, to_write); -+ if (ret != to_write) { -+ failed("write"); -+ err_msg("failed to write %d bytes at offset %d " -+ "of volume %d", to_write, written, -+ vol_id); -+ err_msg("update: %d bytes", bytes); -+ goto close; -+ } -+ -+ written += to_write; -+ } -+ -+ close(fd); -+ -+ fd = open(vol_node, O_RDONLY); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ goto free; -+ } -+ -+ /* read data back and check */ -+ while (rd < bytes) { -+ int to_read = random() % (bytes - rd); -+ -+ if (to_read == 0) -+ to_read = 1; -+ -+ ret = read(fd, rbuf, to_read); -+ if (ret != to_read) { -+ failed("read"); -+ err_msg("failed to read %d bytes at offset %d " -+ "of volume %d", to_read, rd, vol_id); -+ goto close; -+ } -+ -+ rd += to_read; -+ } -+ -+ close(fd); -+ -+ } -+ -+ free(wbuf); -+ free(rbuf); -+ return NULL; -+ -+close: -+ close(fd); -+free: -+ free(wbuf); -+ free(rbuf); -+ return NULL; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int i, ret; -+ pthread_t threads[THREADS_NUM]; -+ struct ubi_mkvol_request req; -+ long long mem_limit; -+ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ req.alignment = 1; -+ mem_limit = memory_limit(); -+ if (mem_limit && mem_limit < dev_info.avail_bytes) -+ total_bytes = req.bytes = -+ (mem_limit / dev_info.leb_size / THREADS_NUM) -+ * dev_info.leb_size; -+ else -+ total_bytes = req.bytes = -+ ((dev_info.avail_lebs - 3) / THREADS_NUM) -+ * dev_info.leb_size; -+ for (i = 0; i < THREADS_NUM; i++) { -+ char name[100]; -+ -+ req.vol_id = i; -+ sprintf(name, TESTNAME":%d", i); -+ req.name = name; -+ req.vol_type = (i & 1) ? UBI_STATIC_VOLUME : UBI_DYNAMIC_VOLUME; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ goto remove; -+ } -+ } -+ -+ /* Create one volume with static data to make WL work more */ -+ req.vol_id = THREADS_NUM; -+ req.name = TESTNAME ":static"; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.bytes = 3*dev_info.leb_size; -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ goto remove; -+ } -+ -+ for (i = 0; i < THREADS_NUM; i++) { -+ ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i); -+ if (ret) { -+ failed("pthread_create"); -+ goto remove; -+ } -+ } -+ -+ for (i = 0; i < THREADS_NUM; i++) -+ pthread_join(threads[i], NULL); -+ -+ for (i = 0; i <= THREADS_NUM; i++) { -+ if (ubi_rmvol(libubi, node, i)) { -+ failed("ubi_rmvol"); -+ goto remove; -+ } -+ } -+ -+ libubi_close(libubi); -+ return 0; -+ -+remove: -+ for (i = 0; i <= THREADS_NUM; i++) -+ ubi_rmvol(libubi, node, i); -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,388 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test UBI volume read. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "io_basic" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+static int fd; -+ -+/* Data lengthes to test, @io - minimal I/O unit size, @s - eraseblock size */ -+#define LENGTHES(io, s) \ -+ {1, (io), (io)+1, 2*(io), 3*(io)-1, 3*(io), \ -+ PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io), \ -+ (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s), \ -+ 2*(s)+(io), 3*(s), 3*(s)+(io)}; -+ -+/* -+ * Offsets to test, @io - minimal I/O unit size, @s - eraseblock size, @sz - -+ * volume size. -+ */ -+#define OFFSETS(io, s, sz) \ -+ {0, (io)-1, (io), (io)+1, 2*(io)-1, 2*(io), 3*(io)-1, 3*(io), \ -+ PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io), \ -+ (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s), \ -+ 2*(s)+(io), 3*(s), (sz)-(s)-1, (sz)-(io)-1, (sz)-PAGE_SIZE-1}; -+ -+/** -+ * test_static - test static volume-specific features. -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_static(void) -+{ -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":io_basic()"; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ struct ubi_vol_info vol_info; -+ int fd, ret; -+ char buf[20]; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = UBI_STATIC_VOLUME; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ goto remove; -+ } -+ -+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { -+ failed("ubi_get_vol_info"); -+ goto close; -+ } -+ -+ /* Make sure new static volume contains no data */ -+ if (vol_info.data_bytes != 0) { -+ err_msg("data_bytes = %lld, not zero", vol_info.data_bytes); -+ goto close; -+ } -+ -+ /* Ensure read returns EOF */ -+ ret = read(fd, buf, 1); -+ if (ret < 0) { -+ failed("read"); -+ goto close; -+ } -+ if (ret != 0) { -+ err_msg("read data from free static volume"); -+ goto close; -+ } -+ -+ if (ubi_update_start(libubi, fd, 10)) { -+ failed("ubi_update_start"); -+ goto close; -+ } -+ -+ ret = write(fd, buf, 10); -+ if (ret < 0) { -+ failed("write"); -+ goto close; -+ } -+ if (ret != 10) { -+ err_msg("written %d bytes", ret); -+ goto close; -+ } -+ -+ if (lseek(fd, 0, SEEK_SET) != 0) { -+ failed("seek"); -+ goto close; -+ } -+ ret = read(fd, buf, 20); -+ if (ret < 0) { -+ failed("read"); -+ goto close; -+ } -+ if (ret != 10) { -+ err_msg("read %d bytes", ret); -+ goto close; -+ } -+ -+ close(fd); -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ return 0; -+ -+close: -+ close(fd); -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+/* -+ * A helper function for test_read2(). -+ */ -+static int test_read3(const struct ubi_vol_info *vol_info, int len, off_t off) -+{ -+ int i, len1; -+ unsigned char ck_buf[len], buf[len]; -+ off_t new_off; -+ -+ if (off + len > vol_info->data_bytes) -+ len1 = vol_info->data_bytes - off; -+ else -+ len1 = len; -+ -+ if (lseek(fd, off, SEEK_SET) != off) { -+ failed("seek"); -+ err_msg("len = %d", len); -+ return -1; -+ } -+ if (read(fd, buf, len) != len1) { -+ failed("read"); -+ err_msg("len = %d", len); -+ return -1; -+ } -+ -+ new_off = lseek(fd, 0, SEEK_CUR); -+ if (new_off != off + len1) { -+ if (new_off == -1) -+ failed("lseek"); -+ else -+ err_msg("read %d bytes from %lld, but resulting " -+ "offset is %lld", len1, (long long) off, (long long) new_off); -+ return -1; -+ } -+ -+ for (i = 0; i < len1; i++) -+ ck_buf[i] = (unsigned char)(off + i); -+ -+ if (memcmp(buf, ck_buf, len1)) { -+ err_msg("incorrect data read from offset %lld", -+ (long long)off); -+ err_msg("len = %d", len); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+/* -+ * A helper function for test_read1(). -+ */ -+static int test_read2(const struct ubi_vol_info *vol_info, int len) -+{ -+ int i; -+ off_t offsets[] = OFFSETS(dev_info.min_io_size, vol_info->leb_size, -+ vol_info->data_bytes); -+ -+ for (i = 0; i < sizeof(offsets)/sizeof(off_t); i++) { -+ if (test_read3(vol_info, len, offsets[i])) { -+ err_msg("offset = %d", offsets[i]); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * A helper function for test_read(). -+ */ -+static int test_read1(struct ubi_vol_info *vol_info) -+{ -+ int i, written = 0; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ int lengthes[] = LENGTHES(dev_info.min_io_size, vol_info->leb_size); -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ vol_info->vol_id); -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ return -1; -+ } -+ -+ /* Write some pattern to the volume */ -+ if (ubi_update_start(libubi, fd, vol_info->rsvd_bytes)) { -+ failed("ubi_update_start"); -+ err_msg("bytes = %lld", vol_info->rsvd_bytes); -+ goto close; -+ } -+ -+ while (written < vol_info->rsvd_bytes) { -+ int i, ret; -+ unsigned char buf[512]; -+ -+ for (i = 0; i < 512; i++) -+ buf[i] = (unsigned char)(written + i); -+ -+ ret = write(fd, buf, 512); -+ if (ret == -1) { -+ failed("write"); -+ err_msg("written = %d, ret = %d", written, ret); -+ goto close; -+ } -+ written += ret; -+ } -+ -+ close(fd); -+ -+ if (ubi_get_vol_info(libubi, vol_node, vol_info)) { -+ failed("ubi_get_vol_info"); -+ return -1; -+ } -+ -+ fd = open(vol_node, O_RDONLY); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ return -1; -+ } -+ -+ for (i = 0; i < sizeof(lengthes)/sizeof(int); i++) { -+ if (test_read2(vol_info, lengthes[i])) { -+ err_msg("length = %d", lengthes[i]); -+ goto close; -+ } -+ } -+ -+ close(fd); -+ return 0; -+ -+close: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * test_read - test UBI volume reading from different offsets. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_read(int type) -+{ -+ const char *name = TESTNAME ":test_read()"; -+ int alignments[] = ALIGNMENTS(dev_info.leb_size); -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ struct ubi_mkvol_request req; -+ int i; -+ -+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { -+ int leb_size; -+ struct ubi_vol_info vol_info; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.vol_type = type; -+ req.name = name; -+ -+ req.alignment = alignments[i]; -+ req.alignment -= req.alignment % dev_info.min_io_size; -+ if (req.alignment == 0) -+ req.alignment = dev_info.min_io_size; -+ -+ leb_size = dev_info.leb_size - dev_info.leb_size % req.alignment; -+ req.bytes = MIN_AVAIL_EBS * leb_size; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ req.vol_id); -+ -+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { -+ failed("ubi_get_vol_info"); -+ goto remove; -+ } -+ -+ if (test_read1(&vol_info)) { -+ err_msg("alignment = %d", req.alignment); -+ goto remove; -+ } -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (test_static()) -+ goto close; -+ if (test_read(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_read(UBI_STATIC_VOLUME)) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,298 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test UBI volume update and atomic LEB change -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#define TESTNAME "io_update" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+ -+#define SEQUENCES(io, s) { \ -+ {3*(s)-(io)-1, 1}, \ -+ {512}, \ -+ {666}, \ -+ {2048}, \ -+ {(io), (io), PAGE_SIZE}, \ -+ {(io)+1, (io)+1, PAGE_SIZE}, \ -+ {PAGE_SIZE}, \ -+ {PAGE_SIZE-1}, \ -+ {PAGE_SIZE+(io)}, \ -+ {(s)}, \ -+ {(s)-1}, \ -+ {(s)+1}, \ -+ {(io), (s)+1}, \ -+ {(s)+(io), PAGE_SIZE}, \ -+ {2*(s), PAGE_SIZE}, \ -+ {PAGE_SIZE, 2*(s), 1}, \ -+ {PAGE_SIZE, 2*(s)}, \ -+ {2*(s)-1, 2*(s)-1}, \ -+ {3*(s), PAGE_SIZE + 1}, \ -+ {1, PAGE_SIZE}, \ -+ {(io), (s)} \ -+} -+ -+#define SEQ_SZ 21 -+ -+/* -+ * test_update1 - helper function for test_update(). -+ */ -+static int test_update1(struct ubi_vol_info *vol_info, int leb_change) -+{ -+ long long total_len = leb_change ? vol_info->leb_size -+ : vol_info->rsvd_bytes; -+ int sequences[SEQ_SZ][3] = SEQUENCES(dev_info.min_io_size, -+ leb_change ? dev_info.min_io_size * 2 -+ : vol_info->leb_size); -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ unsigned char buf[total_len]; -+ int fd, i, j; -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ vol_info->vol_id); -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ return -1; -+ } -+ -+ for (i = 0; i < SEQ_SZ; i++) { -+ int ret, stop = 0, len = 0; -+ off_t off = 0; -+ long long test_len; -+ unsigned char buf1[total_len]; -+ -+ /* -+ * test_len is LEB size (if we test atomic LEB change) or -+ * volume size (if we test update). For better test coverage, -+ * use a little smaller LEB change/update length. -+ */ -+ test_len = total_len - (rand() % (total_len / 10)); -+ -+ if (leb_change) { -+ if (ubi_leb_change_start(libubi, fd, 0, test_len, -+ UBI_SHORTTERM)) { -+ failed("ubi_update_start"); -+ goto close; -+ } -+ } else { -+ if (ubi_update_start(libubi, fd, test_len)) { -+ failed("ubi_update_start"); -+ goto close; -+ } -+ } -+ -+ for (j = 0; off < test_len; j++) { -+ int n, rnd_len, l; -+ -+ if (!stop) { -+ if (sequences[i][j] != 0) -+ l = len = sequences[i][j]; -+ else -+ stop = 1; -+ } -+ -+ /* -+ * Fill some part of the write buffer with random data, -+ * and the other part with 0xFFs to test how UBI -+ * stripes 0xFFs multiple of I/O unit size. -+ */ -+ if (off + l > test_len) -+ l = test_len - off; -+ rnd_len = rand() % (l + 1); -+ for (n = 0; n < rnd_len; n++) -+ buf[off + n] = (unsigned char)rand(); -+ memset(buf + off + rnd_len, 0xFF, l - rnd_len); -+ -+ /* -+ * Deliberately pass len instead of l (len may be -+ * greater then l if this is the last chunk) because -+ * UBI have to read only l bytes anyway. -+ */ -+ ret = write(fd, buf + off, len); -+ if (ret < 0) { -+ failed("write"); -+ err_msg("failed to write %d bytes at offset " -+ "%lld", len, (long long)off); -+ goto close; -+ } -+ len = l; -+ if (ret != len) { -+ err_msg("failed to write %d bytes at offset " -+ "%lld, wrote %d", len, (long long)off, ret); -+ goto close; -+ } -+ off += len; -+ } -+ -+ /* Check data */ -+ if ((ret = lseek(fd, SEEK_SET, 0)) != 0) { -+ failed("lseek"); -+ err_msg("cannot seek to 0"); -+ goto close; -+ } -+ -+ memset(buf1, 0x01, test_len); -+ -+ if (vol_info->type == UBI_STATIC_VOLUME) -+ /* -+ * Static volume must not let use read more then it -+ * contains. -+ */ -+ ret = read(fd, buf1, test_len + 100); -+ else -+ ret = read(fd, buf1, test_len); -+ if (ret < 0) { -+ failed("read"); -+ err_msg("failed to read %d bytes", test_len); -+ goto close; -+ } -+ if (ret != test_len) { -+ err_msg("failed to read %d bytes, read %d", test_len, ret); -+ goto close; -+ } -+ if (memcmp(buf, buf1, test_len)) { -+ err_msg("data corruption"); -+ goto close; -+ } -+ } -+ -+ close(fd); -+ return 0; -+ -+close: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * test_update - check volume update and atomic LEB change capabilities. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_update(int type) -+{ -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":io_update()"; -+ int alignments[] = ALIGNMENTS(dev_info.leb_size); -+ struct ubi_vol_info vol_info; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ int i; -+ -+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { -+ int leb_size; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.vol_type = type; -+ req.name = name; -+ -+ req.alignment = alignments[i]; -+ req.alignment -= req.alignment % dev_info.min_io_size; -+ if (req.alignment == 0) -+ req.alignment = dev_info.min_io_size; -+ -+ leb_size = dev_info.leb_size - dev_info.leb_size % req.alignment; -+ req.bytes = MIN_AVAIL_EBS * leb_size; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ req.vol_id); -+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { -+ failed("ubi_get_vol_info"); -+ goto remove; -+ } -+ -+ if (test_update1(&vol_info, 0)) { -+ err_msg("alignment = %d", req.alignment); -+ goto remove; -+ } -+ -+ if (vol_info.type != UBI_STATIC_VOLUME) { -+ if (test_update1(&vol_info, 1)) { -+ err_msg("alignment = %d", req.alignment); -+ goto remove; -+ } -+ } -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (test_update(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_update(UBI_STATIC_VOLUME)) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,301 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test UBI volume creation and deletion ioctl()s with bad input and in case of -+ * incorrect usage. -+ */ -+ -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "mkvol_bad" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+ -+/** -+ * test_mkvol - test that UBI mkvol ioctl rejects bad input parameters. -+ * -+ * This function returns %0 if the test passed and %-1 if not. -+ */ -+static int test_mkvol(void) -+{ -+ int ret, i; -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":test_mkvol()"; -+ -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = name; -+ -+ /* Bad volume ID */ -+ req.vol_id = -2; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id)) -+ return -1; -+ -+ req.vol_id = dev_info.max_vol_count; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id)) -+ return -1; -+ -+ /* Bad alignment */ -+ req.vol_id = 0; -+ req.alignment = 0; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", -+ req.alignment)) -+ return -1; -+ -+ req.alignment = -1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", -+ req.alignment)) -+ return -1; -+ -+ req.alignment = dev_info.leb_size + 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", -+ req.alignment)) -+ return -1; -+ -+ if (dev_info.min_io_size > 1) { -+ req.alignment = dev_info.min_io_size + 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", -+ req.alignment)) -+ return -1; -+ } -+ -+ /* Bad bytes */ -+ req.alignment = 1; -+ req.bytes = -1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes)) -+ return -1; -+ -+ req.bytes = 0; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes)) -+ return -1; -+ -+ req.bytes = dev_info.avail_bytes + 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes)) -+ return -1; -+ -+ req.alignment = dev_info.leb_size - dev_info.min_io_size; -+ req.bytes = (dev_info.leb_size - dev_info.leb_size % req.alignment) * -+ dev_info.avail_lebs + 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes)) -+ return -1; -+ -+ /* Bad vol_type */ -+ req.alignment = 1; -+ req.bytes = dev_info.leb_size; -+ req.vol_type = UBI_DYNAMIC_VOLUME + UBI_STATIC_VOLUME; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_type = %d", -+ req.vol_type)) -+ return -1; -+ -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ -+ /* Too long name */ -+ { -+ char name[UBI_VOL_NAME_MAX + 5]; -+ -+ memset(name, 'x', UBI_VOL_NAME_MAX + 1); -+ name[UBI_VOL_NAME_MAX + 1] = '\0'; -+ -+ req.name = name; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "name_len = %d", -+ UBI_VOL_NAME_MAX + 1)) -+ return -1; -+ } -+ -+ /* Try to create 2 volumes with the same ID and name */ -+ req.name = name; -+ req.vol_id = 0; -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EEXIST, "ubi_mkvol", -+ "volume with ID 0 created twice")) -+ return -1; -+ -+ req.vol_id = 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EEXIST, "ubi_mkvol", -+ "volume with name \"%s\" created twice", name)) -+ return -1; -+ -+ if (ubi_rmvol(libubi, node, 0)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ /* Try to use too much space */ -+ req.vol_id = 0; -+ req.bytes = dev_info.avail_bytes; -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ req.bytes = 1; -+ req.vol_id = 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EEXIST, "ubi_mkvol", -+ "created volume of maximum size %lld, but still " -+ "can create more volumes", dev_info.avail_bytes)) -+ return -1; -+ -+ if (ubi_rmvol(libubi, node, 0)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ /* Try to create too many volumes */ -+ for (i = 0; i < dev_info.max_vol_count; i++) { -+ char nm[strlen(name) + 50]; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = 1; -+ req.vol_type = UBI_STATIC_VOLUME; -+ -+ sprintf(nm, "%s:%d", name, i); -+ req.name = nm; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ /* -+ * Note, because of gluebi we may be unable to create -+ * dev_info.max_vol_count devices (MTD restrictions). -+ */ -+ if (errno == ENFILE) -+ break; -+ failed("ubi_mkvol"); -+ err_msg("vol_id %d", i); -+ goto remove; -+ } -+ } -+ -+ for (i = 0; i < dev_info.max_vol_count + 1; i++) -+ ubi_rmvol(libubi, node, i); -+ -+ return 0; -+ -+remove: -+ for (i = 0; i < dev_info.max_vol_count + 1; i++) -+ ubi_rmvol(libubi, node, i); -+ return -1; -+} -+ -+/** -+ * test_rmvol - test that UBI rmvol ioctl rejects bad input parameters. -+ * -+ * This function returns %0 if the test passed and %-1 if not. -+ */ -+static int test_rmvol(void) -+{ -+ int ret; -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":test_rmvol()"; -+ -+ /* Bad vol_id */ -+ ret = ubi_rmvol(libubi, node, -1); -+ if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = -1")) -+ return -1; -+ -+ ret = ubi_rmvol(libubi, node, dev_info.max_vol_count); -+ if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = %d", -+ dev_info.max_vol_count)) -+ return -1; -+ -+ /* Try to remove non-existing volume */ -+ ret = ubi_rmvol(libubi, node, 0); -+ if (check_failed(ret, ENODEV, "ubi_rmvol", -+ "removed non-existing volume 0")) -+ return -1; -+ -+ /* Try to remove volume twice */ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = name; -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ ret = ubi_rmvol(libubi, node, req.vol_id); -+ if (check_failed(ret, ENODEV, "ubi_rmvol", "volume %d removed twice", -+ req.vol_id)) -+ return -1; -+ -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (test_mkvol()) -+ goto close; -+ -+ if (test_rmvol()) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,250 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test test checks basic volume creation and deletion capabilities. -+ */ -+ -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "mkvol_basic" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+ -+/** -+ * mkvol_alignment - create volumes with different alignments. -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int mkvol_alignment(void) -+{ -+ struct ubi_mkvol_request req; -+ int i, vol_id, ebsz; -+ const char *name = TESTNAME ":mkvol_alignment()"; -+ int alignments[] = ALIGNMENTS(dev_info.leb_size); -+ -+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ -+ /* Alignment should actually be multiple of min. I/O size */ -+ req.alignment = alignments[i]; -+ req.alignment -= req.alignment % dev_info.min_io_size; -+ if (req.alignment == 0) -+ req.alignment = dev_info.min_io_size; -+ -+ /* Bear in mind alignment reduces EB size */ -+ ebsz = dev_info.leb_size - dev_info.leb_size % req.alignment; -+ req.bytes = dev_info.avail_lebs * ebsz; -+ -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ err_msg("alignment %d", req.alignment); -+ return -1; -+ } -+ -+ vol_id = req.vol_id; -+ if (check_volume(vol_id, &req)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, vol_id); -+ return -1; -+} -+ -+/** -+ * mkvol_basic - simple test that checks basic volume creation capability. -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int mkvol_basic(void) -+{ -+ struct ubi_mkvol_request req; -+ struct ubi_vol_info vol_info; -+ int vol_id, ret; -+ const char *name = TESTNAME ":mkvol_basic()"; -+ -+ /* Create dynamic volume of maximum size */ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ vol_id = req.vol_id; -+ if (check_volume(vol_id, &req)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ /* Create static volume of maximum size */ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = UBI_STATIC_VOLUME; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ vol_id = req.vol_id; -+ if (check_volume(vol_id, &req)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ /* Make sure volume does not exist */ -+ ret = ubi_get_vol_info1(libubi, dev_info.dev_num, vol_id, &vol_info); -+ if (ret == 0) { -+ err_msg("removed volume %d exists", vol_id); -+ goto remove; -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, vol_id); -+ return -1; -+} -+ -+/** -+ * mkvol_multiple - test multiple volumes creation -+ * -+ * Thus function returns %0 if the test passed and %-1 if not. -+ */ -+static int mkvol_multiple(void) -+{ -+ struct ubi_mkvol_request req; -+ int i, ret, max = dev_info.max_vol_count; -+ const char *name = TESTNAME ":mkvol_multiple()"; -+ -+ /* Create maximum number of volumes */ -+ for (i = 0; i < max; i++) { -+ char nm[strlen(name) + 50]; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = 1; -+ req.vol_type = UBI_STATIC_VOLUME; -+ -+ sprintf(nm, "%s:%d", name, i); -+ req.name = nm; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ if (errno == ENFILE) { -+ max = i; -+ break; -+ } -+ failed("ubi_mkvol"); -+ err_msg("vol_id %d", i); -+ goto remove; -+ } -+ -+ if (check_volume(req.vol_id, &req)) { -+ err_msg("vol_id %d", i); -+ goto remove; -+ } -+ } -+ -+ for (i = 0; i < max; i++) { -+ struct ubi_vol_info vol_info; -+ -+ if (ubi_rmvol(libubi, node, i)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ /* Make sure volume does not exist */ -+ ret = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info); -+ if (ret == 0) { -+ err_msg("removed volume %d exists", i); -+ goto remove; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ for (i = 0; i < dev_info.max_vol_count + 1; i++) -+ ubi_rmvol(libubi, node, i); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (mkvol_basic()) -+ goto close; -+ -+ if (mkvol_alignment()) -+ goto close; -+ -+ if (mkvol_multiple()) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,110 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * This test creates and deletes volumes in parallel. -+ */ -+ -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "mkvol_paral" -+#include "common.h" -+ -+#define THREADS_NUM 4 -+#define ITERATIONS 500 -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+static int iterations = ITERATIONS; -+ -+/** -+ * the_thread - the testing thread. -+ * -+ * @ptr thread number -+ */ -+static void * the_thread(void *ptr) -+{ -+ int n = (int)ptr, iter = iterations; -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":the_thread()"; -+ char nm[strlen(name) + 50]; -+ -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes/ITERATIONS; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ sprintf(nm, "%s:%d", name, n); -+ req.name = nm; -+ -+ while (iter--) { -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return NULL; -+ } -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return NULL; -+ } -+ } -+ -+ return NULL; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int i, ret; -+ pthread_t threads[THREADS_NUM]; -+ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ for (i = 0; i < THREADS_NUM; i++) { -+ ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i); -+ if (ret) { -+ failed("pthread_create"); -+ goto close; -+ } -+ } -+ -+ for (i = 0; i < THREADS_NUM; i++) -+ pthread_join(threads[i], NULL); -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,305 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Tes UBI volume re-size. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "rsvol" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+ -+/** -+ * test_basic - check volume re-size capability. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_basic(int type) -+{ -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":test_basic()"; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = MIN_AVAIL_EBS * dev_info.leb_size; -+ req.vol_type = type; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ req.bytes = dev_info.leb_size; -+ if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { -+ failed("ubi_rsvol"); -+ goto remove; -+ } -+ -+ if (check_volume(req.vol_id, &req)) -+ goto remove; -+ -+ req.bytes = (MIN_AVAIL_EBS + 1) * dev_info.leb_size; -+ if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { -+ failed("ubi_rsvol"); -+ goto remove; -+ } -+ -+ if (check_volume(req.vol_id, &req)) -+ goto remove; -+ -+ req.bytes -= 1; -+ if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { -+ failed("ubi_rsvol"); -+ goto remove; -+ } -+ -+ if (check_volume(req.vol_id, &req)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+/* -+ * Helper function for test_rsvol(). -+ */ -+static int test_rsvol1(struct ubi_vol_info *vol_info) -+{ -+ long long bytes; -+ struct ubi_vol_info vol_info1; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ unsigned char buf[vol_info->rsvd_bytes]; -+ int fd, i, ret; -+ -+ /* Make the volume smaller and check basic volume I/O */ -+ bytes = vol_info->rsvd_bytes - vol_info->leb_size; -+ if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes - 1)) { -+ failed("ubi_rsvol"); -+ return -1; -+ } -+ -+ if (ubi_get_vol_info1(libubi, vol_info->dev_num, vol_info->vol_id, -+ &vol_info1)) { -+ failed("ubi_get_vol_info"); -+ return -1; -+ } -+ -+ if (vol_info1.rsvd_bytes != bytes) { -+ err_msg("rsvd_bytes %lld, must be %lld", -+ vol_info1.rsvd_bytes, bytes); -+ return -1; -+ } -+ -+ if (vol_info1.rsvd_lebs != vol_info->rsvd_lebs - 1) { -+ err_msg("rsvd_lebs %d, must be %d", -+ vol_info1.rsvd_lebs, vol_info->rsvd_lebs - 1); -+ return -1; -+ } -+ -+ /* Write data to the volume */ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ vol_info->vol_id); -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", vol_node); -+ return -1; -+ } -+ -+ bytes = vol_info->rsvd_bytes - vol_info->leb_size - 1; -+ if (ubi_update_start(libubi, fd, bytes)) { -+ failed("ubi_update_start"); -+ goto close; -+ } -+ -+ for (i = 0; i < bytes; i++) -+ buf[i] = (unsigned char)i; -+ -+ ret = write(fd, buf, bytes); -+ if (ret != bytes) { -+ failed("write"); -+ goto close; -+ } -+ -+ close(fd); -+ -+ if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes)) { -+ failed("ubi_rsvol"); -+ return -1; -+ } -+ -+ if (ubi_rsvol(libubi, node, vol_info->vol_id, -+ vol_info->leb_size * dev_info.avail_lebs)) { -+ failed("ubi_rsvol"); -+ return -1; -+ } -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", vol_node); -+ return -1; -+ } -+ -+ /* Read data back */ -+ if (lseek(fd, 0, SEEK_SET) != 0) { -+ failed("seek"); -+ goto close; -+ } -+ memset(buf, 0, bytes); -+ ret = read(fd, buf, bytes); -+ if (ret != bytes) { -+ failed("read"); -+ goto close; -+ } -+ -+ for (i = 0; i < bytes; i++) { -+ if (buf[i] != (unsigned char)i) { -+ err_msg("bad data"); -+ goto close; -+ } -+ } -+ -+ close(fd); -+ return 0; -+ -+close: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * test_rsvol - test UBI volume re-size. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_rsvol(int type) -+{ -+ const char *name = TESTNAME "test_rsvol:()"; -+ int alignments[] = ALIGNMENTS(dev_info.leb_size); -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ struct ubi_mkvol_request req; -+ int i; -+ -+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { -+ int leb_size; -+ struct ubi_vol_info vol_info; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.vol_type = type; -+ req.name = name; -+ -+ req.alignment = alignments[i]; -+ req.alignment -= req.alignment % dev_info.min_io_size; -+ if (req.alignment == 0) -+ req.alignment = dev_info.min_io_size; -+ -+ leb_size = dev_info.leb_size - dev_info.leb_size % req.alignment; -+ req.bytes = MIN_AVAIL_EBS * leb_size; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ req.vol_id); -+ -+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { -+ failed("ubi_get_vol_info"); -+ goto remove; -+ } -+ -+ if (test_rsvol1(&vol_info)) { -+ err_msg("alignment = %d", req.alignment); -+ goto remove; -+ } -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (test_basic(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_basic(UBI_STATIC_VOLUME)) -+ goto close; -+ if (test_rsvol(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_rsvol(UBI_STATIC_VOLUME)) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,39 @@ -+#!/bin/sh -+ -+ubidev="$1" -+tests="mkvol_basic mkvol_bad mkvol_paral rsvol io_basic io_read io_update -+io_paral volrefcnt" -+ -+if test -z "$ubidev"; -+then -+ echo "Usage:" -+ echo "$0 " -+ exit 1 -+fi -+ -+ubiname=`echo $ubidev | cut -d/ -f3` -+ -+major=`cat /sys/class/ubi/$ubiname/dev | cut -d: -f1` -+ -+for minor in `seq 0 4`; do -+ if test ! -e ${ubidev}_${minor} ; -+ then -+ mknod ${ubidev}_${minor} c $major $(($minor + 1)) -+ fi -+done -+ -+if ! test -c "$ubidev"; -+then -+ echo "Error: $ubidev is not character device" -+ exit 1 -+fi -+ -+for t in `echo $tests`; -+do -+ echo "Running $t $ubidev" -+ "./$t" "$ubidev" || exit 1 -+done -+ -+echo SUCCESS -+ -+exit 0 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,122 @@ -+/* -+ * Copyright (c) Nokia Corporation, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test volume reference counting - create a volume, open a sysfs file -+ * belonging to the volume, delete the volume but do not close the file, make -+ * sure the file cannot be read, close the file, make sure the volume -+ * disappeard, make sure its sysfs subtree disappeared. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "rmvol" -+#include "common.h" -+ -+#define SYSFS_FILE "/sys/class/ubi/ubi%d_%d/usable_eb_size" -+ -+int main(int argc, char * const argv[]) -+{ -+ int ret, fd; -+ char fname[sizeof(SYSFS_FILE) + 20]; -+ const char *node; -+ libubi_t libubi; -+ struct ubi_dev_info dev_info; -+ struct ubi_mkvol_request req; -+ char tmp[100]; -+ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto out_libubi; -+ } -+ -+ /* Create a small dynamic volume */ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = dev_info.min_io_size; -+ req.bytes = dev_info.leb_size; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = "rmvol"; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ goto out_libubi; -+ } -+ -+ /* Open volume-related sysfs file */ -+ sprintf(fname, SYSFS_FILE, dev_info.dev_num, req.vol_id); -+ fd = open(fname, O_RDONLY); -+ if (fd == -1) { -+ err_msg("cannot open %s", fname); -+ failed("open"); -+ goto out_rmvol; -+ } -+ -+ /* Remove the volume, but do not close the file */ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ perror("ubi_rmvol"); -+ goto out_close; -+ } -+ -+ /* Try to read from the file, this should fail */ -+ ret = read(fd, tmp, 100); -+ if (ret != -1) { -+ err_msg("read returned %d, expected -1", ret); -+ failed("read"); -+ goto out_close; -+ } -+ -+ /* Close the file and try to open it again, should fail */ -+ close(fd); -+ fd = open(fname, O_RDONLY); -+ if (fd != -1) { -+ err_msg("opened %s again, open returned %d, expected -1", -+ fname, fd); -+ failed("open"); -+ goto out_libubi; -+ } -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_rmvol: -+ ubi_rmvol(libubi, node, req.vol_id); -+out_libubi: -+ libubi_close(libubi); -+ return 1; -+ -+out_close: -+ close(fd); -+ libubi_close(libubi); -+ return 1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,85 @@ -+# -+# Makefile for ubi-utils -+# -+ -+OPTFLAGS := -O2 -g -Wall -+KERNELHDR := ../include -+DESTDIR := /usr/local -+SBINDIR=/usr/sbin -+MANDIR=/usr/share/man -+INCLUDEDIR=/usr/include -+ -+CROSS=mipsel-linux- -+CC := $(CROSS)gcc -+CFLAGS := -I./inc -I./src -I$(KERNELHDR) $(OPTFLAGS) -Werror \ -+ -Wwrite-strings -W -std=gnu99 -DPACKAGE_VERSION=\"1.0\" -+ -+PERLPROGS = mkpfi ubicrc32.pl -+ -+NTARGETS = ubiattach ubicrc32 ubidetach ubimkvol ubinfo ubinize \ -+ ubirmvol ubiupdatevol -+TARGETS = pfiflash pddcustomize ubimirror bin2nand nand2bin ubigen \ -+ mkbootenv unubi pfi2bin $(NTARGETS) -+ -+vpath %.c ./src -+ -+%: %.o -+ $(CC) $(LDFLAGS) -g -o $@ $^ -+ -+%.o: %.c -+ $(CC) $(CFLAGS) -g -c -o $@ $< -g -Wp,-MD,.$(shell basename $<).dep -+ -+all: $(TARGETS) -+ make -C new-utils -+ -+IGNORE=${wildcard .*.c.dep} -+-include ${IGNORE} -+ -+$(NTARGETS): -+ make -C new-utils $@ -+ mv new-utils/$@ $@ -+ -+clean: -+ rm -rf *.o $(TARGETS) .*.c.dep -+ make -C new-utils clean -+ -+pddcustomize: pddcustomize.o error.o libubimirror.o bootenv.o hashmap.o \ -+ libubi.o crc32.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+pfiflash: pfiflash.o libpfiflash.o list.o reader.o error.o libubimirror.o \ -+ bootenv.o hashmap.o pfi.o libubi.o crc32.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+ubimirror: ubimirror.o error.o libubimirror.o bootenv.o hashmap.o \ -+ libubi.o crc32.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+nand2bin: nand2bin.o nandecc.o nandcorr.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+bin2nand: bin2nand.o error.o nandecc.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+ubigen: ubigen.o libubigen.o crc32.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o crc32.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+unubi: unubi.o crc32.o unubi_analyze.o eb_chain.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+pfi2bin: pfi2bin.o peb.o error.o list.o crc32.o libubigen.o bootenv.o \ -+ hashmap.o reader.o pfi.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+install: ${TARGETS} -+ mkdir -p ${DESTDIR}/${SBINDIR} -+ install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/ -+ (cd perl && install ${PERLPROGS} ${DESTDIR}/${SBINDIR}/) -+ -+uninstall: -+ for file in ${TARGETS} ${PERLPROGS}; do \ -+ $(RM) ${DESTDIR}/${SBINDIR}/$$file; \ -+ done ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/README 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,236 @@ -+README -+====== -+ -+The programs and libraries in this directory provide a tool-chain to -+generate binary data for embedded systems which can be flashed either -+by a hardware flash programmer, e.g. JTAG debugger, or on the target -+system directly using pfiflash, or ubimkvol, ubirmvol, ubiwritevol. -+ -+The latter is the case when there is already Linux running which has -+build in UBI support. -+ -+Authors: Oliver Lohmann -+ Frank Haverkamp -+ Andreas Arnez -+ -+mkpfi - tool for flash content generation in PFI -+ format -+pfi2bin - conversion tool to transfer a PFI file into a -+ binary image -+pfiflash - tool to update the embedded systems flash using -+ pfi files created by mkpfi -+libbootenv - library for boot-parameter processing -+libpfi - library for partial flash image (PFI) creation -+ and handling -+ubigen - tool to create binary UBI images e.g. for a -+ jtag flashing tool -+nandimg - tool to add OOB data to binary images intended -+ for NAND flash systems -+ubilib - UBI library -+ -+!!! NOTICE !!! -+If you execute ./configure in the top_level directory the helper Makefile -+gets overwritten. Thats actually no problem, but be aware of that. -+ -+1. Build Process -+ -+1.1 Build, install and forget -+ o Build all and everything -+ $make all (takes a while, builds ppc and x86 binaries/libs) -+ o Installation: -+ $make install -+ o Uninstallation: -+ $make uninstall -+ -+ o x86 only would be: -+ $make x86 && make install_x86 -+ -+1.2 Usage for a developer -+ -+ 1.2.1 The build process in detail -+ -+ o If you've checked out the sources from the CVS repository you'll find a -+ directory setup like this: -+ -+ flashutils/ -+ -rw-r--r-- 1 olli olli 1.3K Mar 14 11:53 Makefile -+ -rw-r--r-- 1 olli olli 1.9K Mar 14 10:50 Makefile.am -+ -rwxr-xr-x 1 olli olli 265 Mar 9 00:47 bootstrap -+ -rw-r--r-- 1 olli olli 1.1K Mar 9 16:55 configure.ac -+ drwxr-xr-x 2 olli olli 4.0K Mar 9 00:28 doc -+ drwxr-xr-x 2 olli olli 4.0K Mar 14 11:56 inc -+ drwxr-xr-x 2 olli olli 4.0K Mar 14 11:56 lib -+ drwxr-xr-x 17 olli olli 4.0K Mar 13 16:50 src -+ -+ o To generate the initial build templates you have to call the bootstrap -+ script: -+ $ ./bootstrap -+ o Create a directory for the target platform -+ $ mkdir build_x86 -+ o Descend into the directory and call the top-level configure script -+ with the desired options. -+ $ cd build_x86 -+ $ ../configure --prefix=/usr/local [...] -+ o Now you'll find a directory structure like this: -+ -+ flashutils/build_x86/ -+ -rw-r--r-- 1 olli olli 47K Mar 14 13:33 Makefile -+ -rw-r--r-- 1 olli olli 33K Mar 14 13:33 config.log -+ -rwxr-xr-x 1 olli olli 38K Mar 14 13:33 config.status -+ drwxr-xr-x 2 olli olli 4.0K Mar 14 13:33 inc -+ drwxr-xr-x 3 olli olli 4.0K Mar 14 13:33 lib -+ -rwxr-xr-x 1 olli olli 202K Mar 14 13:33 libtool -+ -+ o The config.guess script can be used to update the Makefiles in the -+ target directory after a change of the top-level template files -+ (i.e. the Makefile.in files). -+ $ ./config.guess -+ o To compile everything for this platform just invoke make in -+ flashutils/build_x86: -+ $ make -+ or from toplevel: -+ $ make -C ./build_x86 -+ o The build process creates a new directory "bin": -+ flashutils/build_x86/ -+ [...] -+ drwxr-xr-x 3 olli olli 4.0K Mar 14 13:41 bin -+ [...] -+ -+ This directory contains all binary files which will be installed -+ by make install, e.g.: -+ -+ flashutils/build_x86/bin/ -+ -rwxr-xr-x 1 olli olli 7.2K Mar 14 13:41 bin2nand -+ -rwxr-xr-x 1 olli olli 15K Mar 14 13:41 mkbootenv -+ -rwxr-xr-x 1 olli olli 16K Mar 14 13:41 pddcustomize -+ -rwxr-xr-x 1 olli olli 36K Mar 14 13:41 pfi2bin -+ -rwxr-xr-x 1 olli olli 6.8K Mar 14 13:41 pfiflash -+ -rwxr-xr-x 1 olli olli 5.0K Mar 14 13:41 ubicrc32 -+ -rwxr-xr-x 1 olli olli 13K Mar 14 13:41 ubigen -+ -rwxr-xr-x 1 olli olli 6.3K Mar 14 13:41 ubimirror -+ -+ -+ 1.2.2 Modifying and Adding Sources -+ -+ o There is a dedicated directory which contains all source code -+ of the flashutils package, e.g.: -+ -+ flashutils/src/ -+ drwxr-xr-x 2 olli olli 4.0K Mar 13 11:42 libbootenv -+ drwxr-xr-x 2 olli olli 4.0K Mar 13 11:42 liberror -+ drwxr-xr-x 2 olli olli 4.0K Mar 13 16:48 mkpfi -+ drwxr-xr-x 2 olli olli 4.0K Mar 13 16:12 pddcustomize -+ -+ -+ -+ The prefix "lib" is used to mark directories as part of a convenience -+ library. Binaries have no special prefix. -+ -+ o How to add sources? -+ -+ Just create a new directory at flashutils/src/, e.g.: -+ -+ For a binary: -+ $ mkdir rider -+ $ cd rider -+ $ vi rider.c -+ /* do sth with that file... */ -+ -+ For a convenience library (as well as for "normal libs") -+ $ mkdir libworld -+ $ cd libworld -+ $ vi world.c -+ /* do sth with that file... */ -+ -+ o How to register sources in the build process (for binaries)? -+ -+ You have to register your sources at the top-level automake Makefile: -+ -+ In directory flashutils/ -+ $ vi Makefile.am -+ -+ Binaries have to be registered at "bin_PROGRAMS", e.g.: -+ bin_PROGRAMS = bin/pddcustomize \ -+ bin/rider -+ -+ Add the rule how the binary is assembled, e.g.: -+ bin_pddcustomize_SOURCES = \ -+ $(top_srcdir)/src/pddcustomize/pddcustomize.c -+ bin_pddcustomize_LDADD = \ -+ $(top_builddir)/lib/libbootenv.la \ -+ $(top_builddir)/lib/liberror.la -+ -+ bin_rider_SOURCES = \ -+ $(top_srcdir)/src/rider/rider.c -+ -+ This example reflects a simple build process for "rider". "rider" -+ is built without any other dependencies or convenience libraries. -+ The example for pddcustomize is a bit more complicated. -+ "_LDADD" adds some convenience libraris into the link process of -+ "pddcustomize". Imagine, that your "rider" has common code -+ with "dragon_bin" which is held in a library called "libworld". -+ The build rules would like like the following: -+ -+ bin_rider_SOURCES = \ -+ $(top_srcdir)/src/rider/rider.c -+ bin_rider_LDADD = \ -+ $(top_builddir)/lib/libworld.la -+ -+ bin_dragon_SOURCES = \ -+ $(top_srcdir)/src/dragon_bin/dragon_bin.c -+ bin_dragon_LDADD = \ -+ $(top_builddir)/lib/libworld.la -+ -+ Don't forget to add "dragon" to "bin_PROGRAMS"! -+ Don't forget to set the build rule for the "libworld" itself! -+ This is documented in the next section. -+ -+ -+ o How to register sources in the build process (for libraries)? -+ -+ Until now we didn't care about the build process of "libworld". -+ Libraries are handled special in this build process because -+ they are handled as "modules", i.e. they are able to be built -+ without building the binaries in the same step. Additionally, -+ it is possible to assemble complex libraries out of simple ones. -+ That especially makes sense if you want to export (install) a -+ library on a system which uses some common code and makes -+ some adoptions for usability and presents a comfortable interface to -+ the user (see libpfiflash in the sources for an example). -+ -+ o Registering "libworld" as convenience library. -+ -+ Instead of editing the "Makefile.am" in "flashtools/", we have to -+ edit now the "Makefile.am" in "flashtools/lib/": -+ -+ noinst_LTLIBRARIES = libworld.la -+ -+ libworld_la_SOURCES = $(top_srcdir)/src/libworld/world.c -+ -+ o Registering "libworld" as library which gets installed. -+ -+ lib_LTLIBRARIES = libworld.la -+ libworld_la_SOURCES = $(top_srcdir)/src/libworld/world.c -+ libworld_la_LDFLAGS = -no-undefined -version-info 0:0:0 -+ -+ o Header files -+ -+ All header files are stored at "flashutils/inc", regardless -+ if convenience library or not. -+ -+ If you want to export headers you have to specify this in the Makefile.am -+ located at "flashutils/inc", e.g. (this should not be done -+ for convenience libraries): -+ -+ nobase_include_HEADERS = world.h -+ -+ -+ -+Appendix -+ -+A.1. FAQ -+ -+ Q How to call configure to setup a cross-platform build? -+ A $ ./configure --build=i686-pc-linux-gnu --host=ppc-linux \ -+ --prefix=/opt/.../ppcnf/crossroot/ \ -+ --exec-prefix=/opt/..../ppcnf/crossroot/usr ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,108 @@ -+UBI - Unsorted Block Images -+ -+UBI (Latin: "where?") manages multiple logical volumes on a single -+flash device, specifically supporting NAND flash devices. UBI provides -+a flexible partitioning concept which still allows for wear-levelling -+across the whole flash device. -+ -+In a sense, UBI may be compared to the Logical Volume Manager -+(LVM). Whereas LVM maps logical sector numbers to physical HDD sector -+numbers, UBI maps logical eraseblocks to physical eraseblocks. -+ -+More information may be found in the UBI design documentation: -+ubidesign.pdf. Which can be found here: -+http://www.linux-mtd.infradead.org/doc/ubi.html -+ -+Partitioning/Re-partitioning -+ -+ An UBI volume occupies a certain number of erase blocks. This is -+ limited by a configured maximum volume size, which could also be -+ viewed as the partition size. Each individual UBI volume's size can -+ be changed independently of the other UBI volumes, provided that the -+ sum of all volume sizes doesn't exceed a certain limit. -+ -+ UBI supports dynamic volumes and static volumes. Static volumes are -+ read-only and their contents are protected by CRC check sums. -+ -+Bad eraseblocks handling -+ -+ UBI transparently handles bad eraseblocks. When a physical -+ eraseblock becomes bad, it is substituted by a good physical -+ eraseblock, and the user does not even notice this. -+ -+Scrubbing -+ -+ On a NAND flash bit flips can occur on any write operation, -+ sometimes also on read. If bit flips persist on the device, at first -+ they can still be corrected by ECC, but once they accumulate, -+ correction will become impossible. Thus it is best to actively scrub -+ the affected eraseblock, by first copying it to a free eraseblock -+ and then erasing the original. The UBI layer performs this type of -+ scrubbing under the covers, transparently to the UBI volume users. -+ -+Erase Counts -+ -+ UBI maintains an erase count header per eraseblock. This frees -+ higher-level layers (like file systems) from doing this and allows -+ for centralized erase count management instead. The erase counts are -+ used by the wear-levelling algorithm in the UBI layer. The algorithm -+ itself is exchangeable. -+ -+Booting from NAND -+ -+ For booting directly from NAND flash the hardware must at least be -+ capable of fetching and executing a small portion of the NAND -+ flash. Some NAND flash controllers have this kind of support. They -+ usually limit the window to a few kilobytes in erase block 0. This -+ "initial program loader" (IPL) must then contain sufficient logic to -+ load and execute the next boot phase. -+ -+ Due to bad eraseblocks, which may be randomly scattered over the -+ flash device, it is problematic to store the "secondary program -+ loader" (SPL) statically. Also, due to bit-flips it may become -+ corrupted over time. UBI allows to solve this problem gracefully by -+ storing the SPL in a small static UBI volume. -+ -+UBI volumes vs. static partitions -+ -+ UBI volumes are still very similar to static MTD partitions: -+ -+ * both consist of eraseblocks (logical eraseblocks in case of UBI -+ volumes, and physical eraseblocks in case of static partitions; -+ * both support three basic operations - read, write, erase. -+ -+ But UBI volumes have the following advantages over traditional -+ static MTD partitions: -+ -+ * there are no eraseblock wear-leveling constraints in case of UBI -+ volumes, so the user should not care about this; -+ * there are no bit-flips and bad eraseblocks in case of UBI volumes. -+ -+ So, UBI volumes may be considered as flash devices with relaxed -+ restrictions. -+ -+Where can it be found? -+ -+ Documentation, kernel code and applications can be found in the MTD -+ gits. -+ -+What are the applications for? -+ -+ The applications help to create binary flash images for two -+ purposes: pfi files (partial flash images) for in-system update of -+ UBI volumes, and plain binary images, with or without OOB data in -+ case of NAND, for a manufacturing step. Furthermore some tools -+ are/and will be created that allow flash content analysis after a -+ system has crashed. -+ -+Who did UBI? -+ -+ The original ideas, where UBI is based on, were developed by Andreas -+ Arnez, Frank Haverkamp and Thomas Gleixner. Josh W. Boyer and -+ some others were involved too. The implementation of the kernel -+ layer was done by Artem B. Bityutskiy. The user-space applications -+ and tools were written by Oliver Lohmann with contributions from -+ Frank Haverkamp, Andreas Arnez, and Artem. Joern Engel contributed a -+ patch which modifies JFFS2 so that it can be run on a UBI -+ volume. Thomas Gleixner did modifications to the NAND layer and also -+ some to JFFS2 to make it work. ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,123 @@ -+.TH UNUBI 1 "NOVEMBER 2006" FSP "FSP Flashutils" -+.SH NAME -+unubi \- extract volumes/eraseblocks from a raw\-UBI image -+.SH SYNOPSIS -+\fBunubi [\-aevEV] [\-d \fIout\-dir\fB] [\-r \fIvolume\-id\fB] -+[\-b \fIblock\-size\fB] \fIimage\-file -+.SH DESCRIPTION -+.PP -+\fBunubi\fR reads an image file containing blocks of UBI headers and data -+(such as produced from \fBnand2bin\fR) and rebuilds the volumes within. -+The default operation (when no flags are given) is to rebuild all valid -+volumes found in the image. \fBunubi\fR can also read straight from the -+onboard MTD device (ex. /dev/mtdblock/NAND). -+.SH OPTIONS -+.IP "\-a, \-\-analyze" -+When flagged, analysis files are generated within the output directory. These -+may include tables and or graphs detailing statistics gathered from the -+eraseblock data. Files are prefixed `analysis_'. -+ -+See \fBANALYSIS\fR. -+.IP "\-b, \-\-blocksize \fIblock\-size\fR" -+Specify in bytes the \fIimage\-file\fR eraseblock size. Sizes may be -+postfixed with `KiB' or `MiB' to indicate mebibytes or kibibytes -+respectively. Default is 128KiB. -+.IP "\-d, \-\-dir \fIoutput\-dir\fR" -+Specify the output directory. If no directory is specified, the default -+is `unubi_\fIimage\-file\fR' within the curent working directory. If the -+attempt to create the output directory fails, -+.B unubi -+will try to create it in /tmp before aborting. -+.IP "\-e, \-\-eb\-split" -+When flagged, images are created for each eraseblock in \fIimage\-file\fR -+regardless of its validity. Each image is the complete eraseblock, including -+headers and any space to the end of the eraseblock after where the data may -+end. -+ -+Invalid images are named `ebEEEE', where EEEE is the physical index of the -+eraseblock in the image. Valid images are named `ebEEEE_VVV_NNN_RRR' where -+VVV is the known volume ID, NNN is the logical number and RRR is the version -+of the eraseblock data. Note that the version number is in hexadecimal. -+ -+Invalid images may also contain this postfix, if the data in the header -+could be valid (ie. the header contains a resonable volume ID, but the -+header and/or data CRCs are not valid). If this is the case, images are named -+`ebEEEE_VVV_NNN_RRR.reason', so as to distinguish known values from -+non\-definite ones. -+ -+See \fBREASON SUFFIXES\fR. -+.IP "\-r, \-\-rebuild \fIvolume\-id\fR" -+Specify a volume to rebuild. Can be used successively to specify -+several volumes to be rebuilt. -+ -+Images are named `volumeVVV' where VVV is the volume ID. For each missing -+eraseblock, an error message will be printed. -+.IP "\-v, \-\-vol\-split" -+When flagged, images are created for each valid eraseblock in -+\fIimage\-file\fR. Since a vaild eraseblock will have a defined data start and -+data length, only this range will make up the image. -+ -+Images are named `volVVV_NNN_RRR_EEEE', where, for the data in the eraseblock, -+VVV is the volume ID, NNN is the logical number, RRR is the version and EEEE -+is the phyisical index of the eraseblock in the image. -+.IP "\-V, \-\-vol\-split!" -+Same as above, only all images are the complete eraseblock (including headers, -+and raw data, even past the point where the data is supposed to end). -+Overrides \-v when both \-v and \-V are flagged. -+.SH ANALYSIS -+The following files will be generated during the analysis: -+.IP "analysis_ec_hdr.data" -+A space delimited table with these two columns for each eraseblock: the -+eraseblock's index or physical position in the image, and the eraseblock's -+erase count. The third column contains the erase count data sorted. -+.IP "analysis_vid_hdr.data" -+A space delimited table with these four colums for each eraseblock: the -+volume ID, the volume logical number, the leb version, and the data size. -+In addition there are a normalized column representing the volume ID and -+volume logical number, a normalized column representing the leb version, and -+a normalized column representing the data_size. These normalized columns are -+used to better draw the the gnuplot image. -+.IP "analysis_ec_hdr.plot" -+A gnuplot script for quickly viewing a sample output from the respective .data -+file. -+.IP "analysis_vid_hdr.plot" -+A gnuplot script for quickly viewing a sample output from the respective .data -+file. -+.SH REASONS SUFFIXES -+When \-\-eb\-split produces possibly invalid, though usable, eraseblocks, the -+known reason suffixes are: -+.IP ".ec_magic" -+The erase counter header did not contain a valid magic field. -+.IP ".ec_hdr_crc" -+The erase counter header did not contain a vaild header CRC field. -+.IP ".vid_magic" -+The volume ID header did not contain a valid magic field. -+.IP ".vid_hdr_crc" -+The volume ID header did not contain a valid header CRC field. -+.IP ".data_crc" -+The volume ID header did not contain a valid data CRC field. -+.SH EXAMPLES -+To extract and rebuild all valid volumes from demo.img (note the output -+directory will be /home/user/unubi_demo.img): -+.sp 1 -+.RS -+.B /home/user# unubi demo.img -+.sp 1 -+.RE -+To analyze demo.img as well as extract and rebuild volume 7: -+.sp 1 -+.RS -+.B /home/user# unubi \-a \-r 7 demo.img -+.sp 1 -+.RE -+To split demo.img into raw images for each eraseblock into the folder -+/var/eraseblocks: -+.sp 1 -+.RS -+.B /home/user# unubi \-e \-d /var/eraseblocks demo.img -+.SH AUTHORS -+Frank Haverkamp -+.sp 0 -+Drake Dowsett -+.SH CONTACT -+Andreas Arnez ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,268 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#ifndef __LIBUBI_H__ -+#define __LIBUBI_H__ -+ -+#include -+#include -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* UBI version libubi is made for */ -+#define LIBUBI_UBI_VERSION 1 -+ -+/* UBI library descriptor */ -+typedef void * libubi_t; -+ -+/** -+ * struct ubi_mkvol_request - volume creation request. -+ * */ -+struct ubi_mkvol_request -+{ -+ int vol_id; -+ int alignment; -+ long long bytes; -+ int vol_type; -+ const char *name; -+}; -+ -+/** -+ * struct ubi_info - general UBI information. -+ * -+ * @dev_count count of UBI devices in system -+ * @lowest_dev_num lowest UBI device number -+ * @highest_dev_num highest UBI device number -+ * @version UBI version -+ */ -+struct ubi_info -+{ -+ int dev_count; -+ int lowest_dev_num; -+ int highest_dev_num; -+ int version; -+}; -+ -+/** -+ * struct ubi_dev_info - UBI device information. -+ * -+ * @vol_count count of volumes on this UBI device -+ * @lowest_vol_num lowest volume number -+ * @highest_vol_num highest volume number -+ * @total_ebs total number of eraseblocks on this UBI device -+ * @avail_ebs how many eraseblocks are not used and available for new -+ * volumes -+ * @total_bytes @total_ebs * @eb_size -+ * @avail_bytes @avail_ebs * @eb_size -+ * @bad_count count of bad eraseblocks -+ * @eb_size size of UBI eraseblock -+ * @max_ec current highest erase counter value -+ * @bad_rsvd how many physical eraseblocks of the underlying flash -+ * device are reserved for bad eraseblocks handling -+ * @max_vol_count maximum count of volumes on this UBI device -+ * @min_io_size minimum input/output size of the UBI device -+ */ -+struct ubi_dev_info -+{ -+ int dev_num; -+ int vol_count; -+ int lowest_vol_num; -+ int highest_vol_num; -+ int total_ebs; -+ int avail_ebs; -+ long long total_bytes; -+ long long avail_bytes; -+ int bad_count; -+ int eb_size; -+ long long max_ec; -+ int bad_rsvd; -+ int max_vol_count; -+ int min_io_size; -+}; -+ -+/** -+ * struct ubi_vol_info - UBI volume information. -+ * -+ * @dev_num UBI device number the volume resides on -+ * @vol_id ID of this volume -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @alignment alignemnt of this volume -+ * @data_bytes how many data bytes are stored on this volume (equivalent to -+ * @rsvd_bytes for dynamic volumes) -+ * @rsvd_bytes how many bytes are reserved for this volume -+ * @rsvd_ebs how many eraseblocks are reserved for this volume -+ * @eb_size logical eraseblock size of this volume (may be less then -+ * device's logical eraseblock size due to alignment) -+ * @corrupted the volume is corrupted if this flag is not zero -+ * @name volume name (null-terminated) -+ */ -+struct ubi_vol_info -+{ -+ int dev_num; -+ int vol_id; -+ int type; -+ int alignment; -+ long long data_bytes; -+ long long rsvd_bytes; -+ int rsvd_ebs; -+ int eb_size; -+ int corrupted; -+ char name[UBI_VOL_NAME_MAX + 1]; -+}; -+ -+/** -+ * libubi_open - open UBI library. -+ * -+ * This function initializes and opens the UBI library and returns UBI library -+ * descriptor in case of success and %NULL in case of failure. -+ */ -+libubi_t libubi_open(void); -+ -+/** -+ * libubi_close - close UBI library -+ * -+ * @desc UBI library descriptor -+ */ -+void libubi_close(libubi_t desc); -+ -+/** -+ * ubi_get_info - get general UBI information. -+ * -+ * @info pointer to the &struct ubi_info object to fill -+ * @desc UBI library descriptor -+ * -+ * This function fills the passed @info object with general UBI information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_info(libubi_t desc, struct ubi_info *info); -+ -+/** -+ * ubi_mkvol - create an UBI volume. -+ * -+ * @desc UBI library descriptor -+ * @node name of the UBI character device to create a volume at -+ * @req UBI volume creation request (defined at ) -+ * -+ * This function creates a UBI volume as described at @req and returns %0 in -+ * case of success and %-1 in case of failure. The assigned volume ID is -+ * returned in @req->vol_id. -+ */ -+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req); -+ -+/** -+ * ubi_rmvol - remove a UBI volume. -+ * -+ * @desc UBI library descriptor -+ * @node name of the UBI character device to remove a volume from -+ * @vol_id ID of the volume to remove -+ * -+ * This function removes volume @vol_id from UBI device @node and returns %0 in -+ * case of success and %-1 in case of failure. -+ */ -+int ubi_rmvol(libubi_t desc, const char *node, int vol_id); -+ -+/** -+ * ubi_rsvol - re-size UBI volume. -+ * -+ * @desc UBI library descriptor -+ * @node name of the UBI character device owning the volume which should be -+ * re-sized -+ * @vol_id volume ID to re-size -+ * @bytes new volume size in bytes -+ * -+ * This function returns %0 in case of success and %-1 in case of error. -+ */ -+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes); -+ -+/** -+ * ubi_get_dev_info - get UBI device information. -+ * -+ * @desc UBI library descriptor -+ * @node name of the UBI character device to fetch information about -+ * @info pointer to the &struct ubi_dev_info object to fill -+ * -+ * This function fills the passed @info object with UBI device information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_dev_info(libubi_t desc, const char *node, -+ struct ubi_dev_info *info); -+ -+/** -+ * ubi_get_dev_info1 - get UBI device information. -+ * -+ * @desc UBI library descriptor -+ * @dev_num UBI device number to fetch information about -+ * @info pointer to the &struct ubi_dev_info object to fill -+ * -+ * This function is identical to 'ubi_get_dev_info()' except that it accepts UBI -+ * device number, not UBI character device. -+ */ -+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info); -+ -+/** -+ * ubi_get_vol_info - get UBI volume information. -+ * -+ * @desc UBI library descriptor -+ * @node name of the UBI volume character device to fetch information about -+ * @info pointer to the &struct ubi_vol_info object to fill -+ * -+ * This function fills the passed @info object with UBI volume information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_vol_info(libubi_t desc, const char *node, -+ struct ubi_vol_info *info); -+ -+/** -+ * ubi_get_vol_info1 - get UBI volume information. -+ * -+ * @desc UBI library descriptor -+ * @dev_num UBI device number -+ * @vol_id ID of the UBI volume to fetch information about -+ * @info pointer to the &struct ubi_vol_info object to fill -+ * -+ * This function is identical to 'ubi_get_vol_info()' except that it accepts UBI -+ * volume number, not UBI volume character device. -+ */ -+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, -+ struct ubi_vol_info *info); -+ -+/** -+ * ubi_update_start - start UBI volume update. -+ * -+ * @desc UBI library descriptor -+ * @fd volume character devie file descriptor -+ * @bytes how many bytes will be written to the volume -+ * -+ * This function initiates UBI volume update and returns %0 in case of success -+ * and %-1 in case of error. -+ */ -+int ubi_update_start(libubi_t desc, int fd, long long bytes); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__LIBUBI_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,58 @@ -+AUTOMAKE_OPTIONS = foreign -+INCLUDES=-I$(top_srcdir)/inc -I$(top_srcdir)/../../kernel/include -+ -+# ----------------------------------------------------------------------------- -+# all export libs which shall be generated -+lib_LTLIBRARIES = libubi.la \ -+ libpfiflash.la -+ -+# ----------------------------------------------------------------------------- -+# all convinence libs which shall be generated -+noinst_LTLIBRARIES = libcrc32.la \ -+ libubigen.la \ -+ liberror.la \ -+ liblist.la \ -+ libbootenv.la \ -+ libpfi.la \ -+ libpeb.la \ -+ libreader.la \ -+ libubimirror.la -+ -+# ----------------------------------------------------------------------------- -+# exported libs -+libpfiflash_la_SOURCES = $(top_srcdir)/src/libpfiflash/pfiflash.c -+libpfiflash_la_LDFLAGS = -no-undefined -version-info 1:0:0 -+libpfiflash_la_LIBADD = libreader.la \ -+ libubimirror.la \ -+ libubi.la -+ -+libubi_la_SOURCES = $(top_srcdir)/src/libubi/libubi.c \ -+ $(top_srcdir)/src/libubi/libubi_sysfs.c -+libubi_la_LDFLAGS = -no-undefined -version-info 1:0:0 -+ -+# ----------------------------------------------------------------------------- -+# complex convinence libs, beware for double includes. -+libreader_la_SOURCES = $(top_srcdir)/src/libreader/reader.c -+libreader_la_LIBADD = libpfi.la \ -+ liblist.la \ -+ libpeb.la \ -+ libbootenv.la -+ -+libubigen_la_SOURCES = $(top_srcdir)/src/libubigen/ubigen.c -+libubigen_la_LIBADD = libcrc32.la -+ -+libbootenv_la_SOURCES = $(top_srcdir)/src/libbootenv/bootenv.c \ -+ $(top_srcdir)/src/libbootenv/hashmap.c -+libbootenv_la_LIBADD = libcrc32.la -+ -+libubimirror_la_SOURCES = $(top_srcdir)/src/libubimirror/ubimirror.c -+libubimirror_la_LIBADD = libubi.la -+ -+ -+# ----------------------------------------------------------------------------- -+# simple convinence libs -+libcrc32_la_SOURCES = $(top_srcdir)/src/libcrc32/crc32.c -+liberror_la_SOURCES = $(top_srcdir)/src/liberror/error.c -+liblist_la_SOURCES = $(top_srcdir)/src/liblist/list.c -+libpeb_la_SOURCES = $(top_srcdir)/src/libpeb/peb.c -+libpfi_la_SOURCES = $(top_srcdir)/src/libpfi/pfi.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,21 @@ -+Copyright (c) 2000-2007 by Nicolas Devillard. -+MIT License -+ -+Permission is hereby granted, free of charge, to any person obtaining a -+copy of this software and associated documentation files (the "Software"), -+to deal in the Software without restriction, including without limitation -+the rights to use, copy, modify, merge, publish, distribute, sublicense, -+and/or sell copies of the Software, and to permit persons to whom the -+Software is furnished to do so, subject to the following conditions: -+ -+The above copyright notice and this permission notice shall be included in -+all copies or substantial portions of the Software. -+ -+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+DEALINGS IN THE SOFTWARE. -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,81 @@ -+# -+# Makefile for ubi-utils -+# -+ -+OPTFLAGS := -O2 -Wall -+KERNELHDR := ../../include -+#DESTDIR := /usr/local -+DESTDIR := /nfsroot/user/yrtan -+SBINDIR=/usr/sbin -+MANDIR=/usr/man -+INCLUDEDIR=/usr/include -+CROSS=mipsel-linux- -+CC := $(CROSS)gcc -+CFLAGS := -Iinclude -Isrc -I$(KERNELHDR) $(OPTFLAGS) -Werror -Wall -+ -+LIBS = libubi libmtd libubigen libiniparser libscan -+UTILS = ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \ -+ ubidetach ubiformat ubidumpvol ubicrcvol \ -+ ubinize ubicrcsf ubirefimg -+vpath %.c src -+ -+all: $(UTILS) -+ -+# The below cancels existing implicite rule to make programs from .c files, -+# in order to force make using our rule defined below -+%: %.c -+ -+# The below is the rule to get an .o file from a .c file -+%.o: %.c -+ $(CC) $(CFLAGS) $< -c -o $@ -+ -+# And the below is the rule to get final executable from its .o and common.o -+%: libubi.a %.o common.o -+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lubi -o $@ -+ -+ubicrcsf: ubicrcsf.o crc32.o -+ $(CC) $(CFLAGS) -o $@ $^ -+ -+ubicrcvol: ubicrcvol.o common.o crc32.o libubi.a -+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lubi -o $@ -+ -+ubicrc32: ubicrc32.o crc32.o -+ $(CC) $(CFLAGS) -o $@ $^ -+ -+ubinize: ubinize.o common.o crc32.o libiniparser.a libubigen.a -+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -liniparser -lubigen -o $@ -+ -+ubiformat: ubiformat.o common.o crc32.o libmtd.a libscan.a libubi.a libubigen.a -+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lmtd -lscan -lubi -lubigen -o $@ -+ -+libubi.a: libubi.o -+ $(AR) crv $@ $^ -+ ranlib $@ -+ -+libmtd.a: libmtd.o -+ $(AR) crv $@ $^ -+ ranlib $@ -+ -+libubigen.a: libubigen.o -+ $(AR) crv $@ $^ -+ ranlib $@ -+ -+libiniparser.a: libiniparser.o dictionary.o -+ $(AR) crv $@ $^ -+ ranlib $@ -+ -+libscan.a: libscan.o crc32.o -+ $(AR) crv $@ $^ -+ ranlib $@ -+ -+clean: -+ rm -rf *.o $(addsuffix .a, $(LIBS)) $(UTILS) .*.c.dep -+ -+install: ${UTILS} -+ mkdir -p ${DESTDIR}/${SBINDIR} -+ install -m0755 ${UTILS} ${DESTDIR}/${SBINDIR}/ -+ -+uninstall: -+ for file in ${UTILS}; do \ -+ $(RM) ${DESTDIR}/${SBINDIR}/$$file; \ -+ done ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/README 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,55 @@ -+This directory contains a new UBI toolchain which is intended to replace -+the old one. All utilities support "-h" option which prints sufficient -+usage information. See the MTD web-site for more information. -+ -+Motivation for new tool-chain. -+ -+I was doing very active UBI development and had to add new features like -+dynamic UBI devices and auto-resize feature. Because of the mess in the -+the old tools I basically could not figure out how to upgrade them. In -+my humble oppinion, they are unmaintainable. The original authors did not -+show enthusiasm when I mailed them and asked to clean-up the tool-chain -+[1]. Thus, I re-implemented them, but I did borrow things from the old -+tool-chain and preserved copyrights and author names. -+ -+I really did try to clean-up the old tool chain, but gave up (see git -+history for confirmation). So, -+ -+1. I found the source codes very difficult to navigate and read, especially -+ those related to pdd, pfi, and bootenv. Try to do this yourself - they -+ are a puzzle. -+2. I foud the concept of PFI needlesly complecated - PFI file is nothing -+ else but the initial configuration .ini file + the contents of the -+ UBI volumes packed into one file, but with some changes of the .ini file's -+ format. The PFI file format is not very nice and it is difficult to parse, -+ especially because the PFI headers do not tell you data star and end for -+ each data chunk, and you have to do additional parsing. -+ -+ So basically, you have .ini file + images, then you transfer this to pfi, -+ which does not add any other information. For .ini you have libraries -+ which may parse them, for pfi - not. Then you have to parse this pfi -+ which adds unneeded and complex code. This all needs lists, hashmaps, -+ and so on - for no reason. -+3. I found the command line options of the utilities to be inconsistent. -+ This is OK when you script your single task and do not touch it anymore. -+ But when you have to use the utilities while developing and testing, -+ It is difficult to remember their inconsistent options. -+4. I found it wrong to add development options to user utilities like -+ "broken update". End users should not see them. -+5. I did not find any consistent style and convention inside which -+ irritated me. -+6. I found it weird to introduce needless "logging infrastructure" instead -+ of just re-directing stdout and stderr to another file. -+7. I found the tool to be rather IBM-setup oriented. For example, the VID -+ header position was hard-coded. Some utilities were just weird, like -+ mkbootenv, which changed some ethernet addresses mentioned in a -+ configuration file. -+8. Finally, it was very difficult to realize what is pfi and pdd, what for, -+ why I need this transiant pfi file when I just want to create an UBI -+ image. There was zero documentation. -+ -+And so on. -+ -+Feb 19, 2008, Artem Bityutskiy. -+ -+[1]. http://lists.infradead.org/pipermail/linux-mtd/2007-December/020134.html ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,280 @@ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @file iniparser.h -+ @author N. Devillard -+ @date Sep 2007 -+ @version 3.0 -+ @brief Parser for ini files. -+*/ -+/*--------------------------------------------------------------------------*/ -+ -+/* -+ $Id: libiniparser.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Revision: 1.1.1.1 $ -+*/ -+ -+#ifndef _INIPARSER_H_ -+#define _INIPARSER_H_ -+ -+/*--------------------------------------------------------------------------- -+ Includes -+ ---------------------------------------------------------------------------*/ -+ -+#include -+#include -+#include -+ -+/* -+ * The following #include is necessary on many Unixes but not Linux. -+ * It is not needed for Windows platforms. -+ * Uncomment it if needed. -+ */ -+/* #include */ -+ -+#include "dictionary.h" -+ -+/*--------------------------------------------------------------------------- -+ Macros -+ ---------------------------------------------------------------------------*/ -+/** For backwards compatibility only */ -+#define iniparser_getstr(d, k) iniparser_getstring(d, k, NULL) -+#define iniparser_setstr iniparser_setstring -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get number of sections in a dictionary -+ @param d Dictionary to examine -+ @return int Number of sections found in dictionary -+ -+ This function returns the number of sections found in a dictionary. -+ The test to recognize sections is done on the string stored in the -+ dictionary: a section name is given as "section" whereas a key is -+ stored as "section:key", thus the test looks for entries that do not -+ contain a colon. -+ -+ This clearly fails in the case a section name contains a colon, but -+ this should simply be avoided. -+ -+ This function returns -1 in case of error. -+ */ -+/*--------------------------------------------------------------------------*/ -+ -+int iniparser_getnsec(dictionary * d); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get name for section n in a dictionary. -+ @param d Dictionary to examine -+ @param n Section number (from 0 to nsec-1). -+ @return Pointer to char string -+ -+ This function locates the n-th section in a dictionary and returns -+ its name as a pointer to a string statically allocated inside the -+ dictionary. Do not free or modify the returned string! -+ -+ This function returns NULL in case of error. -+ */ -+/*--------------------------------------------------------------------------*/ -+ -+char * iniparser_getsecname(dictionary * d, int n); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Save a dictionary to a loadable ini file -+ @param d Dictionary to dump -+ @param f Opened file pointer to dump to -+ @return void -+ -+ This function dumps a given dictionary into a loadable ini file. -+ It is Ok to specify @c stderr or @c stdout as output files. -+ */ -+/*--------------------------------------------------------------------------*/ -+ -+void iniparser_dump_ini(dictionary * d, FILE * f); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Dump a dictionary to an opened file pointer. -+ @param d Dictionary to dump. -+ @param f Opened file pointer to dump to. -+ @return void -+ -+ This function prints out the contents of a dictionary, one element by -+ line, onto the provided file pointer. It is OK to specify @c stderr -+ or @c stdout as output files. This function is meant for debugging -+ purposes mostly. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_dump(dictionary * d, FILE * f); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param def Default value to return if key not found. -+ @return pointer to statically allocated character string -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the pointer passed as 'def' is returned. -+ The returned char pointer is pointing to a string allocated in -+ the dictionary, do not free or modify it. -+ */ -+/*--------------------------------------------------------------------------*/ -+char * iniparser_getstring(dictionary * d, const char * key, char * def); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to an int -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return integer -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ -+ Supported values for integers include the usual C notation -+ so decimal, octal (starting with 0) and hexadecimal (starting with 0x) -+ are supported. Examples: -+ -+ - "42" -> 42 -+ - "042" -> 34 (octal -> decimal) -+ - "0x42" -> 66 (hexa -> decimal) -+ -+ Warning: the conversion may overflow in various ways. Conversion is -+ totally outsourced to strtol(), see the associated man page for overflow -+ handling. -+ -+ Credits: Thanks to A. Becker for suggesting strtol() -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_getint(dictionary * d, const char * key, int notfound); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to a double -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return double -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ */ -+/*--------------------------------------------------------------------------*/ -+double iniparser_getdouble(dictionary * d, char * key, double notfound); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to a boolean -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return integer -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ -+ A true boolean is found if one of the following is matched: -+ -+ - A string starting with 'y' -+ - A string starting with 'Y' -+ - A string starting with 't' -+ - A string starting with 'T' -+ - A string starting with '1' -+ -+ A false boolean is found if one of the following is matched: -+ -+ - A string starting with 'n' -+ - A string starting with 'N' -+ - A string starting with 'f' -+ - A string starting with 'F' -+ - A string starting with '0' -+ -+ The notfound value returned if no boolean is identified, does not -+ necessarily have to be 0 or 1. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_getboolean(dictionary * d, const char * key, int notfound); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Set an entry in a dictionary. -+ @param ini Dictionary to modify. -+ @param entry Entry to modify (entry name) -+ @param val New value to associate to the entry. -+ @return int 0 if Ok, -1 otherwise. -+ -+ If the given entry can be found in the dictionary, it is modified to -+ contain the provided value. If it cannot be found, -1 is returned. -+ It is Ok to set val to NULL. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_setstring(dictionary * ini, char * entry, char * val); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete an entry in a dictionary -+ @param ini Dictionary to modify -+ @param entry Entry to delete (entry name) -+ @return void -+ -+ If the given entry can be found, it is deleted from the dictionary. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_unset(dictionary * ini, char * entry); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Finds out if a given entry exists in a dictionary -+ @param ini Dictionary to search -+ @param entry Name of the entry to look for -+ @return integer 1 if entry exists, 0 otherwise -+ -+ Finds out if a given entry exists in the dictionary. Since sections -+ are stored as keys with NULL associated values, this is the only way -+ of querying for the presence of sections in a dictionary. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_find_entry(dictionary * ini, char * entry) ; -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Parse an ini file and return an allocated dictionary object -+ @param ininame Name of the ini file to read. -+ @return Pointer to newly allocated dictionary -+ -+ This is the parser for ini files. This function is called, providing -+ the name of the file to be read. It returns a dictionary object that -+ should not be accessed directly, but through accessor functions -+ instead. -+ -+ The returned dictionary must be freed using iniparser_freedict(). -+ */ -+/*--------------------------------------------------------------------------*/ -+dictionary * iniparser_load(const char * ininame); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Free all memory associated to an ini dictionary -+ @param d Dictionary to free -+ @return void -+ -+ Free all memory associated to an ini dictionary. -+ It is mandatory to call this function before the dictionary object -+ gets out of the current context. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_freedict(dictionary * d); -+ -+#endif ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,73 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * MTD library. -+ */ -+ -+#ifndef __LIBMTD_H__ -+#define __LIBMTD_H__ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** -+ * struct mtd_info - information about an MTD device. -+ * @num: MTD device number -+ * @major: major number of corresponding character device -+ * @minor: minor number of corresponding character device -+ * @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h) -+ * @type_str: static R/O flash type string -+ * @size: device size in bytes -+ * @eb_cnt: count of eraseblocks -+ * @eb_size: eraseblock size -+ * @min_io_size: minimum input/output unit size -+ * @subpage_size: sub-page size (not set by 'mtd_get_info()'!!!) -+ * @rdonly: non-zero if the device is read-only -+ * @allows_bb: non-zero if the MTD device may have bad eraseblocks -+ * @fd: descriptor of the opened MTD character device node -+ */ -+struct mtd_info -+{ -+ int num; -+ int major; -+ int minor; -+ int type; -+ const char *type_str; -+ long long size; -+ int eb_cnt; -+ int eb_size; -+ int min_io_size; -+ int subpage_size; -+ unsigned int rdonly:1; -+ unsigned int allows_bb:1; -+ int fd; -+}; -+ -+int mtd_get_info(const char *node, struct mtd_info *mtd); -+int mtd_erase(const struct mtd_info *mtd, int eb); -+int mtd_is_bad(const struct mtd_info *mtd, int eb); -+int mtd_read(const struct mtd_info *mtd, int eb, int offs, void *buf, int len); -+int mtd_write(const struct mtd_info *mtd, int eb, int offs, void *buf, int len); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* __LIBMTD_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,112 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * UBI scanning library. -+ */ -+ -+#ifndef __LIBSCAN_H__ -+#define __LIBSCAN_H__ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * If an eraseblock does not contain an erase counter, this value is used -+ * instead of the erase counter. -+ */ -+#define NO_EC 0xFFFFFFFF -+ -+/* -+ * If an eraseblock contains a corrupted erase counter, this value is used -+ * instead of the erase counter. -+ */ -+#define CORRUPT_EC 0xFFFFFFFE -+ -+/* -+ * If an eraseblock does not contain an erase counter, one of these values is -+ * used. -+ * -+ * @EB_EMPTY: the eraseblock appeared to be empty -+ * @EB_CORRUPTED: the eraseblock contains corrupted erase counter header -+ * @EB_ALIEN: the eraseblock contains some non-UBI data -+ * @EC_MAX: maximum allowed erase counter value -+ */ -+enum -+{ -+ EB_EMPTY = 0xFFFFFFFF, -+ EB_CORRUPTED = 0xFFFFFFFE, -+ EB_ALIEN = 0xFFFFFFFD, -+ EB_BAD = 0xFFFFFFFC, -+ EC_MAX = UBI_MAX_ERASECOUNTER, -+}; -+ -+/** -+ * struct ubi_scan_info - UBI scanning information. -+ * @ec: erase counters or eraseblock status for all eraseblocks -+ * @mean_ec: mean erase counter -+ * @ok_cnt: count of eraseblock with correct erase counter header -+ * @empty_cnt: count of supposedly eraseblocks -+ * @corrupted_cnt: count of eraseblocks with corrupted erase counter header -+ * @alien_cnt: count of eraseblock containing non-ubi data -+ * @bad_cnt: count of bad eraseblocks -+ * @bad_cnt: count of non-bad eraseblocks -+ * @vid_hdr_offs: volume ID header offset from the found EC headers (%-1 means -+ * undefined) -+ * @data_offs: data offset from the found EC headers (%-1 means undefined) -+ */ -+struct ubi_scan_info -+{ -+ uint32_t *ec; -+ long long mean_ec; -+ int ok_cnt; -+ int empty_cnt; -+ int corrupted_cnt; -+ int alien_cnt; -+ int bad_cnt; -+ int good_cnt; -+ int vid_hdr_offs; -+ int data_offs; -+}; -+ -+struct mtd_info; -+ -+/** -+ * ubi_scan - scan an MTD device. -+ * @mtd: information about the MTD device to scan -+ * @info: the result of the scanning is returned here -+ * @verbose: verbose mode: %0 - be silent, %1 - output progress information, -+ * 2 - debugging output mode -+ */ -+int ubi_scan(struct mtd_info *mtd, struct ubi_scan_info **info, int verbose); -+ -+/** -+ * ubi_scan_free - free scanning information. -+ * @si: scanning information to free -+ */ -+void ubi_scan_free(struct ubi_scan_info *si); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* __LIBSCAN_H__ */ -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,382 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#ifndef __LIBUBI_H__ -+#define __LIBUBI_H__ -+ -+#include -+#include -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* UBI version libubi is made for */ -+#define LIBUBI_UBI_VERSION 1 -+ -+/* UBI library descriptor */ -+typedef void * libubi_t; -+ -+/** -+ * struct ubi_attach_request - MTD device attachement request. -+ * @dev_num: number to assigne to the newly created UBI device -+ * (%UBI_DEV_NUM_AUTO should be used to automatically assign the -+ * number) -+ * @mtd_num: MTD device number to attach -+ * @vid_hdr_offset: VID header offset (%0 means default offset and this is what -+ * most of the users want) -+ */ -+struct ubi_attach_request -+{ -+ int dev_num; -+ int mtd_num; -+ int vid_hdr_offset; -+}; -+ -+/** -+ * struct ubi_mkvol_request - volume creation request. -+ * @vol_id: ID to assign to the new volume (%UBI_VOL_NUM_AUTO should be used to -+ * automatically assign ID) -+ * @alignment: volume alignment -+ * @bytes: volume size in bytes -+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @name: volume name -+ */ -+struct ubi_mkvol_request -+{ -+ int vol_id; -+ int alignment; -+ long long bytes; -+ int vol_type; -+ const char *name; -+}; -+ -+/** -+ * struct ubi_info - general UBI information. -+ * @dev_count: count of UBI devices in system -+ * @lowest_dev_num: lowest UBI device number -+ * @highest_dev_num: highest UBI device number -+ * @version: UBI version -+ * @ctrl_major: major number of the UBI control device -+ * @ctrl_minor: minor number of the UBI control device -+ */ -+struct ubi_info -+{ -+ int dev_count; -+ int lowest_dev_num; -+ int highest_dev_num; -+ int version; -+ int ctrl_major; -+ int ctrl_minor; -+}; -+ -+/** -+ * struct ubi_dev_info - UBI device information. -+ * @vol_count: count of volumes on this UBI device -+ * @lowest_vol_num: lowest volume number -+ * @highest_vol_num: highest volume number -+ * @major: major number of corresponding character device -+ * @minor: minor number of corresponding character device -+ * @total_lebs: total number of logical eraseblocks on this UBI device -+ * @avail_lebs: how many logical eraseblocks are not used and available for new -+ * volumes -+ * @total_bytes: @total_lebs * @leb_size -+ * @avail_bytes: @avail_lebs * @leb_size -+ * @bad_count: count of bad physical eraseblocks -+ * @leb_size: logical eraseblock size -+ * @max_ec: current highest erase counter value -+ * @bad_rsvd: how many physical eraseblocks of the underlying flash device are -+ * reserved for bad eraseblocks handling -+ * @max_vol_count: maximum possible number of volumes on this UBI device -+ * @min_io_size: minimum input/output unit size of the UBI device -+ */ -+struct ubi_dev_info -+{ -+ int dev_num; -+ int vol_count; -+ int lowest_vol_num; -+ int highest_vol_num; -+ int major; -+ int minor; -+ int total_lebs; -+ int avail_lebs; -+ long long total_bytes; -+ long long avail_bytes; -+ int bad_count; -+ int leb_size; -+ long long max_ec; -+ int bad_rsvd; -+ int max_vol_count; -+ int min_io_size; -+}; -+ -+/** -+ * struct ubi_vol_info - UBI volume information. -+ * @dev_num: UBI device number the volume resides on -+ * @vol_id: ID of this volume -+ * @major: major number of corresponding volume character device -+ * @minor: minor number of corresponding volume character device -+ * @dev_major: major number of corresponding UBI device character device -+ * @dev_minor: minor number of corresponding UBI device character device -+ * @type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @alignment: alignemnt of this volume -+ * @data_bytes: how many data bytes are stored on this volume (equivalent to -+ * @rsvd_bytes for dynamic volumes) -+ * @rsvd_bytes: how many bytes are reserved for this volume -+ * @rsvd_lebs: how many logical eraseblocks are reserved for this volume -+ * @leb_size: logical eraseblock size of this volume (may be less then -+ * device's logical eraseblock size due to alignment) -+ * @corrupted: non-zero if the volume is corrupted -+ * @name: volume name (null-terminated) -+ */ -+struct ubi_vol_info -+{ -+ int dev_num; -+ int vol_id; -+ int major; -+ int minor; -+ int dev_major; -+ int dev_minor; -+ int type; -+ int alignment; -+ long long data_bytes; -+ long long rsvd_bytes; -+ int rsvd_lebs; -+ int leb_size; -+ int corrupted; -+ char name[UBI_VOL_NAME_MAX + 1]; -+}; -+ -+/** -+ * libubi_open - open UBI library. -+ * @required: if non-zero, libubi will print an error messages if this UBI is -+ * not present in the system -+ * -+ * This function initializes and opens the UBI library and returns UBI library -+ * descriptor in case of success and %NULL in case of failure. -+ */ -+libubi_t libubi_open(int required); -+ -+/** -+ * libubi_close - close UBI library. -+ * @desc UBI library descriptor -+ */ -+void libubi_close(libubi_t desc); -+ -+/** -+ * ubi_get_info - get general UBI information. -+ * @desc: UBI library descriptor -+ * @info: pointer to the &struct ubi_info object to fill -+ * -+ * This function fills the passed @info object with general UBI information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_info(libubi_t desc, struct ubi_info *info); -+ -+/** -+ * mtd_num2ubi_dev - find UBI device by attached MTD device. -+ * @@desc: UBI library descriptor -+ * @mtd_num: MTD device number -+ * @dev_num: UBI device number is returned here -+ * -+ * This function finds UBI device to which MTD device @mtd_num is attached. -+ * Returns %0 if the UBI device was found and %-1 if not. -+ */ -+int mtd_num2ubi_dev(libubi_t desc, int mtd_num, int *dev_num); -+ -+/** -+ * ubi_attach_mtd - attach MTD device to UBI. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI control character device node -+ * @req: MTD attach request. -+ * -+ * This function creates a new UBI device by attaching an MTD device as -+ * described by @req. Returns %0 in case of success and %-1 in case of failure. -+ * The newly created UBI device number is returned in @req->dev_num. -+ */ -+int ubi_attach_mtd(libubi_t desc, const char *node, -+ struct ubi_attach_request *req); -+ -+/** -+ * ubi_detach_mtd - detach an MTD device. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI control character device node -+ * @mtd_num: MTD device number to detach -+ * -+ * This function detaches MTD device number @mtd_num from UBI, which means the -+ * corresponding UBI device is removed. Returns zero in case of success and %-1 -+ * in case of failure. -+ */ -+int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num); -+ -+/** -+ * ubi_remove_dev - remove an UBI device. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI control character device node -+ * @ubi_dev: UBI device number to remove -+ * -+ * This function removes UBI device number @ubi_dev and returns zero in case of -+ * success and %-1 in case of failure. -+ */ -+int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev); -+ -+/** -+ * ubi_mkvol - create an UBI volume. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI character device to create a volume at -+ * @req: UBI volume creation request -+ * -+ * This function creates a UBI volume as described at @req and returns %0 in -+ * case of success and %-1 in case of failure. The assigned volume ID is -+ * returned in @req->vol_id. -+ */ -+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req); -+ -+/** -+ * ubi_rmvol - remove a UBI volume. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI character device to remove a volume from -+ * @vol_id: ID of the volume to remove -+ * -+ * This function removes volume @vol_id from UBI device @node and returns %0 in -+ * case of success and %-1 in case of failure. -+ */ -+int ubi_rmvol(libubi_t desc, const char *node, int vol_id); -+ -+/** -+ * ubi_rsvol - re-size UBI volume. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI character device owning the volume which should be -+ * re-sized -+ * @vol_id: volume ID to re-size -+ * @bytes: new volume size in bytes -+ * -+ * This function returns %0 in case of success and %-1 in case of error. -+ */ -+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes); -+ -+/** -+ * ubi_node_type - test UBI node type. -+ * @desc: UBI library descriptor -+ * @node: the node to test -+ * -+ * This function tests whether @node is a UBI device or volume node and returns -+ * %1 if this is an UBI device node, %2 if this is a volume node, and %-1 if -+ * this is not an UBI node or if an error occurred (the latter is indicated by -+ * a non-zero errno). -+ */ -+int ubi_node_type(libubi_t desc, const char *node); -+ -+/** -+ * ubi_get_dev_info - get UBI device information. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI character device to fetch information about -+ * @info: pointer to the &struct ubi_dev_info object to fill -+ * -+ * This function fills the passed @info object with UBI device information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_dev_info(libubi_t desc, const char *node, -+ struct ubi_dev_info *info); -+ -+/** -+ * ubi_get_dev_info1 - get UBI device information. -+ * @desc: UBI library descriptor -+ * @dev_num: UBI device number to fetch information about -+ * @info: pointer to the &struct ubi_dev_info object to fill -+ * -+ * This function is identical to 'ubi_get_dev_info()' except that it accepts UBI -+ * device number, not UBI character device. -+ */ -+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info); -+ -+/** -+ * ubi_get_vol_info - get UBI volume information. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI volume character device to fetch information about -+ * @info: pointer to the &struct ubi_vol_info object to fill -+ * -+ * This function fills the passed @info object with UBI volume information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_vol_info(libubi_t desc, const char *node, -+ struct ubi_vol_info *info); -+ -+/** -+ * ubi_get_vol_info1 - get UBI volume information. -+ * @desc: UBI library descriptor -+ * @dev_num: UBI device number -+ * @vol_id: ID of the UBI volume to fetch information about -+ * @info: pointer to the &struct ubi_vol_info object to fill -+ * -+ * This function is identical to 'ubi_get_vol_info()' except that it accepts UBI -+ * volume number, not UBI volume character device. -+ */ -+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, -+ struct ubi_vol_info *info); -+ -+/** -+ * ubi_update_start - start UBI volume update. -+ * @desc: UBI library descriptor -+ * @fd: volume character devie file descriptor -+ * @bytes: how many bytes will be written to the volume -+ * -+ * This function initiates UBI volume update and returns %0 in case of success -+ * and %-1 in case of error. The caller is assumed to write @bytes data to the -+ * volume @fd afterwards. -+ */ -+int ubi_update_start(libubi_t desc, int fd, long long bytes); -+ -+ -+/** -+ * ubi_leb_read_start -+ * @fd: volume character devie file descriptor -+ * @leb: structure pointer for volume dump request -+ * -+ * This function call "UBI_IOCLEBREAD" ioctl. -+ * return %1 means the LEB is not mapped, no need to dump -+ * return %0 LEB read done successful -+ * return any others error -+ */ -+int ubi_leb_read_start(int fd, struct ubi_leb *leb); -+ -+/** -+ * ubi_leb_change_start - start atomic LEB change. -+ * @desc: UBI library descriptor -+ * @fd: volume character devie file descriptor -+ * @lnum: LEB number to change -+ * @bytes: how many bytes of new data will be written to the LEB -+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN) -+ * -+ * This function initiates atomic LEB change operation and returns %0 in case -+ * of success and %-1 in case of error. he caller is assumed to write @bytes -+ * data to the volume @fd afterwards. -+ */ -+int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes, int dtype); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__LIBUBI_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,110 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Authors: Frank Haverkamp -+ * Artem Bityutskiy -+ */ -+ -+#ifndef __LIBUBIGEN_H__ -+#define __LIBUBIGEN_H__ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** -+ * struct ubigen_info - libubigen information. -+ * @leb_size: logical eraseblock size -+ * @peb_size: size of the physical eraseblock -+ * @min_io_size: minimum input/output unit size -+ * @vid_hdr_offs: offset of the VID header -+ * @data_offs: data offset -+ * @ubi_ver: UBI version -+ * @vtbl_size: volume table size -+ * @max_volumes: maximum amount of volumes -+ */ -+struct ubigen_info -+{ -+ int leb_size; -+ int peb_size; -+ int min_io_size; -+ int vid_hdr_offs; -+ int data_offs; -+ int ubi_ver; -+ int vtbl_size; -+ int max_volumes; -+}; -+ -+/** -+ * struct ubigen_vol_info - information about a volume. -+ * @id: volume id -+ * @type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) -+ * @alignment: volume alignment -+ * @data_pad: how many bytes are unused at the end of the each physical -+ * eraseblock to satisfy the requested alignment -+ * @usable_leb_size: LEB size accessible for volume users -+ * @name: volume name -+ * @name_len: volume name length -+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, -+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) -+ * @used_ebs: total number of used logical eraseblocks in this volume (relevant -+ * for static volumes only) -+ * @bytes: size of the volume contents in bytes (relevant for static volumes -+ * only) -+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) -+ */ -+struct ubigen_vol_info -+{ -+ int id; -+ int type; -+ int alignment; -+ int data_pad; -+ int usable_leb_size; -+ const char *name; -+ int name_len; -+ int compat; -+ int used_ebs; -+ long long bytes; -+ uint8_t flags; -+}; -+ -+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size, -+ int subpage_size, int vid_hdr_offs, int ubi_ver); -+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui); -+void ubigen_init_ec_hdr(const struct ubigen_info *ui, -+ struct ubi_ec_hdr *hdr, long long ec); -+int ubigen_get_vtbl_size(const struct ubigen_info *ui); -+int ubigen_add_volume(const struct ubigen_info *ui, -+ const struct ubigen_vol_info *vi, -+ struct ubi_vtbl_record *vtbl); -+int ubigen_write_volume(const struct ubigen_info *ui, -+ const struct ubigen_vol_info *vi, long long ec, -+ long long bytes, int in, int out); -+int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2, -+ long long ec1, long long ec2, -+ struct ubi_vtbl_record *vtbl, int fd); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__LIBUBIGEN_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,194 @@ -+/* -+ * Copyright (C) 2007, 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * This file contains various common stuff used by UBI utilities. -+ * -+ * Authors: Artem Bityutskiy -+ * Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+ -+/** -+ * get_multiplier - convert size specifier to an integer multiplier. -+ * @str: the size specifier string -+ * -+ * This function parses the @str size specifier, which may be one of -+ * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive -+ * size multiplier in case of success and %-1 in case of failure. -+ */ -+static int get_multiplier(const char *str) -+{ -+ if (!str) -+ return 1; -+ -+ /* Remove spaces before the specifier */ -+ while (*str == ' ' || *str == '\t') -+ str += 1; -+ -+ if (!strcmp(str, "KiB")) -+ return 1024; -+ if (!strcmp(str, "MiB")) -+ return 1024 * 1024; -+ if (!strcmp(str, "GiB")) -+ return 1024 * 1024 * 1024; -+ -+ /* Handle deprecated stuff */ -+ if (!strcmp(str, "KB") || !strcmp(str, "Kib") || !strcmp(str, "kib") || -+ !strcmp(str, "kiB")) { -+ fprintf(stderr, "Warning: use \"KiB\" instead of \"%s\" to " -+ "specify Kilobytes - support will be removed\n", str); -+ return 1024; -+ } -+ if (!strcmp(str, "MB") || !strcmp(str, "Mib") || !strcmp(str, "mb")) { -+ fprintf(stderr, "Warning: use \"MiB\" instead of \"%s\", " -+ "this support will be removed\n", str); -+ return 1024*1024; -+ } -+ if (!strcmp(str, "GB") || !strcmp(str, "Gib") || !strcmp(str, "gb")) { -+ fprintf(stderr, "Warning: use \"GiB\" instead of \"%s\", " -+ "this support will be removed\n", str); -+ return 1024*1024*1024; -+ } -+ -+ return -1; -+} -+ -+/** -+ * ubiutils_get_bytes - convert a string containing amount of bytes into an -+ * integer -+ * @str: string to convert -+ * -+ * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB' -+ * size specifiers. Returns positive amount of bytes in case of success and %-1 -+ * in case of failure. -+ */ -+long long ubiutils_get_bytes(const char *str) -+{ -+ char *endp; -+ long long bytes = strtoull(str, &endp, 0); -+ -+ if (endp == str || bytes < 0) { -+ fprintf(stderr, "incorrect amount of bytes: \"%s\"\n", str); -+ return -1; -+ } -+ -+ if (*endp != '\0') { -+ int mult = get_multiplier(endp); -+ -+ if (mult == -1) { -+ fprintf(stderr, "bad size specifier: \"%s\" - " -+ "should be 'KiB', 'MiB' or 'GiB'\n", endp); -+ return -1; -+ } -+ bytes *= mult; -+ } -+ -+ return bytes; -+} -+ -+/** -+ * ubiutils_print_bytes - print bytes. -+ * @bytes: variable to print -+ * @bracket: whether brackets have to be put or not -+ * -+ * This is a helper function which prints amount of bytes in a human-readable -+ * form, i.e., it prints the exact amount of bytes following by the approximate -+ * amount of Kilobytes, Megabytes, or Gigabytes, depending on how big @bytes -+ * is. -+ */ -+void ubiutils_print_bytes(long long bytes, int bracket) -+{ -+ const char *p; -+ -+ if (bracket) -+ p = " ("; -+ else -+ p = ", "; -+ -+ printf("%lld bytes", bytes); -+ -+ if (bytes > 1024 * 1024 * 1024) -+ printf("%s%.1f GiB", p, (double)bytes / (1024 * 1024 * 1024)); -+ else if (bytes > 1024 * 1024) -+ printf("%s%.1f MiB", p, (double)bytes / (1024 * 1024)); -+ else if (bytes > 1024 && bytes != 0) -+ printf("%s%.1f KiB", p, (double)bytes / 1024); -+ else -+ return; -+ -+ if (bracket) -+ printf(")"); -+} -+ -+/** -+ * ubiutils_print_text - print text and fold it. -+ * @stream: file stream to print to -+ * @text: text to print -+ * @width: maximum allowed text width -+ * -+ * Print text and fold it so that each line would not have more then @width -+ * characters. -+ */ -+void ubiutils_print_text(FILE *stream, const char *text, int width) -+{ -+ int pos, bpos = 0; -+ const char *p; -+ char line[1024]; -+ -+ if (width > 1023) { -+ fprintf(stream, "%s\n", text); -+ return; -+ } -+ p = text; -+ pos = 0; -+ while (p[pos]) { -+ while (!isspace(p[pos])) { -+ line[pos] = p[pos]; -+ if (!p[pos]) -+ break; -+ ++pos; -+ if (pos == width) { -+ line[pos] = '\0'; -+ fprintf(stream, "%s\n", line); -+ p += pos; -+ pos = 0; -+ } -+ } -+ while (pos < width) { -+ line[pos] = p[pos]; -+ if (!p[pos]) { -+ bpos = pos; -+ break; -+ } -+ if (isspace(p[pos])) -+ bpos = pos; -+ ++pos; -+ } -+ line[bpos] = '\0'; -+ fprintf(stream, "%s\n", line); -+ p += bpos; -+ pos = 0; -+ while (p[pos] && isspace(p[pos])) -+ ++p; -+ } -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,84 @@ -+/* -+ * Copyright (c) Artem Bityutskiy, 2007, 2008 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#ifndef __UBI_UTILS_COMMON_H__ -+#define __UBI_UTILS_COMMON_H__ -+ -+#include -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#define MIN(a ,b) ((a) < (b) ? (a) : (b)) -+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -+ -+/* Verbose messages */ -+#define verbose(verbose, fmt, ...) do { \ -+ if (verbose) \ -+ printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \ -+} while(0) -+ -+/* Normal messages */ -+#define normsg(fmt, ...) do { \ -+ printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \ -+} while(0) -+#define normsg_cont(fmt, ...) do { \ -+ printf(PROGRAM_NAME ": " fmt, ##__VA_ARGS__); \ -+} while(0) -+#define normsg_cont(fmt, ...) do { \ -+ printf(PROGRAM_NAME ": " fmt, ##__VA_ARGS__); \ -+} while(0) -+ -+/* Error messages */ -+#define errmsg(fmt, ...) ({ \ -+ fprintf(stderr, PROGRAM_NAME ": error!: " fmt "\n", ##__VA_ARGS__); \ -+ -1; \ -+}) -+ -+/* System error messages */ -+#define sys_errmsg(fmt, ...) ({ \ -+ int _err = errno, _i; \ -+ fprintf(stderr, PROGRAM_NAME ": error!: " fmt "\n", ##__VA_ARGS__); \ -+ for (_i = 0; _i < sizeof(PROGRAM_NAME) + 1; _i++) \ -+ fprintf(stderr, " "); \ -+ fprintf(stderr, "error %d (%s)\n", _err, strerror(_err)); \ -+ -1; \ -+}) -+ -+/* Warnings */ -+#define warnmsg(fmt, ...) do { \ -+ fprintf(stderr, PROGRAM_NAME ": warning!: " fmt "\n", ##__VA_ARGS__); \ -+} while(0) -+ -+static inline int is_power_of_2(unsigned long long n) -+{ -+ return (n != 0 && ((n & (n - 1)) == 0)); -+} -+ -+long long ubiutils_get_bytes(const char *str); -+void ubiutils_print_bytes(long long bytes, int bracket); -+void ubiutils_print_text(FILE *stream, const char *txt, int len); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__UBI_UTILS_COMMON_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,95 @@ -+/* -+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or -+ * code or tables extracted from it, as desired without restriction. -+ * -+ * First, the polynomial itself and its table of feedback terms. The -+ * polynomial is -+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 -+ * -+ * Note that we take it "backwards" and put the highest-order term in -+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the -+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in -+ * the MSB being 1 -+ * -+ * Note that the usual hardware shift register implementation, which -+ * is what we're using (we're merely optimizing it by doing eight-bit -+ * chunks at a time) shifts bits into the lowest-order term. In our -+ * implementation, that means shifting towards the right. Why do we -+ * do it this way? Because the calculated CRC must be transmitted in -+ * order from highest-order term to lowest-order term. UARTs transmit -+ * characters in order from LSB to MSB. By storing the CRC this way -+ * we hand it to the UART in the order low-byte to high-byte; the UART -+ * sends each low-bit to hight-bit; and the result is transmission bit -+ * by bit from highest- to lowest-order term without requiring any bit -+ * shuffling on our part. Reception works similarly -+ * -+ * The feedback terms table consists of 256, 32-bit entries. Notes -+ * -+ * The table can be generated at runtime if desired; code to do so -+ * is shown later. It might not be obvious, but the feedback -+ * terms simply represent the results of eight shift/xor opera -+ * tions for all combinations of data and CRC register values -+ * -+ * The values must be right-shifted by eight bits by the "updcrc -+ * logic; the shift must be unsigned (bring in zeroes). On some -+ * hardware you could probably optimize the shift in assembler by -+ * using byte-swap instructions -+ * polynomial $edb88320 -+ */ -+ -+#include -+ -+const uint32_t crc32_table[256] = { -+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, -+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, -+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, -+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, -+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, -+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, -+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, -+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, -+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, -+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, -+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, -+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, -+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, -+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, -+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, -+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, -+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, -+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, -+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, -+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, -+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, -+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, -+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, -+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, -+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, -+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, -+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, -+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, -+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, -+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, -+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, -+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, -+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, -+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, -+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, -+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, -+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, -+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, -+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, -+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, -+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, -+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, -+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, -+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, -+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, -+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, -+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, -+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, -+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, -+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, -+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, -+ 0x2d02ef8dL -+}; ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,19 @@ -+#ifndef CRC32_H -+#define CRC32_H -+ -+#include -+ -+extern const uint32_t crc32_table[256]; -+ -+/* Return a 32-bit CRC of the contents of the buffer. */ -+ -+ static inline uint32_t -+crc32(uint32_t val, const void *ss, int len) -+{ -+ const unsigned char *s = ss; -+ while (--len >= 0) -+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); -+ return val; -+} -+ -+#endif ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,405 @@ -+/*-------------------------------------------------------------------------*/ -+/** -+ @file dictionary.c -+ @author N. Devillard -+ @date Sep 2007 -+ @version $Revision: 1.1.1.1 $ -+ @brief Implements a dictionary for string variables. -+ -+ This module implements a simple dictionary object, i.e. a list -+ of string/string associations. This object is useful to store e.g. -+ informations retrieved from a configuration file (ini files). -+*/ -+/*--------------------------------------------------------------------------*/ -+ -+/* -+ $Id: dictionary.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Revision: 1.1.1.1 $ -+*/ -+/*--------------------------------------------------------------------------- -+ Includes -+ ---------------------------------------------------------------------------*/ -+#include "dictionary.h" -+ -+#include -+#include -+#include -+#include -+ -+/** Maximum value size for integers and doubles. */ -+#define MAXVALSZ 1024 -+ -+/** Minimal allocated number of entries in a dictionary */ -+#define DICTMINSZ 128 -+ -+/** Invalid key token */ -+#define DICT_INVALID_KEY ((char*)-1) -+ -+/*--------------------------------------------------------------------------- -+ Private functions -+ ---------------------------------------------------------------------------*/ -+ -+/* Doubles the allocated size associated to a pointer */ -+/* 'size' is the current allocated size. */ -+static void * mem_double(void * ptr, int size) -+{ -+ void * newptr ; -+ -+ newptr = calloc(2*size, 1); -+ if (newptr==NULL) { -+ return NULL ; -+ } -+ memcpy(newptr, ptr, size); -+ free(ptr); -+ return newptr ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Duplicate a string -+ @param s String to duplicate -+ @return Pointer to a newly allocated string, to be freed with free() -+ -+ This is a replacement for strdup(). This implementation is provided -+ for systems that do not have it. -+ */ -+/*--------------------------------------------------------------------------*/ -+static char * xstrdup(char * s) -+{ -+ char * t ; -+ if (!s) -+ return NULL ; -+ t = malloc(strlen(s)+1) ; -+ if (t) { -+ strcpy(t,s); -+ } -+ return t ; -+} -+ -+/*--------------------------------------------------------------------------- -+ Function codes -+ ---------------------------------------------------------------------------*/ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Compute the hash key for a string. -+ @param key Character string to use for key. -+ @return 1 unsigned int on at least 32 bits. -+ -+ This hash function has been taken from an Article in Dr Dobbs Journal. -+ This is normally a collision-free function, distributing keys evenly. -+ The key is stored anyway in the struct so that collision can be avoided -+ by comparing the key itself in last resort. -+ */ -+/*--------------------------------------------------------------------------*/ -+unsigned dictionary_hash(char * key) -+{ -+ int len ; -+ unsigned hash ; -+ int i ; -+ -+ len = strlen(key); -+ for (hash=0, i=0 ; i>6) ; -+ } -+ hash += (hash <<3); -+ hash ^= (hash >>11); -+ hash += (hash <<15); -+ return hash ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Create a new dictionary object. -+ @param size Optional initial size of the dictionary. -+ @return 1 newly allocated dictionary objet. -+ -+ This function allocates a new dictionary object of given size and returns -+ it. If you do not know in advance (roughly) the number of entries in the -+ dictionary, give size=0. -+ */ -+/*--------------------------------------------------------------------------*/ -+dictionary * dictionary_new(int size) -+{ -+ dictionary * d ; -+ -+ /* If no size was specified, allocate space for DICTMINSZ */ -+ if (sizesize = size ; -+ d->val = (char **)calloc(size, sizeof(char*)); -+ d->key = (char **)calloc(size, sizeof(char*)); -+ d->hash = (unsigned int *)calloc(size, sizeof(unsigned)); -+ return d ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete a dictionary object -+ @param d dictionary object to deallocate. -+ @return void -+ -+ Deallocate a dictionary object and all memory associated to it. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_del(dictionary * d) -+{ -+ int i ; -+ -+ if (d==NULL) return ; -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]!=NULL) -+ free(d->key[i]); -+ if (d->val[i]!=NULL) -+ free(d->val[i]); -+ } -+ free(d->val); -+ free(d->key); -+ free(d->hash); -+ free(d); -+ return ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get a value from a dictionary. -+ @param d dictionary object to search. -+ @param key Key to look for in the dictionary. -+ @param def Default value to return if key not found. -+ @return 1 pointer to internally allocated character string. -+ -+ This function locates a key in a dictionary and returns a pointer to its -+ value, or the passed 'def' pointer if no such key can be found in -+ dictionary. The returned character pointer points to data internal to the -+ dictionary object, you should not try to free it or modify it. -+ */ -+/*--------------------------------------------------------------------------*/ -+char * dictionary_get(dictionary * d, char * key, char * def) -+{ -+ unsigned hash ; -+ int i ; -+ -+ hash = dictionary_hash(key); -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ /* Compare hash */ -+ if (hash==d->hash[i]) { -+ /* Compare string, to avoid hash collisions */ -+ if (!strcmp(key, d->key[i])) { -+ return d->val[i] ; -+ } -+ } -+ } -+ return def ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Set a value in a dictionary. -+ @param d dictionary object to modify. -+ @param key Key to modify or add. -+ @param val Value to add. -+ @return int 0 if Ok, anything else otherwise -+ -+ If the given key is found in the dictionary, the associated value is -+ replaced by the provided one. If the key cannot be found in the -+ dictionary, it is added to it. -+ -+ It is Ok to provide a NULL value for val, but NULL values for the dictionary -+ or the key are considered as errors: the function will return immediately -+ in such a case. -+ -+ Notice that if you dictionary_set a variable to NULL, a call to -+ dictionary_get will return a NULL value: the variable will be found, and -+ its value (NULL) is returned. In other words, setting the variable -+ content to NULL is equivalent to deleting the variable from the -+ dictionary. It is not possible (in this implementation) to have a key in -+ the dictionary without value. -+ -+ This function returns non-zero in case of failure. -+ */ -+/*--------------------------------------------------------------------------*/ -+int dictionary_set(dictionary * d, char * key, char * val) -+{ -+ int i ; -+ unsigned hash ; -+ -+ if (d==NULL || key==NULL) return -1 ; -+ -+ /* Compute hash for this key */ -+ hash = dictionary_hash(key) ; -+ /* Find if value is already in dictionary */ -+ if (d->n>0) { -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ if (hash==d->hash[i]) { /* Same hash value */ -+ if (!strcmp(key, d->key[i])) { /* Same key */ -+ /* Found a value: modify and return */ -+ if (d->val[i]!=NULL) -+ free(d->val[i]); -+ d->val[i] = val ? xstrdup(val) : NULL ; -+ /* Value has been modified: return */ -+ return 0 ; -+ } -+ } -+ } -+ } -+ /* Add a new value */ -+ /* See if dictionary needs to grow */ -+ if (d->n==d->size) { -+ -+ /* Reached maximum size: reallocate dictionary */ -+ d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ; -+ d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ; -+ d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ; -+ if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) { -+ /* Cannot grow dictionary */ -+ return -1 ; -+ } -+ /* Double size */ -+ d->size *= 2 ; -+ } -+ -+ /* Insert key in the first empty slot */ -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) { -+ /* Add key here */ -+ break ; -+ } -+ } -+ /* Copy key */ -+ d->key[i] = xstrdup(key); -+ d->val[i] = val ? xstrdup(val) : NULL ; -+ d->hash[i] = hash; -+ d->n ++ ; -+ return 0 ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete a key in a dictionary -+ @param d dictionary object to modify. -+ @param key Key to remove. -+ @return void -+ -+ This function deletes a key in a dictionary. Nothing is done if the -+ key cannot be found. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_unset(dictionary * d, char * key) -+{ -+ unsigned hash ; -+ int i ; -+ -+ if (key == NULL) { -+ return; -+ } -+ -+ hash = dictionary_hash(key); -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ /* Compare hash */ -+ if (hash==d->hash[i]) { -+ /* Compare string, to avoid hash collisions */ -+ if (!strcmp(key, d->key[i])) { -+ /* Found key */ -+ break ; -+ } -+ } -+ } -+ if (i>=d->size) -+ /* Key not found */ -+ return ; -+ -+ free(d->key[i]); -+ d->key[i] = NULL ; -+ if (d->val[i]!=NULL) { -+ free(d->val[i]); -+ d->val[i] = NULL ; -+ } -+ d->hash[i] = 0 ; -+ d->n -- ; -+ return ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Dump a dictionary to an opened file pointer. -+ @param d Dictionary to dump -+ @param f Opened file pointer. -+ @return void -+ -+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out -+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as -+ output file pointers. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_dump(dictionary * d, FILE * out) -+{ -+ int i ; -+ -+ if (d==NULL || out==NULL) return ; -+ if (d->n<1) { -+ fprintf(out, "empty dictionary\n"); -+ return ; -+ } -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]) { -+ fprintf(out, "%20s\t[%s]\n", -+ d->key[i], -+ d->val[i] ? d->val[i] : "UNDEF"); -+ } -+ } -+ return ; -+} -+ -+ -+/* Test code */ -+#ifdef TESTDIC -+#define NVALS 20000 -+int main(int argc, char *argv[]) -+{ -+ dictionary * d ; -+ char * val ; -+ int i ; -+ char cval[90] ; -+ -+ /* Allocate dictionary */ -+ printf("allocating...\n"); -+ d = dictionary_new(0); -+ -+ /* Set values in dictionary */ -+ printf("setting %d values...\n", NVALS); -+ for (i=0 ; in != 0) { -+ printf("error deleting values\n"); -+ } -+ printf("deallocating...\n"); -+ dictionary_del(d); -+ return 0 ; -+} -+#endif -+/* vim: set ts=4 et sw=4 tw=75 */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,174 @@ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @file dictionary.h -+ @author N. Devillard -+ @date Sep 2007 -+ @version $Revision: 1.1.1.1 $ -+ @brief Implements a dictionary for string variables. -+ -+ This module implements a simple dictionary object, i.e. a list -+ of string/string associations. This object is useful to store e.g. -+ informations retrieved from a configuration file (ini files). -+*/ -+/*--------------------------------------------------------------------------*/ -+ -+/* -+ $Id: dictionary.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Author: yrtan $ -+ $Date: 2008-05-13 07:15:32 $ -+ $Revision: 1.1.1.1 $ -+*/ -+ -+#ifndef _DICTIONARY_H_ -+#define _DICTIONARY_H_ -+ -+/*--------------------------------------------------------------------------- -+ Includes -+ ---------------------------------------------------------------------------*/ -+ -+#include -+#include -+#include -+#include -+ -+/*--------------------------------------------------------------------------- -+ New types -+ ---------------------------------------------------------------------------*/ -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Dictionary object -+ -+ This object contains a list of string/string associations. Each -+ association is identified by a unique string key. Looking up values -+ in the dictionary is speeded up by the use of a (hopefully collision-free) -+ hash function. -+ */ -+/*-------------------------------------------------------------------------*/ -+typedef struct _dictionary_ { -+ int n ; /** Number of entries in dictionary */ -+ int size ; /** Storage size */ -+ char ** val ; /** List of string values */ -+ char ** key ; /** List of string keys */ -+ unsigned * hash ; /** List of hash values for keys */ -+} dictionary ; -+ -+ -+/*--------------------------------------------------------------------------- -+ Function prototypes -+ ---------------------------------------------------------------------------*/ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Compute the hash key for a string. -+ @param key Character string to use for key. -+ @return 1 unsigned int on at least 32 bits. -+ -+ This hash function has been taken from an Article in Dr Dobbs Journal. -+ This is normally a collision-free function, distributing keys evenly. -+ The key is stored anyway in the struct so that collision can be avoided -+ by comparing the key itself in last resort. -+ */ -+/*--------------------------------------------------------------------------*/ -+unsigned dictionary_hash(char * key); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Create a new dictionary object. -+ @param size Optional initial size of the dictionary. -+ @return 1 newly allocated dictionary objet. -+ -+ This function allocates a new dictionary object of given size and returns -+ it. If you do not know in advance (roughly) the number of entries in the -+ dictionary, give size=0. -+ */ -+/*--------------------------------------------------------------------------*/ -+dictionary * dictionary_new(int size); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete a dictionary object -+ @param d dictionary object to deallocate. -+ @return void -+ -+ Deallocate a dictionary object and all memory associated to it. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_del(dictionary * vd); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get a value from a dictionary. -+ @param d dictionary object to search. -+ @param key Key to look for in the dictionary. -+ @param def Default value to return if key not found. -+ @return 1 pointer to internally allocated character string. -+ -+ This function locates a key in a dictionary and returns a pointer to its -+ value, or the passed 'def' pointer if no such key can be found in -+ dictionary. The returned character pointer points to data internal to the -+ dictionary object, you should not try to free it or modify it. -+ */ -+/*--------------------------------------------------------------------------*/ -+char * dictionary_get(dictionary * d, char * key, char * def); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Set a value in a dictionary. -+ @param d dictionary object to modify. -+ @param key Key to modify or add. -+ @param val Value to add. -+ @return int 0 if Ok, anything else otherwise -+ -+ If the given key is found in the dictionary, the associated value is -+ replaced by the provided one. If the key cannot be found in the -+ dictionary, it is added to it. -+ -+ It is Ok to provide a NULL value for val, but NULL values for the dictionary -+ or the key are considered as errors: the function will return immediately -+ in such a case. -+ -+ Notice that if you dictionary_set a variable to NULL, a call to -+ dictionary_get will return a NULL value: the variable will be found, and -+ its value (NULL) is returned. In other words, setting the variable -+ content to NULL is equivalent to deleting the variable from the -+ dictionary. It is not possible (in this implementation) to have a key in -+ the dictionary without value. -+ -+ This function returns non-zero in case of failure. -+ */ -+/*--------------------------------------------------------------------------*/ -+int dictionary_set(dictionary * vd, char * key, char * val); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete a key in a dictionary -+ @param d dictionary object to modify. -+ @param key Key to remove. -+ @return void -+ -+ This function deletes a key in a dictionary. Nothing is done if the -+ key cannot be found. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_unset(dictionary * d, char * key); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Dump a dictionary to an opened file pointer. -+ @param d Dictionary to dump -+ @param f Opened file pointer. -+ @return void -+ -+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out -+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as -+ output file pointers. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_dump(dictionary * d, FILE * out); -+ -+#endif ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,646 @@ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @file iniparser.c -+ @author N. Devillard -+ @date Sep 2007 -+ @version 3.0 -+ @brief Parser for ini files. -+*/ -+/*--------------------------------------------------------------------------*/ -+/* -+ $Id: libiniparser.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Revision: 1.1.1.1 $ -+ $Date: 2008-05-13 07:15:32 $ -+*/ -+/*---------------------------- Includes ------------------------------------*/ -+#include -+#include -+ -+/*---------------------------- Defines -------------------------------------*/ -+#define ASCIILINESZ (1024) -+#define INI_INVALID_KEY ((char*)-1) -+ -+/*--------------------------------------------------------------------------- -+ Private to this module -+ ---------------------------------------------------------------------------*/ -+/** -+ * This enum stores the status for each parsed line (internal use only). -+ */ -+typedef enum _line_status_ { -+ LINE_UNPROCESSED, -+ LINE_ERROR, -+ LINE_EMPTY, -+ LINE_COMMENT, -+ LINE_SECTION, -+ LINE_VALUE -+} line_status ; -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Convert a string to lowercase. -+ @param s String to convert. -+ @return ptr to statically allocated string. -+ -+ This function returns a pointer to a statically allocated string -+ containing a lowercased version of the input string. Do not free -+ or modify the returned string! Since the returned string is statically -+ allocated, it will be modified at each function call (not re-entrant). -+ */ -+/*--------------------------------------------------------------------------*/ -+static char * strlwc(const char * s) -+{ -+ static char l[ASCIILINESZ+1]; -+ int i ; -+ -+ if (s==NULL) return NULL ; -+ memset(l, 0, ASCIILINESZ+1); -+ i=0 ; -+ while (s[i] && i l) { -+ if (!isspace((int)*(last-1))) -+ break ; -+ last -- ; -+ } -+ *last = (char)0; -+ return (char*)l ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get number of sections in a dictionary -+ @param d Dictionary to examine -+ @return int Number of sections found in dictionary -+ -+ This function returns the number of sections found in a dictionary. -+ The test to recognize sections is done on the string stored in the -+ dictionary: a section name is given as "section" whereas a key is -+ stored as "section:key", thus the test looks for entries that do not -+ contain a colon. -+ -+ This clearly fails in the case a section name contains a colon, but -+ this should simply be avoided. -+ -+ This function returns -1 in case of error. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_getnsec(dictionary * d) -+{ -+ int i ; -+ int nsec ; -+ -+ if (d==NULL) return -1 ; -+ nsec=0 ; -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ if (strchr(d->key[i], ':')==NULL) { -+ nsec ++ ; -+ } -+ } -+ return nsec ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get name for section n in a dictionary. -+ @param d Dictionary to examine -+ @param n Section number (from 0 to nsec-1). -+ @return Pointer to char string -+ -+ This function locates the n-th section in a dictionary and returns -+ its name as a pointer to a string statically allocated inside the -+ dictionary. Do not free or modify the returned string! -+ -+ This function returns NULL in case of error. -+ */ -+/*--------------------------------------------------------------------------*/ -+char * iniparser_getsecname(dictionary * d, int n) -+{ -+ int i ; -+ int foundsec ; -+ -+ if (d==NULL || n<0) return NULL ; -+ foundsec=0 ; -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ if (strchr(d->key[i], ':')==NULL) { -+ foundsec++ ; -+ if (foundsec>n) -+ break ; -+ } -+ } -+ if (foundsec<=n) { -+ return NULL ; -+ } -+ return d->key[i] ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Dump a dictionary to an opened file pointer. -+ @param d Dictionary to dump. -+ @param f Opened file pointer to dump to. -+ @return void -+ -+ This function prints out the contents of a dictionary, one element by -+ line, onto the provided file pointer. It is OK to specify @c stderr -+ or @c stdout as output files. This function is meant for debugging -+ purposes mostly. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_dump(dictionary * d, FILE * f) -+{ -+ int i ; -+ -+ if (d==NULL || f==NULL) return ; -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ if (d->val[i]!=NULL) { -+ fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); -+ } else { -+ fprintf(f, "[%s]=UNDEF\n", d->key[i]); -+ } -+ } -+ return ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Save a dictionary to a loadable ini file -+ @param d Dictionary to dump -+ @param f Opened file pointer to dump to -+ @return void -+ -+ This function dumps a given dictionary into a loadable ini file. -+ It is Ok to specify @c stderr or @c stdout as output files. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_dump_ini(dictionary * d, FILE * f) -+{ -+ int i, j ; -+ char keym[ASCIILINESZ+1]; -+ int nsec ; -+ char * secname ; -+ int seclen ; -+ -+ if (d==NULL || f==NULL) return ; -+ -+ nsec = iniparser_getnsec(d); -+ if (nsec<1) { -+ /* No section in file: dump all keys as they are */ -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ fprintf(f, "%s = %s\n", d->key[i], d->val[i]); -+ } -+ return ; -+ } -+ for (i=0 ; isize ; j++) { -+ if (d->key[j]==NULL) -+ continue ; -+ if (!strncmp(d->key[j], keym, seclen+1)) { -+ fprintf(f, -+ "%-30s = %s\n", -+ d->key[j]+seclen+1, -+ d->val[j] ? d->val[j] : ""); -+ } -+ } -+ } -+ fprintf(f, "\n"); -+ return ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param def Default value to return if key not found. -+ @return pointer to statically allocated character string -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the pointer passed as 'def' is returned. -+ The returned char pointer is pointing to a string allocated in -+ the dictionary, do not free or modify it. -+ */ -+/*--------------------------------------------------------------------------*/ -+char * iniparser_getstring(dictionary * d, const char * key, char * def) -+{ -+ char * lc_key ; -+ char * sval ; -+ -+ if (d==NULL || key==NULL) -+ return def ; -+ -+ lc_key = strlwc(key); -+ sval = dictionary_get(d, lc_key, def); -+ return sval ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to an int -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return integer -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ -+ Supported values for integers include the usual C notation -+ so decimal, octal (starting with 0) and hexadecimal (starting with 0x) -+ are supported. Examples: -+ -+ "42" -> 42 -+ "042" -> 34 (octal -> decimal) -+ "0x42" -> 66 (hexa -> decimal) -+ -+ Warning: the conversion may overflow in various ways. Conversion is -+ totally outsourced to strtol(), see the associated man page for overflow -+ handling. -+ -+ Credits: Thanks to A. Becker for suggesting strtol() -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_getint(dictionary * d, const char * key, int notfound) -+{ -+ char * str ; -+ -+ str = iniparser_getstring(d, key, INI_INVALID_KEY); -+ if (str==INI_INVALID_KEY) return notfound ; -+ return (int)strtol(str, NULL, 0); -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to a double -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return double -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ */ -+/*--------------------------------------------------------------------------*/ -+double iniparser_getdouble(dictionary * d, char * key, double notfound) -+{ -+ char * str ; -+ -+ str = iniparser_getstring(d, key, INI_INVALID_KEY); -+ if (str==INI_INVALID_KEY) return notfound ; -+ return atof(str); -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to a boolean -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return integer -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ -+ A true boolean is found if one of the following is matched: -+ -+ - A string starting with 'y' -+ - A string starting with 'Y' -+ - A string starting with 't' -+ - A string starting with 'T' -+ - A string starting with '1' -+ -+ A false boolean is found if one of the following is matched: -+ -+ - A string starting with 'n' -+ - A string starting with 'N' -+ - A string starting with 'f' -+ - A string starting with 'F' -+ - A string starting with '0' -+ -+ The notfound value returned if no boolean is identified, does not -+ necessarily have to be 0 or 1. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_getboolean(dictionary * d, const char * key, int notfound) -+{ -+ char * c ; -+ int ret ; -+ -+ c = iniparser_getstring(d, key, INI_INVALID_KEY); -+ if (c==INI_INVALID_KEY) return notfound ; -+ if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') { -+ ret = 1 ; -+ } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') { -+ ret = 0 ; -+ } else { -+ ret = notfound ; -+ } -+ return ret; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Finds out if a given entry exists in a dictionary -+ @param ini Dictionary to search -+ @param entry Name of the entry to look for -+ @return integer 1 if entry exists, 0 otherwise -+ -+ Finds out if a given entry exists in the dictionary. Since sections -+ are stored as keys with NULL associated values, this is the only way -+ of querying for the presence of sections in a dictionary. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_find_entry( -+ dictionary * ini, -+ char * entry -+) -+{ -+ int found=0 ; -+ if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) { -+ found = 1 ; -+ } -+ return found ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Set an entry in a dictionary. -+ @param ini Dictionary to modify. -+ @param entry Entry to modify (entry name) -+ @param val New value to associate to the entry. -+ @return int 0 if Ok, -1 otherwise. -+ -+ If the given entry can be found in the dictionary, it is modified to -+ contain the provided value. If it cannot be found, -1 is returned. -+ It is Ok to set val to NULL. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_set(dictionary * ini, char * entry, char * val) -+{ -+ return dictionary_set(ini, strlwc(entry), val) ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete an entry in a dictionary -+ @param ini Dictionary to modify -+ @param entry Entry to delete (entry name) -+ @return void -+ -+ If the given entry can be found, it is deleted from the dictionary. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_unset(dictionary * ini, char * entry) -+{ -+ dictionary_unset(ini, strlwc(entry)); -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Load a single line from an INI file -+ @param input_line Input line, may be concatenated multi-line input -+ @param section Output space to store section -+ @param key Output space to store key -+ @param value Output space to store value -+ @return line_status value -+ */ -+/*--------------------------------------------------------------------------*/ -+static line_status iniparser_line( -+ char * input_line, -+ char * section, -+ char * key, -+ char * value) -+{ -+ line_status sta ; -+ char line[ASCIILINESZ+1]; -+ int len ; -+ -+ strcpy(line, strstrip(input_line)); -+ len = (int)strlen(line); -+ -+ sta = LINE_UNPROCESSED ; -+ if (len<1) { -+ /* Empty line */ -+ sta = LINE_EMPTY ; -+ } else if (line[0]=='#') { -+ /* Comment line */ -+ sta = LINE_COMMENT ; -+ } else if (line[0]=='[' && line[len-1]==']') { -+ /* Section name */ -+ sscanf(line, "[%[^]]", section); -+ strcpy(section, strstrip(section)); -+ strcpy(section, strlwc(section)); -+ sta = LINE_SECTION ; -+ } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 -+ || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2 -+ || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) { -+ /* Usual key=value, with or without comments */ -+ strcpy(key, strstrip(key)); -+ strcpy(key, strlwc(key)); -+ strcpy(value, strstrip(value)); -+ /* -+ * sscanf cannot handle '' or "" as empty values -+ * this is done here -+ */ -+ if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) { -+ value[0]=0 ; -+ } -+ sta = LINE_VALUE ; -+ } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2 -+ || sscanf(line, "%[^=] %[=]", key, value) == 2) { -+ /* -+ * Special cases: -+ * key= -+ * key=; -+ * key=# -+ */ -+ strcpy(key, strstrip(key)); -+ strcpy(key, strlwc(key)); -+ value[0]=0 ; -+ sta = LINE_VALUE ; -+ } else { -+ /* Generate syntax error */ -+ sta = LINE_ERROR ; -+ } -+ return sta ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Parse an ini file and return an allocated dictionary object -+ @param ininame Name of the ini file to read. -+ @return Pointer to newly allocated dictionary -+ -+ This is the parser for ini files. This function is called, providing -+ the name of the file to be read. It returns a dictionary object that -+ should not be accessed directly, but through accessor functions -+ instead. -+ -+ The returned dictionary must be freed using iniparser_freedict(). -+ */ -+/*--------------------------------------------------------------------------*/ -+dictionary * iniparser_load(const char * ininame) -+{ -+ FILE * in ; -+ -+ char line [ASCIILINESZ+1] ; -+ char section [ASCIILINESZ+1] ; -+ char key [ASCIILINESZ+1] ; -+ char tmp [ASCIILINESZ+1] ; -+ char val [ASCIILINESZ+1] ; -+ -+ int last=0 ; -+ int len ; -+ int lineno=0 ; -+ int errs=0; -+ -+ dictionary * dict ; -+ -+ if ((in=fopen(ininame, "r"))==NULL) { -+ fprintf(stderr, "iniparser: cannot open %s\n", ininame); -+ return NULL ; -+ } -+ -+ dict = dictionary_new(0) ; -+ if (!dict) { -+ fclose(in); -+ return NULL ; -+ } -+ -+ memset(line, 0, ASCIILINESZ); -+ memset(section, 0, ASCIILINESZ); -+ memset(key, 0, ASCIILINESZ); -+ memset(val, 0, ASCIILINESZ); -+ last=0 ; -+ -+ while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) { -+ lineno++ ; -+ len = (int)strlen(line)-1; -+ /* Safety check against buffer overflows */ -+ if (line[len]!='\n') { -+ fprintf(stderr, -+ "iniparser: input line too long in %s (%d)\n", -+ ininame, -+ lineno); -+ dictionary_del(dict); -+ fclose(in); -+ return NULL ; -+ } -+ /* Get rid of \n and spaces at end of line */ -+ while ((len>=0) && -+ ((line[len]=='\n') || (isspace(line[len])))) { -+ line[len]=0 ; -+ len-- ; -+ } -+ /* Detect multi-line */ -+ if (line[len]=='\\') { -+ /* Multi-line value */ -+ last=len ; -+ continue ; -+ } else { -+ last=0 ; -+ } -+ switch (iniparser_line(line, section, key, val)) { -+ case LINE_EMPTY: -+ case LINE_COMMENT: -+ break ; -+ -+ case LINE_SECTION: -+ errs = dictionary_set(dict, section, NULL); -+ break ; -+ -+ case LINE_VALUE: -+ sprintf(tmp, "%s:%s", section, key); -+ errs = dictionary_set(dict, tmp, val) ; -+ break ; -+ -+ case LINE_ERROR: -+ fprintf(stderr, "iniparser: syntax error in %s (%d):\n", -+ ininame, -+ lineno); -+ fprintf(stderr, "-> %s\n", line); -+ errs++ ; -+ break; -+ -+ default: -+ break ; -+ } -+ memset(line, 0, ASCIILINESZ); -+ last=0; -+ if (errs<0) { -+ fprintf(stderr, "iniparser: memory allocation failure\n"); -+ break ; -+ } -+ } -+ if (errs) { -+ dictionary_del(dict); -+ dict = NULL ; -+ } -+ fclose(in); -+ return dict ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Free all memory associated to an ini dictionary -+ @param d Dictionary to free -+ @return void -+ -+ Free all memory associated to an ini dictionary. -+ It is mandatory to call this function before the dictionary object -+ gets out of the current context. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_freedict(dictionary * d) -+{ -+ dictionary_del(d); -+} -+ -+/* vim: set ts=4 et sw=4 tw=75 */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,314 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * MTD library. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include "common.h" -+ -+#define PROGRAM_NAME "libmtd" -+#define MTD_DEV_MAJOR 90 -+ -+/** -+ * mtd_get_info - get information about an MTD device. -+ * @node: name of the MTD device node -+ * @mtd: the MTD device information is returned here -+ * -+ * This function gets information about MTD device defined by the @node device -+ * node file and saves this information in the @mtd object. Returns %0 in case -+ * of success and %-1 in case of failure. -+ */ -+int mtd_get_info(const char *node, struct mtd_info *mtd) -+{ -+ struct stat st; -+ struct mtd_info_user ui; -+ int ret; -+ loff_t offs = 0; -+ -+ if (stat(node, &st)) -+ return sys_errmsg("cannot open \"%s\"", node); -+ -+ if (!S_ISCHR(st.st_mode)) { -+ errno = EINVAL; -+ return errmsg("\"%s\" is not a character device", node); -+ } -+ -+ mtd->major = major(st.st_rdev); -+ mtd->minor = minor(st.st_rdev); -+ -+ if (mtd->major != MTD_DEV_MAJOR) { -+ errno = EINVAL; -+ return errmsg("\"%s\" has major number %d, MTD devices have " -+ "major %d", node, mtd->major, MTD_DEV_MAJOR); -+ } -+ -+ mtd->num = mtd->minor / 2; -+ mtd->rdonly = mtd->minor & 1; -+ -+ mtd->fd = open(node, O_RDWR); -+ if (mtd->fd == -1) -+ return sys_errmsg("cannot open \"%s\"", node); -+ -+ if (ioctl(mtd->fd, MEMGETINFO, &ui)) { -+ sys_errmsg("MEMGETINFO ioctl request failed"); -+ goto out_close; -+ } -+ -+ ret = ioctl(mtd->fd, MEMGETBADBLOCK, &offs); -+ if (ret == -1) { -+ if (errno != EOPNOTSUPP) { -+ sys_errmsg("MEMGETBADBLOCK ioctl failed"); -+ goto out_close; -+ } -+ errno = 0; -+ mtd->allows_bb = 0; -+ } else -+ mtd->allows_bb = 1; -+ -+ mtd->type = ui.type; -+ mtd->size = ui.size; -+ mtd->eb_size = ui.erasesize; -+ mtd->min_io_size = ui.writesize; -+ -+ if (mtd->min_io_size <= 0) { -+ errmsg("mtd%d (%s) has insane min. I/O unit size %d", -+ mtd->num, node, mtd->min_io_size); -+ goto out_close; -+ } -+ if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) { -+ errmsg("mtd%d (%s) has insane eraseblock size %d", -+ mtd->num, node, mtd->eb_size); -+ goto out_close; -+ } -+ if (mtd->size <= 0 || mtd->size < mtd->eb_size) { -+ errmsg("mtd%d (%s) has insane size %lld", -+ mtd->num, node, mtd->size); -+ goto out_close; -+ } -+ mtd->eb_cnt = mtd->size / mtd->eb_size; -+ -+ switch(mtd->type) { -+ case MTD_ABSENT: -+ errmsg("mtd%d (%s) is removable and is not present", -+ mtd->num, node); -+ goto out_close; -+ case MTD_RAM: -+ mtd->type_str = "RAM-based"; -+ break; -+ case MTD_ROM: -+ mtd->type_str = "ROM"; -+ break; -+ case MTD_NORFLASH: -+ mtd->type_str = "NOR"; -+ break; -+ case MTD_NANDFLASH: -+ mtd->type_str = "NAND"; -+ break; -+ case MTD_DATAFLASH: -+ mtd->type_str = "DataFlash"; -+ break; -+ case MTD_UBIVOLUME: -+ mtd->type_str = "UBI-emulated MTD"; -+ break; -+ default: -+ mtd->type_str = "Unknown flash type"; -+ break; -+ } -+ -+ if (!(ui.flags & MTD_WRITEABLE)) -+ mtd->rdonly = 1; -+ -+ return 0; -+ -+out_close: -+ close(mtd->fd); -+ return -1; -+} -+ -+/** -+ * mtd_erase - erase an eraseblock. -+ * @mtd: MTD device description object -+ * @eb: eraseblock to erase -+ * -+ * This function erases the eraseblock and returns %0 in case of success and -+ * %-1 in case of failure. -+ */ -+int mtd_erase(const struct mtd_info *mtd, int eb) -+{ -+ struct erase_info_user ei; -+ -+ ei.start = eb * mtd->eb_size;; -+ ei.length = mtd->eb_size; -+ return ioctl(mtd->fd, MEMERASE, &ei); -+} -+ -+/** -+ * mtd_is_bad - check if eraseblock is bad. -+ * @mtd: MTD device description object -+ * @eb: eraseblock to check -+ * -+ * This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes, -+ * and %-1 in case of failure. -+ */ -+int mtd_is_bad(const struct mtd_info *mtd, int eb) -+{ -+ int ret; -+ loff_t seek; -+ -+ if (eb < 0 || eb >= mtd->eb_cnt) { -+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks", -+ eb, mtd->num, mtd->eb_cnt); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ if (!mtd->allows_bb) -+ return 0; -+ -+ seek = eb * mtd->eb_size; -+ ret = ioctl(mtd->fd, MEMGETBADBLOCK, &seek); -+ if (ret == -1) { -+ sys_errmsg("MEMGETBADBLOCK ioctl failed for " -+ "eraseblock %d (mtd%d)", eb, mtd->num); -+ return -1; -+ } -+ -+ return ret; -+} -+ -+/** -+ * mtd_read - read data from an MTD device. -+ * @mtd: MTD device description object -+ * @eb: eraseblock to read from -+ * @offs: offset withing the eraseblock to read from -+ * @buf: buffer to read data to -+ * @len: how many bytes to read -+ * -+ * This function reads @len bytes of data from eraseblock @eb and offset @offs -+ * of the MTD device defined by @mtd and stores the read data at buffer @buf. -+ * Returns %0 in case of success and %-1 in case of failure. -+ */ -+int mtd_read(const struct mtd_info *mtd, int eb, int offs, void *buf, int len) -+{ -+ int ret, rd = 0; -+ off_t seek; -+ -+ if (eb < 0 || eb >= mtd->eb_cnt) { -+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks", -+ eb, mtd->num, mtd->eb_cnt); -+ errno = EINVAL; -+ return -1; -+ } -+ if (offs < 0 || offs + len > mtd->eb_size) { -+ errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d", -+ offs, len, mtd->num, mtd->eb_size); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ /* Seek to the beginning of the eraseblock */ -+ seek = eb * mtd->eb_size + offs; -+ if (lseek(mtd->fd, seek, SEEK_SET) != seek) { -+ sys_errmsg("cannot seek mtd%d to offset %llu", -+ mtd->num, (unsigned long long)seek); -+ return -1; -+ } -+ -+ while (rd < len) { -+ ret = read(mtd->fd, buf, len); -+ if (ret < 0) { -+ sys_errmsg("cannot read %d bytes from mtd%d (eraseblock %d, offset %d)", -+ len, mtd->num, eb, offs); -+ return -1; -+ } -+ rd += ret; -+ } -+ -+ return 0; -+} -+ -+/** -+ * mtd_write - write data to an MTD device. -+ * @mtd: MTD device description object -+ * @eb: eraseblock to write to -+ * @offs: offset withing the eraseblock to write to -+ * @buf: buffer to write -+ * @len: how many bytes to write -+ * -+ * This function writes @len bytes of data to eraseblock @eb and offset @offs -+ * of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in -+ * case of failure. -+ */ -+int mtd_write(const struct mtd_info *mtd, int eb, int offs, void *buf, int len) -+{ -+ int ret; -+ off_t seek; -+ -+ if (eb < 0 || eb >= mtd->eb_cnt) { -+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks", -+ eb, mtd->num, mtd->eb_cnt); -+ errno = EINVAL; -+ return -1; -+ } -+ if (offs < 0 || offs + len > mtd->eb_size) { -+ errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d", -+ offs, len, mtd->num, mtd->eb_size); -+ errno = EINVAL; -+ return -1; -+ } -+#if 0 -+ if (offs % mtd->subpage_size) { -+ errmsg("write offset %d is not aligned to mtd%d min. I/O size %d", -+ offs, mtd->num, mtd->subpage_size); -+ errno = EINVAL; -+ return -1; -+ } -+ if (len % mtd->subpage_size) { -+ errmsg("write length %d is not aligned to mtd%d min. I/O size %d", -+ len, mtd->num, mtd->subpage_size); -+ errno = EINVAL; -+ return -1; -+ } -+#endif -+ -+ /* Seek to the beginning of the eraseblock */ -+ seek = eb * mtd->eb_size + offs; -+ if (lseek(mtd->fd, seek, SEEK_SET) != seek) { -+ sys_errmsg("cannot seek mtd%d to offset %llu", -+ mtd->num, (unsigned long long)seek); -+ return -1; -+ } -+ -+ ret = write(mtd->fd, buf, len); -+ if (ret != len) { -+ sys_errmsg("cannot write %d bytes to mtd%d (eraseblock %d, offset %d)", -+ len, mtd->num, eb, offs); -+ return -1; -+ } -+ -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,225 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * UBI scanning library. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include "common.h" -+#include "crc32.h" -+ -+#define PROGRAM_NAME "libscan" -+ -+static int all_ff(const void *buf, int len) -+{ -+ int i; -+ const uint8_t *p = buf; -+ -+ for (i = 0; i < len; i++) -+ if (p[i] != 0xFF) -+ return 0; -+ return 1; -+} -+ -+int ubi_scan(struct mtd_info *mtd, struct ubi_scan_info **info, int verbose) -+{ -+ int eb, v = (verbose == 2), pr = (verbose == 1); -+ struct ubi_scan_info *si; -+ unsigned long long sum = 0; -+ -+ si = calloc(1, sizeof(struct ubi_scan_info)); -+ if (!si) -+ return sys_errmsg("cannot allocate %zd bytes of memory", -+ sizeof(struct ubi_scan_info)); -+ -+ si->ec = calloc(mtd->eb_cnt, sizeof(uint32_t)); -+ if (!si->ec) { -+ sys_errmsg("cannot allocate %zd bytes of memory", -+ sizeof(struct ubi_scan_info)); -+ goto out_si; -+ } -+ -+ si->vid_hdr_offs = si->data_offs = -1; -+ -+ verbose(v, "start scanning eraseblocks 0-%d", mtd->eb_cnt); -+ for (eb = 0; eb < mtd->eb_cnt; eb++) { -+ int ret; -+ uint32_t crc; -+ struct ubi_ec_hdr hdr; -+ unsigned long long ec; -+ -+ if (v) { -+ normsg_cont("scanning eraseblock %d", eb); -+ fflush(stdout); -+ } -+ if (pr) { -+ printf("\r" PROGRAM_NAME ": scanning eraseblock %d -- %2lld %% complete ", -+ eb, (long long)(eb + 1) * 100 / mtd->eb_cnt); -+ fflush(stdout); -+ } -+ -+ ret = mtd_is_bad(mtd, eb); -+ if (ret == -1) -+ goto out_ec; -+ if (ret) { -+ si->bad_cnt += 1; -+ si->ec[eb] = EB_BAD; -+ if (v) -+ printf(": bad\n"); -+ continue; -+ } -+ -+ ret = mtd_read(mtd, eb, 0, &hdr, sizeof(struct ubi_ec_hdr));; -+ if (ret < 0) -+ goto out_ec; -+ -+ /* Check the EC header */ -+ if (be32_to_cpu(hdr.magic) != UBI_EC_HDR_MAGIC) { -+ if (all_ff(&hdr, sizeof(struct ubi_ec_hdr))) { -+ si->empty_cnt += 1; -+ si->ec[eb] = EB_EMPTY; -+ if (v) -+ printf(": empty\n"); -+ } else { -+ si->alien_cnt += 1; -+ si->ec[eb] = EB_ALIEN; -+ if (v) -+ printf(": alien\n"); -+ } -+ continue; -+ } -+ -+ crc = crc32(UBI_CRC32_INIT, &hdr, UBI_EC_HDR_SIZE_CRC); -+ if (be32_to_cpu(hdr.hdr_crc) != crc) { -+ si->corrupted_cnt += 1; -+ si->ec[eb] = EB_CORRUPTED; -+ if (v) -+ printf(": bad CRC %#08x, should be %#08x\n", -+ crc, be32_to_cpu(hdr.hdr_crc)); -+ continue; -+ } -+ -+ ec = be64_to_cpu(hdr.ec); -+ if (ec > EC_MAX) { -+ if (pr) -+ printf("\n"); -+ errmsg("erase counter in EB %d is %llu, while this " -+ "program expects them to be less than %u", -+ eb, ec, EC_MAX); -+ goto out_ec; -+ } -+ -+ if (si->vid_hdr_offs == -1) { -+ si->vid_hdr_offs = be32_to_cpu(hdr.vid_hdr_offset); -+ si->data_offs = be32_to_cpu(hdr.data_offset); -+ if (si->data_offs % mtd->min_io_size) { -+ if (pr) -+ printf("\n"); -+ if (v) -+ printf(": corrupted because of the below\n"); -+ warnmsg("bad data offset %d at eraseblock %d (n" -+ "of multiple of min. I/O unit size %d)", -+ si->data_offs, eb, mtd->min_io_size); -+ warnmsg("treat eraseblock %d as corrupted", eb); -+ si->corrupted_cnt += 1; -+ si->ec[eb] = EB_CORRUPTED; -+ continue; -+ -+ } -+ } else { -+ if (be32_to_cpu(hdr.vid_hdr_offset) != si->vid_hdr_offs) { -+ if (pr) -+ printf("\n"); -+ if (v) -+ printf(": corrupted because of the below\n"); -+ warnmsg("inconsistent VID header offset: was " -+ "%d, but is %d in eraseblock %d", -+ si->vid_hdr_offs, -+ be32_to_cpu(hdr.vid_hdr_offset), eb); -+ warnmsg("treat eraseblock %d as corrupted", eb); -+ si->corrupted_cnt += 1; -+ si->ec[eb] = EB_CORRUPTED; -+ continue; -+ } -+ if (be32_to_cpu(hdr.data_offset) != si->data_offs) { -+ if (pr) -+ printf("\n"); -+ if (v) -+ printf(": corrupted because of the below\n"); -+ warnmsg("inconsistent data offset: was %d, but" -+ " is %d in eraseblock %d", -+ si->data_offs, -+ be32_to_cpu(hdr.data_offset), eb); -+ warnmsg("treat eraseblock %d as corrupted", eb); -+ si->corrupted_cnt += 1; -+ si->ec[eb] = EB_CORRUPTED; -+ continue; -+ } -+ } -+ -+ si->ok_cnt += 1; -+ si->ec[eb] = ec; -+ if (v) -+ printf(": OK, erase counter %u\n", si->ec[eb]); -+ } -+ -+ if (si->ok_cnt != 0) { -+ /* Calculate mean erase counter */ -+ for (eb = 0; eb < mtd->eb_cnt; eb++) { -+ if (si->ec[eb] > EC_MAX) -+ continue; -+ sum += si->ec[eb]; -+ } -+ si->mean_ec = sum / si->ok_cnt; -+ } -+ -+ si->good_cnt = mtd->eb_cnt - si->bad_cnt; -+ verbose(v, "finished, mean EC %lld, %d OK, %d corrupted, %d empty, %d " -+ "alien, bad %d", si->mean_ec, si->ok_cnt, si->corrupted_cnt, -+ si->empty_cnt, si->alien_cnt, si->bad_cnt); -+ -+ *info = si; -+ if (pr) -+ printf("\n"); -+ return 0; -+ -+out_ec: -+ free(si->ec); -+out_si: -+ free(si); -+ *info = NULL; -+ return -1; -+} -+ -+void ubi_scan_free(struct ubi_scan_info *si) -+{ -+ free(si->ec); -+ free(si); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1154 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#include "libubi_int.h" -+#include "common.h" -+ -+#define PROGRAM_NAME "libubi" -+ -+/** -+ * mkpath - compose full path from 2 given components. -+ * @path: the first component -+ * @name: the second component -+ * -+ * This function returns the resulting path in case of success and %NULL in -+ * case of failure. -+ */ -+static char *mkpath(const char *path, const char *name) -+{ -+ char *n; -+ int len1 = strlen(path); -+ int len2 = strlen(name); -+ -+ n = malloc(len1 + len2 + 2); -+ if (!n) { -+ sys_errmsg("cannot allocate %d bytes", len1 + len2 + 2); -+ return NULL; -+ } -+ -+ memcpy(n, path, len1); -+ if (n[len1 - 1] != '/') -+ n[len1++] = '/'; -+ -+ memcpy(n + len1, name, len2 + 1); -+ return n; -+} -+ -+/** -+ * read_positive_ll - read a positive 'long long' value from a file. -+ * @file: the file to read from -+ * @value: the result is stored here -+ * -+ * This function reads file @file and interprets its contents as a positive -+ * 'long long' integer. If this is not true, it fails with %EINVAL error code. -+ * Returns %0 in case of success and %-1 in case of failure. -+ */ -+static int read_positive_ll(const char *file, long long *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ -+ fd = open(file, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, buf, 50); -+ if (rd == -1) { -+ sys_errmsg("cannot read \"%s\"", file); -+ goto out_error; -+ } -+ if (rd == 50) { -+ errmsg("contents of \"%s\" is too long", file); -+ errno = EINVAL; -+ goto out_error; -+ } -+ -+ if (sscanf(buf, "%lld\n", value) != 1) { -+ /* This must be a UBI bug */ -+ errmsg("cannot read integer from \"%s\"\n", file); -+ errno = EINVAL; -+ goto out_error; -+ } -+ -+ if (*value < 0) { -+ errmsg("negative value %lld in \"%s\"", *value, file); -+ errno = EINVAL; -+ goto out_error; -+ } -+ -+ if (close(fd)) -+ return sys_errmsg("close failed on \"%s\"", file); -+ -+ return 0; -+ -+out_error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * read_positive_int - read a positive 'int' value from a file. -+ * @file: the file to read from -+ * @value: the result is stored here -+ * -+ * This function is the same as 'read_positive_ll()', but it reads an 'int' -+ * value, not 'long long'. -+ */ -+static int read_positive_int(const char *file, int *value) -+{ -+ long long res; -+ -+ if (read_positive_ll(file, &res)) -+ return -1; -+ -+ /* Make sure the value is not too big */ -+ if (res > INT_MAX) { -+ errmsg("value %lld read from file \"%s\" is out of range", -+ res, file); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ *value = res; -+ return 0; -+} -+ -+/** -+ * read_data - read data from a file. -+ * @file: the file to read from -+ * @buf: the buffer to read to -+ * @buf_len: buffer length -+ * -+ * This function returns number of read bytes in case of success and %-1 in -+ * case of failure. Note, if the file contains more then @buf_len bytes of -+ * date, this function fails with %EINVAL error code. -+ */ -+static int read_data(const char *file, void *buf, int buf_len) -+{ -+ int fd, rd, tmp, tmp1; -+ -+ fd = open(file, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, buf, buf_len); -+ if (rd == -1) { -+ sys_errmsg("cannot read \"%s\"", file); -+ goto out_error; -+ } -+ -+ /* Make sure all data is read */ -+ tmp1 = read(fd, &tmp, 1); -+ if (tmp1 == 1) { -+ sys_errmsg("cannot read \"%s\"", file); -+ goto out_error; -+ } -+ if (tmp1) { -+ errmsg("file \"%s\" contains too much data (> %d bytes)", -+ file, buf_len); -+ errno = EINVAL; -+ goto out_error; -+ } -+ -+ if (close(fd)) { -+ sys_errmsg("close failed on \"%s\"", file); -+ return -1; -+ } -+ -+ return rd; -+ -+out_error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * read_major - read major and minor numbers from a file. -+ * @file: name of the file to read from -+ * @major: major number is returned here -+ * @minor: minor number is returned here -+ * -+ * This function returns % in case of succes, and %-1 in case of failure. -+ */ -+static int read_major(const char *file, int *major, int *minor) -+{ -+ int ret; -+ char buf[50]; -+ -+ ret = read_data(file, buf, 50); -+ if (ret < 0) -+ return ret; -+ -+ ret = sscanf(buf, "%d:%d\n", major, minor); -+ if (ret != 2) { -+ errno = EINVAL; -+ return errmsg("\"%s\" does not have major:minor format", file); -+ } -+ -+ if (*major < 0 || *minor < 0) { -+ errno = EINVAL; -+ return errmsg("bad major:minor %d:%d in \"%s\"", -+ *major, *minor, file); -+ } -+ -+ return 0; -+} -+ -+/** -+ * dev_read_int - read a positive 'int' value from an UBI device sysfs file. -+ * @patt: file pattern to read from -+ * @dev_num: UBI device number -+ * @value: the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int dev_read_int(const char *patt, int dev_num, int *value) -+{ -+ char file[strlen(patt) + 50]; -+ -+ sprintf(file, patt, dev_num); -+ return read_positive_int(file, value); -+} -+ -+/** -+ * vol_read_int - read a positive 'int' value from an UBI volume sysfs file. -+ * @patt: file pattern to read from -+ * @dev_num: UBI device number -+ * @vol_id: volume ID -+ * @value: the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value) -+{ -+ char file[strlen(patt) + 100]; -+ -+ sprintf(file, patt, dev_num, vol_id); -+ return read_positive_int(file, value); -+} -+ -+/** -+ * dev_read_ll - read a positive 'long long' value from an UBI device sysfs file. -+ * @patt: file pattern to read from -+ * @dev_num: UBI device number -+ * @value: the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int dev_read_ll(const char *patt, int dev_num, long long *value) -+{ -+ char file[strlen(patt) + 50]; -+ -+ sprintf(file, patt, dev_num); -+ return read_positive_ll(file, value); -+} -+ -+/** -+ * vol_read_ll - read a positive 'long long' value from an UBI volume sysfs file. -+ * @patt: file pattern to read from -+ * @dev_num: UBI device number -+ * @vol_id: volume ID -+ * @value: the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int vol_read_ll(const char *patt, int dev_num, int vol_id, -+ long long *value) -+{ -+ char file[strlen(patt) + 100]; -+ -+ sprintf(file, patt, dev_num, vol_id); -+ return read_positive_ll(file, value); -+} -+ -+/** -+ * vol_read_data - read data from an UBI volume's sysfs file. -+ * @patt: file pattern to read from -+ * @dev_num: UBI device number -+ * @vol_id: volume ID -+ * @buf: buffer to read to -+ * @buf_len: buffer length -+ * -+ * This function returns number of read bytes in case of success and %-1 in -+ * case of failure. -+ */ -+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf, -+ int buf_len) -+{ -+ char file[strlen(patt) + 100]; -+ -+ sprintf(file, patt, dev_num, vol_id); -+ return read_data(file, buf, buf_len); -+} -+ -+/** -+ * dev_get_major - get major and minor numbers of an UBI device. -+ * @lib: libubi descriptor -+ * @dev_num: UBI device number -+ * @major: major number is returned here -+ * @minor: minor number is returned here -+ * -+ * This function returns zero in case of succes and %-1 in case of failure. -+ */ -+static int dev_get_major(struct libubi *lib, int dev_num, int *major, int *minor) -+{ -+ char file[strlen(lib->dev_dev) + 50]; -+ -+ sprintf(file, lib->dev_dev, dev_num); -+ return read_major(file, major, minor); -+} -+ -+/** -+ * vol_get_major - get major and minor numbers of an UBI volume. -+ * @lib: libubi descriptor -+ * @dev_num: UBI device number -+ * @vol_id: volume ID -+ * @major: major number is returned here -+ * @minor: minor number is returned here -+ * -+ * This function returns zero in case of succes and %-1 in case of failure. -+ */ -+static int vol_get_major(struct libubi *lib, int dev_num, int vol_id, -+ int *major, int *minor) -+{ -+ char file[strlen(lib->vol_dev) + 100]; -+ -+ sprintf(file, lib->vol_dev, dev_num, vol_id); -+ return read_major(file, major, minor); -+} -+ -+/** -+ * vol_node2nums - find UBI device number and volume ID by volume device node -+ * file. -+ * @lib: UBI library descriptor -+ * @node: UBI character device node name -+ * @dev_num: UBI device number is returned here -+ * @vol_id: volume ID is returned hers -+ * -+ * This function returns zero in case of succes and %-1 in case of failure. -+ */ -+static int vol_node2nums(struct libubi *lib, const char *node, int *dev_num, -+ int *vol_id) -+{ -+ struct stat st; -+ struct ubi_info info; -+ int i, fd, major, minor; -+ char file[strlen(lib->ubi_vol) + 100]; -+ -+ if (lstat(node, &st)) -+ return -1; -+ -+ if (!S_ISCHR(st.st_mode)) { -+ errno = EINVAL; -+ return errmsg("\"%s\" is not a character device", node); -+ } -+ -+ major = major(st.st_rdev); -+ minor = minor(st.st_rdev); -+ -+ if (minor == 0) { -+ errno = EINVAL; -+ return errmsg("\"%s\" is not a volume character device", node); -+ } -+ -+ if (ubi_get_info((libubi_t *)lib, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ int major1, minor1, ret; -+ -+ ret = dev_get_major(lib, i, &major1, &minor1); -+ if (ret) { -+ if (errno == ENOENT) -+ continue; -+ return -1; -+ } -+ -+ if (major1 == major) -+ break; -+ } -+ -+ if (i > info.highest_dev_num) { -+ errno = ENODEV; -+ return -1; -+ } -+ -+ /* Make sure this UBI volume exists */ -+ sprintf(file, lib->ubi_vol, i, minor - 1); -+ fd = open(file, O_RDONLY); -+ if (fd == -1) { -+ errno = ENODEV; -+ return -1; -+ } -+ -+ *dev_num = i; -+ *vol_id = minor - 1; -+ errno = 0; -+ return 0; -+} -+ -+/** -+ * dev_node2num - find UBI device number by its character device node. -+ * @lib: UBI library descriptor -+ * @node: UBI character device node name -+ * -+ * This function returns positive UBI device number in case of success and %-1 -+ * in case of failure. -+ */ -+static int dev_node2num(struct libubi *lib, const char *node, int *dev_num) -+{ -+ struct stat stat; -+ struct ubi_info info; -+ int i, major, minor; -+ -+ if (lstat(node, &stat)) -+ return -1; -+ -+ if (!S_ISCHR(stat.st_mode)) { -+ errno = EINVAL; -+ return errmsg("\"%s\" is not a character device", node); -+ } -+ -+ major = major(stat.st_rdev); -+ minor = minor(stat.st_rdev); -+ -+ if (minor != 0) { -+ errno = EINVAL; -+ return errmsg("\"%s\" is not an UBI character device", node); -+ } -+ -+ if (ubi_get_info((libubi_t *)lib, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ int major1, minor1, ret; -+ -+ ret = dev_get_major(lib, i, &major1, &minor1); -+ if (ret) { -+ if (errno == ENOENT) -+ continue; -+ return -1; -+ } -+ -+ if (major1 == major) { -+ if (minor1 != 0) { -+ errmsg("UBI character device minor number is " -+ "%d, but must be 0", minor1); -+ errno = EINVAL; -+ return -1; -+ } -+ errno = 0; -+ *dev_num = i; -+ return 0; -+ } -+ } -+ -+ errno = ENODEV; -+ return -1; -+} -+ -+int mtd_num2ubi_dev(libubi_t desc, int mtd_num, int *dev_num) -+{ -+ struct ubi_info info; -+ int i, ret, mtd_num1; -+ struct libubi *lib = desc; -+ -+ if (ubi_get_info(desc, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ ret = dev_read_int(lib->dev_mtd_num, i, &mtd_num1); -+ if (ret) { -+ if (errno == ENOENT) -+ continue; -+ return -1; -+ } -+ -+ if (mtd_num1 == mtd_num) { -+ errno = 0; -+ *dev_num = i; -+ return 0; -+ } -+ } -+ -+ errno = 0; -+ return -1; -+} -+ -+libubi_t libubi_open(int required) -+{ -+ int fd, version; -+ struct libubi *lib; -+ -+ lib = calloc(1, sizeof(struct libubi)); -+ if (!lib) -+ return NULL; -+ -+ /* TODO: this must be discovered instead */ -+ lib->sysfs = strdup("/sys"); -+ if (!lib->sysfs) -+ goto out_error; -+ -+ lib->sysfs_ctrl = mkpath(lib->sysfs, SYSFS_CTRL); -+ if (!lib->sysfs_ctrl) -+ goto out_error; -+ -+ lib->ctrl_dev = mkpath(lib->sysfs_ctrl, CTRL_DEV); -+ if (!lib->ctrl_dev) -+ goto out_error; -+ -+ lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI); -+ if (!lib->sysfs_ubi) -+ goto out_error; -+ -+ /* Make sure UBI is present */ -+ fd = open(lib->sysfs_ubi, O_RDONLY); -+ if (fd == -1) { -+ if (required) -+ errmsg("cannot open \"%s\", UBI does not seem to " -+ "exist in system", lib->sysfs_ubi); -+ goto out_error; -+ } -+ -+ if (close(fd)) { -+ sys_errmsg("close failed on \"%s\"", lib->sysfs_ubi); -+ goto out_error; -+ } -+ -+ lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT); -+ if (!lib->ubi_dev) -+ goto out_error; -+ -+ lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER); -+ if (!lib->ubi_version) -+ goto out_error; -+ -+ lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV); -+ if (!lib->dev_dev) -+ goto out_error; -+ -+ lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS); -+ if (!lib->dev_avail_ebs) -+ goto out_error; -+ -+ lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS); -+ if (!lib->dev_total_ebs) -+ goto out_error; -+ -+ lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT); -+ if (!lib->dev_bad_count) -+ goto out_error; -+ -+ lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE); -+ if (!lib->dev_eb_size) -+ goto out_error; -+ -+ lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC); -+ if (!lib->dev_max_ec) -+ goto out_error; -+ -+ lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD); -+ if (!lib->dev_bad_rsvd) -+ goto out_error; -+ -+ lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS); -+ if (!lib->dev_max_vols) -+ goto out_error; -+ -+ lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE); -+ if (!lib->dev_min_io_size) -+ goto out_error; -+ -+ lib->dev_mtd_num = mkpath(lib->ubi_dev, DEV_MTD_NUM); -+ if (!lib->dev_mtd_num) -+ goto out_error; -+ -+ lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT); -+ if (!lib->ubi_vol) -+ goto out_error; -+ -+ lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE); -+ if (!lib->vol_type) -+ goto out_error; -+ -+ lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV); -+ if (!lib->vol_dev) -+ goto out_error; -+ -+ lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT); -+ if (!lib->vol_alignment) -+ goto out_error; -+ -+ lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES); -+ if (!lib->vol_data_bytes) -+ goto out_error; -+ -+ lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS); -+ if (!lib->vol_rsvd_ebs) -+ goto out_error; -+ -+ lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE); -+ if (!lib->vol_eb_size) -+ goto out_error; -+ -+ lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED); -+ if (!lib->vol_corrupted) -+ goto out_error; -+ -+ lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME); -+ if (!lib->vol_name) -+ goto out_error; -+ -+ if (read_positive_int(lib->ubi_version, &version)) -+ goto out_error; -+ if (version != LIBUBI_UBI_VERSION) { -+ errmsg("this library was made for UBI version %d, but UBI " -+ "version %d is detected\n", LIBUBI_UBI_VERSION, version); -+ goto out_error; -+ } -+ -+ return lib; -+ -+out_error: -+ libubi_close((libubi_t)lib); -+ return NULL; -+} -+ -+void libubi_close(libubi_t desc) -+{ -+ struct libubi *lib = (struct libubi *)desc; -+ -+ free(lib->vol_name); -+ free(lib->vol_corrupted); -+ free(lib->vol_eb_size); -+ free(lib->vol_rsvd_ebs); -+ free(lib->vol_data_bytes); -+ free(lib->vol_alignment); -+ free(lib->vol_dev); -+ free(lib->vol_type); -+ free(lib->ubi_vol); -+ free(lib->dev_mtd_num); -+ free(lib->dev_min_io_size); -+ free(lib->dev_max_vols); -+ free(lib->dev_bad_rsvd); -+ free(lib->dev_max_ec); -+ free(lib->dev_eb_size); -+ free(lib->dev_bad_count); -+ free(lib->dev_total_ebs); -+ free(lib->dev_avail_ebs); -+ free(lib->dev_dev); -+ free(lib->ubi_version); -+ free(lib->ubi_dev); -+ free(lib->sysfs_ubi); -+ free(lib->ctrl_dev); -+ free(lib->sysfs_ctrl); -+ free(lib->sysfs); -+ free(lib); -+} -+ -+int ubi_attach_mtd(libubi_t desc, const char *node, -+ struct ubi_attach_request *req) -+{ -+ int fd, ret; -+ struct ubi_attach_req r; -+ -+ memset(&r, sizeof(struct ubi_attach_req), '\0'); -+ -+ desc = desc; -+ r.ubi_num = req->dev_num; -+ r.mtd_num = req->mtd_num; -+ r.vid_hdr_offset = req->vid_hdr_offset; -+ -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ ret = ioctl(fd, UBI_IOCATT, &r); -+ close(fd); -+ if (ret == -1) -+ return -1; -+ -+ req->dev_num = r.ubi_num; -+ -+#ifdef UDEV_SETTLE_HACK -+ if (system("udevsettle") == -1) -+ return -1; -+ if (system("udevsettle") == -1) -+ return -1; -+#endif -+ -+ return ret; -+} -+ -+int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num) -+{ -+ int ret, ubi_dev; -+ -+ ret = mtd_num2ubi_dev(desc, mtd_num, &ubi_dev); -+ if (ret == -1) { -+ errno = ENODEV; -+ return ret; -+ } -+ -+ return ubi_remove_dev(desc, node, ubi_dev); -+} -+ -+int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev) -+{ -+ int fd, ret; -+ -+ desc = desc; -+ -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ ret = ioctl(fd, UBI_IOCDET, &ubi_dev); -+ if (ret == -1) -+ goto out_close; -+ -+#ifdef UDEV_SETTLE_HACK -+ if (system("udevsettle") == -1) -+ return -1; -+#endif -+ -+out_close: -+ close(fd); -+ return ret; -+} -+ -+int ubi_node_type(libubi_t desc, const char *node) -+{ -+ struct stat st; -+ struct ubi_info info; -+ int i, fd, major, minor; -+ struct libubi *lib = (struct libubi *)desc; -+ char file[strlen(lib->ubi_vol) + 100]; -+ -+ if (lstat(node, &st)) -+ return -1; -+ -+ if (!S_ISCHR(st.st_mode)) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ major = major(st.st_rdev); -+ minor = minor(st.st_rdev); -+ -+ if (ubi_get_info((libubi_t *)lib, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ int major1, minor1, ret; -+ -+ ret = dev_get_major(lib, i, &major1, &minor1); -+ if (ret) { -+ if (errno == ENOENT) -+ continue; -+ return -1; -+ } -+ -+ if (major1 == major) -+ break; -+ } -+ -+ if (i > info.highest_dev_num) { -+ /* -+ * The character device node does not correspond to any -+ * existing UBI device or volume, but we do not want to return -+ * any error number in this case, to indicate the fact that it -+ * could be a UBI device/volume, but it doesn't. -+ */ -+ errno = 0; -+ return -1; -+ } -+ -+ if (minor == 0) -+ return 1; -+ -+ /* This is supposdely an UBI volume device node */ -+ sprintf(file, lib->ubi_vol, i, minor - 1); -+ fd = open(file, O_RDONLY); -+ if (fd == -1) { -+ errno = 0; -+ return -1; -+ } -+ -+ return 2; -+} -+ -+int ubi_get_info(libubi_t desc, struct ubi_info *info) -+{ -+ DIR *sysfs_ubi; -+ struct dirent *dirent; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ memset(info, '\0', sizeof(struct ubi_info)); -+ -+ if (read_major(lib->ctrl_dev, &info->ctrl_major, &info->ctrl_minor)) { -+ /* -+ * Older UBI versions did not have control device, so we do not -+ * panic here for compatibility reasons. May be few years later -+ * we could return -1 here, but for now just set major:minor to -+ * -1. -+ */ -+ info->ctrl_major = info->ctrl_minor = -1; -+ } -+ -+ /* -+ * We have to scan the UBI sysfs directory to identify how many UBI -+ * devices are present. -+ */ -+ sysfs_ubi = opendir(lib->sysfs_ubi); -+ if (!sysfs_ubi) -+ return sys_errmsg("cannot open %s", lib->sysfs_ubi); -+ -+ info->lowest_dev_num = INT_MAX; -+ while (1) { -+ int dev_num, ret; -+ char tmp_buf[256]; -+ -+ errno = 0; -+ dirent = readdir(sysfs_ubi); -+ if (!dirent) -+ break; -+ -+ if (strlen(dirent->d_name) > 256) { -+ errmsg("invalid entry in %s: \"%s\"", -+ lib->sysfs_ubi, dirent->d_name); -+ goto out_close; -+ } -+ -+ ret = sscanf(dirent->d_name, UBI_DEV_NAME_PATT"%s", -+ &dev_num, tmp_buf); -+ if (ret == 1) { -+ info->dev_count += 1; -+ if (dev_num > info->highest_dev_num) -+ info->highest_dev_num = dev_num; -+ if (dev_num < info->lowest_dev_num) -+ info->lowest_dev_num = dev_num; -+ } -+ } -+ -+ if (!dirent && errno) { -+ sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi); -+ goto out_close; -+ } -+ -+ if (closedir(sysfs_ubi)) -+ return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi); -+ -+ if (info->lowest_dev_num == INT_MAX) -+ info->lowest_dev_num = 0; -+ -+ if (read_positive_int(lib->ubi_version, &info->version)) -+ return -1; -+ -+ return 0; -+ -+out_close: -+ closedir(sysfs_ubi); -+ return -1; -+} -+ -+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req) -+{ -+ int fd, ret; -+ struct ubi_mkvol_req r; -+ size_t n; -+ -+ memset(&r, sizeof(struct ubi_mkvol_req), '\0'); -+ -+ desc = desc; -+ r.vol_id = req->vol_id; -+ r.alignment = req->alignment; -+ r.bytes = req->bytes; -+ r.vol_type = req->vol_type; -+ -+ n = strlen(req->name); -+ if (n > UBI_MAX_VOLUME_NAME) -+ return -1; -+ -+ strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1); -+ r.name_len = n; -+ -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ ret = ioctl(fd, UBI_IOCMKVOL, &r); -+ if (ret == -1) -+ goto out_close; -+ -+ req->vol_id = r.vol_id; -+ -+#ifdef UDEV_SETTLE_HACK -+ if (system("udevsettle") == -1) -+ return -1; -+#endif -+ -+out_close: -+ close(fd); -+ return ret; -+} -+ -+int ubi_rmvol(libubi_t desc, const char *node, int vol_id) -+{ -+ int fd, ret; -+ -+ desc = desc; -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ ret = ioctl(fd, UBI_IOCRMVOL, &vol_id); -+ if (ret == -1) -+ goto out_close; -+ -+#ifdef UDEV_SETTLE_HACK -+ if (system("udevsettle") == -1) -+ return -1; -+#endif -+ -+out_close: -+ close(fd); -+ return ret; -+} -+ -+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes) -+{ -+ int fd, ret; -+ struct ubi_rsvol_req req; -+ -+ desc = desc; -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ req.bytes = bytes; -+ req.vol_id = vol_id; -+ -+ ret = ioctl(fd, UBI_IOCRSVOL, &req); -+ close(fd); -+ return ret; -+} -+ -+int ubi_update_start(libubi_t desc, int fd, long long bytes) -+{ -+ desc = desc; -+ if (ioctl(fd, UBI_IOCVOLUP, &bytes)) -+ return -1; -+ return 0; -+} -+ -+int ubi_leb_read_start(int fd, struct ubi_leb *leb) -+{ -+ return ioctl(fd, UBI_IOCLEBREAD, leb); -+} -+ -+int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes, int dtype) -+{ -+ struct ubi_leb_change_req req; -+ -+ desc = desc; -+ memset(&req, 0, sizeof(struct ubi_leb_change_req)); -+ req.lnum = lnum; -+ req.bytes = bytes; -+ req.dtype = dtype; -+ -+ if (ioctl(fd, UBI_IOCEBCH, &req)) -+ return -1; -+ return 0; -+} -+ -+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info) -+{ -+ DIR *sysfs_ubi; -+ struct dirent *dirent; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ memset(info, '\0', sizeof(struct ubi_dev_info)); -+ info->dev_num = dev_num; -+ -+ sysfs_ubi = opendir(lib->sysfs_ubi); -+ if (!sysfs_ubi) -+ return -1; -+ -+ info->lowest_vol_num = INT_MAX; -+ -+ while (1) { -+ int vol_id, ret, devno; -+ char tmp_buf[256]; -+ -+ errno = 0; -+ dirent = readdir(sysfs_ubi); -+ if (!dirent) -+ break; -+ -+ if (strlen(dirent->d_name) > 256) { -+ errmsg("invalid entry in %s: \"%s\"", -+ lib->sysfs_ubi, dirent->d_name); -+ goto out_close; -+ } -+ -+ ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT"%s", &devno, &vol_id, tmp_buf); -+ if (ret == 2 && devno == dev_num) { -+ info->vol_count += 1; -+ if (vol_id > info->highest_vol_num) -+ info->highest_vol_num = vol_id; -+ if (vol_id < info->lowest_vol_num) -+ info->lowest_vol_num = vol_id; -+ } -+ } -+ -+ if (!dirent && errno) { -+ sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi); -+ goto out_close; -+ } -+ -+ if (closedir(sysfs_ubi)) -+ return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi); -+ -+ if (info->lowest_vol_num == INT_MAX) -+ info->lowest_vol_num = 0; -+ -+ if (dev_get_major(lib, dev_num, &info->major, &info->minor)) -+ return -1; -+ -+ if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_lebs)) -+ return -1; -+ if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_lebs)) -+ return -1; -+ if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count)) -+ return -1; -+ if (dev_read_int(lib->dev_eb_size, dev_num, &info->leb_size)) -+ return -1; -+ if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd)) -+ return -1; -+ if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec)) -+ return -1; -+ if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count)) -+ return -1; -+ if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size)) -+ return -1; -+ -+ info->avail_bytes = info->avail_lebs * info->leb_size; -+ info->total_bytes = info->total_lebs * info->leb_size; -+ -+ return 0; -+ -+out_close: -+ closedir(sysfs_ubi); -+ return -1; -+} -+ -+int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info) -+{ -+ int dev_num; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ if (dev_node2num(lib, node, &dev_num)) -+ return -1; -+ -+ return ubi_get_dev_info1(desc, dev_num, info); -+} -+ -+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, -+ struct ubi_vol_info *info) -+{ -+ int ret; -+ struct libubi *lib = (struct libubi *)desc; -+ char buf[50]; -+ -+ memset(info, '\0', sizeof(struct ubi_vol_info)); -+ info->dev_num = dev_num; -+ info->vol_id = vol_id; -+ -+ if (dev_get_major(lib, dev_num, &info->dev_major, &info->dev_minor)) -+ return -1; -+ if (vol_get_major(lib, dev_num, vol_id, &info->major, &info->minor)) -+ return -1; -+ -+ ret = vol_read_data(lib->vol_type, dev_num, vol_id, buf, 50); -+ if (ret < 0) -+ return -1; -+ -+ if (strncmp(buf, "static\n", ret) == 0) -+ info->type = UBI_STATIC_VOLUME; -+ else if (strncmp(buf, "dynamic\n", ret) == 0) -+ info->type = UBI_DYNAMIC_VOLUME; -+ else { -+ errmsg("bad value at \"%s\"", buf); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ ret = vol_read_int(lib->vol_alignment, dev_num, vol_id, -+ &info->alignment); -+ if (ret) -+ return -1; -+ ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id, -+ &info->data_bytes); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_lebs); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->leb_size); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id, -+ &info->corrupted); -+ if (ret) -+ return -1; -+ info->rsvd_bytes = info->leb_size * info->rsvd_lebs; -+ -+ ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name, -+ UBI_VOL_NAME_MAX + 2); -+ if (ret < 0) -+ return -1; -+ -+ info->name[ret - 1] = '\0'; -+ return 0; -+} -+ -+int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info) -+{ -+ int vol_id, dev_num; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ if (vol_node2nums(lib, node, &dev_num, &vol_id)) -+ return -1; -+ -+ return ubi_get_vol_info1(desc, dev_num, vol_id, info); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,133 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#ifndef __LIBUBI_INT_H__ -+#define __LIBUBI_INT_H__ -+ -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * The below are pre-define UBI file and directory names. -+ * -+ * Note, older kernels put 'ubiX_Y' directories straight to '/sys/class/ubi/'. -+ * New kernels puts 'ubiX_Y' directories to '/sys/class/ubi/ubiX/', which is -+ * saner. And for compatibility reasons it also puts symlinks to 'ubiX_Y' -+ * directories to '/sys/class/ubi/'. For now libubi assumes old layout. -+ */ -+ -+#define SYSFS_UBI "class/ubi" -+#define SYSFS_CTRL "class/misc/ubi_ctrl/" -+ -+#define CTRL_DEV "dev" -+ -+#define UBI_VER "version" -+#define UBI_DEV_NAME_PATT "ubi%d" -+ -+#define DEV_DEV "dev" -+#define DEV_AVAIL_EBS "avail_eraseblocks" -+#define DEV_TOTAL_EBS "total_eraseblocks" -+#define DEV_BAD_COUNT "bad_peb_count" -+#define DEV_EB_SIZE "eraseblock_size" -+#define DEV_MAX_EC "max_ec" -+#define DEV_MAX_RSVD "reserved_for_bad" -+#define DEV_MAX_VOLS "max_vol_count" -+#define DEV_MIN_IO_SIZE "min_io_size" -+#define DEV_MTD_NUM "mtd_num" -+ -+#define UBI_VOL_NAME_PATT "ubi%d_%d" -+#define VOL_TYPE "type" -+#define VOL_DEV "dev" -+#define VOL_ALIGNMENT "alignment" -+#define VOL_DATA_BYTES "data_bytes" -+#define VOL_RSVD_EBS "reserved_ebs" -+#define VOL_EB_SIZE "usable_eb_size" -+#define VOL_CORRUPTED "corrupted" -+#define VOL_NAME "name" -+ -+/** -+ * libubi - UBI library description data structure. -+ * @sysfs: sysfs file system path -+ * @sysfs_ctrl: UBI control device directory in sysfs -+ * @ctrl_dev: UBI control device major/minor numbers sysfs file -+ * @sysfs_ubi: UBI directory in sysfs -+ * @ubi_dev: UBI device sysfs directory pattern -+ * @ubi_version: UBI version file sysfs path -+ * @dev_dev: UBI device major/minor numbers file pattern -+ * @dev_avail_ebs: count of available eraseblocks sysfs path pattern -+ * @dev_total_ebs: total eraseblocks count sysfs path pattern -+ * @dev_bad_count: count of bad eraseblocks sysfs path pattern -+ * @dev_eb_size: size of UBI device's eraseblocks sysfs path pattern -+ * @dev_max_ec: maximum erase counter sysfs path pattern -+ * @dev_bad_rsvd: count of physical eraseblock reserved for bad eraseblocks -+ * handling -+ * @dev_max_vols: maximum volumes number count sysfs path pattern -+ * @dev_min_io_size: minimum I/O unit size sysfs path pattern -+ * @ubi_vol: UBI volume sysfs directory pattern -+ * @vol_type: volume type sysfs path pattern -+ * @vol_dev: volume major/minor numbers file pattern -+ * @vol_alignment: volume alignment sysfs path pattern -+ * @vol_data_bytes: volume data size sysfs path pattern -+ * @vol_rsvd_ebs: volume reserved size sysfs path pattern -+ * @vol_eb_size: volume eraseblock size sysfs path pattern -+ * @vol_corrupted: volume corruption flag sysfs path pattern -+ * @vol_name: volume name sysfs path pattern -+ */ -+struct libubi -+{ -+ char *sysfs; -+ char *sysfs_ctrl; -+ char *ctrl_dev; -+ char *sysfs_ubi; -+ char *ubi_dev; -+ char *ubi_version; -+ char *dev_dev; -+ char *dev_avail_ebs; -+ char *dev_total_ebs; -+ char *dev_bad_count; -+ char *dev_eb_size; -+ char *dev_max_ec; -+ char *dev_bad_rsvd; -+ char *dev_max_vols; -+ char *dev_min_io_size; -+ char *dev_mtd_num; -+ char *ubi_vol; -+ char *vol_type; -+ char *vol_dev; -+ char *vol_alignment; -+ char *vol_data_bytes; -+ char *vol_rsvd_ebs; -+ char *vol_eb_size; -+ char *vol_corrupted; -+ char *vol_name; -+ char *vol_max_count; -+}; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__LIBUBI_INT_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,335 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Generating UBI images. -+ * -+ * Authors: Oliver Lohmann -+ * Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include "crc32.h" -+#include "common.h" -+ -+#define PROGRAM_NAME "libubigen" -+ -+/** -+ * ubigen_info_init - initialize libubigen. -+ * @ui: libubigen information -+ * @peb_size: flash physical eraseblock size -+ * @min_io_size: flash minimum input/output unit size -+ * @subpage_size: flash sub-page, if present (has to be equivalent to -+ * @min_io_size if does not exist) -+ * @vid_hdr_offs: offset of the VID header -+ * @ubi_ver: UBI version -+ */ -+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size, -+ int subpage_size, int vid_hdr_offs, int ubi_ver) -+{ -+ if (!vid_hdr_offs) { -+ vid_hdr_offs = UBI_EC_HDR_SIZE + subpage_size - 1; -+ vid_hdr_offs /= subpage_size; -+ vid_hdr_offs *= subpage_size; -+ } -+ -+ ui->peb_size = peb_size; -+ ui->min_io_size = min_io_size; -+ ui->vid_hdr_offs = vid_hdr_offs; -+ ui->data_offs = vid_hdr_offs + UBI_VID_HDR_SIZE + min_io_size - 1; -+ ui->data_offs /= min_io_size; -+ ui->data_offs *= min_io_size; -+ ui->leb_size = peb_size - ui->data_offs; -+ ui->ubi_ver = ubi_ver; -+ -+ ui->max_volumes = ui->leb_size / UBI_VTBL_RECORD_SIZE; -+ if (ui->max_volumes > UBI_MAX_VOLUMES) -+ ui->max_volumes = UBI_MAX_VOLUMES; -+ ui->vtbl_size = ui->max_volumes * UBI_VTBL_RECORD_SIZE; -+} -+ -+/** -+ * ubigen_create_empty_vtbl - creates empty volume table. -+ * -+ * This function creates an empty volume table and returns a pointer to it in -+ * case of success and %NULL in case of failure. The returned object has to be -+ * freed with 'free()' call. -+ */ -+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui) -+{ -+ struct ubi_vtbl_record *vtbl; -+ int i; -+ -+ vtbl = calloc(1, ui->vtbl_size); -+ if (!vtbl) { -+ sys_errmsg("cannot allocate %d bytes of memory", ui->vtbl_size); -+ return NULL; -+ } -+ -+ for (i = 0; i < ui->max_volumes; i++) { -+ uint32_t crc = crc32(UBI_CRC32_INIT, &vtbl[i], -+ UBI_VTBL_RECORD_SIZE_CRC); -+ vtbl[i].crc = cpu_to_be32(crc); -+ } -+ -+ return vtbl; -+} -+ -+/** -+ * ubigen_add_volume - add a volume to the volume table. -+ * @ui: libubigen information -+ * @vi: volume information -+ * @vtbl: volume table to add to -+ * -+ * This function adds volume described by input parameters to the volume table -+ * @vtbl. -+ */ -+int ubigen_add_volume(const struct ubigen_info *ui, -+ const struct ubigen_vol_info *vi, -+ struct ubi_vtbl_record *vtbl) -+{ -+ struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id]; -+ uint32_t tmp; -+ -+ if (vi->id >= ui->max_volumes) -+ return errmsg("too high volume id %d, max. volumes is %d", -+ vi->id, ui->max_volumes); -+ -+ if (vi->alignment >= ui->leb_size) -+ return errmsg("too large alignment %d, max is %d (LEB size)", -+ vi->alignment, ui->leb_size); -+ -+ memset(vtbl_rec, '\0', sizeof(struct ubi_vtbl_record)); -+ tmp = (vi->bytes + ui->leb_size - 1) / ui->leb_size; -+ vtbl_rec->reserved_pebs = cpu_to_be32(tmp); -+ vtbl_rec->alignment = cpu_to_be32(vi->alignment); -+ vtbl_rec->vol_type = vi->type; -+ tmp = ui->leb_size % vi->alignment; -+ vtbl_rec->data_pad = cpu_to_be32(tmp); -+ vtbl_rec->flags = vi->flags; -+ -+ memcpy(vtbl_rec->name, vi->name, vi->name_len); -+ vtbl_rec->name[vi->name_len] = '\0'; -+ vtbl_rec->name_len = cpu_to_be16(vi->name_len); -+ -+ tmp = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC); -+ vtbl_rec->crc = cpu_to_be32(tmp); -+ return 0; -+} -+ -+/** -+ * ubigen_init_ec_hdr - initialize EC header. -+ * @ui: libubigen information -+ * @hdr: the EC header to initialize -+ * @ec: erase counter value -+ */ -+void ubigen_init_ec_hdr(const struct ubigen_info *ui, -+ struct ubi_ec_hdr *hdr, long long ec) -+{ -+ uint32_t crc; -+ -+ memset(hdr, '\0', sizeof(struct ubi_ec_hdr)); -+ -+ hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC); -+ hdr->version = ui->ubi_ver; -+ hdr->ec = cpu_to_be64(ec); -+ hdr->vid_hdr_offset = cpu_to_be32(ui->vid_hdr_offs); -+ -+ hdr->data_offset = cpu_to_be32(ui->data_offs); -+ -+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC); -+ hdr->hdr_crc = cpu_to_be32(crc); -+} -+ -+/** -+ * init_vid_hdr - initialize VID header. -+ * @ui: libubigen information -+ * @vi: volume information -+ * @hdr: the VID header to initialize -+ * @lnum: logical eraseblock number -+ * @data: the contents of the LEB (static volumes only) -+ * @data_size: amount of data in this LEB (static volumes only) -+ * -+ * Note, @used_ebs, @data and @data_size are ignored in case of dynamic -+ * volumes. -+ */ -+static void init_vid_hdr(const struct ubigen_info *ui, -+ const struct ubigen_vol_info *vi, -+ struct ubi_vid_hdr *hdr, int lnum, -+ const void *data, int data_size) -+{ -+ uint32_t crc; -+ -+ memset(hdr, '\0', sizeof(struct ubi_vid_hdr)); -+ -+ hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC); -+ hdr->version = ui->ubi_ver; -+ hdr->vol_type = vi->type; -+ hdr->vol_id = cpu_to_be32(vi->id); -+ hdr->lnum = cpu_to_be32(lnum); -+ hdr->data_pad = cpu_to_be32(vi->data_pad); -+ hdr->compat = vi->compat; -+ -+ if (vi->type == UBI_VID_STATIC) { -+ hdr->data_size = cpu_to_be32(data_size); -+ hdr->used_ebs = cpu_to_be32(vi->used_ebs); -+ crc = crc32(UBI_CRC32_INIT, data, data_size); -+ hdr->data_crc = cpu_to_be32(crc); -+ } -+ -+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC); -+ hdr->hdr_crc = cpu_to_be32(crc); -+} -+ -+/** -+ * ubigen_write_volume - write UBI volume. -+ * @ui: libubigen information -+ * @vi: volume information -+ * @ec: erase coutner value to put to EC headers -+ * @bytes: volume size in bytes -+ * @in: input file descriptor (has to be properly seeked) -+ * @out: output file descriptor -+ * -+ * This function reads the contents of the volume from the input file @in and -+ * writes the UBI volume to the output file @out. Returns zero on success and -+ * %-1 on failure. -+ */ -+int ubigen_write_volume(const struct ubigen_info *ui, -+ const struct ubigen_vol_info *vi, long long ec, -+ long long bytes, int in, int out) -+{ -+ int len = vi->usable_leb_size, rd, lnum = 0; -+ char inbuf[ui->leb_size+sizeof(unsigned int)], outbuf[ui->peb_size]; -+ -+ if (vi->id >= ui->max_volumes) -+ return errmsg("too high volume id %d, max. volumes is %d", -+ vi->id, ui->max_volumes); -+ -+ if (vi->alignment >= ui->leb_size) -+ return errmsg("too large alignment %d, max is %d (LEB size)", -+ vi->alignment, ui->leb_size); -+ -+ memset(outbuf, 0xFF, ui->data_offs); -+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec); -+ -+ while (bytes) { -+ int l; -+ struct ubi_vid_hdr *vid_hdr; -+ -+ if (bytes < len) -+ len = bytes; -+ bytes -= len; -+ -+ l = len; -+ do { -+ rd = read(in, inbuf + len - l, sizeof(unsigned int)); -+ if (rd != sizeof(unsigned int)) -+ return sys_errmsg("cannot read leb lnum from the input file"); -+ -+ rd = read(in, inbuf + len - l + sizeof(unsigned int), l); -+ if (rd != l) -+ return sys_errmsg("cannot read %d bytes from the input file", l); -+ -+ l -= rd; -+ } while (l); -+ -+ vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]); -+ lnum = ((unsigned int *)inbuf)[0]; -+ init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf+sizeof(unsigned int), len); -+ -+ memcpy(outbuf + ui->data_offs, inbuf+sizeof(unsigned int), len); -+ memset(outbuf + ui->data_offs + len, 0xFF, -+ ui->peb_size - ui->data_offs - len); -+ -+ if (write(out, outbuf, ui->peb_size) != ui->peb_size) -+ return sys_errmsg("cannot write %d bytes to the output file", ui->peb_size); -+ -+// lnum += 1; -+ } -+ -+ return 0; -+} -+ -+/** -+ * ubigen_write_layout_vol - write UBI layout volume -+ * @ui: libubigen information -+ * @peb1: physical eraseblock number to write the first volume table copy -+ * @peb2: physical eraseblock number to write the second volume table copy -+ * @ec1: erase counter value for @peb1 -+ * @ec2: erase counter value for @peb1 -+ * @vtbl: volume table -+ * @fd: output file descriptor seeked to the proper position -+ * -+ * This function creates the UBI layout volume which contains 2 copies of the -+ * volume table. Returns zero in case of success and %-1 in case of failure. -+ */ -+int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2, -+ long long ec1, long long ec2, -+ struct ubi_vtbl_record *vtbl, int fd) -+{ -+ int ret; -+ struct ubigen_vol_info vi; -+ char outbuf[ui->peb_size]; -+ struct ubi_vid_hdr *vid_hdr; -+ off_t seek; -+ -+ vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS; -+ vi.id = UBI_LAYOUT_VOLUME_ID; -+ vi.alignment = UBI_LAYOUT_VOLUME_ALIGN; -+ vi.data_pad = ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN; -+ vi.usable_leb_size = ui->leb_size - vi.data_pad; -+ vi.data_pad = ui->leb_size - vi.usable_leb_size; -+ vi.type = UBI_LAYOUT_VOLUME_TYPE; -+ vi.name = UBI_LAYOUT_VOLUME_NAME; -+ vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME); -+ vi.compat = UBI_LAYOUT_VOLUME_COMPAT; -+ -+ memset(outbuf, 0xFF, ui->data_offs); -+ vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]); -+ memcpy(outbuf + ui->data_offs, vtbl, ui->vtbl_size); -+ memset(outbuf + ui->data_offs + ui->vtbl_size, 0xFF, -+ ui->peb_size - ui->data_offs - ui->vtbl_size); -+ -+ seek = peb1 * ui->peb_size; -+ if (lseek(fd, seek, SEEK_SET) != seek) -+ return sys_errmsg("cannot seek output file"); -+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec1); -+ init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0); -+ ret = write(fd, outbuf, ui->peb_size); -+ if (ret != ui->peb_size) -+ return sys_errmsg("cannot write %d bytes", ui->peb_size); -+ -+ seek = peb2 * ui->peb_size; -+ if (lseek(fd, seek, SEEK_SET) != seek) -+ return sys_errmsg("cannot seek output file"); -+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec2); -+ init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0); -+ ret = write(fd, outbuf, ui->peb_size); -+ if (ret != ui->peb_size) -+ return sys_errmsg("cannot write %d bytes", ui->peb_size); -+ -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,205 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * An utility to attach MTD devices to UBI. -+ * -+ * Author: Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubiattach" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ int devn; -+ int mtdn; -+ int vidoffs; -+ const char *node; -+}; -+ -+static struct args args = { -+ .devn = UBI_DEV_NUM_AUTO, -+ .mtdn = -1, -+ .vidoffs = 0, -+ .node = NULL, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to attach MTD device to UBI."; -+ -+static const char *optionsstr = -+"-d, --devn= the number to assign to the newly created UBI device\n" -+" (the number is assigned automatically if this is not\n" -+" specified\n" -+"-m, --mtdn= MTD device number to attach\n" -+"-O, --vid-hdr-offset VID header offset (do not specify this unless you\n" -+" really know what you do and the optimal defaults will\n" -+" be used)\n" -+"-h, --help print help message\n" -+"-V, --version print program version"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-m ] [-d ]\n" -+"\t\t[--mtdn=] [--devn ]\n" -+"Example 1: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 - attach MTD device 0 (mtd0) to UBI\n" -+"Example 2: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 -d 3 - attach MTD device 0 (mtd0) to UBI and\n" -+" and create UBI device number 3 (ubi3)"; -+ -+static const struct option long_options[] = { -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' }, -+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "m:d:O:hV", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'd': -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: \"%s\"", optarg); -+ -+ break; -+ -+ case 'm': -+ args.mtdn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.mtdn < 0) -+ return errmsg("bad MTD device number: \"%s\"", optarg); -+ -+ break; -+ -+ case 'O': -+ args.vidoffs = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.vidoffs <= 0) -+ return errmsg("bad VID header offset: \"%s\"", optarg); -+ -+ break; -+ -+ case 'h': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ if (optind == argc) -+ return errmsg("UBI control device name was not specified (use -h for help)"); -+ else if (optind != argc - 1) -+ return errmsg("more then one UBI control device specified (use -h for help)"); -+ -+ if (args.mtdn == -1) -+ return errmsg("MTD device number was not specified (use -h for help)"); -+ -+ args.node = argv[optind]; -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_info ubi_info; -+ struct ubi_dev_info dev_info; -+ struct ubi_attach_request req; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) -+ return sys_errmsg("cannot open libubi"); -+ -+ /* -+ * Make sure the kernel is fresh enough and this feature is supported. -+ */ -+ err = ubi_get_info(libubi, &ubi_info); -+ if (err) { -+ sys_errmsg("cannot get UBI information"); -+ goto out_libubi; -+ } -+ -+ if (ubi_info.ctrl_major == -1) { -+ errmsg("MTD attach/detach feature is not supported by your kernel"); -+ goto out_libubi; -+ } -+ -+ req.dev_num = args.devn; -+ req.mtd_num = args.mtdn; -+ req.vid_hdr_offset = args.vidoffs; -+ -+ err = ubi_attach_mtd(libubi, args.node, &req); -+ if (err) { -+ sys_errmsg("cannot attach mtd%d", args.mtdn); -+ goto out_libubi; -+ } -+ -+ /* Print some information about the new UBI device */ -+ err = ubi_get_dev_info1(libubi, req.dev_num, &dev_info); -+ if (err) { -+ sys_errmsg("cannot get information about newly created UBI device"); -+ goto out_libubi; -+ } -+ -+ printf("UBI device number %d, total %d LEBs (", dev_info.dev_num, dev_info.total_lebs); -+ ubiutils_print_bytes(dev_info.total_bytes, 0); -+ printf("), available %d LEBs (", dev_info.avail_lebs); -+ ubiutils_print_bytes(dev_info.avail_bytes, 0); -+ printf("), LEB size "); -+ ubiutils_print_bytes(dev_info.leb_size, 1); -+ printf("\n"); -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,124 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Calculate CRC32 with UBI start value (0xFFFFFFFF) for a given binary image. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "crc32.h" -+#include "common.h" -+ -+#define BUFSIZE 4096 -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubicrc32" -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to calculate CRC32 with UBI start value (0xFFFFFFFF)"; -+ -+static const char *optionsstr = -+"-h, --help print help message\n" -+"-V, --version print program version"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-h] [--help]"; -+ -+static const struct option long_options[] = { -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "hV", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'h': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err = 0; -+ uint32_t crc = UBI_CRC32_INIT; -+ char buf[BUFSIZE]; -+ FILE *fp; -+ -+ if (argc > 1) { -+ fp = fopen(argv[1], "r"); -+ if (!fp) -+ return sys_errmsg("cannot open \"%s\"", argv[1]); -+ } else -+ fp = stdin; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return err; -+ -+ while (!feof(fp)) { -+ size_t read; -+ -+ read = fread(buf, 1, BUFSIZE, fp); -+ if (ferror(fp)) { -+ sys_errmsg("cannot read input file"); -+ err = -1; -+ goto out_close; -+ } -+ crc = crc32(crc, buf, read); -+ } -+ -+ printf("0x%08x\n", crc); -+ -+out_close: -+ if (fp != stdin) -+ fclose(fp); -+ return err; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,94 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to generate input file CRC -+ * -+ * Authors: Yurong Tan (Nancy) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+#include "crc32.h" -+ -+#define PROGRAM_VERSION "1.1" -+#define PROGRAM_NAME "ubicrcsf" -+#define UBI_LEB_SIZE 258048 -+#define BUF_SIZE (UBI_LEB_SIZE + sizeof(unsigned int)) -+ -+/* -+ * usage: $ubicrcsf ubifs.img -+ */ -+int main(int argc, char * const argv[]) -+{ -+ int err, ifd, tmp, i; -+ int crc_sum = 0; -+ struct stat st; -+ char *buf=NULL; -+ -+ buf = malloc(BUF_SIZE); -+ if(buf==NULL){ -+ printf("no mem\n"); -+ goto out_free; -+ } -+ -+ err = stat(argv[1], &st); -+ if (err < 0) { -+ printf("stat failed on \"%s\"", argv[1]); -+ goto out_free; -+ } -+ -+ ifd = open(argv[1], O_RDONLY); -+ if (ifd == -1) { -+ printf("cannot open \"%s\"", argv[1]); -+ goto out_close; -+ } -+ -+ tmp = st.st_size/BUF_SIZE; -+ -+ for( i=0; i< tmp; i++ ){ -+ err = read(ifd, buf, BUF_SIZE); -+ if (err != BUF_SIZE) { -+ printf("read error\n"); -+ goto out_close; -+ } -+ crc_sum = crc32(crc_sum, &buf[sizeof(unsigned int)], UBI_LEB_SIZE); -+ } -+ -+ printf("CRC sum: %d\n",crc_sum); -+ free(buf); -+ close(ifd); -+ return 0; -+out_close: -+ close(ifd); -+out_free: -+ free(buf); -+ return -1; -+} -+ -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,221 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to update UBI volumes. -+ * -+ * Authors: Frank Haverkamp -+ * Joshua W. Boyer -+ * Artem Bityutskiy -+ * Yurong Tan (Nancy) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+#include "crc32.h" -+ -+#define PROGRAM_VERSION "1.1" -+#define PROGRAM_NAME "ubicrcfatvol" -+ -+struct args { -+ const char *node; -+ long long size; -+ int devn; -+ char dev_name[256]; -+}; -+ -+static struct args args = { -+ .devn = -1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to read UBI volumes data and generate CRC."; -+ -+static const char *optionsstr = -+"-h, --help print help message\n" -+"-V, --version print program version\n\n" -+"-s, --read size\n" -+; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-s] [-h] [-V] [--help]\n" -+"\t\t\t[--version] \n\n" -+ "Example 1: " PROGRAM_NAME " /dev/ubi0_1 \n"; -+ -+struct option long_options[] = { -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ /* Deprecated -d and -B options */ -+ { .name = "size", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "n:sh?Vd:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 's': -+ args.size = ubiutils_get_bytes(optarg); -+ if (args.size <= 0) -+ return errmsg("bad read size: \"%s\"", optarg); -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ /* Handle deprecated -d option */ -+ if (args.devn != -1) { -+ sprintf(args.dev_name, "/dev/ubi%d", args.devn); -+ args.node = args.dev_name; -+ } else { -+ if (optind == argc) -+ return errmsg("UBI device name was not specified (use -h for help)"); -+ else if (optind != argc - 1) -+ return errmsg("specify UBI device name and image file name as first 2 " -+ "parameters (use -h for help)"); -+ } -+ -+ args.node = argv[optind]; -+ -+ return 0; -+} -+ -+static int crc_volume(libubi_t libubi, struct ubi_vol_info *vol_info) -+{ -+ int fd; -+ struct ubi_leb leb; -+ int i, tmp; -+ int crc_sum = 0; -+ -+ leb.buf = malloc(vol_info->leb_size); -+ if (!leb.buf) -+ return errmsg("cannot allocate %d bytes of memory", vol_info->leb_size); -+ -+ fd = open(args.node, O_RDONLY); -+ if (fd == -1) { -+ sys_errmsg("cannot open UBI volume \"%s\"", args.node); -+ goto out_free; -+ } -+ -+ for(i=0; i < vol_info->rsvd_lebs ; i++){ -+ leb.lnum = i; -+ tmp = ubi_leb_read_start(fd, &leb); -+ if(tmp == 1) -+ continue; -+ else if(tmp == 0){ -+ crc_sum = crc32(crc_sum, leb.buf, vol_info->leb_size); -+ }else{ -+ printf("LEB %d read error\n", i); -+ goto out_close; -+ } -+ } -+ -+ close(fd); -+ free(leb.buf); -+ printf("CRC sum: %d\n",crc_sum); -+ return 0; -+ goto out_close; -+out_close: -+ close(fd); -+out_free: -+ free(leb.buf); -+ return -1; -+} -+ -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_vol_info vol_info; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) { -+ sys_errmsg("cannot open libubi"); -+ goto out_libubi; -+ } -+ -+ err = ubi_node_type(libubi, args.node); -+ if (err == 1) { -+ errmsg("\"%s\" is an UBI device node, not an UBI volume node", -+ args.node); -+ goto out_libubi; -+ } else if (err < 0) { -+ errmsg("\"%s\" is not an UBI volume node", args.node); -+ goto out_libubi; -+ } -+ -+ err = ubi_get_vol_info(libubi, args.node, &vol_info); -+ if (err) { -+ sys_errmsg("cannot get information about UBI volume \"%s\"", -+ args.node); -+ goto out_libubi; -+ } -+ -+ err = crc_volume(libubi, &vol_info); -+ if (err) -+ goto out_libubi; -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+ -+} -+ -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,181 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * An utility to delete UBI devices (detach MTD devices from UBI). -+ * -+ * Author: Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubidetach" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ int devn; -+ int mtdn; -+ const char *node; -+}; -+ -+static struct args args = { -+ .devn = UBI_DEV_NUM_AUTO, -+ .mtdn = -1, -+ .node = NULL, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+" - a tool to remove UBI devices (detach MTD devices from UBI)"; -+ -+static const char *optionsstr = -+"-d, --devn= UBI device number to delete\n" -+"-m, --mtdn= or altrnatively, MTD device number to detach -\n" -+" this will delete corresponding UBI device\n" -+"-h, --help print help message\n" -+"-V, --version print program version"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-d ] [-m ]\n" -+"\t\t[--devn ] [--mtdn=]\n" -+"Example 1: " PROGRAM_NAME " /dev/ubi_ctrl -d 2 - delete UBI device 2 (ubi2)\n" -+"Example 2: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 - detach MTD device 0 (mtd0)"; -+ -+static const struct option long_options[] = { -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "m:d:hV", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'd': -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: \"%s\"", optarg); -+ -+ break; -+ -+ case 'm': -+ args.mtdn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.mtdn < 0) -+ return errmsg("bad MTD device number: \"%s\"", optarg); -+ -+ break; -+ -+ case 'h': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ if (optind == argc) -+ return errmsg("UBI control device name was not specified (use -h for help)"); -+ else if (optind != argc - 1) -+ return errmsg("more then one UBI control device specified (use -h for help)"); -+ -+ if (args.mtdn == -1 && args.devn == -1) -+ return errmsg("neither MTD nor UBI devices were specified (use -h for help)"); -+ -+ if (args.mtdn != -1 && args.devn != -1) -+ return errmsg("specify either MTD or UBI device (use -h for help)"); -+ -+ args.node = argv[optind]; -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_info ubi_info; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) -+ return sys_errmsg("cannot open libubi"); -+ -+ /* -+ * Make sure the kernel is fresh enough and this feature is supported. -+ */ -+ err = ubi_get_info(libubi, &ubi_info); -+ if (err) { -+ sys_errmsg("cannot get UBI information"); -+ goto out_libubi; -+ } -+ -+ if (ubi_info.ctrl_major == -1) { -+ errmsg("MTD detach/detach feature is not supported by your kernel"); -+ goto out_libubi; -+ } -+ -+ if (args.devn != -1) { -+ err = ubi_remove_dev(libubi, args.node, args.devn); -+ if (err) { -+ sys_errmsg("cannot remove ubi%d", args.devn); -+ goto out_libubi; -+ } -+ } else { -+ err = ubi_detach_mtd(libubi, args.node, args.mtdn); -+ if (err) { -+ sys_errmsg("cannot detach mtd%d", args.mtdn); -+ goto out_libubi; -+ } -+ } -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,264 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to update UBI volumes. -+ * -+ * Authors: Frank Haverkamp -+ * Joshua W. Boyer -+ * Artem Bityutskiy -+ * Yurong Tan (Nancy) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.1" -+#define PROGRAM_NAME "ubidumpvol" -+ -+struct args { -+ int truncate; -+ const char *node; -+ const char *img; -+ /* For deprecated -d and -B options handling */ -+ int devn; -+ char dev_name[256]; -+ int broken_update; -+}; -+ -+static struct args args = { -+ .devn = -1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to write data to UBI volumes."; -+ -+static const char *optionsstr = -+"-n, --vol_id= ID of UBI volume to update\n" -+"-t, --truncate truncate volume (wipe it out)\n" -+"-h, --help print help message\n" -+"-V, --version print program version\n\n" -+"The following are compatibility options which are deprecated, do not use them\n" -+"-d, --devn= UBI device number - may be used instead of the UBI\n" -+" device node name in which case the utility assumes\n" -+" that the device node is \"/dev/ubi\"\n" -+"-B, --broken-update broken update, this is for testing"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-t] [-h] [-V] [--truncate] [--help]\n" -+"\t\t\t[--version] \n\n" -+ "Example 1: " PROGRAM_NAME " /dev/ubi0_1 fs.img - dump UBI volume /dev/ubi0_1 to file \"fs.img\" \n"; -+ -+struct option long_options[] = { -+ { .name = "truncate", .has_arg = 0, .flag = NULL, .val = 't' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ /* Deprecated -d and -B options */ -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "broken-update", .has_arg = 1, .flag = NULL, .val = 'B' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "n:th?Vd:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 't': -+ args.truncate = 1; -+ break; -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'd': -+ { -+ char *endp; -+ -+ /* Handle deprecated -d option */ -+ warnmsg("-d is depricated and will be removed, do not use it"); -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: " "\"%s\"", optarg); -+ break; -+ } -+ -+ case 'B': -+ /* Handle deprecated -B option */ -+ warnmsg("-B is depricated and will be removed, do not use it"); -+ args.broken_update = 1; -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ /* Handle deprecated -d option */ -+ if (args.devn != -1) { -+ sprintf(args.dev_name, "/dev/ubi%d", args.devn); -+ args.node = args.dev_name; -+ } else { -+ if (optind == argc) -+ return errmsg("UBI device name was not specified (use -h for help)"); -+ else if (optind != argc - 2) -+ return errmsg("specify UBI device name and image file name as first 2 " -+ "parameters (use -h for help)"); -+ } -+ -+ args.node = argv[optind]; -+ args.img = argv[optind + 1]; -+ -+ return 0; -+} -+ -+static int dump_volume(libubi_t libubi, struct ubi_vol_info *vol_info) -+{ -+ int err, fd, ifd; -+ struct ubi_leb leb; -+ int i, tmp; -+ -+ leb.buf = malloc(vol_info->leb_size); -+ if (!leb.buf) -+ return errmsg("cannot allocate %d bytes of memory", vol_info->leb_size); -+ -+ fd = open(args.node, O_RDONLY); -+ if (fd == -1) { -+ sys_errmsg("cannot open UBI volume \"%s\"", args.node); -+ goto out_free; -+ } -+ -+ ifd = open(args.img, O_WRONLY | O_TRUNC | O_CREAT, 0644); -+ if (ifd == -1) { -+ sys_errmsg("cannot open \"%s\"", args.img); -+ goto out_close1; -+ } -+ -+ for(i=0; i < vol_info->rsvd_lebs; i++){ -+ leb.lnum = i; -+ tmp = ubi_leb_read_start(fd, &leb); -+ if(tmp == 1) -+ continue; -+ else if(tmp == 0){ -+ // write lnum -+ err = write(ifd, (char *)&leb.lnum, sizeof(leb.lnum)); -+ if (err != sizeof(leb.lnum)){ -+ perror("Image file write error\n"); -+ goto out_close; -+ } -+ // write LEB data -+ err = write(ifd, leb.buf, vol_info->leb_size); -+ if (err != vol_info->leb_size){ -+ perror("Image file write error\n"); -+ goto out_close; -+ } -+ }else{ -+ printf("LEB %d read error\n", i); -+ goto out_close; -+ } -+ } -+ -+ close(ifd); -+ close(fd); -+ free(leb.buf); -+ printf("Dump Volume succeed\n"); -+ return 0; -+ goto out_close; -+out_close: -+ close(ifd); -+out_close1: -+ close(fd); -+out_free: -+ free(leb.buf); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_vol_info vol_info; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ if (!args.img && !args.truncate) -+ return errmsg("incorrect arguments, use -h for help"); -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) { -+ sys_errmsg("cannot open libubi"); -+ goto out_libubi; -+ } -+ -+ err = ubi_node_type(libubi, args.node); -+ if (err == 1) { -+ errmsg("\"%s\" is an UBI device node, not an UBI volume node", -+ args.node); -+ goto out_libubi; -+ } else if (err < 0) { -+ errmsg("\"%s\" is not an UBI volume node", args.node); -+ goto out_libubi; -+ } -+ -+ err = ubi_get_vol_info(libubi, args.node, &vol_info); -+ if (err) { -+ sys_errmsg("cannot get information about UBI volume \"%s\"", -+ args.node); -+ goto out_libubi; -+ } -+ -+ err = dump_volume(libubi, &vol_info); -+ if (err) -+ goto out_libubi; -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,712 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to format MTD devices into UBI and flash UBI images. -+ * -+ * Author: Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubiformat" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ unsigned int yes:1; -+ unsigned int quiet:1; -+ unsigned int verbose:1; -+ unsigned int override_ec:1; -+ unsigned int novtbl:1; -+ int subpage_size; -+ int vid_hdr_offs; -+ int ubi_ver; -+ long long ec; -+ const char *image; -+ const char *node; -+}; -+ -+static struct args args = -+{ -+ .ubi_ver = 1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to format MTD devices and flash UBI images"; -+ -+static const char *optionsstr = -+"-s, --sub-page-size= minimum input/output unit used for UBI\n" -+" headers, e.g. sub-page size in case of NAND\n" -+" flash (equivalent to the minimum input/output\n" -+" unit size by default)\n" -+"-O, --vid-hdr-offset= offset if the VID header from start of the\n" -+" physical eraseblock (default is the next\n" -+" minimum I/O unit or sub-page after the EC\n" -+" header)\n" -+"-n, --no-volume-table only erase all eraseblock and preserve erase\n" -+" counters, do not write empty volume table\n" -+"-f, --flash-image= flash image file\n" -+"-e, --erase-counter= use as the erase counter value for all\n" -+" eraseblocks\n" -+"-y, --yes assume the answer is \"yes\" for all question\n" -+" this program would otherwise ask\n" -+"-q, --quiet suppress progress percentage information\n" -+"-v, --verbose be verbose\n" -+"-x, --ubi-ver= UBI version number to put to EC headers\n" -+" (default is 1)\n" -+"-h, -?, --help print help message\n" -+"-V, --version print program version\n"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-h] [-V] [-y] [-q] [-v]\n" -+"\t\t\t[-x ] [-E ] [-s ] [-O ] [-n]\n" -+"\t\t\t[--help] [--version] [--yes] [--verbose] [--quiet]\n" -+"\t\t\t[--ec=] [--vid-hdr-offset=]\n" -+"\t\t\t[--ubi-ver=] [--no-volume-table]\n\n" -+ -+"Example 1: " PROGRAM_NAME " /dev/mtd0 -y - format MTD device number 0 and do\n" -+" not ask questions.\n" -+"Example 2: " PROGRAM_NAME " /dev/mtd0 -q -e 0 - format MTD device number 0,\n" -+" be quiet and force erase counter value 0."; -+ -+static const struct option long_options[] = { -+ { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' }, -+ { .name = "no-volume-table", .has_arg = 0, .flag = NULL, .val = 'n' }, -+ { .name = "flash-image", .has_arg = 0, .flag = NULL, .val = 'f' }, -+ { .name = "yes", .has_arg = 0, .flag = NULL, .val = 'y' }, -+ { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' }, -+ { .name = "quiet", .has_arg = 0, .flag = NULL, .val = 'q' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "nh?Vyqve:x:s:O:f:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 's': -+ args.subpage_size = ubiutils_get_bytes(optarg); -+ if (args.subpage_size <= 0) -+ return errmsg("bad sub-page size: \"%s\"", optarg); -+ if (!is_power_of_2(args.subpage_size)) -+ return errmsg("sub-page size should be power of 2"); -+ break; -+ -+ case 'O': -+ args.vid_hdr_offs = strtoul(optarg, &endp, 0); -+ if (args.vid_hdr_offs <= 0 || *endp != '\0' || endp == optarg) -+ return errmsg("bad VID header offset: \"%s\"", optarg); -+ break; -+ -+ case 'e': -+ args.ec = strtoull(optarg, &endp, 0); -+ if (args.ec <= 0 || *endp != '\0' || endp == optarg) -+ return errmsg("bad erase counter value: \"%s\"", optarg); -+ if (args.ec >= EC_MAX) -+ return errmsg("too high erase %llu, counter, max is %u", args.ec, EC_MAX); -+ args.override_ec = 1; -+ break; -+ -+ case 'f': -+ args.image = optarg; -+ break; -+ -+ case 'n': -+ args.novtbl = 1; -+ break; -+ -+ case 'y': -+ args.yes = 1; -+ break; -+ -+ case 'q': -+ args.quiet = 1; -+ break; -+ -+ case 'x': -+ args.ubi_ver = strtoul(optarg, &endp, 0); -+ if (args.ubi_ver < 0 || *endp != '\0' || endp == optarg) -+ return errmsg("bad UBI version: \"%s\"", optarg); -+ break; -+ -+ case 'v': -+ args.verbose = 1; -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ if (args.quiet && args.verbose) -+ return errmsg("using \"-q\" and \"-v\" at the same time does not make sense"); -+ -+ if (optind == argc) -+ return errmsg("MTD device name was not specified (use -h for help)"); -+ else if (optind != argc - 1) -+ return errmsg("more then one MTD device specified (use -h for help)"); -+ -+ if (args.image && args.novtbl) -+ return errmsg("-n cannot be used together with -f"); -+ -+ args.node = argv[optind]; -+ return 0; -+} -+ -+static int want_exit(void) -+{ -+ char buf[4]; -+ -+ while (1) { -+ normsg_cont("continue? (yes/no) "); -+ scanf("%3s", buf); -+ if (!strncmp(buf, "yes", 3) || !strncmp(buf, "y", 1)) -+ return 0; -+ if (!strncmp(buf, "no", 2) || !strncmp(buf, "n", 1)) -+ return 1; -+ } -+} -+ -+static int answer_is_yes(void) -+{ -+ char buf[4]; -+ -+ while (1) { -+ scanf("%3s", buf); -+ if (!strncmp(buf, "yes", 3) || !strncmp(buf, "y", 1)) -+ return 1; -+ if (!strncmp(buf, "no", 2) || !strncmp(buf, "n", 1)) -+ return 0; -+ } -+} -+ -+static void print_bad_eraseblocks(const struct mtd_info *mtd, -+ const struct ubi_scan_info *si) -+{ -+ int first = 1, eb; -+ -+ if (si->bad_cnt == 0) -+ return; -+ -+ normsg_cont("bad eraseblocks: "); -+ for (eb = 0; eb < mtd->eb_cnt; eb++) { -+ if (si->ec[eb] != EB_BAD) -+ continue; -+ if (first) { -+ printf("%d", eb); -+ first = 0; -+ } else -+ printf(", %d", eb); -+ } -+ printf("\n"); -+} -+ -+static int change_ec(struct ubi_ec_hdr *hdr, long long ec) -+{ -+ uint32_t crc; -+ -+ /* Check the EC header */ -+ if (be32_to_cpu(hdr->magic) != UBI_EC_HDR_MAGIC) -+ return errmsg("mad UBI magic %#08x, should be %#08x", -+ be32_to_cpu(hdr->magic), UBI_EC_HDR_MAGIC); -+ -+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC); -+ if (be32_to_cpu(hdr->hdr_crc) != crc) -+ return errmsg("bad CRC %#08x, should be %#08x\n", -+ crc, be32_to_cpu(hdr->hdr_crc)); -+ -+ hdr->ec = cpu_to_be64(ec); -+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC); -+ hdr->hdr_crc = cpu_to_be32(crc); -+ -+ return 0; -+} -+ -+static int drop_ffs(const struct mtd_info *mtd, const void *buf, int len) -+{ -+ int i; -+ -+ for (i = len - 1; i >= 0; i--) -+ if (((const uint8_t *)buf)[i] != 0xFF) -+ break; -+ -+ /* The resulting length must be aligned to the minimum flash I/O size */ -+ len = i + 1; -+ len = (len + mtd->min_io_size - 1) / mtd->min_io_size; -+ len *= mtd->min_io_size; -+ return len; -+} -+ -+static int flash_image(const struct mtd_info *mtd, const struct ubigen_info *ui, -+ struct ubi_scan_info *si) -+{ -+ int fd, img_ebs, eb, written_ebs = 0, divisor; -+ struct stat st; -+ -+ if (stat(args.image, &st)) -+ return sys_errmsg("cannot open \"%s\"", args.image); -+ -+ img_ebs = st.st_size / mtd->eb_size; -+ if (img_ebs > si->good_cnt) -+ return sys_errmsg("file \"%s\" is too large (%lld bytes)", -+ args.image, (long long)st.st_size); -+ -+ if (st.st_size % mtd->eb_size) -+ return sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of eraseblock size (%d bytes)", -+ args.image, (long long)st.st_size, mtd->eb_size); -+ -+ fd = open(args.image, O_RDONLY); -+ if (fd == -1) -+ return sys_errmsg("cannot open \"%s\"", args.image); -+ -+ verbose(args.verbose, "will write %d eraseblocks", img_ebs); -+ divisor = img_ebs; -+ for (eb = 0; eb < mtd->eb_cnt; eb++) { -+ int err, new_len; -+ char buf[mtd->eb_size]; -+ long long ec; -+ -+ if (!args.quiet && !args.verbose) { -+ printf("\r" PROGRAM_NAME ": flashing eraseblock %d -- %2lld %% complete ", -+ eb, (long long)(eb + 1) * 100 / divisor); -+ fflush(stdout); -+ } -+ -+ if (si->ec[eb] == EB_BAD) { -+ divisor += 1; -+ continue; -+ } -+ -+ if (args.verbose) { -+ normsg_cont("eraseblock %d: erase", eb); -+ fflush(stdout); -+ } -+ -+ err = mtd_erase(mtd, eb); -+ if (err) { -+ sys_errmsg("failed to erase eraseblock %d", eb); -+ goto out_close; -+ } -+ -+ if (read(fd, buf, mtd->eb_size) != mtd->eb_size) { -+ sys_errmsg("failed to read eraseblock %d from \"%s\"", -+ written_ebs, args.image); -+ goto out_close; -+ } -+ -+ -+ if (si->ec[eb] <= EC_MAX) -+ ec = si->ec[eb] + 1; -+ else if (!args.override_ec) -+ ec = si->mean_ec; -+ else -+ ec = args.ec; -+ -+ if (args.verbose) { -+ printf(", change EC to %lld", ec); -+ fflush(stdout); -+ } -+ -+ err = change_ec((struct ubi_ec_hdr *)buf, ec); -+ if (err) { -+ errmsg("bad EC header at eraseblock %d of \"%s\"", -+ written_ebs, args.image); -+ goto out_close; -+ } -+ -+ if (args.verbose) { -+ printf(", write data\n"); -+ fflush(stdout); -+ } -+ -+ new_len = drop_ffs(mtd, buf, mtd->eb_size); -+ -+ err = mtd_write(mtd, eb, 0, buf, new_len); -+ if (err) { -+ sys_errmsg("cannot write eraseblock %d", eb); -+ goto out_close; -+ } -+ if (++written_ebs >= img_ebs) -+ break; -+ } -+ -+ if (!args.quiet && !args.verbose) -+ printf("\n"); -+ close(fd); -+ return eb + 1; -+ -+out_close: -+ close(fd); -+ return -1; -+} -+ -+static int format(const struct mtd_info *mtd, const struct ubigen_info *ui, -+ const struct ubi_scan_info *si, int start_eb, int novtbl) -+{ -+ int eb, err, write_size; -+ struct ubi_ec_hdr *hdr; -+ struct ubi_vtbl_record *vtbl; -+ int eb1 = -1, eb2 = -1; -+ long long ec1 = -1, ec2 = -1; -+ -+ write_size = UBI_EC_HDR_SIZE + mtd->subpage_size - 1; -+ write_size /= mtd->subpage_size; -+ write_size *= mtd->subpage_size; -+ hdr = malloc(write_size); -+ if (!hdr) -+ return sys_errmsg("cannot allocate %d bytes of memory", write_size); -+ -+ memset(hdr, 0xFF, write_size); -+ -+ for (eb = start_eb; eb < mtd->eb_cnt; eb++) { -+ long long ec; -+ -+ if (!args.quiet && !args.verbose) { -+ printf("\r" PROGRAM_NAME ": formatting eraseblock %d -- %2lld %% complete ", -+ eb, (long long)(eb + 1 - start_eb) * 100 / (mtd->eb_cnt - start_eb)); -+ fflush(stdout); -+ } -+ -+ if (si->ec[eb] == EB_BAD) -+ continue; -+ -+ if (si->ec[eb] <= EC_MAX) -+ ec = si->ec[eb] + 1; -+ else if (!args.override_ec) -+ ec = si->mean_ec; -+ else -+ ec = args.ec; -+ ubigen_init_ec_hdr(ui, hdr, ec); -+ -+ if (args.verbose) { -+ normsg_cont("eraseblock %d: erase", eb); -+ fflush(stdout); -+ } -+ -+ err = mtd_erase(mtd, eb); -+ if (err) { -+ sys_errmsg("failed to erase eraseblock %d", eb); -+ goto out_free; -+ } -+ -+ if ((eb1 == -1 || eb2 == -1) && !novtbl) { -+ if (eb1 == -1) { -+ eb1 = eb; -+ ec1 = ec; -+ } else if (eb2 == -1) { -+ eb2 = eb; -+ ec2 = ec; -+ } -+ if (args.verbose) -+ printf(", do not write EC, leave for vtbl\n"); -+ continue; -+ } -+ -+ if (args.verbose) { -+ printf(", write EC %lld\n", ec); -+ fflush(stdout); -+ } -+ -+ err = mtd_write(mtd, eb, 0, hdr, write_size); -+ if (err) { -+ sys_errmsg("cannot write EC header (%d bytes buffer) to eraseblock %d", -+ write_size, eb); -+ if (args.subpage_size != mtd->min_io_size) -+ normsg("may be %d is incorrect?", args.subpage_size); -+ goto out_free; -+ } -+ } -+ -+ if (!args.quiet && !args.verbose) -+ printf("\n"); -+ -+ if (!novtbl) { -+ if (eb1 == -1 || eb2 == -1) { -+ errmsg("no eraseblocks for volume table"); -+ goto out_free; -+ } -+ -+ verbose(args.verbose, "write volume table to eraseblocks %d and %d", eb1, eb2); -+ vtbl = ubigen_create_empty_vtbl(ui); -+ if (!vtbl) -+ goto out_free; -+ -+ err = ubigen_write_layout_vol(ui, eb1, eb2, ec1, ec2, vtbl, mtd->fd); -+ free(vtbl); -+ if (err) { -+ errmsg("cannot write layout volume"); -+ goto out_free; -+ } -+ } -+ -+ free(hdr); -+ return 0; -+ -+out_free: -+ free(hdr); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err, verbose; -+ struct mtd_info mtd; -+ libubi_t libubi; -+ struct ubigen_info ui; -+ struct ubi_scan_info *si; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ err = mtd_get_info(args.node, &mtd); -+ if (err) -+ return errmsg("cannot get information about \"%s\"", args.node); -+ -+ if (args.subpage_size == 0) -+ args.subpage_size = mtd.min_io_size; -+ else { -+ if (args.subpage_size > mtd.min_io_size) { -+ errmsg("sub-page cannot be larger than min. I/O unit"); -+ goto out_close; -+ } -+ -+ if (mtd.min_io_size % args.subpage_size) { -+ errmsg("min. I/O unit size should be multiple of sub-page size"); -+ goto out_close; -+ } -+ } -+ -+ /* Validate VID header offset if it was specified */ -+ if (args.vid_hdr_offs != 0) { -+ if (args.vid_hdr_offs % 8) { -+ errmsg("VID header offset has to be multiple of min. I/O unit size"); -+ goto out_close; -+ } -+ if (args.vid_hdr_offs + UBI_VID_HDR_SIZE > mtd.eb_size) { -+ errmsg("bad VID header offset"); -+ goto out_close; -+ } -+ } -+ -+ /* -+ * Because of MTD interface limitations 'mtd_get_info()' cannot get -+ * sub-page so we force the user to pass it via the command line. Let's -+ * hope the user passed us something sane. -+ */ -+ mtd.subpage_size = args.subpage_size; -+ -+ if (mtd.rdonly) { -+ errmsg("mtd%d (%s) is a read-only device", mtd.num, args.node); -+ goto out_close; -+ } -+ -+ /* Make sure this MTD device is not attached to UBI */ -+ libubi = libubi_open(0); -+ if (libubi) { -+ int ubi_dev_num; -+ -+ err = mtd_num2ubi_dev(libubi, mtd.num, &ubi_dev_num); -+ libubi_close(libubi); -+ if (!err) { -+ errmsg("please, first detach mtd%d (%s) from ubi%d", -+ mtd.num, args.node, ubi_dev_num); -+ goto out_close; -+ } -+ } -+ -+ if (!args.quiet) { -+ normsg_cont("mtd%d (%s), size ", mtd.num, mtd.type_str); -+ ubiutils_print_bytes(mtd.size, 1); -+ printf(", %d eraseblocks of ", mtd.eb_size); -+ ubiutils_print_bytes(mtd.eb_size, 1); -+ printf(", min. I/O size %d bytes\n", mtd.min_io_size); -+ } -+ -+ if (args.quiet) -+ verbose = 0; -+ else if (args.verbose) -+ verbose = 2; -+ else -+ verbose = 1; -+ err = ubi_scan(&mtd, &si, verbose); -+ if (err) { -+ errmsg("failed to scan mtd%d (%s)", mtd.num, args.node); -+ goto out_close; -+ } -+ -+ if (si->good_cnt == 0) { -+ errmsg("all %d eraseblocks are bad", si->bad_cnt); -+ goto out_free; -+ } -+ -+ if (si->good_cnt < 2 && (!args.novtbl || args.image)) { -+ errmsg("too few non-bad eraseblocks (%d) on mtd%d", si->good_cnt, mtd.num); -+ goto out_free; -+ } -+ -+ if (!args.quiet) { -+ if (si->ok_cnt) -+ normsg("%d eraseblocks have valid erase counter, mean value is %lld", -+ si->ok_cnt, si->mean_ec); -+ if (si->empty_cnt) -+ normsg("%d eraseblocks are supposedly empty", si->empty_cnt); -+ if (si->corrupted_cnt) -+ normsg("%d corrupted erase counters", si->corrupted_cnt); -+ print_bad_eraseblocks(&mtd, si); -+ } -+ -+ if (si->alien_cnt) { -+ if (!args.yes || !args.quiet) -+ warnmsg("%d of %d eraseblocks contain non-ubifs data", -+ si->alien_cnt, si->good_cnt); -+ if (!args.yes && want_exit()) { -+ if (args.yes && !args.quiet) -+ printf("yes\n"); -+ goto out_free; -+ } -+ } -+ -+ if (!args.override_ec && si->empty_cnt < si->good_cnt) { -+ int percent = ((double)si->ok_cnt)/si->good_cnt * 100; -+ -+ /* -+ * Make sure the majority of eraseblocks have valid -+ * erase counters. -+ */ -+ if (percent < 50) { -+ if (!args.yes || !args.quiet) -+ warnmsg("only %d of %d eraseblocks have valid erase counter", -+ si->ok_cnt, si->good_cnt); -+ normsg("erase counter 0 will be used for all eraseblocks"); -+ normsg("note, arbitrary erase counter value may be specified using -e option"); -+ if (!args.yes && want_exit()) { -+ if (args.yes && !args.quiet) -+ printf("yes\n"); -+ goto out_free; -+ } -+ args.ec = 0; -+ args.override_ec = 1; -+ } else if (percent < 95) { -+ if (!args.yes || !args.quiet) -+ warnmsg("only %d of %d eraseblocks have valid erase counter", -+ si->ok_cnt, si->good_cnt); -+ normsg("mean erase counter %lld will be used for the rest of eraseblock", -+ si->mean_ec); -+ if (!args.yes && want_exit()) { -+ if (args.yes && !args.quiet) -+ printf("yes\n"); -+ goto out_free; -+ } -+ args.ec = si->mean_ec; -+ args.override_ec = 1; -+ } -+ } -+ -+ if (!args.quiet && args.override_ec) -+ normsg("use erase counter %lld for all eraseblocks", args.ec); -+ -+ ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, args.subpage_size, -+ args.vid_hdr_offs, args.ubi_ver); -+ -+ if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) { -+ /* -+ * Hmm, what we read from flash and what we calculated using -+ * min. I/O unit size and sub-page size differs. -+ */ -+ if (!args.yes || !args.quiet) { -+ warnmsg("VID header and data offsets on flash are %d and %d, " -+ "which is different to calculated offsets %d and %d", -+ si->vid_hdr_offs, si->data_offs, ui.vid_hdr_offs, -+ ui.data_offs); -+ normsg_cont("use old offsets %d and %d? (yes/no) ", -+ si->vid_hdr_offs, si->data_offs); -+ } -+ if (args.yes || answer_is_yes()) { -+ if (args.yes && !args.quiet) -+ printf("yes\n"); -+ ui.vid_hdr_offs = si->vid_hdr_offs; -+ ui.data_offs = si->data_offs; -+ } -+ } -+ -+ if (args.image) { -+ err = flash_image(&mtd, &ui, si); -+ if (err < 0) -+ goto out_free; -+ -+ err = format(&mtd, &ui, si, err, 1); -+ if (err) -+ goto out_free; -+ } else { -+ err = format(&mtd, &ui, si, 0, args.novtbl); -+ if (err) -+ goto out_free; -+ } -+ -+ ubi_scan_free(si); -+ close(mtd.fd); -+ return 0; -+ -+out_free: -+ ubi_scan_free(si); -+out_close: -+ close(mtd.fd); -+ return -1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,310 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to create UBI volumes. -+ * -+ * Authors: Artem Bityutskiy -+ * Frank Haverkamp -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubimkvol" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ int vol_id; -+ int vol_type; -+ long long bytes; -+ int lebs; -+ int alignment; -+ const char *name; -+ int nlen; -+ const char *node; -+ int maxavs; -+ /* For deprecated -d option handling */ -+ int devn; -+ char dev_name[256]; -+}; -+ -+static struct args args = { -+ .vol_type = UBI_DYNAMIC_VOLUME, -+ .bytes = -1, -+ .lebs = -1, -+ .alignment = 1, -+ .vol_id = UBI_VOL_NUM_AUTO, -+ .devn = -1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to create UBI volumes."; -+ -+static const char *optionsstr = -+"-a, --alignment= volume alignment (default is 1)\n" -+"-n, --vol_id= UBI volume ID, if not specified, the volume ID\n" -+" will be assigned automatically\n" -+"-N, --name= volume name\n" -+"-s, --size= volume size volume size in bytes, kilobytes (KiB)\n" -+" or megabytes (MiB)\n" -+"-S, --lebs= alternative way to give volume size in logical\n" -+" eraseblocks\n" -+"-m, --maxavsize set volume size to maximum available size\n" -+"-t, --type= volume type (dynamic, static), default is dynamic\n" -+"-h, -?, --help print help message\n" -+"-V, --version print program version\n\n" -+"The following is a compatibility option which is deprecated, do not use it\n" -+"-d, --devn= UBI device number - may be used instead of the UBI\n" -+" device node name in which case the utility assumes\n" -+" that the device node is \"/dev/ubi\""; -+ -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-h] [-a ] [-n ] [-N ]\n" -+"\t\t\t[-s ] [-S ] [-t ] [-V] [-m]\n" -+"\t\t\t[--alignment=][--vol_id=] [--name=]\n" -+"\t\t\t[--size=] [--lebs=] [--type=] [--help]\n" -+"\t\t\t[--version] [--maxavsize]\n\n" -+"Example: " PROGRAM_NAME "/dev/ubi0 -s 20MiB -N config_data - create a 20 Megabytes volume\n" -+" named \"config_data\" on UBI device /dev/ubi0."; -+ -+static const struct option long_options[] = { -+ { .name = "alignment", .has_arg = 1, .flag = NULL, .val = 'a' }, -+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' }, -+ { .name = "name", .has_arg = 1, .flag = NULL, .val = 'N' }, -+ { .name = "size", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "lebs", .has_arg = 1, .flag = NULL, .val = 'S' }, -+ { .name = "type", .has_arg = 1, .flag = NULL, .val = 't' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { .name = "maxavsize", .has_arg = 0, .flag = NULL, .val = 'm' }, -+ /* Deprecated -d option */ -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int param_sanity_check(void) -+{ -+ int len; -+ -+ if (args.bytes == -1 && !args.maxavs && args.lebs == -1) -+ return errmsg("volume size was not specified (use -h for help)"); -+ -+ if ((args.bytes != -1 && (args.maxavs || args.lebs != -1)) || -+ (args.lebs != -1 && (args.maxavs || args.bytes != -1)) || -+ (args.maxavs && (args.bytes != -1 || args.lebs != -1))) -+ return errmsg("size specified with more then one option"); -+ -+ if (args.name == NULL) -+ return errmsg("volume name was not specified (use -h for help)"); -+ -+ len = strlen(args.name); -+ if (len > UBI_MAX_VOLUME_NAME) -+ return errmsg("too long name (%d symbols), max is %d", len, UBI_MAX_VOLUME_NAME); -+ -+ return 0; -+} -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "a:n:N:s:S:t:h?Vmd:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 't': -+ if (!strcmp(optarg, "dynamic")) -+ args.vol_type = UBI_DYNAMIC_VOLUME; -+ else if (!strcmp(optarg, "static")) -+ args.vol_type = UBI_STATIC_VOLUME; -+ else -+ return errmsg("bad volume type: \"%s\"", optarg); -+ break; -+ -+ case 's': -+ args.bytes = ubiutils_get_bytes(optarg); -+ if (args.bytes <= 0) -+ return errmsg("bad volume size: \"%s\"", optarg); -+ break; -+ -+ case 'S': -+ args.lebs = strtoull(optarg, &endp, 0); -+ if (endp == optarg || args.lebs <= 0 || *endp != '\0') -+ return errmsg("bad LEB count: \"%s\"", optarg); -+ break; -+ -+ case 'a': -+ args.alignment = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.alignment <= 0) -+ return errmsg("bad volume alignment: \"%s\"", optarg); -+ break; -+ -+ case 'n': -+ args.vol_id = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.vol_id < 0) -+ return errmsg("bad volume ID: " "\"%s\"", optarg); -+ break; -+ -+ case 'd': -+ /* Handle deprecated -d option */ -+ warnmsg("-d is depricated and will be removed, do not use it"); -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: " "\"%s\"", optarg); -+ break; -+ -+ case 'N': -+ args.name = optarg; -+ args.nlen = strlen(args.name); -+ break; -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case 'm': -+ args.maxavs = 1; -+ break; -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ /* Handle deprecated -d option */ -+ if (args.devn != -1) { -+ sprintf(args.dev_name, "/dev/ubi%d", args.devn); -+ args.node = args.dev_name; -+ } else { -+ if (optind == argc) -+ return errmsg("UBI device name was not specified (use -h for help)"); -+ else if (optind != argc - 1) -+ return errmsg("more then one UBI device specified (use -h for help)"); -+ -+ args.node = argv[optind]; -+ } -+ -+ if (param_sanity_check()) -+ return -1; -+ -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_dev_info dev_info; -+ struct ubi_vol_info vol_info; -+ struct ubi_mkvol_request req; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return err; -+ -+ libubi = libubi_open(1); -+ if (!libubi) -+ return sys_errmsg("cannot open libubi"); -+ -+ err = ubi_node_type(libubi, args.node); -+ if (err == 2) { -+ errmsg("\"%s\" is an UBI volume node, not an UBI device node", -+ args.node); -+ goto out_libubi; -+ } else if (err < 0) { -+ errmsg("\"%s\" is not an UBI device node", args.node); -+ goto out_libubi; -+ } -+ -+ err = ubi_get_dev_info(libubi, args.node, &dev_info); -+ if (err) { -+ sys_errmsg("cannot get information about UBI device \"%s\"", -+ args.node); -+ goto out_libubi; -+ } -+ -+ if (args.maxavs) { -+ args.bytes = dev_info.avail_bytes; -+ printf("Set volume size to %lld\n", args.bytes); -+ } -+ -+ if (args.lebs != -1) { -+ args.bytes = dev_info.leb_size; -+ args.bytes -= dev_info.leb_size % args.alignment; -+ args.bytes *= args.lebs; -+ } -+ -+ req.vol_id = args.vol_id; -+ req.alignment = args.alignment; -+ req.bytes = args.bytes; -+ req.vol_type = args.vol_type; -+ req.name = args.name; -+ -+ err = ubi_mkvol(libubi, args.node, &req); -+ if (err < 0) { -+ sys_errmsg("cannot UBI create volume"); -+ goto out_libubi; -+ } -+ -+ args.vol_id = req.vol_id; -+ -+ /* Print information about the created device */ -+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, args.vol_id, &vol_info); -+ if (err) { -+ sys_errmsg("cannot get information about newly created UBI volume"); -+ goto out_libubi; -+ } -+ -+ printf("Volume ID %d, size %d LEBs (", vol_info.vol_id, vol_info.rsvd_lebs); -+ ubiutils_print_bytes(vol_info.rsvd_bytes, 0); -+ printf("), LEB size "); -+ ubiutils_print_bytes(vol_info.leb_size, 1); -+ printf(", %s, name \"%s\", alignment %d\n", -+ req.vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static", -+ vol_info.name, vol_info.alignment); -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,409 @@ -+/* -+ * Copyright (C) 2007, 2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * An utility to get UBI information. -+ * -+ * Author: Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubinfo" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ int devn; -+ int vol_id; -+ int all; -+ const char *node; -+}; -+ -+static struct args args = { -+ .vol_id = -1, -+ .devn = -1, -+ .all = 0, -+ .node = NULL, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to print UBI information."; -+ -+static const char *optionsstr = -+"-d, --devn= UBI device number to get information about\n" -+"-n, --vol_id= ID of UBI volume to print information about\n" -+"-a, --all print information about all devices and volumes,\n" -+" or about all volumes if the UBI device was\n" -+" specified\n" -+"-h, --help print help message\n" -+"-V, --version print program version"; -+ -+static const char *usage = -+"Usage 1: " PROGRAM_NAME " [-d ] [-n ] [-a] [-h] [-V] [--vol_id=]\n" -+"\t\t[--devn ] [--all] [--help] [--version]\n" -+"Usage 2: " PROGRAM_NAME " [-a] [-h] [-V] [--all] [--help] [--version]\n" -+"Usage 3: " PROGRAM_NAME " [-h] [-V] [--help] [--version]\n\n" -+"Example 1: " PROGRAM_NAME " - (no arguments) print general UBI information\n" -+"Example 2: " PROGRAM_NAME " -d 1 - print information about UBI device number 1\n" -+"Example 3: " PROGRAM_NAME " /dev/ubi0 -a - print information about all volumes of UBI\n" -+" device /dev/ubi0\n" -+"Example 4: " PROGRAM_NAME " /dev/ubi1_0 - print information about UBI volume /dev/ubi1_0\n" -+"Example 5: " PROGRAM_NAME " -a - print all information\n"; -+ -+static const struct option long_options[] = { -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' }, -+ { .name = "all", .has_arg = 0, .flag = NULL, .val = 'a' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "an:d:hV", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'a': -+ args.all = 1; -+ break; -+ -+ case 'n': -+ args.vol_id = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.vol_id < 0) -+ return errmsg("bad volume ID: " "\"%s\"", optarg); -+ break; -+ -+ case 'd': -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: \"%s\"", optarg); -+ -+ break; -+ -+ case 'h': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ if (optind == argc - 1) -+ args.node = argv[optind]; -+ else if (optind < argc) -+ return errmsg("more then one UBI devices specified (use -h for help)"); -+ -+ return 0; -+} -+ -+static int translate_dev(libubi_t libubi, const char *node) -+{ -+ int err; -+ -+ err = ubi_node_type(libubi, node); -+ if (err == -1) { -+ if (errno) -+ return errmsg("unrecognized device node \"%s\"", node); -+ return errmsg("\"%s\" does not correspond to any UBI device or volume", node); -+ } -+ -+ if (err == 1) { -+ struct ubi_dev_info dev_info; -+ -+ err = ubi_get_dev_info(libubi, node, &dev_info); -+ if (err) -+ return sys_errmsg("cannot get information about UBI device \"%s\"", node); -+ -+ args.devn = dev_info.dev_num; -+ } else { -+ struct ubi_vol_info vol_info; -+ -+ err = ubi_get_vol_info(libubi, node, &vol_info); -+ if (err) -+ return sys_errmsg("cannot get information about UBI volume \"%s\"", node); -+ -+ if (args.vol_id != -1) -+ return errmsg("both volume character device node (\"%s\") and " -+ "volume ID (%d) are specify, use only one of them" -+ "(use -h for help)", node, args.vol_id); -+ -+ args.devn = vol_info.dev_num; -+ args.vol_id = vol_info.vol_id; -+ } -+ -+ return 0; -+} -+ -+static int print_vol_info(libubi_t libubi, int dev_num, int vol_id) -+{ -+ int err; -+ struct ubi_vol_info vol_info; -+ -+ err = ubi_get_vol_info1(libubi, dev_num, vol_id, &vol_info); -+ if (err) -+ return sys_errmsg("cannot get information about UBI volume %d on ubi%d", -+ vol_id, dev_num); -+ -+ printf("Volume ID: %d (on ubi%d)\n", vol_info.vol_id, vol_info.dev_num); -+ printf("Type: %s\n", -+ vol_info.type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static"); -+ printf("Alignment: %d\n", vol_info.alignment); -+ -+ printf("Size: %d LEBs (", vol_info.rsvd_lebs); -+ ubiutils_print_bytes(vol_info.rsvd_bytes, 0); -+ printf(")\n"); -+ -+ if (vol_info.type == UBI_STATIC_VOLUME) { -+ printf("Data bytes: "); -+ ubiutils_print_bytes(vol_info.data_bytes, 1); -+ } -+ printf("State: %s\n", vol_info.corrupted ? "corrupted" : "OK"); -+ printf("Name: %s\n", vol_info.name); -+ printf("Character device major/minor: %d:%d\n", -+ vol_info.major, vol_info.minor); -+ -+ return 0; -+} -+ -+static int print_dev_info(libubi_t libubi, int dev_num, int all) -+{ -+ int i, err, first = 1; -+ struct ubi_dev_info dev_info; -+ struct ubi_vol_info vol_info; -+ -+ err = ubi_get_dev_info1(libubi, dev_num, &dev_info); -+ if (err) -+ return sys_errmsg("cannot get information about UBI device %d", dev_num); -+ -+ printf("ubi%d:\n", dev_info.dev_num); -+ printf("Volumes count: %d\n", dev_info.vol_count); -+ printf("Logical eraseblock size: %d\n", dev_info.leb_size); -+ -+ printf("Total amount of logical eraseblocks: %d (", dev_info.total_lebs); -+ ubiutils_print_bytes(dev_info.total_bytes, 0); -+ printf(")\n"); -+ -+ printf("Amount of available logical eraseblocks: %d (", dev_info.avail_lebs); -+ ubiutils_print_bytes(dev_info.avail_bytes, 0); -+ printf(")\n"); -+ -+ printf("Maximum count of volumes %d\n", dev_info.max_vol_count); -+ printf("Count of bad physical eraseblocks: %d\n", dev_info.bad_count); -+ printf("Count of reserved physical eraseblocks: %d\n", dev_info.bad_rsvd); -+ printf("Current maximum erase counter value: %lld\n", dev_info.max_ec); -+ printf("Minimum input/output unit size: %d bytes\n", dev_info.min_io_size); -+ printf("Character device major/minor: %d:%d\n", -+ dev_info.major, dev_info.minor); -+ -+ if (dev_info.vol_count == 0) -+ return 0; -+ -+ printf("Present volumes: "); -+ for (i = dev_info.lowest_vol_num; -+ i <= dev_info.highest_vol_num; i++) { -+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info); -+ if (err == -1) { -+ if (errno == ENOENT) -+ continue; -+ -+ return sys_errmsg("libubi failed to probe volume %d on ubi%d", -+ i, dev_info.dev_num); -+ } -+ -+ if (!first) -+ printf(", %d", i); -+ else { -+ printf("%d", i); -+ first = 0; -+ } -+ } -+ printf("\n"); -+ -+ if (!all) -+ return 0; -+ -+ first = 1; -+ printf("\n"); -+ -+ for (i = dev_info.lowest_vol_num; -+ i <= dev_info.highest_vol_num; i++) { -+ if(!first) -+ printf("-----------------------------------\n"); -+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info); -+ if (err == -1) { -+ if (errno == ENOENT) -+ continue; -+ -+ return sys_errmsg("libubi failed to probe volume %d on ubi%d", -+ i, dev_info.dev_num); -+ } -+ first = 0; -+ -+ err = print_vol_info(libubi, dev_info.dev_num, i); -+ if (err) -+ return err; -+ } -+ -+ return 0; -+} -+ -+static int print_general_info(libubi_t libubi, int all) -+{ -+ int i, err, first = 1; -+ struct ubi_info ubi_info; -+ struct ubi_dev_info dev_info; -+ -+ err = ubi_get_info(libubi, &ubi_info); -+ if (err) -+ return sys_errmsg("cannot get UBI information"); -+ -+ printf("UBI version: %d\n", ubi_info.version); -+ printf("Count of UBI devices: %d\n", ubi_info.dev_count); -+ if (ubi_info.ctrl_major != -1) -+ printf("UBI control device major/minor: %d:%d\n", -+ ubi_info.ctrl_major, ubi_info.ctrl_minor); -+ else -+ printf("UBI control device is not supported by this kernel\n"); -+ -+ if (ubi_info.dev_count == 0) -+ return 0; -+ -+ printf("Present UBI devices: "); -+ for (i = ubi_info.lowest_dev_num; -+ i <= ubi_info.highest_dev_num; i++) { -+ err = ubi_get_dev_info1(libubi, i, &dev_info); -+ if (err == -1) { -+ if (errno == ENOENT) -+ continue; -+ -+ return sys_errmsg("libubi failed to probe UBI device %d", i); -+ } -+ -+ if (!first) -+ printf(", ubi%d", i); -+ else { -+ printf("ubi%d", i); -+ first = 0; -+ } -+ } -+ printf("\n"); -+ -+ if (!all) -+ return 0; -+ -+ first = 1; -+ printf("\n"); -+ -+ for (i = ubi_info.lowest_dev_num; -+ i <= ubi_info.highest_dev_num; i++) { -+ if(!first) -+ printf("\n===================================\n\n"); -+ err = ubi_get_dev_info1(libubi, i, &dev_info); -+ if (err == -1) { -+ if (errno == ENOENT) -+ continue; -+ -+ return sys_errmsg("libubi failed to probe UBI device %d", i); -+ } -+ first = 0; -+ -+ err = print_dev_info(libubi, i, all); -+ if (err) -+ return err; -+ } -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ if (!args.node && args.devn != -1) -+ return errmsg("specify either device number or node file (use -h for help)"); -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) -+ return sys_errmsg("cannot open libubi"); -+ -+ if (args.node) { -+ /* -+ * A character device was specified, translate this into UBI -+ * device number and volume ID. -+ */ -+ err = translate_dev(libubi, args.node); -+ if (err) -+ goto out_libubi; -+ } -+ -+ if (args.vol_id != -1 && args.devn == -1) { -+ errmsg("volume ID is specified, but UBI device number is not " -+ "(use -h for help)\n"); -+ goto out_libubi; -+ } -+ -+ if (args.devn != -1 && args.vol_id != -1) { -+ print_vol_info(libubi, args.devn, args.vol_id); -+ goto out; -+ } -+ -+ if (args.devn == -1 && args.vol_id == -1) -+ err = print_general_info(libubi, args.all); -+ else if (args.devn != -1 && args.vol_id == -1) -+ err = print_dev_info(libubi, args.devn, args.all); -+ -+ if (err) -+ goto out_libubi; -+ -+out: -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,582 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Generate UBI images. -+ * -+ * Authors: Artem Bityutskiy -+ * Oliver Lohmann -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubinize" -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+" - a tool to generate UBI images. An UBI image may contain one or more UBI " -+"volumes which have to be defined in the input configuration ini-file. The " -+"ini file defines all the UBI volumes - their characteristics and the and the " -+"contents, but it does not define the characteristics of the flash the UBI " -+"image is generated for. Instead, the flash characteristics are defined via " -+"the command-line options. Note, if not sure about some of the command-line " -+"parameters, do not specify them and let the utility to use default values."; -+ -+static const char *optionsstr = -+"-o, --output= output file name\n" -+"-p, --peb-size= size of the physical eraseblock of the flash\n" -+" this UBI image is created for in bytes,\n" -+" kilobytes (KiB), or megabytes (MiB)\n" -+" (mandatory parameter)\n" -+"-m, --min-io-size= minimum input/output unit size of the flash\n" -+" in bytes\n" -+"-s, --sub-page-size= minimum input/output unit used for UBI\n" -+" headers, e.g. sub-page size in case of NAND\n" -+" flash (equivalent to the minimum input/output\n" -+" unit size by default)\n" -+"-O, --vid-hdr-offset= offset if the VID header from start of the\n" -+" physical eraseblock (default is the next\n" -+" minimum I/O unit or sub-page after the EC\n" -+" header)\n" -+"-e, --erase-counter= the erase counter value to put to EC headers\n" -+" (default is 0)\n" -+"-x, --ubi-ver= UBI version number to put to EC headers\n" -+" (default is 1)\n" -+"-v, --verbose be verbose\n" -+"-h, --help print help message\n" -+"-V, --version print program version"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-o filename] [-h] [-V] [--output=] [--help]\n" -+"\t\t[--version] ini-file\n" -+"Example: " PROGRAM_NAME " -o ubi.img cfg.ini - create UBI image 'ubi.img' as\n" -+" described by configuration file 'cfg.ini'"; -+ -+static const char *ini_doc = "INI-file format.\n" -+"The input configuration ini-file describes all the volumes which have to\n" -+"be included to the output UBI image. Each volume is described in its own\n" -+"section which may be named arbitrarily. The section consists on\n" -+"\"key=value\" pairs, for example:\n\n" -+"[jffs2-volume]\n" -+"mode=ubi\n" -+"image=../jffs2.img\n" -+"vol_id=1\n" -+"vol_size=30MiB\n" -+"vol_type=dynamic\n" -+"vol_name=jffs2_volume\n" -+"vol_flags=autoresize\n" -+"vol_alignment=1\n\n" -+"This example configuration file tells the utility to create an UBI image\n" -+"with one volume with ID 1, volume size 30MiB, the volume is dynamic, has\n" -+"name \"jffs2_volume\", \"autoresize\" volume flag, and alignment 1. The\n" -+"\"image=../jffs2.img\" line tells the utility to take the contents of the\n" -+"volume from the \"../jffs2.img\" file. The size of the image file has to be\n" -+"less or equivalent to the volume size (30MiB). The \"mode=ubi\" line is\n" -+"mandatory and just tells that the section describes an UBI volume - other\n" -+"section modes may be added in the future.\n" -+"Notes:\n" -+" * size in vol_size might be specified kilobytes (KiB), megabytes (MiB),\n" -+" gigabytes (GiB) or bytes (no modifier);\n" -+" * if \"vol_size\" key is absent, the volume size is assumed to be\n" -+" equivalent to the size of the image file (defined by \"image\" key);\n" -+" * if the \"image\" is absent, the volume is assumed to be empty;\n" -+" * volume alignment must not be greater than the logical eraseblock size;\n" -+" * one ini file may contain arbitrary number of sections, the utility will\n" -+" put all the volumes which are described by these section to the output\n" -+" UBI image file."; -+ -+struct option long_options[] = { -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "peb-size", .has_arg = 1, .flag = NULL, .val = 'p' }, -+ { .name = "min-io-size", .has_arg = 1, .flag = NULL, .val = 'm' }, -+ { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' }, -+ { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' }, -+ { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+struct args { -+ const char *f_in; -+ const char *f_out; -+ int out_fd; -+ int peb_size; -+ int min_io_size; -+ int subpage_size; -+ int vid_hdr_offs; -+ int ec; -+ int ubi_ver; -+ int verbose; -+ dictionary *dict; -+}; -+ -+static struct args args = { -+ .peb_size = -1, -+ .min_io_size = -1, -+ .subpage_size = -1, -+ .ubi_ver = 1, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "o:p:m:s:O:e:x:vhV", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'o': -+ args.out_fd = open(optarg, O_CREAT | O_TRUNC | O_WRONLY, -+ S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ if (args.out_fd == -1) -+ return sys_errmsg("cannot open file \"%s\"", optarg); -+ args.f_out = optarg; -+ break; -+ -+ case 'p': -+ args.peb_size = ubiutils_get_bytes(optarg); -+ if (args.peb_size <= 0) -+ return errmsg("bad physical eraseblock size: \"%s\"", optarg); -+ break; -+ -+ case 'm': -+ args.min_io_size = ubiutils_get_bytes(optarg); -+ if (args.min_io_size <= 0) -+ return errmsg("bad min. I/O unit size: \"%s\"", optarg); -+ if (!is_power_of_2(args.min_io_size)) -+ return errmsg("min. I/O unit size should be power of 2"); -+ break; -+ -+ case 's': -+ args.subpage_size = ubiutils_get_bytes(optarg); -+ if (args.subpage_size <= 0) -+ return errmsg("bad sub-page size: \"%s\"", optarg); -+ if (!is_power_of_2(args.subpage_size)) -+ return errmsg("sub-page size should be power of 2"); -+ break; -+ -+ case 'O': -+ args.vid_hdr_offs = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.vid_hdr_offs < 0) -+ return errmsg("bad VID header offset: \"%s\"", optarg); -+ break; -+ -+ case 'e': -+ args.ec = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.ec < 0) -+ return errmsg("bad erase counter value: \"%s\"", optarg); -+ break; -+ -+ case 'x': -+ args.ubi_ver = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.ubi_ver < 0) -+ return errmsg("bad UBI version: \"%s\"", optarg); -+ break; -+ -+ case 'v': -+ args.verbose = 1; -+ break; -+ -+ case 'h': -+ ubiutils_print_text(stderr, doc, 80); -+ fprintf(stderr, "\n%s\n\n", ini_doc); -+ fprintf(stderr, "%s\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ if (optind == argc) -+ return errmsg("input configuration file was not specified (use -h for help)"); -+ -+ if (optind != argc - 1) -+ return errmsg("more then one configuration file was specified (use -h for help)"); -+ -+ args.f_in = argv[optind]; -+ -+ if (args.peb_size < 0) -+ return errmsg("physical eraseblock size was not specified (use -h for help)"); -+ -+ if (args.peb_size > 1024*1024) -+ return errmsg("too high physical eraseblock size %d", args.peb_size); -+ -+ if (args.min_io_size < 0) -+ return errmsg("min. I/O unit size was not specified (use -h for help)"); -+ -+ if (args.subpage_size < 0) -+ args.subpage_size = args.min_io_size; -+ -+ if (args.subpage_size > args.min_io_size) -+ return errmsg("sub-page cannot be larger then min. I/O unit"); -+ -+ if (args.peb_size % args.min_io_size) -+ return errmsg("physical eraseblock should be multiple of min. I/O units"); -+ -+ if (args.min_io_size % args.subpage_size) -+ return errmsg("min. I/O unit size should be multiple of sub-page size"); -+ -+ if (!args.f_out) -+ return errmsg("output file was not specified (use -h for help)"); -+ -+ if (args.vid_hdr_offs) { -+ if (args.vid_hdr_offs + UBI_VID_HDR_SIZE >= args.peb_size) -+ return errmsg("bad VID header position"); -+ if (args.vid_hdr_offs % 8) -+ return errmsg("VID header offset has to be multiple of min. I/O unit size"); -+ } -+ -+ return 0; -+} -+ -+static int read_section(const char *sname, struct ubigen_vol_info *vi, -+ const char **img) -+{ -+ char buf[256]; -+ const char *p; -+ -+ *img = NULL; -+ -+ if (strlen(sname) > 128) -+ return errmsg("too long section name \"%s\"", sname); -+ -+ /* Make sure mode is UBI, otherwise ignore this section */ -+ sprintf(buf, "%s:mode", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (!p) { -+ errmsg("\"mode\" key not found in section \"%s\"", sname); -+ errmsg("the \"mode\" key is mandatory and has to be " -+ "\"mode=ubi\" if the section describes an UBI volume"); -+ return -1; -+ } -+ -+ /* If mode is not UBI, skip this section */ -+ if (strcmp(p, "ubi")) { -+ verbose(args.verbose, "skip non-ubi section \"%s\"", sname); -+ return 1; -+ } -+ -+ verbose(args.verbose, "mode=ubi, keep parsing"); -+ -+ /* Fetch the name of the volume image file */ -+ sprintf(buf, "%s:image", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (p) -+ *img = p; -+ -+ /* Fetch volume id */ -+ sprintf(buf, "%s:vol_id", sname); -+ vi->id = iniparser_getint(args.dict, buf, -1); -+ if (vi->id == -1) -+ return errmsg("\"vol_id\" key not found in section \"%s\"", sname); -+ -+ if (vi->id < 0) -+ return errmsg("negative volume ID %d", vi->id); -+ -+ if (vi->id >= UBI_MAX_VOLUMES) -+ return errmsg("too high volume ID %d, max. is %d", vi->id, UBI_MAX_VOLUMES); -+ -+ verbose(args.verbose, "volume ID: %d", vi->id); -+ -+ /* Fetch volume size */ -+ sprintf(buf, "%s:vol_size", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (p) { -+ vi->bytes = ubiutils_get_bytes(p); -+ if (vi->bytes <= 0) -+ return errmsg("bad \"vol_size\" key: \"%s\"", p); -+ -+ verbose(args.verbose, "volume size: %lld bytes", vi->bytes); -+ } else { -+ struct stat st; -+ -+ if (!*img) -+ return errmsg("neither image file (\"image=\") nor volume size (\"vol_size=\") specified"); -+ -+ if (stat(*img, &st)) -+ return sys_errmsg("cannot stat \"%s\"", *img); -+ -+ vi->bytes = st.st_size; -+ -+ if (vi->bytes == 0) -+ return errmsg("file \"%s\" referred from section \"%s\" is empty", *img, sname); -+ -+ normsg_cont("volume size was not specified in section \"%s\", assume ", sname); -+ ubiutils_print_bytes(vi->bytes, 1); -+ printf("\n"); -+ } -+ -+ /* Fetch volume type */ -+ sprintf(buf, "%s:vol_type", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (!p) { -+ normsg("volume type was not specified in " -+ "section \"%s\", assume \"dynamic\"\n", sname); -+ vi->type = UBI_VID_DYNAMIC; -+ } else { -+ if (!strcmp(p, "static")) -+ vi->type = UBI_VID_STATIC; -+ else if (!strcmp(p, "dynamic")) -+ vi->type = UBI_VID_DYNAMIC; -+ else -+ return errmsg("invalid volume type \"%s\"", p); -+ } -+ -+ verbose(args.verbose, "volume type: %s", -+ vi->type == UBI_VID_DYNAMIC ? "dynamic" : "static"); -+ -+ /* Fetch volume name */ -+ sprintf(buf, "%s:vol_name", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (!p) -+ return errmsg("\"vol_name\" key not found in section \"%s\"", sname); -+ -+ vi->name = p; -+ vi->name_len = strlen(p); -+ if (vi->name_len > UBI_VOL_NAME_MAX) -+ return errmsg("too long volume name in section \"%s\", max. is %d characters", -+ vi->name, UBI_VOL_NAME_MAX); -+ -+ verbose(args.verbose, "volume name: %s", p); -+ -+ /* Fetch volume alignment */ -+ sprintf(buf, "%s:vol_alignment", sname); -+ vi->alignment = iniparser_getint(args.dict, buf, -1); -+ if (vi->alignment == -1) { -+ normsg("volume alignment was not specified in section " -+ "\"%s\", assume 1", sname); -+ vi->alignment = 1; -+ } else if (vi->id < 0) -+ return errmsg("negative volume alignement %d", vi->alignment); -+ -+ verbose(args.verbose, "volume alignment: %d", vi->alignment); -+ -+ /* Fetch volume flags */ -+ sprintf(buf, "%s:vol_flags", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (p) { -+ if (!strcmp(p, "autoresize")) { -+ verbose(args.verbose, "autoresize flags found"); -+ vi->flags |= UBI_VTBL_AUTORESIZE_FLG; -+ } else { -+ return errmsg("unknown flags \"%s\" in section \"%s\"", p, sname); -+ } -+ } -+ -+ return 0; -+} -+ -+static void init_vol_info(const struct ubigen_info *ui, -+ struct ubigen_vol_info *vi) -+{ -+ vi->data_pad = ui->leb_size % vi->alignment; -+ vi->usable_leb_size = ui->leb_size - vi->data_pad; -+ vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size; -+ vi->compat = 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err = -1, sects, i, volumes, autoresize_was_already = 0; -+ struct ubigen_info ui; -+ struct ubi_vtbl_record *vtbl; -+ off_t seek; -+ int tmp; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ ubigen_info_init(&ui, args.peb_size, args.min_io_size, -+ args.subpage_size, args.vid_hdr_offs, -+ args.ubi_ver); -+ -+ verbose(args.verbose, "LEB size: %d", ui.leb_size); -+ verbose(args.verbose, "PEB size: %d", ui.peb_size); -+ verbose(args.verbose, "min. I/O size: %d", ui.min_io_size); -+ verbose(args.verbose, "sub-page size: %d", ui.min_io_size); -+ verbose(args.verbose, "VID offset: %d", ui.vid_hdr_offs); -+ verbose(args.verbose, "data offset: %d", ui.data_offs); -+ -+ vtbl = ubigen_create_empty_vtbl(&ui); -+ if (!vtbl) -+ goto out; -+ -+ args.dict = iniparser_load(args.f_in); -+ if (!args.dict) { -+ errmsg("cannot load the input ini file \"%s\"", args.f_in); -+ goto out_vtbl; -+ } -+ -+ verbose(args.verbose, "loaded the ini-file \"%s\"", args.f_in); -+ -+ /* Each section describes one volume */ -+ sects = iniparser_getnsec(args.dict); -+ if (sects == -1) { -+ errmsg("ini-file parsing error (iniparser_getnsec)"); -+ goto out_dict; -+ } -+ -+ verbose(args.verbose, "count of sections: %d", sects); -+ if (sects == 0) { -+ errmsg("no sections found the ini-file \"%s\"", args.f_in); -+ goto out_dict; -+ } -+ -+ /* -+ * Skip 2 PEBs at the beginning of the file for the volume table which -+ * will be written later. -+ */ -+ seek = ui.peb_size * 2; -+ if (lseek(args.out_fd, seek, SEEK_SET) != seek) { -+ sys_errmsg("cannot seek file \"%s\"", args.f_out); -+ goto out_dict; -+ } -+ -+ for (i = 0; i < sects; i++) { -+ const char *sname = iniparser_getsecname(args.dict, i); -+ struct ubigen_vol_info vi; -+ const char *img = NULL; -+ struct stat st; -+ int fd; -+ -+ if (!sname) { -+ errmsg("ini-file parsing error (iniparser_getsecname)"); -+ goto out_dict; -+ } -+ -+ if (args.verbose) -+ printf("\n"); -+ verbose(args.verbose, "parsing section \"%s\"", sname); -+ -+ err = read_section(sname, &vi, &img); -+ if (err == -1) -+ goto out_dict; -+ if (!err) -+ volumes += 1; -+ init_vol_info(&ui, &vi); -+ -+ if (vi.id >= ui.max_volumes) -+ return errmsg("too high volume ID %d, max. is %d", -+ vi.id, ui.max_volumes); -+ -+ verbose(args.verbose, "adding volume %d", vi.id); -+ -+ /* Make sure only one volume has auto-resize flag */ -+ if (vi.flags & UBI_VTBL_AUTORESIZE_FLG) { -+ if (autoresize_was_already) -+ return errmsg("only one volume is allowed " -+ "to have auto-resize flag"); -+ autoresize_was_already = 1; -+ } -+ -+ err = ubigen_add_volume(&ui, &vi, vtbl); -+ if (err) { -+ errmsg("cannot add volume for section \"%s\"", sname); -+ goto out_dict; -+ } -+ -+ if (!img) -+ continue; -+ -+ if (stat(img, &st)) { -+ sys_errmsg("cannot stat \"%s\"", img); -+ goto out_dict; -+ } -+ -+ /* -+ * Make sure the image size is not larger then the volume size. -+ */ -+ tmp = (st.st_size / (ui.leb_size + sizeof(unsigned int))) * sizeof(unsigned int); -+ if (st.st_size - tmp> vi.bytes) { -+ errmsg("error in section \"%s\": size of the image file \"%s\" " -+ "is %lld, which is larger then the volume size %lld", -+ sname, img, (long long)st.st_size, vi.bytes); -+ goto out_dict; -+ } -+ -+ fd = open(img, O_RDONLY); -+ if (fd == -1) { -+ sys_errmsg("cannot open \"%s\"", img); -+ goto out_dict; -+ } -+ -+ verbose(args.verbose, "writing volume %d", vi.id); -+ verbose(args.verbose, "image file: %s", img); -+ -+ err = ubigen_write_volume(&ui, &vi, args.ec, st.st_size-tmp, fd, args.out_fd); -+ close(fd); -+ if (err) { -+ errmsg("cannot write volume for section \"%s\"", sname); -+ goto out_dict; -+ } -+ -+ if (args.verbose) -+ printf("\n"); -+ } -+ -+ verbose(args.verbose, "writing layout volume"); -+ -+ err = ubigen_write_layout_vol(&ui, 0, 1, args.ec, args.ec, vtbl, args.out_fd); -+ if (err) { -+ errmsg("cannot write layout volume"); -+ goto out_dict; -+ } -+ -+ verbose(args.verbose, "done"); -+ -+ iniparser_freedict(args.dict); -+ free(vtbl); -+ close(args.out_fd); -+ return 0; -+ -+out_dict: -+ iniparser_freedict(args.dict); -+out_vtbl: -+ free(vtbl); -+out: -+ close(args.out_fd); -+ remove(args.f_out); -+ return err; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,99 @@ -+/* -+ * An utility to reformat the image file generated by mkfs.ubifs -+ * -+ * Authors: Yurong Tan (Nancy) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#define PROGRAM_VERSION "1.1" -+#define PROGRAM_NAME "ubirefimg" -+#define UBI_LEB_SIZE 258048 -+ -+/* -+ * sourcefile usually generated by mkfs.ubifs. -+ * usage: #ubirefimg sourcefile outputfile -+ */ -+int main(int argc, char * const argv[]) -+{ -+ int err, ifd, ofd, i, j, tmp; -+ struct stat st; -+ unsigned char *buf=NULL; -+ -+ buf = malloc(UBI_LEB_SIZE); -+ if(buf==NULL){ -+ printf("no mem\n"); -+ goto out_free; -+ } -+ -+ err = stat(argv[1], &st); -+ if (err < 0) { -+ printf("stat failed on \"%s\"", argv[1]); -+ goto out_free; -+ } -+ -+ ifd = open(argv[1], O_RDONLY); -+ if (ifd == -1) { -+ printf("cannot open \"%s\"", argv[1]); -+ goto out_close; -+ } -+ -+ ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644); -+ if (ofd == -1) { -+ printf("cannot create \"%s\"", argv[2]); -+ goto out_close; -+ } -+ -+ tmp = st.st_size/UBI_LEB_SIZE; -+ -+ for( i=0; i< tmp; i++ ){ -+ err = read(ifd, buf, UBI_LEB_SIZE); -+ if (err != UBI_LEB_SIZE) { -+ printf("read error\n"); -+ goto out_close1; -+ } -+ for(j=0; j -+ * Frank Haverkamp -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubirmvol" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ int vol_id; -+ const char *node; -+ /* For deprecated -d option handling */ -+ int devn; -+ char dev_name[256]; -+}; -+ -+static struct args args = { -+ .vol_id = -1, -+ .devn = -1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to remove UBI volumes."; -+ -+static const char *optionsstr = -+"-n, --vol_id= volume ID to remove\n" -+"-h, -?, --help print help message\n" -+"-V, --version print program version\n\n" -+"The following is a compatibility option which is deprecated, do not use it\n" -+"-d, --devn= UBI device number - may be used instead of the UBI\n" -+" device node name in which case the utility assumes\n" -+" that the device node is \"/dev/ubi\""; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-n ] [--vol_id=] [-h] [--help]\n\n" -+"Example: " PROGRAM_NAME "/dev/ubi0 -n 1 - remove UBI volume 1 from UBI device corresponding\n" -+" to the node file /dev/ubi0."; -+ -+static const struct option long_options[] = { -+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ /* Deprecated -d option */ -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int param_sanity_check(void) -+{ -+ if (args.vol_id == -1) { -+ errmsg("volume ID is was not specified"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "n:h?Vd:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ -+ case 'n': -+ args.vol_id = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.vol_id < 0) { -+ errmsg("bad volume ID: " "\"%s\"", optarg); -+ return -1; -+ } -+ break; -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'd': -+ /* Handle deprecated -d option */ -+ warnmsg("-d is depricated and will be removed, do not use it"); -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: " "\"%s\"", optarg); -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ errmsg("parameter is missing"); -+ return -1; -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ /* Handle deprecated -d option */ -+ if (args.devn != -1) { -+ sprintf(args.dev_name, "/dev/ubi%d", args.devn); -+ args.node = args.dev_name; -+ } else { -+ if (optind == argc) { -+ errmsg("UBI device name was not specified (use -h for help)"); -+ return -1; -+ } else if (optind != argc - 1) { -+ errmsg("more then one UBI device specified (use -h for help)"); -+ return -1; -+ } -+ -+ args.node = argv[optind]; -+ } -+ -+ -+ if (param_sanity_check()) -+ return -1; -+ -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) -+ return sys_errmsg("cannot open libubi"); -+ -+ err = ubi_node_type(libubi, args.node); -+ if (err == 2) { -+ errmsg("\"%s\" is an UBI volume node, not an UBI device node", -+ args.node); -+ goto out_libubi; -+ } else if (err < 0) { -+ errmsg("\"%s\" is not an UBI device node", args.node); -+ goto out_libubi; -+ } -+ -+ err = ubi_rmvol(libubi, args.node, args.vol_id); -+ if (err) { -+ sys_errmsg("cannot UBI remove volume"); -+ goto out_libubi; -+ } -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,335 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to update UBI volumes. -+ * -+ * Authors: Frank Haverkamp -+ * Joshua W. Boyer -+ * Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.1" -+#define PROGRAM_NAME "ubiupdatevol" -+ -+struct args { -+ int truncate; -+ const char *node; -+ const char *img; -+ /* For deprecated -d and -B options handling */ -+ int devn; -+ char dev_name[256]; -+ int broken_update; -+}; -+ -+static struct args args = { -+ .devn = -1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to write data to UBI volumes."; -+ -+static const char *optionsstr = -+"-n, --vol_id= ID of UBI volume to update\n" -+"-t, --truncate truncate volume (wipe it out)\n" -+"-h, --help print help message\n" -+"-V, --version print program version\n\n" -+"The following are compatibility options which are deprecated, do not use them\n" -+"-d, --devn= UBI device number - may be used instead of the UBI\n" -+" device node name in which case the utility assumes\n" -+" that the device node is \"/dev/ubi\"\n" -+"-B, --broken-update broken update, this is for testing"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-t] [-h] [-V] [--truncate] [--help]\n" -+"\t\t\t[--version] \n\n" -+"Example 1: " PROGRAM_NAME " /dev/ubi0_1 fs.img - write file \"fs.img\" to UBI volume /dev/ubi0_1\n" -+"Example 2: " PROGRAM_NAME " /dev/ubi0_1 -t - wipe out UBI volume /dev/ubi0_1"; -+ -+struct option long_options[] = { -+ { .name = "truncate", .has_arg = 0, .flag = NULL, .val = 't' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ /* Deprecated -d and -B options */ -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "broken-update", .has_arg = 1, .flag = NULL, .val = 'B' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "n:th?Vd:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 't': -+ args.truncate = 1; -+ break; -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'd': -+ { -+ char *endp; -+ -+ /* Handle deprecated -d option */ -+ warnmsg("-d is depricated and will be removed, do not use it"); -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: " "\"%s\"", optarg); -+ break; -+ } -+ -+ case 'B': -+ /* Handle deprecated -B option */ -+ warnmsg("-B is depricated and will be removed, do not use it"); -+ args.broken_update = 1; -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ /* Handle deprecated -d option */ -+ if (args.devn != -1) { -+ sprintf(args.dev_name, "/dev/ubi%d", args.devn); -+ args.node = args.dev_name; -+ } else { -+ if (optind == argc) -+ return errmsg("UBI device name was not specified (use -h for help)"); -+ else if (optind != argc - 2 && !args.truncate) -+ return errmsg("specify UBI device name and image file name as first 2 " -+ "parameters (use -h for help)"); -+ } -+ -+ args.node = argv[optind]; -+ args.img = argv[optind + 1]; -+ -+ return 0; -+} -+ -+static int truncate_volume(libubi_t libubi) -+{ -+ int err, fd; -+ -+ fd = open(args.node, O_RDWR); -+ if (fd == -1) -+ return sys_errmsg("cannot open \"%s\"", args.node); -+ -+ err = ubi_update_start(libubi, fd, 0); -+ if (err) { -+ sys_errmsg("cannot truncate volume \"%s\"", args.node); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return 0; -+} -+ -+static int ubi_write(int fd, const void *buf, int len) -+{ -+ int ret; -+ -+ while (len) { -+ ret = write(fd, buf, len); -+ if (ret < 0) { -+ if (errno == EINTR) { -+ warnmsg("do not interrupt me!"); -+ continue; -+ } -+ return sys_errmsg("cannot write %d bytes to volume \"%s\"", -+ len, args.node); -+ } -+ -+ if (ret == 0) -+ return errmsg("cannot write %d bytes to volume \"%s\"", len, args.node); -+ -+ len -= ret; -+ buf += ret; -+ } -+ -+ return 0; -+} -+ -+static int update_volume(libubi_t libubi, struct ubi_vol_info *vol_info) -+{ -+ int err, fd, ifd; -+ long long bytes, tmp; -+ struct stat st; -+ char *buf; -+ -+ buf = malloc(vol_info->leb_size+sizeof(unsigned int)); -+ if (!buf) -+ return errmsg("cannot allocate %d bytes of memory", vol_info->leb_size); -+ -+ err = stat(args.img, &st); -+ if (err < 0) { -+ errmsg("stat failed on \"%s\"", args.img); -+ goto out_free; -+ } -+ -+ bytes = st.st_size; -+ tmp = bytes / (vol_info->leb_size + sizeof(unsigned int)) * sizeof(unsigned int); -+ bytes -= tmp; -+ if (bytes > vol_info->rsvd_bytes ) { -+ errmsg("\"%s\" (size %lld) will not fit volume \"%s\" (size %lld)", -+ args.img, bytes, args.node, vol_info->rsvd_bytes); -+ goto out_free; -+ } -+ -+ /* A hack to handle deprecated -B option */ -+ if (args.broken_update) -+ bytes = 1; -+ -+ fd = open(args.node, O_RDWR); -+ if (fd == -1) { -+ sys_errmsg("cannot open UBI volume \"%s\"", args.node); -+ goto out_free; -+ } -+ -+ ifd = open(args.img, O_RDONLY); -+ if (ifd == -1) { -+ sys_errmsg("cannot open \"%s\"", args.img); -+ goto out_close1; -+ } -+ -+ err = ubi_update_start(libubi, fd, bytes); -+ if (err) { -+ sys_errmsg("cannot start volume \"%s\" update", args.node); -+ goto out_close; -+ } -+ -+ bytes += tmp; -+ while (bytes) { -+ int tocopy = vol_info->leb_size + sizeof(unsigned int) ; -+ -+ if (tocopy > bytes) -+ tocopy = bytes; -+ -+ err = read(ifd, buf, tocopy); -+ if (err != tocopy) { -+ if (errno == EINTR) { -+ warnmsg("do not interrupt me!"); -+ continue; -+ } else { -+ sys_errmsg("cannot read %d bytes from \"%s\"", -+ tocopy, args.img); -+ goto out_close; -+ } -+ } -+ -+ err = ubi_write(fd, buf, tocopy-sizeof(unsigned int)); -+ if (err) -+ goto out_close; -+ -+ bytes -= tocopy; -+ } -+ -+ close(ifd); -+ close(fd); -+ free(buf); -+ return 0; -+ -+out_close: -+ close(ifd); -+out_close1: -+ close(fd); -+out_free: -+ free(buf); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_vol_info vol_info; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) { -+ sys_errmsg("cannot open libubi"); -+ goto out_libubi; -+ } -+ -+ err = ubi_node_type(libubi, args.node); -+ if (err == 1) { -+ errmsg("\"%s\" is an UBI device node, not an UBI volume node", -+ args.node); -+ goto out_libubi; -+ } else if (err < 0) { -+ errmsg("\"%s\" is not an UBI volume node", args.node); -+ goto out_libubi; -+ } -+ -+ err = ubi_get_vol_info(libubi, args.node, &vol_info); -+ if (err) { -+ sys_errmsg("cannot get information about UBI volume \"%s\"", -+ args.node); -+ goto out_libubi; -+ } -+ -+ if (args.truncate) -+ err = truncate_volume(libubi); -+ else -+ err = update_volume(libubi, &vol_info); -+ if (err) -+ goto out_libubi; -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,38 @@ -+[targets] -+complete=ipl,spl,bootenv,kernel,rootfs -+bootcode=spl,bootenv -+ -+# Build sections -+[ipl] -+image=ipl.bin -+raw_starts=0x00000000 -+raw_total_size=128kiB -+ -+[spl] -+image=u-boot.bin -+ubi_ids=2,3 -+ubi_size=2MiB -+ubi_type=static -+ubi_names=spl_0,spl_1 -+ -+[bootenv] -+bootenv_file=bootenv_complete.txt -+ubi_ids=4,5 -+ubi_size=128kiB -+ubi_type=static -+ubi_names=bootenv_0,bootenv_1 -+ -+[kernel] -+image=vmlinux.bin -+ubi_ids=6,7 -+ubi_size=6MiB -+ubi_type=static -+ubi_names=kernel_0,kernel_1 -+ -+[rootfs] -+image=rootfs.bin -+ubi_ids=8,9 -+ubi_alignment=2kiB -+ubi_size=16MiB -+ubi_type=dynamic -+ubi_names=rootfs_0,rootfs_1 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,39 @@ -+[targets] -+complete=ipl,spl,bootenv,kernel,rootfs -+bootcode=spl,bootenv -+rootfs=rootfs -+ -+# Build sections -+[ipl] -+image=ipl.bin -+raw_starts=0x02FE0000, 0x03FE0000 -+raw_total_size=128kiB -+ -+[spl] -+image=u-boot.bin -+ubi_ids=2,3 -+ubi_size=2MiB -+ubi_type=static -+ubi_names=spl_0,spl_1 -+ -+[bootenv] -+bootenv_file=bootenv_complete.txt -+ubi_ids=4,5 -+ubi_size=128kiB -+ubi_type=static -+ubi_names=bootenv_0,bootenv_1 -+ -+[kernel] -+image=vmlinux.bin -+ubi_ids=6,7 -+ubi_size=6MiB -+ubi_type=static -+ubi_names=kernel_0,kernel_1 -+ -+[rootfs] -+image=rootfs.bin -+ubi_ids=8,9 -+ubi_alignment=2kiB -+ubi_size=16128kiB -+ubi_type=dynamic -+ubi_names=rootfs_0,rootfs_1 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,723 @@ -+#!/usr/bin/perl -+# -+# Copyright (c) International Business Machines Corp., 2006 -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+# -+ -+# -+# mkpfi -+# -+# This perl program is assembles PFI files from a config file. -+# -+# Author: Oliver Lohmann (oliloh@de.ibm.com) -+# -+use warnings; -+use strict; -+use lib "/usr/lib/perl5"; # Please change this path as you need it, or -+ # make a proposal how this could be done -+ # nicer. -+use Getopt::Long; -+use Pod::Usage; -+use Config::IniFiles; -+use File::Temp; -+ -+# ---------------------------------------------------------------------------- -+# Versions -+our $version : unique = "0.1"; -+our $pfi_version : unique = "0x1"; -+ -+# ---------------------------------------------------------------------------- -+# Globals -+my $verbose = 0; -+my $cfg; -+ -+my %opts = (); -+my %files = (config => ""); -+my @tmp_files; -+ -+my %tools = (ubicrc32 => "ubicrc32"); -+ -+# ---------------------------------------------------------------------------- -+# Processing the input sections -+# -+# The idea is to combine each section entry with a function -+# in order to allow some kind of preprocessing for the values -+# before they are written into the PFI file. -+# This is especially useful to be more verbose and -+# user-friendly in the layout file. -+# -+# All key-function hashes are applied after the general -+# validation of the configuration file. -+# If any mandatory key is missing in a section the user -+# will be informed and the PFI creation process is aborted. -+# -+# Default keys will be checked for their presence inside the config -+# file. If they are missing, they will be generated with appr. values. -+ -+# Mandatory keys for UBI volumes. -+my %ubi_keys = ("ubi_ids" => \&check_id_list, -+ "ubi_size" => \&replace_num, -+ "ubi_type" => \&replace_type, -+ "ubi_names" => \&remove_spaces, -+ "ubi_alignment" => \&replace_num); -+ -+# Mandatory keys for RAW sections. -+my %raw_keys = ("raw_starts" => \&expand_starts, -+ "raw_total_size" => \&replace_num); -+ -+# Common default keys for documentation and control purposes. -+my %common_keys = ("flags" => \&replace_num, -+ "label" => \&do_nothing); -+ -+# Define any defaults here. Values which maintained in this default -+# region need not to be specified by the user explicitly. -+my %def_ubi_keys = ("ubi_alignment" => [\&set_default, "0x1"]); -+my %def_raw_keys = (); -+my %def_common_keys = ("flags" => [\&set_default, "0x0"], -+ "label" => [\&generate_label, ""]); -+ -+# ---------------------------------------------------------------------------- -+# Input keys, actually the path to the input data. -+ -+my %input_keys = ("image" => \&do_nothing); -+ -+# Placeholder keys allow the replacement via a special -+# purpose function. E.g. the bootenv_file key will be used -+# to generate bootenv binary data from an text file and -+# replace the bootenv_file key with an image key to handle it -+# in the same way in the further creation process. -+my %input_placeholder_keys = ("bootenv_file" => \&create_bootenv_image); -+ -+# ---------------------------------------------------------------------------- -+# Helper -+ -+# @brief Get current time string. -+sub get_date { -+ my $tmp = scalar localtime; -+ $tmp =~ s/ /_/g; -+ return $tmp; -+} -+ -+# @brief Print an info message to stdout. -+sub INFO($) { -+ my $str = shift; -+ -+ if (!$verbose) { -+ return; -+ } -+ -+ print STDOUT $str; -+} -+ -+# @brief Print an error message to stderr. -+sub ERR($) { -+ my $str = shift; -+ print STDERR $str; -+} -+ -+# @brief Print a warning message to stderr. -+sub WARN($) { -+ my $str = shift; -+ print STDERR $str; -+} -+ -+sub parse_command_line($) { -+ my $opt = shift; -+ my $result = GetOptions( "help" => \$$opt{'help'}, -+ "man" => \$$opt{'man'}, -+ "config=s" => \$$opt{'config'}, -+ "verbose" => \$$opt{'verbose'}, -+ ) or pod2usage(2); -+ pod2usage(1) if defined ($$opt{help}); -+ pod2usage(-verbose => 2) if defined ($$opt{man}); -+ -+ $verbose = $$opt{verbose} if defined $$opt{verbose}; -+ -+ if (!defined $$opt{config}) { -+ ERR("[ ERROR: No config file specified. Aborting...\n"); -+ exit 1; -+ } -+ -+} -+ -+# @brief Check if all needed tools are in PATH. -+sub check_tools { -+ my $err = 0; -+ my $key; -+ -+ foreach $key (keys %tools) { -+ if (`which $tools{$key}` eq "") { -+ ERR("\n") if ($err == 0); -+ ERR("! Please add the tool \'$tools{$key}\' " . -+ "to your path!\n"); -+ $err = 1; -+ } -+ } -+ die "[ ERROR: Did not find all needed tools!\n" if $err; -+} -+ -+sub open_cfg_file($) { -+ my $fname = shift; -+ my $res = new Config::IniFiles( -file => $fname ); -+ -+ die "[ ERROR: Cannot load your config file!\n" if (!defined $res); -+ return $res; -+} -+ -+sub set_default($$$$) { -+ my ($cfg, $section, $parameter, $def_value) = @_; -+ $cfg->newval($section, $parameter, $def_value); -+ return; -+} -+ -+sub generate_label($$$$) { -+ my ($cfg, $section, $parameter, $def_value) = @_; -+ my $new_label = $def_value . $section; -+ $new_label .= "_" . get_date; -+ $cfg->newval($section, $parameter, $new_label); -+ return; -+} -+ -+# @brief Converts any num to a unified hex string, i.e the resulting value -+# always starts with "0x" and is aligned to 8 hexdigits. -+# @return Returns 0 on success, otherwise an error occured. -+# -+sub any_num_to_hex($$) { -+ my $val = shift; -+ my $res = shift; -+ -+ # M(iB) -+ if ($val =~ m/([0-9]+)[Mm][i]?[Bb]?/g) { -+ $$res = sprintf("0x%08x", $1 * 1024 * 1024); -+ } -+ # k(iB) -+ elsif ($val =~ m/([0-9]+)[kK][i]?[Bb]?/g) { -+ $$res = sprintf("0x%08x", $1 * 1024); -+ } -+ # hex -+ elsif ($val =~ m/0x?([0-9a-fA-F]+)/g) { -+ $$res = sprintf("0x%08x", hex $1); -+ } -+ # decimal -+ elsif ($val =~ m/^([0-9]+)$/g) { -+ $$res = sprintf("0x%08x", $1); -+ } -+ else { -+ $$res = ""; -+ return -1; -+ } -+ -+ return 0; -+} -+ -+sub remove_spaces($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my ($start, @starts, @new_starts); -+ my $val = $cfg->val($section, $parameter); -+ my $res; -+ -+ $val =~ s/ //g; # spaces -+ $cfg->newval($section, $parameter, $val); -+} -+ -+sub expand_starts($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my ($start, @starts, @new_starts); -+ my $val = $cfg->val($section, $parameter); -+ my $res; -+ -+ $val =~ s/ //g; # spaces -+ @starts = split(/,/, $val); -+ -+ foreach $start (@starts) { -+ if (any_num_to_hex($start, \$res) != 0) { -+ ERR("[ ERROR: [$section]\n"); -+ ERR("[ Expecting a list of numeric " . -+ "values for parameter: $parameter\n"); -+ exit 1; -+ } -+ push (@new_starts, $res); -+ } -+ $res = join(',', @starts); -+ -+ $cfg->newval($section, $parameter, $res); -+} -+ -+sub check_id_list($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my $val = $cfg->val($section, $parameter); -+ my $res; -+ -+ if (!($val =~ m/^[0-9]+[,0-9]*/)) { -+ ERR("[ ERROR: Syntax error in 'ubi_ids' in " . -+ "section '$section': $val\n"); -+ ERR("[ Aborting... "); -+ exit 1; -+ } -+} -+ -+sub replace_type($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my $val = $cfg->val($section, $parameter); -+ my $res; -+ -+ $res = lc($val); -+ grep {$res eq $_} ('static', 'dynamic') -+ or die "[ ERROR: Unknown UBI Volume Type in " . -+ "section '$section': $val\n"; -+ -+ $cfg->newval($section, $parameter, $res); -+} -+ -+ -+sub replace_num($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my $val = $cfg->val($section, $parameter); -+ my $res = ""; -+ -+ if (any_num_to_hex($val, \$res) != 0) { -+ ERR("[ ERROR: [$section]\n"); -+ ERR("[ Expecting a numeric value " . -+ "for parameter: $parameter\n"); -+ exit 1; -+ } -+ $cfg->newval($section, $parameter, $res); -+} -+ -+sub do_nothing($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ return; -+} -+ -+sub bootenv_sanity_check($) { -+ my $env = shift; # hash array containing bootenv -+ my %pdd = (); -+ -+ defined($$env{'pdd'}) or return "'pdd' not defined"; -+ foreach (split /,/, $$env{'pdd'}) { -+ defined($$env{$_}) or return "undefined '$_' in pdd"; -+ $pdd{$_} = 1; -+ } -+ -+ defined $$env{'pdd_preserve'} or -+ return ""; -+ foreach (split /,/, $$env{'pdd_preserve'}) { -+ defined($pdd{$_}) -+ or return "pdd_preserve field '$_' not in pdd"; -+ } -+ return ""; -+} -+ -+sub create_bootenv_image($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my $txt_fn = $cfg->val($section, "bootenv_file"); -+ my $in; -+ -+ my %value = (); -+ my @key = (); -+ -+ open $in, "<", $txt_fn -+ or die "[ ERROR: can't open bootenv file '$txt_fn'.\n"; -+ while (<$in>) { -+ next if (/^\s*(\#.*)?$/); # Skip comments/whitespace. -+ -+ if (/^(\S+?)\+\=(.*)$/) { -+ defined($value{$1}) or -+ die "$txt_fn:$.: error: appending to" . -+ " non-existent '$1'\n"; -+ $value{$1} .= $2; -+ } elsif (/^(\S+?)\=(.*)$/) { -+ not defined($value{$1}) or -+ die "$txt_fn:$.: error: trying to" . -+ " redefine '$1'\n"; -+ push @key, $1; -+ $value{$1} = $2; -+ } else { -+ die "$txt_fn:$.: error: unrecognized syntax\n"; -+ } -+ } -+ close $in; -+ -+ $_ = &bootenv_sanity_check(\%value) -+ and die "$txt_fn: error: $_\n"; -+ -+ my $tmp_file = new File::Temp(); -+ push (@tmp_files, $tmp_file); -+ -+ foreach (@key) { -+ print $tmp_file "$_=", $value{$_}, "\0"; -+ } -+ close $tmp_file; -+ -+ $cfg->newval($section, "image", $tmp_file-> filename); -+} -+ -+sub process_keys($$$) { -+ my ($cfg, $section, $keys) = @_; -+ my @parameters = $cfg->Parameters($section); -+ my $i; -+ -+ for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { -+ if (defined($$keys{$parameters[$i]})) { -+ $$keys{$parameters[$i]}->($cfg, $section, -+ $parameters[$i]); -+ } -+ } -+ -+} -+ -+sub is_in_keylist($$) { -+ my ($key, $keys) = @_; -+ my $i; -+ -+ for ($i = 0; $i < scalar(@$keys); $i++) { -+ if ($$keys[$i] eq $key) { -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+sub check_default_keys($$$) { -+ my ($cfg, $section, $keys) = @_; -+ my @parameters = $cfg->Parameters($section); -+ my $key; -+ -+ foreach $key (keys %$keys) { -+ if (!is_in_keylist($key, \@parameters)) { -+ $$keys{$key}[0]-> -+ ($cfg, $section, $key, $$keys{$key}[1]); -+ } -+ } -+ -+} -+ -+ -+ -+sub check_keys($$$) { -+ my ($cfg, $section, $keys) = @_; -+ my @parameters = $cfg->Parameters($section); -+ my ($i, $key, $err); -+ -+ $err = 0; -+ for ($i = 0 ; $i < scalar(@$keys) ; $i++ ) { -+ if (!is_in_keylist($$keys[$i], \@parameters)) { -+ ERR("[ ERROR: [$section]\n") if $err == 0; -+ $err = 1; -+ ERR("[ Missing key '$$keys[$i]'\n"); -+ } -+ } -+ -+ if ($err) { -+ ERR("[ Aborting...\n"); -+ exit 1; -+ } -+} -+ -+sub push_pfi_data($$$$$) { -+ my ($cfg, $section, $pfi_infos, $keys, $mode) = @_; -+ my ($tmp, $i, $hdr); -+ -+ my %pfi_info = (); -+ $pfi_info{'mode'} = $mode; -+ $pfi_info{'image'} = $cfg->val($section, "image"); -+ -+ # Build the PFI header -+ $hdr = sprintf("PFI!\n"); -+ $hdr .= sprintf("version=0x%08x\n", hex $pfi_version); -+ $hdr .= sprintf("mode=$mode\n"); -+ -+ # calculate the size of the binary data part -+ $tmp = -s $cfg->val($section, "image"); -+ if (!defined $tmp) { -+ ERR("[ ERROR: [$section]\n"); -+ ERR("[ Missing input image: " -+ . $cfg->val($section, "image") . "\n"); -+ exit 1; -+ } -+ # Check for the image to fit into the given space -+ my $quota; -+ if ($mode eq 'raw') { -+ $quota = oct $cfg->val($section, "raw_total_size"); -+ } elsif ($mode eq 'ubi') { -+ $quota = oct $cfg->val($section, "ubi_size"); -+ } -+ $tmp <= $quota -+ or die "[ERROR: image file too big: " . -+ $cfg->val($section, "image") . "\n"; -+ $pfi_info{'size'} = $tmp; -+ -+ $hdr .= sprintf("size=0x%08x\n", $tmp); -+ -+ my $img_file = $cfg->val($section, "image"); -+ my $crc32 = `$tools{'ubicrc32'} $img_file 2>&1`; -+ if (any_num_to_hex($crc32, \$tmp) != 0) { -+ die "[ ERROR: $tools{'ubicrc32'} returned with errors"; -+ } -+ $hdr .= sprintf("crc=$tmp\n"); -+ -+ -+ # Process all remaining keys -+ for ($i = 0; $i < scalar (@$keys); $i++) { -+ if ($$keys[$i] eq "image") { # special case image input file -+ if (! -e ($tmp = $cfg->val($section, "image"))) { -+ ERR("[ ERROR: [$section]\n"); -+ ERR("[ Cannot find input file $tmp\n"); -+ exit 1; -+ } -+ next; -+ } -+ $hdr .= sprintf("%s=%s\n", $$keys[$i], -+ $cfg->val($section, $$keys[$i])); -+ } -+ -+ $hdr .= sprintf("\n"); # end marker for PFI-header -+ -+ $pfi_info{'header'} = $hdr; -+ -+ # store in the header list -+ push @$pfi_infos, \%pfi_info; -+} -+ -+sub process_section($$$$$$) { -+ my ($cfg, $section, $pfi_infos, $custom_keys, -+ $def_custom_keys, $mode) = @_; -+ my @keys = (keys %common_keys, keys %$custom_keys); -+ my @complete_keys = (@keys, keys %input_keys); -+ -+ # set defaults if necessary -+ check_default_keys($cfg, $section, $def_custom_keys); -+ check_default_keys($cfg, $section, \%def_common_keys); -+ -+ # check for placeholders... -+ process_keys($cfg, $section, \%input_placeholder_keys); -+ -+ # VALIDATE layout.cfg entries -+ check_keys($cfg, $section, \@complete_keys); -+ -+ # execute linked functions (if any) -+ process_keys($cfg, $section, \%common_keys); -+ process_keys($cfg, $section, $custom_keys); -+ -+ push_pfi_data($cfg, $section, $pfi_infos, \@keys, $mode); -+} -+ -+sub get_section_info($$) { -+ my ($cfg, $section) = @_; -+ my @parameters = $cfg->Parameters($section); -+ my ($ubi, $raw, $i, @res); -+ -+ $ubi = $raw = 0; -+ for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { -+ if ($parameters[$i] =~ m/ubi_/gi) { -+ $ubi = 1; -+ @res = (\%ubi_keys, \%def_ubi_keys, "ubi"); -+ } -+ if ($parameters[$i] =~ m/raw_/gi) { -+ $raw = 1; -+ @res = (\%raw_keys, \%def_raw_keys, "raw"); -+ } -+ } -+ -+ if (($ubi + $raw) != 1) { # double definition in section -+ ERR("[ ERROR: Layout error in section '$section'\n"); -+ exit 1; -+ } -+ -+ return @res; -+} -+ -+sub mk_target_list($$) { -+ my $val = shift; -+ my $tmp = shift; -+ my $complete = 0; -+ -+ if ($val =~ m/\((.*)\)/g) { -+ $val = $1; -+ $complete = 1; -+ } -+ $val =~ s/ //g; # spaces -+ -+ @$tmp = split(/,/, $val); -+ -+ return $complete; -+} -+ -+sub copy_bytes($$$) { -+ my ($in, $out, $to_copy) = @_; -+ -+ while ($to_copy) { -+ my $buf; -+ my $bufsize = 1024*1024; -+ -+ $bufsize < $to_copy or $bufsize = $to_copy; -+ read($in, $buf, $bufsize) == $bufsize -+ or die "[ ERROR: Image file shrunk during operation\n"; -+ print $out $buf; -+ $to_copy -= $bufsize; -+ } -+} -+ -+sub write_target($$) { -+ my ($pfi_infos, $target) = @_; -+ my ($pfi_info); -+ -+ INFO("[ Writting target pfi file: '$target.pfi'...\n"); -+ if (-e "$target.pfi") { -+ WARN("! Replaced old pfi...\n"); -+ `rm -f $target.pfi`; -+ } -+ open(FILE, ">", "$target.pfi") -+ or die "[ ERROR: Cannot create output file: $target.pfi\n"; -+ binmode(FILE); -+ -+ # @FIXME sort by mode (first raw, then ubi) -+ # Currently this ordering is based on a string comparism. :-) -+ @$pfi_infos = sort {(lc $$a{'mode'}) cmp (lc $$b{'mode'})} @$pfi_infos; -+ -+ # Print all headers first -+ foreach $pfi_info (@$pfi_infos) { -+ print FILE $$pfi_info{'header'}; -+ -+ } -+ # Print the linked data sections -+ print FILE "DATA\n"; -+ foreach $pfi_info (@$pfi_infos) { -+ open(IMAGE, "<", $$pfi_info{'image'}) -+ or die "[ ERROR: Cannot open input image: " . -+ "$$pfi_info{'image'}" . "\n"; -+ binmode(IMAGE); -+ ©_bytes(\*IMAGE, \*FILE, $$pfi_info{'size'}); -+ close(IMAGE) or die "[ ERROR: Cannot close input image: " . -+ "$$pfi_info{'image'}" . "\n"; -+ } -+ close(FILE) or die "[ ERROR: Cannot close output file: $target.pfi\n"; -+} -+ -+sub process_config($) { -+ my $cfg = shift; -+ my @sections = $cfg->Sections; -+ my ($i, $j, $keylist, $def_keylist, $mode, $tmp, -+ @tlist, $complete,@pfi_infos); -+ -+ my @parameters = $cfg->Parameters("targets") or -+ die "[ ERROR: Config file has no 'targets' section!\n"; -+ -+ for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { -+ INFO("[ Processing target '$parameters[$i]'...\n"); -+ @pfi_infos = (); -+ -+ # get a list of subtargets -+ $complete = mk_target_list($cfg->val("targets", -+ $parameters[$i]), \@tlist); -+ # build all subtargets -+ for ($j = 0 ; $j < scalar(@tlist) ; $j++ ) { -+ ($keylist, $def_keylist, $mode) -+ = get_section_info($cfg, $tlist[$j]); -+ process_section($cfg, $tlist[$j], -+ \@pfi_infos, -+ $keylist, $def_keylist, $mode); -+ } -+ -+ write_target(\@pfi_infos, $parameters[$i]); -+ } -+ -+ INFO("[ Success.\n"); -+ -+ -+} -+ -+sub clear_files() { -+ # @FIXME: -+ # Works implicitly and Fedora seems to have removed -+ # the cleanup call. Thus for now, inactive. -+ # File::Temp::cleanup(); -+} -+ -+require 5.008_000; # Tested with version 5.8.0. -+select STDOUT; $| = 1; # make STDOUT output unbuffered -+select STDERR; $| = 1; # make STDERR output unbuffered -+ -+parse_command_line(\%opts); -+check_tools; -+$cfg = open_cfg_file($opts{config}); -+process_config($cfg); -+clear_files; -+ -+__END__ -+ -+ -+=head1 NAME -+ -+mkpfi - Using GetOpt::Long, Pod::Usage, Config::IniFiles -+ -+ -+=head1 SYNOPSIS -+ -+mkpfi [OPTIONS ...] -+ -+ -+ OPTION -+ -+ [--config] [--help] [--man] -+ -+ -+=head1 ABSTRACT -+ -+Perl script for generating pdd pfi files from given config files. -+ -+=head1 OPTIONS -+ -+=over -+ -+=item B<--help> -+ -+Print out brief help message. -+ -+=item B<--usage> -+ -+Print usage. -+ -+=item B<--config> -+ -+Config input file. -+ -+=item B<--man> -+ -+Print manual page, same as 'perldoc mkpfi'. -+ -+=item B<--verbose> -+ -+Be verbose! -+ -+=back -+ -+=head1 BUGS -+ -+Report via MTD mailing list -+ -+ -+=head1 SEE ALSO -+ -+http://www.linux-mtd.infradead.org/ -+ -+ -+=head1 AUTHOR -+ -+Oliver Lohmann (oliloh@de.ibm.com) -+ -+=cut ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,74 @@ -+#!/usr/bin/perl -w -+ -+# Subroutine crc32(): Calculates the CRC on a given string. -+ -+{ -+ my @table = (); -+ -+ # @brief Calculate CRC32 for a given string. -+ sub crc32 -+ { -+ unless (@table) { -+ # Initialize the CRC table -+ my $poly = 0xEDB88320; -+ @table = (); -+ -+ for my $i (0..255) { -+ my $c = $i; -+ -+ for my $j (0..7) { -+ $c = ($c & 1) ? (($c >> 1) ^ $poly) : ($c >> 1); -+ } -+ $table[$i] = $c; -+ } -+ } -+ my $s = shift; # string to calculate the CRC for -+ my $crc = shift; # CRC start value -+ -+ defined($crc) -+ or $crc = 0xffffffff; # Default CRC start value -+ -+ for (my $i = 0; $i < length($s); $i++) { -+ $crc = $table[($crc ^ ord(substr($s, $i, 1))) & 0xff] -+ ^ ($crc >> 8); -+ } -+ return $crc; -+ } -+} -+ -+sub crc32_on_file -+{ -+ my $file = shift; -+ -+ my $crc32 = crc32(''); -+ my $buf = ''; -+ my $ret = 0; -+ -+ while ($ret = read($file, $buf, 8192)) { -+ $crc32 = crc32($buf, $crc32); -+ } -+ defined($ret) -+ or return undef; -+ printf("0x%x\n", $crc32); -+} -+ -+ -+# Main routine: Calculate the CRCs on the given files and print the -+# results. -+ -+{ -+ if (@ARGV) { -+ while (my $path = shift) { -+ my $file; -+ open $file, "<", $path -+ or die "Error opening '$path'.\n"; -+ -+ &crc32_on_file($file) -+ or die "Error reading from '$path'.\n"; -+ close $file; -+ } -+ } else { -+ &crc32_on_file(\*STDIN) -+ or die "Error reading from stdin.\n"; -+ } -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,75 @@ -+# -+# Makefile -+# -+# Testcase for UBI pfi update. -+# -+# Author: Frank Haverkamp -+# -+ -+card = test -+mkpfi_cfg = test.cfg -+ -+# -+# Some default values you might want to overwrite. Try it if you need -+# it and add more if needed. Note that no real sanity checking is done -+# on those values. If you do it wrong your card has no valid PDD data. -+# -+ -+PATH := $(PATH):/opt/ppc/usr/bin:../perl:.. -+ -+dd = dd -+sed = sed -+bin2nand = bin2nand -+ubigen = ubigen -+mkpfi = mkpfi -v -+pfi2bin = pfi2bin -v -+ -+vmlinux_bin ?= test_vmlinux.bin -+rootfs_bin ?= test_rootfs.bin -+spl_bin ?= test_u-boot.bin -+pdd_txt ?= pdd.txt -+ -+flashtype ?= nand -+pagesize ?= 2048 -+ -+compl ?= $(card)_complete -+compl_pfi ?= $(compl).pfi -+compl_img ?= $(compl).img -+ -+compl_nand2048_mif=$(compl).$(flashtype)$(pagesize).mif -+compl_nand2048_img=$(compl).$(flashtype)$(pagesize).img -+ -+all: $(compl_pfi) $(compl_nand2048_mif) -+ -+$(compl_pfi): $(vmlinux_bin) $(rootfs_bin) $(spl_bin) -+ $(mkpfi) -c $(mkpfi_cfg) -+ -+# Binary data and out of band data (OOB) -+# -+$(compl_nand2048_mif): $(compl_img) -+ $(bin2nand) -p $(pagesize) -o $(compl_nand2048_mif) $< -+ -+# Binary data only -+# -+$(compl_img): $(compl_pfi) -+ $(pfi2bin) -j $(pdd_txt) -o $@ $< -+ -+# -+# Default data -+# -+# If the binary data is not available in the current working directory -+# we try to create symlinks to our test data. -+# -+$(vmlinux_bin) $(rootfs_bin) $(spl_bin): -+ @echo -+ @echo "No $@ found, will use defaults !" -+ @echo -+ @echo "OR press CTRL-C to provide your own $@" && \ -+ sleep 1 && \ -+ $(dd) if=/dev/urandom of=$@ bs=1M count=1 -+ -+clean: -+ $(RM) *.pfi *~ -+ -+distclean: clean -+ $(RM) *.bin *.mif *.oob *.img ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/README 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,11 @@ -+README -+====== -+ -+This procedure creates a test pfi which should be flashed to our -+system with pfiflash. The testcase should read the data back and -+compare with the original. -+ -+We should try not forget to run these tests before we release -+a new version of UBI. -+ -+Frank ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,5 @@ -+TODO -+==== -+ -+ * Range checking is broken, reserving 2M and offering 3M binary data -+ ... works!? No! ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,184 @@ -+#!/bin/sh -+# -+# Testcase for nand2bin and bin2nand. Generate testdata and inject -+# biterrors. Convert data back and compare with original data. -+# -+# Conversion: -+# bin -> bin2nand -> mif -> nand2bin -> img -+# -+ -+inject_biterror=./scripts/inject_biterror.pl -+ -+pagesize=2048 -+oobsize=64 -+ -+# Create test data -+dd if=/dev/urandom of=testblock.bin bs=131072 count=1 -+ -+echo "Test conversion without bitflips ..." -+ -+echo -n "Convert bin to mif ... " -+bin2nand --pagesize=${pagesize} -o testblock.mif testblock.bin -+if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+else -+ echo "ok" -+fi -+ -+echo -n "Convert mif to bin ... " -+nand2bin --pagesize=${pagesize} -o testblock.img testblock.mif -+if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+else -+ echo "ok" -+fi -+ -+echo -n "Comparing data ... " -+diff testblock.bin testblock.img -+if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+else -+ echo "ok" -+fi -+ -+echo "Test conversion with uncorrectable ECC erors ..." -+echo -n "Inject biterror at offset $ioffs ... " -+${inject_biterror} --offset=0 --bitmask=0x81 \ -+ --input=testblock.mif \ -+ --output=testblock_bitflip.mif -+if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+else -+ echo "ok" -+fi -+ -+echo "Convert mif to bin ... " -+rm testblock.img -+nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \ -+ testblock_bitflip.mif -+if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+else -+ echo "ok" -+fi -+ -+echo -n "Comparing data, must fail due to uncorrectable ECC ... " -+diff testblock.bin testblock.img -+if [ $? -ne "0" ]; then -+ echo "ok" # Must fail! -+else -+ echo "failed!" -+ exit 1 -+fi -+ -+echo "Test bitflips in data ... " -+for offs in `seq 0 255` ; do -+ -+ cp testblock.mif testblock_bitflip.mif -+ -+ for xoffs in 0 256 512 768 ; do -+ let ioffs=$offs+$xoffs -+ -+ cp testblock_bitflip.mif testblock_bitflip_tmp.mif -+ echo -n "Inject biterror at offset $ioffs ... " -+ ${inject_biterror} --offset=${ioffs} --bitmask=0x01 \ -+ --input=testblock_bitflip_tmp.mif \ -+ --output=testblock_bitflip.mif -+ if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ done -+ -+ echo "Convert mif to bin ... " -+ rm testblock.img -+ nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \ -+ testblock_bitflip.mif -+ if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ -+ echo -n "Comparing data ... " -+ diff testblock.bin testblock.img -+ if [ $? -ne "0" ]; then -+ hexdump testblock.bin > testblock.bin.txt -+ hexdump testblock.img > testblock.img.txt -+ echo "Use tkdiff testblock.bin.txt testblock.img.txt to compare" -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ -+ # Without correction -+ echo "Convert mif to bin ... " -+ rm testblock.img -+ nand2bin --pagesize=${pagesize} -o testblock.img \ -+ testblock_bitflip.mif -+ if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ -+ echo -n "Comparing data must differ, correction is disabled ... " -+ diff testblock.bin testblock.img -+ if [ $? -ne "0" ]; then -+ echo "ok" # must fail -+ else -+ echo "failed!" -+ exit 1 -+ fi -+done -+ -+echo "Test bitflips in OOB data ... " -+for offs in `seq 0 $oobsize` ; do -+ -+ let ioffs=$pagesize+$offs -+ -+ echo -n "Inject biterror at offset $ioffs ... " -+ ${inject_biterror} --offset=${ioffs} --bitmask=0x01 \ -+ --input=testblock.mif \ -+ --output=testblock_bitflip.mif -+ if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ -+ echo "Convert mif to bin ... " -+ rm testblock.img -+ nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \ -+ testblock_bitflip.mif -+ if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ -+ echo -n "Comparing data ... " -+ diff testblock.bin testblock.img -+ if [ $? -ne "0" ]; then -+ hexdump testblock.bin > testblock.bin.txt -+ hexdump testblock.img > testblock.img.txt -+ echo "Use tkdiff testblock.bin.txt testblock.img.txt to compare" -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+done -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,94 @@ -+#!/usr/bin/perl -w -+# -+# 2007 Frank Haverkamp -+# -+# Program for bit-error injection. I am sure that perl experts do it -+# in 1 line. Please let me know how it is done right ;-). -+# -+ -+use strict; -+use warnings; -+use Getopt::Long; -+use Pod::Usage; -+ -+my $i; -+my $help; -+my $result; -+my $offset = 0; -+my $bitmask = 0x01; -+my $in = "input.mif"; -+my $out = "output.mif"; -+ -+$result = GetOptions ("offset=i" => \$offset, # numeric -+ "bitmask=o" => \$bitmask, # numeric -+ "input=s" => \$in, # string -+ "output=s" => \$out, # string -+ "help|?" => \$help) or pod2usage(2); -+ -+pod2usage(1) if $help; -+ -+my $buf; -+ -+open(my $in_fh, "<", $in) -+ or die "Cannot open file $in: $!"; -+binmode $in_fh; -+ -+open(my $out_fh, ">", $out) or -+ die "Cannot open file $out: $!"; -+binmode $out_fh; -+ -+$i = 0; -+while (sysread($in_fh, $buf, 1)) { -+ -+ $buf = pack('C', unpack('C', $buf) ^ $bitmask) if ($i == $offset); -+ syswrite($out_fh, $buf, 1) or -+ die "Cannot write to offset $offset: $!"; -+ $i++; -+} -+ -+close $in_fh; -+close $out_fh; -+ -+__END__ -+ -+=head1 NAME -+ -+inject_biterrors.pl -+ -+=head1 SYNOPSIS -+ -+inject_biterror.pl [options] -+ -+=head1 OPTIONS -+ -+=over 8 -+ -+=item B<--help> -+ -+Print a brief help message and exits. -+ -+=item B<--offset>=I -+ -+Byte-offset where bit-error should be injected. -+ -+=item B<--bitmask>=I -+ -+Bit-mask where to inject errors in the byte. -+ -+=item B<--input>=I -+ -+Input file. -+ -+=item B<--output>=I -+ -+Output file. -+ -+=back -+ -+=head1 DESCRIPTION -+ -+B will read the given input file and inject -+biterrors at the I specified. The location of the biterrors -+are defined by the I parameter. -+ -+=cut ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,91 @@ -+#!/bin/sh -+# -+# Testcase for JFFS2 verification. We do not want to see any -+# kernel errors occuring when this is executed. -+# -+# -+# To have a standardized output I define the following function to be -+# used when a test was ok or when it failed. -+# -+failed () -+{ -+ echo "FAILED" -+} -+ -+passed () -+{ -+ echo "PASSED" -+} -+ -+# -+# Print sucess message. Consider to exit with zero as return code. -+# -+exit_success () -+{ -+ echo "SUCCESS" -+ exit 0 -+} -+ -+# -+# Print failure message. Consider to exit with non zero return code. -+# -+exit_failure () -+{ -+ echo "FAILED" -+ exit 1 -+} -+ -+echo "***********************************************************************" -+echo "* jffs2 testing ... *" -+echo "***********************************************************************" -+ -+ulimit -c unlimited -+ -+for i in `seq 5000`; do -+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " -+ dd if=/dev/urandom of=test.bin bs=$i count=1; -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo "Copy to different file ... " -+ dd if=test.bin of=new.bin bs=$i count=1; -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo "Comparing files ... " -+ cmp test.bin new.bin -+ dd if=test.bin of=new.bin bs=$i count=1; -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+done -+ -+for i in `seq 5000`; do -+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " -+ dd if=/dev/urandom of=foo bs=$i count=1; -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+done -+ -+for i in `seq 5000`; do -+ echo "Testing $i byte (dd if=/dev/zero of=foo bs=$i count=1) ... " -+ dd if=/dev/zero of=foo bs=$i count=1; -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+done -+ -+echo "***********************************************************************" -+echo "* Congratulations, no errors found! *" -+echo "* Have fun with your cool JFFS2 using system! *" -+echo "***********************************************************************" -+ -+exit_success ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,32 @@ -+#!/usr/bin/perl -w -+ -+# -+# Author: Artem B. Bityutskiy -+# -+# A small scrip which creates UBI device nodes in /dev. UBI allocates -+# major number dynamically, so the script looks at /proc/devices to find -+# out UBI's major number. -+# -+ -+ -+my $proc = '/proc/devices'; -+my $regexp = '(\d+) (ubi\d+)$'; -+ -+ -+open FILE, "<", $proc or die "Cannot open $proc file: $!\n"; -+my @file = ; -+close FILE; -+ -+foreach (@file) { -+ next if not m/$regexp/g; -+ print "found $2\n"; -+ -+ system("rm -rf /dev/$2"); -+ system("mknod /dev/$2 c $1 0"); -+ -+ for (my $i = 0; $i < 128; $i += 1) { -+ system("rm -rf /dev/$2_$i"); -+ my $j = $i + 1; -+ system("mknod /dev/$2_$i c $1 $j"); -+ } -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,16 @@ -+pdd=flash_type,flash_size,flash_eraseblock_size,flash_page_size,card_serialnumber,card_type,ethaddr,eth1addr,eth0,eth1,total,card_hardwarelevel -+pdd_preserve=ethaddr,eth1addr,card_serialnumber -+# To be personalized -+ethaddr=00:04:34:56:78:9A -+eth1addr=00:04:34:56:78:9B -+card_serialnumber=SN0 -+# Static for this card type -+total=102M -+card_type=nand_driven_testcard -+card_hardwarelevel=0 -+eth0=bcm5222,eth0,0 -+eth1=bcm5222,eth0,1 -+flash_type=NAND -+flash_size=0x08000000 -+flash_eraseblock_size=0x00020000 -+flash_page_size=0x00000800 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,101 @@ -+#!/bin/sh -+ -+exit_success () -+{ -+ echo "UBI Utils Test Scripts - SUCCESS!" -+ exit 0 -+} -+ -+exit_failure () -+{ -+ echo $1 -+ echo "UBI Utils Test Scripts - FAILED!" -+ exit 1 -+} -+ -+echo UBI Utils Test Scripts -+ -+devno=$1 -+logfile=temp-test-log.txt -+ -+if test -z "$devno"; -+then -+ echo "Usage is $0 " -+ exit 1 -+fi -+ -+cwd=`pwd` || exit_failure "pwd failed" -+ -+log="${cwd}/${logfile}" -+ -+PATH=$PATH:$cwd:.. -+ -+cat /dev/null > $log || exit_failure "Failed to create $log" -+ -+echo "Setting up for jffs2_test.sh" | tee -a $log -+ -+avail=`cat /sys/class/ubi/ubi${devno}/avail_eraseblocks` -+size=`cat /sys/class/ubi/ubi${devno}/eraseblock_size` -+ -+bytes=`expr $avail \* $size` -+ -+ubimkvol -d$devno -s$bytes -n0 -Njtstvol || exit_failure "ubimkvol failed" -+ -+mkdir -p /mnt/test_file_system || exit_failure "mkdir failed" -+ -+mtd=`cat /proc/mtd | grep jtstvol | cut -d: -f1` -+ -+if test -z "$mtd"; -+then -+ exit_failure "mtd device not found" -+fi -+ -+mount -t jffs2 $mtd /mnt/test_file_system || exit_failure "mount failed" -+ -+cd /mnt/test_file_system || exit_failure "cd failed" -+ -+echo Running jffs2_test.sh | tee -a $log -+ -+jffs2_test.sh >> $log 2>&1 || exit_failure "jffs2_test.sh failed" -+ -+rm -f * -+ -+cd $cwd || exit_failure "cd failed" -+ -+umount /mnt/test_file_system || exit_failure "umount failed" -+ -+ubirmvol -d$devno -n0 || exit_failure "ubirmvol failed" -+ -+major=`cat /sys/class/ubi/ubi${devno}/dev | cut -d: -f1` -+ -+for minor in `seq 0 32`; do -+ if test ! -e /dev/ubi${devno}_$minor ; -+ then -+ mknod /dev/ubi${devno}_$minor c $major $(($minor + 1)) -+ fi -+done -+ -+rm -f testdata.bin readdata.bin -+ -+echo Running ubi_jffs2_test.sh | tee -a $log -+ -+ubi_jffs2_test.sh >> $log 2>&1 || exit_failure "ubi_jffs2_test.sh failed" -+ -+echo Running ubi_test.sh | tee -a $log -+ -+ubi_test.sh >> $log 2>&1 || exit_failure "ubi_test.sh failed" -+ -+for minor in `seq 0 32`; do -+ if test -e /sys/class/ubi/ubi${devno}/$minor; -+ then -+ ubirmvol -d$devno -n$minor || exit_failure "ubirmvol failed" -+ fi -+done -+ -+echo Running ubi_tools_test.sh | tee -a $log -+ -+ubi_tools_test.sh >> $log 2>&1 || exit_failure "ubi_tools_test failed" -+ -+rm -f $log -+ -+exit_success ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,23 @@ -+[targets] -+test_complete=spl,kernel,rootfs -+ -+[spl] -+image=test_u-boot.bin -+ubi_ids=10,11 -+ubi_size=1MiB -+ubi_type=static -+ubi_names=test_spl_0,test_spl_1 -+ -+[kernel] -+image=test_vmlinux.bin -+ubi_ids=12,13 -+ubi_size=2MiB -+ubi_type=static -+ubi_names=test_kernel_0,test_kernel_1 -+ -+[rootfs] -+image=test_rootfs.bin -+ubi_ids=14,15 -+ubi_size=2MiB -+ubi_type=dynamic -+ubi_names=test_rootfs_0,test_rootfs_1 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,411 @@ -+#!/bin/sh -+# -+# UBI Volume creation/deletion/write/read and JFFS2 on top of UBI -+# testcases. -+# -+# Written in shell language to reduce dependencies to more sophisticated -+# interpreters, which may not be available on some stupid platforms. -+# -+# Author: Frank Haverkamp -+# -+# 1.0 Initial version -+# 1.1 Added fixup for delayed device node creation by udev -+# This points to a problem in the tools, mabe in the desing -+# Tue Oct 31 14:14:54 CET 2006 -+# -+ -+VERSION="1.1" -+ -+export PATH=$PATH:/bin:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/ -+ -+ITERATIONS=250 -+ALIGNMENT=2048 -+ -+UBIMKVOL="ubimkvol -a $ALIGNMENT" -+UBIRMVOL=ubirmvol -+UBIUPDATEVOL=ubiupdatevol -+ -+SIZE_512K=524288 -+SIZE_1M=1310720 -+ -+MINVOL=10 -+MAXVOL=12 -+ -+TLOG=/dev/null -+ -+# -+# To have a standardized output I define the following function to be -+# used when a test was ok or when it failed. -+# -+failed () -+{ -+ echo "FAILED" -+} -+ -+passed () -+{ -+ echo "PASSED" -+} -+ -+# -+# Print sucess message. Consider to exit with zero as return code. -+# -+exit_success () -+{ -+ echo "SUCCESS" -+ exit 0 -+} -+ -+# -+# Print failure message. Consider to exit with non zero return code. -+# -+exit_failure () -+{ -+ echo "FAILED" -+ exit 1 -+} -+ -+############################################################################### -+# -+# START -+# -+############################################################################### -+ -+fix_sysfs_issue () -+{ -+ echo "*** Fixing the sysfs issue with the /dev nodes ... " -+ -+ minor=0 -+ major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'` -+ -+ rm -rf /dev/ubi0 -+ mknod /dev/ubi0 c $major 0 -+ -+ for minor in `seq $MINVOL $MAXVOL`; do -+ echo " -> mknod /dev/ubi0_$minor c $major $(($minor + 1))" -+ rm -rf /dev/ubi0_$minor -+ mknod /dev/ubi0_$minor c $major $(($minor + 1)) -+ done -+ passed -+} -+ -+# -+# FIXME Udev needs some time until the device nodes are created. -+# This will cause trouble if after ubimkvol an update attempt -+# is started immediately, since the device node is not yet -+# available. We should either fix the tools with inotify or -+# other ideas or figure out a different way to solve the problem -+# e.g. to use ubi0 and make the volume device nodes obsolete... -+# -+udev_wait () -+{ -+ echo -n "FIXME Waiting for udev to create/delete device node " -+ grep 2\.6\.5 /proc/version > /dev/null -+ if [ $? -eq "0" ]; then -+ for i in `seq 0 5`; do -+ sleep 1; echo -n "."; -+ done -+ echo " ok" -+ fi -+} -+ -+# delete_volume - Delete a volume. If it does not exist, do not try -+# to delete it. -+# @id: volume id -+# -+delete_volume () -+{ -+ volume=$1 -+ -+ ### FIXME broken sysfs!!!! -+ if [ -e /sys/class/ubi/$volume -o \ -+ -e /sys/class/ubi/ubi0/$volume -o \ -+ -e /sys/class/ubi/ubi0_$volume ]; then -+ -+ echo "*** Truncate volume if it exists ... " -+ echo " $UBIUPDATEVOL -d0 -n$volume -t" -+ $UBIUPDATEVOL -d0 -n$volume -t -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** Delete volume if it exists ... " -+ $UBIRMVOL -d0 -n$volume -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ # udev_wait -+ fi -+} -+ -+# writevol_test - Tests volume creation and writing data to it. -+# -+# @volume: Volume number -+# @size: Size of random data to write -+# @type: Volume type static or dynamic -+# -+writevol_test () -+{ -+ volume=$1 -+ size=$2 -+ type=$3 -+ -+ echo "*** Write volume test with size $size" -+ -+### Make sure that volume exist, delete existing volume, create new -+ -+ delete_volume $volume -+ -+ echo "*** Try to create volume" -+ echo " $UBIMKVOL -d0 -n$volume -t$type -NNEW$volume -s $size ... " -+ $UBIMKVOL -d0 -n$volume -t$type -N"NEW$volume" -s $size -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ udev_wait -+ -+### Try to create same volume again -+ echo -n "*** Try to create some volume again, this must fail ... " -+ $UBIMKVOL -d0 -n$volume -t$type -N"NEW$volume" -s $size -+ if [ $? -eq "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+### Now create test data, write it, read it, compare it -+ echo -n "*** Create test data ... " -+ dd if=/dev/urandom of=testdata.bin bs=$size count=1 -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo "*** Now writing data to volume ... " -+ echo " $UBIUPDATEVOL -d0 -n$volume testdata.bin" -+ ls -l testdata.bin -+ $UBIUPDATEVOL -d0 -n$volume testdata.bin -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo "*** Download data with dd bs=1 ... " -+ dd if=/dev/ubi0_$volume of=readdata.bin bs=$size count=1 -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** Comparing data ... " -+ cmp readdata.bin testdata.bin -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** Now truncate volume ... " -+ $UBIUPDATEVOL -d0 -n$volume -t -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+} -+ -+jffs2_torture () -+{ -+ cat /dev/null > TLOG -+ -+ echo "*** Torture test ... " -+ -+ for i in `seq $iterations`; do -+ dd if=/dev/urandom of=test.bin bs=$i count=1 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " -+ exit_failure -+ fi -+ #passed -+ -+ dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ echo "dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG" -+ exit_failure -+ fi -+ #passed -+ -+ #echo "Comparing files ... " -+ cmp test.bin new.bin -+ dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ #passed -+ #echo -n "." -+ done -+ -+ echo -n "step0:ok " -+ -+ for i in `seq $iterations`; do -+ dd if=/dev/urandom of=foo bs=$i count=1 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " -+ exit_failure -+ fi -+ #passed -+ done -+ -+ echo -n "step1:ok " -+ -+ for i in `seq $iterations`; do -+ dd if=/dev/zero of=foo bs=1 count=$i 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ echo "Testing $i byte (dd if=/dev/zero of=foo bs=1 count=$i) ... " -+ exit_failure -+ fi -+ #passed -+ done -+ -+ echo -n "step2:ok " -+ -+ for i in `seq $iterations`; do -+ dd if=/dev/zero of=foo bs=$i count=16 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ echo "Testing $i byte (dd if=/dev/zero of=foo bs=$i count=1024) ... " -+ exit_failure -+ fi -+ #passed -+ done -+ -+ echo -n "step3:ok " -+ -+ passed -+} -+ -+# writevol_test - Tests volume creation and writing data to it. -+# -+# @volume: Volume number -+# @size: Size of random data to write -+# @type: Volume type static or dynamic -+# -+jffs2_test () -+{ -+ name=$1 -+ iterations=$2 -+ directory=`pwd` -+ -+ ### Setup -+ ulimit -c unlimited -+ -+ echo -n "*** Create directory /mnt/$name ... " -+ mkdir -p /mnt/$name -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** mount -t jffs2 mtd:$name /mnt/$name ... " -+ mount -t jffs2 mtd:$name /mnt/$name -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** change directory ... " -+ cd /mnt/$name -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ ls -+ echo "*** list directory ... " -+ ls -la -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ ### Torture -+ echo -n "*** touch I_WAS_HERE ... " -+ touch I_WAS_HERE -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ jffs2_torture -+ -+ echo "*** list directory ... " -+ ls -la -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ ### Cleanup -+ echo -n "*** go back ... " -+ cd $directory -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ ### Still mounted, ubiupdatevol must fail! -+ -+ echo -n "*** $UBIUPDATEVOL -d0 -n$volume -t must fail! ..." -+ $UBIUPDATEVOL -d0 -n$volume -t -+ if [ $? -eq "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** umount /mnt/$name ... " -+ umount /mnt/$name -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ return -+} -+ -+echo "***********************************************************************" -+echo "* UBI JFFS2 Testing starts now ... *" -+echo "* Good luck! *" -+echo "***********************************************************************" -+echo "VERSION: $VERSION" -+ -+# Set to zero if not running on example hardware -+grep ubi /proc/devices > /dev/null -+if [ $? -ne "0" ]; then -+ echo "No UBI found in /proc/devices! I am broken!" -+ exit_failure -+fi -+ -+# Set to zero if not running on example hardware -+grep 1142 /proc/cpuinfo > /dev/null -+if [ $? -eq "0" ]; then -+ echo "Running on example hardware" -+ mount -o remount,rw / / -+ sleep 1 -+ fix_sysfs_issue -+else -+ echo "Running on Artems hardware" -+fi -+ -+for volume in `seq $MINVOL $MAXVOL`; do -+ echo -n "************ VOLUME $volume NEW$volume " -+ echo "******************************************" -+ writevol_test $volume $SIZE_1M dynamic -+ jffs2_test NEW$volume $ITERATIONS -+ delete_volume $volume -+done -+ -+echo "***********************************************************************" -+echo "* Congratulations, no errors found! *" -+echo "* Have fun with your cool UBI system! *" -+echo "***********************************************************************" -+ -+exit_success ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,328 @@ -+#!/bin/sh -+# -+# UBI Volume creation/deletion/write/read test script -+# -+# Written in shell language to reduce dependencies to more sophisticated -+# interpreters, which may not be available on some stupid platforms. -+# -+# Author: Frank Haverkamp -+# -+# 1.0 Initial version -+# 1.1 Use ubiupdatevol instead of ubiwritevol -+# -+ -+VERSION="1.1" -+ -+export PATH=$PATH:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/ -+ -+UBIMKVOL=ubimkvol -+UBIRMVOL=ubirmvol -+UBIUPDATEVOL=ubiupdatevol -+ -+# 128 KiB 131072 -+# 256 KiB 262144 -+# 512 KiB 524288 -+ -+SIZE_512K=524288 -+SIZE_1M=1310720 -+ -+SELF=$0 -+MINVOL=10 -+MAXVOL=12 -+ -+# -+# To have a standardized output I define the following function to be -+# used when a test was ok or when it failed. -+# -+failed () -+{ -+ echo "FAILED" -+} -+ -+passed () -+{ -+ echo "PASSED" -+} -+ -+# -+# Print sucess message. Consider to exit with zero as return code. -+# -+exit_success () -+{ -+ echo "SUCCESS" -+ exit 0 -+} -+ -+# -+# Print failure message. Consider to exit with non zero return code. -+# -+exit_failure () -+{ -+ echo "FAILED" -+ exit 1 -+} -+ -+############################################################################### -+# -+# START -+# -+############################################################################### -+ -+fix_sysfs_issue () -+{ -+ echo -n "*** Fixing the sysfs issue with the /dev nodes ... " -+ -+ minor=0 -+ major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'` -+ -+ rm -rf /dev/ubi0 -+ mknod /dev/ubi0 c $major 0 -+ -+ for minor in `seq 0 $MAXVOL`; do -+ ### echo " mknod /dev/ubi0_$minor c $major $(($minor + 1))" -+ rm -rf /dev/ubi0_$minor -+ mknod /dev/ubi0_$minor c $major $(($minor + 1)) -+ done -+ passed -+} -+ -+# delete_volume - Delete a volume. If it does not exist, do not try -+# to delete it. -+# @id: volume id -+# -+delete_volume () -+{ -+ volume=$1 -+ -+ ### FIXME broken sysfs!!!! -+ if [ -e /sys/class/ubi/$volume -o -e /sys/class/ubi/ubi0/$volume -o -e /sys/class/ubi/ubi0_$volume ]; then -+ -+ echo -n "*** Truncate volume if it exists ... " -+ $UBIUPDATEVOL -d0 -n$volume -t -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** Delete volume if it exists ... " -+ $UBIRMVOL -d0 -n$volume -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ fi -+} -+ -+mkvol_rmvol_test () -+{ -+ type=$1 -+ -+### Test if volume delete on non-existing volumes fails nicely -+ -+ for i in `seq $MINVOL $MAXVOL`; do -+ echo "*** Delete if exist or not $i ... " -+ -+ delete_volume $i -+ passed -+ done -+ -+### Now deleting volumes must fail -+ -+ for i in `seq $MINVOL $MAXVOL`; do -+ echo "*** Trying to delete non existing UBI Volume $i ... " -+ -+ $UBIRMVOL -d0 -n$i -+ if [ $? -eq "0" ] ; then -+ exit_failure -+ fi -+ passed -+ done -+ -+### Test if volume creation works ok -+ -+ for i in `seq $MINVOL $MAXVOL`; do -+ echo "*** Creating UBI Volume $i ... " -+ echo " $UBIMKVOL -d0 -n$i -t$type -NNEW$i -s $SIZE_512K" -+ -+ $UBIMKVOL -d0 -n$i -t$type -N"NEW$i" -s $SIZE_512K -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ done -+ -+### Now deleting volumes must be ok -+ -+ for i in `seq $MINVOL $MAXVOL`; do -+ echo "*** Trying to delete UBI Volume $i ... " -+ -+ $UBIRMVOL -d0 -n$i -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ done -+ -+### Now allocate too large volume -+ -+ echo -n "*** Try to create too large volume" -+ $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s 800000000 -+ if [ $? -eq "0" ] ; then -+ exit_failure -+ fi -+ passed -+} -+ -+# writevol_test - Tests volume creation and writing data to it. -+# -+# @size: Size of random data to write -+# @type: Volume type static or dynamic -+# -+writevol_test () -+{ -+ size=$1 -+ type=$2 -+ -+ echo "*** Write volume test with size $size" -+ -+### Make sure that volume exist, delete existing volume, create new -+ -+ delete_volume $MINVOL -+ -+ echo -n "*** Try to create volume ... " -+ $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s $SIZE_1M -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+### Try to create same volume again -+ echo -n "*** Try to create some volume again, this must fail ... " -+ $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s $SIZE_1M -+ if [ $? -eq "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+### Now create test data, write it, read it, compare it -+ echo -n "*** Create test data ... " -+ dd if=/dev/urandom of=testdata.bin bs=$size count=1 -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo "*** Now writing data to volume ... " -+ # sleep 5 -+ ls -l testdata.bin -+ echo " $UBIUPDATEVOL -d0 -n$MINVOL testdata.bin" -+ $UBIUPDATEVOL -d0 -n$MINVOL testdata.bin -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ if [ $type = "static" ] ; then -+ echo "*** Download data with cat ... " -+ cat /dev/ubi0_$MINVOL > readdata.bin -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ else -+ echo "*** Download data with dd bs=1 ... " -+ dd if=/dev/ubi0_$MINVOL of=readdata.bin bs=$size count=1 -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ # Size 1 does not work with this test ... -+ # -+ #echo "*** Download data with dd bs=$size ... " -+ #dd if=/dev/ubi0_$MINVOL of=readdata2.bin bs=$size count=1 -+ #if [ $? -ne "0" ] ; then -+ # exit_failure -+ #fi -+ #passed -+ -+ #echo -n "*** Comparing data (1) ... " -+ #cmp readdata.bin readdata2.bin -+ #if [ $? -ne "0" ] ; then -+ # exit_failure -+ #fi -+ #passed -+ fi -+ -+ echo -n "*** Comparing data ... " -+ cmp readdata.bin testdata.bin -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+} -+ -+echo "***********************************************************************" -+echo "* UBI Testing starts now ... *" -+echo "* Good luck! *" -+echo "***********************************************************************" -+ -+# Set to zero if not running on example hardware -+grep ubi /proc/devices > /dev/null -+if [ $? -ne "0" ]; then -+ echo "No UBI found in /proc/devices! I am broken!" -+ exit_failure -+fi -+ -+# Set to zero if not running on example hardware -+grep 1142 /proc/cpuinfo > /dev/null -+if [ $? -eq "0" ]; then -+ echo "Running on example hardware" -+ mount -o remount,rw / / -+ sleep 1 -+ fix_sysfs_issue -+else -+ echo "Running on Artems hardware" -+fi -+ -+echo "***********************************************************************" -+echo "* mkvol/rmvol testing for static volumes ... *" -+echo "***********************************************************************" -+ -+mkvol_rmvol_test static -+ -+echo "***********************************************************************" -+echo "* mkvol/rmvol testing for dynamic volumes ... *" -+echo "***********************************************************************" -+ -+mkvol_rmvol_test dynamic -+ -+echo "***********************************************************************" -+echo "* write to static volumes ... *" -+echo "***********************************************************************" -+ -+# 10 Erase blocks = (128 KiB - 64 * 2) * 10 -+# = 1309440 bytes -+# 128 KiB 131072 -+# 256 KiB 262144 -+# 512 KiB 524288 -+ -+for size in 262144 131073 131072 2048 1 4096 12800 31313 ; do -+ writevol_test $size static -+done -+ -+echo "***********************************************************************" -+echo "* write to dynamic volumes ... *" -+echo "***********************************************************************" -+echo "VERSION: $VERSION" -+ -+for size in 131073 131072 2048 1 4096 12800 31313 262144 ; do -+ writevol_test $size dynamic -+done -+ -+echo "***********************************************************************" -+echo "* Congratulations, no errors found! *" -+echo "* Have fun with your cool UBI system! *" -+echo "***********************************************************************" -+ -+exit_success ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,252 @@ -+#!/bin/sh -+# -+# UBI Volume creation/deletion/write/read test script. -+# Uses our flash update tools and the associated toolchain for flash -+# image creation. -+# -+# Written in shell language to reduce dependencies to more sophisticated -+# interpreters, which may not be available on some stupid platforms. -+# -+# Author: Frank Haverkamp -+# -+# 1.0 Initial version -+# -+ -+VERSION="1.0" -+ -+export PATH=$PATH:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/ -+ -+UBIMKVOL=ubimkvol -+UBIRMVOL=ubirmvol -+UBIWRITEVOL=ubiupdatevol -+PFIFLASH=pfiflash -+CMP=cmp -+ -+MAXVOL=32 -+ -+test_pfi=test_complete.pfi -+real_pfi=example_complete.pfi -+ -+# 128 KiB 131072 -+# 256 KiB 262144 -+# 512 KiB 524288 -+ -+# -+# To have a standardized output I define the following function to be -+# used when a test was ok or when it failed. -+# -+failed () -+{ -+ echo "FAILED" -+} -+ -+passed () -+{ -+ echo "PASSED" -+} -+ -+# -+# Print sucess message. Consider to exit with zero as return code. -+# -+exit_success () -+{ -+ echo "SUCCESS" -+ exit 0 -+} -+ -+# -+# Print failure message. Consider to exit with non zero return code. -+# -+exit_failure () -+{ -+ echo "FAILED" -+ exit 1 -+} -+ -+############################################################################### -+# -+# START -+# -+############################################################################### -+ -+fix_sysfs_issue () -+{ -+ echo -n "*** Fixing the sysfs issue with the /dev nodes ... " -+ -+ minor=0 -+ major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'` -+ -+ rm -rf /dev/ubi0 -+ mknod /dev/ubi0 c $major 0 -+ -+ for minor in `seq 0 $MAXVOL`; do -+ ### echo " mknod /dev/ubi0_$minor c $major $(($minor + 1))" -+ rm -rf /dev/ubi0_$minor -+ mknod /dev/ubi0_$minor c $major $(($minor + 1)) -+ done -+ passed -+} -+ -+# delete_volume - Delete a volume. If it does not exist, do not try -+# to delete it. -+# @id: volume id -+# -+delete_volume () -+{ -+ volume=$1 -+ -+ ### FIXME broken sysfs!!!! -+ if [ -e /sys/class/ubi/$volume -o -e /sys/class/ubi/ubi0/$volume -o -e /sys/class/ubi/ubi0_$volume ]; then -+ -+ echo -n "*** Truncate volume if it exists ... " -+ $UBIWRITEVOL -d0 -n$volume -t -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** Delete volume if it exists ... " -+ $UBIRMVOL -d0 -n$volume -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ fi -+} -+ -+echo "***********************************************************************" -+echo "* UBI Tools Testing starts now ... *" -+echo "* Good luck! *" -+echo "***********************************************************************" -+ -+# Set to zero if not running on example hardware -+grep ubi /proc/devices > /dev/null -+if [ $? -ne "0" ]; then -+ echo "No UBI found in /proc/devices! I am broken!" -+ exit_failure -+fi -+ -+# Set to zero if not running on example hardware -+grep 1142 /proc/cpuinfo > /dev/null -+if [ $? -eq "0" ]; then -+ echo "Running on example hardware" -+ mount -o remount,rw / / -+ sleep 1 -+ fix_sysfs_issue -+else -+ echo "Running on other hardware" -+fi -+ -+### Test basic stuff -+pfiflash_basic () -+{ -+ echo "Calling pfiflash with test-data ... " -+ echo " $PFIFLASH $test_pfi" -+ $PFIFLASH $test_pfi -+ if [ $? -ne "0" ]; then -+ echo "Uhhh something went wrong!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Testing if data is correct 10 and 11 ... " -+ $CMP /dev/ubi0_10 /dev/ubi0_11 -+ if [ $? -ne "0" ]; then -+ echo "Mirrored volumes not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Comparing against original data ... " -+ $CMP /dev/ubi0_10 test_u-boot.bin -+ if [ $? -ne "0" ]; then -+ echo "Compared volume not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Testing if data is correct 12 and 13 ... " -+ $CMP /dev/ubi0_12 /dev/ubi0_13 -+ if [ $? -ne "0" ]; then -+ echo "Mirrored volumes not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Comparing against original data ... " -+ $CMP /dev/ubi0_12 test_vmlinux.bin -+ if [ $? -ne "0" ]; then -+ echo "Compared volume not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Testing if data is correct 14 and 15 ... " -+ $CMP /dev/ubi0_14 /dev/ubi0_15 -+ if [ $? -ne "0" ]; then -+ echo "Mirrored volumes not equal!" -+ exit_failure -+ fi -+ passed -+} -+ -+### Test each and everything -+pfiflash_advanced () -+{ -+ if [ -e example_complete.pfi ]; then -+ echo "Calling pfiflash with real data ... " -+ $PFIFLASH -p overwrite --complete example_complete.pfi -+ if [ $? -ne "0" ]; then -+ echo "Uhhh something went wrong!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Testing if data is correct 2 and 3 ... " -+ $CMP /dev/ubi0_2 /dev/ubi0_3 -+ if [ $? -ne "0" ]; then -+ echo "Mirrored volumes not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Comparing against original data ... " -+ $CMP /dev/ubi0_2 u-boot.bin -+ if [ $? -ne "0" ]; then -+ echo "Compared volume not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Testing if data is correct 6 and 7 ... " -+ $CMP /dev/ubi0_6 /dev/ubi0_7 -+ if [ $? -ne "0" ]; then -+ echo "Mirrored volumes not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Comparing against original data ... " -+ $CMP /dev/ubi0_6 vmlinux.bin -+ if [ $? -ne "0" ]; then -+ echo "Compared volume not equal!" -+ exit_failure -+ fi -+ passed -+ fi -+} -+ -+echo "***********************************************************************" -+echo "* Testing pfiflash ... *" -+echo "***********************************************************************" -+echo "VERSION: $VERSION" -+ -+pfiflash_basic -+pfiflash_advanced -+ -+echo "***********************************************************************" -+echo "* Congratulations, no errors found! *" -+echo "* Have fun with your cool UBI system! *" -+echo "***********************************************************************" -+ -+exit_success ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,105 @@ -+#!/bin/sh -+# -+# Use raw NAND data, extract UBI image and apply tool to it. -+# Test basic functionality. -+# -+# 2007 Frank Haverkamp -+# -+ -+version=1.1 -+ -+image=data.mif -+oob=oob.bin -+data=data.bin -+pagesize=2048 -+volmax=31 -+datadir=unubi_data -+ -+# general arguments e.g. debug enablement -+# unubi_args="-D" -+ -+echo "------------------------------------------------------------------------" -+echo "Testcase: ${0} Version: ${version}" -+echo "------------------------------------------------------------------------" -+echo "Testing nand2bin ..." -+echo " Input: ${image}" -+echo " Data: ${data}" -+echo " OOB: ${oob}" -+echo " Pagesize: ${pagesize}" -+nand2bin --pagesize ${pagesize} -o ${data} -O ${oob} ${image} -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Testing unubi ..." -+echo "------------------------------------------------------------------------" -+unubi --version -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Trying to extract first ${volmax} volumes ..." -+echo "------------------------------------------------------------------------" -+mkdir -p ${datadir}/volumes -+for v in `seq 0 ${volmax}` ; do -+ unubi ${unubi_args} -r${v} -d${datadir}/volumes ${data} -+ echo -n "." -+done -+echo "ok" -+ls -l ${datadir}/volumes -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Extracting graphics ..." -+echo "------------------------------------------------------------------------" -+unubi -a -d${datadir} ${data} -+echo "Use gnuplot to display:" -+ls ${datadir}/*.plot -+ls ${datadir}/*.data -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "eb-split" -+echo "------------------------------------------------------------------------" -+unubi -e -d${datadir}/eb-split ${data} -+ls -l ${datadir}/eb-split -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "vol-split" -+echo "------------------------------------------------------------------------" -+unubi -v -d${datadir}/vol-split ${data} -+ls -l ${datadir}/vol-split -+echo -+echo "The generated images contain only the data (126KiB in our " -+echo "case) not including the UBI erase count and volume info " -+echo "header. For dynamic volumes the data should be the full " -+echo "126KiB. Unubi cannot know how much of the data is valid. " -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "!vol-split" -+echo "------------------------------------------------------------------------" -+unubi -V -d${datadir}/vol-split! ${data} -+ls -l ${datadir}/vol-split\! -+echo -+echo "The generated images contain the full block data of 128KiB " -+echo "including the UBI erase count and volume information header." -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Extracting volume info table ..." -+echo "------------------------------------------------------------------------" -+unubi -i -d${datadir} ${data} -+echo "I strongly hope that empty ubi blocks are filled with 0xff! " -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Table 0" -+echo "------------------------------------------------------------------------" -+cat ${datadir}/vol_info_table0 -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Table 1" -+echo "------------------------------------------------------------------------" -+cat ${datadir}/vol_info_table1 -+echo ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,344 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+/* -+ * Create a flashable NAND image from a binary image -+ * -+ * History: -+ * 1.0 Initial release (tglx) -+ * 1.1 Understands hex and dec input parameters (tglx) -+ * 1.2 Generates separated OOB data, if needed. (oloh) -+ * 1.3 Padds data/oob to a given size. (oloh) -+ * 1.4 Removed argp because we want to use uClibc. -+ * 1.5 Minor cleanup -+ * 1.6 written variable not initialized (-j did not work) (haver) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "error.h" -+#include "config.h" -+#include "nandecc.h" -+ -+#define PROGRAM_VERSION "1.6" -+ -+#define CHECK_ENDP(option, endp) do { \ -+ if (*endp) { \ -+ fprintf(stderr, \ -+ "Parse error option \'%s\'. " \ -+ "No correct numeric value.\n" \ -+ , option); \ -+ exit(EXIT_FAILURE); \ -+ } \ -+} while(0) -+ -+typedef enum action_t { -+ ACT_NORMAL = 0x00000001, -+} action_t; -+ -+#define PAGESIZE 2048 -+#define PADDING 0 /* 0 means, do not adjust anything */ -+#define BUFSIZE 4096 -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "bin2nand - a tool for adding OOB information to a " -+ "binary input file.\n"; -+ -+static const char *optionsstr = -+" -c, --copyright Print copyright informatoin.\n" -+" -j, --padding= Padding in Byte/Mi/ki. Default = no padding\n" -+" -p, --pagesize= Pagesize in Byte/Mi/ki. Default = 2048\n" -+" -o, --output= Output filename. Interleaved Data/OOB if\n" -+" output-oob not specified.\n" -+" -q, --output-oob= Write OOB data in separate file.\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: bin2nand [-c?V] [-j ] [-p ] [-o ] [-q ]\n" -+" [--copyright] [--padding=] [--pagesize=]\n" -+" [--output=] [--output-oob=] [--help] [--usage]\n" -+" [--version]\n"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "padding", .has_arg = 1, .flag = NULL, .val = 'j' }, -+ { .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' }, -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "output-oob", .has_arg = 1, .flag = NULL, .val = 'q' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright IBM Corp. 2006"; -+ -+typedef struct myargs { -+ action_t action; -+ -+ size_t pagesize; -+ size_t padding; -+ -+ FILE* fp_in; -+ char *file_out_data; /* Either: Data and OOB interleaved -+ or plain data */ -+ char *file_out_oob; /* OOB Data only. */ -+ -+ /* special stuff needed to get additional arguments */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+ -+static int ustrtoull(const char *cp, char **endp, unsigned int base) -+{ -+ unsigned long long res = strtoull(cp, endp, base); -+ -+ switch (**endp) { -+ case 'G': -+ res *= 1024; -+ case 'M': -+ res *= 1024; -+ case 'k': -+ case 'K': -+ res *= 1024; -+ /* "Ki", "ki", "Mi" or "Gi" are to be used. */ -+ if ((*endp)[1] == 'i') -+ (*endp) += 2; -+ } -+ return res; -+} -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ char* endp; -+ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "cj:p:o:q:?V", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'p': /* pagesize */ -+ args->pagesize = (size_t) -+ ustrtoull(optarg, &endp, 0); -+ CHECK_ENDP("p", endp); -+ break; -+ case 'j': /* padding */ -+ args->padding = (size_t) -+ ustrtoull(optarg, &endp, 0); -+ CHECK_ENDP("j", endp); -+ break; -+ case 'o': /* output */ -+ args->file_out_data = optarg; -+ break; -+ case 'q': /* output oob */ -+ args->file_out_oob = optarg; -+ break; -+ case '?': /* help */ -+ printf("%s", doc); -+ printf("%s", optionsstr); -+ exit(0); -+ break; -+ case 'V': -+ printf("%s\n", PROGRAM_VERSION); -+ exit(0); -+ break; -+ case 'c': -+ printf("%s\n", copyright); -+ exit(0); -+ default: -+ printf("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) { -+ args->fp_in = fopen(argv[optind++], "rb"); -+ if ((args->fp_in) == NULL) { -+ err_quit("Cannot open file %s for input\n", -+ argv[optind++]); -+ } -+ } -+ -+ return 0; -+} -+ -+static int -+process_page(uint8_t* buf, size_t pagesize, -+ FILE *fp_data, FILE* fp_oob, size_t* written) -+{ -+ int eccpoi, oobsize; -+ size_t i; -+ uint8_t oobbuf[64]; -+ -+ memset(oobbuf, 0xff, sizeof(oobbuf)); -+ -+ switch(pagesize) { -+ case 2048: oobsize = 64; eccpoi = 64 / 2; break; -+ case 512: oobsize = 16; eccpoi = 16 / 2; break; -+ default: -+ err_msg("Unsupported page size: %d\n", pagesize); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < pagesize; i += 256, eccpoi += 3) { -+ oobbuf[eccpoi++] = 0x0; -+ /* Calculate ECC */ -+ nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]); -+ } -+ -+ /* write data */ -+ *written += fwrite(buf, 1, pagesize, fp_data); -+ -+ /* either separate oob or interleave with data */ -+ if (fp_oob) { -+ i = fwrite(oobbuf, 1, oobsize, fp_oob); -+ if (ferror(fp_oob)) { -+ err_msg("IO error\n"); -+ return -EIO; -+ } -+ } -+ else { -+ i = fwrite(oobbuf, 1, oobsize, fp_data); -+ if (ferror(fp_data)) { -+ err_msg("IO error\n"); -+ return -EIO; -+ } -+ } -+ -+ return 0; -+} -+ -+int main (int argc, char** argv) -+{ -+ int rc = -1; -+ int res = 0; -+ size_t written = 0, read; -+ myargs args = { -+ .action = ACT_NORMAL, -+ .pagesize = PAGESIZE, -+ .padding = PADDING, -+ .fp_in = NULL, -+ .file_out_data = NULL, -+ .file_out_oob = NULL, -+ }; -+ -+ FILE* fp_out_data = stdout; -+ FILE* fp_out_oob = NULL; -+ -+ parse_opt(argc, argv, &args); -+ -+ uint8_t* buf = calloc(1, BUFSIZE); -+ if (!buf) { -+ err_quit("Cannot allocate page buffer.\n"); -+ } -+ -+ if (!args.fp_in) { -+ err_msg("No input image specified!\n"); -+ goto err; -+ } -+ -+ if (args.file_out_data) { -+ fp_out_data = fopen(args.file_out_data, "wb"); -+ if (fp_out_data == NULL) { -+ err_sys("Cannot open file %s for output\n", -+ args.file_out_data); -+ goto err; -+ } -+ } -+ -+ if (args.file_out_oob) { -+ fp_out_oob = fopen(args.file_out_oob, "wb"); -+ if (fp_out_oob == NULL) { -+ err_sys("Cannot open file %s for output\n", -+ args.file_out_oob); -+ goto err; -+ } -+ } -+ -+ -+ while(1) { -+ read = fread(buf, 1, args.pagesize, args.fp_in); -+ if (feof(args.fp_in) && read == 0) -+ break; -+ -+ if (read < args.pagesize) { -+ err_msg("Image not page aligned\n"); -+ goto err; -+ } -+ -+ if (ferror(args.fp_in)) { -+ err_msg("Read error\n"); -+ goto err; -+ } -+ -+ res = process_page(buf, args.pagesize, fp_out_data, -+ fp_out_oob, &written); -+ if (res != 0) -+ goto err; -+ } -+ -+ while (written < args.padding) { -+ memset(buf, 0xff, args.pagesize); -+ res = process_page(buf, args.pagesize, fp_out_data, -+ fp_out_oob, &written); -+ if (res != 0) -+ goto err; -+ } -+ -+ rc = 0; -+err: -+ free(buf); -+ -+ if (args.fp_in) -+ fclose(args.fp_in); -+ -+ if (fp_out_oob) -+ fclose(fp_out_oob); -+ -+ if (fp_out_data && fp_out_data != stdout) -+ fclose(fp_out_data); -+ -+ if (rc != 0) { -+ err_msg("Error during conversion. rc: %d\n", rc); -+ if (args.file_out_data) -+ remove(args.file_out_data); -+ if (args.file_out_oob) -+ remove(args.file_out_oob); -+ } -+ return rc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1032 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2008 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "hashmap.h" -+#include "error.h" -+ -+#include -+#include "crc32.h" -+ -+#define ubi_unused __attribute__((unused)) -+ -+#define BOOTENV_MAXLINE 512 /* max line size of a bootenv.txt file */ -+ -+/* Structures */ -+struct bootenv { -+ hashmap_t map; ///< Pointer to hashmap which holds data structure. -+}; -+ -+struct bootenv_list { -+ hashmap_t head; ///< Pointer to list which holds the data structure. -+}; -+ -+/** -+ * @brief Remove the '\n' from a given line. -+ * @param line Input/Output line. -+ * @param size Size of the line. -+ * @param fp File Pointer. -+ * @return 0 -+ * @return or error -+ */ -+static int -+remove_lf(char *line, size_t size, FILE* fp) -+{ -+ size_t i; -+ -+ for (i = 0; i < size; i++) { -+ if (line[i] == '\n') { -+ line[i] = '\0'; -+ return 0; -+ } -+ } -+ -+ if (!feof(fp)) { -+ return BOOTENV_EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * @brief Determine if a line contains only WS. -+ * @param line The line to process. -+ * @param size Size of input line. -+ * @return 1 Yes, only WS. -+ * @return 0 No, contains data. -+ */ -+static int -+is_ws(const char *line, size_t size) -+{ -+ size_t i = 0; -+ -+ while (i < size) { -+ switch (line[i]) { -+ case '\n': -+ return 1; -+ case '#': -+ return 1; -+ case ' ': -+ i++; -+ continue; -+ case '\t': -+ i++; -+ continue; -+ default: /* any other char -> no cmnt */ -+ return 0; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+/* ------------------------------------------------------------------------- */ -+ -+/** -+ * @brief Build a list from a comma seperated value string. -+ * @param list Pointer to hashmap structure which shall store -+ * the list. -+ * @param value Comma seperated value string. -+ * @return 0 -+ * @return or error. -+ */ -+static int -+build_list_definition(hashmap_t list, const char *value) -+{ -+ int rc = 0; -+ char *str = NULL; -+ char *ptr = NULL; -+ size_t len, i, j; -+ -+ /* str: val1,val2 , val4,...,valN */ -+ len = strlen(value); -+ str = (char*) malloc((len+1) * sizeof(char)); -+ -+ /* 1. reformat string: remove spaces */ -+ for (i = 0, j = 0; i < len; i++) { -+ if (value[i] == ' ') -+ continue; -+ -+ str[j] = value[i]; -+ j++; -+ } -+ str[j] = '\0'; -+ -+ /* str: val1,val2,val4,...,valN\0*/ -+ /* 2. replace ',' seperator with '\0' */ -+ len = strlen(str); -+ for (i = 0; i < len; i++) { -+ if (str[i] == ',') { -+ str[i] = '\0'; -+ } -+ } -+ -+ /* str: val1\0val2\0val4\0...\0valN\0*/ -+ /* 3. insert definitions into a hash map, using it like a list */ -+ i = j = 0; -+ ptr = str; -+ while (((i = strlen(ptr)) > 0) && (j < len)) { -+ rc = hashmap_add(list, ptr, ""); -+ if (rc != 0) { -+ free(str); -+ return rc; -+ } -+ j += i+1; -+ if (j < len) -+ ptr += i+1; -+ } -+ -+ free(str); -+ return rc; -+} -+ -+/** -+ * @brief Extract a key value pair and add it to a hashmap -+ * @param str Input string which contains a key value pair. -+ * @param env The updated handle which contains the new pair. -+ * @return 0 -+ * @return or error -+ * @note The input string format is: "key=value" -+ */ -+static int -+extract_pair(const char *str, bootenv_t env) -+{ -+ int rc = 0; -+ char *key = NULL; -+ char *val = NULL; -+ -+ key = strdup(str); -+ if (key == NULL) -+ return -ENOMEM; -+ -+ val = strstr(key, "="); -+ if (val == NULL) { -+ rc = BOOTENV_EBADENTRY; -+ goto err; -+ } -+ -+ *val = '\0'; /* split strings */ -+ val++; -+ -+ rc = bootenv_set(env, key, val); -+ -+ err: -+ free(key); -+ return rc; -+} -+ -+int -+bootenv_destroy(bootenv_t* env) -+{ -+ int rc = 0; -+ -+ if (env == NULL || *env == NULL) -+ return -EINVAL; -+ -+ bootenv_t tmp = *env; -+ -+ rc = hashmap_free(tmp->map); -+ if (rc != 0) -+ return rc; -+ -+ free(tmp); -+ return rc; -+} -+ -+int -+bootenv_create(bootenv_t* env) -+{ -+ bootenv_t res; -+ res = (bootenv_t) calloc(1, sizeof(struct bootenv)); -+ -+ if (res == NULL) -+ return -ENOMEM; -+ -+ res->map = hashmap_new(); -+ -+ if (res->map == NULL) { -+ free(res); -+ return -ENOMEM; -+ } -+ -+ *env = res; -+ -+ return 0; -+} -+ -+ -+/** -+ * @brief Read a formatted buffer and scan it for valid bootenv -+ * key/value pairs. Add those pairs into a hashmap. -+ * @param env Hashmap which shall be used to hold the data. -+ * @param buf Formatted buffer. -+ * @param size Size of the buffer. -+ * @return 0 -+ * @return or error -+ */ -+static int -+rd_buffer(bootenv_t env, const char *buf, size_t size) -+{ -+ const char *curr = buf; /* ptr to current key/value pair */ -+ uint32_t i, j; /* current length, chars processed */ -+ -+ if (buf[size - 1] != '\0') /* must end in '\0' */ -+ return BOOTENV_EFMT; -+ -+ for (j = 0; j < size; j += i, curr += i) { -+ /* strlen returns the size of the string upto -+ but not including the null terminator; -+ adding 1 to account for '\0' */ -+ i = strlen(curr) + 1; -+ -+ if (i == 1) -+ return 0; /* no string found */ -+ -+ if (extract_pair(curr, env) != 0) -+ return BOOTENV_EINVAL; -+ } -+ -+ return 0; -+} -+ -+ -+int -+bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t* ret_crc) -+{ -+ int rc; -+ char *buf = NULL; -+ size_t i = 0; -+ uint32_t crc32_table[256]; -+ -+ if ((fp == NULL) || (env == NULL)) -+ return -EINVAL; -+ -+ /* allocate temp buffer */ -+ buf = (char*) calloc(1, size * sizeof(char)); -+ if (buf == NULL) -+ return -ENOMEM; -+ -+ /* FIXME Andreas, please review this I removed size-1 and -+ * replaced it by just size, I saw the kernel image starting -+ * with a 0x0060.... and not with the 0x60.... what it should -+ * be. Is this a tools problem or is it a problem here where -+ * fp is moved not to the right place due to the former size-1 -+ * here. -+ */ -+ while((i < size) && (!feof(fp))) { -+ int c = fgetc(fp); -+ if (c == EOF) { -+ /* FIXME isn't this dangerous, to update -+ the boot envs with incomplete data? */ -+ buf[i++] = '\0'; -+ break; /* we have enough */ -+ } -+ if (ferror(fp)) { -+ rc = -EIO; -+ goto err; -+ } -+ -+ buf[i++] = (char)c; -+ } -+ -+ /* calculate crc to return */ -+ if (ret_crc != NULL) { -+ init_crc32_table(crc32_table); -+ *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size); -+ } -+ -+ /* transfer to hashmap */ -+ rc = rd_buffer(env, buf, size); -+ -+err: -+ free(buf); -+ return rc; -+} -+ -+ -+/** -+ * If we have a single file containing the boot-parameter size should -+ * be specified either as the size of the file or as BOOTENV_MAXSIZE. -+ * If the bootparameter are in the middle of a file we need the exact -+ * length of the data. -+ */ -+int -+bootenv_read(FILE* fp, bootenv_t env, size_t size) -+{ -+ return bootenv_read_crc(fp, env, size, NULL); -+} -+ -+ -+int -+bootenv_read_txt(FILE* fp, bootenv_t env) -+{ -+ int rc = 0; -+ char *buf = NULL; -+ char *line = NULL; -+ char *lstart = NULL; -+ char *curr = NULL; -+ size_t len; -+ size_t size; -+ -+ if ((fp == NULL) || (env == NULL)) -+ return -EINVAL; -+ -+ size = BOOTENV_MAXSIZE; -+ -+ /* allocate temp buffers */ -+ buf = (char*) calloc(1, size * sizeof(char)); -+ lstart = line = (char*) calloc(1, size * sizeof(char)); -+ if ((buf == NULL) || (line == NULL)) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ -+ curr = buf; -+ while ((line = fgets(line, size, fp)) != NULL) { -+ if (is_ws(line, size)) { -+ continue; -+ } -+ rc = remove_lf(line, BOOTENV_MAXSIZE, fp); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ /* copy new line to binary buffer */ -+ len = strlen(line); -+ if (len > size) { -+ rc = -EFBIG; -+ goto err; -+ } -+ size -= len; /* track remaining space */ -+ -+ memcpy(curr, line, len); -+ curr += len + 1; /* for \0 seperator */ -+ } -+ -+ rc = rd_buffer(env, buf, BOOTENV_MAXSIZE); -+err: -+ if (buf != NULL) -+ free(buf); -+ if (lstart != NULL) -+ free(lstart); -+ return rc; -+} -+ -+static int -+fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max ubi_unused, -+ size_t *written) -+{ -+ int rc = 0; -+ size_t keys_size, i; -+ size_t wr = 0; -+ const char **keys = NULL; -+ const char *val = NULL; -+ -+ rc = bootenv_get_key_vector(env, &keys_size, 1, &keys); -+ if (rc != 0) -+ goto err; -+ -+ for (i = 0; i < keys_size; i++) { -+ if (wr > BOOTENV_MAXSIZE) { -+ rc = -ENOSPC; -+ goto err; -+ } -+ -+ rc = bootenv_get(env, keys[i], &val); -+ if (rc != 0) -+ goto err; -+ -+ wr += snprintf(buf + wr, BOOTENV_MAXSIZE - wr, -+ "%s=%s", keys[i], val); -+ wr++; /* for \0 */ -+ } -+ -+ *written = wr; -+ -+err: -+ if (keys != NULL) -+ free(keys); -+ -+ return rc; -+} -+ -+int -+bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc) -+{ -+ int rc = 0; -+ size_t size = 0; -+ char *buf = NULL; -+ uint32_t crc32_table[256]; -+ -+ if ((fp == NULL) || (env == NULL)) -+ return -EINVAL; -+ -+ buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); -+ if (buf == NULL) -+ return -ENOMEM; -+ -+ -+ rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, &size); -+ if (rc != 0) -+ goto err; -+ -+ /* calculate crc to return */ -+ if (ret_crc != NULL) { -+ init_crc32_table(crc32_table); -+ *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size); -+ } -+ -+ if (fwrite(buf, size, 1, fp) != 1) { -+ rc = -EIO; -+ goto err; -+ } -+ -+err: -+ if (buf != NULL) -+ free(buf); -+ return rc; -+} -+ -+int -+bootenv_write(FILE* fp, bootenv_t env) -+{ -+ return bootenv_write_crc(fp, env, NULL); -+} -+ -+int -+bootenv_compare(bootenv_t first, bootenv_t second) -+{ -+ int rc; -+ size_t written_first, written_second; -+ char *buf_first, *buf_second; -+ -+ if (first == NULL || second == NULL) -+ return -EINVAL; -+ -+ buf_first = malloc(BOOTENV_MAXSIZE); -+ if (!buf_first) -+ return -ENOMEM; -+ buf_second = malloc(BOOTENV_MAXSIZE); -+ if (!buf_second) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ -+ rc = fill_output_buffer(first, buf_first, BOOTENV_MAXSIZE, -+ &written_first); -+ if (rc < 0) -+ goto err; -+ rc = fill_output_buffer(second, buf_second, BOOTENV_MAXSIZE, -+ &written_second); -+ if (rc < 0) -+ goto err; -+ -+ if (written_first != written_second) { -+ rc = 1; -+ goto err; -+ } -+ -+ rc = memcmp(buf_first, buf_second, written_first); -+ if (rc != 0) { -+ rc = 2; -+ goto err; -+ } -+ -+err: -+ if (buf_first) -+ free(buf_first); -+ if (buf_second) -+ free(buf_second); -+ -+ return rc; -+} -+ -+int -+bootenv_size(bootenv_t env, size_t *size) -+{ -+ int rc = 0; -+ char *buf = NULL; -+ -+ if (env == NULL) -+ return -EINVAL; -+ -+ buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); -+ if (buf == NULL) -+ return -ENOMEM; -+ -+ rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, size); -+ if (rc != 0) -+ goto err; -+ -+err: -+ if (buf != NULL) -+ free(buf); -+ return rc; -+} -+ -+int -+bootenv_write_txt(FILE* fp, bootenv_t env) -+{ -+ int rc = 0; -+ size_t size, wr, i; -+ const char **keys = NULL; -+ const char *key = NULL; -+ const char *val = NULL; -+ -+ if ((fp == NULL) || (env == NULL)) -+ return -EINVAL; -+ -+ rc = bootenv_get_key_vector(env, &size, 1, &keys); -+ if (rc != 0) -+ goto err; -+ -+ for (i = 0; i < size; i++) { -+ key = keys[i]; -+ rc = bootenv_get(env, key, &val); -+ if (rc != 0) -+ goto err; -+ -+ wr = fprintf(fp, "%s=%s\n", key, val); -+ if (wr != strlen(key) + strlen(val) + 2) { -+ rc = -EIO; -+ goto err; -+ } -+ } -+ -+err: -+ if (keys != NULL) -+ free(keys); -+ return rc; -+} -+ -+int -+bootenv_valid(bootenv_t env ubi_unused) -+{ -+ /* @FIXME No sanity check implemented. */ -+ return 0; -+} -+ -+int -+bootenv_copy_bootenv(bootenv_t in, bootenv_t *out) -+{ -+ int rc = 0; -+ const char *tmp = NULL; -+ const char **keys = NULL; -+ size_t vec_size, i; -+ -+ if ((in == NULL) || (out == NULL)) -+ return -EINVAL; -+ -+ /* purge output var for sure... */ -+ rc = bootenv_destroy(out); -+ if (rc != 0) -+ return rc; -+ -+ /* create the new map */ -+ rc = bootenv_create(out); -+ if (rc != 0) -+ goto err; -+ -+ /* get the key list from the input map */ -+ rc = bootenv_get_key_vector(in, &vec_size, 0, &keys); -+ if (rc != 0) -+ goto err; -+ -+ if (vec_size != hashmap_size(in->map)) { -+ rc = BOOTENV_ECOPY; -+ goto err; -+ } -+ -+ /* make a deep copy of the hashmap */ -+ for (i = 0; i < vec_size; i++) { -+ rc = bootenv_get(in, keys[i], &tmp); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_set(*out, keys[i], tmp); -+ if (rc != 0) -+ goto err; -+ } -+ -+err: -+ if (keys != NULL) -+ free(keys); -+ -+ return rc; -+} -+ -+/* ------------------------------------------------------------------------- */ -+ -+ -+int -+bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, -+ int *warnings, char *err_buf ubi_unused, -+ size_t err_buf_size ubi_unused) -+{ -+ bootenv_list_t l_old = NULL; -+ bootenv_list_t l_new = NULL; -+ const char *pdd_old = NULL; -+ const char *pdd_new = NULL; -+ const char *tmp = NULL; -+ const char **vec_old = NULL; -+ const char **vec_new = NULL; -+ const char **pdd_up_vec = NULL; -+ size_t vec_old_size, vec_new_size, pdd_up_vec_size, i; -+ int rc = 0; -+ -+ if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) -+ return -EINVAL; -+ -+ /* get the pdd strings, e.g.: -+ * pdd_old=a,b,c -+ * pdd_new=a,c,d,e */ -+ rc = bootenv_get(env_old, "pdd", &pdd_old); -+ if (rc != 0) -+ goto err; -+ rc = bootenv_get(env_new, "pdd", &pdd_new); -+ if (rc != 0) -+ goto err; -+ -+ /* put it into a list and then convert it to an vector */ -+ rc = bootenv_list_create(&l_old); -+ if (rc != 0) -+ goto err; -+ rc = bootenv_list_create(&l_new); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_list_import(l_old, pdd_old); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_list_import(l_new, pdd_new); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_list_to_vector(l_old, &vec_old_size, &vec_old); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_list_to_vector(l_new, &vec_new_size, &vec_new); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_copy_bootenv(env_new, env_res); -+ if (rc != 0) -+ goto err; -+ -+ /* calculate the update vector between the old and new pdd */ -+ pdd_up_vec = hashmap_get_update_key_vector(vec_old, vec_old_size, -+ vec_new, vec_new_size, &pdd_up_vec_size); -+ -+ if (pdd_up_vec == NULL) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ -+ if (pdd_up_vec_size != 0) { -+ /* need to warn the user about the unset of -+ * some pdd/bootenv values */ -+ *warnings = BOOTENV_WPDD_STRING_DIFFERS; -+ -+ /* remove all entries in the new bootenv load */ -+ for (i = 0; i < pdd_up_vec_size; i++) { -+ bootenv_unset(*env_res, pdd_up_vec[i]); -+ } -+ } -+ -+ /* generate the keep array and copy old pdd values to new bootenv */ -+ for (i = 0; i < vec_old_size; i++) { -+ rc = bootenv_get(env_old, vec_old[i], &tmp); -+ if (rc != 0) { -+ rc = BOOTENV_EPDDINVAL; -+ goto err; -+ } -+ rc = bootenv_set(*env_res, vec_old[i], tmp); -+ if (rc != 0) { -+ goto err; -+ } -+ } -+ /* put the old pdd string into the result map */ -+ rc = bootenv_set(*env_res, "pdd", pdd_old); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ -+err: -+ if (vec_old != NULL) -+ free(vec_old); -+ if (vec_new != NULL) -+ free(vec_new); -+ if (pdd_up_vec != NULL) -+ free(pdd_up_vec); -+ -+ bootenv_list_destroy(&l_old); -+ bootenv_list_destroy(&l_new); -+ return rc; -+} -+ -+ -+int -+bootenv_pdd_overwrite(bootenv_t env_old, bootenv_t env_new, -+ bootenv_t *env_res, int *warnings ubi_unused, -+ char *err_buf ubi_unused, size_t err_buf_size ubi_unused) -+{ -+ if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) -+ return -EINVAL; -+ -+ return bootenv_copy_bootenv(env_new, env_res); -+} -+ -+int -+bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, -+ int *warnings ubi_unused, char *err_buf, size_t err_buf_size) -+{ -+ if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) -+ return -EINVAL; -+ -+ snprintf(err_buf, err_buf_size, "The PDD merge operation is not " -+ "implemented. Contact: "); -+ -+ return BOOTENV_ENOTIMPL; -+} -+ -+/* ------------------------------------------------------------------------- */ -+ -+int -+bootenv_get(bootenv_t env, const char *key, const char **value) -+{ -+ if (env == NULL) -+ return -EINVAL; -+ -+ *value = hashmap_lookup(env->map, key); -+ if (*value == NULL) -+ return BOOTENV_ENOTFOUND; -+ -+ return 0; -+} -+ -+int -+bootenv_get_num(bootenv_t env, const char *key, uint32_t *value) -+{ -+ char *endptr = NULL; -+ const char *str; -+ -+ if (env == NULL) -+ return 0; -+ -+ str = hashmap_lookup(env->map, key); -+ if (!str) -+ return -EINVAL; -+ -+ *value = strtoul(str, &endptr, 0); -+ -+ if (*endptr == '\0') { -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+int -+bootenv_set(bootenv_t env, const char *key, const char *value) -+{ -+ if (env == NULL) -+ return -EINVAL; -+ -+ return hashmap_add(env->map, key, value); -+} -+ -+int -+bootenv_unset(bootenv_t env, const char *key) -+{ -+ if (env == NULL) -+ return -EINVAL; -+ -+ return hashmap_remove(env->map, key); -+} -+ -+int -+bootenv_get_key_vector(bootenv_t env, size_t* size, int sort, -+ const char ***vector) -+{ -+ if ((env == NULL) || (size == NULL)) -+ return -EINVAL; -+ -+ *vector = hashmap_get_key_vector(env->map, size, sort); -+ -+ if (*vector == NULL) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+int -+bootenv_dump(bootenv_t env) -+{ -+ if (env == NULL) -+ return -EINVAL; -+ -+ return hashmap_dump(env->map); -+} -+ -+int -+bootenv_list_create(bootenv_list_t *list) -+{ -+ bootenv_list_t res; -+ res = (bootenv_list_t) calloc(1, sizeof(struct bootenv_list)); -+ -+ if (res == NULL) -+ return -ENOMEM; -+ -+ res->head = hashmap_new(); -+ -+ if (res->head == NULL) { -+ free(res); -+ return -ENOMEM; -+ } -+ -+ *list = res; -+ return 0; -+} -+ -+int -+bootenv_list_destroy(bootenv_list_t *list) -+{ -+ int rc = 0; -+ -+ if (list == NULL) -+ return -EINVAL; -+ -+ bootenv_list_t tmp = *list; -+ if (tmp == 0) -+ return 0; -+ -+ rc = hashmap_free(tmp->head); -+ if (rc != 0) -+ return rc; -+ -+ free(tmp); -+ *list = NULL; -+ return 0; -+} -+ -+int -+bootenv_list_import(bootenv_list_t list, const char *str) -+{ -+ if (list == NULL) -+ return -EINVAL; -+ -+ return build_list_definition(list->head, str); -+} -+ -+int -+bootenv_list_export(bootenv_list_t list, char **string) -+{ -+ size_t size, i, j, bufsize, tmp, rc = 0; -+ const char **items; -+ -+ if (list == NULL) -+ return -EINVAL; -+ -+ bufsize = BOOTENV_MAXLINE; -+ char *res = (char*) malloc(bufsize * sizeof(char)); -+ if (res == NULL) -+ return -ENOMEM; -+ -+ rc = bootenv_list_to_vector(list, &size, &items); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ j = 0; -+ for (i = 0; i < size; i++) { -+ tmp = strlen(items[i]); -+ if (j >= bufsize) { -+ bufsize += BOOTENV_MAXLINE; -+ res = (char*) realloc(res, bufsize * sizeof(char)); -+ if (res == NULL) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ } -+ memcpy(res + j, items[i], tmp); -+ j += tmp; -+ if (i < (size - 1)) { -+ res[j] = ','; -+ j++; -+ } -+ } -+ j++; -+ res[j] = '\0'; -+ free(items); -+ *string = res; -+ return 0; -+err: -+ free(items); -+ return rc; -+} -+ -+int -+bootenv_list_add(bootenv_list_t list, const char *item) -+{ -+ if ((list == NULL) || (item == NULL)) -+ return -EINVAL; -+ -+ return hashmap_add(list->head, item, ""); -+} -+ -+int -+bootenv_list_remove(bootenv_list_t list, const char *item) -+{ -+ if ((list == NULL) || (item == NULL)) -+ return -EINVAL; -+ -+ return hashmap_remove(list->head, item); -+} -+ -+int -+bootenv_list_is_in(bootenv_list_t list, const char *item) -+{ -+ if ((list == NULL) || (item == NULL)) -+ return -EINVAL; -+ -+ return hashmap_lookup(list->head, item) != NULL ? 1 : 0; -+} -+ -+int -+bootenv_list_to_vector(bootenv_list_t list, size_t *size, const char ***vector) -+{ -+ if ((list == NULL) || (size == NULL)) -+ return -EINVAL; -+ -+ *vector = hashmap_get_key_vector(list->head, size, 1); -+ if (*vector == NULL) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+int -+bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, -+ uint32_t **vector) -+{ -+ int rc = 0; -+ size_t i; -+ uint32_t* res = NULL; -+ char *endptr = NULL; -+ const char **a = NULL; -+ -+ rc = bootenv_list_to_vector(list, size, &a); -+ if (rc != 0) -+ goto err; -+ -+ res = (uint32_t*) malloc (*size * sizeof(uint32_t)); -+ if (!res) -+ goto err; -+ -+ for (i = 0; i < *size; i++) { -+ res[i] = strtoul(a[i], &endptr, 0); -+ if (*endptr != '\0') -+ goto err; -+ } -+ -+ if (a) -+ free(a); -+ *vector = res; -+ return 0; -+ -+err: -+ if (a) -+ free(a); -+ if (res) -+ free(res); -+ return rc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,434 @@ -+#ifndef __BOOTENV_H__ -+#define __BOOTENV_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include /* FILE */ -+#include -+#include -+ -+/* DOXYGEN DOCUMENTATION */ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** -+ * @file bootenv.h -+ * @author oliloh@de.ibm.com -+ * @version 1.3 -+ * -+ * 1.3 Some renaming -+ */ -+ -+/** -+ * @mainpage Usage -+ * -+ * @section intro Introduction -+ * This library provides all functionality to handle with the so-called -+ * platform description data (PDD) and the bootparameters defined in -+ * U-Boot. It is able to apply the defined PDD operations in PDD update -+ * scenarios. For more information about the PDD and bootparameter -+ * environment "bootenv" confer the PDD documentation. -+ * -+ * @section ret Return codes -+ * This library defines some return codes which will be delivered classified -+ * as warnings or errors. See the "Defines" section for details and numeric -+ * values. -+ * -+ * @section benv Bootenv format description -+ * There are two different input formats: -+ * - text files -+ * - binary files -+ * -+ * @subsection txt Text Files -+ * Text files have to be specified like: -+ * @verbatim key1=value1,value2,value7\n key2=value55,value1\n key4=value1\n@endverbatim -+ * -+ * @subsection bin Binary files -+ * Binary files have to be specified like: -+ * @verbatimkey1=value1,value2,value7\0key2=value55,value1\0... @endverbatim -+ * You can confer the U-Boot documentation for more details. -+ * -+ * @section benvlists Bootenv lists format description. -+ * Values referenced in the preceeding subsection can be -+ * defined like lists: -+ * @verbatim value1,value2,value3 @endverbatim -+ * There are some situation where a conversion of a comma -+ * seperated list can be useful, e.g. to get a list -+ * of defined PDD entries. -+ */ -+ -+#define BOOTENV_MAXSIZE (1024 * 100) /* max 100kiB space for bootenv */ -+ -+/** -+ * @def BOOTENV_ECRC -+ * @brief Given binary file is to large. -+ * @def BOOTENV_EFMT -+ * @brief Given bootenv section has an invalid format -+ * @def BOOTENV_EBADENTRY -+ * @brief Bad entry in the bootenv section. -+ * @def BOOTENV_EINVAL -+ * @brief Invalid bootenv defintion. -+ * @def BOOTENV_ENOPDD -+ * @brief Given bootenv sectoin has no PDD defintion string (pdd=...). -+ * @def BOOTENV_EPDDINVAL -+ * @brief Given bootenv section has an invalid PDD defintion. -+ * @def BOOTENV_ENOTIMPL -+ * @brief Functionality not implemented. -+ * @def BOOTENV_ECOPY -+ * @brief Bootenv memory copy error -+ * @def BOOTENV_ENOTFOUND -+ * @brief Given key has has no value. -+ * @def BOOTENV_EMAX -+ * @brief Highest error value. -+ */ -+#define BOOTENV_ETOOBIG 1 -+#define BOOTENV_EFMT 2 -+#define BOOTENV_EBADENTRY 3 -+#define BOOTENV_EINVAL 4 -+#define BOOTENV_ENOPDD 5 -+#define BOOTENV_EPDDINVAL 6 -+#define BOOTENV_ENOTIMPL 7 -+#define BOOTENV_ECOPY 8 -+#define BOOTENV_ENOTFOUND 9 -+#define BOOTENV_EMAX 10 -+ -+/** -+ * @def BOOTENV_W -+ * @brief A warning which is handled internally as an error -+ * but can be recovered by manual effort. -+ * @def BOOTENV_WPDD_STRING_DIFFERS -+ * @brief The PDD strings of old and new PDD differ and -+ * can cause update problems, because new PDD values -+ * are removed from the bootenv section completely. -+ */ -+#define BOOTENV_W 20 -+#define BOOTENV_WPDD_STRING_DIFFERS 21 -+#define BOOTENV_WMAX 22 /* highest warning value */ -+ -+ -+typedef struct bootenv *bootenv_t; -+ /**< A bootenv library handle. */ -+ -+typedef struct bootenv_list *bootenv_list_t; -+ /**< A handle for a value list. */ -+ -+typedef int(*pdd_func_t)(bootenv_t, bootenv_t, bootenv_t*, -+ int*, char*, size_t); -+ -+ -+/** -+ * @brief Get a new handle. -+ * @return 0 -+ * @return or error -+ * */ -+int bootenv_create(bootenv_t *env); -+ -+/** -+ * @brief Cleanup structure. -+ * @param env Bootenv structure which shall be destroyed. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_destroy(bootenv_t *env); -+ -+/** -+ * @brief Copy a bootenv handle. -+ * @param in The input bootenv. -+ * @param out The copied output bootenv. Discards old data. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_copy_bootenv(bootenv_t in, bootenv_t *out); -+ -+/** -+ * @brief Looks for a value inside the bootenv data. -+ * @param env Handle to a bootenv structure. -+ * @param key The key. -+ * @return NULL key not found -+ * @return !NULL ptr to value -+ */ -+int bootenv_get(bootenv_t env, const char *key, const char **value); -+ -+ -+/** -+ * @brief Looks for a value inside the bootenv data and converts it to num. -+ * @param env Handle to a bootenv structure. -+ * @param key The key. -+ * @param value A pointer to the resulting numerical value -+ * @return NULL key not found -+ * @return !NULL ptr to value -+ */ -+int bootenv_get_num(bootenv_t env, const char *key, uint32_t *value); -+ -+/** -+ * @brief Set a bootenv value by key. -+ * @param env Handle to a bootenv structure. -+ * @param key Key. -+ * @param value Value to set. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_set(bootenv_t env, const char *key, const char *value); -+ -+/** -+ * @brief Remove the given key (and its value) from a bootenv structure. -+ * @param env Handle to a bootenv structure. -+ * @param key Key. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_unset(bootenv_t env, const char *key); -+ -+ -+/** -+ * @brief Get a vector of all keys which are currently set -+ * within a bootenv handle. -+ * @param env Handle to a bootenv structure. -+ * @param size The size of the allocated array structure. -+ * @param sort Flag, if set the vector is sorted ascending. -+ * @return NULL on error. -+ * @return !NULL a pointer to the first element the allocated vector. -+ * @warning Free the allocate memory yourself! -+ */ -+int bootenv_get_key_vector(bootenv_t env, size_t *size, int sort, -+ const char ***vector); -+ -+/** -+ * @brief Calculate the size in bytes which are necessary to write the -+ * current bootenv section in a *binary file. -+ * @param env bootenv handle. -+ * @param size The size in bytes of the bootenv handle. -+ * @return 0 -+ * @return or ERROR. -+ */ -+int bootenv_size(bootenv_t env, size_t *size); -+ -+/** -+ * @brief Read a binary bootenv file. -+ * @param fp File pointer to input stream. -+ * @param env bootenv handle. -+ * @param size maximum data size. -+ * @return 0 -+ * @return or ERROR. -+ */ -+int bootenv_read(FILE* fp, bootenv_t env, size_t size); -+ -+/** -+ * @param ret_crc return value of crc of read data -+ */ -+int bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t *ret_crc); -+ -+/** -+ * @brief Read bootenv data from an text/ascii file. -+ * @param fp File pointer to ascii PDD file. -+ * @param env bootenv handle -+ * @return 0 -+ * @return or ERROR. -+ */ -+int bootenv_read_txt(FILE* fp, bootenv_t env); -+ -+/** -+ * @brief Write a bootenv structure to the given location (binary). -+ * @param fp Filepointer to binary file. -+ * @param env Bootenv structure which shall be written. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_write(FILE* fp, bootenv_t env); -+ -+/** -+ * @param ret_crc return value of crc of read data -+ */ -+int bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc); -+ -+/** -+ * @brief Write a bootenv structure to the given location (text). -+ * @param fp Filepointer to text file. -+ * @param env Bootenv structure which shall be written. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_write_txt(FILE* fp, bootenv_t env); -+ -+/** -+ * @brief Compare bootenvs using memcmp(). -+ * @param first First bootenv. -+ * @param second Second bootenv. -+ * @return 0 if bootenvs are equal -+ * @return < 0 if error -+ * @return > 0 if unequal -+ */ -+int bootenv_compare(bootenv_t first, bootenv_t second); -+ -+/** -+ * @brief Prototype for a PDD handling funtion -+ */ -+ -+/** -+ * @brief The PDD keep operation. -+ * @param env_old The old bootenv structure. -+ * @param env_new The new bootenv structure. -+ * @param env_res The result of PDD keep. -+ * @param warnings A flag which marks any warnings. -+ * @return 0 -+ * @return or error -+ * @note For a complete documentation about the algorithm confer the -+ * PDD documentation. -+ */ -+int bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, -+ bootenv_t *env_res, int *warnings, -+ char *err_buf, size_t err_buf_size); -+ -+ -+/** -+ * @brief The PDD merge operation. -+ * @param env_old The old bootenv structure. -+ * @param env_new The new bootenv structure. -+ * @param env_res The result of merge-pdd. -+ * @param warnings A flag which marks any warnings. -+ * @return 0 -+ * @return or error -+ * @note For a complete documentation about the algorithm confer the -+ * PDD documentation. -+ */ -+int bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, -+ bootenv_t *env_res, int *warnings, -+ char *err_buf, size_t err_buf_size); -+ -+/** -+ * @brief The PDD overwrite operation. -+ * @param env_old The old bootenv structure. -+ * @param env_new The new bootenv structure. -+ * @param env_res The result of overwrite-pdd. -+ * @param warnings A flag which marks any warnings. -+ * @return 0 -+ * @return or error -+ * @note For a complete documentation about the algorithm confer the -+ * PDD documentation. -+ */ -+int bootenv_pdd_overwrite(bootenv_t env_new, -+ bootenv_t env_old, bootenv_t *env_res, int *warnings, -+ char *err_buf, size_t err_buf_size); -+ -+/** -+ * @brief Dump a bootenv structure to stdout. (Debug) -+ * @param env Handle to a bootenv structure. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_dump(bootenv_t env); -+ -+/** -+ * @brief Validate a bootenv structure. -+ * @param env Handle to a bootenv structure. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_valid(bootenv_t env); -+ -+/** -+ * @brief Create a new bootenv list structure. -+ * @return NULL on error -+ * @return or a new list handle. -+ * @note This structure is used to store values in a list. -+ * A useful addition when handling PDD strings. -+ */ -+int bootenv_list_create(bootenv_list_t *list); -+ -+/** -+ * @brief Destroy a bootenv list structure -+ * @param list Handle to a bootenv list structure. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_list_destroy(bootenv_list_t *list); -+ -+/** -+ * @brief Import a list from a comma seperated string -+ * @param list Handle to a bootenv list structure. -+ * @param str Comma seperated string list. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_list_import(bootenv_list_t list, const char *str); -+ -+/** -+ * @brief Export a list to a string of comma seperated values. -+ * @param list Handle to a bootenv list structure. -+ * @return NULL one error -+ * @return or pointer to a newly allocated string. -+ * @warning Free the allocated memory by yourself! -+ */ -+int bootenv_list_export(bootenv_list_t list, char **string); -+ -+/** -+ * @brief Add an item to the list. -+ * @param list A handle of a list structure. -+ * @param item An item. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_list_add(bootenv_list_t list, const char *item); -+ -+/** -+ * @brief Remove an item from the list. -+ * @param list A handle of a list structure. -+ * @param item An item. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_list_remove(bootenv_list_t list, const char *item); -+ -+/** -+ * @brief Check if a given item is in a given list. -+ * @param list A handle of a list structure. -+ * @param item An item. -+ * @return 1 Item is in list. -+ * @return 0 Item is not in list. -+ */ -+int bootenv_list_is_in(bootenv_list_t list, const char *item); -+ -+ -+/** -+ * @brief Convert a list into a vector of all values inside the list. -+ * @param list Handle to a bootenv structure. -+ * @param size The size of the allocated vector structure. -+ * @return 0 -+ * @return or error -+ * @warning Free the allocate memory yourself! -+ */ -+int bootenv_list_to_vector(bootenv_list_t list, size_t *size, -+ const char ***vector); -+ -+/** -+ * @brief Convert a list into a vector of all values inside the list. -+ * @param list Handle to a bootenv structure. -+ * @param size The size of the allocated vector structure. -+ * @return 0 -+ * @return or error -+ * @warning Free the allocate memory yourself! -+ */ -+int bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, -+ uint32_t **vector); -+ -+#ifdef __cplusplus -+} -+#endif -+#endif /*__BOOTENV_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/config.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/config.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,28 @@ -+#ifndef __CONFIG_H__ -+#define __CONFIG_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Frank Haverkamp -+ */ -+ -+#define PACKAGE_BUGREPORT \ -+ "haver@vnet.ibm.com, dedekind@linutronix.de, or tglx@linutronix.de" -+ -+#define ubi_unused __attribute__((unused)) -+ -+#endif ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,83 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Thomas Gleixner -+ */ -+ -+/* -+ * CRC32 functions -+ * -+ * Can be compiled as seperate object, but is included into the ipl source -+ * so gcc can inline the functions. We optimize for size so the omission of -+ * the function frame is helpful. -+ * -+ */ -+ -+#include -+#include -+ -+/* CRC polynomial */ -+#define CRC_POLY 0xEDB88320 -+ -+/** -+ * init_crc32_table - Initialize crc table -+ * -+ * @table: pointer to the CRC table which must be initialized -+ * -+ * Create CRC32 table for given polynomial. The table is created with -+ * the lowest order term in the highest order bit. So the x^32 term -+ * has to implied in the crc calculation function. -+ */ -+void init_crc32_table(uint32_t *table) -+{ -+ uint32_t crc; -+ int i, j; -+ -+ for (i = 0; i < 256; i++) { -+ crc = i; -+ for (j = 8; j > 0; j--) { -+ if (crc & 1) -+ crc = (crc >> 1) ^ CRC_POLY; -+ else -+ crc >>= 1; -+ } -+ table[i] = crc; -+ } -+} -+ -+/** -+ * clc_crc32 - Calculate CRC32 over a buffer -+ * -+ * @table: pointer to the CRC table -+ * @crc: initial crc value -+ * @buf: pointer to the buffer -+ * @len: number of bytes to calc -+ * -+ * Returns the updated crc value. -+ * -+ * The algorithm resembles a hardware shift register, but calculates 8 -+ * bit at once. -+ */ -+uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, -+ int len) -+{ -+ const unsigned char *p = buf; -+ -+ while(--len >= 0) -+ crc = table[(crc ^ *p++) & 0xff] ^ (crc >> 8); -+ return crc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,36 @@ -+#ifndef __CRC32_H__ -+#define __CRC32_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Author: Thomas Gleixner -+ * -+ * CRC32 functions -+ * -+ * Can be compiled as seperate object, but is included into the ipl source -+ * so gcc can inline the functions. We optimize for size so the omission of -+ * the function frame is helpful. -+ * -+ */ -+#include -+ -+void init_crc32_table(uint32_t *table); -+uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, int len); -+ -+#endif /* __CRC32_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,281 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Author: Drake Dowsett, dowsett@de.ibm.com -+ * Contact: Andreas Arnez, arnez@de.ibm.com -+ */ -+ -+/* see eb_chain.h */ -+ -+#include -+#include -+#include -+#include -+#include "unubi_analyze.h" -+#include "crc32.h" -+ -+#define COPY(dst, src) \ -+ do { \ -+ dst = malloc(sizeof(*dst)); \ -+ if (dst == NULL) \ -+ return -ENOMEM; \ -+ memcpy(dst, src, sizeof(*dst)); \ -+ } while (0) -+ -+ -+/** -+ * inserts an eb_info into the chain starting at head, then searching -+ * linearly for the correct position; -+ * new should contain valid vid and ec headers and the data_crc should -+ * already have been checked before insertion, otherwise the chain -+ * could be have un an undesired manner; -+ * returns -ENOMEM if alloc fails, otherwise SHOULD always return 0, -+ * if not, the code reached the last line and returned -EAGAIN, -+ * meaning there is a bug or a case not being handled here; -+ **/ -+int -+eb_chain_insert(struct eb_info **head, struct eb_info *new) -+{ -+ uint32_t vol, num, ver; -+ uint32_t new_vol, new_num, new_ver; -+ struct eb_info *prev, *cur, *hist, *ins; -+ struct eb_info **prev_ptr; -+ -+ if ((head == NULL) || (new == NULL)) -+ return 0; -+ -+ if (*head == NULL) { -+ COPY(*head, new); -+ (*head)->next = NULL; -+ return 0; -+ } -+ -+ new_vol = be32_to_cpu(new->vid.vol_id); -+ new_num = be32_to_cpu(new->vid.lnum); -+ new_ver = be32_to_cpu(new->vid.leb_ver); -+ -+ /** TRAVERSE HORIZONTALY **/ -+ -+ cur = *head; -+ prev = NULL; -+ -+ /* traverse until vol_id/lnum align */ -+ vol = be32_to_cpu(cur->vid.vol_id); -+ num = be32_to_cpu(cur->vid.lnum); -+ while ((new_vol > vol) || ((new_vol == vol) && (new_num > num))) { -+ /* insert new at end of chain */ -+ if (cur->next == NULL) { -+ COPY(ins, new); -+ ins->next = NULL; -+ cur->next = ins; -+ return 0; -+ } -+ -+ prev = cur; -+ cur = cur->next; -+ vol = be32_to_cpu(cur->vid.vol_id); -+ num = be32_to_cpu(cur->vid.lnum); -+ } -+ -+ if (prev == NULL) -+ prev_ptr = head; -+ else -+ prev_ptr = &(prev->next); -+ -+ /* insert new into the middle of chain */ -+ if ((new_vol != vol) || (new_num != num)) { -+ COPY(ins, new); -+ ins->next = cur; -+ *prev_ptr = ins; -+ return 0; -+ } -+ -+ /** TRAVERSE VERTICALY **/ -+ -+ hist = cur; -+ prev = NULL; -+ -+ /* traverse until versions align */ -+ ver = be32_to_cpu(cur->vid.leb_ver); -+ while (new_ver < ver) { -+ /* insert new at bottom of history */ -+ if (hist->older == NULL) { -+ COPY(ins, new); -+ ins->next = NULL; -+ ins->older = NULL; -+ hist->older = ins; -+ return 0; -+ } -+ -+ prev = hist; -+ hist = hist->older; -+ ver = be32_to_cpu(hist->vid.leb_ver); -+ } -+ -+ if (prev == NULL) { -+ /* replace active version */ -+ COPY(ins, new); -+ ins->next = hist->next; -+ *prev_ptr = ins; -+ -+ /* place cur in vertical histroy */ -+ ins->older = hist; -+ hist->next = NULL; -+ return 0; -+ } -+ -+ /* insert between versions, beneath active version */ -+ COPY(ins, new); -+ ins->next = NULL; -+ ins->older = prev->older; -+ prev->older = ins; -+ return 0; -+} -+ -+ -+/** -+ * sets the pointer at pos to the position of the first entry in the chain -+ * with of vol_id and, if given, with the same lnum as *lnum; -+ * if there is no entry in the chain, then *pos is NULL on return; -+ * always returns 0; -+ **/ -+int -+eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum, -+ struct eb_info **pos) -+{ -+ uint32_t vol, num; -+ struct eb_info *cur; -+ -+ if ((head == NULL) || (*head == NULL) || (pos == NULL)) -+ return 0; -+ -+ *pos = NULL; -+ -+ cur = *head; -+ while (cur != NULL) { -+ vol = be32_to_cpu(cur->vid.vol_id); -+ num = be32_to_cpu(cur->vid.lnum); -+ -+ if ((vol_id == vol) && ((lnum == NULL) || (*lnum == num))) { -+ *pos = cur; -+ return 0; -+ } -+ -+ cur = cur->next; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * prints to stream, the vol_id, lnum and leb_ver for each entry in the -+ * chain, starting at head; -+ * this is intended for debuging purposes; -+ * always returns 0; -+ * -+ * FIXME I do not like the double list traversion ... -+ **/ -+int -+eb_chain_print(FILE* stream, struct eb_info *head) -+{ -+ struct eb_info *cur; -+ -+ if (stream == NULL) -+ stream = stdout; -+ -+ if (head == NULL) { -+ fprintf(stream, "EMPTY\n"); -+ return 0; -+ } -+ /* 012345678012345678012345678012301230123 0123 01234567 0123457 01234567*/ -+ fprintf(stream, "VOL_ID LNUM LEB_VER EC VID DAT PBLK PADDR DSIZE EC\n"); -+ cur = head; -+ while (cur != NULL) { -+ struct eb_info *hist; -+ -+ fprintf(stream, "%08x %-8u %08x %-4s%-4s", -+ be32_to_cpu(cur->vid.vol_id), -+ be32_to_cpu(cur->vid.lnum), -+ be32_to_cpu(cur->vid.leb_ver), -+ cur->ec_crc_ok ? "ok":"bad", -+ cur->vid_crc_ok ? "ok":"bad"); -+ if (cur->vid.vol_type == UBI_VID_STATIC) -+ fprintf(stream, "%-4s", cur->data_crc_ok ? "ok":"bad"); -+ else fprintf(stream, "%-4s", cur->data_crc_ok ? "ok":"ign"); -+ fprintf(stream, " %-4d %08x %-8u %-8llu\n", cur->phys_block, -+ cur->phys_addr, be32_to_cpu(cur->vid.data_size), -+ (unsigned long long)be64_to_cpu(cur->ec.ec)); -+ -+ hist = cur->older; -+ while (hist != NULL) { -+ fprintf(stream, "%08x %-8u %08x %-4s%-4s", -+ be32_to_cpu(hist->vid.vol_id), -+ be32_to_cpu(hist->vid.lnum), -+ be32_to_cpu(hist->vid.leb_ver), -+ hist->ec_crc_ok ? "ok":"bad", -+ hist->vid_crc_ok ? "ok":"bad"); -+ if (hist->vid.vol_type == UBI_VID_STATIC) -+ fprintf(stream, "%-4s", hist->data_crc_ok ? "ok":"bad"); -+ else fprintf(stream, "%-4s", hist->data_crc_ok ? "ok":"ign"); -+ fprintf(stream, " %-4d %08x %-8u %-8llu (*)\n", -+ hist->phys_block, hist->phys_addr, -+ be32_to_cpu(hist->vid.data_size), -+ (unsigned long long)be64_to_cpu(hist->ec.ec)); -+ -+ hist = hist->older; -+ } -+ cur = cur->next; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * frees the memory of the entire chain, starting at head; -+ * head will be NULL on return; -+ * always returns 0; -+ **/ -+int -+eb_chain_destroy(struct eb_info **head) -+{ -+ if (head == NULL) -+ return 0; -+ -+ while (*head != NULL) { -+ struct eb_info *cur; -+ struct eb_info *hist; -+ -+ cur = *head; -+ *head = (*head)->next; -+ -+ hist = cur->older; -+ while (hist != NULL) { -+ struct eb_info *temp; -+ -+ temp = hist; -+ hist = hist->older; -+ free(temp); -+ } -+ free(cur); -+ } -+ return 0; -+} -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/error.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/error.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,240 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "error.h" -+ -+#define MAXLINE 4096 -+#define MAXWIDTH 80 -+ -+static FILE *logfp = NULL; -+ -+static void err_doit(int, int, const char *, va_list); -+ -+int -+read_procfile(FILE *fp_out, const char *procfile) -+{ -+ FILE *fp; -+ -+ if (!fp_out) -+ return -ENXIO; -+ -+ fp = fopen(procfile, "r"); -+ if (!fp) -+ return -ENOENT; -+ -+ while(!feof(fp)) { -+ int c = fgetc(fp); -+ -+ if (c == EOF) -+ return 0; -+ -+ if (putc(c, fp_out) == EOF) -+ return -EIO; -+ -+ if (ferror(fp)) -+ return -EIO; -+ } -+ return fclose(fp); -+} -+ -+void -+error_initlog(const char *logfile) -+{ -+ if (!logfile) -+ return; -+ -+ logfp = fopen(logfile, "a+"); -+ read_procfile(logfp, "/proc/cpuinfo"); -+} -+ -+void -+info_msg(const char *fmt, ...) -+{ -+ FILE* fpout; -+ char buf[MAXLINE + 1]; -+ va_list ap; -+ int n; -+ -+ fpout = stdout; -+ -+ va_start(ap, fmt); -+ vsnprintf(buf, MAXLINE, fmt, ap); -+ n = strlen(buf); -+ strcat(buf, "\n"); -+ -+ fputs(buf, fpout); -+ fflush(fpout); -+ if (fpout != stdout) -+ fclose(fpout); -+ -+ va_end(ap); -+ return; -+} -+ -+void -+__err_ret(const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ err_doit(1, LOG_INFO, fmt, ap); -+ va_end(ap); -+ return; -+} -+ -+void -+__err_sys(const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ err_doit(1, LOG_ERR, fmt, ap); -+ va_end(ap); -+ exit(EXIT_FAILURE); -+} -+ -+ -+void -+__err_msg(const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ err_doit(0, LOG_INFO, fmt, ap); -+ va_end(ap); -+ -+ return; -+} -+ -+void -+__err_quit(const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ err_doit(0, LOG_ERR, fmt, ap); -+ va_end(ap); -+ exit(EXIT_FAILURE); -+} -+ -+void -+__err_dump(const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ err_doit(1, LOG_ERR, fmt, ap); -+ va_end(ap); -+ abort(); /* dump core and terminate */ -+ exit(EXIT_FAILURE); /* shouldn't get here */ -+} -+ -+/** -+ * If a logfile is used we must not print on stderr and stdout -+ * anymore. Since pfilfash might be used in a server context, it is -+ * even dangerous to write to those descriptors. -+ */ -+static void -+err_doit(int errnoflag, int level __attribute__((unused)), -+ const char *fmt, va_list ap) -+{ -+ FILE* fpout; -+ int errno_save, n; -+ char buf[MAXLINE + 1]; -+ fpout = stderr; -+ -+ errno_save = errno; /* value caller might want printed */ -+ -+ vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ -+ -+ n = strlen(buf); -+ -+ if (errnoflag) -+ snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); -+ strcat(buf, "\n"); -+ -+ if (logfp) { -+ fputs(buf, logfp); -+ fflush(logfp); -+ return; /* exit when logging completes */ -+ } -+ -+ if (fpout == stderr) { -+ /* perform line wrap when outputting to stderr */ -+ int word_len, post_len, chars; -+ char *buf_ptr; -+ const char *frmt = "%*s%n %n"; -+ -+ chars = 0; -+ buf_ptr = buf; -+ while (sscanf(buf_ptr, frmt, &word_len, &post_len) != EOF) { -+ int i; -+ char word[word_len + 1]; -+ char post[post_len + 1]; -+ -+ strncpy(word, buf_ptr, word_len); -+ word[word_len] = '\0'; -+ buf_ptr += word_len; -+ post_len -= word_len; -+ -+ if (chars + word_len > MAXWIDTH) { -+ fputc('\n', fpout); -+ chars = 0; -+ } -+ fputs(word, fpout); -+ chars += word_len; -+ -+ if (post_len > 0) { -+ strncpy(post, buf_ptr, post_len); -+ post[post_len] = '\0'; -+ buf_ptr += post_len; -+ } -+ for (i = 0; i < post_len; i++) { -+ int inc = 1, chars_new; -+ -+ if (post[i] == '\t') -+ inc = 8; -+ if (post[i] == '\n') { -+ inc = 0; -+ chars_new = 0; -+ } else -+ chars_new = chars + inc; -+ -+ if (chars_new > MAXWIDTH) { -+ fputc('\n', fpout); -+ chars_new = inc; -+ } -+ fputc(post[i], fpout); -+ chars = chars_new; -+ } -+ } -+ } -+ else -+ fputs(buf, fpout); -+ fflush(fpout); -+ if (fpout != stderr) -+ fclose(fpout); -+ -+ return; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/error.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/error.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,84 @@ -+#ifndef __ERROR_H__ -+#define __ERROR_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+ -+void error_initlog(const char *logfile); -+int read_procfile(FILE *fp_out, const char *procfile); -+ -+void __err_ret(const char *fmt, ...); -+void __err_sys(const char *fmt, ...); -+void __err_msg(const char *fmt, ...); -+void __err_quit(const char *fmt, ...); -+void __err_dump(const char *fmt, ...); -+ -+void info_msg(const char *fmt, ...); -+ -+#ifdef DEBUG -+#define __loc_msg(str) do { \ -+ __err_msg("[%s. FILE: %s FUNC: %s LINE: %d]\n", \ -+ str, __FILE__, __FUNCTION__, __LINE__); \ -+} while (0) -+#else -+#define __loc_msg(str) -+#endif -+ -+ -+#define err_dump(fmt, ...) do { \ -+ __loc_msg("ErrDump"); \ -+ __err_dump(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define err_quit(fmt, ...) do { \ -+ __loc_msg("ErrQuit"); \ -+ __err_quit(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+ -+#define err_ret(fmt, ...) do { \ -+ __loc_msg("ErrRet"); \ -+ __err_ret(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define err_sys(fmt, ...) do { \ -+ __loc_msg("ErrSys"); \ -+ __err_sys(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define err_msg(fmt, ...) do { \ -+ __loc_msg("ErrMsg"); \ -+ __err_msg(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define log_msg(fmt, ...) do { \ -+ /* __loc_msg("LogMsg"); */ \ -+ __err_msg(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#ifdef DEBUG -+#define dbg_msg(fmt, ...) do { \ -+ __loc_msg("DbgMsg"); \ -+ __err_msg(fmt, ##__VA_ARGS__); \ -+} while (0) -+#else -+#define dbg_msg(fmt, ...) do {} while (0) -+#endif -+ -+#endif /* __ERROR_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,28 @@ -+#ifndef __EXAMPLE_UBI_H__ -+#define __EXAMPLE_UBI_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/** -+ * Defaults for our cards. -+ */ -+#define EXAMPLE_UBI_DEVICE 0 -+#define EXAMPLE_BOOTENV_VOL_ID_1 4 -+#define EXAMPLE_BOOTENV_VOL_ID_2 5 -+ -+#endif /* __EXAMPLE_UBI_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,412 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+#include -+#include -+#include "error.h" -+#include "hashmap.h" -+#define DEFAULT_BUCKETS 4096 -+ -+#if 0 -+#define INFO_MSG(fmt...) do { \ -+ info_msg(fmt); \ -+} while (0) -+#else -+#define INFO_MSG(fmt...) -+#endif -+ -+struct hashentry { -+ char* key; /* key '0' term. str */ -+ char* value; /* payload '0' term. str */ -+ -+ hashentry_t next; -+}; -+ -+struct hashmap { -+ size_t entries; /* current #entries */ -+ size_t maxsize; /* no. of hash buckets */ -+ hashentry_t* data; /* array of buckets */ -+}; -+ -+static int -+is_empty(hashentry_t l) -+{ -+ return l == NULL ? 1 : 0; -+} -+ -+hashmap_t -+hashmap_new(void) -+{ -+ hashmap_t res; -+ res = (hashmap_t) calloc(1, sizeof(struct hashmap)); -+ -+ if (res == NULL) -+ return NULL; -+ -+ res->maxsize = DEFAULT_BUCKETS; -+ res->entries = 0; -+ -+ res->data = (hashentry_t*) -+ calloc(1, res->maxsize * sizeof(struct hashentry)); -+ -+ if (res->data == NULL) -+ return NULL; -+ -+ return res; -+} -+ -+static hashentry_t -+new_entry(const char* key, const char* value) -+{ -+ hashentry_t res; -+ -+ res = (hashentry_t) calloc(1, sizeof(struct hashentry)); -+ -+ if (res == NULL) -+ return NULL; -+ -+ /* allocate key and value and copy them */ -+ res->key = strdup(key); -+ if (res->key == NULL) { -+ free(res); -+ return NULL; -+ } -+ -+ res->value = strdup(value); -+ if (res->value == NULL) { -+ free(res->key); -+ free(res); -+ return NULL; -+ } -+ -+ res->next = NULL; -+ -+ return res; -+} -+ -+static hashentry_t -+free_entry(hashentry_t e) -+{ -+ if (!is_empty(e)) { -+ if(e->key != NULL) { -+ free(e->key); -+ } -+ if(e->value != NULL) -+ free(e->value); -+ free(e); -+ } -+ -+ return NULL; -+} -+ -+static hashentry_t -+remove_entry(hashentry_t l, const char* key, size_t* entries) -+{ -+ hashentry_t lnext; -+ if (is_empty(l)) -+ return NULL; -+ -+ if(strcmp(l->key,key) == 0) { -+ lnext = l->next; -+ l = free_entry(l); -+ (*entries)--; -+ return lnext; -+ } -+ -+ l->next = remove_entry(l->next, key, entries); -+ -+ return l; -+} -+ -+static hashentry_t -+insert_entry(hashentry_t l, hashentry_t e, size_t* entries) -+{ -+ if (is_empty(l)) { -+ (*entries)++; -+ return e; -+ } -+ -+ /* check for update */ -+ if (strcmp(l->key, e->key) == 0) { -+ e->next = l->next; -+ l = free_entry(l); -+ return e; -+ } -+ -+ l->next = insert_entry(l->next, e, entries); -+ return l; -+} -+ -+static hashentry_t -+remove_all(hashentry_t l, size_t* entries) -+{ -+ hashentry_t lnext; -+ if (is_empty(l)) -+ return NULL; -+ -+ lnext = l->next; -+ free_entry(l); -+ (*entries)--; -+ -+ return remove_all(lnext, entries); -+} -+ -+static const char* -+value_lookup(hashentry_t l, const char* key) -+{ -+ if (is_empty(l)) -+ return NULL; -+ -+ if (strcmp(l->key, key) == 0) -+ return l->value; -+ -+ return value_lookup(l->next, key); -+} -+ -+static void -+print_all(hashentry_t l) -+{ -+ if (is_empty(l)) { -+ printf("\n"); -+ return; -+ } -+ -+ printf("%s=%s", l->key, l->value); -+ if (!is_empty(l->next)) { -+ printf(","); -+ } -+ -+ print_all(l->next); -+} -+ -+static void -+keys_to_array(hashentry_t l, const char** a, size_t* i) -+{ -+ if (is_empty(l)) -+ return; -+ -+ a[*i] = l->key; -+ (*i)++; -+ -+ keys_to_array(l->next, a, i); -+} -+ -+uint32_t -+hash_str(const char* str, uint32_t mapsize) -+{ -+ uint32_t hash = 0; -+ uint32_t x = 0; -+ uint32_t i = 0; -+ size_t len = strlen(str); -+ -+ for(i = 0; i < len; str++, i++) { -+ hash = (hash << 4) + (*str); -+ if((x = hash & 0xF0000000L) != 0) { -+ hash ^= (x >> 24); -+ hash &= ~x; -+ } -+ } -+ -+ return (hash & 0x7FFFFFFF) % mapsize; -+} -+ -+ -+int -+hashmap_is_empty(hashmap_t map) -+{ -+ if (map == NULL) -+ return -EINVAL; -+ -+ return map->entries > 0 ? 1 : 0; -+} -+ -+const char* -+hashmap_lookup(hashmap_t map, const char* key) -+{ -+ uint32_t i; -+ -+ if ((map == NULL) || (key == NULL)) -+ return NULL; -+ -+ i = hash_str(key, map->maxsize); -+ -+ return value_lookup(map->data[i], key); -+} -+ -+int -+hashmap_add(hashmap_t map, const char* key, const char* value) -+{ -+ uint32_t i; -+ hashentry_t entry; -+ -+ if ((map == NULL) || (key == NULL) || (value == NULL)) -+ return -EINVAL; -+ -+ i = hash_str(key, map->maxsize); -+ entry = new_entry(key, value); -+ if (entry == NULL) -+ return -ENOMEM; -+ -+ map->data[i] = insert_entry(map->data[i], -+ entry, &map->entries); -+ -+ INFO_MSG("HASH_ADD: chain[%d] key:%s val:%s",i, key, value); -+ return 0; -+} -+ -+int -+hashmap_remove(hashmap_t map, const char* key) -+{ -+ uint32_t i; -+ -+ if ((map == NULL) || (key == NULL)) -+ return -EINVAL; -+ -+ i = hash_str(key, map->maxsize); -+ map->data[i] = remove_entry(map->data[i], key, &map->entries); -+ -+ return 0; -+} -+ -+size_t -+hashmap_size(hashmap_t map) -+{ -+ if (map != NULL) -+ return map->entries; -+ else -+ return 0; -+} -+ -+int -+hashmap_free(hashmap_t map) -+{ -+ size_t i; -+ -+ if (map == NULL) -+ return -EINVAL; -+ -+ /* "children" first */ -+ for(i = 0; i < map->maxsize; i++) { -+ map->data[i] = remove_all(map->data[i], &map->entries); -+ } -+ free(map->data); -+ free(map); -+ -+ return 0; -+} -+ -+int -+hashmap_dump(hashmap_t map) -+{ -+ size_t i; -+ if (map == NULL) -+ return -EINVAL; -+ -+ for(i = 0; i < map->maxsize; i++) { -+ if (map->data[i] != NULL) { -+ printf("[%zd]: ", i); -+ print_all(map->data[i]); -+ } -+ } -+ -+ return 0; -+} -+ -+static const char** -+sort_key_vector(const char** a, size_t size) -+{ -+ /* uses bubblesort */ -+ size_t i, j; -+ const char* tmp; -+ -+ if (size <= 0) -+ return a; -+ -+ for (i = size - 1; i > 0; i--) { -+ for (j = 0; j < i; j++) { -+ if (strcmp(a[j], a[j+1]) > 0) { -+ tmp = a[j]; -+ a[j] = a[j+1]; -+ a[j+1] = tmp; -+ } -+ } -+ } -+ return a; -+} -+ -+const char** -+hashmap_get_key_vector(hashmap_t map, size_t* size, int sort) -+{ -+ const char** res; -+ size_t i, j; -+ *size = map->entries; -+ -+ res = (const char**) malloc(*size * sizeof(char*)); -+ if (res == NULL) -+ return NULL; -+ -+ j = 0; -+ for(i=0; i < map->maxsize; i++) { -+ keys_to_array(map->data[i], res, &j); -+ } -+ -+ if (sort) -+ res = sort_key_vector(res, *size); -+ -+ return res; -+} -+ -+int -+hashmap_key_is_in_vector(const char** vec, size_t size, const char* key) -+{ -+ size_t i; -+ for (i = 0; i < size; i++) { -+ if (strcmp(vec[i], key) == 0) /* found */ -+ return 1; -+ } -+ -+ return 0; -+} -+ -+const char** -+hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, -+ const char** vec2, size_t vec2_size, size_t* res_size) -+{ -+ const char** res; -+ size_t i, j; -+ -+ *res_size = vec2_size; -+ -+ res = (const char**) malloc(*res_size * sizeof(char*)); -+ if (res == NULL) -+ return NULL; -+ -+ /* get all keys from vec2 which are not set in vec1 */ -+ j = 0; -+ for (i = 0; i < vec2_size; i++) { -+ if (!hashmap_key_is_in_vector(vec1, vec1_size, vec2[i])) -+ res[j++] = vec2[i]; -+ } -+ -+ *res_size = j; -+ return res; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,49 @@ -+#ifndef __HASHMAP_H__ -+#define __HASHMAP_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+ -+typedef struct hashentry *hashentry_t; -+typedef struct hashmap *hashmap_t; -+ -+hashmap_t hashmap_new(void); -+int hashmap_free(hashmap_t map); -+ -+int hashmap_add(hashmap_t map, const char* key, const char* value); -+int hashmap_update(hashmap_t map, const char* key, const char* value); -+int hashmap_remove(hashmap_t map, const char* key); -+const char* hashmap_lookup(hashmap_t map, const char* key); -+ -+const char** hashmap_get_key_vector(hashmap_t map, size_t* size, int sort); -+int hashmap_key_is_in_vector(const char** vec, size_t size, const char* key); -+const char** hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, -+ const char** vec2, size_t vec2_size, size_t* res_size); -+ -+int hashmap_dump(hashmap_t map); -+ -+int hashmap_is_empty(hashmap_t map); -+size_t hashmap_size(hashmap_t map); -+ -+uint32_t hash_str(const char* str, uint32_t mapsize); -+ -+#endif /* __HASHMAP_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1325 @@ -+/* -+ * Copyright International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Authors: Oliver Lohmann -+ * Drake Dowsett -+ * Contact: Andreas Arnez -+ */ -+ -+/* TODO Compare data before writing it. This implies that the volume -+ * parameters are compared first: size, alignment, name, type, ..., -+ * this is the same, compare the data. Volume deletion is deffered -+ * until the difference has been found out. -+ */ -+ -+#include -+#include -+#include -+#include -+#define __USE_GNU -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include /* FIXME Is this ok here? */ -+#include -+ -+#include "pfiflash_error.h" -+#include "ubimirror.h" -+#include "error.h" -+#include "reader.h" -+#include "example_ubi.h" -+#include "bootenv.h" -+ -+/* ubi-header.h and crc32.h needed for CRC checking */ -+#include /* FIXME Is this ok here? */ -+#include "crc32.h" -+ -+#define ubi_unused __attribute__((unused)) -+ -+#define COMPARE_BUFFER_SIZE 2048 -+ -+#define DEFAULT_DEV_PATTERN "/dev/ubi%d" -+#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d" -+ -+static const char copyright [] ubi_unused = -+ "Copyright International Business Machines Corp., 2006, 2007"; -+ -+/* simply clear buffer, then write into front of it */ -+#define EBUF(fmt...) \ -+ snprintf(err_buf, err_buf_size, fmt); -+ -+/* make a history of buffer and then prepend something in front */ -+#define EBUF_PREPEND(fmt) \ -+ do { \ -+ int EBUF_HISTORY_LENGTH = strlen(err_buf); \ -+ char EBUF_HISTORY[EBUF_HISTORY_LENGTH + 1]; \ -+ strncpy(EBUF_HISTORY, err_buf, EBUF_HISTORY_LENGTH + 1);\ -+ EBUF(fmt ": %s", EBUF_HISTORY); \ -+ } while (0) -+ -+/* An array of PDD function pointers indexed by the algorithm. */ -+static pdd_func_t pdd_funcs[PDD_HANDLING_NUM] = -+ { -+ &bootenv_pdd_keep, -+ &bootenv_pdd_merge, -+ &bootenv_pdd_overwrite -+ }; -+ -+typedef enum ubi_update_process_t { -+ UBI_REMOVE = 0, -+ UBI_WRITE, -+ UBI_COMPARE, -+} ubi_update_process_t; -+ -+ -+/** -+ * skip_raw_volumes - reads data from pfi to advance fp past raw block -+ * @pfi: fp to pfi data -+ * @pfi_raws: header information -+ * -+ * Error handling): -+ * when early EOF in pfi data -+ * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err -+ * when file I/O error -+ * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err -+ **/ -+static int -+skip_raw_volumes(FILE* pfi, list_t pfi_raws, -+ char* err_buf, size_t err_buf_size) -+{ -+ int rc; -+ void *i; -+ list_t ptr; -+ -+ if (is_empty(pfi_raws)) -+ return 0; -+ -+ rc = 0; -+ foreach(i, ptr, pfi_raws) { -+ size_t j; -+ pfi_raw_t raw; -+ -+ raw = (pfi_raw_t)i; -+ for(j = 0; j < raw->data_size; j++) { -+ int c; -+ -+ c = fgetc(pfi); -+ if (c == EOF) -+ rc = -PFIFLASH_ERR_EOF; -+ else if (ferror(pfi)) -+ rc = -PFIFLASH_ERR_FIO; -+ -+ if (rc != 0) -+ goto err; -+ } -+ } -+ -+ err: -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ return rc; -+} -+ -+ -+/** -+ * my_ubi_mkvol - wraps the ubi_mkvol functions and impl. bootenv update hook -+ * @devno: UBI device number. -+ * @s: Current seqnum. -+ * @u: Information about the UBI volume from the PFI. -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ * when UBI system couldn't create a volume -+ * - returns -PFIFLASH_ERR_UBI_MKVOL, err_buf matches text to err -+ **/ -+static int -+my_ubi_mkvol(int devno, int s, pfi_ubi_t u, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc, type; -+ char path[PATH_MAX]; -+ libubi_t ulib; -+ struct ubi_mkvol_request req; -+ -+ rc = 0; -+ ulib = NULL; -+ -+ log_msg("[ ubimkvol id=%d, size=%d, data_size=%d, type=%d, " -+ "alig=%d, nlen=%d, name=%s", -+ u->ids[s], u->size, u->data_size, u->type, u->alignment, -+ strnlen(u->names[s], PFI_UBI_VOL_NAME_LEN), u->names[s]); -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ switch (u->type) { -+ case pfi_ubi_static: -+ type = UBI_STATIC_VOLUME; break; -+ case pfi_ubi_dynamic: -+ default: -+ type = UBI_DYNAMIC_VOLUME; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno); -+ -+ req.vol_id = u->ids[s]; -+ req.alignment = u->alignment; -+ req.bytes = u->size; -+ req.vol_type = type; -+ req.name = u->names[s]; -+ -+ rc = ubi_mkvol(ulib, path, &req); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_UBI_MKVOL; -+ EBUF(PFIFLASH_ERRSTR[-rc], u->ids[s]); -+ goto err; -+ } -+ -+ err: -+ if (ulib != NULL) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+ -+/** -+ * my_ubi_rmvol - a wrapper around the UBI library function ubi_rmvol -+ * @devno UBI device number -+ * @id UBI volume id to remove -+ * -+ * If the volume does not exist, the function will return success. -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ * when UBI system couldn't update (truncate) a volume -+ * - returns -PFIFLASH_ERR_UBI_VOL_UPDATE, err_buf matches text to err -+ * when UBI system couldn't remove a volume -+ * - returns -PFIFLASH_ERR_UBI_RMVOL, err_buf matches text to err -+ **/ -+static int -+my_ubi_rmvol(int devno, uint32_t id, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc, fd; -+ char path[PATH_MAX]; -+ libubi_t ulib; -+ -+ rc = 0; -+ ulib = NULL; -+ -+ log_msg("[ ubirmvol id=%d", id); -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ /* truncate whether it exist or not */ -+ fd = open(path, O_RDWR); -+ if (fd < 0) { -+ libubi_close(ulib); -+ return 0; /* not existent, return 0 */ -+ } -+ -+ rc = ubi_update_start(ulib, fd, 0); -+ close(fd); -+ if (rc < 0) { -+ rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; /* if EBUSY than empty device, continue */ -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno); -+ -+ rc = ubi_rmvol(ulib, path, id); -+ if (rc != 0) { -+#ifdef DEBUG -+ int rc_old = rc; -+ dbg_msg("Remove UBI volume %d returned with error: %d " -+ "errno=%d", id, rc_old, errno); -+#endif -+ -+ rc = -PFIFLASH_ERR_UBI_RMVOL; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ -+ /* TODO Define a ubi_rmvol return value which says -+ * sth like EUBI_NOSUCHDEV. In this case, a failed -+ * operation is acceptable. Everything else has to be -+ * classified as real error. But talk to Andreas Arnez -+ * before defining something odd... -+ */ -+ /* if ((errno == EINVAL) || (errno == ENODEV)) -+ return 0; */ /* currently it is EINVAL or ENODEV */ -+ -+ goto err; -+ } -+ -+ err: -+ if (ulib != NULL) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+ -+/** -+ * read_bootenv_volume - reads the current bootenv data from id into be_old -+ * @devno UBI device number -+ * @id UBI volume id to remove -+ * @bootenv_old to hold old boot_env data -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ * when UBI system couldn't open a volume to read -+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err -+ * when couldn't read bootenv data -+ * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err -+ **/ -+static int -+read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc; -+ FILE* fp_in; -+ char path[PATH_MAX]; -+ libubi_t ulib; -+ -+ rc = 0; -+ fp_in = NULL; -+ ulib = NULL; -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ fp_in = fopen(path, "r"); -+ if (!fp_in) { -+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ -+ log_msg("[ reading old bootenvs ..."); -+ -+ /* Save old bootenvs for reference */ -+ rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_READ; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ err: -+ if (fp_in) -+ fclose(fp_in); -+ if (ulib) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+ -+/** -+ * write_bootenv_volume - writes data from PFI file int to bootenv UBI volume -+ * @devno UBI device number -+ * @id UBI volume id -+ * @bootend_old old PDD data from machine -+ * @pdd_f function to handle PDD with -+ * @fp_in new pdd data contained in PFI -+ * @fp_in_size data size of new pdd data in PFI -+ * @pfi_crc crc value from PFI header -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ * when bootenv can't be created -+ * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err -+ * when bootenv can't be read -+ * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err -+ * when PDD handling function returns and error -+ * - passes rc and err_buf data -+ * when CRC check fails -+ * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err -+ * when bootenv can't be resized -+ * - returns -PFIFLASH_ERR_BOOTENV_SIZE, err_buf matches text to err -+ * when UBI system couldn't open a volume -+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err -+ * when couldn't write bootenv data -+ * - returns -PFIFLASH_ERR_BOOTENV_WRITE, err_buf matches text to err -+ **/ -+static int -+write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, -+ pdd_func_t pdd_f, FILE* fp_in, size_t fp_in_size, -+ uint32_t pfi_crc, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc, warnings, fd_out; -+ uint32_t crc; -+ char path[PATH_MAX]; -+ size_t update_size; -+ FILE *fp_out; -+ bootenv_t bootenv_new, bootenv_res; -+ libubi_t ulib; -+ -+ rc = 0; -+ warnings = 0; -+ crc = 0; -+ update_size = 0; -+ fp_out = NULL; -+ bootenv_new = NULL; -+ bootenv_res = NULL; -+ ulib = NULL; -+ -+ log_msg("[ ubiupdatevol bootenv id=%d, fp_in=%p", id, fp_in); -+ -+ /* Workflow: -+ * 1. Apply PDD operation and get the size of the returning -+ * bootenv_res section. Without the correct size it wouldn't -+ * be possible to call UBI update vol. -+ * 2. Call UBI update vol -+ * 3. Get FILE* to vol dev -+ * 4. Write to FILE* -+ */ -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ rc = bootenv_create(&bootenv_new); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], " 'new'"); -+ goto err; -+ } -+ -+ rc = bootenv_create(&bootenv_res); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], " 'res'"); -+ goto err; -+ } -+ -+ rc = bootenv_read_crc(fp_in, bootenv_new, fp_in_size, &crc); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_READ; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } else if (crc != pfi_crc) { -+ rc = -PFIFLASH_ERR_CRC_CHECK; -+ EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc); -+ goto err; -+ } -+ -+ rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("handling PDD"); -+ goto err; -+ } -+ else if (warnings) -+ /* TODO do something with warnings */ -+ dbg_msg("A warning in the PDD operation occured: %d", -+ warnings); -+ -+ rc = bootenv_size(bootenv_res, &update_size); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_SIZE; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ fd_out = open(path, O_RDWR); -+ if (fd_out < 0) { -+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ fp_out = fdopen(fd_out, "r+"); -+ if (!fp_out) { -+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ rc = ubi_update_start(ulib, fd_out, update_size); -+ if (rc < 0) { -+ rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ -+ rc = bootenv_write(fp_out, bootenv_res); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_WRITE; -+ EBUF(PFIFLASH_ERRSTR[-rc], devno, id); -+ goto err; -+ } -+ -+ err: -+ if (ulib != NULL) -+ libubi_close(ulib); -+ if (bootenv_new != NULL) -+ bootenv_destroy(&bootenv_new); -+ if (bootenv_res != NULL) -+ bootenv_destroy(&bootenv_res); -+ if (fp_out) -+ fclose(fp_out); -+ -+ return rc; -+} -+ -+ -+/** -+ * write_normal_volume - writes data from PFI file int to regular UBI volume -+ * @devno UBI device number -+ * @id UBI volume id -+ * @update_size size of data stream -+ * @fp_in PFI data file pointer -+ * @pfi_crc CRC data from PFI header -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ * when UBI system couldn't open a volume -+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err -+ * when unexpected EOF is encountered -+ * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err -+ * when file I/O error -+ * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err -+ * when CRC check fails -+ * - retruns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err -+ **/ -+static int -+write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in, -+ uint32_t pfi_crc, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc, fd_out; -+ uint32_t crc, crc32_table[256]; -+ char path[PATH_MAX]; -+ size_t bytes_left; -+ FILE* fp_out; -+ libubi_t ulib; -+ -+ rc = 0; -+ crc = UBI_CRC32_INIT; -+ bytes_left = update_size; -+ fp_out = NULL; -+ ulib = NULL; -+ -+ log_msg("[ ubiupdatevol id=%d, update_size=%d fp_in=%p", -+ id, update_size, fp_in); -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ fd_out = open(path, O_RDWR); -+ if (fd_out < 0) { -+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ fp_out = fdopen(fd_out, "r+"); -+ if (!fp_out) { -+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ rc = ubi_update_start(ulib, fd_out, update_size); -+ if (rc < 0) { -+ rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ -+ init_crc32_table(crc32_table); -+ while (bytes_left) { -+ char buf[1024]; -+ size_t to_rw = sizeof buf > bytes_left ? -+ bytes_left : sizeof buf; -+ if (fread(buf, 1, to_rw, fp_in) != to_rw) { -+ rc = -PFIFLASH_ERR_EOF; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ crc = clc_crc32(crc32_table, crc, buf, to_rw); -+ if (fwrite(buf, 1, to_rw, fp_out) != to_rw) { -+ rc = -PFIFLASH_ERR_FIO; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ bytes_left -= to_rw; -+ } -+ -+ if (crc != pfi_crc) { -+ rc = -PFIFLASH_ERR_CRC_CHECK; -+ EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc); -+ goto err; -+ } -+ -+ err: -+ if (fp_out) -+ fclose(fp_out); -+ if (ulib) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+static int compare_bootenv(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size, -+ uint32_t data_size, pdd_func_t pdd_f, char *err_buf, -+ size_t err_buf_size) -+{ -+ int rc, warnings = 0; -+ unsigned int i; -+ bootenv_t bootenv_pfi, bootenv_res = NULL, bootenv_flash = NULL; -+ -+ rc = bootenv_create(&bootenv_pfi); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ goto err; -+ } -+ -+ rc = bootenv_create(&bootenv_res); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ goto err; -+ } -+ -+ rc = bootenv_read(fp_pfi, bootenv_pfi, data_size); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_READ; -+ goto err; -+ } -+ -+ for (i = 0; i < ids_size; i++) { -+ rc = bootenv_create(&bootenv_flash); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ goto err; -+ } -+ -+ rc = bootenv_read(fp_flash[i], bootenv_flash, BOOTENV_MAXSIZE); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_READ; -+ goto err; -+ } -+ -+ rc = pdd_f(bootenv_flash, bootenv_pfi, &bootenv_res, -+ &warnings, err_buf, err_buf_size); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_PDD_UNKNOWN; -+ goto err; -+ } -+ -+ rc = bootenv_compare(bootenv_flash, bootenv_res); -+ if (rc > 0) { -+ rc = -PFIFLASH_CMP_DIFF; -+ goto err; -+ } else if (rc < 0) { -+ rc = -PFIFLASH_ERR_COMPARE; -+ goto err; -+ } -+ -+ bootenv_destroy(&bootenv_flash); -+ bootenv_flash = NULL; -+ } -+ -+err: -+ if (bootenv_pfi) -+ bootenv_destroy(&bootenv_pfi); -+ if (bootenv_res) -+ bootenv_destroy(&bootenv_res); -+ if (bootenv_flash) -+ bootenv_destroy(&bootenv_flash); -+ -+ return rc; -+} -+ -+static int compare_data(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size, -+ uint32_t bytes_left) -+{ -+ unsigned int i; -+ size_t read_bytes, rc = 0; -+ char buf_pfi[COMPARE_BUFFER_SIZE]; -+ char *buf_flash[ids_size]; -+ -+ for (i = 0; i < ids_size; i++) { -+ buf_flash[i] = malloc(COMPARE_BUFFER_SIZE); -+ if (!buf_flash[i]) -+ return -PFIFLASH_ERR_COMPARE; -+ } -+ -+ while (bytes_left) { -+ if (bytes_left > COMPARE_BUFFER_SIZE) -+ read_bytes = COMPARE_BUFFER_SIZE; -+ else -+ read_bytes = bytes_left; -+ -+ rc = fread(buf_pfi, 1, read_bytes, fp_pfi); -+ if (rc != read_bytes) { -+ rc = -PFIFLASH_ERR_COMPARE; -+ goto err; -+ } -+ -+ for (i = 0; i < ids_size; i++) { -+ rc = fread(buf_flash[i], 1, read_bytes, fp_flash[i]); -+ if (rc != read_bytes) { -+ rc = -PFIFLASH_CMP_DIFF; -+ goto err; -+ } -+ -+ rc = memcmp(buf_pfi, buf_flash[i], read_bytes); -+ if (rc != 0) { -+ rc = -PFIFLASH_CMP_DIFF; -+ goto err; -+ } -+ } -+ -+ bytes_left -= read_bytes; -+ } -+ -+err: -+ for (i = 0; i < ids_size; i++) -+ free(buf_flash[i]); -+ -+ return rc; -+} -+ -+static int compare_volumes(int devno, pfi_ubi_t u, FILE *fp_pfi, -+ pdd_func_t pdd_f, char *err_buf, size_t err_buf_size) -+{ -+ int rc, is_bootenv = 0; -+ unsigned int i; -+ char path[PATH_MAX]; -+ libubi_t ulib = NULL; -+ FILE *fp_flash[u->ids_size]; -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ goto err; -+ } -+ -+ for (i = 0; i < u->ids_size; i++) { -+ if (u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_1 || -+ u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_2) -+ is_bootenv = 1; -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, u->ids[i]); -+ -+ fp_flash[i] = fopen(path, "r"); -+ if (fp_flash[i] == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ goto err; -+ } -+ } -+ -+ if (is_bootenv) -+ rc = compare_bootenv(fp_pfi, fp_flash, u->ids_size, -+ u->data_size, pdd_f, err_buf, err_buf_size); -+ else -+ rc = compare_data(fp_pfi, fp_flash, u->ids_size, u->data_size); -+ -+err: -+ if (rc < 0) -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ -+ for (i = 0; i < u->ids_size; i++) -+ fclose(fp_flash[i]); -+ if (ulib) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+static int -+erase_mtd_region(FILE* file_p, int start, int length) -+{ -+ int rc, fd; -+ erase_info_t erase; -+ mtd_info_t mtdinfo; -+ loff_t offset = start; -+ loff_t end = offset + length; -+ -+ fd = fileno(file_p); -+ if (fd < 0) -+ return -PFIFLASH_ERR_MTD_ERASE; -+ -+ rc = ioctl(fd, MEMGETINFO, &mtdinfo); -+ if (rc) -+ return -PFIFLASH_ERR_MTD_ERASE; -+ -+ /* check for bad blocks in case of NAND flash */ -+ if (mtdinfo.type == MTD_NANDFLASH) { -+ while (offset < end) { -+ rc = ioctl(fd, MEMGETBADBLOCK, &offset); -+ if (rc > 0) { -+ return -PFIFLASH_ERR_MTD_ERASE; -+ } -+ -+ offset += mtdinfo.erasesize; -+ } -+ } -+ -+ erase.start = start; -+ erase.length = length; -+ -+ rc = ioctl(fd, MEMERASE, &erase); -+ if (rc) { -+ return -PFIFLASH_ERR_MTD_ERASE; -+ } -+ -+ return rc; -+} -+ -+/** -+ * process_raw_volumes - writes the raw sections of the PFI data -+ * @pfi PFI data file pointer -+ * @pfi_raws list of PFI raw headers -+ * @rawdev device to use to write raw data -+ * -+ * Error handling: -+ * when early EOF in PFI data -+ * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err -+ * when file I/O error -+ * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err -+ * when CRC check fails -+ * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err -+ * when opening MTD device fails -+ * - reutrns -PFIFLASH_ERR_MTD_OPEN, err_buf matches text to err -+ * when closing MTD device fails -+ * - returns -PFIFLASH_ERR_MTD_CLOSE, err_buf matches text to err -+ **/ -+static int -+process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, -+ char* err_buf, size_t err_buf_size) -+{ -+ int rc; -+ char *pfi_data; -+ void *i; -+ uint32_t crc, crc32_table[256]; -+ size_t j, k; -+ FILE* mtd = NULL; -+ list_t ptr; -+ -+ if (is_empty(pfi_raws)) -+ return 0; -+ -+ if (rawdev == NULL) -+ return 0; -+ -+ rc = 0; -+ -+ pfi_data = NULL; -+ -+ log_msg("[ rawupdate dev=%s", rawdev); -+ -+ crc = UBI_CRC32_INIT; -+ init_crc32_table(crc32_table); -+ -+ /* most likely only one element in list, but just in case */ -+ foreach(i, ptr, pfi_raws) { -+ pfi_raw_t r = (pfi_raw_t)i; -+ -+ /* read in pfi data */ -+ if (pfi_data != NULL) -+ free(pfi_data); -+ pfi_data = malloc(r->data_size * sizeof(char)); -+ for (j = 0; j < r->data_size; j++) { -+ int c = fgetc(pfi); -+ if (c == EOF) { -+ rc = -PFIFLASH_ERR_EOF; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } else if (ferror(pfi)) { -+ rc = -PFIFLASH_ERR_FIO; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ pfi_data[j] = (char)c; -+ } -+ crc = clc_crc32(crc32_table, crc, pfi_data, r->data_size); -+ -+ /* check crc */ -+ if (crc != r->crc) { -+ rc = -PFIFLASH_ERR_CRC_CHECK; -+ EBUF(PFIFLASH_ERRSTR[-rc], r->crc, crc); -+ goto err; -+ } -+ -+ /* open device */ -+ mtd = fopen(rawdev, "r+"); -+ if (mtd == NULL) { -+ rc = -PFIFLASH_ERR_MTD_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], rawdev); -+ goto err; -+ } -+ -+ for (j = 0; j < r->starts_size; j++) { -+ rc = erase_mtd_region(mtd, r->starts[j], r->data_size); -+ if (rc) { -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ fseek(mtd, r->starts[j], SEEK_SET); -+ for (k = 0; k < r->data_size; k++) { -+ int c = fputc((int)pfi_data[k], mtd); -+ if (c == EOF) { -+ fclose(mtd); -+ rc = -PFIFLASH_ERR_EOF; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ if ((char)c != pfi_data[k]) { -+ fclose(mtd); -+ rc = -1; -+ goto err; -+ } -+ } -+ } -+ rc = fclose(mtd); -+ mtd = NULL; -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_MTD_CLOSE; -+ EBUF(PFIFLASH_ERRSTR[-rc], rawdev); -+ goto err; -+ } -+ } -+ -+ err: -+ if (mtd != NULL) -+ fclose(mtd); -+ if (pfi_data != NULL) -+ free(pfi_data); -+ return rc; -+} -+ -+ -+/** -+ * erase_unmapped_ubi_volumes - skip volumes provided by PFI file, clear rest -+ * @devno UBI device number -+ * @pfi_ubis list of UBI header data -+ * -+ * Error handling: -+ * when UBI id is out of bounds -+ * - returns -PFIFLASH_ERR_UBI_VID_OOB, err_buf matches text to err -+ * when UBI volume can't be removed -+ * - passes rc, prepends err_buf with contextual aid -+ **/ -+static int -+erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc; -+ uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES]; -+ size_t i; -+ list_t ptr; -+ pfi_ubi_t u; -+ -+ rc = 0; -+ -+ for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) -+ ubi_volumes[i] = 1; -+ -+ foreach(u, ptr, pfi_ubis) { -+ /* iterate over each vol_id */ -+ for(i = 0; i < u->ids_size; i++) { -+ if (u->ids[i] >= PFI_UBI_MAX_VOLUMES) { -+ rc = -PFIFLASH_ERR_UBI_VID_OOB; -+ EBUF(PFIFLASH_ERRSTR[-rc], u->ids[i]); -+ goto err; -+ } -+ /* remove from removal list */ -+ ubi_volumes[u->ids[i]] = 0; -+ } -+ } -+ -+ for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { -+ if (ubi_volumes[i]) { -+ rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("remove volume failed"); -+ goto err; -+ } -+ } -+ } -+ -+ err: -+ return rc; -+} -+ -+ -+/** -+ * process_ubi_volumes - delegate tasks regarding UBI volumes -+ * @pfi PFI data file pointer -+ * @seqnum sequence number -+ * @pfi_ubis list of UBI header data -+ * @bootenv_old storage for current system PDD -+ * @pdd_f function to handle PDD -+ * @ubi_update_process whether reading or writing -+ * -+ * Error handling: -+ * when and unknown ubi_update_process is given -+ * - returns -PFIFLASH_ERR_UBI_UNKNOWN, err_buf matches text to err -+ * otherwise -+ * - passes rc and err_buf -+ **/ -+static int -+process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis, -+ bootenv_t bootenv_old, pdd_func_t pdd_f, -+ ubi_update_process_t ubi_update_process, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc; -+ pfi_ubi_t u; -+ list_t ptr; -+ -+ rc = 0; -+ -+ foreach(u, ptr, pfi_ubis) { -+ int s = seqnum; -+ -+ if (s > ((int)u->ids_size - 1)) -+ s = 0; /* per default use the first */ -+ u->curr_seqnum = s; -+ -+ switch (ubi_update_process) { -+ case UBI_REMOVE: -+ /* TODO are all these "EXAMPLE" vars okay? */ -+ if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || -+ (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { -+ rc = read_bootenv_volume(EXAMPLE_UBI_DEVICE, -+ u->ids[s], bootenv_old, -+ err_buf, err_buf_size); -+ /* it's okay if there is no bootenv -+ * we're going to write one */ -+ if ((rc == -PFIFLASH_ERR_UBI_VOL_FOPEN) || -+ (rc == -PFIFLASH_ERR_BOOTENV_READ)) -+ rc = 0; -+ if (rc != 0) -+ goto err; -+ } -+ -+ rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s], -+ err_buf, err_buf_size); -+ if (rc != 0) -+ goto err; -+ -+ break; -+ case UBI_WRITE: -+ rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("creating volume"); -+ goto err; -+ } -+ -+ if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || -+ (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { -+ rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE, -+ u->ids[s], -+ bootenv_old, pdd_f, -+ pfi, -+ u->data_size, -+ u->crc, -+ err_buf, -+ err_buf_size); -+ if (rc != 0) -+ EBUF_PREPEND("bootenv volume"); -+ } else { -+ rc = write_normal_volume(EXAMPLE_UBI_DEVICE, -+ u->ids[s], -+ u->data_size, pfi, -+ u->crc, -+ err_buf, -+ err_buf_size); -+ if (rc != 0) -+ EBUF_PREPEND("normal volume"); -+ } -+ if (rc != 0) -+ goto err; -+ -+ break; -+ case UBI_COMPARE: -+ rc = compare_volumes(EXAMPLE_UBI_DEVICE, u, pfi, pdd_f, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("compare volume"); -+ goto err; -+ } -+ -+ break; -+ default: -+ rc = -PFIFLASH_ERR_UBI_UNKNOWN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ } -+ -+ err: -+ return rc; -+} -+ -+ -+/** -+ * mirror_ubi_volumes - mirror redundant pairs of volumes -+ * @devno UBI device number -+ * @pfi_ubis list of PFI header data -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ **/ -+static int -+mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc; -+ uint32_t j; -+ list_t ptr; -+ pfi_ubi_t i; -+ libubi_t ulib; -+ -+ rc = 0; -+ ulib = NULL; -+ -+ log_msg("[ mirror ..."); -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ /** -+ * Execute all mirror operations on redundant groups. -+ * Create a volume within a redundant group if it does -+ * not exist already (this is a precondition of -+ * ubimirror). -+ */ -+ foreach(i, ptr, pfi_ubis) { -+ for (j = 0; j < i->ids_size; j++) { -+ /* skip self-match */ -+ if (i->ids[j] == i->ids[i->curr_seqnum]) -+ continue; -+ -+ rc = my_ubi_rmvol(devno, i->ids[j], -+ err_buf, err_buf_size); -+ if (rc != 0) -+ goto err; -+ -+ rc = my_ubi_mkvol(devno, j, i, -+ err_buf, err_buf_size); -+ if (rc != 0) -+ goto err; -+ } -+ } -+ -+ foreach(i, ptr, pfi_ubis) { -+ rc = ubimirror(devno, i->curr_seqnum, i->ids, i->ids_size, -+ err_buf, err_buf_size); -+ if (rc != 0) -+ goto err; -+ } -+ -+ -+ err: -+ if (ulib != NULL) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+ -+/** -+ * pfiflash_with_options - exposed func to flash memory with a PFI file -+ * @pfi PFI data file pointer -+ * @complete flag to erase unmapped volumes -+ * @seqnum sequence number -+ * @compare flag to compare -+ * @pdd_handling method to handle pdd (keep, merge, overwrite...) -+ * -+ * Error handling: -+ * when bootenv can't be created -+ * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err -+ * when PFI headers can't be read, or -+ * when fail to skip raw sections, or -+ * when error occurs while processing raw volumes, or -+ * when fail to erase unmapped UBI vols, or -+ * when error occurs while processing UBI volumes, or -+ * when error occurs while mirroring UBI volumes -+ * - passes rc, prepends err_buf with contextual aid -+ **/ -+int -+pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare, -+ pdd_handling_t pdd_handling, const char* rawdev, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc; -+ bootenv_t bootenv; -+ pdd_func_t pdd_f; -+ -+ if (pfi == NULL) -+ return -EINVAL; -+ -+ rc = 0; -+ pdd_f = NULL; -+ -+ /* If the user didnt specify a seqnum we start per default -+ * with the index 0 */ -+ int curr_seqnum = seqnum < 0 ? 0 : seqnum; -+ -+ list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */ -+ list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */ -+ -+ rc = bootenv_create(&bootenv); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], ""); -+ goto err; -+ } -+ -+ rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("reading PFI header"); -+ goto err; -+ } -+ -+ if (rawdev == NULL || compare) -+ rc = skip_raw_volumes(pfi, pfi_raws, err_buf, err_buf_size); -+ else -+ rc = process_raw_volumes(pfi, pfi_raws, rawdev, err_buf, -+ err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("handling raw section"); -+ goto err; -+ } -+ -+ if (complete && !compare) { -+ rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("deleting unmapped UBI volumes"); -+ goto err; -+ } -+ } -+ -+ if (((int)pdd_handling >= 0) && -+ (pdd_handling < PDD_HANDLING_NUM)) -+ pdd_f = pdd_funcs[pdd_handling]; -+ else { -+ rc = -PFIFLASH_ERR_PDD_UNKNOWN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ if (!compare) { -+ rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, -+ pdd_f, UBI_REMOVE, err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("removing UBI volumes"); -+ goto err; -+ } -+ -+ rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, -+ pdd_f, UBI_WRITE, err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("writing UBI volumes"); -+ goto err; -+ } -+ -+ if (seqnum < 0) { /* mirror redundant pairs */ -+ rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("mirroring UBI volumes"); -+ goto err; -+ } -+ } -+ } else { -+ /* only compare volumes, don't alter the content */ -+ rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, -+ pdd_f, UBI_COMPARE, err_buf, err_buf_size); -+ -+ if (rc == -PFIFLASH_CMP_DIFF) -+ /* update is necessary, return positive value */ -+ rc = 1; -+ -+ if (rc < 0) { -+ EBUF_PREPEND("comparing UBI volumes"); -+ goto err; -+ } -+ } -+ -+ err: -+ pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws); -+ pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis); -+ bootenv_destroy(&bootenv); -+ return rc; -+} -+ -+ -+/** -+ * pfiflash - passes to pfiflash_with_options -+ * @pfi PFI data file pointer -+ * @complete flag to erase unmapped volumes -+ * @seqnum sequence number -+ * @pdd_handling method to handle pdd (keep, merge, overwrite...) -+ **/ -+int -+pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, -+ char *err_buf, size_t err_buf_size) -+{ -+ return pfiflash_with_options(pfi, complete, seqnum, 0, pdd_handling, -+ NULL, err_buf, err_buf_size); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,915 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#include "libubi_int.h" -+ -+libubi_t libubi_open(void) -+{ -+ int fd, version; -+ struct libubi *lib; -+ -+ lib = calloc(1, sizeof(struct libubi)); -+ if (!lib) -+ return NULL; -+ -+ /* TODO: this must be discovered instead */ -+ lib->sysfs = strdup("/sys"); -+ if (!lib->sysfs) -+ goto error; -+ -+ lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI); -+ if (!lib->sysfs_ubi) -+ goto error; -+ -+ /* Make sure UBI is present */ -+ fd = open(lib->sysfs_ubi, O_RDONLY); -+ if (fd == -1) -+ goto error; -+ close(fd); -+ -+ lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT); -+ if (!lib->ubi_dev) -+ goto error; -+ -+ lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER); -+ if (!lib->ubi_version) -+ goto error; -+ -+ lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV); -+ if (!lib->dev_dev) -+ goto error; -+ -+ lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS); -+ if (!lib->dev_avail_ebs) -+ goto error; -+ -+ lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS); -+ if (!lib->dev_total_ebs) -+ goto error; -+ -+ lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT); -+ if (!lib->dev_bad_count) -+ goto error; -+ -+ lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE); -+ if (!lib->dev_eb_size) -+ goto error; -+ -+ lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC); -+ if (!lib->dev_max_ec) -+ goto error; -+ -+ lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD); -+ if (!lib->dev_bad_rsvd) -+ goto error; -+ -+ lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS); -+ if (!lib->dev_max_vols) -+ goto error; -+ -+ lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE); -+ if (!lib->dev_min_io_size) -+ goto error; -+ -+ lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT); -+ if (!lib->ubi_vol) -+ goto error; -+ -+ lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE); -+ if (!lib->vol_type) -+ goto error; -+ -+ lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV); -+ if (!lib->vol_dev) -+ goto error; -+ -+ lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT); -+ if (!lib->vol_alignment) -+ goto error; -+ -+ lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES); -+ if (!lib->vol_data_bytes) -+ goto error; -+ -+ lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS); -+ if (!lib->vol_rsvd_ebs) -+ goto error; -+ -+ lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE); -+ if (!lib->vol_eb_size) -+ goto error; -+ -+ lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED); -+ if (!lib->vol_corrupted) -+ goto error; -+ -+ lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME); -+ if (!lib->vol_name) -+ goto error; -+ -+ if (read_int(lib->ubi_version, &version)) -+ goto error; -+ if (version != LIBUBI_UBI_VERSION) { -+ fprintf(stderr, "LIBUBI: this library was made for UBI version " -+ "%d, but UBI version %d is detected\n", -+ LIBUBI_UBI_VERSION, version); -+ goto error; -+ } -+ -+ return lib; -+ -+error: -+ free(lib->vol_corrupted); -+ free(lib->vol_eb_size); -+ free(lib->vol_rsvd_ebs); -+ free(lib->vol_data_bytes); -+ free(lib->vol_alignment); -+ free(lib->vol_dev); -+ free(lib->vol_type); -+ free(lib->ubi_vol); -+ free(lib->dev_min_io_size); -+ free(lib->dev_max_vols); -+ free(lib->dev_bad_rsvd); -+ free(lib->dev_max_ec); -+ free(lib->dev_eb_size); -+ free(lib->dev_bad_count); -+ free(lib->dev_total_ebs); -+ free(lib->dev_avail_ebs); -+ free(lib->dev_dev); -+ free(lib->ubi_version); -+ free(lib->ubi_dev); -+ free(lib->sysfs_ubi); -+ free(lib->sysfs); -+ free(lib); -+ return NULL; -+} -+ -+void libubi_close(libubi_t desc) -+{ -+ struct libubi *lib = (struct libubi *)desc; -+ -+ free(lib->vol_name); -+ free(lib->vol_corrupted); -+ free(lib->vol_eb_size); -+ free(lib->vol_rsvd_ebs); -+ free(lib->vol_data_bytes); -+ free(lib->vol_alignment); -+ free(lib->vol_dev); -+ free(lib->vol_type); -+ free(lib->ubi_vol); -+ free(lib->dev_min_io_size); -+ free(lib->dev_max_vols); -+ free(lib->dev_bad_rsvd); -+ free(lib->dev_max_ec); -+ free(lib->dev_eb_size); -+ free(lib->dev_bad_count); -+ free(lib->dev_total_ebs); -+ free(lib->dev_avail_ebs); -+ free(lib->dev_dev); -+ free(lib->ubi_version); -+ free(lib->ubi_dev); -+ free(lib->sysfs_ubi); -+ free(lib->sysfs); -+ free(lib); -+} -+ -+int ubi_get_info(libubi_t desc, struct ubi_info *info) -+{ -+ DIR *sysfs_ubi; -+ struct dirent *dirent; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ memset(info, '\0', sizeof(struct ubi_info)); -+ -+ /* -+ * We have to scan the UBI sysfs directory to identify how many UBI -+ * devices are present. -+ */ -+ sysfs_ubi = opendir(lib->sysfs_ubi); -+ if (!sysfs_ubi) -+ return -1; -+ -+ info->lowest_dev_num = INT_MAX; -+ while ((dirent = readdir(sysfs_ubi))) { -+ char *name = &dirent->d_name[0]; -+ int dev_num, ret; -+ -+ ret = sscanf(name, UBI_DEV_NAME_PATT, &dev_num); -+ if (ret == 1) { -+ info->dev_count += 1; -+ if (dev_num > info->highest_dev_num) -+ info->highest_dev_num = dev_num; -+ if (dev_num < info->lowest_dev_num) -+ info->lowest_dev_num = dev_num; -+ } -+ } -+ -+ if (info->lowest_dev_num == INT_MAX) -+ info->lowest_dev_num = 0; -+ -+ if (read_int(lib->ubi_version, &info->version)) -+ goto close; -+ -+ return closedir(sysfs_ubi); -+ -+close: -+ closedir(sysfs_ubi); -+ return -1; -+} -+ -+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req) -+{ -+ int fd, ret; -+ struct ubi_mkvol_req r; -+ size_t n; -+ -+ desc = desc; -+ r.vol_id = req->vol_id; -+ r.alignment = req->alignment; -+ r.bytes = req->bytes; -+ r.vol_type = req->vol_type; -+ -+ n = strlen(req->name); -+ if (n > UBI_MAX_VOLUME_NAME) -+ return -1; -+ -+ strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1); -+ r.name_len = n; -+ -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ ret = ioctl(fd, UBI_IOCMKVOL, &r); -+ if (!ret) -+ req->vol_id = r.vol_id; -+ -+ close(fd); -+ return ret; -+} -+ -+int ubi_rmvol(libubi_t desc, const char *node, int vol_id) -+{ -+ int fd, ret; -+ -+ desc = desc; -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ ret = ioctl(fd, UBI_IOCRMVOL, &vol_id); -+ close(fd); -+ return ret; -+} -+ -+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes) -+{ -+ int fd, ret; -+ struct ubi_rsvol_req req; -+ -+ desc = desc; -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ req.bytes = bytes; -+ req.vol_id = vol_id; -+ -+ ret = ioctl(fd, UBI_IOCRSVOL, &req); -+ close(fd); -+ return ret; -+} -+ -+int ubi_update_start(libubi_t desc, int fd, long long bytes) -+{ -+ desc = desc; -+ if (ioctl(fd, UBI_IOCVOLUP, &bytes)) -+ return -1; -+ return 0; -+} -+ -+int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info) -+{ -+ int dev_num; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ dev_num = find_dev_num(lib, node); -+ if (dev_num == -1) -+ return -1; -+ -+ return ubi_get_dev_info1(desc, dev_num, info); -+} -+ -+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info) -+{ -+ DIR *sysfs_ubi; -+ struct dirent *dirent; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ memset(info, '\0', sizeof(struct ubi_dev_info)); -+ info->dev_num = dev_num; -+ -+ sysfs_ubi = opendir(lib->sysfs_ubi); -+ if (!sysfs_ubi) -+ return -1; -+ -+ info->lowest_vol_num = INT_MAX; -+ while ((dirent = readdir(sysfs_ubi))) { -+ char *name = &dirent->d_name[0]; -+ int vol_id, ret, devno; -+ -+ ret = sscanf(name, UBI_VOL_NAME_PATT, &devno, &vol_id); -+ if (ret == 2 && devno == dev_num) { -+ info->vol_count += 1; -+ if (vol_id > info->highest_vol_num) -+ info->highest_vol_num = vol_id; -+ if (vol_id < info->lowest_vol_num) -+ info->lowest_vol_num = vol_id; -+ } -+ } -+ -+ closedir(sysfs_ubi); -+ -+ if (info->lowest_vol_num == INT_MAX) -+ info->lowest_vol_num = 0; -+ -+ if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_ebs)) -+ return -1; -+ if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_ebs)) -+ return -1; -+ if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count)) -+ return -1; -+ if (dev_read_int(lib->dev_eb_size, dev_num, &info->eb_size)) -+ return -1; -+ if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd)) -+ return -1; -+ if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec)) -+ return -1; -+ if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count)) -+ return -1; -+ if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size)) -+ return -1; -+ -+ info->avail_bytes = info->avail_ebs * info->eb_size; -+ info->total_bytes = info->total_ebs * info->eb_size; -+ -+ return 0; -+} -+ -+int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info) -+{ -+ int vol_id, dev_num; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ dev_num = find_dev_num_vol(lib, node); -+ if (dev_num == -1) -+ return -1; -+ -+ vol_id = find_vol_num(lib, dev_num, node); -+ if (vol_id == -1) -+ return -1; -+ -+ return ubi_get_vol_info1(desc, dev_num, vol_id, info); -+} -+ -+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, -+ struct ubi_vol_info *info) -+{ -+ int ret; -+ struct libubi *lib = (struct libubi *)desc; -+ char buf[50]; -+ -+ memset(info, '\0', sizeof(struct ubi_vol_info)); -+ info->dev_num = dev_num; -+ info->vol_id = vol_id; -+ -+ ret = vol_read_data(lib->vol_type, dev_num, vol_id, &buf[0], 50); -+ if (ret < 0) -+ return -1; -+ -+ if (strncmp(&buf[0], "static\n", ret) == 0) -+ info->type = UBI_STATIC_VOLUME; -+ else if (strncmp(&buf[0], "dynamic\n", ret) == 0) -+ info->type = UBI_DYNAMIC_VOLUME; -+ else { -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ ret = vol_read_int(lib->vol_alignment, dev_num, vol_id, -+ &info->alignment); -+ if (ret) -+ return -1; -+ ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id, -+ &info->data_bytes); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_ebs); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->eb_size); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id, -+ &info->corrupted); -+ if (ret) -+ return -1; -+ info->rsvd_bytes = info->eb_size * info->rsvd_ebs; -+ -+ ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name, -+ UBI_VOL_NAME_MAX + 2); -+ if (ret < 0) -+ return -1; -+ -+ info->name[ret - 1] = '\0'; -+ return 0; -+} -+ -+/** -+ * read_int - read an 'int' value from a file. -+ * -+ * @file the file to read from -+ * @value the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int read_int(const char *file, int *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ -+ fd = open(file, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, &buf[0], 50); -+ if (rd == -1) -+ goto error; -+ -+ if (sscanf(&buf[0], "%d\n", value) != 1) { -+ /* This must be a UBI bug */ -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ goto error; -+ } -+ -+ close(fd); -+ return 0; -+ -+error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * dev_read_int - read an 'int' value from an UBI device's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @value the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int dev_read_int(const char *patt, int dev_num, int *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ char file[strlen(patt) + 50]; -+ -+ sprintf(&file[0], patt, dev_num); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, &buf[0], 50); -+ if (rd == -1) -+ goto error; -+ -+ if (sscanf(&buf[0], "%d\n", value) != 1) { -+ /* This must be a UBI bug */ -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ goto error; -+ } -+ -+ close(fd); -+ return 0; -+ -+error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * dev_read_ll - read a 'long long' value from an UBI device's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @value the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int dev_read_ll(const char *patt, int dev_num, long long *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ char file[strlen(patt) + 50]; -+ -+ sprintf(&file[0], patt, dev_num); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, &buf[0], 50); -+ if (rd == -1) -+ goto error; -+ -+ if (sscanf(&buf[0], "%lld\n", value) != 1) { -+ /* This must be a UBI bug */ -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ goto error; -+ } -+ -+ close(fd); -+ return 0; -+ -+error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * dev_read_data - read data from an UBI device's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @buf buffer to read data to -+ * @buf_len buffer length -+ * -+ * This function returns number of read bytes in case of success and %-1 in -+ * case of failure. -+ */ -+static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len) -+{ -+ int fd, rd; -+ char file[strlen(patt) + 50]; -+ -+ sprintf(&file[0], patt, dev_num); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, buf, buf_len); -+ if (rd == -1) { -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return rd; -+} -+ -+/** -+ * vol_read_int - read an 'int' value from an UBI volume's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @vol_id volume identifier -+ * @value the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ char file[strlen(patt) + 100]; -+ -+ sprintf(&file[0], patt, dev_num, vol_id); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, &buf[0], 50); -+ if (rd == -1) -+ goto error; -+ -+ if (sscanf(&buf[0], "%d\n", value) != 1) { -+ /* This must be a UBI bug */ -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ goto error; -+ } -+ -+ close(fd); -+ return 0; -+ -+error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * vol_read_ll - read a 'long long' value from an UBI volume's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @vol_id volume identifier -+ * @value the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int vol_read_ll(const char *patt, int dev_num, int vol_id, -+ long long *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ char file[strlen(patt) + 100]; -+ -+ sprintf(&file[0], patt, dev_num, vol_id); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, &buf[0], 50); -+ if (rd == -1) -+ goto error; -+ -+ if (sscanf(&buf[0], "%lld\n", value) != 1) { -+ /* This must be a UBI bug */ -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ goto error; -+ } -+ -+ close(fd); -+ return 0; -+ -+error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * vol_read_data - read data from an UBI volume's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @vol_id volume identifier -+ * @buf buffer to read to -+ * @buf_len buffer length -+ * -+ * This function returns number of read bytes in case of success and %-1 in -+ * case of failure. -+ */ -+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf, -+ int buf_len) -+{ -+ int fd, rd; -+ char file[strlen(patt) + 100]; -+ -+ sprintf(&file[0], patt, dev_num, vol_id); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, buf, buf_len); -+ if (rd == -1) { -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return rd; -+} -+ -+/** -+ * mkpath - compose full path from 2 given components. -+ * -+ * @path first component -+ * @name second component -+ * -+ * This function returns the resulting path in case of success and %NULL in -+ * case of failure. -+ */ -+static char *mkpath(const char *path, const char *name) -+{ -+ char *n; -+ int len1 = strlen(path); -+ int len2 = strlen(name); -+ -+ n = malloc(len1 + len2 + 2); -+ if (!n) -+ return NULL; -+ -+ memcpy(n, path, len1); -+ if (n[len1 - 1] != '/') -+ n[len1++] = '/'; -+ -+ memcpy(n + len1, name, len2 + 1); -+ return n; -+} -+ -+/** -+ * find_dev_num - find UBI device number by its character device node. -+ * -+ * @lib UBI library descriptor -+ * @node UBI character device node name -+ * -+ * This function returns positive UBI device number in case of success and %-1 -+ * in case of failure. -+ */ -+static int find_dev_num(struct libubi *lib, const char *node) -+{ -+ struct stat stat; -+ struct ubi_info info; -+ int i, major, minor; -+ -+ if (lstat(node, &stat)) -+ return -1; -+ -+ if (!S_ISCHR(stat.st_mode)) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ major = major(stat.st_rdev); -+ minor = minor(stat.st_rdev); -+ -+ if (minor != 0) { -+ errno = -EINVAL; -+ return -1; -+ } -+ -+ if (ubi_get_info((libubi_t *)lib, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ int major1, minor1, ret; -+ char buf[50]; -+ -+ ret = dev_read_data(lib->dev_dev, i, &buf[0], 50); -+ if (ret < 0) -+ return -1; -+ -+ ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1); -+ if (ret != 2) { -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ if (minor1 == minor && major1 == major) -+ return i; -+ } -+ -+ errno = ENOENT; -+ return -1; -+} -+ -+/** -+ * find_dev_num_vol - find UBI device number by volume character device node. -+ * -+ * @lib UBI library descriptor -+ * @node UBI character device node name -+ * -+ * This function returns positive UBI device number in case of success and %-1 -+ * in case of failure. -+ */ -+static int find_dev_num_vol(struct libubi *lib, const char *node) -+{ -+ struct stat stat; -+ struct ubi_info info; -+ int i, major; -+ -+ if (lstat(node, &stat)) -+ return -1; -+ -+ if (!S_ISCHR(stat.st_mode)) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ major = major(stat.st_rdev); -+ -+ if (minor(stat.st_rdev) == 0) { -+ errno = -EINVAL; -+ return -1; -+ } -+ -+ if (ubi_get_info((libubi_t *)lib, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ int major1, minor1, ret; -+ char buf[50]; -+ -+ ret = dev_read_data(lib->dev_dev, i, &buf[0], 50); -+ if (ret < 0) -+ return -1; -+ -+ ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1); -+ if (ret != 2) { -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ if (major1 == major) -+ return i; -+ } -+ -+ errno = ENOENT; -+ return -1; -+} -+ -+/** -+ * find_vol_num - find UBI volume number by its character device node. -+ * -+ * @lib UBI library descriptor -+ * @dev_num UBI device number -+ * @node UBI volume character device node name -+ * -+ * This function returns positive UBI volume number in case of success and %-1 -+ * in case of failure. -+ */ -+static int find_vol_num(struct libubi *lib, int dev_num, const char *node) -+{ -+ struct stat stat; -+ struct ubi_dev_info info; -+ int i, major, minor; -+ -+ if (lstat(node, &stat)) -+ return -1; -+ -+ if (!S_ISCHR(stat.st_mode)) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ major = major(stat.st_rdev); -+ minor = minor(stat.st_rdev); -+ -+ if (minor == 0) { -+ errno = -EINVAL; -+ return -1; -+ } -+ -+ if (ubi_get_dev_info1((libubi_t *)lib, dev_num, &info)) -+ return -1; -+ -+ for (i = info.lowest_vol_num; i <= info.highest_vol_num; i++) { -+ int major1, minor1, ret; -+ char buf[50]; -+ -+ ret = vol_read_data(lib->vol_dev, dev_num, i, &buf[0], 50); -+ if (ret < 0) -+ return -1; -+ -+ ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1); -+ if (ret != 2) { -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ if (minor1 == minor && major1 == major) -+ return i; -+ } -+ -+ errno = ENOENT; -+ return -1; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,129 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#ifndef __LIBUBI_INT_H__ -+#define __LIBUBI_INT_H__ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * UBI heavily makes use of the sysfs file system to interact with users-pace. -+ * The below are pre-define UBI file and directory names. -+ */ -+ -+#define SYSFS_UBI "class/ubi" -+#define UBI_DEV_NAME_PATT "ubi%d" -+#define UBI_VER "version" -+#define DEV_DEV "dev" -+#define UBI_VOL_NAME_PATT "ubi%d_%d" -+#define DEV_AVAIL_EBS "avail_eraseblocks" -+#define DEV_TOTAL_EBS "total_eraseblocks" -+#define DEV_BAD_COUNT "bad_peb_count" -+#define DEV_EB_SIZE "eraseblock_size" -+#define DEV_MAX_EC "max_ec" -+#define DEV_MAX_RSVD "reserved_for_bad" -+#define DEV_MAX_VOLS "max_vol_count" -+#define DEV_MIN_IO_SIZE "min_io_size" -+#define VOL_TYPE "type" -+#define VOL_DEV "dev" -+#define VOL_ALIGNMENT "alignment" -+#define VOL_DATA_BYTES "data_bytes" -+#define VOL_RSVD_EBS "reserved_ebs" -+#define VOL_EB_SIZE "usable_eb_size" -+#define VOL_CORRUPTED "corrupted" -+#define VOL_NAME "name" -+ -+/** -+ * libubi - UBI library description data structure. -+ * -+ * @sysfs sysfs file system path -+ * @sysfs_ubi UBI directory in sysfs -+ * @ubi_dev UBI device sysfs directory pattern -+ * @ubi_version UBI version file sysfs path -+ * @dev_dev UBI device's major/minor numbers file pattern -+ * @dev_avail_ebs count of available eraseblocks sysfs path pattern -+ * @dev_total_ebs total eraseblocks count sysfs path pattern -+ * @dev_bad_count count of bad eraseblocks sysfs path pattern -+ * @dev_eb_size size of UBI device's eraseblocks sysfs path pattern -+ * @dev_max_ec maximum erase counter sysfs path pattern -+ * @dev_bad_rsvd count of physical eraseblock reserved for bad eraseblocks -+ * handling -+ * @dev_max_vols maximum volumes number count sysfs path pattern -+ * @dev_min_io_size minimum I/O unit size sysfs path pattern -+ * @ubi_vol UBI volume sysfs directory pattern -+ * @vol_type volume type sysfs path pattern -+ * @vol_dev volume's major/minor numbers file pattern -+ * @vol_alignment volume alignment sysfs path pattern -+ * @vol_data_bytes volume data size sysfs path pattern -+ * @vol_rsvd_ebs volume reserved size sysfs path pattern -+ * @vol_eb_size volume eraseblock size sysfs path pattern -+ * @vol_corrupted volume corruption flag sysfs path pattern -+ * @vol_name volume name sysfs path pattern -+ */ -+struct libubi -+{ -+ char *sysfs; -+ char *sysfs_ubi; -+ char *ubi_dev; -+ char *ubi_version; -+ char *dev_dev; -+ char *dev_avail_ebs; -+ char *dev_total_ebs; -+ char *dev_bad_count; -+ char *dev_eb_size; -+ char *dev_max_ec; -+ char *dev_bad_rsvd; -+ char *dev_max_vols; -+ char *dev_min_io_size; -+ char *ubi_vol; -+ char *vol_type; -+ char *vol_dev; -+ char *vol_alignment; -+ char *vol_data_bytes; -+ char *vol_rsvd_ebs; -+ char *vol_eb_size; -+ char *vol_corrupted; -+ char *vol_name; -+ char *vol_max_count; -+}; -+ -+static int read_int(const char *file, int *value); -+static int dev_read_int(const char *patt, int dev_num, int *value); -+static int dev_read_ll(const char *patt, int dev_num, long long *value); -+static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len); -+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value); -+static int vol_read_ll(const char *patt, int dev_num, int vol_id, -+ long long *value); -+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf, -+ int buf_len); -+static char *mkpath(const char *path, const char *name); -+static int find_dev_num(struct libubi *lib, const char *node); -+static int find_dev_num_vol(struct libubi *lib, const char *node); -+static int find_vol_num(struct libubi *lib, int dev_num, const char *node); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__LIBUBI_INT_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,487 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Add UBI headers to binary data. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "config.h" -+#include "ubigen.h" -+#include "crc32.h" -+ -+#define UBI_NAME_SIZE 256 -+#define DEFAULT_VID_OFFSET ((DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE)) -+#define MIN(a,b) ((a) < (b) ? (a) : (b)) -+ -+static uint32_t crc32_table[256]; -+ -+struct ubi_info { -+ struct ubi_vid_hdr* v; /* Volume ID header */ -+ struct ubi_ec_hdr* ec; /* Erase count header */ -+ -+ FILE* fp_in; /* Input Stream */ -+ FILE* fp_out; /* Output stream */ -+ -+ size_t eb_size; /* Physical EB size in bytes */ -+ size_t leb_size; /* Size of a logical EB in a physical EB */ -+ size_t leb_total; /* Total input size in logical EB */ -+ size_t alignment; /* Block alignment */ -+ size_t data_pad; /* Size of padding in each physical EB */ -+ -+ size_t bytes_total; /* Total input size in bytes */ -+ size_t bytes_read; /* Nymber of read bytes (total) */ -+ -+ uint32_t blks_written; /* Number of written logical EB */ -+ -+ uint8_t* buf; /* Allocated buffer */ -+ uint8_t* ptr_ec_hdr; /* Pointer to EC hdr in buf */ -+ uint8_t* ptr_vid_hdr; /* Pointer to VID hdr in buf */ -+ uint8_t* ptr_data; /* Pointer to data region in buf */ -+}; -+ -+ -+static uint32_t -+byte_to_blk(uint64_t byte, uint32_t eb_size) -+{ -+ return (byte % eb_size) == 0 -+ ? (byte / eb_size) -+ : (byte / eb_size) + 1; -+} -+ -+static int -+validate_ubi_info(ubi_info_t u) -+{ -+ if ((u->v->vol_type != UBI_VID_DYNAMIC) && -+ (u->v->vol_type != UBI_VID_STATIC)) { -+ return EUBIGEN_INVALID_TYPE; -+ } -+ -+ if (be32_to_cpu(u->ec->vid_hdr_offset) < UBI_VID_HDR_SIZE) { -+ return EUBIGEN_INVALID_HDR_OFFSET; -+ } -+ -+ return 0; -+} -+ -+static int -+skip_blks(ubi_info_t u, uint32_t blks) -+{ -+ uint32_t i; -+ size_t read = 0, to_read = 0; -+ -+ /* Step to a maximum of leb_total - 1 to keep the -+ restrictions. */ -+ for (i = 0; i < MIN(blks, u->leb_total-1); i++) { -+ /* Read in data */ -+ to_read = MIN(u->leb_size, -+ (u->bytes_total - u->bytes_read)); -+ read = fread(u->ptr_data, 1, to_read, u->fp_in); -+ if (read != to_read) { -+ return -EIO; -+ } -+ u->bytes_read += read; -+ u->blks_written++; -+ } -+ -+ return 0; -+} -+ -+static void -+clear_buf(ubi_info_t u) -+{ -+ memset(u->buf, 0xff, u->eb_size); -+} -+ -+static void -+write_ec_hdr(ubi_info_t u) -+{ -+ memcpy(u->ptr_ec_hdr, u->ec, UBI_EC_HDR_SIZE); -+} -+ -+static int -+fill_data_buffer_from_file(ubi_info_t u, size_t* read) -+{ -+ size_t to_read = 0; -+ -+ if (u-> fp_in == NULL) -+ return -EIO; -+ -+ to_read = MIN(u->leb_size, (u->bytes_total - u->bytes_read)); -+ *read = fread(u->ptr_data, 1, to_read, u->fp_in); -+ if (*read != to_read) { -+ return -EIO; -+ } -+ return 0; -+} -+ -+static void -+add_static_info(ubi_info_t u, size_t data_size, ubigen_action_t action) -+{ -+ uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT, -+ u->ptr_data, data_size); -+ -+ u->v->data_size = cpu_to_be32(data_size); -+ u->v->data_crc = cpu_to_be32(crc); -+ -+ if (action & BROKEN_DATA_CRC) { -+ u->v->data_crc = -+ cpu_to_be32(be32_to_cpu(u->v->data_crc) + 1); -+ } -+ if (action & BROKEN_DATA_SIZE) { -+ u->v->data_size = -+ cpu_to_be32(be32_to_cpu(u->v->data_size) + 1); -+ } -+} -+ -+static void -+write_vid_hdr(ubi_info_t u, ubigen_action_t action) -+{ -+ uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT, -+ u->v, UBI_VID_HDR_SIZE_CRC); -+ /* Write VID header */ -+ u->v->hdr_crc = cpu_to_be32(crc); -+ if (action & BROKEN_HDR_CRC) { -+ u->v->hdr_crc = cpu_to_be32(be32_to_cpu(u->v->hdr_crc) + 1); -+ } -+ memcpy(u->ptr_vid_hdr, u->v, UBI_VID_HDR_SIZE); -+} -+ -+static int -+write_to_output_stream(ubi_info_t u) -+{ -+ size_t written; -+ -+ written = fwrite(u->buf, 1, u->eb_size, u->fp_out); -+ if (written != u->eb_size) { -+ return -EIO; -+ } -+ return 0; -+} -+ -+int -+ubigen_write_leb(ubi_info_t u, ubigen_action_t action) -+{ -+ int rc = 0; -+ size_t read = 0; -+ -+ clear_buf(u); -+ write_ec_hdr(u); -+ -+ rc = fill_data_buffer_from_file(u, &read); -+ if (rc != 0) -+ return rc; -+ -+ if (u->v->vol_type == UBI_VID_STATIC) { -+ add_static_info(u, read, action); -+ } -+ -+ u->v->lnum = cpu_to_be32(u->blks_written); -+ -+ if (action & MARK_AS_UPDATE) { -+ u->v->copy_flag = (u->v->copy_flag)++; -+ } -+ -+ write_vid_hdr(u, action); -+ rc = write_to_output_stream(u); -+ if (rc != 0) -+ return rc; -+ -+ /* Update current handle */ -+ u->bytes_read += read; -+ u->blks_written++; -+ return 0; -+} -+ -+int -+ubigen_write_complete(ubi_info_t u) -+{ -+ size_t i; -+ int rc = 0; -+ -+ for (i = 0; i < u->leb_total; i++) { -+ rc = ubigen_write_leb(u, NO_ERROR); -+ if (rc != 0) -+ return rc; -+ } -+ -+ return 0; -+} -+ -+int -+ubigen_write_broken_update(ubi_info_t u, uint32_t blk) -+{ -+ int rc = 0; -+ -+ rc = skip_blks(u, blk); -+ if (rc != 0) -+ return rc; -+ -+ rc = ubigen_write_leb(u, MARK_AS_UPDATE | BROKEN_DATA_CRC); -+ if (rc != 0) -+ return rc; -+ -+ -+ return 0; -+} -+ -+void -+dump_info(ubi_info_t u ubi_unused) -+{ -+#ifdef DEBUG -+ int err = 0; -+ if (!u) { -+ fprintf(stderr, ""); -+ return; -+ } -+ if (!u->ec) { -+ fprintf(stderr, ""); -+ err = 1; -+ } -+ if (!u->v) { -+ fprintf(stderr, ""); -+ err = 1; -+ } -+ if (err) return; -+ -+ fprintf(stderr, "ubi volume\n"); -+ fprintf(stderr, "version : %8d\n", u->v->version); -+ fprintf(stderr, "vol_id : %8d\n", be32_to_cpu(u->v->vol_id)); -+ fprintf(stderr, "vol_type : %8s\n", -+ u->v->vol_type == UBI_VID_STATIC ? -+ "static" : "dynamic"); -+ fprintf(stderr, "used_ebs : %8d\n", -+ be32_to_cpu(u->v->used_ebs)); -+ fprintf(stderr, "eb_size : 0x%08x\n", u->eb_size); -+ fprintf(stderr, "leb_size : 0x%08x\n", u->leb_size); -+ fprintf(stderr, "data_pad : 0x%08x\n", -+ be32_to_cpu(u->v->data_pad)); -+ fprintf(stderr, "leb_total : %8d\n", u->leb_total); -+ fprintf(stderr, "header offs : 0x%08x\n", -+ be32_to_cpu(u->ec->vid_hdr_offset)); -+ fprintf(stderr, "bytes_total : %8d\n", u->bytes_total); -+ fprintf(stderr, " + in MiB : %8.2f M\n", -+ ((float)(u->bytes_total)) / 1024 / 1024); -+ fprintf(stderr, "-------------------------------\n\n"); -+#else -+ return; -+#endif -+} -+ -+int -+ubigen_destroy(ubi_info_t *u) -+{ -+ if (u == NULL) -+ return -EINVAL; -+ -+ ubi_info_t tmp = *u; -+ -+ if (tmp) { -+ if (tmp->v) -+ free(tmp->v); -+ if (tmp->ec) -+ free(tmp->ec); -+ if (tmp->buf) -+ free(tmp->buf); -+ free(tmp); -+ } -+ *u = NULL; -+ return 0; -+} -+ -+void -+ubigen_init(void) -+{ -+ init_crc32_table(crc32_table); -+} -+ -+int -+ubigen_create(ubi_info_t* u, uint32_t vol_id, uint8_t vol_type, -+ uint32_t eb_size, uint64_t ec, uint32_t alignment, -+ uint8_t version, uint32_t vid_hdr_offset, uint8_t compat_flag, -+ size_t data_size, FILE* fp_in, FILE* fp_out) -+{ -+ int rc = 0; -+ ubi_info_t res = NULL; -+ uint32_t crc; -+ uint32_t data_offset; -+ -+ if (alignment == 0) { -+ rc = EUBIGEN_INVALID_ALIGNMENT; -+ goto ubigen_create_err; -+ } -+ if ((fp_in == NULL) || (fp_out == NULL)) { -+ rc = -EINVAL; -+ goto ubigen_create_err; -+ } -+ -+ res = (ubi_info_t) calloc(1, sizeof(struct ubi_info)); -+ if (res == NULL) { -+ rc = -ENOMEM; -+ goto ubigen_create_err; -+ } -+ -+ res->v = (struct ubi_vid_hdr*) calloc(1, sizeof(struct ubi_vid_hdr)); -+ if (res->v == NULL) { -+ rc = -ENOMEM; -+ goto ubigen_create_err; -+ } -+ -+ res->ec = (struct ubi_ec_hdr*) calloc(1, sizeof(struct ubi_ec_hdr)); -+ if (res->ec == NULL) { -+ rc = -ENOMEM; -+ goto ubigen_create_err; -+ } -+ -+ /* data which is needed in the general process */ -+ vid_hdr_offset = vid_hdr_offset ? vid_hdr_offset : DEFAULT_VID_OFFSET; -+ data_offset = vid_hdr_offset + UBI_VID_HDR_SIZE; -+ res->bytes_total = data_size; -+ res->eb_size = eb_size ? eb_size : DEFAULT_BLOCKSIZE; -+ res->data_pad = (res->eb_size - data_offset) % alignment; -+ res->leb_size = res->eb_size - data_offset - res->data_pad; -+ res->leb_total = byte_to_blk(data_size, res->leb_size); -+ res->alignment = alignment; -+ -+ if ((res->eb_size < (vid_hdr_offset + UBI_VID_HDR_SIZE))) { -+ rc = EUBIGEN_TOO_SMALL_EB; -+ goto ubigen_create_err; -+ } -+ res->fp_in = fp_in; -+ res->fp_out = fp_out; -+ -+ /* vid hdr data which doesn't change */ -+ res->v->magic = cpu_to_be32(UBI_VID_HDR_MAGIC); -+ res->v->version = version ? version : UBI_VERSION; -+ res->v->vol_type = vol_type; -+ res->v->vol_id = cpu_to_be32(vol_id); -+ res->v->compat = compat_flag; -+ res->v->data_pad = cpu_to_be32(res->data_pad); -+ -+ /* static only: used_ebs */ -+ if (res->v->vol_type == UBI_VID_STATIC) { -+ res->v->used_ebs = cpu_to_be32(byte_to_blk -+ (res->bytes_total, -+ res->leb_size)); -+ } -+ -+ /* ec hdr (fixed, doesn't change) */ -+ res->ec->magic = cpu_to_be32(UBI_EC_HDR_MAGIC); -+ res->ec->version = version ? version : UBI_VERSION; -+ res->ec->ec = cpu_to_be64(ec); -+ res->ec->vid_hdr_offset = cpu_to_be32(vid_hdr_offset); -+ -+ res->ec->data_offset = cpu_to_be32(data_offset); -+ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, res->ec, -+ UBI_EC_HDR_SIZE_CRC); -+ res->ec->hdr_crc = cpu_to_be32(crc); -+ -+ /* prepare a read buffer */ -+ res->buf = (uint8_t*) malloc (res->eb_size * sizeof(uint8_t)); -+ if (res->buf == NULL) { -+ rc = -ENOMEM; -+ goto ubigen_create_err; -+ } -+ -+ /* point to distinct regions within the buffer */ -+ res->ptr_ec_hdr = res->buf; -+ res->ptr_vid_hdr = res->buf + be32_to_cpu(res->ec->vid_hdr_offset); -+ res->ptr_data = res->buf + be32_to_cpu(res->ec->vid_hdr_offset) -+ + UBI_VID_HDR_SIZE; -+ -+ rc = validate_ubi_info(res); -+ if (rc != 0) { -+ fprintf(stderr, "Volume validation failed: %d\n", rc); -+ goto ubigen_create_err; -+ } -+ -+ dump_info(res); -+ *u = res; -+ return rc; -+ -+ ubigen_create_err: -+ if (res) { -+ if (res->v) -+ free(res->v); -+ if (res->ec) -+ free(res->ec); -+ if (res->buf) -+ free(res->buf); -+ free(res); -+ } -+ *u = NULL; -+ return rc; -+} -+ -+int -+ubigen_get_leb_size(ubi_info_t u, size_t* size) -+{ -+ if (u == NULL) -+ return -EINVAL; -+ -+ *size = u->leb_size; -+ return 0; -+} -+ -+ -+int -+ubigen_get_leb_total(ubi_info_t u, size_t* total) -+{ -+ if (u == NULL) -+ return -EINVAL; -+ -+ *total = u->leb_total; -+ return 0; -+} -+ -+int -+ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes, -+ const char* vol_name, struct ubi_vtbl_record *lvol_rec) -+{ -+ uint32_t crc; -+ -+ if ((u == NULL) || (vol_name == NULL)) -+ return -EINVAL; -+ -+ memset(lvol_rec, 0x0, UBI_VTBL_RECORD_SIZE); -+ -+ lvol_rec->reserved_pebs = -+ cpu_to_be32(byte_to_blk(reserved_bytes, u->leb_size)); -+ lvol_rec->alignment = cpu_to_be32(u->alignment); -+ lvol_rec->data_pad = u->v->data_pad; -+ lvol_rec->vol_type = u->v->vol_type; -+ -+ lvol_rec->name_len = -+ cpu_to_be16((uint16_t)strlen((const char*)vol_name)); -+ -+ memcpy(lvol_rec->name, vol_name, UBI_VOL_NAME_MAX + 1); -+ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, -+ lvol_rec, UBI_VTBL_RECORD_SIZE_CRC); -+ lvol_rec->crc = cpu_to_be32(crc); -+ -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,237 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "ubimirror.h" -+ -+#define COMPARE_BUF_SIZE (128 * 1024) -+ -+#define DEFAULT_DEV_PATTERN "/dev/ubi%d" -+#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d" -+ -+#define EBUF(fmt...) do { \ -+ snprintf(err_buf, err_buf_size, fmt); \ -+} while (0) -+ -+enum { -+ compare_error = -1, -+ seek_error = -2, -+ write_error = -3, -+ read_error = -4, -+ update_error = -5, -+ ubi_error = -6, -+ open_error = -7, -+ close_error = -8, -+ compare_equal = 0, -+ compare_different = 1 -+}; -+ -+/* -+ * Read len number of bytes from fd. -+ * Return 0 on EOF, -1 on error. -+ */ -+static ssize_t fill_buffer(int fd, unsigned char *buf, ssize_t len) -+{ -+ ssize_t got, have = 0; -+ -+ do { -+ got = read(fd, buf + have, len - have); -+ if (got == -1 && errno != EINTR) -+ return -1; -+ have += got; -+ } while (got > 0 && have < len); -+ return have; -+} -+ -+/* -+ * Write len number of bytes to fd. -+ * Return bytes written (>= 0), -1 on error. -+ */ -+static ssize_t flush_buffer(int fd, unsigned char *buf, ssize_t len) -+{ -+ ssize_t done, have = 0; -+ -+ do { -+ done = write(fd, buf + have, len - have); -+ if (done == -1 && errno != EINTR) -+ return -1; -+ have += done; -+ } while (done > 0 && have < len); -+ return have; -+} -+ -+/* -+ * Compare two files. Return 0, 1, or -1, depending on whether the -+ * files are equal, different, or an error occured. -+ * Return compare-different when target volume can not be read. Might be -+ * an interrupted volume update and then the target device returns -EIO but -+ * can be updated. -+ * -+ * fd_a is source -+ * fd_b is destination -+ */ -+static int compare_files(int fd_a, int fd_b) -+{ -+ unsigned char buf_a[COMPARE_BUF_SIZE], buf_b[COMPARE_BUF_SIZE]; -+ ssize_t len_a, len_b; -+ int rc; -+ -+ for (;;) { -+ len_a = fill_buffer(fd_a, buf_a, sizeof(buf_a)); -+ if (len_a == -1) { -+ rc = compare_error; -+ break; -+ } -+ len_b = fill_buffer(fd_b, buf_b, sizeof(buf_b)); -+ if (len_b == -1) { -+ rc = compare_different; -+ break; -+ } -+ if (len_a != len_b) { -+ rc = compare_different; -+ break; -+ } -+ if (len_a == 0) { /* Size on both files equal and EOF */ -+ rc = compare_equal; -+ break; -+ } -+ if (memcmp(buf_a, buf_b, len_a) != 0 ) { -+ rc = compare_different; -+ break; -+ } -+ } -+ /* Position both files at the beginning */ -+ if (lseek(fd_a, 0, SEEK_SET) == -1 || -+ lseek(fd_b, 0, SEEK_SET) == -1) -+ rc = seek_error; -+ return rc; -+} -+ -+int vol_get_used_bytes(int vol_fd, unsigned long long *bytes) -+{ -+ off_t res; -+ -+ res = lseek(vol_fd, 0, SEEK_END); -+ if (res == (off_t)-1) -+ return -1; -+ *bytes = (unsigned long long) res; -+ res = lseek(vol_fd, 0, SEEK_SET); -+ return res == (off_t)-1 ? -1 : 0; -+} -+ -+static int copy_files(libubi_t ulib, int fd_in, int fd_out) -+{ -+ unsigned char buf_a[COMPARE_BUF_SIZE]; -+ ssize_t len_a, len_b; -+ unsigned long long update_size, copied; -+ -+ if (vol_get_used_bytes(fd_in, &update_size) == -1 || -+ ubi_update_start(ulib, fd_out, update_size) == -1) -+ return update_error; -+ for (copied = 0; copied < update_size; copied += len_b ) { -+ len_a = fill_buffer(fd_in, buf_a, sizeof(buf_a)); -+ if (len_a == -1) -+ return read_error; -+ if (len_a == 0) /* Reach EOF */ -+ return 0; -+ len_b = flush_buffer(fd_out, buf_a, len_a); -+ if (len_b != len_a) -+ return write_error; -+ } -+ return 0; -+} -+ -+int ubimirror(uint32_t devno, int seqnum, uint32_t *ids, ssize_t ids_size, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc = 0; -+ uint32_t src_id; -+ char path[PATH_MAX]; -+ libubi_t ulib; -+ int fd_in = -1, i = 0, fd_out = -1; -+ -+ if (ids_size == 0) -+ return 0; -+ else { -+ if ((seqnum < 0) || (seqnum > (ids_size - 1))) { -+ EBUF("volume id %d out of range", seqnum); -+ return EUBIMIRROR_NO_SRC; -+ } -+ src_id = ids[seqnum]; -+ } -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) -+ return ubi_error; -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, src_id); -+ -+ fd_in = open(path, O_RDONLY); -+ if (fd_in == -1) { -+ EBUF("open error source volume %d", ids[i]); -+ rc = open_error; -+ goto err; -+ } -+ -+ for (i = 0; i < ids_size; i++) { -+ if (ids[i] == src_id) /* skip self-mirror */ -+ continue; -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, ids[i]); -+ -+ fd_out = open(path, O_RDWR); -+ if (fd_out < 0){ -+ EBUF("open error destination volume %d", ids[i]); -+ rc = open_error; -+ goto err; -+ } -+ rc = compare_files(fd_in, fd_out); -+ if (rc < 0) { -+ EBUF("compare error volume %d and %d", src_id, ids[i]); -+ goto err; -+ } else if (rc == compare_different) { -+ rc = copy_files(ulib, fd_in, fd_out); -+ if (rc != 0) { -+ EBUF("mirror error volume %d to %d", src_id, -+ ids[i]); -+ goto err; -+ } -+ } -+ if ((rc = close(fd_out)) == -1) { -+ EBUF("close error volume %d", ids[i]); -+ rc = close_error; -+ goto err; -+ } else -+ fd_out = -1; -+ } -+err: -+ if (fd_out != -1) -+ close(fd_out); -+ if (fd_in != -1) -+ close(fd_in); -+ if (ulib != NULL) -+ libubi_close(ulib); -+ return rc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/list.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/list.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,149 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+#include -+ -+#include "list.h" -+ -+list_t -+mk_empty(void) -+{ -+ return (list_t) NULL; -+} -+ -+int -+is_empty(list_t l) -+{ -+ return l == NULL; -+} -+ -+info_t -+head(list_t l) -+{ -+ assert(!is_empty(l)); -+ return l->info; -+} -+ -+list_t -+tail(list_t l) -+{ -+ assert(!is_empty(l)); -+ return l->next; -+} -+ -+list_t -+remove_head(list_t l) -+{ -+ list_t res; -+ assert(!is_empty(l)); -+ -+ res = l->next; -+ free(l); -+ return res; -+} -+ -+list_t -+cons(info_t e, list_t l) -+{ -+ list_t res = malloc(sizeof(*l)); -+ if (!res) -+ return NULL; -+ res->info = e; -+ res->next = l; -+ -+ return res; -+} -+ -+list_t -+prepend_elem(info_t e, list_t l) -+{ -+ return cons(e,l); -+} -+ -+list_t -+append_elem(info_t e, list_t l) -+{ -+ if (is_empty(l)) { -+ return cons(e,l); -+ } -+ l->next = append_elem(e, l->next); -+ -+ return l; -+} -+ -+list_t -+insert_sorted(cmp_func_t cmp, info_t e, list_t l) -+{ -+ if (is_empty(l)) -+ return cons(e, l); -+ -+ switch (cmp(e, l->info)) { -+ case -1: -+ case 0: -+ return l; -+ break; -+ case 1: -+ l->next = insert_sorted(cmp, e, l); -+ break; -+ default: -+ break; -+ } -+ -+ /* never reached */ -+ return NULL; -+} -+ -+list_t -+remove_all(free_func_t free_func, list_t l) -+{ -+ if (is_empty(l)) -+ return l; -+ list_t lnext = l->next; -+ -+ if (free_func && l->info) { -+ free_func(&(l->info)); -+ } -+ free(l); -+ -+ return remove_all(free_func, lnext); -+} -+ -+ -+info_t -+is_in(cmp_func_t cmp, info_t e, list_t l) -+{ -+ return -+ (is_empty(l)) -+ ? NULL -+ : (cmp(e, l->info)) == 0 ? l->info : is_in(cmp, e, l->next); -+} -+ -+ -+void -+apply(process_func_t process_func, list_t l) -+{ -+ list_t ptr; -+ void *i; -+ foreach(i, ptr, l) { -+ process_func(i); -+ } -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/list.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/list.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,56 @@ -+#ifndef __LIST_H__ -+#define __LIST_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+ -+#define foreach(elem, ptr, list) \ -+ for (elem = list != NULL ? (typeof(elem)) head(list) \ -+ : NULL, ptr = list; \ -+ ptr != NULL; \ -+ ptr = tail(ptr), \ -+ elem = (typeof(elem)) ptr ? head(ptr) : NULL) -+ -+typedef struct node* list_t; -+typedef void* info_t; -+typedef int (*free_func_t)(info_t*); -+typedef int (*cmp_func_t)(info_t, info_t); -+typedef void (*process_func_t)(info_t); -+ -+struct node { -+ list_t next; -+ info_t info; -+}; -+ -+list_t mk_empty(void); -+int is_empty(list_t l); -+info_t is_in(cmp_func_t cmp, info_t e, list_t l); -+info_t head(list_t l); -+list_t tail(list_t l); -+list_t remove_head(list_t l); -+list_t cons(info_t e, list_t l); -+list_t prepend_elem(info_t e, list_t); -+list_t append_elem(info_t e, list_t); -+list_t remove_all(free_func_t free_func, list_t l); -+list_t insert_sorted(cmp_func_t cmp_func, info_t e, list_t l); -+void apply(process_func_t process_func, list_t l); -+ -+#endif /* __LIST_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,168 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Create boot-parameter/pdd data from an ASCII-text input file. -+ * -+ * 1.2 Removed argp because we want to use uClibc. -+ * 1.3 Minor cleanup -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "config.h" -+#include "bootenv.h" -+#include "error.h" -+ -+#define PROGRAM_VERSION "1.3" -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "mkbootenv - processes bootenv text files and convertes " -+ "them into a binary format.\n"; -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright (c) International Business Machines Corp., 2006"; -+ -+static const char *optionsstr = -+" -c, --copyright Print copyright informatoin.\n" -+" -o, --output= Write the output data to instead of\n" -+" stdout.\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: mkbootenv [-c?V] [-o ] [--copyright] [--output=]\n" -+" [--help] [--usage] [--version] [bootenv-txt-file]\n"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+typedef struct myargs { -+ FILE* fp_in; -+ FILE* fp_out; -+ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "co:?V", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'c': -+ fprintf(stderr, "%s\n", copyright); -+ exit(0); -+ break; -+ case 'o': -+ args->fp_out = fopen(optarg, "wb"); -+ if ((args->fp_out) == NULL) { -+ fprintf(stderr, "Cannot open file %s " -+ "for output\n", optarg); -+ exit(1); -+ } -+ break; -+ case '?': /* help */ -+ printf("%s", doc); -+ printf("%s", optionsstr); -+ printf("\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ case 'V': -+ printf("%s\n", PROGRAM_VERSION); -+ exit(0); -+ break; -+ default: -+ printf("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) { -+ args->fp_in = fopen(argv[optind++], "rb"); -+ if ((args->fp_in) == NULL) { -+ fprintf(stderr, "Cannot open file %s for input\n", -+ argv[optind]); -+ exit(1); -+ } -+ } -+ -+ return 0; -+} -+ -+int -+main(int argc, char **argv) { -+ int rc = 0; -+ bootenv_t env; -+ -+ myargs args = { -+ .fp_in = stdin, -+ .fp_out = stdout, -+ .arg1 = NULL, -+ .options = NULL, -+ }; -+ -+ parse_opt(argc, argv, &args); -+ -+ rc = bootenv_create(&env); -+ if (rc != 0) { -+ err_msg("Cannot create bootenv handle."); -+ goto err; -+ } -+ rc = bootenv_read_txt(args.fp_in, env); -+ if (rc != 0) { -+ err_msg("Cannot read bootenv from input file."); -+ goto err; -+ } -+ rc = bootenv_write(args.fp_out, env); -+ if (rc != 0) { -+ err_msg("Cannot write bootenv to output file."); -+ goto err; -+ } -+ -+ if (args.fp_in != stdin) { -+ fclose(args.fp_in); -+ } -+ if (args.fp_out != stdout) { -+ fclose(args.fp_out); -+ } -+ -+err: -+ bootenv_destroy(&env); -+ return rc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,493 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Frank Haverkamp -+ * -+ * An utility to decompose NAND images and strip OOB off. Not yet finished ... -+ * -+ * 1.2 Removed argp because we want to use uClibc. -+ * 1.3 Minor cleanup -+ * 1.4 Fixed OOB output file -+ * 1.5 Added verbose output and option to set blocksize. -+ * Added split block mode for more convenient analysis. -+ * 1.6 Fixed ECC error detection and correction. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "config.h" -+#include "nandecc.h" -+ -+#define PROGRAM_VERSION "1.6" -+ -+#define MAXPATH 1024 -+#define MIN(x,y) ((x)<(y)?(x):(y)) -+ -+struct args { -+ const char *oob_file; -+ const char *output_file; -+ size_t pagesize; -+ size_t blocksize; -+ int split_blocks; -+ size_t in_len; /* size of input file */ -+ int correct_ecc; -+ -+ /* special stuff needed to get additional arguments */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+}; -+ -+static struct args myargs = { -+ .output_file = "data.bin", -+ .oob_file = "oob.bin", -+ .pagesize = 2048, -+ .blocksize = 128 * 1024, -+ .in_len = 0, -+ .split_blocks = 0, -+ .correct_ecc = 0, -+ .arg1 = NULL, -+ .options = NULL, -+}; -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "nand2bin - split data and OOB.\n"; -+ -+static const char *optionsstr = -+" -o, --output= Data output file\n" -+" -O, --oob= OOB output file\n" -+" -p, --pagesize= NAND pagesize\n" -+" -b, --blocksize= NAND blocksize\n" -+" -s, --split-blocks generate binaries for each block\n" -+" -e, --correct-ecc Correct data according to ECC info\n" -+" -v, --verbose verbose output\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n"; -+ -+static const char *usage = -+"Usage: nand2bin [-?] [-o ] [-O ] [-p ]\n" -+" [--output=] [--oob=] [--pagesize=] [--help]\n" -+" [--usage] input.mif\n"; -+ -+static int verbose = 0; -+ -+static struct option long_options[] = { -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "oob", .has_arg = 1, .flag = NULL, .val = 'O' }, -+ { .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' }, -+ { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' }, -+ { .name = "split-blocks", .has_arg = 0, .flag = NULL, .val = 's' }, -+ { .name = "correct-ecc", .has_arg = 0, .flag = NULL, .val = 'e' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { NULL, 0, NULL, 0} -+}; -+ -+/* -+ * str_to_num - Convert string into number and cope with endings like -+ * k, K, kib, KiB for kilobyte -+ * m, M, mib, MiB for megabyte -+ */ -+static uint32_t str_to_num(char *str) -+{ -+ char *s = str; -+ ulong num = strtoul(s, &s, 0); -+ -+ if (*s != '\0') { -+ if (strcmp(s, "KiB") == 0) -+ num *= 1024; -+ else if (strcmp(s, "MiB") == 0) -+ num *= 1024*1024; -+ else { -+ fprintf(stderr, "WARNING: Wrong number format " -+ "\"%s\", check your paramters!\n", str); -+ } -+ } -+ return num; -+} -+ -+/* -+ * @brief Parse the arguments passed into the test case. -+ * -+ * @param argc The number of arguments -+ * @param argv The argument list -+ * @param args Pointer to program args structure -+ * -+ * @return error -+ * -+ */ -+static int parse_opt(int argc, char **argv, struct args *args) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "b:eo:O:p:sv?", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'p': /* --pagesize */ -+ args->pagesize = str_to_num(optarg); -+ break; -+ -+ case 'b': /* --blocksize */ -+ args->blocksize = str_to_num(optarg); -+ break; -+ -+ case 'v': /* --verbose */ -+ verbose++; -+ break; -+ -+ case 's': /* --split-blocks */ -+ args->split_blocks = 1; -+ break; -+ -+ case 'e': /* --correct-ecc */ -+ args->correct_ecc = 1; -+ break; -+ -+ case 'o': /* --output= */ -+ args->output_file = optarg; -+ break; -+ -+ case 'O': /* --oob= */ -+ args->oob_file = optarg; -+ break; -+ -+ case '?': /* help */ -+ printf("Usage: nand2bin [OPTION...] input.mif\n"); -+ printf("%s", doc); -+ printf("%s", optionsstr); -+ printf("\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ -+ case 'V': -+ printf("%s\n", PROGRAM_VERSION); -+ exit(0); -+ break; -+ -+ default: -+ printf("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) -+ args->arg1 = argv[optind++]; -+ -+ return 0; -+} -+ -+static int calc_oobsize(size_t pagesize) -+{ -+ switch (pagesize) { -+ case 512: return 16; -+ case 2048: return 64; -+ default: -+ exit(EXIT_FAILURE); -+ } -+ return 0; -+} -+ -+static inline void hexdump(FILE *fp, const uint8_t *buf, ssize_t size) -+{ -+ int k; -+ -+ for (k = 0; k < size; k++) { -+ fprintf(fp, "%02x ", buf[k]); -+ if ((k & 15) == 15) -+ fprintf(fp, "\n"); -+ } -+} -+ -+static int process_page(uint8_t* buf, uint8_t *oobbuf, size_t pagesize) -+{ -+ int eccpoi, oobsize; -+ size_t i; -+ -+ switch (pagesize) { -+ case 2048: oobsize = 64; eccpoi = 64 / 2; break; -+ case 512: oobsize = 16; eccpoi = 16 / 2; break; -+ default: -+ fprintf(stderr, "Unsupported page size: %zd\n", pagesize); -+ return -EINVAL; -+ } -+ memset(oobbuf, 0xff, oobsize); -+ -+ for (i = 0; i < pagesize; i += 256, eccpoi += 3) { -+ oobbuf[eccpoi++] = 0x0; -+ /* Calculate ECC */ -+ nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]); -+ } -+ return 0; -+} -+ -+static int bad_marker_offs_in_oob(int pagesize) -+{ -+ switch (pagesize) { -+ case 2048: return 0; -+ case 512: return 5; -+ } -+ return -EINVAL; -+} -+ -+static int decompose_image(struct args *args, FILE *in_fp, -+ FILE *bin_fp, FILE *oob_fp) -+{ -+ int read, rc, page = 0; -+ size_t oobsize = calc_oobsize(args->pagesize); -+ uint8_t *buf = malloc(args->pagesize); -+ uint8_t *oob = malloc(oobsize); -+ uint8_t *calc_oob = malloc(oobsize); -+ uint8_t *calc_buf = malloc(args->pagesize); -+ uint8_t *page_buf; -+ int pages_per_block = args->blocksize / args->pagesize; -+ int eccpoi = 0, eccpoi_start; -+ unsigned int i; -+ int badpos = bad_marker_offs_in_oob(args->pagesize); -+ -+ switch (args->pagesize) { -+ case 2048: eccpoi_start = 64 / 2; break; -+ case 512: eccpoi_start = 16 / 2; break; -+ default: exit(EXIT_FAILURE); -+ } -+ -+ if (!buf) -+ exit(EXIT_FAILURE); -+ if (!oob) -+ exit(EXIT_FAILURE); -+ if (!calc_oob) -+ exit(EXIT_FAILURE); -+ if (!calc_buf) -+ exit(EXIT_FAILURE); -+ -+ while (!feof(in_fp)) { -+ /* read page by page */ -+ read = fread(buf, 1, args->pagesize, in_fp); -+ if (ferror(in_fp)) { -+ fprintf(stderr, "I/O Error."); -+ exit(EXIT_FAILURE); -+ } -+ if (read != (ssize_t)args->pagesize) -+ break; -+ -+ read = fread(oob, 1, oobsize, in_fp); -+ if (ferror(in_fp)) { -+ fprintf(stderr, "I/O Error."); -+ exit(EXIT_FAILURE); -+ } -+ -+ page_buf = buf; /* default is unmodified data */ -+ -+ if ((page == 0 || page == 1) && (oob[badpos] != 0xff)) { -+ if (verbose) -+ printf("Block %d is bad\n", -+ page / pages_per_block); -+ goto write_data; -+ } -+ if (args->correct_ecc) -+ page_buf = calc_buf; -+ -+ process_page(buf, calc_oob, args->pagesize); -+ memcpy(calc_buf, buf, args->pagesize); -+ -+ /* -+ * Our oob format uses only the last 3 bytes out of 4. -+ * The first byte is 0x00 when the ECC is generated by -+ * our toolset and 0xff when generated by Linux. This -+ * is to be fixed when we want nand2bin work for other -+ * ECC layouts too. -+ */ -+ for (i = 0, eccpoi = eccpoi_start; i < args->pagesize; -+ i += 256, eccpoi += 4) -+ oob[eccpoi] = calc_oob[eccpoi] = 0xff; -+ -+ if (verbose && memcmp(oob, calc_oob, oobsize) != 0) { -+ printf("\nECC compare mismatch found at block %d page %d!\n", -+ page / pages_per_block, page % pages_per_block); -+ -+ printf("Read out OOB Data:\n"); -+ hexdump(stdout, oob, oobsize); -+ -+ printf("Calculated OOB Data:\n"); -+ hexdump(stdout, calc_oob, oobsize); -+ } -+ -+ /* Do correction on subpage base */ -+ for (i = 0, eccpoi = eccpoi_start; i < args->pagesize; -+ i += 256, eccpoi += 4) { -+ rc = nand_correct_data(calc_buf + i, &oob[eccpoi + 1], -+ &calc_oob[eccpoi + 1]); -+ -+ if (rc == -1) -+ fprintf(stdout, "Uncorrectable ECC error at " -+ "block %d page %d/%d\n", -+ page / pages_per_block, -+ page % pages_per_block, i / 256); -+ else if (rc > 0) -+ fprintf(stdout, "Correctable ECC error at " -+ "block %d page %d/%d\n", -+ page / pages_per_block, -+ page % pages_per_block, i / 256); -+ } -+ -+ write_data: -+ rc = fwrite(page_buf, 1, args->pagesize, bin_fp); -+ if (ferror(bin_fp)) { -+ fprintf(stderr, "I/O Error."); -+ exit(EXIT_FAILURE); -+ } -+ rc = fwrite(oob, 1, oobsize, oob_fp); -+ if (ferror(bin_fp)) { -+ fprintf(stderr, "I/O Error."); -+ exit(EXIT_FAILURE); -+ } -+ -+ page++; -+ } -+ free(calc_buf); -+ free(calc_oob); -+ free(oob); -+ free(buf); -+ return 0; -+} -+ -+static int split_blocks(struct args *args, FILE *in_fp) -+{ -+ uint8_t *buf; -+ size_t oobsize = calc_oobsize(args->pagesize); -+ int pages_per_block = args->blocksize / args->pagesize; -+ int block_len = pages_per_block * (args->pagesize + oobsize); -+ int blocks = args->in_len / block_len; -+ char bname[256] = { 0, }; -+ int badpos = bad_marker_offs_in_oob(args->pagesize); -+ int bad_blocks = 0, i, bad_block = 0; -+ ssize_t rc; -+ FILE *b; -+ -+ buf = malloc(block_len); -+ if (!buf) { -+ perror("Not enough memory"); -+ exit(EXIT_FAILURE); -+ } -+ -+ for (i = 0; i < blocks; i++) { -+ rc = fread(buf, 1, block_len, in_fp); -+ if (rc != block_len) { -+ fprintf(stderr, "cannot read enough data!\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ /* do block analysis */ -+ bad_block = 0; -+ if ((buf[args->pagesize + badpos] != 0xff) || -+ (buf[2 * args->pagesize + oobsize + badpos] != 0xff)) { -+ bad_blocks++; -+ bad_block = 1; -+ } -+ if ((verbose && bad_block) || (verbose > 1)) { -+ printf("-- (block %d oob of page 0 and 1)\n", i); -+ hexdump(stdout, buf + args->pagesize, oobsize); -+ printf("--\n"); -+ hexdump(stdout, buf + 2 * args->pagesize + -+ oobsize, oobsize); -+ } -+ -+ /* write complete block out */ -+ snprintf(bname, sizeof(bname) - 1, "%s.%d", args->arg1, i); -+ b = fopen(bname, "w+"); -+ if (!b) { -+ perror("Cannot open file"); -+ exit(EXIT_FAILURE); -+ } -+ rc = fwrite(buf, 1, block_len, b); -+ if (rc != block_len) { -+ fprintf(stderr, "could not write all data!\n"); -+ exit(EXIT_FAILURE); -+ } -+ fclose(b); -+ } -+ -+ free(buf); -+ if (bad_blocks || verbose) -+ fprintf(stderr, "%d blocks, %d bad blocks\n", -+ blocks, bad_blocks); -+ return 0; -+} -+ -+int -+main(int argc, char *argv[]) -+{ -+ FILE *in, *bin = NULL, *oob = NULL; -+ struct stat file_info; -+ -+ parse_opt(argc, argv, &myargs); -+ -+ if (!myargs.arg1) { -+ fprintf(stderr, "Please specify input file!\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (lstat(myargs.arg1, &file_info) != 0) { -+ perror("Cannot fetch file size from input file.\n"); -+ exit(EXIT_FAILURE); -+ } -+ myargs.in_len = file_info.st_size; -+ -+ in = fopen(myargs.arg1, "r"); -+ if (!in) { -+ perror("Cannot open file"); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (myargs.split_blocks) { -+ split_blocks(&myargs, in); -+ goto out; -+ } -+ -+ bin = fopen(myargs.output_file, "w+"); -+ if (!bin) { -+ perror("Cannot open file"); -+ exit(EXIT_FAILURE); -+ } -+ oob = fopen(myargs.oob_file, "w+"); -+ if (!oob) { -+ perror("Cannot open file"); -+ exit(EXIT_FAILURE); -+ } -+ decompose_image(&myargs, in, bin, oob); -+ -+ out: -+ if (in) fclose(in); -+ if (bin) fclose(bin); -+ if (oob) fclose(oob); -+ exit(EXIT_SUCCESS); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,95 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * ECC algorithm for NAND FLASH. Detects and corrects 1 bit errors in -+ * a 256 bytes of data. -+ * -+ * Reimplement by Thomas Gleixner after staring long enough at the -+ * mess in drivers/mtd/nand/nandecc.c -+ * -+ */ -+ -+#include "nandecc.h" -+ -+static int countbits(uint32_t byte) -+{ -+ int res = 0; -+ -+ for (;byte; byte >>= 1) -+ res += byte & 0x01; -+ return res; -+} -+ -+/** -+ * @dat: data which should be corrected -+ * @read_ecc: ecc information read from flash -+ * @calc_ecc: calculated ecc information from the data -+ * @return: number of corrected bytes -+ * or -1 when no correction is possible -+ */ -+int nand_correct_data(uint8_t *dat, const uint8_t *read_ecc, -+ const uint8_t *calc_ecc) -+{ -+ uint8_t s0, s1, s2; -+ -+ /* -+ * Do error detection -+ * -+ * Be careful, the index magic is due to a pointer to a -+ * uint32_t. -+ */ -+ s0 = calc_ecc[0] ^ read_ecc[0]; -+ s1 = calc_ecc[1] ^ read_ecc[1]; -+ s2 = calc_ecc[2] ^ read_ecc[2]; -+ -+ if ((s0 | s1 | s2) == 0) -+ return 0; -+ -+ /* Check for a single bit error */ -+ if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && -+ ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && -+ ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { -+ -+ uint32_t byteoffs, bitnum; -+ -+ byteoffs = (s1 << 0) & 0x80; -+ byteoffs |= (s1 << 1) & 0x40; -+ byteoffs |= (s1 << 2) & 0x20; -+ byteoffs |= (s1 << 3) & 0x10; -+ -+ byteoffs |= (s0 >> 4) & 0x08; -+ byteoffs |= (s0 >> 3) & 0x04; -+ byteoffs |= (s0 >> 2) & 0x02; -+ byteoffs |= (s0 >> 1) & 0x01; -+ -+ bitnum = (s2 >> 5) & 0x04; -+ bitnum |= (s2 >> 4) & 0x02; -+ bitnum |= (s2 >> 3) & 0x01; -+ -+ dat[byteoffs] ^= (1 << bitnum); -+ -+ return 1; -+ } -+ -+ if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) -+ return 1; -+ -+ return -1; -+} -+ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,159 @@ -+/* -+ * This file contains an ECC algorithm from Toshiba that detects and -+ * corrects 1 bit errors in a 256 byte block of data. -+ * -+ * drivers/mtd/nand/nand_ecc.c -+ * -+ * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) -+ * Toshiba America Electronics Components, Inc. -+ * -+ * This file is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 or (at your option) any -+ * later version. -+ * -+ * This file is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this file; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * As a special exception, if other files instantiate templates or use -+ * macros or inline functions from these files, or you compile these -+ * files and link them with other works to produce a work based on these -+ * files, these files do not by themselves cause the resulting work to be -+ * covered by the GNU General Public License. However the source code for -+ * these files must still be made available in accordance with section (3) -+ * of the GNU General Public License. -+ * -+ * This exception does not invalidate any other reasons why a work based on -+ * this file might be covered by the GNU General Public License. -+ */ -+ -+#include "nandecc.h" -+ -+/* -+ * Pre-calculated 256-way 1 byte column parity -+ */ -+static const uint8_t nand_ecc_precalc_table[] = { -+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, -+ 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, -+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, -+ 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, -+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, -+ 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, -+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, -+ 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, -+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, -+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, -+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, -+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, -+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, -+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, -+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, -+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, -+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, -+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, -+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, -+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, -+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, -+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, -+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, -+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, -+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, -+ 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, -+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, -+ 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, -+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, -+ 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, -+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, -+ 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 -+}; -+ -+/** -+ * nand_trans_result - [GENERIC] create non-inverted ECC -+ * @reg2: line parity reg 2 -+ * @reg3: line parity reg 3 -+ * @ecc_code: ecc -+ * -+ * Creates non-inverted ECC code from line parity -+ */ -+static void nand_trans_result(uint8_t reg2, uint8_t reg3, -+ uint8_t *ecc_code) -+{ -+ uint8_t a, b, i, tmp1, tmp2; -+ -+ /* Initialize variables */ -+ a = b = 0x80; -+ tmp1 = tmp2 = 0; -+ -+ /* Calculate first ECC byte */ -+ for (i = 0; i < 4; i++) { -+ if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ -+ tmp1 |= b; -+ b >>= 1; -+ if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ -+ tmp1 |= b; -+ b >>= 1; -+ a >>= 1; -+ } -+ -+ /* Calculate second ECC byte */ -+ b = 0x80; -+ for (i = 0; i < 4; i++) { -+ if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ -+ tmp2 |= b; -+ b >>= 1; -+ if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ -+ tmp2 |= b; -+ b >>= 1; -+ a >>= 1; -+ } -+ -+ /* Store two of the ECC bytes */ -+ ecc_code[1] = tmp1; -+ ecc_code[0] = tmp2; -+} -+ -+/** -+ * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for -+ * 256 byte block -+ * -+ * @dat: raw data -+ * @ecc_code: buffer for ECC -+ */ -+int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code) -+{ -+ uint8_t idx, reg1, reg2, reg3; -+ int j; -+ -+ /* Initialize variables */ -+ reg1 = reg2 = reg3 = 0; -+ ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; -+ -+ /* Build up column parity */ -+ for(j = 0; j < 256; j++) { -+ -+ /* Get CP0 - CP5 from table */ -+ idx = nand_ecc_precalc_table[dat[j]]; -+ reg1 ^= (idx & 0x3f); -+ -+ /* All bit XOR = 1 ? */ -+ if (idx & 0x40) { -+ reg3 ^= (uint8_t) j; -+ reg2 ^= ~((uint8_t) j); -+ } -+ } -+ -+ /* Create non-inverted ECC code from line parity */ -+ nand_trans_result(reg2, reg3, ecc_code); -+ -+ /* Calculate final ECC code */ -+ ecc_code[0] = ~ecc_code[0]; -+ ecc_code[1] = ~ecc_code[1]; -+ ecc_code[2] = ((~reg1) << 2) | 0x03; -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,29 @@ -+#ifndef _NAND_ECC_H -+#define _NAND_ECC_H -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * NAND ecc functions -+ */ -+ -+#include -+ -+int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code); -+int nand_correct_data(uint8_t *dat, const uint8_t *read_ecc, -+ const uint8_t *calc_ecc); -+ -+#endif ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,516 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2008 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * PDD (platform description data) contains a set of system specific -+ * boot-parameters. Some of those parameters need to be handled -+ * special on updates, e.g. the MAC addresses. They must also be kept -+ * if the system is updated and one must be able to modify them when -+ * the system has booted the first time. This tool is intended to do -+ * PDD modification. -+ * -+ * 1.3 Removed argp because we want to use uClibc. -+ * 1.4 Minor cleanups -+ * 1.5 Migrated to new libubi -+ * 1.6 Fixed broken volume update -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "config.h" -+#include "bootenv.h" -+#include "error.h" -+#include "example_ubi.h" -+#include "libubi.h" -+#include "ubimirror.h" -+ -+#define PROGRAM_VERSION "1.6" -+ -+#define DEFAULT_DEV_PATTERN "/dev/ubi%d" -+#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d" -+ -+typedef enum action_t { -+ ACT_NORMAL = 0, -+ ACT_LIST, -+ ACT_ARGP_ABORT, -+ ACT_ARGP_ERR, -+} action_t; -+ -+#define ABORT_ARGP do { \ -+ args->action = ACT_ARGP_ABORT; \ -+} while (0) -+ -+#define ERR_ARGP do { \ -+ args->action = ACT_ARGP_ERR; \ -+} while (0) -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "pddcustomize - customize bootenv and pdd values.\n"; -+ -+static const char *optionsstr = -+" -b, --both Mirror updated PDD to redundand copy.\n" -+" -c, --copyright Print copyright information.\n" -+" -i, --input= Binary input file. For debug purposes.\n" -+" -l, --list List card bootenv/pdd values.\n" -+" -o, --output= Binary output file. For debug purposes.\n" -+" -s, --side= The side/seqnum to update.\n" -+" -x, --host use x86 platform for debugging.\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: pddcustomize [-bclx?V] [-i ] [-o ] [-s ]\n" -+" [--both] [--copyright] [--input=] [--list]\n" -+" [--output=] [--side=] [--host] [--help] [--usage]\n" -+" [--version] [key=value] [...]\n"; -+ -+struct option long_options[] = { -+ { .name = "both", .has_arg = 0, .flag = NULL, .val = 'b' }, -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "input", .has_arg = 1, .flag = NULL, .val = 'i' }, -+ { .name = "list", .has_arg = 0, .flag = NULL, .val = 'l' }, -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "host", .has_arg = 0, .flag = NULL, .val = 'x' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright IBM Corp 2006"; -+ -+typedef struct myargs { -+ action_t action; -+ const char* file_in; -+ const char* file_out; -+ int both; -+ int side; -+ int x86; /* X86 host, use files for testing */ -+ bootenv_t env_in; -+ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+static int -+get_update_side(const char* str) -+{ -+ uint32_t i = strtoul(str, NULL, 0); -+ -+ if ((i != 0) && (i != 1)) { -+ return -1; -+ } -+ -+ return i; -+} -+ -+static int -+extract_pair(bootenv_t env, const char* str) -+{ -+ int rc = 0; -+ char* key; -+ char* val; -+ -+ key = strdup(str); -+ if (key == NULL) -+ return -ENOMEM; -+ -+ val = strstr(key, "="); -+ if (val == NULL) { -+ err_msg("Wrong argument: %s\n" -+ "Expecting key=value pair.\n", str); -+ rc = -1; -+ goto err; -+ } -+ -+ *val = '\0'; /* split strings */ -+ val++; -+ rc = bootenv_set(env, key, val); -+ -+err: -+ free(key); -+ return rc; -+} -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ int rc = 0; -+ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "clbxs:i:o:?V", -+ long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'c': -+ err_msg("%s\n", copyright); -+ ABORT_ARGP; -+ break; -+ case 'l': -+ args->action = ACT_LIST; -+ break; -+ case 'b': -+ args->both = 1; -+ break; -+ case 'x': -+ args->x86 = 1; -+ break; -+ case 's': -+ args->side = get_update_side(optarg); -+ if (args->side < 0) { -+ err_msg("Unsupported seqnum: %d.\n" -+ "Supported seqnums are " -+ "'0' and '1'\n", -+ args->side, optarg); -+ ERR_ARGP; -+ } -+ break; -+ case 'i': -+ args->file_in = optarg; -+ break; -+ case 'o': -+ args->file_out = optarg; -+ break; -+ case '?': /* help */ -+ err_msg("Usage: pddcustomize [OPTION...] " -+ "[key=value] [...]"); -+ err_msg("%s", doc); -+ err_msg("%s", optionsstr); -+ err_msg("\nReport bugs to %s", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ case 'V': -+ err_msg("%s", PROGRAM_VERSION); -+ exit(0); -+ break; -+ default: -+ err_msg("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) { -+ rc = extract_pair(args->env_in, argv[optind++]); -+ if (rc != 0) -+ ERR_ARGP; -+ } -+ -+ return 0; -+} -+ -+static int -+list_bootenv(bootenv_t env) -+{ -+ int rc = 0; -+ rc = bootenv_write_txt(stdout, env); -+ if (rc != 0) { -+ err_msg("Cannot list bootenv/pdd. rc: %d\n", rc); -+ goto err; -+ } -+err: -+ return rc; -+} -+ -+static int -+process_key_value(bootenv_t env_in, bootenv_t env) -+{ -+ int rc = 0; -+ size_t size, i; -+ const char* tmp; -+ const char** key_vec = NULL; -+ -+ rc = bootenv_get_key_vector(env_in, &size, 0, &key_vec); -+ if (rc != 0) -+ goto err; -+ -+ for (i = 0; i < size; i++) { -+ rc = bootenv_get(env_in, key_vec[i], &tmp); -+ if (rc != 0) { -+ err_msg("Cannot read value to input key: %s. rc: %d\n", -+ key_vec[i], rc); -+ goto err; -+ } -+ rc = bootenv_set(env, key_vec[i], tmp); -+ if (rc != 0) { -+ err_msg("Cannot set value key: %s. rc: %d\n", -+ key_vec[i], rc); -+ goto err; -+ } -+ } -+ -+err: -+ if (key_vec != NULL) -+ free(key_vec); -+ return rc; -+} -+ -+static int -+read_bootenv(const char* file, bootenv_t env) -+{ -+ int rc = 0; -+ FILE* fp_in = NULL; -+ -+ fp_in = fopen(file, "rb"); -+ if (fp_in == NULL) { -+ err_msg("Cannot open file: %s\n", file); -+ return -EIO; -+ } -+ -+ rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); -+ if (rc != 0) { -+ err_msg("Cannot read bootenv from file %s. rc: %d\n", -+ file, rc); -+ goto err; -+ } -+ -+err: -+ fclose(fp_in); -+ return rc; -+} -+ -+/* -+ * Read bootenv from ubi volume -+ */ -+static int -+ubi_read_bootenv(uint32_t devno, uint32_t id, bootenv_t env) -+{ -+ libubi_t ulib; -+ int rc = 0; -+ char path[PATH_MAX]; -+ FILE* fp_in = NULL; -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ err_msg("Cannot allocate ubi structure\n"); -+ return -1; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ fp_in = fopen(path, "r"); -+ if (fp_in == NULL) { -+ err_msg("Cannot open volume:%d number:%d\n", devno, id); -+ goto err; -+ } -+ -+ rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); -+ if (rc != 0) { -+ err_msg("Cannot read volume:%d number:%d\n", devno, id); -+ goto err; -+ } -+ -+err: -+ if (fp_in) -+ fclose(fp_in); -+ libubi_close(ulib); -+ return rc; -+} -+ -+static int -+write_bootenv(const char* file, bootenv_t env) -+{ -+ int rc = 0; -+ FILE* fp_out; -+ -+ fp_out = fopen(file, "wb"); -+ if (fp_out == NULL) { -+ err_msg("Cannot open file: %s\n", file); -+ return -EIO; -+ } -+ -+ rc = bootenv_write(fp_out, env); -+ if (rc != 0) { -+ err_msg("Cannot write bootenv to file %s. rc: %d\n", file, rc); -+ goto err; -+ } -+ -+err: -+ fclose(fp_out); -+ return rc; -+} -+ -+/* -+ * Read bootenv from ubi volume -+ */ -+static int -+ubi_write_bootenv(uint32_t devno, uint32_t id, bootenv_t env) -+{ -+ libubi_t ulib; -+ int rc = 0; -+ char path[PATH_MAX]; -+ FILE* fp_out = NULL; -+ size_t nbytes; -+ -+ rc = bootenv_size(env, &nbytes); -+ if (rc) { -+ err_msg("Cannot determine size of bootenv structure\n"); -+ return rc; -+ } -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ err_msg("Cannot allocate ubi structure\n"); -+ return rc; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ fp_out = fopen(path, "r+"); -+ if (fp_out == NULL) { -+ err_msg("Cannot fopen volume:%d number:%d\n", devno, id); -+ rc = -EBADF; -+ goto err; -+ } -+ -+ rc = ubi_update_start(ulib, fileno(fp_out), nbytes); -+ if (rc != 0) { -+ err_msg("Cannot start update for %s\n", path); -+ goto err; -+ } -+ -+ rc = bootenv_write(fp_out, env); -+ if (rc != 0) { -+ err_msg("Cannot write bootenv to volume %d number:%d\n", -+ devno, id); -+ goto err; -+ } -+err: -+ if( fp_out ) -+ fclose(fp_out); -+ libubi_close(ulib); -+ return rc; -+} -+ -+static int -+do_mirror(int volno) -+{ -+ char errbuf[1024]; -+ uint32_t ids[2]; -+ int rc; -+ int src_volno_idx = 0; -+ -+ ids[0] = EXAMPLE_BOOTENV_VOL_ID_1; -+ ids[1] = EXAMPLE_BOOTENV_VOL_ID_2; -+ -+ if (volno == EXAMPLE_BOOTENV_VOL_ID_2) -+ src_volno_idx = 1; -+ -+ rc = ubimirror(EXAMPLE_UBI_DEVICE, src_volno_idx, ids, 2, errbuf, -+ sizeof errbuf); -+ if( rc ) -+ err_msg(errbuf); -+ return rc; -+} -+ -+int -+main(int argc, char **argv) { -+ int rc = 0; -+ bootenv_t env = NULL; -+ uint32_t boot_volno; -+ myargs args = { -+ .action = ACT_NORMAL, -+ .file_in = NULL, -+ .file_out = NULL, -+ .side = -1, -+ .x86 = 0, -+ .both = 0, -+ .env_in = NULL, -+ -+ .arg1 = NULL, -+ .options = NULL, -+ }; -+ -+ rc = bootenv_create(&env); -+ if (rc != 0) { -+ err_msg("Cannot create bootenv handle. rc: %d", rc); -+ goto err; -+ } -+ -+ rc = bootenv_create(&(args.env_in)); -+ if (rc != 0) { -+ err_msg("Cannot create bootenv handle. rc: %d", rc); -+ goto err; -+ } -+ -+ parse_opt(argc, argv, &args); -+ if (args.action == ACT_ARGP_ERR) { -+ rc = -1; -+ goto err; -+ } -+ if (args.action == ACT_ARGP_ABORT) { -+ rc = 0; -+ goto out; -+ } -+ -+ if ((args.side == 0) || (args.side == -1)) -+ boot_volno = EXAMPLE_BOOTENV_VOL_ID_1; -+ else -+ boot_volno = EXAMPLE_BOOTENV_VOL_ID_2; -+ -+ if( args.x86 ) -+ rc = read_bootenv(args.file_in, env); -+ else -+ rc = ubi_read_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ if (args.action == ACT_LIST) { -+ rc = list_bootenv(env); -+ if (rc != 0) { -+ goto err; -+ } -+ goto out; -+ } -+ -+ rc = process_key_value(args.env_in, env); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ if( args.x86 ) -+ rc = write_bootenv(args.file_in, env); -+ else -+ rc = ubi_write_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); -+ if (rc != 0) -+ goto err; -+ -+ if( args.both ) /* No side specified, update both */ -+ rc = do_mirror(boot_volno); -+ -+ out: -+ err: -+ bootenv_destroy(&env); -+ bootenv_destroy(&(args.env_in)); -+ return rc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/peb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/peb.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,116 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "peb.h" -+ -+int -+peb_cmp(peb_t eb_1, peb_t eb_2) -+{ -+ assert(eb_1); -+ assert(eb_2); -+ -+ return eb_1->num == eb_2->num ? 0 -+ : eb_1->num > eb_2->num ? 1 : -1; -+} -+ -+int -+peb_new(uint32_t eb_num, uint32_t eb_size, peb_t *peb) -+{ -+ int rc = 0; -+ -+ peb_t res = (peb_t) malloc(sizeof(struct peb)); -+ if (!res) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ -+ res->num = eb_num; -+ res->size = eb_size; -+ res->data = (uint8_t*) malloc(res->size * sizeof(uint8_t)); -+ if (!res->data) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ memset(res->data, 0xff, res->size); -+ -+ *peb = res; -+ return 0; -+err: -+ if (res) { -+ if (res->data) -+ free(res->data); -+ free(res); -+ } -+ *peb = NULL; -+ return rc; -+} -+ -+int -+peb_fill(peb_t peb, uint8_t* buf, size_t buf_size) -+{ -+ if (!peb) -+ return -EINVAL; -+ -+ if (buf_size > peb->size) -+ return -EINVAL; -+ -+ memcpy(peb->data, buf, buf_size); -+ return 0; -+} -+ -+int -+peb_write(FILE* fp_out, peb_t peb) -+{ -+ size_t written = 0; -+ -+ if (peb == NULL) -+ return -EINVAL; -+ -+ written = fwrite(peb->data, 1, peb->size, fp_out); -+ -+ if (written != peb->size) -+ return -EIO; -+ -+ return 0; -+} -+ -+int -+peb_free(peb_t* peb) -+{ -+ peb_t tmp = *peb; -+ if (tmp) { -+ if (tmp->data) -+ free(tmp->data); -+ free(tmp); -+ } -+ *peb = NULL; -+ -+ return 0; -+} -+ -+void peb_dump(FILE* fp_out, peb_t peb) -+{ -+ fprintf(fp_out, "num: %08d\tsize: 0x%08x\n", peb->num, peb->size); -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/peb.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/peb.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,41 @@ -+#ifndef __RAW_BLOCK_H__ -+#define __RAW_BLOCK_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+ -+typedef struct peb *peb_t; -+struct peb { -+ uint32_t num; /* Physical eraseblock number -+ * in the RAW file. */ -+ uint32_t size; /* Data Size (equals physical -+ * erase block size) */ -+ uint8_t* data; /* Data buffer */ -+}; -+ -+int peb_new(uint32_t peb_num, uint32_t peb_size, peb_t* peb); -+int peb_free(peb_t* peb); -+int peb_cmp(peb_t peb_1, peb_t peb_2); -+int peb_write(FILE* fp_out, peb_t peb); -+void peb_dump(FILE* fp_out, peb_t peb); -+ -+#endif /* __RAW_BLOCK_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,458 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * @file pfi.c -+ * -+ * @author Oliver Lohmann -+ * Andreas Arnez -+ * Joern Engel -+ * Frank Haverkamp -+ * -+ * @brief libpfi holds all code to create and process pfi files. -+ * -+ * Wed Feb 8 11:38:22 CET 2006: Initial creation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "pfi.h" -+ -+#define PFI_MAGIC "PFI!\n" -+#define PFI_DATA "DATA\n" /* The same size as PFI_MAGIC */ -+#define PFI_MAGIC_LEN 5 -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright (c) International Business Machines Corp., 2006"; -+ -+enum key_id { -+ /* version 1 */ -+ key_version, /* must be index position 0! */ -+ key_mode, -+ key_size, -+ key_crc, -+ key_label, -+ key_flags, -+ key_ubi_ids, -+ key_ubi_size, -+ key_ubi_type, -+ key_ubi_names, -+ key_ubi_alignment, -+ key_raw_starts, -+ key_raw_total_size, -+ num_keys, -+}; -+ -+struct pfi_header { -+ char defined[num_keys]; /* reserve all possible keys even if -+ version does not require this. */ -+ int mode_no; /* current mode no. -> can only increase */ -+ union { -+ char *str; -+ uint32_t num; -+ } value[num_keys]; -+}; -+ -+ -+#define PFI_MANDATORY 0x0001 -+#define PFI_STRING 0x0002 -+#define PFI_LISTVALUE 0x0004 /* comma seperated list of nums */ -+#define PFI_MANDATORY_UBI 0x0008 -+#define PFI_MANDATORY_RAW 0x0010 -+ -+struct key_descriptor { -+ enum key_id id; -+ const char *name; -+ uint32_t flags; -+}; -+ -+static const struct key_descriptor key_desc_v1[] = { -+ { key_version, "version", PFI_MANDATORY }, -+ { key_mode, "mode", PFI_MANDATORY | PFI_STRING }, -+ { key_size, "size", PFI_MANDATORY }, -+ { key_crc, "crc", PFI_MANDATORY }, -+ { key_label, "label", PFI_MANDATORY | PFI_STRING }, -+ { key_flags, "flags", PFI_MANDATORY }, -+ { key_ubi_ids, "ubi_ids", PFI_MANDATORY_UBI | PFI_STRING }, -+ { key_ubi_size, "ubi_size", PFI_MANDATORY_UBI }, -+ { key_ubi_type, "ubi_type", PFI_MANDATORY_UBI | PFI_STRING }, -+ { key_ubi_names, "ubi_names", PFI_MANDATORY_UBI | PFI_STRING }, -+ { key_ubi_alignment, "ubi_alignment", PFI_MANDATORY_UBI }, -+ { key_raw_starts, "raw_starts", PFI_MANDATORY_RAW | PFI_STRING }, -+ { key_raw_total_size, "raw_total_size", PFI_MANDATORY_RAW }, -+}; -+ -+static const struct key_descriptor *key_descriptors[] = { -+ NULL, -+ key_desc_v1, /* version 1 */ -+}; -+ -+static const int key_descriptors_max[] = { -+ 0, /* version 0 */ -+ sizeof(key_desc_v1)/sizeof(struct key_descriptor), /* version 1 */ -+}; -+ -+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -+ -+static const char* modes[] = {"raw", "ubi"}; /* order isn't arbitrary! */ -+ -+/* latest version contains all possible keys */ -+static const struct key_descriptor *key_desc = key_desc_v1; -+ -+#define PFI_IS_UBI(mode) \ -+ (((mode) != NULL) && (strcmp("ubi", (mode)) == 0)) -+ -+#define PFI_IS_RAW(mode) \ -+ (((mode) != NULL) && (strcmp("raw", (mode)) == 0)) -+ -+/** -+ * @return <0 On Error. -+ * >=0 Mode no. -+ */ -+static int -+get_mode_no(const char* mode) -+{ -+ int i; -+ -+ for (i = 0; i < (int)ARRAY_SIZE(modes); i++) -+ if (strcmp(mode, modes[i]) == 0) -+ return i; -+ return -1; -+} -+ -+static int -+find_key_by_name (const char *name) -+{ -+ int i; -+ -+ for (i = 0; i < num_keys; i++) { -+ if (strcmp(name, key_desc[i].name) == 0) -+ return i; -+ } -+ return -1; -+} -+ -+static int -+check_valid (pfi_header head) -+{ -+ int i; -+ int max_keys; -+ uint32_t version; -+ const char *mode; -+ const struct key_descriptor *desc; -+ uint32_t to_check = PFI_MANDATORY; -+ -+ /* -+ * For the validity check the list of possible keys depends on -+ * the version of the PFI file used. -+ */ -+ version = head->value[key_version].num; -+ if (version > PFI_HDRVERSION) -+ return PFI_ENOHEADER; -+ -+ max_keys = key_descriptors_max[version]; -+ desc = key_descriptors[version]; -+ -+ if (!desc) -+ return PFI_ENOVERSION; -+ -+ mode = head->value[key_mode].str; -+ if (PFI_IS_UBI(mode)) { -+ to_check |= PFI_MANDATORY_UBI; -+ } -+ else if (PFI_IS_RAW(mode)) { -+ to_check |= PFI_MANDATORY_RAW; -+ } -+ else { /* neither UBI nor RAW == ERR */ -+ return PFI_EINSUFF; -+ } -+ -+ for (i = 0; i < max_keys; i++) { -+ if ((desc[i].flags & to_check) && !head->defined[i]) { -+ fprintf(stderr, "libpfi: %s missing\n", desc[i].name); -+ return PFI_EINSUFF; -+ } -+ } -+ -+ return 0; -+} -+ -+int pfi_header_init (pfi_header *head) -+{ -+ int i; -+ pfi_header self = (pfi_header) malloc(sizeof(*self)); -+ -+ *head = self; -+ if (self == NULL) -+ return PFI_ENOMEM; -+ -+ /* initialize maximum number of possible keys */ -+ for (i = 0; i < num_keys; i++) { -+ memset(self, 0, sizeof(*self)); -+ self->defined[i] = 0; -+ } -+ -+ return 0; -+} -+ -+int pfi_header_destroy (pfi_header *head) -+{ -+ int i; -+ pfi_header self = *head; -+ -+ for (i = 0; i < num_keys; i++) { -+ if (self->defined[i] && (key_desc[i].flags & PFI_STRING) && -+ self->value[i].str) { -+ free(self->value[i].str); -+ } -+ } -+ free(*head); -+ *head = NULL; -+ return 0; -+} -+ -+int pfi_header_setnumber (pfi_header head, -+ const char *key, uint32_t value) -+{ -+ int key_id = find_key_by_name(key); -+ -+ if (key_id < 0) -+ return PFI_EUNDEF; -+ -+ if (key_desc[key_id].flags & PFI_STRING) -+ return PFI_EBADTYPE; -+ -+ head->value[key_id].num = value; -+ head->defined[key_id] = 1; -+ return 0; -+} -+ -+int pfi_header_setvalue (pfi_header head, -+ const char *key, const char *value) -+{ -+ int key_id = find_key_by_name(key); -+ -+ if (value == NULL) -+ return PFI_EINSUFF; -+ -+ if ((key_id < 0) || (key_id >= num_keys)) -+ return PFI_EUNDEF; -+ -+ if (key_desc[key_id].flags & PFI_STRING) { -+ /* -+ * The value is a string. Copy to a newly allocated -+ * buffer. Delete the old value, if already set. -+ */ -+ size_t len = strlen(value) + 1; -+ char *old_str = NULL; -+ char *str; -+ -+ old_str = head->value[key_id].str; -+ if (old_str != NULL) -+ free(old_str); -+ -+ str = head->value[key_id].str = (char *) malloc(len); -+ if (str == NULL) -+ return PFI_ENOMEM; -+ -+ strcpy(str, value); -+ } else { -+ int len; -+ int ret; -+ /* FIXME: here we assume that the value is always -+ given in hex and starts with '0x'. */ -+ ret = sscanf(value, "0x%x%n", &head->value[key_id].num, &len); -+ if (ret < 1 || value[len] != '\0') -+ return PFI_EBADTYPE; -+ } -+ head->defined[key_id] = 1; -+ return 0; -+} -+ -+int pfi_header_getnumber (pfi_header head, -+ const char *key, uint32_t *value) -+{ -+ int key_id = find_key_by_name(key); -+ -+ if (key_id < 0) -+ return PFI_EUNDEF; -+ -+ if (key_desc[key_id].flags & PFI_STRING) -+ return PFI_EBADTYPE; -+ -+ if (!head->defined[key_id]) -+ return PFI_EUNDEF; -+ -+ *value = head->value[key_id].num; -+ return 0; -+} -+ -+int pfi_header_getstring (pfi_header head, -+ const char *key, char *value, size_t size) -+{ -+ int key_id = find_key_by_name(key); -+ -+ if (key_id < 0) -+ return PFI_EUNDEF; -+ -+ if (!(key_desc[key_id].flags & PFI_STRING)) -+ return PFI_EBADTYPE; -+ -+ if (!head->defined[key_id]) -+ return PFI_EUNDEF; -+ -+ strncpy(value, head->value[key_id].str, size-1); -+ value[size-1] = '\0'; -+ return 0; -+} -+ -+int pfi_header_write (FILE *out, pfi_header head) -+{ -+ int i; -+ int ret; -+ -+ pfi_header_setnumber(head, "version", PFI_HDRVERSION); -+ -+ if ((ret = check_valid(head)) != 0) -+ return ret; -+ -+ /* OK. Now write the header. */ -+ -+ ret = fwrite(PFI_MAGIC, 1, PFI_MAGIC_LEN, out); -+ if (ret < PFI_MAGIC_LEN) -+ return ret; -+ -+ -+ for (i = 0; i < num_keys; i++) { -+ if (!head->defined[i]) -+ continue; -+ -+ ret = fprintf(out, "%s=", key_desc[i].name); -+ if (ret < 0) -+ return PFI_EFILE; -+ -+ if (key_desc[i].flags & PFI_STRING) { -+ ret = fprintf(out, "%s", head->value[i].str); -+ if (ret < 0) -+ return PFI_EFILE; -+ } else { -+ ret = fprintf(out, "0x%8x", head->value[i].num); -+ if (ret < 0) -+ return PFI_EFILE; -+ -+ } -+ ret = fprintf(out, "\n"); -+ if (ret < 0) -+ return PFI_EFILE; -+ } -+ ret = fprintf(out, "\n"); -+ if (ret < 0) -+ return PFI_EFILE; -+ -+ ret = fflush(out); -+ if (ret != 0) -+ return PFI_EFILE; -+ -+ return 0; -+} -+ -+int pfi_header_read (FILE *in, pfi_header head) -+{ -+ char magic[PFI_MAGIC_LEN]; -+ char mode[PFI_KEYWORD_LEN]; -+ char buf[256]; -+ -+ if (PFI_MAGIC_LEN != fread(magic, 1, PFI_MAGIC_LEN, in)) -+ return PFI_EFILE; -+ if (memcmp(magic, PFI_MAGIC, PFI_MAGIC_LEN) != 0) { -+ if (memcmp(magic, PFI_DATA, PFI_MAGIC_LEN) == 0) { -+ return PFI_DATA_START; -+ } -+ return PFI_ENOHEADER; -+ } -+ -+ while (fgets(buf, sizeof(buf), in) != NULL && buf[0] != '\n') { -+ char *value; -+ char *end; -+ value = strchr(buf, '='); -+ if (value == NULL) -+ return PFI_ENOHEADER; -+ -+ *value = '\0'; -+ value++; -+ end = strchr(value, '\n'); -+ if (end) -+ *end = '\0'; -+ -+ if (pfi_header_setvalue(head, buf, value)) -+ return PFI_ENOHEADER; -+ } -+ -+ if (check_valid(head) != 0) -+ return PFI_ENOHEADER; -+ -+ /* set current mode no. in head */ -+ pfi_header_getstring(head, "mode", mode, PFI_KEYWORD_LEN); -+ if (head->mode_no > get_mode_no(mode)) { -+ return PFI_EMODE; -+ } -+ head->mode_no = get_mode_no(mode); -+ return 0; -+} -+ -+int pfi_header_dump (FILE *out, pfi_header head __attribute__((__unused__))) -+{ -+ fprintf(out, "Sorry not implemented yet. Write mail to " -+ "Andreas Arnez and complain!\n"); -+ return 0; -+} -+ -+int pfi_read (FILE *in, pfi_read_func func, void *priv_data) -+{ -+ int rc; -+ pfi_header header; -+ -+ rc = pfi_header_init (&header); -+ if (0 != rc) -+ return rc; -+ if (!func) -+ return PFI_EINVAL; -+ -+ while ((0 == rc) && !feof(in)) { -+ /* -+ * Read header and check consistency of the fields. -+ */ -+ rc = pfi_header_read( in, header ); -+ if (0 != rc) -+ break; -+ if (func) { -+ rc = func(in, header, priv_data); -+ if (rc != 0) -+ break; -+ } -+ } -+ -+ pfi_header_destroy(&header); -+ return rc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,244 @@ -+#ifndef __pfi_h -+#define __pfi_h -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/** -+ * @file pfi.h -+ * -+ * @author Oliver Lohmann -+ * Andreas Arnez -+ * Joern Engel -+ * Frank Haverkamp -+ * -+ * @brief libpfi will hold all code to create and process pfi -+ * images. Definitions made in this file are equaly usable for the -+ * development host and the target system. -+ * -+ * @note This header additionally holds the official definitions for -+ * the pfi headers. -+ */ -+ -+#include /* FILE */ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* Definitions. */ -+ -+#define PFI_HDRVERSION 1 /* current header version */ -+ -+#define PFI_ENOVERSION 1 /* unknown version */ -+#define PFI_ENOHEADER 2 /* not a pfi header */ -+#define PFI_EINSUFF 3 /* insufficient information */ -+#define PFI_EUNDEF 4 /* key not defined */ -+#define PFI_ENOMEM 5 /* out of memory */ -+#define PFI_EBADTYPE 6 /* bad data type */ -+#define PFI_EFILE 7 /* file I/O error: see errno */ -+#define PFI_EFILEINVAL 8 /* file format not valid */ -+#define PFI_EINVAL 9 /* invalid parameter */ -+#define PFI_ERANGE 10 /* invalid range */ -+#define PFI_EMODE 11 /* expecting other mode in this header */ -+#define PFI_DATA_START 12 /* data section starts */ -+#define PFI_EMAX 13 /* should be always larger as the largest -+ error code */ -+ -+#define PFI_LABEL_LEN 64 /* This is the maximum length for a -+ PFI header label */ -+#define PFI_KEYWORD_LEN 32 /* This is the maximum length for an -+ entry in the mode and type fields */ -+ -+#define PFI_UBI_MAX_VOLUMES 128 -+#define PFI_UBI_VOL_NAME_LEN 127 -+ -+/** -+ * @brief The pfi header allows to set flags which influence the flashing -+ * behaviour. -+ */ -+#define PFI_FLAG_PROTECTED 0x00000001 -+ -+ -+/** -+ * @brief Handle to pfi header. Used in most of the functions associated -+ * with pfi file handling. -+ */ -+typedef struct pfi_header *pfi_header; -+ -+ -+/** -+ * @brief Initialize a pfi header object. -+ * -+ * @param head Pointer to handle. This function allocates memory -+ * for this data structure. -+ * @return 0 on success, otherwise: -+ * PFI_ENOMEM : no memory available for the handle. -+ */ -+int pfi_header_init (pfi_header *head); -+ -+ -+/** -+ * @brief Destroy a pfi header object. -+ * -+ * @param head handle. head is invalid after calling this function. -+ * @return 0 always. -+ */ -+int pfi_header_destroy (pfi_header *head); -+ -+ -+/** -+ * @brief Add a key/value pair to a pfi header object. -+ * -+ * @param head handle. -+ * @param key pointer to key string. Must be 0 terminated. -+ * @param value pointer to value string. Must be 0 terminated. -+ * @return 0 on success, otherwise: -+ * PFI_EUNDEF : key was not found. -+ * PFI_ENOMEM : no memory available for the handle. -+ * PFI_EBADTYPE : value is not an hex string. This happens -+ * when the key stores an integer and the -+ * new value is not convertable e.g. not in -+ * 0xXXXXXXXX format. -+ */ -+int pfi_header_setvalue (pfi_header head, -+ const char *key, const char *value); -+ -+ -+/** -+ * @brief Add a key/value pair to a pfi header object. Provide the -+ * value as a number. -+ * -+ * @param head handle. -+ * @param key pointer to key string. Must be 0 terminated. -+ * @param value value to set. -+ * @return 0 on success, otherwise: -+ * PFI_EUNDEF : key was not found. -+ * PFI_EBADTYPE : value is not a string. This happens -+ * when the key stores a string. -+ */ -+int pfi_header_setnumber (pfi_header head, -+ const char *key, uint32_t value); -+ -+ -+/** -+ * @brief For a given key, return the numerical value stored in a -+ * pfi header object. -+ * -+ * @param head handle. -+ * @param key pointer to key string. Must be 0 terminated. -+ * @param value pointer to value. -+ * @return 0 on success, otherwise: -+ * PFI_EUNDEF : key was not found. -+ * PFI_EBADTYPE : stored value is not an integer but a string. -+ */ -+int pfi_header_getnumber (pfi_header head, -+ const char *key, uint32_t *value); -+ -+ -+static inline uint32_t -+pfi_getnumber(pfi_header head, const char *key) -+{ -+ uint32_t value; -+ pfi_header_getnumber(head, key, &value); -+ return value; -+} -+ -+/** -+ * @brief For a given key, return the string value stored in a pfi -+ * header object. -+ * -+ * @param head handle. -+ * @param key pointer to key string. Must be 0 terminated. -+ * @param value pointer to value string. Memory must be allocated by the user. -+ * @return 0 on success, otherwise: -+ * PFI_EUNDEF : key was not found. -+ * PFI_EBADTYPE : stored value is not a string but an integer. -+ */ -+int pfi_header_getstring (pfi_header head, -+ const char *key, char *value, size_t size); -+ -+ -+/** -+ * @brief Write a pfi header object into a given file. -+ * -+ * @param out output stream. -+ * @param head handle. -+ * @return 0 on success, error values otherwise: -+ * PFI_EINSUFF : not all mandatory fields are filled. -+ * PFI_ENOHEADER : wrong header version or magic number. -+ * -E* : see . -+ */ -+int pfi_header_write (FILE *out, pfi_header head); -+ -+ -+/** -+ * @brief Read a pfi header object from a given file. -+ * -+ * @param in input stream. -+ * @param head handle. -+ * @return 0 on success, error values otherwise: -+ * PFI_ENOVERSION: unknown header version. -+ * PFI_EFILE : cannot read enough data. -+ * PFI_ENOHEADER : wrong header version or magic number. -+ * -E* : see . -+ * -+ * If the header verification returned success the user can assume that -+ * all mandatory fields for a particular version are accessible. Checking -+ * the return code when calling the get-function for those keys is not -+ * required in those cases. For optional fields the checking must still be -+ * done. -+ */ -+int pfi_header_read (FILE *in, pfi_header head); -+ -+ -+/** -+ * @brief Display a pfi header in human-readable form. -+ * -+ * @param out output stream. -+ * @param head handle. -+ * @return always 0. -+ * -+ * @note Prints out that it is not implemented and whom you should -+ * contact if you need it urgently!. -+ */ -+int pfi_header_dump (FILE *out, pfi_header head); -+ -+ -+/* -+ * @brief Iterates over a stream of pfi files. The iterator function -+ * must advance the file pointer in FILE *in to the next pfi -+ * header. Function exists on feof(in). -+ * -+ * @param in input file descriptor, must be open and valid. -+ * @param func iterator function called when pfi header could be -+ * read and was validated. The function must return 0 on -+ * success. -+ * @return See pfi_header_init and pfi_header_read. -+ * PFI_EINVAL : func is not valid -+ * 0 ok. -+ */ -+typedef int (* pfi_read_func)(FILE *in, pfi_header hdr, void *priv_data); -+ -+int pfi_read (FILE *in, pfi_read_func func, void *priv_data); -+ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* __pfi_h */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,682 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Convert a PFI file (partial flash image) into a plain binary file. -+ * This tool can be used to prepare the data to be burned into flash -+ * chips in a manufacturing step where the flashes are written before -+ * being soldered onto the hardware. For NAND images another step is -+ * required to add the right OOB data to the binary image. -+ * -+ * 1.3 Removed argp because we want to use uClibc. -+ * 1.4 Minor cleanups -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "config.h" -+#include "list.h" -+#include "error.h" -+#include "reader.h" -+#include "peb.h" -+#include "crc32.h" -+ -+#define PROGRAM_VERSION "1.4" -+ -+#define MAX_FNAME 255 -+#define DEFAULT_ERASE_COUNT 0 /* Hmmm.... Perhaps */ -+#define ERR_BUF_SIZE 1024 -+ -+#define MIN(a,b) ((a) < (b) ? (a) : (b)) -+ -+static uint32_t crc32_table[256]; -+static char err_buf[ERR_BUF_SIZE]; -+ -+/* -+ * Data used to buffer raw blocks which have to be -+ * located at a specific point inside the generated RAW file -+ */ -+ -+typedef enum action_t { -+ ACT_NOTHING = 0x00000000, -+ ACT_RAW = 0x00000001, -+} action_t; -+ -+static const char copyright [] __attribute__((unused)) = -+ "(c) Copyright IBM Corp 2006\n"; -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "pfi2bin - a tool to convert PFI files into binary images.\n"; -+ -+static const char *optionsstr = -+" Common settings:\n" -+" -c, --copyright\n" -+" -v, --verbose Print more information.\n" -+"\n" -+" Input:\n" -+" -j, --platform=pdd-file PDD information which contains the card settings.\n" -+"\n" -+" Output:\n" -+" -o, --output=filename Outputfile, default: stdout.\n" -+"\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: pfi2bin [-cv?V] [-j pdd-file] [-o filename] [--copyright]\n" -+" [--verbose] [--platform=pdd-file] [--output=filename] [--help]\n" -+" [--usage] [--version] pfifile\n"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "platform", .has_arg = 1, .flag = NULL, .val = 'j' }, -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+typedef struct io { -+ FILE* fp_pdd; /* a FilePointer to the PDD data */ -+ FILE* fp_pfi; /* a FilePointer to the PFI input stream */ -+ FILE* fp_out; /* a FilePointer to the output stream */ -+} *io_t; -+ -+typedef struct myargs { -+ /* common settings */ -+ action_t action; -+ int verbose; -+ const char *f_in_pfi; -+ const char *f_in_pdd; -+ const char *f_out; -+ -+ /* special stuff needed to get additional arguments */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "cvj:o:?V", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ /* common settings */ -+ case 'v': /* --verbose= */ -+ args->verbose = 1; -+ break; -+ -+ case 'c': /* --copyright */ -+ fprintf(stderr, "%s\n", copyright); -+ exit(0); -+ break; -+ -+ case 'j': /* --platform */ -+ args->f_in_pdd = optarg; -+ break; -+ -+ case 'o': /* --output */ -+ args->f_out = optarg; -+ break; -+ -+ case '?': /* help */ -+ printf("pfi2bin [OPTION...] pfifile\n"); -+ printf("%s", doc); -+ printf("%s", optionsstr); -+ printf("\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ -+ case 'V': -+ printf("%s\n", PROGRAM_VERSION); -+ exit(0); -+ break; -+ -+ default: -+ printf("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) -+ args->f_in_pfi = argv[optind++]; -+ -+ return 0; -+} -+ -+ -+static size_t -+byte_to_blk(size_t byte, size_t blk_size) -+{ -+ return (byte % blk_size) == 0 -+ ? byte / blk_size -+ : byte / blk_size + 1; -+} -+ -+ -+ -+ -+/** -+ * @precondition IO: File stream points to first byte of RAW data. -+ * @postcondition IO: File stream points to first byte of next -+ * or EOF. -+ */ -+static int -+memorize_raw_eb(pfi_raw_t pfi_raw, pdd_data_t pdd, list_t *raw_pebs, -+ io_t io) -+{ -+ int rc = 0; -+ uint32_t i; -+ -+ size_t read, to_read, eb_num; -+ size_t bytes_left; -+ list_t pebs = *raw_pebs; -+ peb_t peb = NULL; -+ -+ long old_file_pos = ftell(io->fp_pfi); -+ for (i = 0; i < pfi_raw->starts_size; i++) { -+ bytes_left = pfi_raw->data_size; -+ rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET); -+ if (rc != 0) -+ goto err; -+ -+ eb_num = byte_to_blk(pfi_raw->starts[i], pdd->eb_size); -+ while (bytes_left) { -+ to_read = MIN(bytes_left, pdd->eb_size); -+ rc = peb_new(eb_num++, pdd->eb_size, &peb); -+ if (rc != 0) -+ goto err; -+ read = fread(peb->data, 1, to_read, io->fp_pfi); -+ if (read != to_read) { -+ rc = -EIO; -+ goto err; -+ } -+ pebs = append_elem(peb, pebs); -+ bytes_left -= read; -+ } -+ -+ } -+ *raw_pebs = pebs; -+ return 0; -+err: -+ pebs = remove_all((free_func_t)&peb_free, pebs); -+ return rc; -+} -+ -+static int -+convert_ubi_volume(pfi_ubi_t ubi, pdd_data_t pdd, list_t raw_pebs, -+ struct ubi_vtbl_record *vol_tab, -+ size_t *ebs_written, io_t io) -+{ -+ int rc = 0; -+ uint32_t i, j; -+ peb_t raw_peb; -+ peb_t cmp_peb; -+ ubi_info_t u; -+ size_t leb_total = 0; -+ uint8_t vol_type; -+ -+ switch (ubi->type) { -+ case pfi_ubi_static: -+ vol_type = UBI_VID_STATIC; break; -+ case pfi_ubi_dynamic: -+ vol_type = UBI_VID_DYNAMIC; break; -+ default: -+ vol_type = UBI_VID_DYNAMIC; -+ } -+ -+ rc = peb_new(0, 0, &cmp_peb); -+ if (rc != 0) -+ goto err; -+ -+ long old_file_pos = ftell(io->fp_pfi); -+ for (i = 0; i < ubi->ids_size; i++) { -+ rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET); -+ if (rc != 0) -+ goto err; -+ rc = ubigen_create(&u, ubi->ids[i], vol_type, -+ pdd->eb_size, DEFAULT_ERASE_COUNT, -+ ubi->alignment, UBI_VERSION, -+ pdd->vid_hdr_offset, 0, ubi->data_size, -+ io->fp_pfi, io->fp_out); -+ if (rc != 0) -+ goto err; -+ -+ rc = ubigen_get_leb_total(u, &leb_total); -+ if (rc != 0) -+ goto err; -+ -+ j = 0; -+ while(j < leb_total) { -+ cmp_peb->num = *ebs_written; -+ raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb, -+ raw_pebs); -+ if (raw_peb) { -+ rc = peb_write(io->fp_out, raw_peb); -+ } -+ else { -+ rc = ubigen_write_leb(u, NO_ERROR); -+ j++; -+ } -+ if (rc != 0) -+ goto err; -+ (*ebs_written)++; -+ } -+ /* memorize volume table entry */ -+ rc = ubigen_set_lvol_rec(u, ubi->size, -+ ubi->names[i], -+ (void*) &vol_tab[ubi->ids[i]]); -+ if (rc != 0) -+ goto err; -+ ubigen_destroy(&u); -+ } -+ -+ peb_free(&cmp_peb); -+ return 0; -+ -+err: -+ peb_free(&cmp_peb); -+ ubigen_destroy(&u); -+ return rc; -+} -+ -+ -+static FILE* -+my_fmemopen (void *buf, size_t size, const char *opentype) -+{ -+ FILE* f; -+ size_t ret; -+ -+ assert(strcmp(opentype, "r") == 0); -+ -+ f = tmpfile(); -+ ret = fwrite(buf, 1, size, f); -+ rewind(f); -+ -+ return f; -+} -+ -+/** -+ * @brief Builds a UBI volume table from a volume entry list. -+ * @return 0 On success. -+ * else Error. -+ */ -+static int -+write_ubi_volume_table(pdd_data_t pdd, list_t raw_pebs, -+ struct ubi_vtbl_record *vol_tab, size_t vol_tab_size, -+ size_t *ebs_written, io_t io) -+{ -+ int rc = 0; -+ ubi_info_t u; -+ peb_t raw_peb; -+ peb_t cmp_peb; -+ size_t leb_size, leb_total, j = 0; -+ uint8_t *ptr = NULL; -+ FILE* fp_leb = NULL; -+ int vt_slots; -+ size_t vol_tab_size_limit; -+ -+ rc = peb_new(0, 0, &cmp_peb); -+ if (rc != 0) -+ goto err; -+ -+ /* @FIXME: Artem creates one volume with 2 LEBs. -+ * IMO 2 volumes would be more convenient. In order -+ * to get 2 reserved LEBs from ubigen, I have to -+ * introduce this stupid mechanism. Until no final -+ * decision of the VTAB structure is made... Good enough. -+ */ -+ rc = ubigen_create(&u, UBI_LAYOUT_VOLUME_ID, UBI_VID_DYNAMIC, -+ pdd->eb_size, DEFAULT_ERASE_COUNT, -+ 1, UBI_VERSION, -+ pdd->vid_hdr_offset, UBI_COMPAT_REJECT, -+ vol_tab_size, stdin, io->fp_out); -+ /* @FIXME stdin for fp_in is a hack */ -+ if (rc != 0) -+ goto err; -+ rc = ubigen_get_leb_size(u, &leb_size); -+ if (rc != 0) -+ goto err; -+ ubigen_destroy(&u); -+ -+ /* -+ * The number of supported volumes is restricted by the eraseblock size -+ * and by the UBI_MAX_VOLUMES constant. -+ */ -+ vt_slots = leb_size / UBI_VTBL_RECORD_SIZE; -+ if (vt_slots > UBI_MAX_VOLUMES) -+ vt_slots = UBI_MAX_VOLUMES; -+ vol_tab_size_limit = vt_slots * UBI_VTBL_RECORD_SIZE; -+ -+ ptr = (uint8_t*) malloc(leb_size * sizeof(uint8_t)); -+ if (ptr == NULL) -+ goto err; -+ -+ memset(ptr, 0xff, leb_size); -+ memcpy(ptr, vol_tab, vol_tab_size_limit); -+ fp_leb = my_fmemopen(ptr, leb_size, "r"); -+ -+ rc = ubigen_create(&u, UBI_LAYOUT_VOLUME_ID, UBI_VID_DYNAMIC, -+ pdd->eb_size, DEFAULT_ERASE_COUNT, -+ 1, UBI_VERSION, pdd->vid_hdr_offset, -+ UBI_COMPAT_REJECT, leb_size * UBI_LAYOUT_VOLUME_EBS, -+ fp_leb, io->fp_out); -+ if (rc != 0) -+ goto err; -+ rc = ubigen_get_leb_total(u, &leb_total); -+ if (rc != 0) -+ goto err; -+ -+ long old_file_pos = ftell(fp_leb); -+ while(j < leb_total) { -+ rc = fseek(fp_leb, old_file_pos, SEEK_SET); -+ if (rc != 0) -+ goto err; -+ -+ cmp_peb->num = *ebs_written; -+ raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb, -+ raw_pebs); -+ if (raw_peb) { -+ rc = peb_write(io->fp_out, raw_peb); -+ } -+ else { -+ rc = ubigen_write_leb(u, NO_ERROR); -+ j++; -+ } -+ -+ if (rc != 0) -+ goto err; -+ (*ebs_written)++; -+ } -+ -+err: -+ free(ptr); -+ peb_free(&cmp_peb); -+ ubigen_destroy(&u); -+ fclose(fp_leb); -+ return rc; -+} -+ -+static int -+write_remaining_raw_ebs(pdd_data_t pdd, list_t raw_blocks, size_t *ebs_written, -+ FILE* fp_out) -+{ -+ int rc = 0; -+ uint32_t j, delta; -+ list_t ptr; -+ peb_t empty_eb, peb; -+ -+ /* create an empty 0xff EB (for padding) */ -+ rc = peb_new(0, pdd->eb_size, &empty_eb); -+ -+ foreach(peb, ptr, raw_blocks) { -+ if (peb->num < *ebs_written) { -+ continue; /* omit blocks which -+ are already passed */ -+ } -+ -+ if (peb->num < *ebs_written) { -+ err_msg("eb_num: %d\n", peb->num); -+ err_msg("Bug: This should never happen. %d %s", -+ __LINE__, __FILE__); -+ goto err; -+ } -+ -+ delta = peb->num - *ebs_written; -+ if (((delta + *ebs_written) * pdd->eb_size) > pdd->flash_size) { -+ err_msg("RAW block outside of flash_size."); -+ goto err; -+ } -+ for (j = 0; j < delta; j++) { -+ rc = peb_write(fp_out, empty_eb); -+ if (rc != 0) -+ goto err; -+ (*ebs_written)++; -+ } -+ rc = peb_write(fp_out, peb); -+ if (rc != 0) -+ goto err; -+ (*ebs_written)++; -+ } -+ -+err: -+ peb_free(&empty_eb); -+ return rc; -+} -+ -+static int -+init_vol_tab(struct ubi_vtbl_record **vol_tab, size_t *vol_tab_size) -+{ -+ uint32_t crc; -+ size_t i; -+ struct ubi_vtbl_record* res = NULL; -+ -+ *vol_tab_size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE; -+ -+ res = (struct ubi_vtbl_record*) calloc(1, *vol_tab_size); -+ if (vol_tab == NULL) { -+ return -ENOMEM; -+ } -+ -+ for (i = 0; i < UBI_MAX_VOLUMES; i++) { -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, -+ &(res[i]), UBI_VTBL_RECORD_SIZE_CRC); -+ res[i].crc = cpu_to_be32(crc); -+ } -+ -+ *vol_tab = res; -+ return 0; -+} -+ -+static int -+create_raw(io_t io) -+{ -+ int rc = 0; -+ size_t ebs_written = 0; /* eraseblocks written already... */ -+ size_t vol_tab_size; -+ list_t ptr; -+ -+ list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */ -+ list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */ -+ list_t raw_pebs = mk_empty(); /* list of raw eraseblocks */ -+ -+ struct ubi_vtbl_record *vol_tab = NULL; -+ pdd_data_t pdd = NULL; -+ -+ rc = init_vol_tab (&vol_tab, &vol_tab_size); -+ if (rc != 0) { -+ err_msg("Cannot initialize volume table."); -+ goto err; -+ } -+ -+ rc = read_pdd_data(io->fp_pdd, &pdd, -+ err_buf, ERR_BUF_SIZE); -+ if (rc != 0) { -+ err_msg("Cannot read necessary pdd_data: %s rc: %d", -+ err_buf, rc); -+ goto err; -+ } -+ -+ rc = read_pfi_headers(&pfi_raws, &pfi_ubis, io->fp_pfi, -+ err_buf, ERR_BUF_SIZE); -+ if (rc != 0) { -+ err_msg("Cannot read pfi header: %s rc: %d", -+ err_buf, rc); -+ goto err; -+ } -+ -+ pfi_raw_t pfi_raw; -+ foreach(pfi_raw, ptr, pfi_raws) { -+ rc = memorize_raw_eb(pfi_raw, pdd, &raw_pebs, -+ io); -+ if (rc != 0) { -+ err_msg("Cannot create raw_block in mem. rc: %d\n", -+ rc); -+ goto err; -+ } -+ } -+ -+ pfi_ubi_t pfi_ubi; -+ foreach(pfi_ubi, ptr, pfi_ubis) { -+ rc = convert_ubi_volume(pfi_ubi, pdd, raw_pebs, -+ vol_tab, &ebs_written, io); -+ if (rc != 0) { -+ err_msg("Cannot convert UBI volume. rc: %d\n", rc); -+ goto err; -+ } -+ } -+ -+ rc = write_ubi_volume_table(pdd, raw_pebs, vol_tab, vol_tab_size, -+ &ebs_written, io); -+ if (rc != 0) { -+ err_msg("Cannot write UBI volume table. rc: %d\n", rc); -+ goto err; -+ } -+ -+ rc = write_remaining_raw_ebs(pdd, raw_pebs, &ebs_written, io->fp_out); -+ if (rc != 0) -+ goto err; -+ -+ if (io->fp_out != stdout) -+ info_msg("Physical eraseblocks written: %8d\n", ebs_written); -+err: -+ free(vol_tab); -+ pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws); -+ pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis); -+ raw_pebs = remove_all((free_func_t)&peb_free, raw_pebs); -+ free_pdd_data(&pdd); -+ return rc; -+} -+ -+ -+/* ------------------------------------------------------------------------- */ -+static void -+open_io_handle(myargs *args, io_t io) -+{ -+ /* set PDD input */ -+ io->fp_pdd = fopen(args->f_in_pdd, "r"); -+ if (io->fp_pdd == NULL) { -+ err_sys("Cannot open: %s", args->f_in_pdd); -+ } -+ -+ /* set PFI input */ -+ io->fp_pfi = fopen(args->f_in_pfi, "r"); -+ if (io->fp_pfi == NULL) { -+ err_sys("Cannot open PFI input file: %s", args->f_in_pfi); -+ } -+ -+ /* set output prefix */ -+ if (strcmp(args->f_out,"") == 0) -+ io->fp_out = stdout; -+ else { -+ io->fp_out = fopen(args->f_out, "wb"); -+ if (io->fp_out == NULL) { -+ err_sys("Cannot open output file: %s", args->f_out); -+ } -+ } -+} -+ -+static void -+close_io_handle(io_t io) -+{ -+ if (fclose(io->fp_pdd) != 0) { -+ err_sys("Cannot close PDD file."); -+ } -+ if (fclose(io->fp_pfi) != 0) { -+ err_sys("Cannot close PFI file."); -+ } -+ if (io->fp_out != stdout) { -+ if (fclose(io->fp_out) != 0) { -+ err_sys("Cannot close output file."); -+ } -+ } -+ -+ io->fp_pdd = NULL; -+ io->fp_pfi = NULL; -+ io->fp_out = NULL; -+} -+ -+int -+main(int argc, char *argv[]) -+{ -+ int rc = 0; -+ -+ ubigen_init(); -+ init_crc32_table(crc32_table); -+ -+ struct io io = {NULL, NULL, NULL}; -+ myargs args = { -+ .action = ACT_RAW, -+ .verbose = 0, -+ -+ .f_in_pfi = "", -+ .f_in_pdd = "", -+ .f_out = "", -+ -+ /* arguments */ -+ .arg1 = NULL, -+ .options = NULL, -+ }; -+ -+ /* parse arguments */ -+ parse_opt(argc, argv, &args); -+ -+ if (strcmp(args.f_in_pfi, "") == 0) { -+ err_quit("No PFI input file specified!"); -+ } -+ -+ if (strcmp(args.f_in_pdd, "") == 0) { -+ err_quit("No PDD input file specified!"); -+ } -+ -+ open_io_handle(&args, &io); -+ -+ info_msg("[ Creating RAW..."); -+ rc = create_raw(&io); -+ if (rc != 0) { -+ err_msg("Creating RAW failed."); -+ goto err; -+ } -+ -+err: -+ close_io_handle(&io); -+ if (rc != 0) { -+ remove(args.f_out); -+ } -+ -+ return rc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,264 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * Frank Haverkamp -+ * -+ * Process a PFI (partial flash image) and write the data to the -+ * specified UBI volumes. This tool is intended to be used for system -+ * update using PFI files. -+ * -+ * 1.1 fixed output to stderr and stdout in logfile mode. -+ * 1.2 updated. -+ * 1.3 removed argp parsing to be able to use uClib. -+ * 1.4 Minor cleanups. -+ * 1.5 Forgot to delete raw block before updating it. -+ * 1.6 Migrated to new libubi. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#undef DEBUG -+#include "error.h" -+#include "config.h" -+ -+#define PROGRAM_VERSION "1.6" -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "pfiflash - a tool for updating a controller with PFI files.\n"; -+ -+static const char *optionsstr = -+" Standard options:\n" -+" -c, --copyright Print copyright information.\n" -+" -l, --logfile= Write a logfile to .\n" -+" -v, --verbose Be verbose during program execution.\n" -+"\n" -+" Process options:\n" -+" -C, --complete Execute a complete system update. Updates both\n" -+" sides.\n" -+" -p, --pdd-update= Specify the pdd-update algorithm. is either\n" -+" 'keep', 'merge' or 'overwrite'.\n" -+" -r, --raw-flash= Flash the raw data. Use the specified mtd device.\n" -+" -s, --side= Select the side which shall be updated.\n" -+" -x, --compare Only compare on-flash and pfi data, print info if\n" -+" an update is neccessary and return appropriate\n" -+" error code.\n" -+"\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: pfiflash [-cvC?V] [-l ] [-p ] [-r ] [-s ]\n" -+" [--copyright] [--logfile=] [--verbose] [--complete]\n" -+" [--pdd-update=] [--raw-flash=] [--side=]\n" -+" [--compare] [--help] [--usage] [--version] [pfifile]\n"; -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright IBM Corp 2006"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "logfile", .has_arg = 1, .flag = NULL, .val = 'l' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "complete", .has_arg = 0, .flag = NULL, .val = 'C' }, -+ { .name = "pdd-update", .has_arg = 1, .flag = NULL, .val = 'p' }, -+ { .name = "raw-flash", .has_arg = 1, .flag = NULL, .val = 'r' }, -+ { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "compare", .has_arg = 0, .flag = NULL, .val = 'x' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+typedef struct myargs { -+ int verbose; -+ const char *logfile; -+ const char *raw_dev; -+ -+ pdd_handling_t pdd_handling; -+ int seqnum; -+ int compare; -+ int complete; -+ -+ FILE* fp_in; -+ -+ /* special stuff needed to get additional arguments */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+static pdd_handling_t -+get_pdd_handling(const char* str) -+{ -+ if (strcmp(str, "keep") == 0) { -+ return PDD_KEEP; -+ } -+ if (strcmp(str, "merge") == 0) { -+ return PDD_MERGE; -+ } -+ if (strcmp(str, "overwrite") == 0) { -+ return PDD_OVERWRITE; -+ } -+ -+ return -1; -+} -+ -+static int -+get_update_seqnum(const char* str) -+{ -+ uint32_t i = strtoul(str, NULL, 0); -+ -+ if ((i != 0) && (i != 1)) { -+ return -1; -+ } -+ -+ return i; -+} -+ -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "cl:vCp:r:s:x?V", -+ long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ /* standard options */ -+ case 'c': -+ err_msg("%s\n", copyright); -+ exit(0); -+ break; -+ case 'v': -+ args->verbose = 1; -+ break; -+ case 'l': -+ args->logfile = optarg; -+ break; -+ /* process options */ -+ case 'C': -+ args->complete = 1; -+ break; -+ case 'p': -+ args->pdd_handling = get_pdd_handling(optarg); -+ if ((int)args->pdd_handling < 0) { -+ err_quit("Unknown PDD handling: %s.\n" -+ "Please use either " -+ "'keep', 'merge' or" -+ "'overwrite'.\n'"); -+ } -+ break; -+ case 's': -+ args->seqnum = get_update_seqnum(optarg); -+ if (args->seqnum < 0) { -+ err_quit("Unsupported side: %s.\n" -+ "Supported sides are '0' " -+ "and '1'\n", optarg); -+ } -+ break; -+ case 'x': -+ args->compare = 1; -+ break; -+ case 'r': -+ args->raw_dev = optarg; -+ break; -+ case '?': /* help */ -+ err_msg("Usage: pfiflash [OPTION...] [pfifile]"); -+ err_msg("%s", doc); -+ err_msg("%s", optionsstr); -+ err_msg("\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ case 'V': -+ err_msg("%s", PROGRAM_VERSION); -+ exit(0); -+ break; -+ default: -+ err_msg("%s", usage); -+ exit(-1); -+ -+ } -+ } -+ -+ if (optind < argc) { -+ args->fp_in = fopen(argv[optind++], "r"); -+ if ((args->fp_in) == NULL) { -+ err_sys("Cannot open PFI file %s for input", -+ argv[optind]); -+ } -+ } -+ -+ return 0; -+} -+ -+int main (int argc, char** argv) -+{ -+ int rc = 0; -+ char err_buf[PFIFLASH_MAX_ERR_BUF_SIZE]; -+ memset(err_buf, '\0', PFIFLASH_MAX_ERR_BUF_SIZE); -+ -+ myargs args = { -+ .verbose = 0, -+ .seqnum = -1, -+ .compare = 0, -+ .complete = 0, -+ .logfile = NULL, /* "/tmp/pfiflash.log", */ -+ .pdd_handling = PDD_KEEP, -+ .fp_in = stdin, -+ .raw_dev = NULL, -+ }; -+ -+ parse_opt(argc, argv, &args); -+ error_initlog(args.logfile); -+ -+ if (!args.fp_in) { -+ rc = -1; -+ snprintf(err_buf, PFIFLASH_MAX_ERR_BUF_SIZE, -+ "No PFI input file specified!\n"); -+ goto err; -+ } -+ -+ rc = pfiflash_with_options(args.fp_in, args.complete, args.seqnum, -+ args.compare, args.pdd_handling, args.raw_dev, err_buf, -+ PFIFLASH_MAX_ERR_BUF_SIZE); -+ if (rc < 0) { -+ goto err_fp; -+ } -+ -+ err_fp: -+ if (args.fp_in != stdin) -+ fclose(args.fp_in); -+ err: -+ if (rc != 0) -+ err_msg("pfiflash: %s\nrc: %d\n", err_buf, rc); -+ return rc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,76 @@ -+#ifndef __PFIFLASH_H__ -+#define __PFIFLASH_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/** -+ * -+ * @file pfi.h -+ * -+ * @author Oliver Lohmann -+ * -+ * @brief The pfiflash library offers an interface for using the -+ * pfiflash * utility. -+ */ -+ -+#include /* FILE */ -+ -+#define PFIFLASH_MAX_ERR_BUF_SIZE 1024 -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef enum pdd_handling_t -+{ -+ PDD_KEEP = 0, -+ PDD_MERGE, -+ PDD_OVERWRITE, -+ PDD_HANDLING_NUM, /* always the last item */ -+} pdd_handling_t; /**< Possible PDD handle algorithms. */ -+ -+/** -+ * @brief Flashes a PFI file to UBI Device 0. -+ * @param complete [0|1] Do a complete system update. -+ * @param seqnum Index in a redundant group. -+ * @param compare [0|1] Compare contents. -+ * @param pdd_handling The PDD handling algorithm. -+ * @param rawdev Device to use for raw flashing -+ * @param err_buf An error buffer. -+ * @param err_buf_size Size of the error buffer. -+ */ -+int pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare, -+ pdd_handling_t pdd_handling, const char* rawdev, -+ char *err_buf, size_t err_buf_size); -+ -+/** -+ * @brief Flashes a PFI file to UBI Device 0. -+ * @param complete [0|1] Do a complete system update. -+ * @param seqnum Index in a redundant group. -+ * @param pdd_handling The PDD handling algorithm. -+ * @param err_buf An error buffer. -+ * @param err_buf_size Size of the error buffer. -+ */ -+int pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, -+ char *err_buf, size_t err_buf_size); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* __PFIFLASH_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,75 @@ -+#ifndef __PFIFLASH_ERROR_H__ -+#define __PFIFLASH_ERROR_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Author: Drake Dowsett -+ * Contact: Andreas Arnez -+ */ -+ -+enum pfiflash_err { -+ PFIFLASH_ERR_EOF = 1, -+ PFIFLASH_ERR_FIO, -+ PFIFLASH_ERR_UBI_OPEN, -+ PFIFLASH_ERR_UBI_CLOSE, -+ PFIFLASH_ERR_UBI_MKVOL, -+ PFIFLASH_ERR_UBI_RMVOL, -+ PFIFLASH_ERR_UBI_VOL_UPDATE, -+ PFIFLASH_ERR_UBI_VOL_FOPEN, -+ PFIFLASH_ERR_UBI_UNKNOWN, -+ PFIFLASH_ERR_UBI_VID_OOB, -+ PFIFLASH_ERR_BOOTENV_CREATE, -+ PFIFLASH_ERR_BOOTENV_READ, -+ PFIFLASH_ERR_BOOTENV_SIZE, -+ PFIFLASH_ERR_BOOTENV_WRITE, -+ PFIFLASH_ERR_PDD_UNKNOWN, -+ PFIFLASH_ERR_MTD_OPEN, -+ PFIFLASH_ERR_MTD_CLOSE, -+ PFIFLASH_ERR_CRC_CHECK, -+ PFIFLASH_ERR_MTD_ERASE, -+ PFIFLASH_ERR_COMPARE, -+ PFIFLASH_CMP_DIFF -+}; -+ -+const char *const PFIFLASH_ERRSTR[] = { -+ "", -+ "unexpected EOF", -+ "file I/O error", -+ "couldn't open UBI", -+ "couldn't close UBI", -+ "couldn't make UBI volume %d", -+ "couldn't remove UBI volume %d", -+ "couldn't update UBI volume %d", -+ "couldn't open UBI volume %d", -+ "unknown UBI operation", -+ "PFI data contains out of bounds UBI id %d", -+ "couldn't create bootenv%s", -+ "couldn't read bootenv", -+ "couldn't resize bootenv", -+ "couldn't write bootenv on ubi%d_%d", -+ "unknown PDD handling algorithm", -+ "couldn't open MTD device %s", -+ "couldn't close MTD device %s", -+ "CRC check failed: given=0x%08x, calculated=0x%08x", -+ "couldn't erase raw mtd region", -+ "couldn't compare volumes", -+ "on-flash data differ from pfi data, update is neccessary" -+}; -+ -+#endif /* __PFIFLASH_ERROR_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/reader.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/reader.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,482 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Read in PFI (partial flash image) data and store it into internal -+ * data structures for further processing. Take also care about -+ * special handling if the data contains PDD (platform description -+ * data/boot-parameters). -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "bootenv.h" -+#include "reader.h" -+ -+#define __unused __attribute__((unused)) -+ -+/* @FIXME hard coded offsets right now - get them from Artem? */ -+#define NAND2048_DEFAULT_VID_HDR_OFF 1984 -+#define NAND512_DEFAULT_VID_HDR_OFF 448 -+#define NOR_DEFAULT_VID_HDR_OFF 64 -+ -+#define EBUF_PFI(fmt...) \ -+ do { int i = snprintf(err_buf, err_buf_size, "%s\n", label); \ -+ snprintf(err_buf + i, err_buf_size - i, fmt); \ -+ } while (0) -+ -+#define EBUF(fmt...) \ -+ do { snprintf(err_buf, err_buf_size, fmt); } while (0) -+ -+ -+int -+read_pdd_data(FILE* fp_pdd, pdd_data_t* pdd_data, -+ char* err_buf, size_t err_buf_size) -+{ -+ int rc = 0; -+ bootenv_t pdd = NULL; -+ pdd_data_t res = NULL; -+ const char* value; -+ -+ res = (pdd_data_t) malloc(sizeof(struct pdd_data)); -+ if (!res) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ rc = bootenv_create(&pdd); -+ if (rc != 0) { -+ goto err; -+ } -+ rc = bootenv_read_txt(fp_pdd, pdd); -+ if (rc != 0) { -+ goto err; -+ } -+ rc = bootenv_get(pdd, "flash_type", &value); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ if (strcmp(value, "NAND") == 0) { -+ -+ rc = bootenv_get_num(pdd, "flash_page_size", -+ &(res->flash_page_size)); -+ if (rc != 0) { -+ EBUF("Cannot read 'flash_page_size' from pdd."); -+ goto err; -+ } -+ res->flash_type = NAND_FLASH; -+ -+ switch (res->flash_page_size) { -+ case 512: -+ res->vid_hdr_offset = NAND512_DEFAULT_VID_HDR_OFF; -+ break; -+ case 2048: -+ res->vid_hdr_offset = NAND2048_DEFAULT_VID_HDR_OFF; -+ break; -+ default: -+ EBUF("Unsupported 'flash_page_size' %d.", -+ res->flash_page_size); -+ goto err; -+ } -+ } -+ else if (strcmp(value, "NOR") == 0){ -+ res->flash_type = NOR_FLASH; -+ res->vid_hdr_offset = NOR_DEFAULT_VID_HDR_OFF; -+ } -+ else { -+ snprintf(err_buf, err_buf_size, -+ "Unkown flash type: %s", value); -+ goto err; -+ } -+ -+ rc = bootenv_get_num(pdd, "flash_eraseblock_size", -+ &(res->eb_size)); -+ if (rc != 0) { -+ EBUF("Cannot read 'flash_eraseblock_size' from pdd."); -+ goto err; -+ } -+ -+ rc = bootenv_get_num(pdd, "flash_size", -+ &(res->flash_size)); -+ if (rc != 0) { -+ EBUF("Cannot read 'flash_size' from pdd."); -+ goto err; -+ } -+ -+ goto out; -+ err: -+ if (res) { -+ free(res); -+ res = NULL; -+ } -+ out: -+ bootenv_destroy(&pdd); -+ *pdd_data = res; -+ return rc; -+} -+ -+int -+read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw, -+ const char* label, char* err_buf, size_t err_buf_size) -+{ -+ int rc = 0; -+ char tmp_str[PFI_KEYWORD_LEN]; -+ bootenv_list_t raw_start_list = NULL; -+ pfi_raw_t res; -+ size_t size; -+ -+ res = (pfi_raw_t) malloc(sizeof(struct pfi_raw)); -+ if (!res) -+ return -ENOMEM; -+ -+ rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'size' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'crc' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getstring(pfi_hd, "raw_starts", -+ tmp_str, PFI_KEYWORD_LEN); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'raw_starts' from PFI."); -+ goto err; -+ } -+ -+ rc = bootenv_list_create(&raw_start_list); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ rc = bootenv_list_import(raw_start_list, tmp_str); -+ if (rc != 0) { -+ EBUF_PFI("Cannot translate PFI value: %s", tmp_str); -+ goto err; -+ } -+ -+ rc = bootenv_list_to_num_vector(raw_start_list, -+ &size, &(res->starts)); -+ res->starts_size = size; -+ -+ if (rc != 0) { -+ EBUF_PFI("Cannot create numeric value array: %s", tmp_str); -+ goto err; -+ } -+ -+ goto out; -+ -+ err: -+ if (res) { -+ free(res); -+ res = NULL; -+ } -+ out: -+ bootenv_list_destroy(&raw_start_list); -+ *pfi_raw = res; -+ return rc; -+} -+ -+int -+read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi, -+ const char *label, char* err_buf, size_t err_buf_size) -+{ -+ int rc = 0; -+ const char** tmp_names = NULL; -+ char tmp_str[PFI_KEYWORD_LEN]; -+ bootenv_list_t ubi_id_list = NULL; -+ bootenv_list_t ubi_name_list = NULL; -+ pfi_ubi_t res; -+ uint32_t i; -+ size_t size; -+ -+ res = (pfi_ubi_t) calloc(1, sizeof(struct pfi_ubi)); -+ if (!res) -+ return -ENOMEM; -+ -+ rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'size' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'crc' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'ubi_ids' from PFI."); -+ goto err; -+ } -+ -+ rc = bootenv_list_create(&ubi_id_list); -+ if (rc != 0) { -+ goto err; -+ } -+ rc = bootenv_list_create(&ubi_name_list); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ rc = bootenv_list_import(ubi_id_list, tmp_str); -+ if (rc != 0) { -+ EBUF_PFI("Cannot translate PFI value: %s", tmp_str); -+ goto err; -+ } -+ -+ rc = bootenv_list_to_num_vector(ubi_id_list, &size, -+ &(res->ids)); -+ res->ids_size = size; -+ if (rc != 0) { -+ EBUF_PFI("Cannot create numeric value array: %s", tmp_str); -+ goto err; -+ } -+ -+ if (res->ids_size == 0) { -+ rc = -1; -+ EBUF_PFI("Sanity check failed: No ubi_ids specified."); -+ goto err; -+ } -+ -+ rc = pfi_header_getstring(pfi_hd, "ubi_type", -+ tmp_str, PFI_KEYWORD_LEN); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'ubi_type' from PFI."); -+ goto err; -+ } -+ if (strcmp(tmp_str, "static") == 0) -+ res->type = pfi_ubi_static; -+ else if (strcmp(tmp_str, "dynamic") == 0) -+ res->type = pfi_ubi_dynamic; -+ else { -+ EBUF_PFI("Unknown ubi_type in PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getnumber(pfi_hd, "ubi_alignment", &(res->alignment)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'ubi_alignment' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getnumber(pfi_hd, "ubi_size", &(res->size)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'ubi_size' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getstring(pfi_hd, "ubi_names", -+ tmp_str, PFI_KEYWORD_LEN); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'ubi_names' from PFI."); -+ goto err; -+ } -+ -+ rc = bootenv_list_import(ubi_name_list, tmp_str); -+ if (rc != 0) { -+ EBUF_PFI("Cannot translate PFI value: %s", tmp_str); -+ goto err; -+ } -+ rc = bootenv_list_to_vector(ubi_name_list, &size, -+ &(tmp_names)); -+ res->names_size = size; -+ if (rc != 0) { -+ EBUF_PFI("Cannot create string array: %s", tmp_str); -+ goto err; -+ } -+ -+ if (res->names_size != res->ids_size) { -+ EBUF_PFI("Sanity check failed: ubi_ids list does not match " -+ "sizeof ubi_names list."); -+ rc = -1; -+ } -+ -+ /* copy tmp_names to own structure */ -+ res->names = (char**) calloc(1, res->names_size * sizeof (char*)); -+ if (res->names == NULL) -+ goto err; -+ -+ for (i = 0; i < res->names_size; i++) { -+ res->names[i] = calloc(PFI_UBI_VOL_NAME_LEN + 1, sizeof(char)); -+ if (res->names[i] == NULL) -+ goto err; -+ strncpy(res->names[i], tmp_names[i], PFI_UBI_VOL_NAME_LEN + 1); -+ } -+ -+ goto out; -+ -+ err: -+ if (res) { -+ if (res->names) { -+ for (i = 0; i < res->names_size; i++) { -+ if (res->names[i]) { -+ free(res->names[i]); -+ } -+ } -+ free(res->names); -+ } -+ if (res->ids) { -+ free(res->ids); -+ } -+ free(res); -+ res = NULL; -+ } -+ -+ out: -+ bootenv_list_destroy(&ubi_id_list); -+ bootenv_list_destroy(&ubi_name_list); -+ if (tmp_names != NULL) -+ free(tmp_names); -+ *pfi_ubi = res; -+ return rc; -+} -+ -+ -+int -+free_pdd_data(pdd_data_t* pdd_data) -+{ -+ if (*pdd_data) { -+ free(*pdd_data); -+ } -+ *pdd_data = NULL; -+ -+ return 0; -+} -+ -+int -+free_pfi_raw(pfi_raw_t* pfi_raw) -+{ -+ pfi_raw_t tmp = *pfi_raw; -+ if (tmp) { -+ if (tmp->starts) -+ free(tmp->starts); -+ free(tmp); -+ } -+ *pfi_raw = NULL; -+ -+ return 0; -+} -+ -+int -+free_pfi_ubi(pfi_ubi_t* pfi_ubi) -+{ -+ size_t i; -+ pfi_ubi_t tmp = *pfi_ubi; -+ if (tmp) { -+ if (tmp->ids) -+ free(tmp->ids); -+ if (tmp->names) { -+ for (i = 0; i < tmp->names_size; i++) { -+ if (tmp->names[i]) { -+ free(tmp->names[i]); -+ } -+ } -+ free(tmp->names); -+ } -+ free(tmp); -+ } -+ *pfi_ubi = NULL; -+ -+ return 0; -+} -+ -+ -+int -+read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi, -+ char* err_buf, size_t err_buf_size) -+{ -+ int rc = 0; -+ char mode[PFI_KEYWORD_LEN]; -+ char label[PFI_LABEL_LEN]; -+ -+ *pfi_raws = mk_empty(); pfi_raw_t raw = NULL; -+ *pfi_ubis = mk_empty(); pfi_ubi_t ubi = NULL; -+ pfi_header pfi_header = NULL; -+ -+ /* read all headers from PFI and store them in lists */ -+ rc = pfi_header_init(&pfi_header); -+ if (rc != 0) { -+ EBUF("Cannot initialize pfi header."); -+ goto err; -+ } -+ while ((rc == 0) && !feof(fp_pfi)) { -+ rc = pfi_header_read(fp_pfi, pfi_header); -+ if (rc != 0) { -+ if (rc == PFI_DATA_START) { -+ rc = 0; -+ break; /* data section starts, -+ all headers read */ -+ } -+ else { -+ goto err; -+ } -+ } -+ rc = pfi_header_getstring(pfi_header, "label", label, -+ PFI_LABEL_LEN); -+ if (rc != 0) { -+ EBUF("Cannot read 'label' from PFI."); -+ goto err; -+ } -+ rc = pfi_header_getstring(pfi_header, "mode", mode, -+ PFI_KEYWORD_LEN); -+ if (rc != 0) { -+ EBUF("Cannot read 'mode' from PFI."); -+ goto err; -+ } -+ if (strcmp(mode, "ubi") == 0) { -+ rc = read_pfi_ubi(pfi_header, fp_pfi, &ubi, label, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ goto err; -+ } -+ *pfi_ubis = append_elem(ubi, *pfi_ubis); -+ } -+ else if (strcmp(mode, "raw") == 0) { -+ rc = read_pfi_raw(pfi_header, fp_pfi, &raw, label, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ goto err; -+ } -+ *pfi_raws = append_elem(raw, *pfi_raws); -+ } -+ else { -+ EBUF("Recvieved unknown mode from PFI: %s", mode); -+ goto err; -+ } -+ } -+ goto out; -+ -+ err: -+ *pfi_raws = remove_all((free_func_t)&free_pfi_raw, *pfi_raws); -+ *pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, *pfi_ubis); -+ out: -+ pfi_header_destroy(&pfi_header); -+ return rc; -+ -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/reader.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/reader.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,87 @@ -+#ifndef __READER_H__ -+#define __READER_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Read Platform Description Data (PDD). -+ */ -+ -+#include -+#include -+ -+#include "pfi.h" -+#include "bootenv.h" -+#include "list.h" -+ -+typedef enum flash_type_t { -+ NAND_FLASH = 0, -+ NOR_FLASH, -+} flash_type_t; -+ -+typedef struct pdd_data *pdd_data_t; -+typedef struct pfi_raw *pfi_raw_t; -+typedef struct pfi_ubi *pfi_ubi_t; -+ -+struct pdd_data { -+ uint32_t flash_size; -+ uint32_t flash_page_size; -+ uint32_t eb_size; -+ uint32_t vid_hdr_offset; -+ flash_type_t flash_type; -+}; -+ -+struct pfi_raw { -+ uint32_t data_size; -+ uint32_t *starts; -+ uint32_t starts_size; -+ uint32_t crc; -+}; -+ -+struct pfi_ubi { -+ uint32_t data_size; -+ uint32_t alignment; -+ uint32_t *ids; -+ uint32_t ids_size; -+ char **names; -+ uint32_t names_size; -+ uint32_t size; -+ enum { pfi_ubi_dynamic, pfi_ubi_static } type; -+ int curr_seqnum; /* specifies the seqnum taken in an update, -+ default: 0 (used by pfiflash, ubimirror) */ -+ uint32_t crc; -+}; -+ -+int read_pdd_data(FILE* fp_pdd, pdd_data_t *pdd_data, -+ char *err_buf, size_t err_buf_size); -+int read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi, pfi_raw_t *pfi_raw, -+ const char *label, char *err_buf, size_t err_buf_size); -+int read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi, pfi_ubi_t *pfi_ubi, -+ const char *label, char *err_buf, size_t err_buf_size); -+ -+/** -+ * @brief Reads all pfi headers into list structures, separated by -+ * RAW and UBI sections. -+ */ -+int read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi, -+ char* err_buf, size_t err_buf_size); -+int free_pdd_data(pdd_data_t *pdd_data); -+int free_pfi_raw(pfi_raw_t *raw_pfi); -+int free_pfi_ubi(pfi_ubi_t *pfi_ubi); -+ -+#endif /* __READER_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,359 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Tool to add UBI headers to binary images. -+ * -+ * 1.0 Initial version -+ * 1.1 Different CRC32 start value -+ * 1.2 Removed argp because we want to use uClibc. -+ * 1.3 Minor cleanups -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "ubigen.h" -+#include "config.h" -+ -+#define PROGRAM_VERSION "1.3" -+ -+typedef enum action_t { -+ ACT_NORMAL = 0x00000001, -+ ACT_BROKEN_UPDATE = 0x00000002, -+} action_t; -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "ubigen - a tool for adding UBI information to a binary input file.\n"; -+ -+static const char *optionsstr = -+" Common settings:\n" -+" -c, --copyright Print copyright information.\n" -+" -d, --debug\n" -+" -v, --verbose Print more progress information.\n" -+"\n" -+" UBI Settings:\n" -+" -A, --alignment= Set the alignment size to (default 1).\n" -+" Values can be specified as bytes, 'ki' or 'Mi'.\n" -+" -B, --blocksize= Set the eraseblock size to (default 128\n" -+" KiB).\n" -+" Values can be specified as bytes, 'ki' or 'Mi'.\n" -+" -E, --erasecount= Set the erase count to (default 0)\n" -+" -I, --id= The UBI volume id.\n" -+" -O, --offset= Offset from start of an erase block to the UBI\n" -+" volume header.\n" -+" -T, --type= The UBI volume type:\n" -+" 1 = dynamic, 2 = static\n" -+" -X, --setver= Set UBI version number to (default 1)\n" -+"\n" -+" Input/Output:\n" -+" -i, --infile= Read input from file.\n" -+" -o, --outfile= Write output to file (default is stdout).\n" -+"\n" -+" Special options:\n" -+" -U, --broken-update= Create an ubi image which simulates a broken\n" -+" update.\n" -+" specifies the logical eraseblock number to\n" -+" update.\n" -+"\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: ubigen [-cdv?V] [-A ] [-B ] [-E ] [-I ]\n" -+" [-O ] [-T ] [-X ] [-i ] [-o ]\n" -+" [-U ] [--copyright] [--debug] [--verbose] [--alignment=]\n" -+" [--blocksize=] [--erasecount=] [--id=]\n" -+" [--offset=] [--type=] [--setver=]\n" -+" [--infile=] [--outfile=]\n" -+" [--broken-update=] [--help] [--usage] [--version]\n"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "debug", .has_arg = 0, .flag = NULL, .val = 'd' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "alignment", .has_arg = 1, .flag = NULL, .val = 'A' }, -+ { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'B' }, -+ { .name = "erasecount", .has_arg = 1, .flag = NULL, .val = 'E' }, -+ { .name = "id", .has_arg = 1, .flag = NULL, .val = 'I' }, -+ { .name = "offset", .has_arg = 1, .flag = NULL, .val = 'O' }, -+ { .name = "type", .has_arg = 1, .flag = NULL, .val = 'T' }, -+ { .name = "setver", .has_arg = 1, .flag = NULL, .val = 'X' }, -+ { .name = "infile", .has_arg = 1, .flag = NULL, .val = 'i' }, -+ { .name = "outfile", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "broken-update", .has_arg = 1, .flag = NULL, .val = 'U' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright IBM Corp 2006"; -+ -+#define CHECK_ENDP(option, endp) do { \ -+ if (*endp) { \ -+ fprintf(stderr, \ -+ "Parse error option \'%s\'. " \ -+ "No correct numeric value.\n" \ -+ , option); \ -+ exit(EXIT_FAILURE); \ -+ } \ -+} while(0) -+ -+typedef struct myargs { -+ /* common settings */ -+ action_t action; -+ int verbose; -+ -+ int32_t id; -+ uint8_t type; -+ uint32_t eb_size; -+ uint64_t ec; -+ uint8_t version; -+ uint32_t hdr_offset; -+ uint32_t update_block; -+ uint32_t alignment; -+ -+ FILE* fp_in; -+ FILE* fp_out; -+ -+ /* special stuff needed to get additional arguments */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+ -+static int ustrtoul(const char *cp, char **endp, unsigned int base) -+{ -+ unsigned long result = strtoul(cp, endp, base); -+ -+ switch (**endp) { -+ case 'G': -+ result *= 1024; -+ case 'M': -+ result *= 1024; -+ case 'k': -+ case 'K': -+ result *= 1024; -+ /* "Ki", "ki", "Mi" or "Gi" are to be used. */ -+ if ((*endp)[1] == 'i') -+ (*endp) += 2; -+ } -+ return result; -+} -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ int err = 0; -+ char* endp; -+ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "cdvA:B:E:I:O:T:X:i:o:U:?V", -+ long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'c': -+ fprintf(stderr, "%s\n", copyright); -+ exit(0); -+ break; -+ case 'o': /* output */ -+ args->fp_out = fopen(optarg, "wb"); -+ if ((args->fp_out) == NULL) { -+ fprintf(stderr, "Cannot open file %s " -+ "for output\n", optarg); -+ exit(1); -+ } -+ break; -+ case 'i': /* input */ -+ args->fp_in = fopen(optarg, "rb"); -+ if ((args->fp_in) == NULL) { -+ fprintf(stderr, "Cannot open file %s " -+ "for input\n", optarg); -+ exit(1); -+ } -+ break; -+ case 'v': /* verbose */ -+ args->verbose = 1; -+ break; -+ -+ case 'B': /* eb_size */ -+ args->eb_size = -+ (uint32_t)ustrtoul(optarg, &endp, 0); -+ CHECK_ENDP("B", endp); -+ break; -+ case 'E': /* erasecount */ -+ args->ec = (uint64_t)strtoul(optarg, &endp, 0); -+ CHECK_ENDP("E", endp); -+ break; -+ case 'I': /* id */ -+ args->id = (uint16_t)strtoul(optarg, &endp, 0); -+ CHECK_ENDP("I", endp); -+ break; -+ case 'T': /* type */ -+ args->type = -+ (uint16_t)strtoul(optarg, &endp, 0); -+ CHECK_ENDP("T", endp); -+ break; -+ case 'X': /* versionnr */ -+ args->version = -+ (uint8_t)strtoul(optarg, &endp, 0); -+ CHECK_ENDP("X", endp); -+ break; -+ case 'O': /* offset for volume hdr */ -+ args->hdr_offset = -+ (uint32_t) strtoul(optarg, &endp, 0); -+ CHECK_ENDP("O", endp); -+ break; -+ -+ case 'U': /* broken update */ -+ args->action = ACT_BROKEN_UPDATE; -+ args->update_block = -+ (uint32_t) strtoul(optarg, &endp, 0); -+ CHECK_ENDP("U", endp); -+ break; -+ -+ case '?': /* help */ -+ fprintf(stderr, "Usage: ubigen [OPTION...]\n"); -+ fprintf(stderr, "%s", doc); -+ fprintf(stderr, "%s", optionsstr); -+ fprintf(stderr, "\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(0); -+ break; -+ -+ default: -+ fprintf(stderr, "%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) { -+ if (!args->fp_in) { -+ args->fp_in = fopen(argv[optind++], "rb"); -+ if ((args->fp_in) == NULL) { -+ fprintf(stderr, "Cannot open file %s for " -+ "input\n", argv[optind]); -+ exit(1); -+ } -+ } -+ } -+ if (args->id < 0) { -+ err = 1; -+ fprintf(stderr, -+ "Please specify an UBI Volume ID.\n"); -+ } -+ if (args->type == 0) { -+ err = 1; -+ fprintf(stderr, -+ "Please specify an UBI Volume type.\n"); -+ } -+ if (err) { -+ fprintf(stderr, "%s", usage); -+ exit(1); -+ } -+ -+ return 0; -+} -+ -+ -+int -+main(int argc, char **argv) -+{ -+ int rc = 0; -+ ubi_info_t u; -+ struct stat file_info; -+ off_t input_len = 0; /* only used in static volumes */ -+ -+ myargs args = { -+ .action = ACT_NORMAL, -+ .verbose = 0, -+ -+ .id = -1, -+ .type = 0, -+ .eb_size = 0, -+ .update_block = 0, -+ .ec = 0, -+ .version = 0, -+ .hdr_offset = (DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE), -+ .alignment = 1, -+ -+ .fp_in = NULL, -+ .fp_out = stdout, -+ /* arguments */ -+ .arg1 = NULL, -+ .options = NULL, -+ }; -+ -+ ubigen_init(); /* Init CRC32 table in ubigen */ -+ -+ /* parse arguments */ -+ parse_opt(argc, argv, &args); -+ -+ if (fstat(fileno(args.fp_in), &file_info) != 0) { -+ fprintf(stderr, "Cannot fetch file size " -+ "from input file.\n"); -+ } -+ input_len = file_info.st_size; -+ -+ rc = ubigen_create(&u, (uint32_t)args.id, args.type, -+ args.eb_size, args.ec, args.alignment, -+ args.version, args.hdr_offset, 0 ,input_len, -+ args.fp_in, args.fp_out); -+ -+ if (rc != 0) { -+ fprintf(stderr, "Cannot create UBI info handler rc: %d\n", rc); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (!args.fp_in || !args.fp_out) { -+ fprintf(stderr, "Input/Output error.\n"); -+ exit(EXIT_FAILURE); -+ -+ } -+ -+ if (args.action & ACT_NORMAL) { -+ rc = ubigen_write_complete(u); -+ } -+ else if (args.action & ACT_BROKEN_UPDATE) { -+ rc = ubigen_write_broken_update(u, args.update_block); -+ } -+ if (rc != 0) { -+ fprintf(stderr, "Error converting input data.\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ rc = ubigen_destroy(&u); -+ return rc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,149 @@ -+#ifndef __UBIGEN_H__ -+#define __UBIGEN_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Frank Haverkamp -+ * -+ * An utility to update UBI volumes. -+ */ -+ -+#include /* FILE */ -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#define DEFAULT_BLOCKSIZE (128 * 1024) -+#define DEFAULT_PAGESIZE (2*1024) -+ -+#define EUBIGEN_INVALID_TYPE 1 -+#define EUBIGEN_INVALID_HDR_OFFSET 2 -+#define EUBIGEN_INVALID_ALIGNMENT 3 -+#define EUBIGEN_TOO_SMALL_EB 4 -+#define EUBIGEN_MAX_ERROR 5 -+ -+ -+typedef enum action { -+ NO_ERROR = 0x00000000, -+ BROKEN_HDR_CRC = 0x00000001, -+ BROKEN_DATA_CRC = 0x00000002, -+ BROKEN_DATA_SIZE = 0x00000004, -+ BROKEN_OMIT_BLK = 0x00000008, -+ MARK_AS_UPDATE = 0x00000010, -+} ubigen_action_t; -+ -+typedef struct ubi_info *ubi_info_t; -+ -+/** -+ * @brief Initialize the internal CRC32 table. -+ * @note Necessary because of the used crc32 function in UBI. -+ * A usage of CRC32, from e.g. zlib will fail. -+ */ -+void ubigen_init(void); -+ -+/** -+ * @brief Create an ubigen handle. -+ * @param ... -+ * @return 0 On sucess. -+ * else Error. -+ * @note This parameterlist is ugly. But we have to use -+ * two big structs and meta information internally, -+ * filling them would be even uglier. -+ */ -+int ubigen_create(ubi_info_t *u, uint32_t vol_id, uint8_t vol_type, -+ uint32_t eb_size, uint64_t ec, uint32_t alignment, -+ uint8_t version, uint32_t vid_hdr_offset, -+ uint8_t compat_flag, size_t data_size, -+ FILE* fp_in, FILE* fp_out); -+ -+/** -+ * @brief Destroy an ubigen handle. -+ * @param u Handle to free. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_destroy(ubi_info_t *u); -+ -+/** -+ * @brief Get number of total logical EBs, necessary for the -+ * complete storage of data in the handle. -+ * @param u The handle. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_get_leb_total(ubi_info_t u, size_t* total); -+ -+/** -+ * @brief Get the size in bytes of one logical EB in the handle. -+ * @param u The handle. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_get_leb_size(ubi_info_t u, size_t* size); -+ -+ -+/** -+ * @brief Write a logical EB (fits exactly into 1 physical EB). -+ * @param u Handle which holds all necessary data. -+ * @param action Additional operations which shall be applied on this -+ * logical eraseblock. Mostly injecting artifical errors. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_write_leb(ubi_info_t u, ubigen_action_t action); -+ -+/** -+ * @brief Write a complete array of logical eraseblocks at once. -+ * @param u Handle which holds all necessary data. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_write_complete(ubi_info_t u); -+ -+/** -+ * @brief Write a single block which is extracted from the -+ * binary input data. -+ * @param u Handle which holds all necessary data. -+ * @param blk Logical eraseblock which shall hold a inc. copy entry -+ * and a bad data crc. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_write_broken_update(ubi_info_t u, uint32_t blk); -+ -+/** -+ * @brief Use the current ubi_info data and some additional data -+ * to set an UBI volume table entry from it. -+ * @param u Handle which holds some of the necessary data. -+ * @param res_bytes Number of reserved bytes which is stored in the volume -+ * table entry. -+ * @param name A string which shall be used as a volume label. -+ * @param lvol_r A pointer to a volume table entry. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes, -+ const char* name, struct ubi_vtbl_record *lvol_rec); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* __UBIGEN_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,213 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * 1.2 Removed argp because we want to use uClibc. -+ * 1.3 Minor cleanups -+ * 1.4 Migrated to new libubi -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "config.h" -+#include "error.h" -+#include "example_ubi.h" -+#include "ubimirror.h" -+ -+#define PROGRAM_VERSION "1.4" -+ -+typedef enum action_t { -+ ACT_NORMAL = 0, -+ ACT_ARGP_ABORT, -+ ACT_ARGP_ERR, -+} action_t; -+ -+#define ABORT_ARGP do { \ -+ args->action = ACT_ARGP_ABORT; \ -+} while (0) -+ -+#define ERR_ARGP do { \ -+ args->action = ACT_ARGP_ERR; \ -+} while (0) -+ -+#define VOL_ARGS_MAX 2 -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "ubimirror - mirrors ubi volumes.\n"; -+ -+static const char *optionsstr = -+" -c, --copyright Print copyright information.\n" -+" -s, --side= Use the side as source.\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: ubimirror [-c?V] [-s ] [--copyright] [--side=]\n" -+" [--help] [--usage] [--version] \n"; -+ -+static const char copyright [] __attribute__((unused)) = -+ "(C) IBM Coorporation 2007"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+typedef struct myargs { -+ action_t action; -+ int side; -+ int vol_no; /* index of current volume */ -+ /* @FIXME replace by bootenv_list, makes live easier */ -+ /* @FIXME remove the constraint of two entries in the array */ -+ const char* vol[VOL_ARGS_MAX]; /* comma separated list of src/dst -+ volumes */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+static int -+get_update_side(const char* str) -+{ -+ uint32_t i = strtoul(str, NULL, 0); -+ -+ if ((i != 0) && (i != 1)) { -+ return -1; -+ } -+ return i; -+} -+ -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "cs:?V", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'c': -+ err_msg("%s", copyright); -+ ABORT_ARGP; -+ break; -+ case 's': -+ args->side = get_update_side(optarg); -+ if (args->side < 0) { -+ err_msg("Unsupported seqnum: %s.\n" -+ "Supported seqnums are '0' " -+ "and '1'\n", optarg); -+ ERR_ARGP; -+ } -+ break; -+ case '?': /* help */ -+ err_msg("Usage: ubimirror [OPTION...] " -+ " \n"); -+ err_msg("%s", doc); -+ err_msg("%s", optionsstr); -+ err_msg("\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ case 'V': -+ err_msg("%s", PROGRAM_VERSION); -+ exit(0); -+ break; -+ default: -+ err_msg("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ while (optind < argc) { -+ /* only two entries allowed */ -+ if (args->vol_no >= VOL_ARGS_MAX) { -+ err_msg("%s", usage); -+ ERR_ARGP; -+ } -+ args->vol[(args->vol_no)++] = argv[optind++]; -+ } -+ -+ return 0; -+} -+ -+ -+int -+main(int argc, char **argv) { -+ int rc = 0; -+ unsigned int ids[VOL_ARGS_MAX]; -+ char err_buf[1024]; -+ -+ myargs args = { -+ .action = ACT_NORMAL, -+ .side = -1, -+ .vol_no = 0, -+ .vol = {"", ""}, -+ .options = NULL, -+ }; -+ -+ parse_opt(argc, argv, &args); -+ if (args.action == ACT_ARGP_ERR) { -+ rc = 127; -+ goto err; -+ } -+ if (args.action == ACT_ARGP_ABORT) { -+ rc = 126; -+ goto out; -+ } -+ if (args.vol_no < VOL_ARGS_MAX) { -+ fprintf(stderr, "missing volume number for %s\n", -+ args.vol_no == 0 ? "source and target" : "target"); -+ rc = 125; -+ goto out; -+ } -+ for( rc = 0; rc < args.vol_no; ++rc){ -+ char *endp; -+ ids[rc] = strtoul(args.vol[rc], &endp, 0); -+ if( *endp != '\0' ){ -+ fprintf(stderr, "invalid volume number %s\n", -+ args.vol[rc]); -+ rc = 125; -+ goto out; -+ } -+ } -+ rc = ubimirror(EXAMPLE_UBI_DEVICE, args.side, ids, args.vol_no, -+ err_buf, sizeof(err_buf)); -+ if( rc ){ -+ err_buf[sizeof err_buf - 1] = '\0'; -+ fprintf(stderr, err_buf); -+ if( rc < 0 ) -+ rc = -rc; -+ } -+ out: -+ err: -+ return rc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,66 @@ -+#ifndef __UBIMIRROR_H__ -+#define __UBIMIRROR_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * An utility to mirror UBI volumes. -+ */ -+ -+#include -+ -+/** -+ * @def EUBIMIRROR_SRC_EQ_DST -+ * @brief Given source volume is also in the set of destination volumes. -+ */ -+#define EUBIMIRROR_SRC_EQ_DST 20 -+ -+/** -+ * @def EUBIMIRROR_NO_SRC -+ * @brief The given source volume does not exist. -+ */ -+#define EUBIMIRROR_NO_SRC 21 -+ -+/** -+ * @def EUBIMIRROR_NO_DST -+ * @brief One of the given destination volumes does not exist. -+ */ -+#define EUBIMIRROR_NO_DST 22 -+ -+/** -+ * @brief Mirrors UBI devices from a source device (specified by seqnum) -+ * to n target devices. -+ * @param devno Device number used by the UBI operations. -+ * @param seqnum An index into ids (defines the src_id). -+ * @param ids An array of ids. -+ * @param ids_size The number of entries in the ids array. -+ * @param err_buf A buffer to store verbose error messages. -+ * @param err_buf_size The size of the error buffer. -+ * -+ * @note A seqnum of value < 0 defaults to a seqnum of 0. -+ * @note A seqnum exceeding the range of ids_size defaults to 0. -+ * @note An empty ids list results in a empty stmt. -+ * @pre The UBI volume which shall be used as source volume exists. -+ * @pre The UBI volumes which are defined as destination volumes exist. -+ * @post The content of the UBI volume which was defined as source volume -+ * equals the content of the volumes which were defined as destination. -+ */ -+int ubimirror(uint32_t devno, int seqnum, uint32_t* ids, ssize_t ids_size, -+ char *err_buf, size_t err_buf_size); -+ -+#endif /* __UBIMIRROR_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1024 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Authors: Drake Dowsett, dowsett@de.ibm.com -+ * Frank Haverkamp, haver@vnet.ibm.com -+ * -+ * 1.2 Removed argp because we want to use uClibc. -+ * 1.3 Minor cleanups. -+ * 1.4 Meanwhile Drake had done a lot of changes, syncing those. -+ * 1.5 Bugfixes, simplifications -+ */ -+ -+/* -+ * unubi reads an image file containing blocks of UBI headers and data -+ * (such as produced from nand2bin) and rebuilds the volumes within. The -+ * default operation (when no flags are given) is to rebuild all valid -+ * volumes found in the image. unubi can also read straight from the -+ * onboard MTD device (ex. /dev/mtdblock/NAND). -+ */ -+ -+/* TODO: consideration for dynamic vs. static volumes */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "crc32.h" -+#include "unubi_analyze.h" -+ -+#define EXEC "unubi" -+#define CONTACT "haver@vnet.ibm.com" -+#define VERSION "1.5" -+ -+static char doc[] = "\nVersion: " VERSION "\n"; -+static int debug = 0; -+ -+static const char *optionsstr = -+"Extract volumes and/or analysis information from an UBI data file.\n" -+"When no parameters are flagged or given, the default operation is\n" -+"to rebuild all valid complete UBI volumes found within the image.\n" -+"\n" -+" OPERATIONS\n" -+" -a, --analyze Analyze image and create gnuplot graphs\n" -+" -i, --info-table Extract volume information tables\n" -+" -r, --rebuild= Extract and rebuild volume\n" -+"\n" -+" OPTIONS\n" -+" -b, --blocksize= Specify size of eraseblocks in image in bytes\n" -+" (default 128KiB)\n" -+" -d, --dir= Specify output directory\n" -+" -D, --debug Enable debug output\n" -+" -s, --headersize= Specify size reserved for metadata in eraseblock\n" -+ " in bytes (default 2048 Byte)\n" -+ /* the -s option might be insufficient when using different vid -+ offset than what we used when writing this tool ... Better would -+ probably be --vid-hdr-offset or alike */ -+"\n" -+" ADVANCED\n" -+" -e, --eb-split Generate individual eraseblock images (all\n" -+" eraseblocks)\n" -+" -v, --vol-split Generate individual eraseblock images (valid\n" -+" eraseblocks only)\n" -+" -V, --vol-split! Raw split by eraseblock (valid eraseblocks only)\n" -+"\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" --version Print program version\n" -+"\n"; -+ -+static const char *usage = -+"Usage: unubi [-aievV?] [-r ] [-b ] [-d ]\n" -+" [-s ] [--analyze] [--info-table]\n" -+" [--rebuild=] [--blocksize=]\n" -+" [--dir=] [--headersize=] [--eb-split]\n" -+" [--vol-split] [--vol-split!] [--help] [--usage] [--version]\n" -+" image-file\n"; -+ -+#define ERR_MSG(fmt...) \ -+ fprintf(stderr, EXEC ": " fmt) -+ -+#define SPLIT_DATA 1 -+#define SPLIT_RAW 2 -+ -+#define DIR_FMT "unubi_%s" -+#define KIB 1024 -+#define MIB (KIB * KIB) -+#define MAXPATH KIB -+ -+/* filenames */ -+#define FN_INVAL "%s/eb%04u%s" /* invalid eraseblock */ -+#define FN_NSURE "%s/eb%04u_%03u_%03u_%03x%s" /* unsure eraseblock */ -+#define FN_VALID "%s/eb%04u_%03u_%03u_%03x%s" /* valid eraseblock */ -+#define FN_VOLSP "%s/vol%03u_%03u_%03u_%04zu" /* split volume */ -+#define FN_VOLWH "%s/volume%03u" /* whole volume */ -+#define FN_VITBL "%s/vol_info_table%zu" /* vol info table */ -+ -+static uint32_t crc32_table[256]; -+ -+/* struct args: -+ * bsize int, blocksize of image blocks -+ * hsize int, eraseblock header size -+ * analyze flag, when non-zero produce analysis -+ * eb_split flag, when non-zero output eb#### -+ * note: SPLIT_DATA vs. SPLIT_RAW -+ * vol_split flag, when non-zero output vol###_#### -+ * note: SPLIT_DATA vs. SPLIT_RAW -+ * odir_path string, directory to place volumes in -+ * img_path string, file to read as ubi image -+ * vols int array of size UBI_MAX_VOLUMES, where a 1 can be -+ * written for each --rebuild flag in the index specified -+ * then the array can be counted and collapsed using -+ * count_set() and collapse() -+ */ -+struct args { -+ int analyze; -+ int itable; -+ uint32_t *vols; -+ -+ size_t vid_hdr_offset; -+ size_t data_offset; -+ size_t bsize; /* FIXME replace by vid_hdr/data offs? */ -+ size_t hsize; -+ -+ char *odir_path; -+ int eb_split; -+ int vol_split; -+ char *img_path; -+ -+ char **options; -+}; -+ -+struct option long_options[] = { -+ { .name = "rebuild", .has_arg = 1, .flag = NULL, .val = 'r' }, -+ { .name = "dir", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "analyze", .has_arg = 0, .flag = NULL, .val = 'a' }, -+ { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' }, -+ { .name = "eb-split", .has_arg = 0, .flag = NULL, .val = 'e' }, -+ { .name = "vol-split", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "vol-split!", .has_arg = 0, .flag = NULL, .val = 'e' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'J' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+/** -+ * parses out a numerical value from a string of numbers followed by: -+ * k, K, kib, KiB for kibibyte -+ * m, M, mib, MiB for mebibyte -+ **/ -+static uint32_t -+str_to_num(char *str) -+{ -+ char *s; -+ ulong num; -+ -+ s = str; -+ num = strtoul(s, &s, 0); -+ -+ if (*s != '\0') { -+ if ((strcmp(s, "KiB") == 0) || (strcmp(s, "K") == 0) || -+ (strcmp(s, "kib") == 0) || (strcmp(s, "k") == 0)) -+ num *= KIB; -+ else if ((strcmp(s, "MiB") == 0) || (strcmp(s, "M") == 0) || -+ (strcmp(s, "mib") == 0) || (strcmp(s, "m") == 0)) -+ num *= MIB; -+ else -+ ERR_MSG("couldn't parse '%s', assuming %lu\n", -+ s, num); -+ } -+ return num; -+} -+ -+static int -+parse_opt(int argc, char **argv, struct args *args) -+{ -+ uint32_t i; -+ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "ab:s:d:Deir:vV?J", -+ long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'a': /* --analyze */ -+ args->analyze = 1; -+ break; -+ case 'b': /* --block-size= */ -+ args->bsize = str_to_num(optarg); -+ break; -+ case 's': /* --header-size= */ -+ args->hsize = str_to_num(optarg); -+ break; -+ case 'd': /* --dir= */ -+ args->odir_path = optarg; -+ break; -+ case 'D': /* --debug */ -+ /* I wanted to use -v but that was already -+ used ... */ -+ debug = 1; -+ break; -+ case 'e': /* --eb-split */ -+ args->eb_split = SPLIT_RAW; -+ break; -+ case 'i': /* --info-table */ -+ args->itable = 1; -+ break; -+ case 'r': /* --rebuild= */ -+ i = str_to_num(optarg); -+ if (i < UBI_MAX_VOLUMES) -+ args->vols[str_to_num(optarg)] = 1; -+ else { -+ ERR_MSG("volume-id out of bounds\n"); -+ return -1; -+ } -+ break; -+ case 'v': /* --vol-split */ -+ if (args->vol_split != SPLIT_RAW) -+ args->vol_split = SPLIT_DATA; -+ break; -+ case 'V': /* --vol-split! */ -+ args->vol_split = SPLIT_RAW; -+ break; -+ case '?': /* help */ -+ fprintf(stderr, "Usage: unubi [OPTION...] " -+ "image-file\n%s%s\nReport bugs to %s\n", -+ doc, optionsstr, CONTACT); -+ exit(0); -+ break; -+ case 'J': -+ fprintf(stderr, "%s\n", VERSION); -+ exit(0); -+ break; -+ default: -+ fprintf(stderr, "%s", usage); -+ exit(-1); -+ } -+ } -+ -+ /* FIXME I suppose hsize should be replaced! */ -+ args->vid_hdr_offset = args->hsize - UBI_VID_HDR_SIZE; -+ args->data_offset = args->hsize; -+ -+ if (optind < argc) -+ args->img_path = argv[optind++]; -+ return 0; -+} -+ -+ -+/** -+ * counts the number of indicies which are flagged in full_array; -+ * full_array is an array of flags (1/0); -+ **/ -+static size_t -+count_set(uint32_t *full_array, size_t full_len) -+{ -+ size_t count, i; -+ -+ if (full_array == NULL) -+ return 0; -+ -+ for (i = 0, count = 0; i < full_len; i++) -+ if (full_array[i] != 0) -+ count++; -+ -+ return count; -+} -+ -+ -+/** -+ * generates coll_array from full_array; -+ * full_array is an array of flags (1/0); -+ * coll_array is an array of the indicies in full_array which are flagged (1); -+ **/ -+static size_t -+collapse(uint32_t *full_array, size_t full_len, -+ uint32_t *coll_array, size_t coll_len) -+{ -+ size_t i, j; -+ -+ if ((full_array == NULL) || (coll_array == NULL)) -+ return 0; -+ -+ for (i = 0, j = 0; (i < full_len) && (j < coll_len); i++) -+ if (full_array[i] != 0) { -+ coll_array[j] = i; -+ j++; -+ } -+ -+ return j; -+} -+ -+/** -+ * data_crc: save the FILE* position, calculate the crc over a span, -+ * reset the position -+ * returns non-zero when EOF encountered -+ **/ -+static int -+data_crc(FILE* fpin, size_t length, uint32_t *ret_crc) -+{ -+ int rc; -+ size_t i; -+ char buf[length]; -+ uint32_t crc; -+ fpos_t start; -+ -+ rc = fgetpos(fpin, &start); -+ if (rc < 0) -+ return -1; -+ -+ for (i = 0; i < length; i++) { -+ int c = fgetc(fpin); -+ if (c == EOF) { -+ ERR_MSG("unexpected EOF\n"); -+ return -1; -+ } -+ buf[i] = (char)c; -+ } -+ -+ rc = fsetpos(fpin, &start); -+ if (rc < 0) -+ return -1; -+ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, length); -+ *ret_crc = crc; -+ return 0; -+} -+ -+ -+/** -+ * reads data of size len from fpin and writes it to path -+ **/ -+static int -+extract_data(FILE* fpin, size_t len, const char *path) -+{ -+ int rc; -+ size_t i; -+ FILE* fpout; -+ -+ rc = 0; -+ fpout = NULL; -+ -+ fpout = fopen(path, "wb"); -+ if (fpout == NULL) { -+ ERR_MSG("couldn't open file for writing: %s\n", path); -+ rc = -1; -+ goto err; -+ } -+ -+ for (i = 0; i < len; i++) { -+ int c = fgetc(fpin); -+ if (c == EOF) { -+ ERR_MSG("unexpected EOF while writing: %s\n", path); -+ rc = -2; -+ goto err; -+ } -+ c = fputc(c, fpout); -+ if (c == EOF) { -+ ERR_MSG("couldn't write: %s\n", path); -+ rc = -3; -+ goto err; -+ } -+ } -+ -+ err: -+ if (fpout != NULL) -+ fclose(fpout); -+ return rc; -+} -+ -+ -+/** -+ * extract volume information table from block. saves and reloads fpin -+ * position -+ * returns -1 when a fpos set or get fails, otherwise <= -2 on other -+ * failure and 0 on success -+ **/ -+static int -+extract_itable(FILE *fpin, struct eb_info *cur, size_t bsize, size_t num, -+ const char *path) -+{ -+ char filename[MAXPATH + 1]; -+ int rc; -+ size_t i, max; -+ fpos_t temp; -+ FILE* fpout = NULL; -+ struct ubi_vtbl_record rec; -+ -+ if (fpin == NULL || cur == NULL || path == NULL) -+ return -2; -+ -+ /* remember position */ -+ rc = fgetpos(fpin, &temp); -+ if (rc < 0) -+ return -1; -+ -+ /* jump to top of eraseblock, skip to data section */ -+ fsetpos(fpin, &cur->eb_top); -+ if (rc < 0) -+ return -1; -+ fseek(fpin, be32_to_cpu(cur->ec.data_offset), SEEK_CUR); -+ -+ /* prepare output file */ -+ if (be32_to_cpu(cur->vid.vol_id) != UBI_LAYOUT_VOLUME_ID) -+ return -2; -+ memset(filename, 0, MAXPATH + 1); -+ snprintf(filename, MAXPATH, FN_VITBL, path, num); -+ fpout = fopen(filename, "w"); -+ if (fpout == NULL) -+ return -2; -+ -+ /* loop through entries */ -+ fprintf(fpout, -+ "index\trpebs\talign\ttype\tcrc\t\tname\n"); -+ max = bsize - be32_to_cpu(cur->ec.data_offset); -+ for (i = 0; i < (max / sizeof(rec)); i++) { -+ int blank = 1; -+ char *ptr, *base; -+ char name[UBI_VOL_NAME_MAX + 1]; -+ const char *type = "unknown\0"; -+ uint32_t crc; -+ -+ /* read record */ -+ rc = fread(&rec, 1, sizeof(rec), fpin); -+ if (rc == 0) -+ break; -+ if (rc != sizeof(rec)) { -+ ERR_MSG("reading volume information " -+ "table record failed\n"); -+ rc = -3; -+ goto exit; -+ } -+ -+ /* check crc */ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &rec, -+ UBI_VTBL_RECORD_SIZE_CRC); -+ if (crc != be32_to_cpu(rec.crc)) -+ continue; -+ -+ /* check for empty */ -+ base = (char *)&rec; -+ ptr = base; -+ while (blank && -+ ((unsigned)(ptr - base) < UBI_VTBL_RECORD_SIZE_CRC)) { -+ if (*ptr != 0) -+ blank = 0; -+ ptr++; -+ } -+ -+ if (blank) -+ continue; -+ -+ /* prep type string */ -+ if (rec.vol_type == UBI_VID_DYNAMIC) -+ type = "dynamic\0"; -+ else if (rec.vol_type == UBI_VID_STATIC) -+ type = "static\0"; -+ -+ /* prep name string */ -+ rec.name[be16_to_cpu(rec.name_len)] = '\0'; -+ sprintf(name, "%s", rec.name); -+ -+ /* print record line to fpout */ -+ fprintf(fpout, "%zu\t%u\t%u\t%s\t0x%08x\t%s\n", -+ i, -+ be32_to_cpu(rec.reserved_pebs), -+ be32_to_cpu(rec.alignment), -+ type, -+ be32_to_cpu(rec.crc), -+ name); -+ } -+ -+ exit: -+ /* reset position */ -+ if (fsetpos(fpin, &temp) < 0) -+ rc = -1; -+ -+ if (fpout != NULL) -+ fclose(fpout); -+ -+ return rc; -+} -+ -+ -+/** -+ * using eb chain, tries to rebuild the data of volume at vol_id, or for all -+ * the known volumes, if vol_id is NULL; -+ **/ -+static int -+rebuild_volume(FILE * fpin, uint32_t *vol_id, struct eb_info **head, -+ const char *path, size_t block_size, size_t header_size) -+{ -+ char filename[MAXPATH]; -+ int rc; -+ uint32_t vol, num, data_size; -+ FILE* fpout; -+ struct eb_info *cur; -+ -+ rc = 0; -+ -+ if ((fpin == NULL) || (head == NULL) || (*head == NULL)) -+ return 0; -+ -+ /* when vol_id is null, then do all */ -+ if (vol_id == NULL) { -+ cur = *head; -+ vol = be32_to_cpu(cur->vid.vol_id); -+ } else { -+ vol = *vol_id; -+ eb_chain_position(head, vol, NULL, &cur); -+ if (cur == NULL) { -+ if (debug) -+ ERR_MSG("no valid volume %d was found\n", vol); -+ return -1; -+ } -+ } -+ -+ num = 0; -+ snprintf(filename, MAXPATH, FN_VOLWH, path, vol); -+ fpout = fopen(filename, "wb"); -+ if (fpout == NULL) { -+ ERR_MSG("couldn't open file for writing: %s\n", filename); -+ return -1; -+ } -+ -+ while (cur != NULL) { -+ size_t i; -+ -+ if (be32_to_cpu(cur->vid.vol_id) != vol) { -+ /* close out file */ -+ fclose(fpout); -+ -+ /* only stay around if that was the only volume */ -+ if (vol_id != NULL) -+ goto out; -+ -+ /* begin with next */ -+ vol = be32_to_cpu(cur->vid.vol_id); -+ num = 0; -+ snprintf(filename, MAXPATH, FN_VOLWH, path, vol); -+ fpout = fopen(filename, "wb"); -+ if (fpout == NULL) { -+ ERR_MSG("couldn't open file for writing: %s\n", -+ filename); -+ return -1; -+ } -+ } -+ -+ while (num < be32_to_cpu(cur->vid.lnum)) { -+ /* FIXME haver: I hope an empty block is -+ written out so that the binary has no holes -+ ... */ -+ if (debug) -+ ERR_MSG("missing valid block %d for volume %d\n", -+ num, vol); -+ num++; -+ } -+ -+ rc = fsetpos(fpin, &(cur->eb_top)); -+ if (rc < 0) -+ goto out; -+ fseek(fpin, be32_to_cpu(cur->ec.data_offset), SEEK_CUR); -+ -+ if (cur->vid.vol_type == UBI_VID_DYNAMIC) -+ /* FIXME It might be that alignment has influence */ -+ data_size = block_size - header_size; -+ else -+ data_size = be32_to_cpu(cur->vid.data_size); -+ -+ for (i = 0; i < data_size; i++) { -+ int c = fgetc(fpin); -+ if (c == EOF) { -+ ERR_MSG("unexpected EOF while writing: %s\n", -+ filename); -+ rc = -2; -+ goto out; -+ } -+ c = fputc(c, fpout); -+ if (c == EOF) { -+ ERR_MSG("couldn't write: %s\n", filename); -+ rc = -3; -+ goto out; -+ } -+ } -+ -+ cur = cur->next; -+ num++; -+ } -+ -+ out: -+ if (vol_id == NULL) -+ fclose(fpout); -+ return rc; -+} -+ -+ -+/** -+ * traverses FILE* trying to load complete, valid and accurate header data -+ * into the eb chain; -+ **/ -+static int -+unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) -+{ -+ char filename[MAXPATH + 1]; -+ char reason[MAXPATH + 1]; -+ int rc; -+ size_t i, count, itable_num; -+ /* relations: -+ * cur ~ head -+ * next ~ first */ -+ struct eb_info *head, *cur, *first, *next; -+ struct eb_info **next_ptr; -+ -+ rc = 0; -+ count = 0; -+ itable_num = 0; -+ head = NULL; -+ first = NULL; -+ next = NULL; -+ cur = malloc(sizeof(*cur)); -+ if (cur == NULL) { -+ ERR_MSG("out of memory\n"); -+ rc = -ENOMEM; -+ goto err; -+ } -+ memset(cur, 0, sizeof(*cur)); -+ -+ fgetpos(fpin, &(cur->eb_top)); -+ while (1) { -+ const char *raw_path; -+ uint32_t crc; -+ -+ cur->phys_addr = ftell(fpin); -+ cur->phys_block = cur->phys_addr / a->bsize; -+ cur->data_crc_ok = 0; -+ cur->ec_crc_ok = 0; -+ cur->vid_crc_ok = 0; -+ -+ memset(filename, 0, MAXPATH + 1); -+ memset(reason, 0, MAXPATH + 1); -+ -+ /* in case of an incomplete ec header */ -+ raw_path = FN_INVAL; -+ -+ /* read erasecounter header */ -+ rc = fread(&cur->ec, 1, sizeof(cur->ec), fpin); -+ if (rc == 0) -+ goto out; /* EOF */ -+ if (rc != sizeof(cur->ec)) { -+ ERR_MSG("reading ec-hdr failed\n"); -+ rc = -1; -+ goto err; -+ } -+ -+ /* check erasecounter header magic */ -+ if (be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) { -+ snprintf(reason, MAXPATH, ".invalid.ec_magic"); -+ goto invalid; -+ } -+ -+ /* check erasecounter header crc */ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->ec), -+ UBI_EC_HDR_SIZE_CRC); -+ if (be32_to_cpu(cur->ec.hdr_crc) != crc) { -+ snprintf(reason, MAXPATH, ".invalid.ec_hdr_crc"); -+ goto invalid; -+ } -+ -+ /* read volume id header */ -+ rc = fsetpos(fpin, &(cur->eb_top)); -+ if (rc != 0) -+ goto err; -+ fseek(fpin, be32_to_cpu(cur->ec.vid_hdr_offset), SEEK_CUR); -+ rc = fread(&cur->vid, 1, sizeof(cur->vid), fpin); -+ if (rc == 0) -+ goto out; /* EOF */ -+ if (rc != sizeof(cur->vid)) { -+ ERR_MSG("reading vid-hdr failed\n"); -+ rc = -1; -+ goto err; -+ } -+ -+ /* if the magic number is 0xFFFFFFFF, then it's very likely -+ * that the volume is empty */ -+ if (be32_to_cpu(cur->vid.magic) == 0xffffffff) { -+ snprintf(reason, MAXPATH, ".empty"); -+ goto invalid; -+ } -+ -+ /* vol_id should be in bounds */ -+ if ((be32_to_cpu(cur->vid.vol_id) >= UBI_MAX_VOLUMES) && -+ (be32_to_cpu(cur->vid.vol_id) < -+ UBI_INTERNAL_VOL_START)) { -+ snprintf(reason, MAXPATH, ".invalid"); -+ goto invalid; -+ } else -+ raw_path = FN_NSURE; -+ -+ /* check volume id header magic */ -+ if (be32_to_cpu(cur->vid.magic) != UBI_VID_HDR_MAGIC) { -+ snprintf(reason, MAXPATH, ".invalid.vid_magic"); -+ goto invalid; -+ } -+ cur->ec_crc_ok = 1; -+ -+ /* check volume id header crc */ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->vid), -+ UBI_VID_HDR_SIZE_CRC); -+ if (be32_to_cpu(cur->vid.hdr_crc) != crc) { -+ snprintf(reason, MAXPATH, ".invalid.vid_hdr_crc"); -+ goto invalid; -+ } -+ cur->vid_crc_ok = 1; -+ -+ /* check data crc, but only for a static volume */ -+ if (cur->vid.vol_type == UBI_VID_STATIC) { -+ rc = data_crc(fpin, be32_to_cpu(cur->vid.data_size), -+ &crc); -+ if (rc < 0) -+ goto err; -+ if (be32_to_cpu(cur->vid.data_crc) != crc) { -+ snprintf(reason, MAXPATH, ".invalid.data_crc"); -+ goto invalid; -+ } -+ cur->data_crc_ok = 1; -+ } -+ -+ /* enlist this vol, it's valid */ -+ raw_path = FN_VALID; -+ cur->linear = count; -+ rc = eb_chain_insert(&head, cur); -+ if (rc < 0) { -+ if (rc == -ENOMEM) { -+ ERR_MSG("out of memory\n"); -+ goto err; -+ } -+ ERR_MSG("unknown and unexpected error, please contact " -+ CONTACT "\n"); -+ goto err; -+ } -+ -+ /* extract info-table */ -+ if (a->itable && -+ (be32_to_cpu(cur->vid.vol_id) == UBI_LAYOUT_VOLUME_ID)) { -+ extract_itable(fpin, cur, a->bsize, -+ itable_num, a->odir_path); -+ itable_num++; -+ } -+ -+ /* split volumes */ -+ if (a->vol_split) { -+ size_t size = 0; -+ -+ rc = fsetpos(fpin, &(cur->eb_top)); -+ if (rc != 0) -+ goto err; -+ -+ /* -+ * FIXME For dynamic UBI volumes we must write -+ * the maximum available data. The -+ * vid.data_size field is not used in this -+ * case. The dynamic volume user is -+ * responsible for the content. -+ */ -+ if (a->vol_split == SPLIT_DATA) { -+ /* Write only data section */ -+ if (cur->vid.vol_type == UBI_VID_DYNAMIC) { -+ /* FIXME Formular is not -+ always right ... */ -+ size = a->bsize - a->hsize; -+ } else -+ size = be32_to_cpu(cur->vid.data_size); -+ -+ fseek(fpin, -+ be32_to_cpu(cur->ec.data_offset), -+ SEEK_CUR); -+ } -+ else if (a->vol_split == SPLIT_RAW) -+ /* write entire eraseblock */ -+ size = a->bsize; -+ -+ snprintf(filename, MAXPATH, FN_VOLSP, -+ a->odir_path, -+ be32_to_cpu(cur->vid.vol_id), -+ be32_to_cpu(cur->vid.lnum), -+ be32_to_cpu(cur->vid.leb_ver), count); -+ rc = extract_data(fpin, size, filename); -+ if (rc < 0) -+ goto err; -+ } -+ -+ invalid: -+ /* split eraseblocks */ -+ if (a->eb_split) { -+ /* jump to top of block */ -+ rc = fsetpos(fpin, &(cur->eb_top)); -+ if (rc != 0) -+ goto err; -+ -+ if (strcmp(raw_path, FN_INVAL) == 0) -+ snprintf(filename, MAXPATH, raw_path, -+ a->odir_path, count, reason); -+ else -+ snprintf(filename, MAXPATH, raw_path, -+ a->odir_path, -+ count, -+ be32_to_cpu(cur->vid.vol_id), -+ be32_to_cpu(cur->vid.lnum), -+ be32_to_cpu(cur->vid.leb_ver), -+ reason); -+ -+ rc = extract_data(fpin, a->bsize, filename); -+ if (rc < 0) -+ goto err; -+ } -+ -+ /* append to simple linked list */ -+ if (first == NULL) -+ next_ptr = &first; -+ else -+ next_ptr = &next->next; -+ -+ *next_ptr = malloc(sizeof(**next_ptr)); -+ if (*next_ptr == NULL) { -+ ERR_MSG("out of memory\n"); -+ rc = -ENOMEM; -+ goto err; -+ } -+ memset(*next_ptr, 0, sizeof(**next_ptr)); -+ -+ next = *next_ptr; -+ memcpy(next, cur, sizeof(*next)); -+ next->next = NULL; -+ -+ count++; -+ rc = fsetpos(fpin, &(cur->eb_top)); -+ if (rc != 0) -+ goto err; -+ fseek(fpin, a->bsize, SEEK_CUR); -+ memset(cur, 0, sizeof(*cur)); -+ -+ fgetpos(fpin, &(cur->eb_top)); -+ } -+ -+ out: -+ for (i = 0; i < vc; i++) { -+ rc = rebuild_volume(fpin, &vols[i], &head, a->odir_path, -+ a->bsize, a->hsize); -+ if (rc < 0) -+ goto err; -+ } -+ -+ /* if there were no volumes specified, rebuild them all, -+ * UNLESS eb_ or vol_ split or analyze was specified */ -+ if ((vc == 0) && (!a->eb_split) && (!a->vol_split) && -+ (!a->analyze) && (!a->itable)) { -+ rc = rebuild_volume(fpin, NULL, &head, a->odir_path, a->bsize, -+ a->hsize); -+ if (rc < 0) -+ goto err; -+ } -+ -+ err: -+ free(cur); -+ -+ if (a->analyze) { -+ char fname[PATH_MAX]; -+ FILE *fp; -+ -+ unubi_analyze(&head, first, a->odir_path); -+ -+ /* prepare output files */ -+ memset(fname, 0, PATH_MAX + 1); -+ snprintf(fname, PATH_MAX, "%s/%s", a->odir_path, FN_EH_STAT); -+ fp = fopen(fname, "w"); -+ if (fp != NULL) { -+ eb_chain_print(fp, head); -+ fclose(fp); -+ } -+ } -+ eb_chain_destroy(&head); -+ eb_chain_destroy(&first); -+ -+ return rc; -+} -+ -+ -+/** -+ * handles command line arguments, then calls unubi_volumes -+ **/ -+int -+main(int argc, char *argv[]) -+{ -+ int rc, free_a_odir; -+ size_t vols_len; -+ uint32_t *vols; -+ FILE* fpin; -+ struct args a; -+ -+ rc = 0; -+ free_a_odir = 0; -+ vols_len = 0; -+ vols = NULL; -+ fpin = NULL; -+ init_crc32_table(crc32_table); -+ -+ /* setup struct args a */ -+ memset(&a, 0, sizeof(a)); -+ a.bsize = 128 * KIB; -+ a.hsize = 2 * KIB; -+ a.vols = malloc(sizeof(*a.vols) * UBI_MAX_VOLUMES); -+ if (a.vols == NULL) { -+ ERR_MSG("out of memory\n"); -+ rc = ENOMEM; -+ goto err; -+ } -+ memset(a.vols, 0, sizeof(*a.vols) * UBI_MAX_VOLUMES); -+ -+ /* parse args and check for validity */ -+ parse_opt(argc, argv, &a); -+ if (a.img_path == NULL) { -+ ERR_MSG("no image file specified\n"); -+ rc = EINVAL; -+ goto err; -+ } -+ else if (a.odir_path == NULL) { -+ char *ptr; -+ int len; -+ -+ ptr = strrchr(a.img_path, '/'); -+ if (ptr == NULL) -+ ptr = a.img_path; -+ else -+ ptr++; -+ -+ len = strlen(DIR_FMT) + strlen(ptr); -+ free_a_odir = 1; -+ a.odir_path = malloc(sizeof(*a.odir_path) * len); -+ if (a.odir_path == NULL) { -+ ERR_MSG("out of memory\n"); -+ rc = ENOMEM; -+ goto err; -+ } -+ snprintf(a.odir_path, len, DIR_FMT, ptr); -+ } -+ -+ fpin = fopen(a.img_path, "rb"); -+ if (fpin == NULL) { -+ ERR_MSG("couldn't open file for reading: " -+ "%s\n", a.img_path); -+ rc = EINVAL; -+ goto err; -+ } -+ -+ rc = mkdir(a.odir_path, 0777); -+ if ((rc < 0) && (errno != EEXIST)) { -+ ERR_MSG("couldn't create ouput directory: " -+ "%s\n", a.odir_path); -+ rc = -rc; -+ goto err; -+ } -+ -+ /* fill in vols array */ -+ vols_len = count_set(a.vols, UBI_MAX_VOLUMES); -+ if (vols_len > 0) { -+ vols = malloc(sizeof(*vols) * vols_len); -+ if (vols == NULL) { -+ ERR_MSG("out of memory\n"); -+ rc = ENOMEM; -+ goto err; -+ } -+ collapse(a.vols, UBI_MAX_VOLUMES, vols, vols_len); -+ } -+ -+ /* unubi volumes */ -+ rc = unubi_volumes(fpin, vols, vols_len, &a); -+ if (rc < 0) { -+ /* ERR_MSG("error encountered while working on image file: " -+ "%s\n", a.img_path); */ -+ rc = -rc; -+ goto err; -+ } -+ -+ err: -+ free(a.vols); -+ if (free_a_odir != 0) -+ free(a.odir_path); -+ if (fpin != NULL) -+ fclose(fpin); -+ if (vols_len > 0) -+ free(vols); -+ return rc; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,463 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Authors: Drake Dowsett, dowsett@de.ibm.com -+ * Contact: Andreas Arnez, arnez@de.ibm.com -+ * -+ * unubi uses the following functions to generate analysis output based on -+ * the header information in a raw-UBI image -+ */ -+ -+/* -+ * TODO: use OOB data to check for eraseblock validity in NAND images -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "unubi_analyze.h" -+#include "crc32.h" -+ -+#define EC_X_INT 50 -+ -+/** -+ * intcmp - function needed by qsort to order integers -+ **/ -+int intcmp(const void *a, const void *b) -+{ -+ int A = *(int *)a; -+ int B = *(int *)b; -+ return A - B; -+} -+ -+int longcmp(const void *a, const void *b) -+{ -+ long long A = *(long long *)a; -+ long long B = *(long long *)b; -+ return A - B; -+} -+ -+ -+/** -+ * unubi_analyze_group_index - finds the normalized index in an array -+ * item: look for this item in the array -+ * array: array to search through -+ * size: length of the array -+ * array should be sorted for this algorithm to perform properly; -+ * if the item is not found returns -1, otherwise return value is the -+ * index in the array (note this contricts the array size to 2^32-1); -+ **/ -+int -+norm_index(uint32_t item, uint32_t *array, size_t length) -+{ -+ size_t i, index; -+ -+ for (index = 0, i = 0; i < length; i++) { -+ if ((i != 0) && (array[i] != array[i - 1])) -+ index++; -+ -+ if (item == array[i]) -+ return index; -+ } -+ -+ return -1; -+} -+ -+ -+/** -+ * unubi_analyze_ec_hdr - generate data table and plot script -+ * first: head of simple linked list -+ * path: folder to write into -+ * generates a data file containing the eraseblock index in the image -+ * and the erase counter found in its ec header; -+ * if the crc check fails, the line is commented out in the data file; -+ * also generates a simple gnuplot sript for quickly viewing one -+ * display of the data file; -+ **/ -+int -+unubi_analyze_ec_hdr(struct eb_info *first, const char *path) -+{ -+ char filename[PATH_MAX + 1]; -+ size_t count, eraseblocks; -+ uint32_t crc, crc32_table[256]; -+ uint64_t *erase_counts; -+ FILE* fpdata; -+ FILE* fpplot; -+ struct eb_info *cur; -+ -+ if (first == NULL) -+ return -1; -+ -+ /* crc check still needed for `first' linked list */ -+ init_crc32_table(crc32_table); -+ -+ /* prepare output files */ -+ memset(filename, 0, PATH_MAX + 1); -+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_EH_DATA); -+ fpdata = fopen(filename, "w"); -+ if (fpdata == NULL) -+ return -1; -+ -+ memset(filename, 0, PATH_MAX + 1); -+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_EH_PLOT); -+ fpplot = fopen(filename, "w"); -+ if (fpplot == NULL) { -+ fclose(fpdata); -+ return -1; -+ } -+ -+ /* make executable */ -+ chmod(filename, 0755); -+ -+ /* first run: count elements */ -+ count = 0; -+ cur = first; -+ while (cur != NULL) { -+ cur = cur->next; -+ count++; -+ } -+ eraseblocks = count; -+ -+ erase_counts = malloc(eraseblocks * sizeof(*erase_counts)); -+ if (!erase_counts) { -+ perror("out of memory"); -+ exit(EXIT_FAILURE); -+ } -+ -+ memset(erase_counts, 0, eraseblocks * sizeof(*erase_counts)); -+ -+ /* second run: populate array to sort */ -+ count = 0; -+ cur = first; -+ while (cur != NULL) { -+ erase_counts[count] = be64_to_cpu(cur->ec.ec); -+ cur = cur->next; -+ count++; -+ } -+ qsort(erase_counts, eraseblocks, sizeof(*erase_counts), -+ (void *)longcmp); -+ -+ /* third run: generate data file */ -+ count = 0; -+ cur = first; -+ fprintf(fpdata, "# eraseblock_no actual_erase_count " -+ "sorted_erase_count\n"); -+ while (cur != NULL) { -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &cur->ec, -+ UBI_EC_HDR_SIZE_CRC); -+ -+ if ((be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) || -+ (crc != be32_to_cpu(cur->ec.hdr_crc))) -+ fprintf(fpdata, "# "); -+ -+ fprintf(fpdata, "%zu %llu %llu", count, -+ (unsigned long long)be64_to_cpu(cur->ec.ec), -+ (unsigned long long)erase_counts[count]); -+ -+ if (be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) -+ fprintf(fpdata, " ## bad magic: %08x", -+ be32_to_cpu(cur->ec.magic)); -+ -+ if (crc != be32_to_cpu(cur->ec.hdr_crc)) -+ fprintf(fpdata, " ## CRC mismatch: given=%08x, " -+ "calc=%08x", be32_to_cpu(cur->ec.hdr_crc), -+ crc); -+ -+ fprintf(fpdata, "\n"); -+ -+ cur = cur->next; -+ count++; -+ } -+ fclose(fpdata); -+ -+ fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n"); -+ fprintf(fpplot, "set xlabel \"eraseblock\"\n"); -+ -+ /* fourth run: generate plot file xtics */ -+ count = 0; -+ cur = first; -+ fprintf(fpplot, "set xtics ("); -+ while (cur != NULL) { -+ if ((count % EC_X_INT) == 0) { -+ if (count > 0) -+ fprintf(fpplot, ", "); -+ fprintf(fpplot, "%zd", count); -+ } -+ -+ cur = cur->next; -+ count++; -+ } -+ fprintf(fpplot, ")\n"); -+ -+ fprintf(fpplot, "set ylabel \"erase count\"\n"); -+ fprintf(fpplot, "set xrange [-1:%zu]\n", eraseblocks + 1); -+ fprintf(fpplot, "# set yrange [-1:%llu]\n", -+ (unsigned long long)erase_counts[eraseblocks - 1] + 1); -+ fprintf(fpplot, "plot \"%s\" u 1:2 t \"unsorted: %s\" with boxes\n", -+ FN_EH_DATA, FN_EH_DATA); -+ fprintf(fpplot, "# replot \"%s\" u 1:3 t \"sorted: %s\" with lines\n", -+ FN_EH_DATA, FN_EH_DATA); -+ fprintf(fpplot, "pause -1 \"press ENTER\"\n"); -+ -+ fclose(fpplot); -+ -+ return 0; -+} -+ -+ -+/** -+ * unubi_analyze_vid_hdr - generate data table and plot script -+ * head: head of complex linked list (eb_chain) -+ * path: folder to write into -+ * generates a data file containing the volume id, logical number, leb version, -+ * and data size from the vid header; -+ * all eraseblocks listed in the eb_chain are valid (checked in unubi); -+ * also generates a simple gnuplot sript for quickly viewing one -+ * display of the data file; -+ **/ -+int -+unubi_analyze_vid_hdr(struct eb_info **head, const char *path) -+{ -+ char filename[PATH_MAX + 1]; -+ int rc, y1, y2; -+ size_t count, step, breadth; -+ uint32_t *leb_versions, *data_sizes; -+ FILE* fpdata; -+ FILE* fpplot; -+ struct eb_info *cur; -+ -+ if (head == NULL || *head == NULL) -+ return -1; -+ -+ rc = 0; -+ fpdata = NULL; -+ fpplot = NULL; -+ data_sizes = NULL; -+ leb_versions = NULL; -+ -+ /* prepare output files */ -+ memset(filename, 0, PATH_MAX + 1); -+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_VH_DATA); -+ fpdata = fopen(filename, "w"); -+ if (fpdata == NULL) { -+ rc = -1; -+ goto exit; -+ } -+ -+ memset(filename, 0, PATH_MAX + 1); -+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_VH_PLOT); -+ fpplot = fopen(filename, "w"); -+ if (fpplot == NULL) { -+ rc = -1; -+ goto exit; -+ } -+ -+ /* make executable */ -+ chmod(filename, 0755); -+ -+ /* first run: count elements */ -+ count = 0; -+ cur = *head; -+ while (cur != NULL) { -+ cur = cur->next; -+ count++; -+ } -+ breadth = count; -+ -+ leb_versions = malloc(breadth * sizeof(uint32_t)); -+ if (leb_versions == NULL) { -+ rc = -1; -+ goto exit; -+ } -+ memset(leb_versions, 0, breadth * sizeof(uint32_t)); -+ -+ data_sizes = malloc(breadth * sizeof(uint32_t)); -+ if (data_sizes == NULL) { -+ rc = -1; -+ goto exit; -+ } -+ memset(data_sizes, 0, breadth * sizeof(*data_sizes)); -+ -+ /* second run: populate arrays to sort */ -+ count = 0; -+ cur = *head; -+ while (cur != NULL) { -+ leb_versions[count] = be32_to_cpu(cur->vid.leb_ver); -+ data_sizes[count] = be32_to_cpu(cur->vid.data_size); -+ cur = cur->next; -+ count++; -+ } -+ qsort(leb_versions, breadth, sizeof(*leb_versions), (void *)intcmp); -+ qsort(data_sizes, breadth, sizeof(*data_sizes), (void *)intcmp); -+ -+ /* third run: generate data file */ -+ count = 0; -+ cur = *head; -+ fprintf(fpdata, "# x_axis vol_id lnum y1_axis leb_ver " -+ "y2_axis data_size\n"); -+ while (cur != NULL) { -+ y1 = norm_index(be32_to_cpu(cur->vid.leb_ver), leb_versions, -+ breadth); -+ y2 = norm_index(be32_to_cpu(cur->vid.data_size), data_sizes, -+ breadth); -+ -+ if ((y1 == -1) || (y2 == -1)) { -+ rc = -1; -+ goto exit; -+ } -+ -+ fprintf(fpdata, "%zu %u %u %u %u %u %u\n", -+ count, -+ be32_to_cpu(cur->vid.vol_id), -+ be32_to_cpu(cur->vid.lnum), -+ y1, -+ be32_to_cpu(cur->vid.leb_ver), -+ y2, -+ be32_to_cpu(cur->vid.data_size)); -+ cur = cur->next; -+ count++; -+ } -+ -+ fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n"); -+ fprintf(fpplot, "set xlabel \"volume\"\n"); -+ -+ /* fourth run: generate plot file xtics */ -+ count = 0; -+ step = 0; -+ cur = *head; -+ fprintf(fpplot, "set xtics ("); -+ while (cur != NULL) { -+ if (count > 0) -+ fprintf(fpplot, ", "); -+ if (step != be32_to_cpu(cur->vid.vol_id)) { -+ step = be32_to_cpu(cur->vid.vol_id); -+ fprintf(fpplot, "\"%zd\" %zd 0", step, count); -+ } -+ else -+ fprintf(fpplot, "\"%d\" %zd 1", -+ be32_to_cpu(cur->vid.lnum), count); -+ cur = cur->next; -+ count++; -+ } -+ fprintf(fpplot, ")\n"); -+ fprintf(fpplot, "set nox2tics\n"); -+ -+ /* fifth run: generate plot file ytics */ -+ count = 0; -+ cur = *head; -+ fprintf(fpplot, "set ylabel \"leb version\"\n"); -+ fprintf(fpplot, "set ytics ("); -+ while (cur->next != NULL) { -+ y1 = norm_index(be32_to_cpu(cur->vid.leb_ver), leb_versions, -+ breadth); -+ -+ if (y1 == -1) { -+ rc = -1; -+ goto exit; -+ } -+ -+ if (count > 0) -+ fprintf(fpplot, ", "); -+ -+ fprintf(fpplot, "\"%u\" %u", be32_to_cpu(cur->vid.leb_ver), -+ y1); -+ -+ cur = cur->next; -+ count++; -+ } -+ fprintf(fpplot, ")\n"); -+ -+ /* sixth run: generate plot file y2tics */ -+ count = 0; -+ cur = *head; -+ fprintf(fpplot, "set y2label \"data size\"\n"); -+ fprintf(fpplot, "set y2tics ("); -+ while (cur != NULL) { -+ y2 = norm_index(be32_to_cpu(cur->vid.data_size), -+ data_sizes, breadth); -+ -+ if (y2 == -1) { -+ rc = -1; -+ goto exit; -+ } -+ -+ if (count > 0) -+ fprintf(fpplot, ", "); -+ -+ fprintf(fpplot, "\"%u\" %u", be32_to_cpu(cur->vid.data_size), -+ y2); -+ -+ cur = cur->next; -+ count++; -+ } -+ fprintf(fpplot, ")\n"); -+ -+ y1 = norm_index(leb_versions[breadth - 1], leb_versions, breadth); -+ y2 = norm_index(data_sizes[breadth - 1], data_sizes, breadth); -+ fprintf(fpplot, "set xrange [-1:%zu]\n", count + 1); -+ fprintf(fpplot, "set yrange [-1:%u]\n", y1 + 1); -+ fprintf(fpplot, "set y2range [-1:%u]\n", y2 + 1); -+ fprintf(fpplot, "plot \"%s\" u 1:4 t \"leb version: %s\" " -+ "axes x1y1 with lp\n", FN_VH_DATA, FN_VH_DATA); -+ fprintf(fpplot, "replot \"%s\" u 1:6 t \"data size: %s\" " -+ "axes x1y2 with lp\n", FN_VH_DATA, FN_VH_DATA); -+ fprintf(fpplot, "pause -1 \"press ENTER\"\n"); -+ -+ exit: -+ if (fpdata != NULL) -+ fclose(fpdata); -+ if (fpplot != NULL) -+ fclose(fpplot); -+ if (data_sizes != NULL) -+ free(data_sizes); -+ if (leb_versions != NULL) -+ free(leb_versions); -+ -+ return rc; -+} -+ -+ -+/** -+ * unubi_analyze - run all analyses -+ * head: eb_chain head -+ * first: simple linked list of eraseblock headers (use .next) -+ * path: directory (without trailing slash) to output to -+ * returns 0 upon successful completion, or -1 otherwise -+ **/ -+int -+unubi_analyze(struct eb_info **head, struct eb_info *first, const char *path) -+{ -+ int ec_rc, vid_rc; -+ -+ if (path == NULL) -+ return -1; -+ -+ ec_rc = unubi_analyze_ec_hdr(first, path); -+ vid_rc = unubi_analyze_vid_hdr(head, path); -+ if (ec_rc < 0 || vid_rc < 0) -+ return -1; -+ -+ return 0; -+} ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,87 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#ifndef __UNUBI_ANALYZE_H__ -+#define __UNUBI_ANALYZE_H__ -+ -+/* -+ * Author: Drake Dowsett -+ * Contact: Andreas Arnez (arnez@de.ibm.com) -+ * -+ * Eraseblock Chain -+ * -+ * A linked list structure to order eraseblocks by volume and logical number -+ * and to update by version number. Doesn't contain actual eraseblock data -+ * but rather the erasecounter and volume id headers as well as a position -+ * indicator. -+ * -+ * Diagram Example: -+ * -+ * [V1.0v0]->[V1.1v2]->[V1.2v1]->[V2.0v2]->[V2.1v0]->[V2.2v1]->NULL -+ * | | | | | | -+ * NULL [V1.1v1] [V1.2v0] [V2.0v1] NULL [V2.2v0] -+ * | | | | -+ * [V1.1v0] NULL [V2.0v0] NULL -+ * | | -+ * NULL NULL -+ * -+ * [VA.BvC] represents the eb_info for the eraseblock with the vol_id A, -+ * lnum B and leb_ver C -+ * -> represents the `next' pointer -+ * | represents the `older' pointer -+ */ -+ -+#include -+#include -+#include -+ -+#define FN_EH_STAT "analysis_blocks.txt" -+#define FN_EH_DATA "analysis_ec_hdr.data" -+#define FN_EH_PLOT "analysis_ec_hdr.plot" -+#define FN_VH_DATA "analysis_vid_hdr.data" -+#define FN_VH_PLOT "analysis_vid_hdr.plot" -+ -+struct eb_info { -+ struct ubi_ec_hdr ec; -+ struct ubi_vid_hdr vid; -+ -+ fpos_t eb_top; -+ uint32_t linear; -+ int ec_crc_ok; -+ int vid_crc_ok; -+ int data_crc_ok; -+ uint32_t phys_addr; -+ int phys_block; -+ -+ struct eb_info *next; -+ struct eb_info *older; -+}; -+ -+int eb_chain_insert(struct eb_info **head, struct eb_info *item); -+ -+int eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum, -+ struct eb_info **pos); -+ -+int eb_chain_print(FILE *stream, struct eb_info *head); -+ -+int eb_chain_destroy(struct eb_info **head); -+ -+int unubi_analyze(struct eb_info **head, struct eb_info *first, -+ const char *path); -+ -+#endif /* __UNUBI_ANALYZE_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/testcases.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/testcases.txt 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,9 @@ -+1. Start some large update, but write there byte-by-byte -+ -+2. start update for N bytes, write N-x bytes, then write y bytes, y>x. -+ You have to see that at the last write only x bytes were written, -+ but y-x bytes were not. we may vary x a bit. good number would be -+ 1, 128, 128Ki-128... -+ -+3. Try to start update for x bytes, write x bytes, then try to write more. -+ Check that it is impossible to write more. --- linux-2.6.24.7.old/drivers/mtd/mtd_blkdevs.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/mtd/mtd_blkdevs.c 2009-04-12 18:13:57.000000000 +0200 @@ -278,7 +278,7 @@ - + /* 2.5 has capacity in units of 512 bytes while still having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ - set_capacity(gd, (new->size * tr->blksize) >> 9); + set_capacity(gd, ((u_int64_t)new->size * tr->blksize) >> 9); - + gd->private_data = new; new->blkcore_priv = gd; --- linux-2.6.24.7.old/drivers/mtd/mtdblock-jz.uu 1970-01-01 01:00:00.000000000 +0100 @@ -69397,15 +13334,6 @@ +end --- linux-2.6.24.7.old/drivers/mtd/mtdblock.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/mtd/mtdblock.c 2009-04-12 18:13:57.000000000 +0200 -@@ -1,7 +1,7 @@ - /* - * Direct MTD block device access - * -- * $Id: mtdblock.c,v 1.68 2005/11/07 11:14:20 gleixner Exp $ -+ * $Id: mtdblock.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $ - * - * (C) 2000-2003 Nicolas Pitre - * (C) 1999-2003 David Woodhouse @@ -15,7 +15,7 @@ #include #include @@ -69418,15 +13346,15 @@ @@ -361,12 +361,27 @@ kfree(dev); } - -+ + ++ +static int mtdblock_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) +{ + struct gendisk *gd = dev->blkcore_priv; + memset(geo, 0, sizeof(*geo)); + geo->heads = 4; + geo->sectors = 16; -+ geo->cylinders = dev->size/(4*16); ++ geo->cylinders = dev->size/(4*16); + + printk("cylinders: %x \n", geo->cylinders); + printk("sects: %x\n", dev->size); @@ -69445,40 +13373,14 @@ .readsect = mtdblock_readsect, --- linux-2.6.24.7.old/drivers/mtd/mtdchar.c 2009-04-12 18:05:07.000000000 +0200 +++ linux-2.6.24.7/drivers/mtd/mtdchar.c 2009-04-12 18:13:57.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $ -+ * $Id: mtdchar.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $ - * - * Character-device access to raw MTD devices. - * @@ -7,7 +7,6 @@ - + #include #include -#include #include #include #include -@@ -83,8 +82,6 @@ - return -EINVAL; - } - -- -- - static int mtd_open(struct inode *inode, struct file *file) - { - int minor = iminor(inode); -@@ -137,8 +134,7 @@ - - DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); - -- /* Only sync if opened RW */ -- if ((file->f_mode & 2) && mtd->sync) -+ if (mtd->sync) - mtd->sync(mtd); - - put_mtd_device(mtd); @@ -157,7 +153,7 @@ { struct mtd_file_info *mfi = file->private_data; @@ -69502,20 +13404,20 @@ struct mtd_oob_buf buf; struct mtd_oob_ops ops; - -+ ++ if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) return -EFAULT; - + @@ -576,6 +572,73 @@ break; } - + + case MEMWRITEPAGE: + { + struct mtd_page_buf buf; + struct mtd_oob_ops ops; + -+ memset(&ops, 0, sizeof(ops)); ++ memset(&ops, 0, sizeof(ops)); +#if 1 + if(!(file->f_mode & 2)) + return -EPERM; @@ -69535,7 +13437,7 @@ + + if (ret) + return ret; -+ ++ + ops.len = mtd->writesize; + ops.ooblen = buf.ooblength; + ops.ooboffs = buf.start & (mtd->oobsize - 1); @@ -69581,24 +13483,24 @@ { struct erase_info_user info; @@ -627,9 +690,9 @@ - + case MEMGETBADBLOCK: { - loff_t offs; + loff_mtd_t offs; - + - if (copy_from_user(&offs, argp, sizeof(loff_t))) + if (copy_from_user(&offs, argp, sizeof(loff_mtd_t))) return -EFAULT; if (!mtd->block_isbad) ret = -EOPNOTSUPP; @@ -640,9 +703,9 @@ - + case MEMSETBADBLOCK: { - loff_t offs; + loff_mtd_t offs; - + - if (copy_from_user(&offs, argp, sizeof(loff_t))) + if (copy_from_user(&offs, argp, sizeof(loff_mtd_t))) return -EFAULT; @@ -69606,7 +13508,7 @@ ret = -EOPNOTSUPP; @@ -764,9 +827,9 @@ #endif - + default: + printk("line : %d\n", __LINE__); ret = -ENOTTY; @@ -69614,831 +13516,12 @@ - return ret; } /* memory_ioctl */ - ---- linux-2.6.24.7.old/drivers/mtd/mtdchar.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtdchar.c.orig 2009-04-12 18:01:55.000000000 +0200 -@@ -0,0 +1,816 @@ -+/* -+ * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $ -+ * -+ * Character-device access to raw MTD devices. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+ -+static struct class *mtd_class; -+ -+static void mtd_notify_add(struct mtd_info* mtd) -+{ -+ if (!mtd) -+ return; -+ -+ class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), -+ NULL, "mtd%d", mtd->index); -+ -+ class_device_create(mtd_class, NULL, -+ MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), -+ NULL, "mtd%dro", mtd->index); -+} -+ -+static void mtd_notify_remove(struct mtd_info* mtd) -+{ -+ if (!mtd) -+ return; -+ -+ class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2)); -+ class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1)); -+} -+ -+static struct mtd_notifier notifier = { -+ .add = mtd_notify_add, -+ .remove = mtd_notify_remove, -+}; -+ -+/* -+ * Data structure to hold the pointer to the mtd device as well -+ * as mode information ofr various use cases. -+ */ -+struct mtd_file_info { -+ struct mtd_info *mtd; -+ enum mtd_file_modes mode; -+}; -+ -+static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) -+{ -+ struct mtd_file_info *mfi = file->private_data; -+ struct mtd_info *mtd = mfi->mtd; -+ -+ switch (orig) { -+ case SEEK_SET: -+ break; -+ case SEEK_CUR: -+ offset += file->f_pos; -+ break; -+ case SEEK_END: -+ offset += mtd->size; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (offset >= 0 && offset <= mtd->size) -+ return file->f_pos = offset; -+ -+ return -EINVAL; -+} -+ -+ -+ -+static int mtd_open(struct inode *inode, struct file *file) -+{ -+ int minor = iminor(inode); -+ int devnum = minor >> 1; -+ struct mtd_info *mtd; -+ struct mtd_file_info *mfi; -+ -+ DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n"); -+ -+ if (devnum >= MAX_MTD_DEVICES) -+ return -ENODEV; -+ -+ /* You can't open the RO devices RW */ -+ if ((file->f_mode & 2) && (minor & 1)) -+ return -EACCES; -+ -+ mtd = get_mtd_device(NULL, devnum); -+ -+ if (IS_ERR(mtd)) -+ return PTR_ERR(mtd); -+ -+ if (MTD_ABSENT == mtd->type) { -+ put_mtd_device(mtd); -+ return -ENODEV; -+ } -+ -+ /* You can't open it RW if it's not a writeable device */ -+ if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { -+ put_mtd_device(mtd); -+ return -EACCES; -+ } -+ -+ mfi = kzalloc(sizeof(*mfi), GFP_KERNEL); -+ if (!mfi) { -+ put_mtd_device(mtd); -+ return -ENOMEM; -+ } -+ mfi->mtd = mtd; -+ file->private_data = mfi; -+ -+ return 0; -+} /* mtd_open */ -+ -+/*====================================================================*/ -+ -+static int mtd_close(struct inode *inode, struct file *file) -+{ -+ struct mtd_file_info *mfi = file->private_data; -+ struct mtd_info *mtd = mfi->mtd; -+ -+ DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); -+ -+ /* Only sync if opened RW */ -+ if ((file->f_mode & 2) && mtd->sync) -+ mtd->sync(mtd); -+ -+ put_mtd_device(mtd); -+ file->private_data = NULL; -+ kfree(mfi); -+ -+ return 0; -+} /* mtd_close */ -+ -+/* FIXME: This _really_ needs to die. In 2.5, we should lock the -+ userspace buffer down and use it directly with readv/writev. -+*/ -+#define MAX_KMALLOC_SIZE 0x20000 -+ -+static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos) -+{ -+ struct mtd_file_info *mfi = file->private_data; -+ struct mtd_info *mtd = mfi->mtd; -+ size_t retlen=0; -+ size_t total_retlen=0; -+ int ret=0; -+ int len; -+ char *kbuf; -+ -+ DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); -+ -+ if (*ppos + count > mtd->size) -+ count = mtd->size - *ppos; -+ -+ if (!count) -+ return 0; -+ -+ /* FIXME: Use kiovec in 2.5 to lock down the user's buffers -+ and pass them directly to the MTD functions */ -+ -+ if (count > MAX_KMALLOC_SIZE) -+ kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL); -+ else -+ kbuf=kmalloc(count, GFP_KERNEL); -+ -+ if (!kbuf) -+ return -ENOMEM; -+ -+ while (count) { -+ -+ if (count > MAX_KMALLOC_SIZE) -+ len = MAX_KMALLOC_SIZE; -+ else -+ len = count; -+ -+ switch (mfi->mode) { -+ case MTD_MODE_OTP_FACTORY: -+ ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); -+ break; -+ case MTD_MODE_OTP_USER: -+ ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); -+ break; -+ case MTD_MODE_RAW: -+ { -+ struct mtd_oob_ops ops; -+ -+ ops.mode = MTD_OOB_RAW; -+ ops.datbuf = kbuf; -+ ops.oobbuf = NULL; -+ ops.len = len; -+ -+ ret = mtd->read_oob(mtd, *ppos, &ops); -+ retlen = ops.retlen; -+ break; -+ } -+ default: -+ ret = mtd->read(mtd, *ppos, len, &retlen, kbuf); -+ } -+ /* Nand returns -EBADMSG on ecc errors, but it returns -+ * the data. For our userspace tools it is important -+ * to dump areas with ecc errors ! -+ * For kernel internal usage it also might return -EUCLEAN -+ * to signal the caller that a bitflip has occured and has -+ * been corrected by the ECC algorithm. -+ * Userspace software which accesses NAND this way -+ * must be aware of the fact that it deals with NAND -+ */ -+ if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) { -+ *ppos += retlen; -+ if (copy_to_user(buf, kbuf, retlen)) { -+ kfree(kbuf); -+ return -EFAULT; -+ } -+ else -+ total_retlen += retlen; -+ -+ count -= retlen; -+ buf += retlen; -+ if (retlen == 0) -+ count = 0; -+ } -+ else { -+ kfree(kbuf); -+ return ret; -+ } -+ -+ } -+ -+ kfree(kbuf); -+ return total_retlen; -+} /* mtd_read */ -+ -+static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos) -+{ -+ struct mtd_file_info *mfi = file->private_data; -+ struct mtd_info *mtd = mfi->mtd; -+ char *kbuf; -+ size_t retlen; -+ size_t total_retlen=0; -+ int ret=0; -+ int len; -+ -+ DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); -+ -+ if (*ppos == mtd->size) -+ return -ENOSPC; -+ -+ if (*ppos + count > mtd->size) -+ count = mtd->size - *ppos; -+ -+ if (!count) -+ return 0; -+ -+ if (count > MAX_KMALLOC_SIZE) -+ kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL); -+ else -+ kbuf=kmalloc(count, GFP_KERNEL); -+ -+ if (!kbuf) -+ return -ENOMEM; -+ -+ while (count) { -+ -+ if (count > MAX_KMALLOC_SIZE) -+ len = MAX_KMALLOC_SIZE; -+ else -+ len = count; -+ -+ if (copy_from_user(kbuf, buf, len)) { -+ kfree(kbuf); -+ return -EFAULT; -+ } -+ -+ switch (mfi->mode) { -+ case MTD_MODE_OTP_FACTORY: -+ ret = -EROFS; -+ break; -+ case MTD_MODE_OTP_USER: -+ if (!mtd->write_user_prot_reg) { -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); -+ break; -+ -+ case MTD_MODE_RAW: -+ { -+ struct mtd_oob_ops ops; -+ -+ ops.mode = MTD_OOB_RAW; -+ ops.datbuf = kbuf; -+ ops.oobbuf = NULL; -+ ops.len = len; -+ -+ ret = mtd->write_oob(mtd, *ppos, &ops); -+ retlen = ops.retlen; -+ break; -+ } -+ -+ default: -+ ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf); -+ } -+ if (!ret) { -+ *ppos += retlen; -+ total_retlen += retlen; -+ count -= retlen; -+ buf += retlen; -+ } -+ else { -+ kfree(kbuf); -+ return ret; -+ } -+ } -+ -+ kfree(kbuf); -+ return total_retlen; -+} /* mtd_write */ -+ -+/*====================================================================== -+ -+ IOCTL calls for getting device parameters. -+ -+======================================================================*/ -+static void mtdchar_erase_callback (struct erase_info *instr) -+{ -+ wake_up((wait_queue_head_t *)instr->priv); -+} -+ -+#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) -+static int otp_select_filemode(struct mtd_file_info *mfi, int mode) -+{ -+ struct mtd_info *mtd = mfi->mtd; -+ int ret = 0; -+ -+ switch (mode) { -+ case MTD_OTP_FACTORY: -+ if (!mtd->read_fact_prot_reg) -+ ret = -EOPNOTSUPP; -+ else -+ mfi->mode = MTD_MODE_OTP_FACTORY; -+ break; -+ case MTD_OTP_USER: -+ if (!mtd->read_fact_prot_reg) -+ ret = -EOPNOTSUPP; -+ else -+ mfi->mode = MTD_MODE_OTP_USER; -+ break; -+ default: -+ ret = -EINVAL; -+ case MTD_OTP_OFF: -+ break; -+ } -+ return ret; -+} -+#else -+# define otp_select_filemode(f,m) -EOPNOTSUPP -+#endif -+ -+static int mtd_ioctl(struct inode *inode, struct file *file, -+ u_int cmd, u_long arg) -+{ -+ struct mtd_file_info *mfi = file->private_data; -+ struct mtd_info *mtd = mfi->mtd; -+ void __user *argp = (void __user *)arg; -+ int ret = 0; -+ u_long size; -+ struct mtd_info_user info; -+ -+ DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); -+ -+ size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; -+ if (cmd & IOC_IN) { -+ if (!access_ok(VERIFY_READ, argp, size)) -+ return -EFAULT; -+ } -+ if (cmd & IOC_OUT) { -+ if (!access_ok(VERIFY_WRITE, argp, size)) -+ return -EFAULT; -+ } -+ -+ switch (cmd) { -+ case MEMGETREGIONCOUNT: -+ if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) -+ return -EFAULT; -+ break; -+ -+ case MEMGETREGIONINFO: -+ { -+ struct region_info_user ur; -+ -+ if (copy_from_user(&ur, argp, sizeof(struct region_info_user))) -+ return -EFAULT; -+ -+ if (ur.regionindex >= mtd->numeraseregions) -+ return -EINVAL; -+ if (copy_to_user(argp, &(mtd->eraseregions[ur.regionindex]), -+ sizeof(struct mtd_erase_region_info))) -+ return -EFAULT; -+ break; -+ } -+ -+ case MEMGETINFO: -+ info.type = mtd->type; -+ info.flags = mtd->flags; -+ info.size = mtd->size; -+ info.erasesize = mtd->erasesize; -+ info.writesize = mtd->writesize; -+ info.oobsize = mtd->oobsize; -+ /* The below fields are obsolete */ -+ info.ecctype = -1; -+ info.eccsize = 0; -+ if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) -+ return -EFAULT; -+ break; -+ -+ case MEMERASE: -+ { -+ struct erase_info *erase; -+ -+ if(!(file->f_mode & 2)) -+ return -EPERM; -+ -+ erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL); -+ if (!erase) -+ ret = -ENOMEM; -+ else { -+ wait_queue_head_t waitq; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ init_waitqueue_head(&waitq); -+ -+ if (copy_from_user(&erase->addr, argp, -+ sizeof(struct erase_info_user))) { -+ kfree(erase); -+ return -EFAULT; -+ } -+ erase->mtd = mtd; -+ erase->callback = mtdchar_erase_callback; -+ erase->priv = (unsigned long)&waitq; -+ -+ /* -+ FIXME: Allow INTERRUPTIBLE. Which means -+ not having the wait_queue head on the stack. -+ -+ If the wq_head is on the stack, and we -+ leave because we got interrupted, then the -+ wq_head is no longer there when the -+ callback routine tries to wake us up. -+ */ -+ ret = mtd->erase(mtd, erase); -+ if (!ret) { -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ add_wait_queue(&waitq, &wait); -+ if (erase->state != MTD_ERASE_DONE && -+ erase->state != MTD_ERASE_FAILED) -+ schedule(); -+ remove_wait_queue(&waitq, &wait); -+ set_current_state(TASK_RUNNING); -+ -+ ret = (erase->state == MTD_ERASE_FAILED)?-EIO:0; -+ } -+ kfree(erase); -+ } -+ break; -+ } -+ -+ case MEMWRITEOOB: -+ { -+ struct mtd_oob_buf buf; -+ struct mtd_oob_ops ops; -+ -+ if(!(file->f_mode & 2)) -+ return -EPERM; -+ -+ if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) -+ return -EFAULT; -+ -+ if (buf.length > 4096) -+ return -EINVAL; -+ -+ if (!mtd->write_oob) -+ ret = -EOPNOTSUPP; -+ else -+ ret = access_ok(VERIFY_READ, buf.ptr, -+ buf.length) ? 0 : EFAULT; -+ -+ if (ret) -+ return ret; -+ -+ ops.ooblen = buf.length; -+ ops.ooboffs = buf.start & (mtd->oobsize - 1); -+ ops.datbuf = NULL; -+ ops.mode = MTD_OOB_PLACE; -+ -+ if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) -+ return -EINVAL; -+ -+ ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); -+ if (!ops.oobbuf) -+ return -ENOMEM; -+ -+ if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) { -+ kfree(ops.oobbuf); -+ return -EFAULT; -+ } -+ -+ buf.start &= ~(mtd->oobsize - 1); -+ ret = mtd->write_oob(mtd, buf.start, &ops); -+ -+ if (copy_to_user(argp + sizeof(uint32_t), &ops.oobretlen, -+ sizeof(uint32_t))) -+ ret = -EFAULT; -+ -+ kfree(ops.oobbuf); -+ break; -+ -+ } -+ -+ case MEMREADOOB: -+ { -+ struct mtd_oob_buf buf; -+ struct mtd_oob_ops ops; -+ -+ if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) -+ return -EFAULT; -+ -+ if (buf.length > 4096) -+ return -EINVAL; -+ -+ if (!mtd->read_oob) -+ ret = -EOPNOTSUPP; -+ else -+ ret = access_ok(VERIFY_WRITE, buf.ptr, -+ buf.length) ? 0 : -EFAULT; -+ if (ret) -+ return ret; -+ -+ ops.ooblen = buf.length; -+ ops.ooboffs = buf.start & (mtd->oobsize - 1); -+ ops.datbuf = NULL; -+ ops.mode = MTD_OOB_PLACE; -+ -+ if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) -+ return -EINVAL; -+ -+ ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); -+ if (!ops.oobbuf) -+ return -ENOMEM; -+ -+ buf.start &= ~(mtd->oobsize - 1); -+ ret = mtd->read_oob(mtd, buf.start, &ops); -+ -+ if (put_user(ops.oobretlen, (uint32_t __user *)argp)) -+ ret = -EFAULT; -+ else if (ops.oobretlen && copy_to_user(buf.ptr, ops.oobbuf, -+ ops.oobretlen)) -+ ret = -EFAULT; -+ -+ kfree(ops.oobbuf); -+ break; -+ } -+ -+ case MEMLOCK: -+ { -+ struct erase_info_user info; -+ -+ if (copy_from_user(&info, argp, sizeof(info))) -+ return -EFAULT; -+ -+ if (!mtd->lock) -+ ret = -EOPNOTSUPP; -+ else -+ ret = mtd->lock(mtd, info.start, info.length); -+ break; -+ } -+ -+ case MEMUNLOCK: -+ { -+ struct erase_info_user info; -+ -+ if (copy_from_user(&info, argp, sizeof(info))) -+ return -EFAULT; -+ -+ if (!mtd->unlock) -+ ret = -EOPNOTSUPP; -+ else -+ ret = mtd->unlock(mtd, info.start, info.length); -+ break; -+ } -+ -+ /* Legacy interface */ -+ case MEMGETOOBSEL: -+ { -+ struct nand_oobinfo oi; -+ -+ if (!mtd->ecclayout) -+ return -EOPNOTSUPP; -+ if (mtd->ecclayout->eccbytes > ARRAY_SIZE(oi.eccpos)) -+ return -EINVAL; -+ -+ oi.useecc = MTD_NANDECC_AUTOPLACE; -+ memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos)); -+ memcpy(&oi.oobfree, mtd->ecclayout->oobfree, -+ sizeof(oi.oobfree)); -+ oi.eccbytes = mtd->ecclayout->eccbytes; -+ -+ if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo))) -+ return -EFAULT; -+ break; -+ } -+ -+ case MEMGETBADBLOCK: -+ { -+ loff_t offs; -+ -+ if (copy_from_user(&offs, argp, sizeof(loff_t))) -+ return -EFAULT; -+ if (!mtd->block_isbad) -+ ret = -EOPNOTSUPP; -+ else -+ return mtd->block_isbad(mtd, offs); -+ break; -+ } -+ -+ case MEMSETBADBLOCK: -+ { -+ loff_t offs; -+ -+ if (copy_from_user(&offs, argp, sizeof(loff_t))) -+ return -EFAULT; -+ if (!mtd->block_markbad) -+ ret = -EOPNOTSUPP; -+ else -+ return mtd->block_markbad(mtd, offs); -+ break; -+ } -+ -+#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) -+ case OTPSELECT: -+ { -+ int mode; -+ if (copy_from_user(&mode, argp, sizeof(int))) -+ return -EFAULT; -+ -+ mfi->mode = MTD_MODE_NORMAL; -+ -+ ret = otp_select_filemode(mfi, mode); -+ -+ file->f_pos = 0; -+ break; -+ } -+ -+ case OTPGETREGIONCOUNT: -+ case OTPGETREGIONINFO: -+ { -+ struct otp_info *buf = kmalloc(4096, GFP_KERNEL); -+ if (!buf) -+ return -ENOMEM; -+ ret = -EOPNOTSUPP; -+ switch (mfi->mode) { -+ case MTD_MODE_OTP_FACTORY: -+ if (mtd->get_fact_prot_info) -+ ret = mtd->get_fact_prot_info(mtd, buf, 4096); -+ break; -+ case MTD_MODE_OTP_USER: -+ if (mtd->get_user_prot_info) -+ ret = mtd->get_user_prot_info(mtd, buf, 4096); -+ break; -+ default: -+ break; -+ } -+ if (ret >= 0) { -+ if (cmd == OTPGETREGIONCOUNT) { -+ int nbr = ret / sizeof(struct otp_info); -+ ret = copy_to_user(argp, &nbr, sizeof(int)); -+ } else -+ ret = copy_to_user(argp, buf, ret); -+ if (ret) -+ ret = -EFAULT; -+ } -+ kfree(buf); -+ break; -+ } -+ -+ case OTPLOCK: -+ { -+ struct otp_info info; -+ -+ if (mfi->mode != MTD_MODE_OTP_USER) -+ return -EINVAL; -+ if (copy_from_user(&info, argp, sizeof(info))) -+ return -EFAULT; -+ if (!mtd->lock_user_prot_reg) -+ return -EOPNOTSUPP; -+ ret = mtd->lock_user_prot_reg(mtd, info.start, info.length); -+ break; -+ } -+#endif -+ -+ case ECCGETLAYOUT: -+ { -+ if (!mtd->ecclayout) -+ return -EOPNOTSUPP; -+ -+ if (copy_to_user(argp, mtd->ecclayout, -+ sizeof(struct nand_ecclayout))) -+ return -EFAULT; -+ break; -+ } -+ -+ case ECCGETSTATS: -+ { -+ if (copy_to_user(argp, &mtd->ecc_stats, -+ sizeof(struct mtd_ecc_stats))) -+ return -EFAULT; -+ break; -+ } -+ -+ case MTDFILEMODE: -+ { -+ mfi->mode = 0; -+ -+ switch(arg) { -+ case MTD_MODE_OTP_FACTORY: -+ case MTD_MODE_OTP_USER: -+ ret = otp_select_filemode(mfi, arg); -+ break; -+ -+ case MTD_MODE_RAW: -+ if (!mtd->read_oob || !mtd->write_oob) -+ return -EOPNOTSUPP; -+ mfi->mode = arg; -+ -+ case MTD_MODE_NORMAL: -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ file->f_pos = 0; -+ break; -+ } -+#ifdef CONFIG_MTD_PARTITIONS -+ case MTDREFRESH: -+ { -+ ret = refresh_mtd_partitions(mtd); -+ break; -+ } -+#endif -+ -+ default: -+ ret = -ENOTTY; -+ } -+ -+ return ret; -+} /* memory_ioctl */ -+ -+static const struct file_operations mtd_fops = { -+ .owner = THIS_MODULE, -+ .llseek = mtd_lseek, -+ .read = mtd_read, -+ .write = mtd_write, -+ .ioctl = mtd_ioctl, -+ .open = mtd_open, -+ .release = mtd_close, -+}; -+ -+static int __init init_mtdchar(void) -+{ -+ if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) { -+ printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", -+ MTD_CHAR_MAJOR); -+ return -EAGAIN; -+ } -+ -+ mtd_class = class_create(THIS_MODULE, "mtd"); -+ -+ if (IS_ERR(mtd_class)) { -+ printk(KERN_ERR "Error creating mtd class.\n"); -+ unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); -+ return PTR_ERR(mtd_class); -+ } -+ -+ register_mtd_user(¬ifier); -+ return 0; -+} -+ -+static void __exit cleanup_mtdchar(void) -+{ -+ unregister_mtd_user(¬ifier); -+ class_destroy(mtd_class); -+ unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); -+} -+ -+module_init(init_mtdchar); -+module_exit(cleanup_mtdchar); -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("David Woodhouse "); -+MODULE_DESCRIPTION("Direct character-device access to MTD devices"); + --- linux-2.6.24.7.old/drivers/mtd/mtdcore.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/mtd/mtdcore.c 2009-04-12 18:13:57.000000000 +0200 @@ -303,10 +303,10 @@ */ - + int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen) + unsigned long count, loff_mtd_t to, size_mtd_t *retlen) @@ -70447,17 +13530,17 @@ - size_t totlen = 0, thislen; + size_mtd_t totlen = 0, thislen; int ret = 0; - + if(!mtd->write) { @@ -350,7 +350,7 @@ if (!this) return 0; - + - return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size, + return sprintf(buf, "mtd%d: %09llx %8.8x \"%s\"\n", i, this->size, this->erasesize, this->name); } - + --- linux-2.6.24.7.old/drivers/mtd/mtdpart.c 2009-04-12 18:05:07.000000000 +0200 +++ linux-2.6.24.7/drivers/mtd/mtdpart.c 2009-04-12 18:38:31.000000000 +0200 @@ -30,7 +30,7 @@ @@ -70472,174 +13555,168 @@ @@ -48,8 +48,8 @@ * to the _real_ device. */ - --static int part_read (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char *buf) -+static int part_read (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, u_char *buf) + +-static int part_read(struct mtd_info *mtd, loff_t from, size_t len, +- size_t *retlen, u_char *buf) ++static int part_read(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, ++ size_mtd_t *retlen, u_char *buf) { - struct mtd_part *part = PART(mtd); - int res; + struct mtd_part *part = PART(mtd); + int res; @@ -69,8 +69,8 @@ return res; } - --static int part_point (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char **buf) -+static int part_point (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, u_char **buf) + +-static int part_point(struct mtd_info *mtd, loff_t from, size_t len, +- size_t *retlen, void **virt, resource_size_t *phys) ++static int part_point(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, ++ size_mtd_t *retlen, void **virt, resource_size_t *phys) { struct mtd_part *part = PART(mtd); if (from >= mtd->size) @@ -81,14 +81,14 @@ - len, retlen, buf); + len, retlen, virt, phys); } - --static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) -+static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_mtd_t from, size_mtd_t len) + +-static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len) ++static void part_unpoint(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len) { struct mtd_part *part = PART(mtd); - - part->master->unpoint (part->master, addr, from + part->offset, len); + + part->master->unpoint(part->master, from + part->offset, len); } - + -static int part_read_oob(struct mtd_info *mtd, loff_t from, +static int part_read_oob(struct mtd_info *mtd, loff_mtd_t from, - struct mtd_oob_ops *ops) + struct mtd_oob_ops *ops) { struct mtd_part *part = PART(mtd); @@ -109,8 +109,8 @@ return res; } - --static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char *buf) -+static int part_read_user_prot_reg (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, u_char *buf) + +-static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from, +- size_t len, size_t *retlen, u_char *buf) ++static int part_read_user_prot_reg(struct mtd_info *mtd, loff_mtd_t from, ++ size_mtd_t len, size_mtd_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->read_user_prot_reg (part->master, from, + return part->master->write_oob(part->master, to + part->offset, ops); @@ -118,14 +118,14 @@ } - - static int part_get_user_prot_info (struct mtd_info *mtd, -- struct otp_info *buf, size_t len) -+ struct otp_info *buf, size_mtd_t len) + + static int part_get_user_prot_info(struct mtd_info *mtd, +- struct otp_info *buf, size_t len) ++ struct otp_info *buf, size_mtd_t len) { struct mtd_part *part = PART(mtd); - return part->master->get_user_prot_info (part->master, buf, len); + return part->master->get_user_prot_info(part->master, buf, len); } - --static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char *buf) -+static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, u_char *buf) + +-static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, +- size_t len, size_t *retlen, u_char *buf) ++static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_mtd_t from, ++ size_mtd_t len, size_mtd_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->read_fact_prot_reg (part->master, from, + return part->master->read_fact_prot_reg(part->master, from, @@ -133,14 +133,14 @@ } - - static int part_get_fact_prot_info (struct mtd_info *mtd, -- struct otp_info *buf, size_t len) -+ struct otp_info *buf, size_mtd_t len) + + static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf, +- size_t len) ++ size_mtd_t len) { struct mtd_part *part = PART(mtd); - return part->master->get_fact_prot_info (part->master, buf, len); + return part->master->get_fact_prot_info(part->master, buf, len); } - --static int part_write (struct mtd_info *mtd, loff_t to, size_t len, -- size_t *retlen, const u_char *buf) -+static int part_write (struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len, -+ size_mtd_t *retlen, const u_char *buf) + +-static int part_write(struct mtd_info *mtd, loff_t to, size_t len, +- size_t *retlen, const u_char *buf) ++static int part_write(struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len, ++ size_mtd_t *retlen, const u_char *buf) { struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) @@ -153,7 +153,7 @@ len, retlen, buf); } - + -static int part_write_oob(struct mtd_info *mtd, loff_t to, +static int part_write_oob(struct mtd_info *mtd, loff_mtd_t to, - struct mtd_oob_ops *ops) + struct mtd_oob_ops *ops) { struct mtd_part *part = PART(mtd); @@ -168,22 +168,22 @@ return part->master->write_oob(part->master, to + part->offset, ops); } - --static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char *buf) -+static int part_write_user_prot_reg (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, u_char *buf) + +-static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from, +- size_t len, size_t *retlen, u_char *buf) ++static int part_write_user_prot_reg(struct mtd_info *mtd, loff_mtd_t from, ++ size_mtd_t len, size_mtd_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->write_user_prot_reg (part->master, from, + return part->master->write_user_prot_reg(part->master, from, len, retlen, buf); } - --static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) -+static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len) + +-static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, +- size_t len) ++static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_mtd_t from, ++ size_mtd_t len) { struct mtd_part *part = PART(mtd); - return part->master->lock_user_prot_reg (part->master, from, len); + return part->master->lock_user_prot_reg(part->master, from, len); } - - static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, -- unsigned long count, loff_t to, size_t *retlen) -+ unsigned long count, loff_mtd_t to, size_mtd_t *retlen) + + static int part_writev(struct mtd_info *mtd, const struct kvec *vecs, +- unsigned long count, loff_t to, size_t *retlen) ++ unsigned long count, loff_mtd_t to, size_mtd_t *retlen) { struct mtd_part *part = PART(mtd); - if (!(mtd->flags & MTD_WRITEABLE)) @@ -224,7 +224,7 @@ } EXPORT_SYMBOL_GPL(mtd_erase_callback); - --static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) -+static int part_lock (struct mtd_info *mtd, loff_mtd_t ofs, size_mtd_t len) + +-static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len) ++static int part_lock(struct mtd_info *mtd, loff_mtd_t ofs, size_mtd_t len) { struct mtd_part *part = PART(mtd); if ((len + ofs) > mtd->size) @@ -232,7 +232,7 @@ return part->master->lock(part->master, ofs + part->offset, len); } - --static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) -+static int part_unlock (struct mtd_info *mtd, loff_mtd_t ofs, size_mtd_t len) + +-static int part_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) ++static int part_unlock(struct mtd_info *mtd, loff_mtd_t ofs, size_mtd_t len) { struct mtd_part *part = PART(mtd); if ((len + ofs) > mtd->size) @@ -258,7 +258,7 @@ part->master->resume(part->master); } - --static int part_block_isbad (struct mtd_info *mtd, loff_t ofs) -+static int part_block_isbad (struct mtd_info *mtd, loff_mtd_t ofs) + +-static int part_block_isbad(struct mtd_info *mtd, loff_t ofs) ++static int part_block_isbad(struct mtd_info *mtd, loff_mtd_t ofs) { struct mtd_part *part = PART(mtd); if (ofs >= mtd->size) @@ -267,7 +267,7 @@ return part->master->block_isbad(part->master, ofs); } - --static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) -+static int part_block_markbad (struct mtd_info *mtd, loff_mtd_t ofs) + +-static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) ++static int part_block_markbad(struct mtd_info *mtd, loff_mtd_t ofs) { struct mtd_part *part = PART(mtd); int res; --- linux-2.6.24.7.old/drivers/mtd/nand/Kconfig 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/mtd/nand/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -1,5 +1,5 @@ - # drivers/mtd/nand/Kconfig --# $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ -+# $Id: Kconfig,v 1.3 2008-07-04 08:05:48 lhhuang Exp $ - - menuconfig MTD_NAND - tristate "NAND Device Support" @@ -306,4 +306,127 @@ - These two (and possibly other) Alauda-based cardreaders for - SmartMedia and xD allow raw flash access. - + Several Renesas SuperH CPU has FLCTL. This option enables support + for NAND Flash using FLCTL. This driver support SH7723. + +config MTD_NAND_JZ4730 + tristate "Support NAND Flash device on Jz4730 board" + depends on SOC_JZ4730 @@ -70684,11 +13761,11 @@ +choice + prompt "ECC type" + default CONFIG_MTD_SW_HM_ECC -+ ++ +config MTD_HW_HM_ECC + depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4730 + bool 'Select hardware HM ECC' -+ ++ +config MTD_SW_HM_ECC + bool 'Select software HM ECC' + @@ -70718,16 +13795,16 @@ + depends on MTD_HW_BCH_ECC + bool 'Use DMA mode' + help -+ This enables using DMA for reading and writing NAND flash, if not selected, ++ This enables using DMA for reading and writing NAND flash, if not selected, + then CPU mode is used. + +config MTD_NAND_DMABUF + depends on MTD_NAND_DMA + bool 'use DMA buffer in NAND driver' + help -+ It's better to say NO. If saying yes, DMA buffers will be allocated for -+ NAND reading and writing in NAND driver instead of upper layer. It's -+ slower. Just usable on CS1_N now. By saying NO, upper buffers will be ++ It's better to say NO. If saying yes, DMA buffers will be allocated for ++ NAND reading and writing in NAND driver instead of upper layer. It's ++ slower. Just usable on CS1_N now. By saying NO, upper buffers will be + used as DMA buffer. It's faster, but kmalloc instead of vmalloc is required. +endif + @@ -70766,23 +13843,14 @@ endif # MTD_NAND --- linux-2.6.24.7.old/drivers/mtd/nand/Makefile 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/mtd/nand/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -1,7 +1,7 @@ - # - # linux/drivers/nand/Makefile - # --# $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $ -+# $Id: Makefile,v 1.2 2008-07-04 08:07:45 lhhuang Exp $ - - obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o - obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o @@ -29,5 +29,8 @@ - obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o - obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o - obj-$(CONFIG_MTD_ALAUDA) += alauda.o + obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o + obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o + obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o +obj-$(CONFIG_MTD_NAND_JZ4730) += jz4730_nand.o +obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o +obj-$(CONFIG_MTD_NAND_JZ4750) += jz4750_nand.o - + nand-objs := nand_base.o nand_bbt.o --- linux-2.6.24.7.old/drivers/mtd/nand/jz4730_nand.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/drivers/mtd/nand/jz4730_nand.c 2009-04-12 18:13:57.000000000 +0200 @@ -70906,7 +13974,7 @@ + +/*-------------------------------------------------------------------------*/ + -+static void jz_hwcontrol(struct mtd_info *mtd, int dat, ++static void jz_hwcontrol(struct mtd_info *mtd, int dat, + unsigned int ctrl) +{ + struct nand_chip *this = (struct nand_chip *)(mtd->priv); @@ -70960,11 +14028,11 @@ +{ + unsigned int calc_ecc; + unsigned char *tmp; -+ ++ + __nand_ecc_disable(); + + calc_ecc = ~(__nand_ecc()) | 0x00030000; -+ ++ + tmp = (unsigned char *)&calc_ecc; + + ecc_code[0] = tmp[1]; @@ -70980,8 +14048,8 @@ + u_char *read_ecc, u_char *calc_ecc) +{ + u_char a, b, c, d1, d2, d3, add, bit, i; -+ -+ /* Do error detection */ ++ ++ /* Do error detection */ + d1 = calc_ecc[0] ^ read_ecc[0]; + d2 = calc_ecc[1] ^ read_ecc[1]; + d3 = calc_ecc[2] ^ read_ecc[2]; @@ -70994,7 +14062,7 @@ + a = (d1 ^ (d1 >> 1)) & 0x55; + b = (d2 ^ (d2 >> 1)) & 0x55; + c = (d3 ^ (d3 >> 1)) & 0x54; -+ ++ + /* Found and will correct single bit error in the data */ + if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { + c = 0x80; @@ -71059,7 +14127,7 @@ + } + } + } -+ ++ + /* Should never happen */ + return -1; +} @@ -71072,7 +14140,7 @@ +{ + struct nand_chip *this; + int nr_partitions; -+ ++ + /* Allocate memory for MTD device structure and private data */ + jz_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), + GFP_KERNEL); @@ -71107,10 +14175,10 @@ + this->ecc.mode = NAND_ECC_HW; + this->ecc.size = 256; + this->ecc.bytes = 3; -+ ++ +#endif + -+#ifdef CONFIG_MTD_SW_HM_ECC ++#ifdef CONFIG_MTD_SW_HM_ECC + this->eccmode = NAND_ECC_SOFT; +#endif + @@ -71142,7 +14210,7 @@ + + /* Unregister partitions */ + del_mtd_partitions(jz_mtd); -+ ++ + /* Unregister the device */ + del_mtd_device (jz_mtd); + @@ -71157,2806 +14225,2806 @@ --- linux-2.6.24.7.old/drivers/mtd/nand/jz4740_nand.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/drivers/mtd/nand/jz4740_nand.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,1037 @@ -+/* -+ * linux/drivers/mtd/nand/jz4740_nand.c -+ * -+ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Ingenic JZ4740 NAND driver -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define NAND_DATA_PORT1 0xB8000000 /* read-write area in static bank 1 */ -+#define NAND_DATA_PORT2 0xB4000000 /* read-write area in static bank 2 */ -+#define NAND_DATA_PORT3 0xAC000000 /* read-write area in static bank 3 */ -+#define NAND_DATA_PORT4 0xA8000000 /* read-write area in static bank 4 */ -+ -+#define PAR_SIZE 9 -+ -+#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1) -+#define __nand_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1) -+ -+#define __nand_ecc_enable() (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST ) -+#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE) -+ -+#define __nand_select_hm_ecc() (REG_EMC_NFECR &= ~EMC_NFECR_RS ) -+#define __nand_select_rs_ecc() (REG_EMC_NFECR |= EMC_NFECR_RS) -+ -+#define __nand_read_hm_ecc() (REG_EMC_NFECC & 0x00ffffff) -+ -+#define __nand_rs_ecc_encoding() (REG_EMC_NFECR |= EMC_NFECR_RS_ENCODING) -+#define __nand_rs_ecc_decoding() (REG_EMC_NFECR &= ~EMC_NFECR_RS_ENCODING) -+#define __nand_ecc_encode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_ENCF)) -+#define __nand_ecc_decode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_DECF)) -+ -+/* -+ * MTD structure for JzSOC board -+ */ -+static struct mtd_info *jz_mtd = NULL; -+extern struct mtd_info *jz_mtd1; -+extern char all_use_planes; -+extern int global_page; /* for two-plane operations */ -+ -+/* -+ * Define partitions for flash devices -+ */ -+#ifdef CONFIG_JZ4740_PAVO -+static struct mtd_partition partition_info[] = { -+ { name: "NAND BOOT partition", -+ offset: 0 * 0x100000, -+ size: 4 * 0x100000, -+ use_planes: 0 }, -+ { name: "NAND KERNEL partition", -+ offset: 4 * 0x100000, -+ size: 4 * 0x100000, -+ use_planes: 0 }, -+ { name: "NAND ROOTFS partition", -+ offset: 8 * 0x100000, -+ size: 120 * 0x100000, -+ use_planes: 0 }, -+ { name: "NAND DATA1 partition", -+ offset: 128 * 0x100000, -+ size: 128 * 0x100000, -+ use_planes: 1 }, -+ { name: "NAND DATA2 partition", -+ offset: 256 * 0x100000, -+ size: 256 * 0x100000, -+ use_planes: 1 }, -+ { name: "NAND VFAT partition", -+ offset: 512 * 0x100000, -+ size: 512 * 0x100000, -+ use_planes: 1 }, -+}; -+ -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10, /* reserved blocks of mtd3 */ -+ 20, /* reserved blocks of mtd4 */ -+ 20}; /* reserved blocks of mtd5 */ -+#endif /* CONFIG_JZ4740_PAVO */ -+ -+#ifdef CONFIG_JZ4740_LEO -+static struct mtd_partition partition_info[] = { -+ { name: "NAND BOOT partition", -+ offset: 0 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND KERNEL partition", -+ offset: 4 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND ROOTFS partition", -+ offset: 8 * 0x100000, -+ size: 56 * 0x100000 }, -+ { name: "NAND VFAT partition", -+ offset: 64 * 0x100000, -+ size: 64 * 0x100000 }, -+}; -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10}; /* reserved blocks of mtd3 */ -+#endif /* CONFIG_JZ4740_LEO */ -+ -+#ifdef CONFIG_JZ4740_LYRA -+static struct mtd_partition partition_info[] = { -+ { name: "NAND BOOT partition", -+ offset: 0 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND KERNEL partition", -+ offset: 4 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND ROOTFS partition", -+ offset: 8 * 0x100000, -+ size: 120 * 0x100000 }, -+ { name: "NAND DATA1 partition", -+ offset: 128 * 0x100000, -+ size: 128 * 0x100000 }, -+ { name: "NAND DATA2 partition", -+ offset: 256 * 0x100000, -+ size: 256 * 0x100000 }, -+ { name: "NAND VFAT partition", -+ offset: 512 * 0x100000, -+ size: 512 * 0x100000 }, -+}; -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10, /* reserved blocks of mtd3 */ -+ 20, /* reserved blocks of mtd4 */ -+ 20}; /* reserved blocks of mtd5 */ -+#endif /* CONFIG_JZ4740_LYRA */ -+ -+#ifdef CONFIG_JZ4725_DIPPER -+static struct mtd_partition partition_info[] = { -+ { name: "NAND BOOT partition", -+ offset: 0 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND KERNEL partition", -+ offset: 4 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND ROOTFS partition", -+ offset: 8 * 0x100000, -+ size: 56 * 0x100000 }, -+ { name: "NAND VFAT partition", -+ offset: 64 * 0x100000, -+ size: 64 * 0x100000 }, -+}; -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10}; /* reserved blocks of mtd3 */ -+#endif /* CONFIG_JZ4740_DIPPER */ -+ -+#ifdef CONFIG_JZ4720_VIRGO -+static struct mtd_partition partition_info[] = { -+ { name: "NAND BOOT partition", -+ offset: 0 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND KERNEL partition", -+ offset: 4 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND ROOTFS partition", -+ offset: 8 * 0x100000, -+ size: 120 * 0x100000 }, -+ { name: "NAND DATA1 partition", -+ offset: 128 * 0x100000, -+ size: 128 * 0x100000 }, -+ { name: "NAND DATA2 partition", -+ offset: 256 * 0x100000, -+ size: 256 * 0x100000 }, -+ { name: "NAND VFAT partition", -+ offset: 512 * 0x100000, -+ size: 512 * 0x100000 }, -+}; -+ -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10, /* reserved blocks of mtd3 */ -+ 20, /* reserved blocks of mtd4 */ -+ 20}; /* reserved blocks of mtd5 */ -+#endif /* CONFIG_JZ4720_VIRGO */ -+/*------------------------------------------------------------------------- -+ * Following three functions are exported and used by the mtdblock-jz.c -+ * NAND FTL driver only. -+ */ -+ -+unsigned short get_mtdblock_write_verify_enable(void) -+{ -+#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE -+ return 1; -+#endif -+ return 0; -+} -+EXPORT_SYMBOL(get_mtdblock_write_verify_enable); -+ -+unsigned short get_mtdblock_oob_copies(void) -+{ -+ return CONFIG_MTD_OOB_COPIES; -+} -+EXPORT_SYMBOL(get_mtdblock_oob_copies); -+ -+int *get_jz_badblock_table(void) -+{ -+ return partition_reserved_badblocks; -+} -+EXPORT_SYMBOL(get_jz_badblock_table); -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void jz_hwcontrol(struct mtd_info *mtd, int dat, -+ unsigned int ctrl) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ unsigned int nandaddr = (unsigned int)this->IO_ADDR_W; -+ extern u8 nand_nce; /* in nand_base.c, indicates which chip select is used for current nand chip */ -+ -+ if (ctrl & NAND_CTRL_CHANGE) { -+ if (ctrl & NAND_NCE) { -+ switch (nand_nce) { -+ case NAND_NCE1: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE1; -+ break; -+ case NAND_NCE2: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE2; -+ break; -+ case NAND_NCE3: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE3; -+ break; -+ case NAND_NCE4: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT4; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE4; -+ break; -+ default: -+ printk("error: no nand_nce 0x%x\n",nand_nce); -+ break; -+ } -+ } else { -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ } -+ -+ if ( ctrl & NAND_ALE ) -+ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) | 0x00010000); -+ else -+ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) & ~0x00010000); -+ -+ if ( ctrl & NAND_CLE ) -+ nandaddr = nandaddr | 0x00008000; -+ else -+ nandaddr = nandaddr & ~0x00008000; -+ } -+ -+ this->IO_ADDR_W = (void __iomem *)nandaddr; -+ if (dat != NAND_CMD_NONE) -+ writeb(dat, this->IO_ADDR_W); -+} -+ -+static int jz_device_ready(struct mtd_info *mtd) -+{ -+ int ready, wait = 10; -+ while (wait--); -+ ready = __gpio_get_pin(94); -+ return ready; -+} -+ -+/* -+ * EMC setup -+ */ -+static void jz_device_setup(void) -+{ -+// PORT 0: -+// ... -+// PORT 1: -+// PIN/BIT N FUNC0 FUNC1 -+// 25 CS1# - -+// 26 CS2# - -+// 27 CS3# - -+// 28 CS4# - -+#define GPIO_CS2_N (32+26) -+#define GPIO_CS3_N (32+27) -+#define GPIO_CS4_N (32+28) -+#define SMCR_VAL 0x0d221200 -+ -+ /* Set NFE bit */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE1; -+ /* Read/Write timings */ -+ REG_EMC_SMCR1 = SMCR_VAL; -+ -+#if defined(CONFIG_MTD_NAND_CS2) -+ /* Set CS2# pin as function 0 */ -+ __gpio_as_func0(GPIO_CS2_N); -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE2; -+ REG_EMC_SMCR2 = SMCR_VAL; -+#endif -+ -+#if defined(CONFIG_MTD_NAND_CS3) -+ __gpio_as_func0(GPIO_CS3_N); -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE3; -+ REG_EMC_SMCR3 = SMCR_VAL; -+#endif -+ -+#if defined(CONFIG_MTD_NAND_CS4) -+ __gpio_as_func0(GPIO_CS4_N); -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE4; -+ REG_EMC_SMCR4 = SMCR_VAL; -+#endif -+} -+ -+#ifdef CONFIG_MTD_HW_HM_ECC -+ -+static int jzsoc_nand_calculate_hm_ecc(struct mtd_info* mtd, -+ const u_char* dat, u_char* ecc_code) -+{ -+ unsigned int calc_ecc; -+ unsigned char *tmp; -+ -+ __nand_ecc_disable(); -+ -+ calc_ecc = ~(__nand_read_hm_ecc()) | 0x00030000; -+ -+ tmp = (unsigned char *)&calc_ecc; -+ //adjust eccbytes order for compatible with software ecc -+ ecc_code[0] = tmp[1]; -+ ecc_code[1] = tmp[0]; -+ ecc_code[2] = tmp[2]; -+ -+ return 0; -+} -+ -+static void jzsoc_nand_enable_hm_hwecc(struct mtd_info* mtd, int mode) -+{ -+ __nand_ecc_enable(); -+ __nand_select_hm_ecc(); -+} -+ -+static int jzsoc_nand_hm_correct_data(struct mtd_info *mtd, u_char *dat, -+ u_char *read_ecc, u_char *calc_ecc) -+{ -+ u_char a, b, c, d1, d2, d3, add, bit, i; -+ -+ /* Do error detection */ -+ d1 = calc_ecc[0] ^ read_ecc[0]; -+ d2 = calc_ecc[1] ^ read_ecc[1]; -+ d3 = calc_ecc[2] ^ read_ecc[2]; -+ -+ if ((d1 | d2 | d3) == 0) { -+ /* No errors */ -+ return 0; -+ } -+ else { -+ a = (d1 ^ (d1 >> 1)) & 0x55; -+ b = (d2 ^ (d2 >> 1)) & 0x55; -+ c = (d3 ^ (d3 >> 1)) & 0x54; -+ -+ /* Found and will correct single bit error in the data */ -+ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { -+ c = 0x80; -+ add = 0; -+ a = 0x80; -+ for (i=0; i<4; i++) { -+ if (d1 & c) -+ add |= a; -+ c >>= 2; -+ a >>= 1; -+ } -+ c = 0x80; -+ for (i=0; i<4; i++) { -+ if (d2 & c) -+ add |= a; -+ c >>= 2; -+ a >>= 1; -+ } -+ bit = 0; -+ b = 0x04; -+ c = 0x80; -+ for (i=0; i<3; i++) { -+ if (d3 & c) -+ bit |= b; -+ c >>= 2; -+ b >>= 1; -+ } -+ b = 0x01; -+ a = dat[add]; -+ a ^= (b << bit); -+ dat[add] = a; -+ return 0; -+ } -+ else { -+ i = 0; -+ while (d1) { -+ if (d1 & 0x01) -+ ++i; -+ d1 >>= 1; -+ } -+ while (d2) { -+ if (d2 & 0x01) -+ ++i; -+ d2 >>= 1; -+ } -+ while (d3) { -+ if (d3 & 0x01) -+ ++i; -+ d3 >>= 1; -+ } -+ if (i == 1) { -+ /* ECC Code Error Correction */ -+ read_ecc[0] = calc_ecc[0]; -+ read_ecc[1] = calc_ecc[1]; -+ read_ecc[2] = calc_ecc[2]; -+ return 0; -+ } -+ else { -+ /* Uncorrectable Error */ -+ printk("NAND: uncorrectable ECC error\n"); -+ return -1; -+ } -+ } -+ } -+ -+ /* Should never happen */ -+ return -1; -+} -+ -+#endif /* CONFIG_MTD_HW_HM_ECC */ -+ -+#ifdef CONFIG_MTD_HW_RS_ECC -+ -+static void jzsoc_nand_enable_rs_hwecc(struct mtd_info* mtd, int mode) -+{ -+ REG_EMC_NFINTS = 0x0; -+ __nand_ecc_enable(); -+ __nand_select_rs_ecc(); -+ -+ if (mode == NAND_ECC_READ) -+ __nand_rs_ecc_decoding(); -+ -+ if (mode == NAND_ECC_WRITE) -+ __nand_rs_ecc_encoding(); -+} -+ -+static void jzsoc_rs_correct(unsigned char *dat, int idx, int mask) -+{ -+ int i; -+ -+ idx--; -+ -+ i = idx + (idx >> 3); -+ if (i >= 512) -+ return; -+ -+ mask <<= (idx & 0x7); -+ -+ dat[i] ^= mask & 0xff; -+ if (i < 511) -+ dat[i+1] ^= (mask >> 8) & 0xff; -+} -+ -+/* -+ * calc_ecc points to oob_buf for us -+ */ -+static int jzsoc_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat, -+ u_char *read_ecc, u_char *calc_ecc) -+{ -+ volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0; -+ short k; -+ u32 stat; -+ -+ /* Set PAR values */ -+ for (k = 0; k < PAR_SIZE; k++) { -+ *paraddr++ = read_ecc[k]; -+ } -+ -+ /* Set PRDY */ -+ REG_EMC_NFECR |= EMC_NFECR_PRDY; -+ -+ /* Wait for completion */ -+ __nand_ecc_decode_sync(); -+ __nand_ecc_disable(); -+ -+ /* Check decoding */ -+ stat = REG_EMC_NFINTS; -+ -+ if (stat & EMC_NFINTS_ERR) { -+ /* Error occurred */ -+ if (stat & EMC_NFINTS_UNCOR) { -+ printk("NAND: Uncorrectable ECC error\n"); -+ return -1; -+ } else { -+ u32 errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT; -+ switch (errcnt) { -+ case 4: -+ jzsoc_rs_correct(dat, (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); -+ /* FALL-THROUGH */ -+ case 3: -+ jzsoc_rs_correct(dat, (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); -+ /* FALL-THROUGH */ -+ case 2: -+ jzsoc_rs_correct(dat, (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); -+ /* FALL-THROUGH */ -+ case 1: -+ jzsoc_rs_correct(dat, (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); -+ return 0; -+ default: -+ break; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int jzsoc_nand_calculate_rs_ecc(struct mtd_info* mtd, const u_char* dat, -+ u_char* ecc_code) -+{ -+ volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0; -+ short i; -+ -+ __nand_ecc_encode_sync(); -+ __nand_ecc_disable(); -+ -+ for(i = 0; i < PAR_SIZE; i++) { -+ ecc_code[i] = *paraddr++; -+ } -+ -+ return 0; -+} -+ -+#endif /* CONFIG_MTD_HW_RS_ECC */ -+ -+/* Nand optimized functions */ -+static int dma_chan; -+static unsigned int dma_src_phys_addr, dma_dst_phys_addr; -+extern int jz_request_dma(int dev_id, const char *dev_str, -+ irqreturn_t (*irqhandler)(int, void *), -+ unsigned long irqflags, void *irq_dev_id); -+ -+static void dma_setup(void) -+{ -+ /* Request DMA channel and setup irq handler */ -+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", NULL, IRQF_DISABLED, NULL); -+ if (dma_chan < 0) { -+ printk("Setup irq for nand failed!\n"); -+ return; -+ } else -+ printk("Nand DMA request channel %d.\n",dma_chan); -+} -+ -+static void jz4740_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -+{ -+ int i; -+ struct nand_chip *chip = mtd->priv; -+ -+ if ((len <= 32) || (len & 0xf) || ((u32)buf >= (u32)high_memory)) -+ { -+ for (i = 0; i < len; i++) -+ buf[i] = readb(chip->IO_ADDR_R); -+ } else { -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; -+ dma_src_phys_addr = CPHYSADDR(chip->IO_ADDR_R); -+ dma_dst_phys_addr = CPHYSADDR(buf); -+ dma_cache_inv((u32)buf, len); -+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; -+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; -+ REG_DMAC_DTCR(dma_chan) = len / 16; -+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE; -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; -+ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */ -+ -+ while(!(REG_DMAC_DCCSR(dma_chan) & DMAC_DCCSR_TT)); -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ __dmac_channel_clear_transmit_end(dma_chan); -+ } -+} -+ -+static void jz4740_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -+{ -+ int i; -+ struct nand_chip *chip = mtd->priv; -+ -+ if ((len <= 32) || (len & 0xf) || ((u32)buf >= (u32)high_memory)) -+ { -+ for (i = 0; i < len; i++) -+ writeb(buf[i], chip->IO_ADDR_W); -+ } else { -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; -+ dma_dst_phys_addr = CPHYSADDR(chip->IO_ADDR_R); -+ dma_src_phys_addr = CPHYSADDR(buf); -+ dma_cache_wback((unsigned long)buf, len); -+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; -+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; -+ REG_DMAC_DTCR(dma_chan) = len / 16; -+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_16BYTE ; -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; -+ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */ -+ -+ while(!(REG_DMAC_DCCSR(dma_chan) & DMAC_DCCSR_TT)); -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ __dmac_channel_clear_transmit_end(dma_chan); -+ } -+} -+ -+static int nand_read_page_hwecc_rs_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ uint8_t *buf) -+{ -+ int i, eccsize = chip->ecc.size; -+ int eccbytes = chip->ecc.bytes; -+ int eccsteps = chip->ecc.steps >> 1; -+ uint8_t *p; -+ uint8_t *ecc_calc = chip->buffers->ecccalc; -+ uint8_t *ecc_code = chip->buffers->ecccode; -+ uint32_t *eccpos = chip->ecc.layout->eccpos; -+ uint32_t page; -+ uint8_t flag = 0; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ int ecctotal = chip->ecc.total >> 1; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* Read first page */ -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ chip->read_buf(mtd, chip->oob_poi, oobsize); -+ for (i = 0; i < ecctotal; i++) { -+ ecc_code[i] = chip->oob_poi[eccpos[i]]; -+ if (ecc_code[i] != 0xff) flag = 1; -+ } -+ -+ p = buf; -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1); -+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { -+ int stat; -+ if (flag) { -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); -+ if (stat < 0) -+ mtd->ecc_stats.failed++; -+ else -+ mtd->ecc_stats.corrected += stat; -+ } -+ else { -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ } -+ } -+ /* Read second page */ -+ page += ppb; -+ flag = 0; -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ chip->read_buf(mtd, chip->oob_poi + oobsize, oobsize); -+ for (i = 0; i < ecctotal; i++) { -+ ecc_code[i] = chip->oob_poi[oobsize + eccpos[i]]; -+ if (ecc_code[i] != 0xff) flag = 1; -+ } -+ -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1); -+ eccsteps = chip->ecc.steps >> 1; -+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { -+ int stat; -+ if (flag) { -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); -+ if (stat < 0) -+ mtd->ecc_stats.failed++; -+ else -+ mtd->ecc_stats.corrected += stat; -+ } -+ else { -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ } -+ } -+ -+ return 0; -+} -+ -+static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ int global_page, int sndcmd) -+{ -+ int page; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* Read first page OOB */ -+ if (sndcmd) { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ } -+ chip->read_buf(mtd, chip->oob_poi, oobsize); -+ /* Read second page OOB */ -+ page += ppb; -+ if (sndcmd) { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ sndcmd = 0; -+ } -+ chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize); -+ return 0; -+} -+ -+static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ int global_page) -+{ -+ int status = 0,page; -+ int pagesize = mtd->writesize >> 1; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ const uint8_t *buf = chip->oob_poi; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x80, pagesize, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ chip->write_buf(mtd, buf, oobsize); -+ /* Send first command to program the OOB data */ -+ chip->cmdfunc(mtd, 0x11, -1, -1); -+ ndelay(100); -+ status = chip->waitfunc(mtd, chip); -+ -+ page += ppb; -+ buf += oobsize; -+ chip->cmdfunc(mtd, 0x81, pagesize, page); -+ chip->write_buf(mtd, buf, oobsize); -+ /* Send command to program the OOB data */ -+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -+ /* Wait long R/B */ -+ ndelay(100); -+ status = chip->waitfunc(mtd, chip); -+ -+ return status & NAND_STATUS_FAIL ? -EIO : 0; -+} -+ -+static void nand_write_page_hwecc_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ const uint8_t *buf) -+{ -+ int i, eccsize = chip->ecc.size; -+ int eccbytes = chip->ecc.bytes; -+ int eccsteps = chip->ecc.steps >> 1; -+ uint8_t *ecc_calc = chip->buffers->ecccalc; -+ uint8_t *p = (uint8_t *)buf; -+ uint32_t *eccpos = chip->ecc.layout->eccpos; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ int ecctotal = chip->ecc.total >> 1; -+ int page; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { -+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); -+ chip->write_buf(mtd, p, eccsize); -+ chip->ecc.calculate(mtd, p, &ecc_calc[i]); -+ } -+ for (i = 0; i < ecctotal; i++) -+ chip->oob_poi[eccpos[i]] = ecc_calc[i]; -+ -+ chip->write_buf(mtd, chip->oob_poi, oobsize); -+ -+ chip->cmdfunc(mtd, 0x11, -1, -1); /* send cmd 0x11 */ -+ ndelay(100); -+ while(!chip->dev_ready(mtd)); -+ -+ page += ppb; -+ chip->cmdfunc(mtd, 0x81, 0x00, page); /* send cmd 0x81 */ -+ eccsteps = chip->ecc.steps >> 1; -+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { -+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); -+ chip->write_buf(mtd, p, eccsize); -+ chip->ecc.calculate(mtd, p, &ecc_calc[i]); -+ } -+ -+ for (i = 0; i < ecctotal; i++) -+ chip->oob_poi[eccpos[i]] = ecc_calc[i]; -+ -+ chip->write_buf(mtd, chip->oob_poi, oobsize); -+} -+ -+static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page) -+{ -+ struct nand_chip *chip = mtd->priv; -+ -+ /* Send commands to erase a block */ -+ int page; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x60, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x60, -1, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x60, -1, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ page += ppb; -+ chip->cmdfunc(mtd, 0x60, -1, page & (~(ppb-1))); /* send cmd 0x60 */ -+ -+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */ -+ /* Do not need wait R/B or check status */ -+} -+ -+/* -+ * Main initialization routine -+ */ -+int __init jznand_init(void) -+{ -+ struct nand_chip *this; -+ int nr_partitions, ret, i; -+ -+ /* Allocate memory for MTD device structure and private data */ -+ jz_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), -+ GFP_KERNEL); -+ if (!jz_mtd) { -+ printk ("Unable to allocate JzSOC NAND MTD device structure.\n"); -+ return -ENOMEM; -+ } -+ -+ jz_mtd1 = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), -+ GFP_KERNEL); -+ if (!jz_mtd1) { -+ printk ("Unable to allocate JzSOC NAND MTD device structure 1.\n"); -+ kfree(jz_mtd); -+ return -ENOMEM; -+ } -+ -+ /* Get pointer to private data */ -+ this = (struct nand_chip *) (&jz_mtd[1]); -+ -+ /* Initialize structures */ -+ memset((char *) jz_mtd, 0, sizeof(struct mtd_info)); -+ memset((char *) this, 0, sizeof(struct nand_chip)); -+ -+ /* Link the private data with the MTD structure */ -+ jz_mtd->priv = this; -+ -+ /* Set & initialize NAND Flash controller */ -+ jz_device_setup(); -+ -+ /* Set address of NAND IO lines */ -+ this->IO_ADDR_R = (void __iomem *) NAND_DATA_PORT1; -+ this->IO_ADDR_W = (void __iomem *) NAND_DATA_PORT1; -+ this->cmd_ctrl = jz_hwcontrol; -+ this->dev_ready = jz_device_ready; -+ -+#ifdef CONFIG_MTD_HW_HM_ECC -+ this->ecc.calculate = jzsoc_nand_calculate_hm_ecc; -+ this->ecc.correct = jzsoc_nand_hm_correct_data; -+ this->ecc.hwctl = jzsoc_nand_enable_hm_hwecc; -+ this->ecc.mode = NAND_ECC_HW; -+ this->ecc.size = 256; -+ this->ecc.bytes = 3; -+ -+#endif -+ -+#ifdef CONFIG_MTD_HW_RS_ECC -+ this->ecc.calculate = jzsoc_nand_calculate_rs_ecc; -+ this->ecc.correct = jzsoc_nand_rs_correct_data; -+ this->ecc.hwctl = jzsoc_nand_enable_rs_hwecc; -+ this->ecc.mode = NAND_ECC_HW; -+ this->ecc.size = 512; -+ this->ecc.bytes = 9; -+#endif -+ -+#ifdef CONFIG_MTD_SW_HM_ECC -+ this->ecc.mode = NAND_ECC_SOFT; -+#endif -+ /* 20 us command delay time */ -+ this->chip_delay = 20; -+ -+ dma_setup(); -+ -+ /* Scan to find existance of the device */ -+ ret = nand_scan_ident(jz_mtd, NAND_MAX_CHIPS); -+ if (!ret) { -+ if (this->planenum == 2) { -+ /* reset nand functions */ -+ this->erase_cmd = single_erase_cmd_planes; -+ this->ecc.read_page = nand_read_page_hwecc_rs_planes; //Muti planes read -+ this->ecc.write_page = nand_write_page_hwecc_planes; -+ this->ecc.read_oob = nand_read_oob_std_planes; -+ this->ecc.write_oob = nand_write_oob_std_planes; -+ this->write_buf = jz4740_nand_write_buf; -+ this->read_buf = jz4740_nand_read_buf; -+ -+ printk(KERN_INFO "Nand using two-plane mode, " -+ "and resized to writesize:%d oobsize:%d blocksize:0x%x \n", -+ jz_mtd->writesize, jz_mtd->oobsize, jz_mtd->erasesize); -+ } else -+ return -ENXIO; -+ } -+ -+ /* Determine whether all the partitions will use multiple planes if supported */ -+ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition); -+ all_use_planes = 1; -+ for (i = 0; i < nr_partitions; i++) { -+ all_use_planes &= partition_info[i].use_planes; -+ } -+ -+ if (!ret) -+ ret = nand_scan_tail(jz_mtd); -+ -+ if (ret){ -+ kfree (jz_mtd1); -+ kfree (jz_mtd); -+ return -ENXIO; -+ } -+ -+ /* Register the partitions */ -+ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name); -+ -+ if ((this->planenum == 2) && !all_use_planes) { -+ for (i = 0; i < nr_partitions; i++) { -+ if (partition_info[i].use_planes) -+ add_mtd_partitions(jz_mtd, &partition_info[i], 1); -+ else -+ add_mtd_partitions(jz_mtd1, &partition_info[i], 1); -+ } -+ } else { -+ kfree(jz_mtd1); -+ add_mtd_partitions(jz_mtd, partition_info, nr_partitions); -+ } -+ return 0; -+} -+module_init(jznand_init); -+ -+/* -+ * Clean up routine -+ */ -+#ifdef MODULE -+static void __exit jznand_cleanup(void) -+{ -+ struct nand_chip *this = (struct nand_chip *) &jz_mtd[1]; -+ -+ /* Unregister partitions */ -+ del_mtd_partitions(jz_mtd); -+ -+ /* Unregister the device */ -+ del_mtd_device (jz_mtd); -+ -+ /* Free internal data buffers */ -+ kfree (this->data_buf); -+ -+ /* Free the MTD device structure */ -+ if ((this->planenum == 2) && !all_use_planes) -+ kfree (jz_mtd1); -+ kfree (jz_mtd); -+} -+module_exit(jznand_cleanup); -+#endif ++/* ++ * linux/drivers/mtd/nand/jz4740_nand.c ++ * ++ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc. ++ * ++ * Ingenic JZ4740 NAND driver ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define NAND_DATA_PORT1 0xB8000000 /* read-write area in static bank 1 */ ++#define NAND_DATA_PORT2 0xB4000000 /* read-write area in static bank 2 */ ++#define NAND_DATA_PORT3 0xAC000000 /* read-write area in static bank 3 */ ++#define NAND_DATA_PORT4 0xA8000000 /* read-write area in static bank 4 */ ++ ++#define PAR_SIZE 9 ++ ++#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1) ++#define __nand_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1) ++ ++#define __nand_ecc_enable() (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST ) ++#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE) ++ ++#define __nand_select_hm_ecc() (REG_EMC_NFECR &= ~EMC_NFECR_RS ) ++#define __nand_select_rs_ecc() (REG_EMC_NFECR |= EMC_NFECR_RS) ++ ++#define __nand_read_hm_ecc() (REG_EMC_NFECC & 0x00ffffff) ++ ++#define __nand_rs_ecc_encoding() (REG_EMC_NFECR |= EMC_NFECR_RS_ENCODING) ++#define __nand_rs_ecc_decoding() (REG_EMC_NFECR &= ~EMC_NFECR_RS_ENCODING) ++#define __nand_ecc_encode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_ENCF)) ++#define __nand_ecc_decode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_DECF)) ++ ++/* ++ * MTD structure for JzSOC board ++ */ ++static struct mtd_info *jz_mtd = NULL; ++extern struct mtd_info *jz_mtd1; ++extern char all_use_planes; ++extern int global_page; /* for two-plane operations */ ++ ++/* ++ * Define partitions for flash devices ++ */ ++#ifdef CONFIG_JZ4740_PAVO ++static struct mtd_partition partition_info[] = { ++ { name: "NAND BOOT partition", ++ offset: 0 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0 }, ++ { name: "NAND KERNEL partition", ++ offset: 4 * 0x100000, ++ size: 4 * 0x100000, ++ use_planes: 0 }, ++ { name: "NAND ROOTFS partition", ++ offset: 8 * 0x100000, ++ size: 120 * 0x100000, ++ use_planes: 0 }, ++ { name: "NAND DATA1 partition", ++ offset: 128 * 0x100000, ++ size: 128 * 0x100000, ++ use_planes: 1 }, ++ { name: "NAND DATA2 partition", ++ offset: 256 * 0x100000, ++ size: 256 * 0x100000, ++ use_planes: 1 }, ++ { name: "NAND VFAT partition", ++ offset: 512 * 0x100000, ++ size: 512 * 0x100000, ++ use_planes: 1 }, ++}; ++ ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10, /* reserved blocks of mtd3 */ ++ 20, /* reserved blocks of mtd4 */ ++ 20}; /* reserved blocks of mtd5 */ ++#endif /* CONFIG_JZ4740_PAVO */ ++ ++#ifdef CONFIG_JZ4740_LEO ++static struct mtd_partition partition_info[] = { ++ { name: "NAND BOOT partition", ++ offset: 0 * 0x100000, ++ size: 4 * 0x100000 }, ++ { name: "NAND KERNEL partition", ++ offset: 4 * 0x100000, ++ size: 4 * 0x100000 }, ++ { name: "NAND ROOTFS partition", ++ offset: 8 * 0x100000, ++ size: 56 * 0x100000 }, ++ { name: "NAND VFAT partition", ++ offset: 64 * 0x100000, ++ size: 64 * 0x100000 }, ++}; ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10}; /* reserved blocks of mtd3 */ ++#endif /* CONFIG_JZ4740_LEO */ ++ ++#ifdef CONFIG_JZ4740_LYRA ++static struct mtd_partition partition_info[] = { ++ { name: "NAND BOOT partition", ++ offset: 0 * 0x100000, ++ size: 4 * 0x100000 }, ++ { name: "NAND KERNEL partition", ++ offset: 4 * 0x100000, ++ size: 4 * 0x100000 }, ++ { name: "NAND ROOTFS partition", ++ offset: 8 * 0x100000, ++ size: 120 * 0x100000 }, ++ { name: "NAND DATA1 partition", ++ offset: 128 * 0x100000, ++ size: 128 * 0x100000 }, ++ { name: "NAND DATA2 partition", ++ offset: 256 * 0x100000, ++ size: 256 * 0x100000 }, ++ { name: "NAND VFAT partition", ++ offset: 512 * 0x100000, ++ size: 512 * 0x100000 }, ++}; ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10, /* reserved blocks of mtd3 */ ++ 20, /* reserved blocks of mtd4 */ ++ 20}; /* reserved blocks of mtd5 */ ++#endif /* CONFIG_JZ4740_LYRA */ ++ ++#ifdef CONFIG_JZ4725_DIPPER ++static struct mtd_partition partition_info[] = { ++ { name: "NAND BOOT partition", ++ offset: 0 * 0x100000, ++ size: 4 * 0x100000 }, ++ { name: "NAND KERNEL partition", ++ offset: 4 * 0x100000, ++ size: 4 * 0x100000 }, ++ { name: "NAND ROOTFS partition", ++ offset: 8 * 0x100000, ++ size: 56 * 0x100000 }, ++ { name: "NAND VFAT partition", ++ offset: 64 * 0x100000, ++ size: 64 * 0x100000 }, ++}; ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10}; /* reserved blocks of mtd3 */ ++#endif /* CONFIG_JZ4740_DIPPER */ ++ ++#ifdef CONFIG_JZ4720_VIRGO ++static struct mtd_partition partition_info[] = { ++ { name: "NAND BOOT partition", ++ offset: 0 * 0x100000, ++ size: 4 * 0x100000 }, ++ { name: "NAND KERNEL partition", ++ offset: 4 * 0x100000, ++ size: 4 * 0x100000 }, ++ { name: "NAND ROOTFS partition", ++ offset: 8 * 0x100000, ++ size: 120 * 0x100000 }, ++ { name: "NAND DATA1 partition", ++ offset: 128 * 0x100000, ++ size: 128 * 0x100000 }, ++ { name: "NAND DATA2 partition", ++ offset: 256 * 0x100000, ++ size: 256 * 0x100000 }, ++ { name: "NAND VFAT partition", ++ offset: 512 * 0x100000, ++ size: 512 * 0x100000 }, ++}; ++ ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10, /* reserved blocks of mtd3 */ ++ 20, /* reserved blocks of mtd4 */ ++ 20}; /* reserved blocks of mtd5 */ ++#endif /* CONFIG_JZ4720_VIRGO */ ++/*------------------------------------------------------------------------- ++ * Following three functions are exported and used by the mtdblock-jz.c ++ * NAND FTL driver only. ++ */ ++ ++unsigned short get_mtdblock_write_verify_enable(void) ++{ ++#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE ++ return 1; ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(get_mtdblock_write_verify_enable); ++ ++unsigned short get_mtdblock_oob_copies(void) ++{ ++ return CONFIG_MTD_OOB_COPIES; ++} ++EXPORT_SYMBOL(get_mtdblock_oob_copies); ++ ++int *get_jz_badblock_table(void) ++{ ++ return partition_reserved_badblocks; ++} ++EXPORT_SYMBOL(get_jz_badblock_table); ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void jz_hwcontrol(struct mtd_info *mtd, int dat, ++ unsigned int ctrl) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ unsigned int nandaddr = (unsigned int)this->IO_ADDR_W; ++ extern u8 nand_nce; /* in nand_base.c, indicates which chip select is used for current nand chip */ ++ ++ if (ctrl & NAND_CTRL_CHANGE) { ++ if (ctrl & NAND_NCE) { ++ switch (nand_nce) { ++ case NAND_NCE1: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE1; ++ break; ++ case NAND_NCE2: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE2; ++ break; ++ case NAND_NCE3: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE3; ++ break; ++ case NAND_NCE4: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT4; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE4; ++ break; ++ default: ++ printk("error: no nand_nce 0x%x\n",nand_nce); ++ break; ++ } ++ } else { ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ } ++ ++ if ( ctrl & NAND_ALE ) ++ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) | 0x00010000); ++ else ++ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) & ~0x00010000); ++ ++ if ( ctrl & NAND_CLE ) ++ nandaddr = nandaddr | 0x00008000; ++ else ++ nandaddr = nandaddr & ~0x00008000; ++ } ++ ++ this->IO_ADDR_W = (void __iomem *)nandaddr; ++ if (dat != NAND_CMD_NONE) ++ writeb(dat, this->IO_ADDR_W); ++} ++ ++static int jz_device_ready(struct mtd_info *mtd) ++{ ++ int ready, wait = 10; ++ while (wait--); ++ ready = __gpio_get_pin(94); ++ return ready; ++} ++ ++/* ++ * EMC setup ++ */ ++static void jz_device_setup(void) ++{ ++// PORT 0: ++// ... ++// PORT 1: ++// PIN/BIT N FUNC0 FUNC1 ++// 25 CS1# - ++// 26 CS2# - ++// 27 CS3# - ++// 28 CS4# - ++#define GPIO_CS2_N (32+26) ++#define GPIO_CS3_N (32+27) ++#define GPIO_CS4_N (32+28) ++#define SMCR_VAL 0x0d221200 ++ ++ /* Set NFE bit */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE1; ++ /* Read/Write timings */ ++ REG_EMC_SMCR1 = SMCR_VAL; ++ ++#if defined(CONFIG_MTD_NAND_CS2) ++ /* Set CS2# pin as function 0 */ ++ __gpio_as_func0(GPIO_CS2_N); ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE2; ++ REG_EMC_SMCR2 = SMCR_VAL; ++#endif ++ ++#if defined(CONFIG_MTD_NAND_CS3) ++ __gpio_as_func0(GPIO_CS3_N); ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE3; ++ REG_EMC_SMCR3 = SMCR_VAL; ++#endif ++ ++#if defined(CONFIG_MTD_NAND_CS4) ++ __gpio_as_func0(GPIO_CS4_N); ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE4; ++ REG_EMC_SMCR4 = SMCR_VAL; ++#endif ++} ++ ++#ifdef CONFIG_MTD_HW_HM_ECC ++ ++static int jzsoc_nand_calculate_hm_ecc(struct mtd_info* mtd, ++ const u_char* dat, u_char* ecc_code) ++{ ++ unsigned int calc_ecc; ++ unsigned char *tmp; ++ ++ __nand_ecc_disable(); ++ ++ calc_ecc = ~(__nand_read_hm_ecc()) | 0x00030000; ++ ++ tmp = (unsigned char *)&calc_ecc; ++ //adjust eccbytes order for compatible with software ecc ++ ecc_code[0] = tmp[1]; ++ ecc_code[1] = tmp[0]; ++ ecc_code[2] = tmp[2]; ++ ++ return 0; ++} ++ ++static void jzsoc_nand_enable_hm_hwecc(struct mtd_info* mtd, int mode) ++{ ++ __nand_ecc_enable(); ++ __nand_select_hm_ecc(); ++} ++ ++static int jzsoc_nand_hm_correct_data(struct mtd_info *mtd, u_char *dat, ++ u_char *read_ecc, u_char *calc_ecc) ++{ ++ u_char a, b, c, d1, d2, d3, add, bit, i; ++ ++ /* Do error detection */ ++ d1 = calc_ecc[0] ^ read_ecc[0]; ++ d2 = calc_ecc[1] ^ read_ecc[1]; ++ d3 = calc_ecc[2] ^ read_ecc[2]; ++ ++ if ((d1 | d2 | d3) == 0) { ++ /* No errors */ ++ return 0; ++ } ++ else { ++ a = (d1 ^ (d1 >> 1)) & 0x55; ++ b = (d2 ^ (d2 >> 1)) & 0x55; ++ c = (d3 ^ (d3 >> 1)) & 0x54; ++ ++ /* Found and will correct single bit error in the data */ ++ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { ++ c = 0x80; ++ add = 0; ++ a = 0x80; ++ for (i=0; i<4; i++) { ++ if (d1 & c) ++ add |= a; ++ c >>= 2; ++ a >>= 1; ++ } ++ c = 0x80; ++ for (i=0; i<4; i++) { ++ if (d2 & c) ++ add |= a; ++ c >>= 2; ++ a >>= 1; ++ } ++ bit = 0; ++ b = 0x04; ++ c = 0x80; ++ for (i=0; i<3; i++) { ++ if (d3 & c) ++ bit |= b; ++ c >>= 2; ++ b >>= 1; ++ } ++ b = 0x01; ++ a = dat[add]; ++ a ^= (b << bit); ++ dat[add] = a; ++ return 0; ++ } ++ else { ++ i = 0; ++ while (d1) { ++ if (d1 & 0x01) ++ ++i; ++ d1 >>= 1; ++ } ++ while (d2) { ++ if (d2 & 0x01) ++ ++i; ++ d2 >>= 1; ++ } ++ while (d3) { ++ if (d3 & 0x01) ++ ++i; ++ d3 >>= 1; ++ } ++ if (i == 1) { ++ /* ECC Code Error Correction */ ++ read_ecc[0] = calc_ecc[0]; ++ read_ecc[1] = calc_ecc[1]; ++ read_ecc[2] = calc_ecc[2]; ++ return 0; ++ } ++ else { ++ /* Uncorrectable Error */ ++ printk("NAND: uncorrectable ECC error\n"); ++ return -1; ++ } ++ } ++ } ++ ++ /* Should never happen */ ++ return -1; ++} ++ ++#endif /* CONFIG_MTD_HW_HM_ECC */ ++ ++#ifdef CONFIG_MTD_HW_RS_ECC ++ ++static void jzsoc_nand_enable_rs_hwecc(struct mtd_info* mtd, int mode) ++{ ++ REG_EMC_NFINTS = 0x0; ++ __nand_ecc_enable(); ++ __nand_select_rs_ecc(); ++ ++ if (mode == NAND_ECC_READ) ++ __nand_rs_ecc_decoding(); ++ ++ if (mode == NAND_ECC_WRITE) ++ __nand_rs_ecc_encoding(); ++} ++ ++static void jzsoc_rs_correct(unsigned char *dat, int idx, int mask) ++{ ++ int i; ++ ++ idx--; ++ ++ i = idx + (idx >> 3); ++ if (i >= 512) ++ return; ++ ++ mask <<= (idx & 0x7); ++ ++ dat[i] ^= mask & 0xff; ++ if (i < 511) ++ dat[i+1] ^= (mask >> 8) & 0xff; ++} ++ ++/* ++ * calc_ecc points to oob_buf for us ++ */ ++static int jzsoc_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat, ++ u_char *read_ecc, u_char *calc_ecc) ++{ ++ volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0; ++ short k; ++ u32 stat; ++ ++ /* Set PAR values */ ++ for (k = 0; k < PAR_SIZE; k++) { ++ *paraddr++ = read_ecc[k]; ++ } ++ ++ /* Set PRDY */ ++ REG_EMC_NFECR |= EMC_NFECR_PRDY; ++ ++ /* Wait for completion */ ++ __nand_ecc_decode_sync(); ++ __nand_ecc_disable(); ++ ++ /* Check decoding */ ++ stat = REG_EMC_NFINTS; ++ ++ if (stat & EMC_NFINTS_ERR) { ++ /* Error occurred */ ++ if (stat & EMC_NFINTS_UNCOR) { ++ printk("NAND: Uncorrectable ECC error\n"); ++ return -1; ++ } else { ++ u32 errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT; ++ switch (errcnt) { ++ case 4: ++ jzsoc_rs_correct(dat, (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); ++ /* FALL-THROUGH */ ++ case 3: ++ jzsoc_rs_correct(dat, (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); ++ /* FALL-THROUGH */ ++ case 2: ++ jzsoc_rs_correct(dat, (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); ++ /* FALL-THROUGH */ ++ case 1: ++ jzsoc_rs_correct(dat, (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); ++ return 0; ++ default: ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int jzsoc_nand_calculate_rs_ecc(struct mtd_info* mtd, const u_char* dat, ++ u_char* ecc_code) ++{ ++ volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0; ++ short i; ++ ++ __nand_ecc_encode_sync(); ++ __nand_ecc_disable(); ++ ++ for(i = 0; i < PAR_SIZE; i++) { ++ ecc_code[i] = *paraddr++; ++ } ++ ++ return 0; ++} ++ ++#endif /* CONFIG_MTD_HW_RS_ECC */ ++ ++/* Nand optimized functions */ ++static int dma_chan; ++static unsigned int dma_src_phys_addr, dma_dst_phys_addr; ++extern int jz_request_dma(int dev_id, const char *dev_str, ++ irqreturn_t (*irqhandler)(int, void *), ++ unsigned long irqflags, void *irq_dev_id); ++ ++static void dma_setup(void) ++{ ++ /* Request DMA channel and setup irq handler */ ++ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", NULL, IRQF_DISABLED, NULL); ++ if (dma_chan < 0) { ++ printk("Setup irq for nand failed!\n"); ++ return; ++ } else ++ printk("Nand DMA request channel %d.\n",dma_chan); ++} ++ ++static void jz4740_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) ++{ ++ int i; ++ struct nand_chip *chip = mtd->priv; ++ ++ if ((len <= 32) || (len & 0xf) || ((u32)buf >= (u32)high_memory)) ++ { ++ for (i = 0; i < len; i++) ++ buf[i] = readb(chip->IO_ADDR_R); ++ } else { ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; ++ dma_src_phys_addr = CPHYSADDR(chip->IO_ADDR_R); ++ dma_dst_phys_addr = CPHYSADDR(buf); ++ dma_cache_inv((u32)buf, len); ++ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; ++ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; ++ REG_DMAC_DTCR(dma_chan) = len / 16; ++ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE; ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; ++ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */ ++ ++ while(!(REG_DMAC_DCCSR(dma_chan) & DMAC_DCCSR_TT)); ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ __dmac_channel_clear_transmit_end(dma_chan); ++ } ++} ++ ++static void jz4740_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) ++{ ++ int i; ++ struct nand_chip *chip = mtd->priv; ++ ++ if ((len <= 32) || (len & 0xf) || ((u32)buf >= (u32)high_memory)) ++ { ++ for (i = 0; i < len; i++) ++ writeb(buf[i], chip->IO_ADDR_W); ++ } else { ++ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; ++ dma_dst_phys_addr = CPHYSADDR(chip->IO_ADDR_R); ++ dma_src_phys_addr = CPHYSADDR(buf); ++ dma_cache_wback((unsigned long)buf, len); ++ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; ++ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; ++ REG_DMAC_DTCR(dma_chan) = len / 16; ++ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_16BYTE ; ++ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; ++ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */ ++ ++ while(!(REG_DMAC_DCCSR(dma_chan) & DMAC_DCCSR_TT)); ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ __dmac_channel_clear_transmit_end(dma_chan); ++ } ++} ++ ++static int nand_read_page_hwecc_rs_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ uint8_t *buf) ++{ ++ int i, eccsize = chip->ecc.size; ++ int eccbytes = chip->ecc.bytes; ++ int eccsteps = chip->ecc.steps >> 1; ++ uint8_t *p; ++ uint8_t *ecc_calc = chip->buffers->ecccalc; ++ uint8_t *ecc_code = chip->buffers->ecccode; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ uint32_t page; ++ uint8_t flag = 0; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ int ecctotal = chip->ecc.total >> 1; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* Read first page */ ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ chip->read_buf(mtd, chip->oob_poi, oobsize); ++ for (i = 0; i < ecctotal; i++) { ++ ecc_code[i] = chip->oob_poi[eccpos[i]]; ++ if (ecc_code[i] != 0xff) flag = 1; ++ } ++ ++ p = buf; ++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1); ++ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { ++ int stat; ++ if (flag) { ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ chip->read_buf(mtd, p, eccsize); ++ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); ++ if (stat < 0) ++ mtd->ecc_stats.failed++; ++ else ++ mtd->ecc_stats.corrected += stat; ++ } ++ else { ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ chip->read_buf(mtd, p, eccsize); ++ } ++ } ++ /* Read second page */ ++ page += ppb; ++ flag = 0; ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ chip->read_buf(mtd, chip->oob_poi + oobsize, oobsize); ++ for (i = 0; i < ecctotal; i++) { ++ ecc_code[i] = chip->oob_poi[oobsize + eccpos[i]]; ++ if (ecc_code[i] != 0xff) flag = 1; ++ } ++ ++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1); ++ eccsteps = chip->ecc.steps >> 1; ++ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { ++ int stat; ++ if (flag) { ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ chip->read_buf(mtd, p, eccsize); ++ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); ++ if (stat < 0) ++ mtd->ecc_stats.failed++; ++ else ++ mtd->ecc_stats.corrected += stat; ++ } ++ else { ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ chip->read_buf(mtd, p, eccsize); ++ } ++ } ++ ++ return 0; ++} ++ ++static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ int global_page, int sndcmd) ++{ ++ int page; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* Read first page OOB */ ++ if (sndcmd) { ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ } ++ chip->read_buf(mtd, chip->oob_poi, oobsize); ++ /* Read second page OOB */ ++ page += ppb; ++ if (sndcmd) { ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ sndcmd = 0; ++ } ++ chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize); ++ return 0; ++} ++ ++static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ int global_page) ++{ ++ int status = 0,page; ++ int pagesize = mtd->writesize >> 1; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ const uint8_t *buf = chip->oob_poi; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x80, pagesize, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ chip->write_buf(mtd, buf, oobsize); ++ /* Send first command to program the OOB data */ ++ chip->cmdfunc(mtd, 0x11, -1, -1); ++ ndelay(100); ++ status = chip->waitfunc(mtd, chip); ++ ++ page += ppb; ++ buf += oobsize; ++ chip->cmdfunc(mtd, 0x81, pagesize, page); ++ chip->write_buf(mtd, buf, oobsize); ++ /* Send command to program the OOB data */ ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++ /* Wait long R/B */ ++ ndelay(100); ++ status = chip->waitfunc(mtd, chip); ++ ++ return status & NAND_STATUS_FAIL ? -EIO : 0; ++} ++ ++static void nand_write_page_hwecc_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ const uint8_t *buf) ++{ ++ int i, eccsize = chip->ecc.size; ++ int eccbytes = chip->ecc.bytes; ++ int eccsteps = chip->ecc.steps >> 1; ++ uint8_t *ecc_calc = chip->buffers->ecccalc; ++ uint8_t *p = (uint8_t *)buf; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ int ecctotal = chip->ecc.total >> 1; ++ int page; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { ++ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); ++ chip->write_buf(mtd, p, eccsize); ++ chip->ecc.calculate(mtd, p, &ecc_calc[i]); ++ } ++ for (i = 0; i < ecctotal; i++) ++ chip->oob_poi[eccpos[i]] = ecc_calc[i]; ++ ++ chip->write_buf(mtd, chip->oob_poi, oobsize); ++ ++ chip->cmdfunc(mtd, 0x11, -1, -1); /* send cmd 0x11 */ ++ ndelay(100); ++ while(!chip->dev_ready(mtd)); ++ ++ page += ppb; ++ chip->cmdfunc(mtd, 0x81, 0x00, page); /* send cmd 0x81 */ ++ eccsteps = chip->ecc.steps >> 1; ++ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { ++ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); ++ chip->write_buf(mtd, p, eccsize); ++ chip->ecc.calculate(mtd, p, &ecc_calc[i]); ++ } ++ ++ for (i = 0; i < ecctotal; i++) ++ chip->oob_poi[eccpos[i]] = ecc_calc[i]; ++ ++ chip->write_buf(mtd, chip->oob_poi, oobsize); ++} ++ ++static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page) ++{ ++ struct nand_chip *chip = mtd->priv; ++ ++ /* Send commands to erase a block */ ++ int page; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x60, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x60, -1, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x60, -1, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ page += ppb; ++ chip->cmdfunc(mtd, 0x60, -1, page & (~(ppb-1))); /* send cmd 0x60 */ ++ ++ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */ ++ /* Do not need wait R/B or check status */ ++} ++ ++/* ++ * Main initialization routine ++ */ ++int __init jznand_init(void) ++{ ++ struct nand_chip *this; ++ int nr_partitions, ret, i; ++ ++ /* Allocate memory for MTD device structure and private data */ ++ jz_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), ++ GFP_KERNEL); ++ if (!jz_mtd) { ++ printk ("Unable to allocate JzSOC NAND MTD device structure.\n"); ++ return -ENOMEM; ++ } ++ ++ jz_mtd1 = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), ++ GFP_KERNEL); ++ if (!jz_mtd1) { ++ printk ("Unable to allocate JzSOC NAND MTD device structure 1.\n"); ++ kfree(jz_mtd); ++ return -ENOMEM; ++ } ++ ++ /* Get pointer to private data */ ++ this = (struct nand_chip *) (&jz_mtd[1]); ++ ++ /* Initialize structures */ ++ memset((char *) jz_mtd, 0, sizeof(struct mtd_info)); ++ memset((char *) this, 0, sizeof(struct nand_chip)); ++ ++ /* Link the private data with the MTD structure */ ++ jz_mtd->priv = this; ++ ++ /* Set & initialize NAND Flash controller */ ++ jz_device_setup(); ++ ++ /* Set address of NAND IO lines */ ++ this->IO_ADDR_R = (void __iomem *) NAND_DATA_PORT1; ++ this->IO_ADDR_W = (void __iomem *) NAND_DATA_PORT1; ++ this->cmd_ctrl = jz_hwcontrol; ++ this->dev_ready = jz_device_ready; ++ ++#ifdef CONFIG_MTD_HW_HM_ECC ++ this->ecc.calculate = jzsoc_nand_calculate_hm_ecc; ++ this->ecc.correct = jzsoc_nand_hm_correct_data; ++ this->ecc.hwctl = jzsoc_nand_enable_hm_hwecc; ++ this->ecc.mode = NAND_ECC_HW; ++ this->ecc.size = 256; ++ this->ecc.bytes = 3; ++ ++#endif ++ ++#ifdef CONFIG_MTD_HW_RS_ECC ++ this->ecc.calculate = jzsoc_nand_calculate_rs_ecc; ++ this->ecc.correct = jzsoc_nand_rs_correct_data; ++ this->ecc.hwctl = jzsoc_nand_enable_rs_hwecc; ++ this->ecc.mode = NAND_ECC_HW; ++ this->ecc.size = 512; ++ this->ecc.bytes = 9; ++#endif ++ ++#ifdef CONFIG_MTD_SW_HM_ECC ++ this->ecc.mode = NAND_ECC_SOFT; ++#endif ++ /* 20 us command delay time */ ++ this->chip_delay = 20; ++ ++ dma_setup(); ++ ++ /* Scan to find existance of the device */ ++ ret = nand_scan_ident(jz_mtd, NAND_MAX_CHIPS); ++ if (!ret) { ++ if (this->planenum == 2) { ++ /* reset nand functions */ ++ this->erase_cmd = single_erase_cmd_planes; ++ this->ecc.read_page = nand_read_page_hwecc_rs_planes; //Muti planes read ++ this->ecc.write_page = nand_write_page_hwecc_planes; ++ this->ecc.read_oob = nand_read_oob_std_planes; ++ this->ecc.write_oob = nand_write_oob_std_planes; ++ this->write_buf = jz4740_nand_write_buf; ++ this->read_buf = jz4740_nand_read_buf; ++ ++ printk(KERN_INFO "Nand using two-plane mode, " ++ "and resized to writesize:%d oobsize:%d blocksize:0x%x \n", ++ jz_mtd->writesize, jz_mtd->oobsize, jz_mtd->erasesize); ++ } else ++ return -ENXIO; ++ } ++ ++ /* Determine whether all the partitions will use multiple planes if supported */ ++ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition); ++ all_use_planes = 1; ++ for (i = 0; i < nr_partitions; i++) { ++ all_use_planes &= partition_info[i].use_planes; ++ } ++ ++ if (!ret) ++ ret = nand_scan_tail(jz_mtd); ++ ++ if (ret){ ++ kfree (jz_mtd1); ++ kfree (jz_mtd); ++ return -ENXIO; ++ } ++ ++ /* Register the partitions */ ++ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name); ++ ++ if ((this->planenum == 2) && !all_use_planes) { ++ for (i = 0; i < nr_partitions; i++) { ++ if (partition_info[i].use_planes) ++ add_mtd_partitions(jz_mtd, &partition_info[i], 1); ++ else ++ add_mtd_partitions(jz_mtd1, &partition_info[i], 1); ++ } ++ } else { ++ kfree(jz_mtd1); ++ add_mtd_partitions(jz_mtd, partition_info, nr_partitions); ++ } ++ return 0; ++} ++module_init(jznand_init); ++ ++/* ++ * Clean up routine ++ */ ++#ifdef MODULE ++static void __exit jznand_cleanup(void) ++{ ++ struct nand_chip *this = (struct nand_chip *) &jz_mtd[1]; ++ ++ /* Unregister partitions */ ++ del_mtd_partitions(jz_mtd); ++ ++ /* Unregister the device */ ++ del_mtd_device (jz_mtd); ++ ++ /* Free internal data buffers */ ++ kfree (this->data_buf); ++ ++ /* Free the MTD device structure */ ++ if ((this->planenum == 2) && !all_use_planes) ++ kfree (jz_mtd1); ++ kfree (jz_mtd); ++} ++module_exit(jznand_cleanup); ++#endif --- linux-2.6.24.7.old/drivers/mtd/nand/jz4750_nand.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/drivers/mtd/nand/jz4750_nand.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,1746 @@ -+/* -+ * linux/drivers/mtd/nand/jz4750_nand.c -+ * -+ * JZ4750 NAND driver -+ * -+ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* 32bit instead of 16byte burst is used by DMA to read or -+ write NAND and BCH avoiding grabbing bus for too long */ -+#define DMAC_DCMD_DS_NAND DMAC_DCMD_DS_32BIT -+#define DIV_DS_NAND 4 -+ -+#define DMAC_DCMD_DS_BCH DMAC_DCMD_DS_32BIT -+#define DIV_DS_BCH 4 -+ -+#define DEBUG1 0 -+#if DEBUG1 -+#define dprintk(n,x...) printk(n,##x) -+#else -+#define dprintk(n,x...) -+#endif -+ -+#if defined(CONFIG_MTD_HW_BCH_8BIT) -+#define __ECC_ENCODING __ecc_encoding_8bit -+#define __ECC_DECODING __ecc_decoding_8bit -+#define ERRS_SIZE 5 /* 5 words */ -+#else -+#define __ECC_ENCODING __ecc_encoding_4bit -+#define __ECC_DECODING __ecc_decoding_4bit -+#define ERRS_SIZE 3 /* 3 words */ -+#endif -+ -+#define NAND_DATA_PORT1 0xB8000000 /* read-write area in static bank 1 */ -+#define NAND_DATA_PORT2 0xB4000000 /* read-write area in static bank 2 */ -+#define NAND_DATA_PORT3 0xAC000000 /* read-write area in static bank 3 */ -+#define NAND_DATA_PORT4 0xA8000000 /* read-write area in static bank 4 */ -+ -+#define NAND_ADDR_OFFSET0 0x00010000 /* address port offset for share mode */ -+#define NAND_CMD_OFFSET0 0x00008000 /* command port offset for share mode */ -+#define NAND_ADDR_OFFSET1 0x00000010 /* address port offset for unshare mode */ -+#define NAND_CMD_OFFSET1 0x00000008 /* command port offset for unshare mode */ -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+#define USE_IRQ 1 -+enum { -+ NAND_NONE, -+ NAND_PROG, -+ NAND_READ -+}; -+static volatile u8 nand_status; -+static volatile int dma_ack = 0; -+static volatile int dma_ack1 = 0; -+static char nand_dma_chan; /* automatically select a free channel */ -+static char bch_dma_chan = 0; /* fixed to channel 0 */ -+static u32 *errs; -+static jz_dma_desc_8word *dma_desc_enc, *dma_desc_enc1, *dma_desc_dec, *dma_desc_dec1, *dma_desc_dec2, -+ *dma_desc_nand_prog, *dma_desc_nand_read; -+static u32 *pval_nand_ddr; -+static u8 *pval_nand_cmd_pgprog; /* for sending 0x11 or 0x10 when programing*/ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+u8 *prog_buf, *read_buf; -+#endif -+DECLARE_WAIT_QUEUE_HEAD(nand_prog_wait_queue); -+DECLARE_WAIT_QUEUE_HEAD(nand_read_wait_queue); -+#endif -+ -+struct buf_be_corrected { -+ u8 *data; -+ u8 *oob; -+}; -+ -+static u32 addr_offset; -+static u32 cmd_offset; -+ -+extern int global_page; /* for two-plane operations */ -+ -+/* -+ * MTD structure for JzSOC board -+ */ -+static struct mtd_info *jz_mtd = NULL; -+extern struct mtd_info *jz_mtd1; -+extern char all_use_planes; -+ -+/* -+ * Define partitions for flash devices -+ */ -+#if defined(CONFIG_JZ4750_FUWA) || defined(CONFIG_JZ4750D_FUWA1) -+static struct mtd_partition partition_info[] = { -+ {name:"NAND BOOT partition", -+ offset:0 * 0x100000, -+ size:4 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND KERNEL partition", -+ offset:4 * 0x100000, -+ size:4 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND ROOTFS partition", -+ offset:8 * 0x100000, -+ size:120 * 0x100000, -+ use_planes: 1}, -+ {name:"NAND DATA1 partition", -+ offset:128 * 0x100000, -+ size:128 * 0x100000, -+ use_planes: 1}, -+ {name:"NAND DATA2 partition", -+ offset:256 * 0x100000, -+ size:256 * 0x100000, -+ use_planes: 1}, -+ {name:"NAND VFAT partition", -+ offset:512 * 0x100000, -+ size:512 * 0x100000, -+ use_planes: 1}, -+}; -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10, /* reserved blocks of mtd3 */ -+ 20, /* reserved blocks of mtd4 */ -+ 20 -+}; /* reserved blocks of mtd5 */ -+#endif /* CONFIG_JZ4750_FUWA or CONFIG_JZ4750_APUS */ -+ -+#if defined(CONFIG_JZ4750_APUS) -+static struct mtd_partition partition_info[] = { -+ {name:"NAND BOOT partition", -+ offset:0 * 0x100000, -+ size:4 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND KERNEL partition", -+ offset:4 * 0x100000, -+ size:4 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND ROOTFS partition", -+ offset:8 * 0x100000, -+ size:504 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND VFAT partition", -+ offset:512 * 0x100000, -+ size:512 * 0x100000, -+ use_planes: 1}, -+}; -+ -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10, /* reserved blocks of mtd3 */ -+}; -+#endif /* CONFIG_JZ4750_FUWA or CONFIG_JZ4750_APUS */ -+ -+/*------------------------------------------------------------------------- -+ * Following three functions are exported and used by the mtdblock-jz.c -+ * NAND FTL driver only. -+ */ -+ -+unsigned short get_mtdblock_write_verify_enable(void) -+{ -+#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE -+ return 1; -+#endif -+ return 0; -+} -+ -+EXPORT_SYMBOL(get_mtdblock_write_verify_enable); -+ -+unsigned short get_mtdblock_oob_copies(void) -+{ -+ return CONFIG_MTD_OOB_COPIES; -+} -+ -+EXPORT_SYMBOL(get_mtdblock_oob_copies); -+ -+int *get_jz_badblock_table(void) -+{ -+ return partition_reserved_badblocks; -+} -+ -+EXPORT_SYMBOL(get_jz_badblock_table); -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void jz_hwcontrol(struct mtd_info *mtd, int dat, u32 ctrl) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ u32 nandaddr = (u32)this->IO_ADDR_W; -+ extern u8 nand_nce; /* defined in nand_base.c, indicates which chip select is used for current nand chip */ -+ -+ if (ctrl & NAND_CTRL_CHANGE) { -+ if (ctrl & NAND_NCE) { -+ switch (nand_nce) { -+ case NAND_NCE1: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE1; -+ break; -+ case NAND_NCE2: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE2; -+ break; -+ case NAND_NCE3: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE3; -+ break; -+ case NAND_NCE4: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT4; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE4; -+ break; -+ default: -+ printk("error: no nand_nce 0x%x\n",nand_nce); -+ break; -+ } -+ } else { -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ } -+ -+ if (ctrl & NAND_ALE) -+ nandaddr = (u32)((u32)(this->IO_ADDR_W) | addr_offset); -+ else -+ nandaddr = (u32)((u32)(this->IO_ADDR_W) & ~addr_offset); -+ if (ctrl & NAND_CLE) -+ nandaddr = (u32)(nandaddr | cmd_offset); -+ else -+ nandaddr = (u32)(nandaddr & ~cmd_offset); -+ } -+ -+ this->IO_ADDR_W = (void __iomem *)nandaddr; -+ if (dat != NAND_CMD_NONE) { -+ writeb(dat, this->IO_ADDR_W); -+ /* printk("write cmd:0x%x to 0x%x\n",dat,(u32)this->IO_ADDR_W); */ -+ } -+} -+ -+static int jz_device_ready(struct mtd_info *mtd) -+{ -+ int ready, wait = 10; -+ while (wait--); -+ ready = __gpio_get_pin(91); -+ return ready; -+} -+ -+/* -+ * EMC setup -+ */ -+static void jz_device_setup(void) -+{ -+// PORT 0: -+// PORT 1: -+// PORT 2: -+// PIN/BIT N FUNC0 FUNC1 -+// 21 CS1# - -+// 22 CS2# - -+// 23 CS3# - -+// 24 CS4# - -+#define GPIO_CS2_N (32*2+22) -+#define GPIO_CS3_N (32*2+23) -+#define GPIO_CS4_N (32*2+24) -+#define SMCR_VAL 0x0d444400 -+ -+ __gpio_as_nand_8bit(1); -+ /* Set NFE bit */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE1; -+ /* Read/Write timings */ -+ REG_EMC_SMCR1 = SMCR_VAL; -+ -+#if defined(CONFIG_MTD_NAND_CS2) -+ __gpio_as_func0(GPIO_CS2_N); -+ /* Set NFE bit */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE2; -+ /* Read/Write timings */ -+ REG_EMC_SMCR2 = SMCR_VAL; -+#endif -+ -+#if defined(CONFIG_MTD_NAND_CS3) -+ __gpio_as_func0(GPIO_CS3_N); -+ /* Set NFE bit */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE3; -+ /* Read/Write timings */ -+ REG_EMC_SMCR3 = SMCR_VAL; -+#endif -+ -+#if defined(CONFIG_MTD_NAND_CS4) -+ __gpio_as_func0(GPIO_CS4_N); -+ /* Set NFE bit */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE4; -+ /* Read/Write timings */ -+ REG_EMC_SMCR4 = SMCR_VAL; -+#endif -+} -+ -+#ifdef CONFIG_MTD_HW_BCH_ECC -+ -+static void jzsoc_nand_enable_bch_hwecc(struct mtd_info *mtd, int mode) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ int eccsize = this->ecc.size; -+ int eccbytes = this->ecc.bytes; -+ int eccsteps = this->ecc.steps / this->planenum; -+ int oob_per_eccsize = this->ecc.layout->eccpos[0] / eccsteps; -+ -+ REG_BCH_INTS = 0xffffffff; -+ if (mode == NAND_ECC_READ) { -+ __ECC_DECODING(); -+ __ecc_cnt_dec(eccsize + oob_per_eccsize + eccbytes); -+#if defined(CONFIG_MTD_NAND_DMA) -+ __ecc_dma_enable(); -+#endif -+ } -+ -+ if (mode == NAND_ECC_WRITE) { -+ __ECC_ENCODING(); -+ __ecc_cnt_enc(eccsize + oob_per_eccsize); -+#if defined(CONFIG_MTD_NAND_DMA) -+ __ecc_dma_enable(); -+#endif -+ } -+} -+ -+/** -+ * bch_correct -+ * @dat: data to be corrected -+ * @idx: the index of error bit in an eccsize -+ */ -+static void bch_correct(struct mtd_info *mtd, u8 * dat, int idx) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ int eccsize = this->ecc.size; -+ int eccsteps = this->ecc.steps / this->planenum; -+ int ecc_pos = this->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ int i, bit; /* the 'bit' of i byte is error */ -+ -+ i = (idx - 1) >> 3; -+ bit = (idx - 1) & 0x7; -+ -+ dprintk("error:i=%d, bit=%d\n",i,bit); -+ -+ if (i < eccsize){ -+ ((struct buf_be_corrected *)dat)->data[i] ^= (1 << bit); -+ } else if (i < eccsize + oob_per_eccsize) { -+ ((struct buf_be_corrected *)dat)->oob[i-eccsize] ^= (1 << bit); -+ } -+} -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+ -+/** -+ * jzsoc_nand_bch_correct_data -+ * @mtd: mtd info structure -+ * @dat: data to be corrected -+ * @errs0: pointer to the dma target buffer of bch decoding which stores BHINTS and -+ * BHERR0~3(8-bit BCH) or BHERR0~1(4-bit BCH) -+ * @calc_ecc: no used -+ */ -+static int jzsoc_nand_bch_correct_data(struct mtd_info *mtd, u_char * dat, u_char * errs0, u_char * calc_ecc) -+{ -+ u32 stat; -+ u32 *errs = (u32 *)errs0; -+ -+ if (REG_DMAC_DCCSR(0) & DMAC_DCCSR_BERR) { -+ stat = errs[0]; -+ dprintk("stat=%x err0:%x err1:%x \n", stat, errs[1], errs[2]); -+ -+ if (stat & BCH_INTS_ERR) { -+ if (stat & BCH_INTS_UNCOR) { -+ printk("NAND: Uncorrectable ECC error\n"); -+ return -1; -+ } else { -+ u32 errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; -+ switch (errcnt) { -+#if defined(CONFIG_MTD_HW_BCH_8BIT) -+ case 8: -+ bch_correct(mtd, dat, (errs[4] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ case 7: -+ bch_correct(mtd, dat, (errs[4] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ case 6: -+ bch_correct(mtd, dat, (errs[3] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ case 5: -+ bch_correct(mtd, dat, (errs[3] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+#endif -+ case 4: -+ bch_correct(mtd, dat, (errs[2] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ case 3: -+ bch_correct(mtd, dat, (errs[2] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ case 2: -+ bch_correct(mtd, dat, (errs[1] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ case 1: -+ bch_correct(mtd, dat, (errs[1] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ default: -+ break; -+ } -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+#else /* cpu mode */ -+ -+/** -+ * jzsoc_nand_bch_correct_data -+ * @mtd: mtd info structure -+ * @dat: data to be corrected -+ * @read_ecc: pointer to ecc buffer calculated when nand writing -+ * @calc_ecc: no used -+ */ -+static int jzsoc_nand_bch_correct_data(struct mtd_info *mtd, u_char * dat, u_char * read_ecc, u_char * calc_ecc) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ int eccsize = this->ecc.size; -+ int eccbytes = this->ecc.bytes; -+ int eccsteps = this->ecc.steps / this->planenum; -+ int ecc_pos = this->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ short k; -+ u32 stat; -+ -+ /* Write data to REG_BCH_DR */ -+ for (k = 0; k < eccsize; k++) { -+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->data[k]; -+ } -+ /* Write oob to REG_BCH_DR */ -+ for (k = 0; k < oob_per_eccsize; k++) { -+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->oob[k]; -+ } -+ /* Write parities to REG_BCH_DR */ -+ for (k = 0; k < eccbytes; k++) { -+ REG_BCH_DR = read_ecc[k]; -+ } -+ -+ /* Wait for completion */ -+ __ecc_decode_sync(); -+ __ecc_disable(); -+ -+ /* Check decoding */ -+ stat = REG_BCH_INTS; -+ -+ if (stat & BCH_INTS_ERR) { -+ /* Error occurred */ -+ if (stat & BCH_INTS_UNCOR) { -+ printk("NAND: Uncorrectable ECC error--\n"); -+ return -1; -+ } else { -+ u32 errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; -+ switch (errcnt) { -+#if defined(CONFIG_MTD_HW_BCH_8BIT) -+ case 8: -+ bch_correct(mtd, dat, (REG_BCH_ERR3 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ /* FALL-THROUGH */ -+ case 7: -+ bch_correct(mtd, dat, (REG_BCH_ERR3 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ /* FALL-THROUGH */ -+ case 6: -+ bch_correct(mtd, dat, (REG_BCH_ERR2 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ /* FALL-THROUGH */ -+ case 5: -+ bch_correct(mtd, dat, (REG_BCH_ERR2 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ /* FALL-THROUGH */ -+#endif -+ case 4: -+ bch_correct(mtd, dat, (REG_BCH_ERR1 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ /* FALL-THROUGH */ -+ case 3: -+ bch_correct(mtd, dat, (REG_BCH_ERR1 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ /* FALL-THROUGH */ -+ case 2: -+ bch_correct(mtd, dat, (REG_BCH_ERR0 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ /* FALL-THROUGH */ -+ case 1: -+ bch_correct(mtd, dat, (REG_BCH_ERR0 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ return 0; -+ default: -+ break; -+ } -+ } -+ } -+ -+ return 0; -+} -+#endif /* CONFIG_MTD_NAND_DMA */ -+ -+static int jzsoc_nand_calculate_bch_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ int eccsize = this->ecc.size; -+ int eccbytes = this->ecc.bytes; -+ int eccsteps = this->ecc.steps / this->planenum; -+ int ecc_pos = this->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ volatile u8 *paraddr = (volatile u8 *)BCH_PAR0; -+ short i; -+ -+ /* Write data to REG_BCH_DR */ -+ for (i = 0; i < eccsize; i++) { -+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->data[i]; -+ } -+ /* Write oob to REG_BCH_DR */ -+ for (i = 0; i < oob_per_eccsize; i++) { -+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->oob[i]; -+ } -+ __ecc_encode_sync(); -+ __ecc_disable(); -+ -+ for (i = 0; i < eccbytes; i++) { -+ ecc_code[i] = *paraddr++; -+ } -+ -+ return 0; -+} -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+ -+/** -+ * nand_write_page_hwecc_bch - [REPLACABLE] hardware ecc based page write function -+ * @mtd: mtd info structure -+ * @chip: nand chip info structure -+ * @buf: data buffer -+ */ -+static void nand_write_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf, u8 cmd_pgprog) -+{ -+ int eccsize = chip->ecc.size; -+ int eccsteps = chip->ecc.steps / chip->planenum; -+ int eccbytes = chip->ecc.bytes; -+ int ecc_pos = chip->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ int pagesize = mtd->writesize / chip->planenum; -+ int oobsize = mtd->oobsize / chip->planenum; -+ int i, err, timeout; -+ const u8 *databuf; -+ u8 *oobbuf; -+ jz_dma_desc_8word *desc; -+ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ memcpy(prog_buf, buf, pagesize); -+ memcpy(prog_buf + pagesize, chip->oob_poi, oobsize); -+ dma_cache_wback_inv((u32)prog_buf, pagesize + oobsize); -+#else -+ databuf = buf; -+ oobbuf = chip->oob_poi; -+ -+ /* descriptors for encoding data blocks */ -+ desc = dma_desc_enc; -+ for (i = 0; i < eccsteps; i++) { -+ desc->dsadr = CPHYSADDR((u32)databuf) + i * eccsize; /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ -+ dprintk("dma_desc_enc:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptors for encoding oob blocks */ -+ desc = dma_desc_enc1; -+ for (i = 0; i < eccsteps; i++) { -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address, 28/4 = 7bytes */ -+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ -+ dprintk("dma_desc_enc1:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptor for nand programing data block */ -+ desc = dma_desc_nand_prog; -+ desc->dsadr = CPHYSADDR((u32)databuf); /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_W); /* It will be changed when using multiply chip select */ -+ dprintk("dma_desc_nand_prog:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ -+ /* descriptor for nand programing oob block */ -+ desc++; -+ desc->dsadr = CPHYSADDR((u32)oobbuf); /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_W); /* It will be changed when using multiply chip select */ -+ dprintk("dma_desc_oob_prog:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ -+ /* descriptor for __nand_cmd(CMD_PGPROG) */ -+ desc++; -+ *pval_nand_cmd_pgprog = cmd_pgprog; -+ desc->dsadr = CPHYSADDR((u32)pval_nand_cmd_pgprog); -+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_R | cmd_offset); /* DMA target address: cmdport */ -+ if (cmd_pgprog == 0x10) -+ desc->dcmd |= DMAC_DCMD_LINK; /* __nand_sync() by a DMA descriptor */ -+ else if (cmd_pgprog == 0x11) -+ desc->dcmd &= ~DMAC_DCMD_LINK; /* __nand_sync() by polling */ -+ -+ dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 1) * (sizeof(jz_dma_desc_8word))); -+ dma_cache_wback_inv((u32)databuf, pagesize); -+ dma_cache_wback_inv((u32)oobbuf, oobsize); -+ /* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */ -+ dma_cache_wback_inv((u32)pval_nand_ddr, 4 * 8); /* 8 words, a cache line */ -+#endif -+ -+ REG_DMAC_DCCSR(bch_dma_chan) = 0; -+ REG_DMAC_DCCSR(nand_dma_chan) = 0; -+ -+ /* Setup DMA descriptor address */ -+ REG_DMAC_DDA(bch_dma_chan) = CPHYSADDR((u32)dma_desc_enc); -+ REG_DMAC_DDA(nand_dma_chan) = CPHYSADDR((u32)dma_desc_nand_prog); -+ -+ /* Setup request source */ -+ REG_DMAC_DRSR(bch_dma_chan) = DMAC_DRSR_RS_BCH_ENC; -+ REG_DMAC_DRSR(nand_dma_chan) = DMAC_DRSR_RS_AUTO; -+ -+ /* Setup DMA channel control/status register */ -+ REG_DMAC_DCCSR(bch_dma_chan) = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */ -+ -+ /* Enable DMA */ -+ REG_DMAC_DMACR(0) |= DMAC_DMACR_DMAE; -+ REG_DMAC_DMACR(nand_dma_chan/HALF_DMA_NUM) |= DMAC_DMACR_DMAE; -+ -+ /* Enable BCH encoding */ -+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); -+ -+ dma_ack1 = 0; -+ nand_status = NAND_PROG; -+ -+ /* DMA doorbell set -- start DMA now ... */ -+ __dmac_channel_set_doorbell(bch_dma_chan); -+ -+#if USE_IRQ -+ if (cmd_pgprog == 0x10) { -+ dprintk("nand prog before wake up\n"); -+ err = wait_event_interruptible_timeout(nand_prog_wait_queue, dma_ack1, 3 * HZ); -+ nand_status = NAND_NONE; -+ dprintk("nand prog after wake up\n"); -+ if (!err) { -+ printk("*** NAND WRITE, Warning, wait event 3s timeout!\n"); -+ dump_jz_dma_channel(0); -+ dump_jz_dma_channel(nand_dma_chan); -+ printk("REG_BCH_CR=%x REG_BCH_CNT=0x%x REG_BCH_INTS=%x\n", REG_BCH_CR, REG_BCH_CNT, REG_BCH_INTS); -+ } -+ dprintk("timeout remain = %d\n", err); -+ } else if (cmd_pgprog == 0x11) { -+ timeout = 100000; -+ while ((!__dmac_channel_transmit_end_detected(nand_dma_chan)) && (timeout--)); -+ if (timeout <= 0) -+ printk("two-plane prog 0x11 timeout!\n"); -+ } -+#else -+ timeout = 100000; -+ while ((!__dmac_channel_transmit_end_detected(nand_dma_chan)) && (timeout--)); -+ while(!chip->dev_ready(mtd)); -+ if (timeout <= 0) -+ printk("not use irq, prog timeout!\n"); -+#endif -+} -+ -+static void nand_write_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf) -+{ -+ nand_write_page_hwecc_bch0(mtd, chip, buf, 0x10); -+} -+ -+static void nand_write_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf) -+{ -+ int page; -+ int pagesize = mtd->writesize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ nand_write_page_hwecc_bch0(mtd, chip, buf, 0x11); -+ chip->cmdfunc(mtd, 0x81, 0x00, page + ppb); -+ nand_write_page_hwecc_bch0(mtd, chip, buf + pagesize, 0x10); -+} -+ -+#else /* nand write in cpu mode */ -+ -+static void nand_write_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, -+ const uint8_t *buf) -+{ -+ int i, eccsize = chip->ecc.size; -+ int eccbytes = chip->ecc.bytes; -+ int eccsteps = chip->ecc.steps / chip->planenum; -+ int oob_per_eccsize = chip->ecc.layout->eccpos[0] / eccsteps; -+ int oobsize = mtd->oobsize / chip->planenum; -+ int ecctotal = chip->ecc.total / chip->planenum; -+ uint8_t *p = (uint8_t *)buf; -+ uint8_t *ecc_calc = chip->buffers->ecccalc; -+ uint32_t *eccpos = chip->ecc.layout->eccpos; -+ static struct buf_be_corrected buf_calc0; -+ struct buf_be_corrected *buf_calc = &buf_calc0; -+ -+ for (i = 0; i < eccsteps; i++, p += eccsize) { -+ buf_calc->data = (u8 *)buf + eccsize * i; -+ buf_calc->oob = chip->oob_poi + oob_per_eccsize * i; -+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); -+ chip->ecc.calculate(mtd, (u8 *)buf_calc, &ecc_calc[eccbytes*i]); -+ chip->write_buf(mtd, p, eccsize); -+ } -+ -+ for (i = 0; i < ecctotal; i++) -+ chip->oob_poi[eccpos[i]] = ecc_calc[i]; -+ -+ chip->write_buf(mtd, chip->oob_poi, oobsize); -+} -+ -+/* nand write using two-plane mode */ -+static void nand_write_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ const uint8_t *buf) -+{ -+ int pagesize = mtd->writesize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ int page; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ nand_write_page_hwecc_bch(mtd, chip, buf); -+ -+ chip->cmdfunc(mtd, 0x11, -1, -1); /* send cmd 0x11 */ -+ ndelay(100); -+ while(!chip->dev_ready(mtd)); -+ -+ chip->cmdfunc(mtd, 0x81, 0x00, page + ppb); /* send cmd 0x81 */ -+ nand_write_page_hwecc_bch(mtd, chip, buf + pagesize); -+} -+#endif /* CONFIG_MTD_NAND_DMA */ -+ -+/** -+ * nand_read_page_hwecc_bch - [REPLACABLE] hardware ecc based page read function -+ * @mtd: mtd info structure -+ * @chip: nand chip info structure -+ * @buf: buffer to store read data -+ * -+ * Not for syndrome calculating ecc controllers which need a special oob layout -+ */ -+#if defined(CONFIG_MTD_NAND_DMA) -+static int nand_read_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf, u32 page) -+{ -+ int i, eccsize = chip->ecc.size; -+ int eccsteps = chip->ecc.steps / chip->planenum; -+ int eccbytes = chip->ecc.bytes; -+ int ecc_pos = chip->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ int pagesize = mtd->writesize / chip->planenum; -+ int oobsize = mtd->oobsize / chip->planenum; -+ u8 *databuf, *oobbuf; -+ jz_dma_desc_8word *desc; -+ int err; -+ u32 addrport, cmdport; -+ static struct buf_be_corrected buf_correct0; -+ -+ addrport = (u32)(chip->IO_ADDR_R) | addr_offset; -+ cmdport = (u32)(chip->IO_ADDR_R) | cmd_offset; -+ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ databuf = read_buf; -+ oobbuf = read_buf + pagesize; -+ -+ dma_cache_inv((u32)read_buf, pagesize + oobsize); // databuf should be invalidated. -+ memset(errs, 0, eccsteps * ERRS_SIZE * 4); -+ dma_cache_wback_inv((u32)errs, eccsteps * ERRS_SIZE * 4); -+#else -+ -+ databuf = buf; -+ oobbuf = chip->oob_poi; -+ -+ /* descriptor for nand reading data block */ -+ desc = dma_desc_nand_read; -+ desc->dsadr = CPHYSADDR((u32)chip->IO_ADDR_R); /* It will be changed when using multiply chip select */ -+ desc->dtadr = CPHYSADDR((u32)databuf); /* DMA target address */ -+ -+ dprintk("desc_nand_read:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ -+ /* descriptor for nand reading oob block */ -+ desc++; -+ desc->dsadr = CPHYSADDR((u32)chip->IO_ADDR_R); /* It will be changed when using multiply chip select */ -+ desc->dtadr = CPHYSADDR((u32)oobbuf); /* DMA target address */ -+ dprintk("desc_oob_read:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ -+ /* descriptors for data to be written to bch */ -+ desc = dma_desc_dec; -+ for (i = 0; i < eccsteps; i++) { -+ desc->dsadr = CPHYSADDR((u32)databuf) + i * eccsize; /* DMA source address */ -+ dprintk("dma_desc_dec:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptors for oob to be written to bch */ -+ desc = dma_desc_dec1; -+ for (i = 0; i < eccsteps; i++) { -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address */ -+ dprintk("dma_desc_dec1:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptors for parities to be written to bch */ -+ desc = dma_desc_dec2; -+ for (i = 0; i < eccsteps; i++) { -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA source address */ -+ dprintk("dma_desc_dec2:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ dma_cache_wback_inv((u32)dma_desc_nand_read, (2 + eccsteps * 3) * (sizeof(jz_dma_desc_8word))); -+ -+ memset(errs, 0, eccsteps * ERRS_SIZE * 4); -+ dma_cache_inv((u32)databuf, pagesize); // databuf should be invalidated. -+ dma_cache_inv((u32)oobbuf, oobsize); // oobbuf should be invalidated too -+ dma_cache_wback_inv((u32)errs, eccsteps * ERRS_SIZE * 4); -+#endif -+ REG_DMAC_DCCSR(bch_dma_chan) = 0; -+ REG_DMAC_DCCSR(nand_dma_chan) = 0; -+ -+ /* Setup DMA descriptor address */ -+ REG_DMAC_DDA(nand_dma_chan) = CPHYSADDR((u32)dma_desc_nand_read); -+ REG_DMAC_DDA(bch_dma_chan) = CPHYSADDR((u32)dma_desc_dec); -+ -+ /* Setup request source */ -+ REG_DMAC_DRSR(nand_dma_chan) = DMAC_DRSR_RS_NAND; -+ REG_DMAC_DRSR(bch_dma_chan) = DMAC_DRSR_RS_BCH_DEC; -+ -+ /* Enable DMA */ -+ REG_DMAC_DMACR(0) |= DMAC_DMACR_DMAE; -+ REG_DMAC_DMACR(nand_dma_chan/HALF_DMA_NUM) |= DMAC_DMACR_DMAE; -+ -+ /* Enable BCH decoding */ -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ -+ dma_ack = 0; -+ nand_status = NAND_READ; -+ /* DMA doorbell set -- start nand DMA now ... */ -+ __dmac_channel_set_doorbell(nand_dma_chan); -+ -+ /* Setup DMA channel control/status register */ -+ REG_DMAC_DCCSR(nand_dma_chan) = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; -+ -+#define __nand_cmd(n) (REG8(cmdport) = (n)) -+#define __nand_addr(n) (REG8(addrport) = (n)) -+ -+ __nand_cmd(NAND_CMD_READ0); -+ -+ __nand_addr(0); -+ if (pagesize != 512) -+ __nand_addr(0); -+ -+ __nand_addr(page & 0xff); -+ __nand_addr((page >> 8) & 0xff); -+ -+ /* One more address cycle for the devices whose number of page address bits > 16 */ -+ if (((chip->chipsize >> chip->page_shift) >> 16) - 1 > 0) -+ __nand_addr((page >> 16) & 0xff); -+ -+ if (pagesize != 512) -+ __nand_cmd(NAND_CMD_READSTART); -+ -+#if USE_IRQ -+ do { -+ err = wait_event_interruptible_timeout(nand_read_wait_queue, dma_ack, 3 * HZ); -+ }while(err == -ERESTARTSYS); -+ nand_status = NAND_NONE; -+ -+ if (!err) { -+ printk("*** NAND READ, Warning, wait event 3s timeout!\n"); -+ dump_jz_dma_channel(0); -+ dump_jz_dma_channel(nand_dma_chan); -+ printk("REG_BCH_CR=%x REG_BCH_CNT=0x%x REG_BCH_INTS=%x\n", REG_BCH_CR, REG_BCH_CNT, REG_BCH_INTS); -+ printk("databuf[0]=%x\n", databuf[0]); -+ } -+ dprintk("timeout remain = %d\n", err); -+#else -+ int timeout; -+ timeout = 100000; -+ while ((!__dmac_channel_transmit_end_detected(bch_dma_chan)) && (timeout--)); -+ if (timeout <= 0) { -+ printk("not use irq, NAND READ timeout!\n"); -+ } -+#endif -+ -+ for (i = 0; i < eccsteps; i++) { -+ int stat; -+ struct buf_be_corrected *buf_correct = &buf_correct0; -+ -+ buf_correct->data = databuf + eccsize * i; -+ buf_correct->oob = oobbuf + oob_per_eccsize * i; -+ -+ stat = chip->ecc.correct(mtd, (u8 *)buf_correct, (u8 *)&errs[i * ERRS_SIZE], NULL); -+ if (stat < 0) -+ mtd->ecc_stats.failed++; -+ else -+ mtd->ecc_stats.corrected += stat; -+ } -+ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ memcpy(buf, read_buf, pagesize); -+ memcpy(chip->oob_poi, read_buf + pagesize, oobsize); -+#endif -+ return 0; -+} -+ -+static int nand_read_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) -+{ -+ u32 page = global_page; -+ -+ nand_read_page_hwecc_bch0(mtd, chip, buf, page); -+ return 0; -+} -+ -+static int nand_read_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) -+{ -+ u32 page; -+ int pagesize = mtd->writesize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* read 1st page */ -+ nand_read_page_hwecc_bch0(mtd, chip, buf, page); -+ -+ /* read 2nd page */ -+ nand_read_page_hwecc_bch0(mtd, chip, buf + pagesize, page + ppb); -+ return 0; -+} -+ -+#else /* nand read in cpu mode */ -+ -+static int nand_read_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) -+{ -+ int i, eccsize = chip->ecc.size; -+ int eccbytes = chip->ecc.bytes; -+ int eccsteps = chip->ecc.steps / chip->planenum; -+ int ecc_pos = chip->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ uint8_t *ecc_calc = chip->buffers->ecccalc; -+ uint8_t *ecc_code = chip->buffers->ecccode; -+ uint32_t *eccpos = chip->ecc.layout->eccpos; -+ int pagesize = mtd->writesize / chip->planenum; -+ int oobsize = mtd->oobsize / chip->planenum; -+ int ecctotal = chip->ecc.total / chip->planenum; -+ static struct buf_be_corrected buf_correct0; -+ -+ chip->read_buf(mtd, buf, pagesize); -+ chip->read_buf(mtd, chip->oob_poi, oobsize); -+ -+ for (i = 0; i < ecctotal; i++) { -+ ecc_code[i] = chip->oob_poi[eccpos[i]]; -+ } -+ -+ for (i = 0; i < eccsteps; i++) { -+ int stat; -+ struct buf_be_corrected *buf_correct = &buf_correct0; -+ -+ buf_correct->data = buf + eccsize * i; -+ buf_correct->oob = chip->oob_poi + oob_per_eccsize * i; -+ -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ stat = chip->ecc.correct(mtd, (u8 *)buf_correct, &ecc_code[eccbytes*i], &ecc_calc[eccbytes*i]); -+ if (stat < 0) -+ mtd->ecc_stats.failed++; -+ else -+ mtd->ecc_stats.corrected += stat; -+ } -+ -+ return 0; -+} -+ -+static int nand_read_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) -+{ -+ int pagesize = mtd->writesize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ uint32_t page; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* Read first page */ -+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); -+ nand_read_page_hwecc_bch(mtd, chip, buf); -+ -+ /* Read 2nd page */ -+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page + ppb); -+ nand_read_page_hwecc_bch(mtd, chip, buf+pagesize); -+ return 0; -+} -+#endif /* CONFIG_MTD_NAND_DMA */ -+ -+#endif /* CONFIG_MTD_HW_BCH_ECC */ -+ -+/* read oob using two-plane mode */ -+static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ int global_page, int sndcmd) -+{ -+ int page; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* Read first page OOB */ -+ if (sndcmd) { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ } -+ chip->read_buf(mtd, chip->oob_poi, oobsize); -+ /* Read second page OOB */ -+ page += ppb; -+ if (sndcmd) { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ sndcmd = 0; -+ } -+ chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize); -+ return 0; -+} -+ -+/* write oob using two-plane mode */ -+static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ int global_page) -+{ -+ int status = 0, page; -+ const uint8_t *buf = chip->oob_poi; -+ int pagesize = mtd->writesize >> 1; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x80, pagesize, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ chip->write_buf(mtd, buf, oobsize); -+ /* Send first command to program the OOB data */ -+ chip->cmdfunc(mtd, 0x11, -1, -1); -+ ndelay(100); -+ status = chip->waitfunc(mtd, chip); -+ -+ page += ppb; -+ buf += oobsize; -+ chip->cmdfunc(mtd, 0x81, pagesize, page); -+ chip->write_buf(mtd, buf, oobsize); -+ /* Send command to program the OOB data */ -+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -+ /* Wait long R/B */ -+ ndelay(100); -+ status = chip->waitfunc(mtd, chip); -+ -+ return status & NAND_STATUS_FAIL ? -EIO : 0; -+} -+ -+/* nand erase using two-plane mode */ -+static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page) -+{ -+ struct nand_chip *chip = mtd->priv; -+ int page, ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x60, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x60, -1, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x60, -1, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ page += ppb; -+ chip->cmdfunc(mtd, 0x60, -1, page & (~(ppb-1))); /* send cmd 0x60 */ -+ -+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */ -+ /* Do not need wait R/B or check status */ -+} -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+ -+#if USE_IRQ -+static irqreturn_t nand_dma_irq(int irq, void *dev_id) -+{ -+ u8 dma_chan; -+ volatile int wakeup = 0; -+ -+ dma_chan = irq - IRQ_DMA_0; -+ -+ dprintk("jz4750_dma_irq %d, channel %d\n", irq, dma_chan); -+ -+ if (__dmac_channel_transmit_halt_detected(dma_chan)) { -+ __dmac_channel_clear_transmit_halt(dma_chan); -+ wakeup = 1; -+ printk("DMA HALT\n"); -+ } -+ -+ if (__dmac_channel_address_error_detected(dma_chan)) { -+ -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ __dmac_channel_clear_address_error(dma_chan); -+ -+ REG_DMAC_DSAR(dma_chan) = 0; /* reset source address register */ -+ REG_DMAC_DTAR(dma_chan) = 0; /* reset destination address register */ -+ -+ /* clear address error in DMACR */ -+ REG_DMAC_DMACR((dma_chan / HALF_DMA_NUM)) &= ~(1 << 2); -+ wakeup = 1; -+ printk("DMA address error!\n"); -+ } -+ -+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { -+ __dmac_channel_clear_descriptor_invalid(dma_chan); -+ wakeup = 1; -+ printk("DMA DESC INVALID\n"); -+ } -+#if 1 -+ -+ while (!__dmac_channel_transmit_end_detected(dma_chan)); -+ -+ if (__dmac_channel_count_terminated_detected(dma_chan)) { -+ dprintk("DMA CT\n"); -+ __dmac_channel_clear_count_terminated(dma_chan); -+ wakeup = 0; -+ } -+#endif -+ -+ if (__dmac_channel_transmit_end_detected(dma_chan)) { -+ dprintk("DMA TT\n"); -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ __dmac_channel_clear_transmit_end(dma_chan); -+ wakeup = 1; -+ } -+ -+ if (wakeup) { -+ dprintk("ack %d irq , wake up dma_chan %d nand_status %d\n", dma_ack, dma_chan, nand_status); -+ /* wakeup wait event */ -+ if ((dma_chan == nand_dma_chan) && (nand_status == NAND_PROG)) { -+ dprintk("nand prog dma irq, wake up----\n"); -+ dma_ack1 = 1; -+ wake_up_interruptible(&nand_prog_wait_queue); -+ } -+ -+ if ((dma_chan == bch_dma_chan) && (nand_status == NAND_READ)) { -+ dprintk("nand read irq, wake up----\n"); -+ dma_ack = 1; -+ wake_up_interruptible(&nand_read_wait_queue); -+ } -+ wakeup = 0; -+ } -+ -+ return IRQ_HANDLED; -+} -+#endif /* USE_IRQ */ -+ -+static int jz4750_nand_dma_init(struct mtd_info *mtd) -+{ -+ struct nand_chip *chip = mtd->priv; -+ int eccsize = chip->ecc.size; -+ int eccsteps = chip->ecc.steps / chip->planenum; -+ int eccbytes = chip->ecc.bytes; -+ int ecc_pos = chip->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ int pagesize = mtd->writesize / chip->planenum; -+ int oobsize = mtd->oobsize / chip->planenum; -+ int i, err; -+ jz_dma_desc_8word *desc, *dma_desc_bch_ddr, *dma_desc_nand_ddr, *dma_desc_nand_cmd_pgprog; -+ u32 *pval_nand_dcs, *pval_bch_ddr, *pval_bch_dcs, *dummy; -+ u32 next; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ u8 *oobbuf; -+#endif -+ -+#if USE_IRQ -+ if ((nand_dma_chan = jz_request_dma(DMA_ID_NAND, "nand read or write", nand_dma_irq, IRQF_DISABLED, NULL)) < 0) { -+ printk("can't reqeust DMA nand channel.\n"); -+ return 0; -+ } -+ dprintk("nand dma channel:%d----\n", nand_dma_chan); -+ -+ if ((err = request_irq(IRQ_DMA_0 + bch_dma_chan, nand_dma_irq, IRQF_DISABLED, "bch_dma", NULL))) { -+ printk("bch_dma irq request err\n"); -+ return 0; -+ } -+#else -+ if ((nand_dma_chan = jz_request_dma(DMA_ID_NAND, "nand read or write", NULL, IRQF_DISABLED, NULL)) < 0) { -+ printk("can't reqeust DMA nand channel.\n"); -+ return 0; -+ } -+ dprintk("nand dma channel:%d----\n", nand_dma_chan); -+#endif -+ -+ __dmac_channel_enable_clk(nand_dma_chan); -+ __dmac_channel_enable_clk(bch_dma_chan); -+ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ if (pagesize < 4096) { -+ read_buf = prog_buf = (u8 *) __get_free_page(GFP_KERNEL); -+ } else { -+ read_buf = prog_buf = (u8 *) __get_free_pages(GFP_KERNEL, 1); -+ } -+ if (!read_buf) -+ return -ENOMEM; -+#endif -+ /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes), and the space for the value -+ * of ddr and dcs of channel 0 and channel nand_dma_chan (4 * (2 + 2) bytes) */ -+ errs = (u32 *)kmalloc(4 * (2 + 2 + 5 * eccsteps), GFP_KERNEL); -+ if (!errs) -+ return -ENOMEM; -+ -+ pval_nand_ddr = errs + 5 * eccsteps; -+ pval_nand_dcs = pval_nand_ddr + 1; -+ pval_bch_ddr = pval_nand_dcs + 1; -+ pval_bch_dcs = pval_bch_ddr + 1; -+ /* space for nand prog waiting target, the content is useless */ -+ dummy = pval_bch_dcs + 1; -+ /* space to store CMD_PGPROG(0x10) or 0x11 */ -+ pval_nand_cmd_pgprog = (u8 *)(dummy + 1); -+ -+ /* desc can't across 4KB boundary, as desc base address is fixed */ -+ /* space of descriptors for nand reading data and oob blocks */ -+ dma_desc_nand_read = (jz_dma_desc_8word *) __get_free_page(GFP_KERNEL); -+ if (!dma_desc_nand_read) -+ return -ENOMEM; -+ -+ /* space of descriptors for bch decoding */ -+ dma_desc_dec = dma_desc_nand_read + 2; -+ dma_desc_dec1 = dma_desc_dec + eccsteps; -+ dma_desc_dec2 = dma_desc_dec + eccsteps * 2; -+ -+ /* space of descriptors for notifying bch channel */ -+ dma_desc_bch_ddr = dma_desc_dec2 + eccsteps; -+ -+ /* space of descriptors for bch encoding */ -+ dma_desc_enc = dma_desc_bch_ddr + 2; -+ dma_desc_enc1 = dma_desc_enc + eccsteps; -+ -+ /* space of descriptors for nand programing data and oob blocks */ -+ dma_desc_nand_prog = dma_desc_enc1 + eccsteps; -+ -+ /* space of descriptors for nand prog waiting, including pgprog and sync */ -+ dma_desc_nand_cmd_pgprog = dma_desc_nand_prog + 2; -+ -+ /* space of descriptors for notifying nand channel, including ddr and dcsr */ -+ dma_desc_nand_ddr = dma_desc_nand_cmd_pgprog + 2; -+ -+/************************************* -+ * Setup of nand programing descriptors -+ *************************************/ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ oobbuf = prog_buf + pagesize; -+#endif -+ /* set descriptor for encoding data blocks */ -+ desc = dma_desc_enc; -+ for (i = 0; i < eccsteps; i++) { -+ next = (CPHYSADDR((u32)dma_desc_enc1) + i * (sizeof(jz_dma_desc_8word))) >> 4; -+ -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | -+ DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)prog_buf) + i * eccsize; /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ -+#endif -+ desc->ddadr = (next << 24) + eccsize / DIV_DS_BCH; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_BCH_ENC; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ desc++; -+ } -+ -+ /* set descriptor for encoding oob blocks */ -+ desc = dma_desc_enc1; -+ for (i = 0; i < eccsteps; i++) { -+ next = (CPHYSADDR((u32)dma_desc_enc) + (i + 1) * (sizeof(jz_dma_desc_8word))) >> 4; -+ -+ desc->dcmd = -+ DMAC_DCMD_BLAST | DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | -+ DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address, 28/4 = 7bytes */ -+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ -+#endif -+ desc->ddadr = (next << 24) + (oob_per_eccsize + 3) / 4; /* size: 7 bytes -> 2 words */ -+ desc->dreqt = DMAC_DRSR_RS_BCH_ENC; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ desc++; -+ } -+ -+ next = (CPHYSADDR((u32)dma_desc_nand_ddr)) >> 4; -+ desc--; -+ desc->ddadr = (next << 24) + (oob_per_eccsize + 3) / 4; -+ -+ /* set the descriptor to set door bell of nand_dma_chan for programing nand */ -+ desc = dma_desc_nand_ddr; -+ *pval_nand_ddr = 1 << (nand_dma_chan - nand_dma_chan / HALF_DMA_NUM * HALF_DMA_NUM); -+ next = (CPHYSADDR((u32)dma_desc_nand_ddr) + sizeof(jz_dma_desc_8word)) >> 4; -+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; -+ desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */ -+ desc->dtadr = CPHYSADDR(DMAC_DMADBSR(nand_dma_chan / HALF_DMA_NUM)); /* nand_dma_chan's descriptor addres register */ -+ desc->ddadr = (next << 24) + 1; /* size: 1 word */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("*pval_nand_ddr=0x%x\n", *pval_nand_ddr); -+ -+ /* set the descriptor to write dccsr of nand_dma_chan for programing nand, dccsr should be set at last */ -+ desc++; -+ *pval_nand_dcs = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; /* set value for writing ddr to enable channel nand_dma_chan */ -+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; -+ desc->dsadr = CPHYSADDR((u32)pval_nand_dcs); /* DMA source address */ -+ desc->dtadr = CPHYSADDR(DMAC_DCCSR(nand_dma_chan)); /* address of dma door bell set register */ -+ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("*pval_nand_dcs=0x%x\n", *pval_nand_dcs); -+ -+ /* set descriptor for nand programing data block */ -+ desc = dma_desc_nand_prog; -+ next = (CPHYSADDR((u32)dma_desc_nand_prog) + sizeof(jz_dma_desc_8word)) >> 4; -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | -+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)prog_buf); /* DMA source address */ -+#endif -+ desc->dtadr = CPHYSADDR((u32)(chip->IO_ADDR_W)); /* DMA target address */ -+ desc->ddadr = (next << 24) + pagesize / DIV_DS_NAND; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* set descriptor for nand programing oob block */ -+ desc++; -+ next = (CPHYSADDR((u32)dma_desc_nand_cmd_pgprog)) >> 4; -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | -+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)oobbuf); /* DMA source address */ -+#endif -+ desc->dtadr = CPHYSADDR((u32)(chip->IO_ADDR_W)); /* DMA target address: dataport */ -+ desc->ddadr = (next << 24) + oobsize / DIV_DS_NAND; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* set descriptor for __nand_cmd(CMD_PGPROG) */ -+ desc = dma_desc_nand_cmd_pgprog; -+ *pval_nand_cmd_pgprog = NAND_CMD_PAGEPROG; -+ next = (CPHYSADDR((u32)dma_desc_nand_cmd_pgprog) + sizeof(jz_dma_desc_8word)) >> 4; -+ desc->dcmd = -+ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_8BIT | DMAC_DCMD_LINK; -+ desc->dsadr = CPHYSADDR((u32)pval_nand_cmd_pgprog); /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_R | cmd_offset); /* DMA target address: cmdport */ -+ desc->ddadr = (next << 24) + 1; /* size: 1 byte */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* set descriptor for __nand_sync() */ -+ desc++; -+#if USE_IRQ -+ desc->dcmd = -+ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_TIE; -+#else -+ desc->dcmd = -+ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; -+#endif -+ desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)dummy); /* DMA target address, the content is useless */ -+ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ -+ desc->dreqt = DMAC_DRSR_RS_NAND; -+ dprintk("1cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* eccsteps*2 + 2 + 2 + 2: -+ dma_desc_enc + dma_desc_enc1 + dma_desc_nand_prog(oob) + dma_desc_nand_ddr(csr) -+ + dma_desc_nand_cmd_pgprog(sync) */ -+ dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 2 + 2) * (sizeof(jz_dma_desc_8word))); -+ /* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */ -+ dma_cache_wback_inv((u32)pval_nand_ddr, 4 * 8); /* 8 words, a cache line */ -+ -+/************************************* -+ * Setup of nand reading descriptors -+ *************************************/ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ oobbuf = read_buf + pagesize; -+#endif -+ /* set descriptor for nand reading data block */ -+ desc = dma_desc_nand_read; -+ next = (CPHYSADDR((u32)dma_desc_nand_read) + sizeof(jz_dma_desc_8word)) >> 4; -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | -+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; -+ desc->dsadr = CPHYSADDR((u32)(chip->IO_ADDR_R)); /* DMA source address */ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dtadr = CPHYSADDR((u32)read_buf); /* DMA target address */ -+#endif -+ desc->ddadr = (next << 24) + pagesize / DIV_DS_NAND; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_NAND; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* set descriptor for nand reading oob block */ -+ desc++; -+ next = (CPHYSADDR((u32)dma_desc_bch_ddr)) >> 4; -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | -+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; -+ desc->dsadr = CPHYSADDR((u32)(chip->IO_ADDR_R)); /* DMA source address */ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dtadr = CPHYSADDR((u32)oobbuf); /* DMA target address */ -+#endif -+ desc->ddadr = (next << 24) + oobsize / DIV_DS_NAND; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* set the descriptor to set door bell for bch */ -+ desc = dma_desc_bch_ddr; -+ *pval_bch_ddr = DMAC_DMADBSR_DBS0; // set value for writing ddr to enable channel 0 -+ next = (CPHYSADDR((u32)dma_desc_bch_ddr) + sizeof(jz_dma_desc_8word)) >> 4; -+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; -+ desc->dsadr = CPHYSADDR((u32)pval_bch_ddr); /* DMA source address */ -+ desc->dtadr = CPHYSADDR(DMAC_DMADBSR(0)); /* channel 1's descriptor addres register */ -+ desc->ddadr = (next << 24) + 1; /* size: 1 word */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ -+ /* set descriptor for writing dcsr */ -+ desc++; -+ *pval_bch_dcs = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; // set value for writing ddr to enable channel 1 -+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; -+ desc->dsadr = CPHYSADDR((u32)pval_bch_dcs); /* DMA source address */ -+ desc->dtadr = CPHYSADDR(DMAC_DCCSR(bch_dma_chan)); /* address of dma door bell set register */ -+ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ -+ /* descriptors for data to be written to bch */ -+ desc = dma_desc_dec; -+ for (i = 0; i < eccsteps; i++) { -+ next = CPHYSADDR((u32)dma_desc_dec1 + i * (sizeof(jz_dma_desc_8word))) >> 4; -+ -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | -+ DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)read_buf) + i * eccsize; /* DMA source address */ -+#endif -+ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ -+ desc->ddadr = (next << 24) + eccsize / DIV_DS_BCH; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; -+ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptors for oob to be written to bch */ -+ desc = dma_desc_dec1; -+ for (i = 0; i < eccsteps; i++) { -+ next = CPHYSADDR((u32)dma_desc_dec2 + i * (sizeof(jz_dma_desc_8word))) >> 4; -+ -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | -+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address */ -+#endif -+ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ -+ desc->ddadr = (next << 24) + oob_per_eccsize; /* size: 7 bytes */ -+ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; -+ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptors for parities to be written to bch */ -+ desc = dma_desc_dec2; -+ for (i = 0; i < eccsteps; i++) { -+ next = (CPHYSADDR((u32)dma_desc_dec) + (i + 1) * (sizeof(jz_dma_desc_8word))) >> 4; -+ -+ desc->dcmd = -+ DMAC_DCMD_BLAST | DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | -+ DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA source address */ -+#endif -+ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ -+ desc->ddadr = (next << 24) + (eccbytes + 15) / DIV_DS_BCH; /* size: eccbytes bytes */ -+ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; -+ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ desc--; -+ desc->dcmd &= ~DMAC_DCMD_LINK; -+#if USE_IRQ -+ desc->dcmd |= DMAC_DCMD_TIE; -+#endif -+ -+ dma_cache_wback_inv((u32)dma_desc_nand_read, (2 + 2 + eccsteps * 3) * (sizeof(jz_dma_desc_8word))); -+ dma_cache_wback_inv((u32)pval_bch_ddr, 4 * 2); /* two words */ -+ -+ return 0; -+} -+ -+#endif /* CONFIG_MTD_NAND_DMA */ -+/* -+ * Main initialization routine -+ */ -+int __init jznand_init(void) -+{ -+ struct nand_chip *this; -+ int nr_partitions, ret, i; -+ -+ printk(KERN_INFO "JZ NAND init"); -+#if defined(CONFIG_MTD_NAND_DMA) -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ printk(KERN_INFO " DMA mode, using DMA buffer in NAND driver.\n"); -+#else -+ printk(KERN_INFO " DMA mode, using DMA buffer in upper layer.\n"); -+#endif -+#else -+ printk(KERN_INFO " CPU mode.\n"); -+#endif -+ -+ -+ /* Allocate memory for MTD device structure and private data */ -+ jz_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); -+ if (!jz_mtd) { -+ printk("Unable to allocate JzSOC NAND MTD device structure.\n"); -+ return -ENOMEM; -+ } -+ -+ /* Allocate memory for NAND when using only one plane */ -+ jz_mtd1 = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); -+ if (!jz_mtd1) { -+ printk ("Unable to allocate JzSOC NAND MTD device structure 1.\n"); -+ kfree(jz_mtd); -+ return -ENOMEM; -+ } -+ -+ /* Get pointer to private data */ -+ this = (struct nand_chip *)(&jz_mtd[1]); -+ -+ /* Initialize structures */ -+ memset((char *)jz_mtd, 0, sizeof(struct mtd_info)); -+ memset((char *)this, 0, sizeof(struct nand_chip)); -+ -+ /* Link the private data with the MTD structure */ -+ jz_mtd->priv = this; -+ -+ if (is_share_mode()) { -+ addr_offset = NAND_ADDR_OFFSET0; -+ cmd_offset = NAND_CMD_OFFSET0; -+ } else { -+ addr_offset = NAND_ADDR_OFFSET1; -+ cmd_offset = NAND_CMD_OFFSET1; -+ } -+ -+ /* Set & initialize NAND Flash controller */ -+ jz_device_setup(); -+ -+ /* Set address of NAND IO lines to static bank1 by default */ -+ this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; -+ this->IO_ADDR_W = (void __iomem *)NAND_DATA_PORT1; -+ this->cmd_ctrl = jz_hwcontrol; -+ this->dev_ready = jz_device_ready; -+ -+#ifdef CONFIG_MTD_HW_BCH_ECC -+ this->ecc.calculate = jzsoc_nand_calculate_bch_ecc; -+ this->ecc.correct = jzsoc_nand_bch_correct_data; -+ this->ecc.hwctl = jzsoc_nand_enable_bch_hwecc; -+ this->ecc.mode = NAND_ECC_HW; -+ this->ecc.size = 512; -+ this->ecc.read_page = nand_read_page_hwecc_bch; -+ this->ecc.write_page = nand_write_page_hwecc_bch; -+#if defined(CONFIG_MTD_HW_BCH_8BIT) -+ this->ecc.bytes = 13; -+#else -+ this->ecc.bytes = 7; -+#endif -+#endif -+ -+#ifdef CONFIG_MTD_SW_HM_ECC -+ this->ecc.mode = NAND_ECC_SOFT; -+#endif -+ /* 20 us command delay time */ -+ this->chip_delay = 20; -+ /* Scan to find existance of the device */ -+ ret = nand_scan_ident(jz_mtd, NAND_MAX_CHIPS); -+ -+ if (!ret) { -+ if (this->planenum == 2) { -+ /* reset nand functions */ -+ this->erase_cmd = single_erase_cmd_planes; -+ this->ecc.read_page = nand_read_page_hwecc_bch_planes; -+ this->ecc.write_page = nand_write_page_hwecc_bch_planes; -+ this->ecc.read_oob = nand_read_oob_std_planes; -+ this->ecc.write_oob = nand_write_oob_std_planes; -+ -+ printk(KERN_INFO "Nand using two-plane mode, " -+ "and resized to writesize:%d oobsize:%d blocksize:0x%x \n", -+ jz_mtd->writesize, jz_mtd->oobsize, jz_mtd->erasesize); -+ } -+ } -+ -+ /* Determine whether all the partitions will use multiple planes if supported */ -+ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition); -+ all_use_planes = 1; -+ for (i = 0; i < nr_partitions; i++) { -+ all_use_planes &= partition_info[i].use_planes; -+ } -+ -+ if (!ret) -+ ret = nand_scan_tail(jz_mtd); -+ -+ if (ret){ -+ kfree (jz_mtd1); -+ kfree (jz_mtd); -+ return -ENXIO; -+ } -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+ jz4750_nand_dma_init(jz_mtd); -+#endif -+ -+ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.read_page = nand_read_page_hwecc_bch; -+ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.write_page = nand_write_page_hwecc_bch; -+ -+ /* Register the partitions */ -+ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name); -+ -+ if ((this->planenum == 2) && !all_use_planes) { -+ for (i = 0; i < nr_partitions; i++) { -+ if (partition_info[i].use_planes) -+ add_mtd_partitions(jz_mtd, &partition_info[i], 1); -+ else -+ add_mtd_partitions(jz_mtd1, &partition_info[i], 1); -+ } -+ } else { -+ kfree(jz_mtd1); -+ add_mtd_partitions(jz_mtd, partition_info, nr_partitions); -+ } -+ return 0; -+} -+ -+module_init(jznand_init); -+ -+/* -+ * Clean up routine -+ */ -+#ifdef MODULE -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+static int jz4750_nand_dma_exit(struct mtd_info *mtd) -+{ -+ int pagesize = mtd->writesize / chip->planenum; -+ -+#if USE_IRQ -+ free_irq(IRQ_DMA_0 + nand_dma_chan, NULL); -+ free_irq(IRQ_DMA_0 + bch_dma_chan, NULL); -+#endif -+ -+ /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes), -+ * and the space for the value of ddr and dcs of channel 0 and channel -+ * nand_dma_chan (4 * (2 + 2) bytes) */ -+ kfree(errs); -+ -+ /* space for dma_desc_nand_read contains dma_desc_nand_prog, -+ * dma_desc_enc and dma_desc_dec */ -+ free_page((u32)dma_desc_nand_read); -+ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ if (pagesize < 4096) { -+ free_page((u32)prog_buf); -+ } else { -+ free_pages((u32)prog_buf, 1); -+ } -+#endif -+ -+ return 0; -+} -+#endif -+ -+static void __exit jznand_cleanup(void) -+{ -+#if defined(CONFIG_MTD_NAND_DMA) -+ jz4750_nand_dma_exit(jz_mtd); -+#endif -+ -+ /* Unregister partitions */ -+ del_mtd_partitions(jz_mtd); -+ -+ /* Unregister the device */ -+ del_mtd_device(jz_mtd); -+ -+ /* Free the MTD device structure */ -+ if ((this->planenum == 2) && !all_use_planes) -+ kfree (jz_mtd1); -+ kfree(jz_mtd); -+} -+ -+module_exit(jznand_cleanup); -+#endif ++/* ++ * linux/drivers/mtd/nand/jz4750_nand.c ++ * ++ * JZ4750 NAND driver ++ * ++ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc. ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* 32bit instead of 16byte burst is used by DMA to read or ++ write NAND and BCH avoiding grabbing bus for too long */ ++#define DMAC_DCMD_DS_NAND DMAC_DCMD_DS_32BIT ++#define DIV_DS_NAND 4 ++ ++#define DMAC_DCMD_DS_BCH DMAC_DCMD_DS_32BIT ++#define DIV_DS_BCH 4 ++ ++#define DEBUG1 0 ++#if DEBUG1 ++#define dprintk(n,x...) printk(n,##x) ++#else ++#define dprintk(n,x...) ++#endif ++ ++#if defined(CONFIG_MTD_HW_BCH_8BIT) ++#define __ECC_ENCODING __ecc_encoding_8bit ++#define __ECC_DECODING __ecc_decoding_8bit ++#define ERRS_SIZE 5 /* 5 words */ ++#else ++#define __ECC_ENCODING __ecc_encoding_4bit ++#define __ECC_DECODING __ecc_decoding_4bit ++#define ERRS_SIZE 3 /* 3 words */ ++#endif ++ ++#define NAND_DATA_PORT1 0xB8000000 /* read-write area in static bank 1 */ ++#define NAND_DATA_PORT2 0xB4000000 /* read-write area in static bank 2 */ ++#define NAND_DATA_PORT3 0xAC000000 /* read-write area in static bank 3 */ ++#define NAND_DATA_PORT4 0xA8000000 /* read-write area in static bank 4 */ ++ ++#define NAND_ADDR_OFFSET0 0x00010000 /* address port offset for share mode */ ++#define NAND_CMD_OFFSET0 0x00008000 /* command port offset for share mode */ ++#define NAND_ADDR_OFFSET1 0x00000010 /* address port offset for unshare mode */ ++#define NAND_CMD_OFFSET1 0x00000008 /* command port offset for unshare mode */ ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++#define USE_IRQ 1 ++enum { ++ NAND_NONE, ++ NAND_PROG, ++ NAND_READ ++}; ++static volatile u8 nand_status; ++static volatile int dma_ack = 0; ++static volatile int dma_ack1 = 0; ++static char nand_dma_chan; /* automatically select a free channel */ ++static char bch_dma_chan = 0; /* fixed to channel 0 */ ++static u32 *errs; ++static jz_dma_desc_8word *dma_desc_enc, *dma_desc_enc1, *dma_desc_dec, *dma_desc_dec1, *dma_desc_dec2, ++ *dma_desc_nand_prog, *dma_desc_nand_read; ++static u32 *pval_nand_ddr; ++static u8 *pval_nand_cmd_pgprog; /* for sending 0x11 or 0x10 when programing*/ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++u8 *prog_buf, *read_buf; ++#endif ++DECLARE_WAIT_QUEUE_HEAD(nand_prog_wait_queue); ++DECLARE_WAIT_QUEUE_HEAD(nand_read_wait_queue); ++#endif ++ ++struct buf_be_corrected { ++ u8 *data; ++ u8 *oob; ++}; ++ ++static u32 addr_offset; ++static u32 cmd_offset; ++ ++extern int global_page; /* for two-plane operations */ ++ ++/* ++ * MTD structure for JzSOC board ++ */ ++static struct mtd_info *jz_mtd = NULL; ++extern struct mtd_info *jz_mtd1; ++extern char all_use_planes; ++ ++/* ++ * Define partitions for flash devices ++ */ ++#if defined(CONFIG_JZ4750_FUWA) || defined(CONFIG_JZ4750D_FUWA1) ++static struct mtd_partition partition_info[] = { ++ {name:"NAND BOOT partition", ++ offset:0 * 0x100000, ++ size:4 * 0x100000, ++ use_planes: 0}, ++ {name:"NAND KERNEL partition", ++ offset:4 * 0x100000, ++ size:4 * 0x100000, ++ use_planes: 0}, ++ {name:"NAND ROOTFS partition", ++ offset:8 * 0x100000, ++ size:120 * 0x100000, ++ use_planes: 1}, ++ {name:"NAND DATA1 partition", ++ offset:128 * 0x100000, ++ size:128 * 0x100000, ++ use_planes: 1}, ++ {name:"NAND DATA2 partition", ++ offset:256 * 0x100000, ++ size:256 * 0x100000, ++ use_planes: 1}, ++ {name:"NAND VFAT partition", ++ offset:512 * 0x100000, ++ size:512 * 0x100000, ++ use_planes: 1}, ++}; ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10, /* reserved blocks of mtd3 */ ++ 20, /* reserved blocks of mtd4 */ ++ 20 ++}; /* reserved blocks of mtd5 */ ++#endif /* CONFIG_JZ4750_FUWA or CONFIG_JZ4750_APUS */ ++ ++#if defined(CONFIG_JZ4750_APUS) ++static struct mtd_partition partition_info[] = { ++ {name:"NAND BOOT partition", ++ offset:0 * 0x100000, ++ size:4 * 0x100000, ++ use_planes: 0}, ++ {name:"NAND KERNEL partition", ++ offset:4 * 0x100000, ++ size:4 * 0x100000, ++ use_planes: 0}, ++ {name:"NAND ROOTFS partition", ++ offset:8 * 0x100000, ++ size:504 * 0x100000, ++ use_planes: 0}, ++ {name:"NAND VFAT partition", ++ offset:512 * 0x100000, ++ size:512 * 0x100000, ++ use_planes: 1}, ++}; ++ ++ ++/* Define max reserved bad blocks for each partition. ++ * This is used by the mtdblock-jz.c NAND FTL driver only. ++ * ++ * The NAND FTL driver reserves some good blocks which can't be ++ * seen by the upper layer. When the bad block number of a partition ++ * exceeds the max reserved blocks, then there is no more reserved ++ * good blocks to be used by the NAND FTL driver when another bad ++ * block generated. ++ */ ++static int partition_reserved_badblocks[] = { ++ 2, /* reserved blocks of mtd0 */ ++ 2, /* reserved blocks of mtd1 */ ++ 10, /* reserved blocks of mtd2 */ ++ 10, /* reserved blocks of mtd3 */ ++}; ++#endif /* CONFIG_JZ4750_FUWA or CONFIG_JZ4750_APUS */ ++ ++/*------------------------------------------------------------------------- ++ * Following three functions are exported and used by the mtdblock-jz.c ++ * NAND FTL driver only. ++ */ ++ ++unsigned short get_mtdblock_write_verify_enable(void) ++{ ++#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE ++ return 1; ++#endif ++ return 0; ++} ++ ++EXPORT_SYMBOL(get_mtdblock_write_verify_enable); ++ ++unsigned short get_mtdblock_oob_copies(void) ++{ ++ return CONFIG_MTD_OOB_COPIES; ++} ++ ++EXPORT_SYMBOL(get_mtdblock_oob_copies); ++ ++int *get_jz_badblock_table(void) ++{ ++ return partition_reserved_badblocks; ++} ++ ++EXPORT_SYMBOL(get_jz_badblock_table); ++ ++/*-------------------------------------------------------------------------*/ ++ ++static void jz_hwcontrol(struct mtd_info *mtd, int dat, u32 ctrl) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ u32 nandaddr = (u32)this->IO_ADDR_W; ++ extern u8 nand_nce; /* defined in nand_base.c, indicates which chip select is used for current nand chip */ ++ ++ if (ctrl & NAND_CTRL_CHANGE) { ++ if (ctrl & NAND_NCE) { ++ switch (nand_nce) { ++ case NAND_NCE1: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE1; ++ break; ++ case NAND_NCE2: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE2; ++ break; ++ case NAND_NCE3: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE3; ++ break; ++ case NAND_NCE4: ++ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT4; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR |= EMC_NFCSR_NFCE4; ++ break; ++ default: ++ printk("error: no nand_nce 0x%x\n",nand_nce); ++ break; ++ } ++ } else { ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; ++ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; ++ } ++ ++ if (ctrl & NAND_ALE) ++ nandaddr = (u32)((u32)(this->IO_ADDR_W) | addr_offset); ++ else ++ nandaddr = (u32)((u32)(this->IO_ADDR_W) & ~addr_offset); ++ if (ctrl & NAND_CLE) ++ nandaddr = (u32)(nandaddr | cmd_offset); ++ else ++ nandaddr = (u32)(nandaddr & ~cmd_offset); ++ } ++ ++ this->IO_ADDR_W = (void __iomem *)nandaddr; ++ if (dat != NAND_CMD_NONE) { ++ writeb(dat, this->IO_ADDR_W); ++ /* printk("write cmd:0x%x to 0x%x\n",dat,(u32)this->IO_ADDR_W); */ ++ } ++} ++ ++static int jz_device_ready(struct mtd_info *mtd) ++{ ++ int ready, wait = 10; ++ while (wait--); ++ ready = __gpio_get_pin(91); ++ return ready; ++} ++ ++/* ++ * EMC setup ++ */ ++static void jz_device_setup(void) ++{ ++// PORT 0: ++// PORT 1: ++// PORT 2: ++// PIN/BIT N FUNC0 FUNC1 ++// 21 CS1# - ++// 22 CS2# - ++// 23 CS3# - ++// 24 CS4# - ++#define GPIO_CS2_N (32*2+22) ++#define GPIO_CS3_N (32*2+23) ++#define GPIO_CS4_N (32*2+24) ++#define SMCR_VAL 0x0d444400 ++ ++ __gpio_as_nand_8bit(1); ++ /* Set NFE bit */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE1; ++ /* Read/Write timings */ ++ REG_EMC_SMCR1 = SMCR_VAL; ++ ++#if defined(CONFIG_MTD_NAND_CS2) ++ __gpio_as_func0(GPIO_CS2_N); ++ /* Set NFE bit */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE2; ++ /* Read/Write timings */ ++ REG_EMC_SMCR2 = SMCR_VAL; ++#endif ++ ++#if defined(CONFIG_MTD_NAND_CS3) ++ __gpio_as_func0(GPIO_CS3_N); ++ /* Set NFE bit */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE3; ++ /* Read/Write timings */ ++ REG_EMC_SMCR3 = SMCR_VAL; ++#endif ++ ++#if defined(CONFIG_MTD_NAND_CS4) ++ __gpio_as_func0(GPIO_CS4_N); ++ /* Set NFE bit */ ++ REG_EMC_NFCSR |= EMC_NFCSR_NFE4; ++ /* Read/Write timings */ ++ REG_EMC_SMCR4 = SMCR_VAL; ++#endif ++} ++ ++#ifdef CONFIG_MTD_HW_BCH_ECC ++ ++static void jzsoc_nand_enable_bch_hwecc(struct mtd_info *mtd, int mode) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ int eccsize = this->ecc.size; ++ int eccbytes = this->ecc.bytes; ++ int eccsteps = this->ecc.steps / this->planenum; ++ int oob_per_eccsize = this->ecc.layout->eccpos[0] / eccsteps; ++ ++ REG_BCH_INTS = 0xffffffff; ++ if (mode == NAND_ECC_READ) { ++ __ECC_DECODING(); ++ __ecc_cnt_dec(eccsize + oob_per_eccsize + eccbytes); ++#if defined(CONFIG_MTD_NAND_DMA) ++ __ecc_dma_enable(); ++#endif ++ } ++ ++ if (mode == NAND_ECC_WRITE) { ++ __ECC_ENCODING(); ++ __ecc_cnt_enc(eccsize + oob_per_eccsize); ++#if defined(CONFIG_MTD_NAND_DMA) ++ __ecc_dma_enable(); ++#endif ++ } ++} ++ ++/** ++ * bch_correct ++ * @dat: data to be corrected ++ * @idx: the index of error bit in an eccsize ++ */ ++static void bch_correct(struct mtd_info *mtd, u8 * dat, int idx) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ int eccsize = this->ecc.size; ++ int eccsteps = this->ecc.steps / this->planenum; ++ int ecc_pos = this->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ int i, bit; /* the 'bit' of i byte is error */ ++ ++ i = (idx - 1) >> 3; ++ bit = (idx - 1) & 0x7; ++ ++ dprintk("error:i=%d, bit=%d\n",i,bit); ++ ++ if (i < eccsize){ ++ ((struct buf_be_corrected *)dat)->data[i] ^= (1 << bit); ++ } else if (i < eccsize + oob_per_eccsize) { ++ ((struct buf_be_corrected *)dat)->oob[i-eccsize] ^= (1 << bit); ++ } ++} ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++ ++/** ++ * jzsoc_nand_bch_correct_data ++ * @mtd: mtd info structure ++ * @dat: data to be corrected ++ * @errs0: pointer to the dma target buffer of bch decoding which stores BHINTS and ++ * BHERR0~3(8-bit BCH) or BHERR0~1(4-bit BCH) ++ * @calc_ecc: no used ++ */ ++static int jzsoc_nand_bch_correct_data(struct mtd_info *mtd, u_char * dat, u_char * errs0, u_char * calc_ecc) ++{ ++ u32 stat; ++ u32 *errs = (u32 *)errs0; ++ ++ if (REG_DMAC_DCCSR(0) & DMAC_DCCSR_BERR) { ++ stat = errs[0]; ++ dprintk("stat=%x err0:%x err1:%x \n", stat, errs[1], errs[2]); ++ ++ if (stat & BCH_INTS_ERR) { ++ if (stat & BCH_INTS_UNCOR) { ++ printk("NAND: Uncorrectable ECC error\n"); ++ return -1; ++ } else { ++ u32 errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; ++ switch (errcnt) { ++#if defined(CONFIG_MTD_HW_BCH_8BIT) ++ case 8: ++ bch_correct(mtd, dat, (errs[4] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ case 7: ++ bch_correct(mtd, dat, (errs[4] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ case 6: ++ bch_correct(mtd, dat, (errs[3] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ case 5: ++ bch_correct(mtd, dat, (errs[3] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++#endif ++ case 4: ++ bch_correct(mtd, dat, (errs[2] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ case 3: ++ bch_correct(mtd, dat, (errs[2] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ case 2: ++ bch_correct(mtd, dat, (errs[1] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ case 1: ++ bch_correct(mtd, dat, (errs[1] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ default: ++ break; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++#else /* cpu mode */ ++ ++/** ++ * jzsoc_nand_bch_correct_data ++ * @mtd: mtd info structure ++ * @dat: data to be corrected ++ * @read_ecc: pointer to ecc buffer calculated when nand writing ++ * @calc_ecc: no used ++ */ ++static int jzsoc_nand_bch_correct_data(struct mtd_info *mtd, u_char * dat, u_char * read_ecc, u_char * calc_ecc) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ int eccsize = this->ecc.size; ++ int eccbytes = this->ecc.bytes; ++ int eccsteps = this->ecc.steps / this->planenum; ++ int ecc_pos = this->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ short k; ++ u32 stat; ++ ++ /* Write data to REG_BCH_DR */ ++ for (k = 0; k < eccsize; k++) { ++ REG_BCH_DR = ((struct buf_be_corrected *)dat)->data[k]; ++ } ++ /* Write oob to REG_BCH_DR */ ++ for (k = 0; k < oob_per_eccsize; k++) { ++ REG_BCH_DR = ((struct buf_be_corrected *)dat)->oob[k]; ++ } ++ /* Write parities to REG_BCH_DR */ ++ for (k = 0; k < eccbytes; k++) { ++ REG_BCH_DR = read_ecc[k]; ++ } ++ ++ /* Wait for completion */ ++ __ecc_decode_sync(); ++ __ecc_disable(); ++ ++ /* Check decoding */ ++ stat = REG_BCH_INTS; ++ ++ if (stat & BCH_INTS_ERR) { ++ /* Error occurred */ ++ if (stat & BCH_INTS_UNCOR) { ++ printk("NAND: Uncorrectable ECC error--\n"); ++ return -1; ++ } else { ++ u32 errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; ++ switch (errcnt) { ++#if defined(CONFIG_MTD_HW_BCH_8BIT) ++ case 8: ++ bch_correct(mtd, dat, (REG_BCH_ERR3 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ /* FALL-THROUGH */ ++ case 7: ++ bch_correct(mtd, dat, (REG_BCH_ERR3 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ /* FALL-THROUGH */ ++ case 6: ++ bch_correct(mtd, dat, (REG_BCH_ERR2 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ /* FALL-THROUGH */ ++ case 5: ++ bch_correct(mtd, dat, (REG_BCH_ERR2 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ /* FALL-THROUGH */ ++#endif ++ case 4: ++ bch_correct(mtd, dat, (REG_BCH_ERR1 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ /* FALL-THROUGH */ ++ case 3: ++ bch_correct(mtd, dat, (REG_BCH_ERR1 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ /* FALL-THROUGH */ ++ case 2: ++ bch_correct(mtd, dat, (REG_BCH_ERR0 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); ++ /* FALL-THROUGH */ ++ case 1: ++ bch_correct(mtd, dat, (REG_BCH_ERR0 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); ++ return 0; ++ default: ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++#endif /* CONFIG_MTD_NAND_DMA */ ++ ++static int jzsoc_nand_calculate_bch_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) ++{ ++ struct nand_chip *this = (struct nand_chip *)(mtd->priv); ++ int eccsize = this->ecc.size; ++ int eccbytes = this->ecc.bytes; ++ int eccsteps = this->ecc.steps / this->planenum; ++ int ecc_pos = this->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ volatile u8 *paraddr = (volatile u8 *)BCH_PAR0; ++ short i; ++ ++ /* Write data to REG_BCH_DR */ ++ for (i = 0; i < eccsize; i++) { ++ REG_BCH_DR = ((struct buf_be_corrected *)dat)->data[i]; ++ } ++ /* Write oob to REG_BCH_DR */ ++ for (i = 0; i < oob_per_eccsize; i++) { ++ REG_BCH_DR = ((struct buf_be_corrected *)dat)->oob[i]; ++ } ++ __ecc_encode_sync(); ++ __ecc_disable(); ++ ++ for (i = 0; i < eccbytes; i++) { ++ ecc_code[i] = *paraddr++; ++ } ++ ++ return 0; ++} ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++ ++/** ++ * nand_write_page_hwecc_bch - [REPLACABLE] hardware ecc based page write function ++ * @mtd: mtd info structure ++ * @chip: nand chip info structure ++ * @buf: data buffer ++ */ ++static void nand_write_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf, u8 cmd_pgprog) ++{ ++ int eccsize = chip->ecc.size; ++ int eccsteps = chip->ecc.steps / chip->planenum; ++ int eccbytes = chip->ecc.bytes; ++ int ecc_pos = chip->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ int pagesize = mtd->writesize / chip->planenum; ++ int oobsize = mtd->oobsize / chip->planenum; ++ int i, err, timeout; ++ const u8 *databuf; ++ u8 *oobbuf; ++ jz_dma_desc_8word *desc; ++ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ memcpy(prog_buf, buf, pagesize); ++ memcpy(prog_buf + pagesize, chip->oob_poi, oobsize); ++ dma_cache_wback_inv((u32)prog_buf, pagesize + oobsize); ++#else ++ databuf = buf; ++ oobbuf = chip->oob_poi; ++ ++ /* descriptors for encoding data blocks */ ++ desc = dma_desc_enc; ++ for (i = 0; i < eccsteps; i++) { ++ desc->dsadr = CPHYSADDR((u32)databuf) + i * eccsize; /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ ++ dprintk("dma_desc_enc:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptors for encoding oob blocks */ ++ desc = dma_desc_enc1; ++ for (i = 0; i < eccsteps; i++) { ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address, 28/4 = 7bytes */ ++ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ ++ dprintk("dma_desc_enc1:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptor for nand programing data block */ ++ desc = dma_desc_nand_prog; ++ desc->dsadr = CPHYSADDR((u32)databuf); /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_W); /* It will be changed when using multiply chip select */ ++ dprintk("dma_desc_nand_prog:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ ++ /* descriptor for nand programing oob block */ ++ desc++; ++ desc->dsadr = CPHYSADDR((u32)oobbuf); /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_W); /* It will be changed when using multiply chip select */ ++ dprintk("dma_desc_oob_prog:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ ++ /* descriptor for __nand_cmd(CMD_PGPROG) */ ++ desc++; ++ *pval_nand_cmd_pgprog = cmd_pgprog; ++ desc->dsadr = CPHYSADDR((u32)pval_nand_cmd_pgprog); ++ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_R | cmd_offset); /* DMA target address: cmdport */ ++ if (cmd_pgprog == 0x10) ++ desc->dcmd |= DMAC_DCMD_LINK; /* __nand_sync() by a DMA descriptor */ ++ else if (cmd_pgprog == 0x11) ++ desc->dcmd &= ~DMAC_DCMD_LINK; /* __nand_sync() by polling */ ++ ++ dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 1) * (sizeof(jz_dma_desc_8word))); ++ dma_cache_wback_inv((u32)databuf, pagesize); ++ dma_cache_wback_inv((u32)oobbuf, oobsize); ++ /* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */ ++ dma_cache_wback_inv((u32)pval_nand_ddr, 4 * 8); /* 8 words, a cache line */ ++#endif ++ ++ REG_DMAC_DCCSR(bch_dma_chan) = 0; ++ REG_DMAC_DCCSR(nand_dma_chan) = 0; ++ ++ /* Setup DMA descriptor address */ ++ REG_DMAC_DDA(bch_dma_chan) = CPHYSADDR((u32)dma_desc_enc); ++ REG_DMAC_DDA(nand_dma_chan) = CPHYSADDR((u32)dma_desc_nand_prog); ++ ++ /* Setup request source */ ++ REG_DMAC_DRSR(bch_dma_chan) = DMAC_DRSR_RS_BCH_ENC; ++ REG_DMAC_DRSR(nand_dma_chan) = DMAC_DRSR_RS_AUTO; ++ ++ /* Setup DMA channel control/status register */ ++ REG_DMAC_DCCSR(bch_dma_chan) = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */ ++ ++ /* Enable DMA */ ++ REG_DMAC_DMACR(0) |= DMAC_DMACR_DMAE; ++ REG_DMAC_DMACR(nand_dma_chan/HALF_DMA_NUM) |= DMAC_DMACR_DMAE; ++ ++ /* Enable BCH encoding */ ++ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); ++ ++ dma_ack1 = 0; ++ nand_status = NAND_PROG; ++ ++ /* DMA doorbell set -- start DMA now ... */ ++ __dmac_channel_set_doorbell(bch_dma_chan); ++ ++#if USE_IRQ ++ if (cmd_pgprog == 0x10) { ++ dprintk("nand prog before wake up\n"); ++ err = wait_event_interruptible_timeout(nand_prog_wait_queue, dma_ack1, 3 * HZ); ++ nand_status = NAND_NONE; ++ dprintk("nand prog after wake up\n"); ++ if (!err) { ++ printk("*** NAND WRITE, Warning, wait event 3s timeout!\n"); ++ dump_jz_dma_channel(0); ++ dump_jz_dma_channel(nand_dma_chan); ++ printk("REG_BCH_CR=%x REG_BCH_CNT=0x%x REG_BCH_INTS=%x\n", REG_BCH_CR, REG_BCH_CNT, REG_BCH_INTS); ++ } ++ dprintk("timeout remain = %d\n", err); ++ } else if (cmd_pgprog == 0x11) { ++ timeout = 100000; ++ while ((!__dmac_channel_transmit_end_detected(nand_dma_chan)) && (timeout--)); ++ if (timeout <= 0) ++ printk("two-plane prog 0x11 timeout!\n"); ++ } ++#else ++ timeout = 100000; ++ while ((!__dmac_channel_transmit_end_detected(nand_dma_chan)) && (timeout--)); ++ while(!chip->dev_ready(mtd)); ++ if (timeout <= 0) ++ printk("not use irq, prog timeout!\n"); ++#endif ++} ++ ++static void nand_write_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf) ++{ ++ nand_write_page_hwecc_bch0(mtd, chip, buf, 0x10); ++} ++ ++static void nand_write_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf) ++{ ++ int page; ++ int pagesize = mtd->writesize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ nand_write_page_hwecc_bch0(mtd, chip, buf, 0x11); ++ chip->cmdfunc(mtd, 0x81, 0x00, page + ppb); ++ nand_write_page_hwecc_bch0(mtd, chip, buf + pagesize, 0x10); ++} ++ ++#else /* nand write in cpu mode */ ++ ++static void nand_write_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, ++ const uint8_t *buf) ++{ ++ int i, eccsize = chip->ecc.size; ++ int eccbytes = chip->ecc.bytes; ++ int eccsteps = chip->ecc.steps / chip->planenum; ++ int oob_per_eccsize = chip->ecc.layout->eccpos[0] / eccsteps; ++ int oobsize = mtd->oobsize / chip->planenum; ++ int ecctotal = chip->ecc.total / chip->planenum; ++ uint8_t *p = (uint8_t *)buf; ++ uint8_t *ecc_calc = chip->buffers->ecccalc; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ static struct buf_be_corrected buf_calc0; ++ struct buf_be_corrected *buf_calc = &buf_calc0; ++ ++ for (i = 0; i < eccsteps; i++, p += eccsize) { ++ buf_calc->data = (u8 *)buf + eccsize * i; ++ buf_calc->oob = chip->oob_poi + oob_per_eccsize * i; ++ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); ++ chip->ecc.calculate(mtd, (u8 *)buf_calc, &ecc_calc[eccbytes*i]); ++ chip->write_buf(mtd, p, eccsize); ++ } ++ ++ for (i = 0; i < ecctotal; i++) ++ chip->oob_poi[eccpos[i]] = ecc_calc[i]; ++ ++ chip->write_buf(mtd, chip->oob_poi, oobsize); ++} ++ ++/* nand write using two-plane mode */ ++static void nand_write_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ const uint8_t *buf) ++{ ++ int pagesize = mtd->writesize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ int page; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ nand_write_page_hwecc_bch(mtd, chip, buf); ++ ++ chip->cmdfunc(mtd, 0x11, -1, -1); /* send cmd 0x11 */ ++ ndelay(100); ++ while(!chip->dev_ready(mtd)); ++ ++ chip->cmdfunc(mtd, 0x81, 0x00, page + ppb); /* send cmd 0x81 */ ++ nand_write_page_hwecc_bch(mtd, chip, buf + pagesize); ++} ++#endif /* CONFIG_MTD_NAND_DMA */ ++ ++/** ++ * nand_read_page_hwecc_bch - [REPLACABLE] hardware ecc based page read function ++ * @mtd: mtd info structure ++ * @chip: nand chip info structure ++ * @buf: buffer to store read data ++ * ++ * Not for syndrome calculating ecc controllers which need a special oob layout ++ */ ++#if defined(CONFIG_MTD_NAND_DMA) ++static int nand_read_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf, u32 page) ++{ ++ int i, eccsize = chip->ecc.size; ++ int eccsteps = chip->ecc.steps / chip->planenum; ++ int eccbytes = chip->ecc.bytes; ++ int ecc_pos = chip->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ int pagesize = mtd->writesize / chip->planenum; ++ int oobsize = mtd->oobsize / chip->planenum; ++ u8 *databuf, *oobbuf; ++ jz_dma_desc_8word *desc; ++ int err; ++ u32 addrport, cmdport; ++ static struct buf_be_corrected buf_correct0; ++ ++ addrport = (u32)(chip->IO_ADDR_R) | addr_offset; ++ cmdport = (u32)(chip->IO_ADDR_R) | cmd_offset; ++ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ databuf = read_buf; ++ oobbuf = read_buf + pagesize; ++ ++ dma_cache_inv((u32)read_buf, pagesize + oobsize); // databuf should be invalidated. ++ memset(errs, 0, eccsteps * ERRS_SIZE * 4); ++ dma_cache_wback_inv((u32)errs, eccsteps * ERRS_SIZE * 4); ++#else ++ ++ databuf = buf; ++ oobbuf = chip->oob_poi; ++ ++ /* descriptor for nand reading data block */ ++ desc = dma_desc_nand_read; ++ desc->dsadr = CPHYSADDR((u32)chip->IO_ADDR_R); /* It will be changed when using multiply chip select */ ++ desc->dtadr = CPHYSADDR((u32)databuf); /* DMA target address */ ++ ++ dprintk("desc_nand_read:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ ++ /* descriptor for nand reading oob block */ ++ desc++; ++ desc->dsadr = CPHYSADDR((u32)chip->IO_ADDR_R); /* It will be changed when using multiply chip select */ ++ desc->dtadr = CPHYSADDR((u32)oobbuf); /* DMA target address */ ++ dprintk("desc_oob_read:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ ++ /* descriptors for data to be written to bch */ ++ desc = dma_desc_dec; ++ for (i = 0; i < eccsteps; i++) { ++ desc->dsadr = CPHYSADDR((u32)databuf) + i * eccsize; /* DMA source address */ ++ dprintk("dma_desc_dec:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptors for oob to be written to bch */ ++ desc = dma_desc_dec1; ++ for (i = 0; i < eccsteps; i++) { ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address */ ++ dprintk("dma_desc_dec1:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptors for parities to be written to bch */ ++ desc = dma_desc_dec2; ++ for (i = 0; i < eccsteps; i++) { ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA source address */ ++ dprintk("dma_desc_dec2:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ dma_cache_wback_inv((u32)dma_desc_nand_read, (2 + eccsteps * 3) * (sizeof(jz_dma_desc_8word))); ++ ++ memset(errs, 0, eccsteps * ERRS_SIZE * 4); ++ dma_cache_inv((u32)databuf, pagesize); // databuf should be invalidated. ++ dma_cache_inv((u32)oobbuf, oobsize); // oobbuf should be invalidated too ++ dma_cache_wback_inv((u32)errs, eccsteps * ERRS_SIZE * 4); ++#endif ++ REG_DMAC_DCCSR(bch_dma_chan) = 0; ++ REG_DMAC_DCCSR(nand_dma_chan) = 0; ++ ++ /* Setup DMA descriptor address */ ++ REG_DMAC_DDA(nand_dma_chan) = CPHYSADDR((u32)dma_desc_nand_read); ++ REG_DMAC_DDA(bch_dma_chan) = CPHYSADDR((u32)dma_desc_dec); ++ ++ /* Setup request source */ ++ REG_DMAC_DRSR(nand_dma_chan) = DMAC_DRSR_RS_NAND; ++ REG_DMAC_DRSR(bch_dma_chan) = DMAC_DRSR_RS_BCH_DEC; ++ ++ /* Enable DMA */ ++ REG_DMAC_DMACR(0) |= DMAC_DMACR_DMAE; ++ REG_DMAC_DMACR(nand_dma_chan/HALF_DMA_NUM) |= DMAC_DMACR_DMAE; ++ ++ /* Enable BCH decoding */ ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ ++ dma_ack = 0; ++ nand_status = NAND_READ; ++ /* DMA doorbell set -- start nand DMA now ... */ ++ __dmac_channel_set_doorbell(nand_dma_chan); ++ ++ /* Setup DMA channel control/status register */ ++ REG_DMAC_DCCSR(nand_dma_chan) = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; ++ ++#define __nand_cmd(n) (REG8(cmdport) = (n)) ++#define __nand_addr(n) (REG8(addrport) = (n)) ++ ++ __nand_cmd(NAND_CMD_READ0); ++ ++ __nand_addr(0); ++ if (pagesize != 512) ++ __nand_addr(0); ++ ++ __nand_addr(page & 0xff); ++ __nand_addr((page >> 8) & 0xff); ++ ++ /* One more address cycle for the devices whose number of page address bits > 16 */ ++ if (((chip->chipsize >> chip->page_shift) >> 16) - 1 > 0) ++ __nand_addr((page >> 16) & 0xff); ++ ++ if (pagesize != 512) ++ __nand_cmd(NAND_CMD_READSTART); ++ ++#if USE_IRQ ++ do { ++ err = wait_event_interruptible_timeout(nand_read_wait_queue, dma_ack, 3 * HZ); ++ }while(err == -ERESTARTSYS); ++ nand_status = NAND_NONE; ++ ++ if (!err) { ++ printk("*** NAND READ, Warning, wait event 3s timeout!\n"); ++ dump_jz_dma_channel(0); ++ dump_jz_dma_channel(nand_dma_chan); ++ printk("REG_BCH_CR=%x REG_BCH_CNT=0x%x REG_BCH_INTS=%x\n", REG_BCH_CR, REG_BCH_CNT, REG_BCH_INTS); ++ printk("databuf[0]=%x\n", databuf[0]); ++ } ++ dprintk("timeout remain = %d\n", err); ++#else ++ int timeout; ++ timeout = 100000; ++ while ((!__dmac_channel_transmit_end_detected(bch_dma_chan)) && (timeout--)); ++ if (timeout <= 0) { ++ printk("not use irq, NAND READ timeout!\n"); ++ } ++#endif ++ ++ for (i = 0; i < eccsteps; i++) { ++ int stat; ++ struct buf_be_corrected *buf_correct = &buf_correct0; ++ ++ buf_correct->data = databuf + eccsize * i; ++ buf_correct->oob = oobbuf + oob_per_eccsize * i; ++ ++ stat = chip->ecc.correct(mtd, (u8 *)buf_correct, (u8 *)&errs[i * ERRS_SIZE], NULL); ++ if (stat < 0) ++ mtd->ecc_stats.failed++; ++ else ++ mtd->ecc_stats.corrected += stat; ++ } ++ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ memcpy(buf, read_buf, pagesize); ++ memcpy(chip->oob_poi, read_buf + pagesize, oobsize); ++#endif ++ return 0; ++} ++ ++static int nand_read_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) ++{ ++ u32 page = global_page; ++ ++ nand_read_page_hwecc_bch0(mtd, chip, buf, page); ++ return 0; ++} ++ ++static int nand_read_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) ++{ ++ u32 page; ++ int pagesize = mtd->writesize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* read 1st page */ ++ nand_read_page_hwecc_bch0(mtd, chip, buf, page); ++ ++ /* read 2nd page */ ++ nand_read_page_hwecc_bch0(mtd, chip, buf + pagesize, page + ppb); ++ return 0; ++} ++ ++#else /* nand read in cpu mode */ ++ ++static int nand_read_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) ++{ ++ int i, eccsize = chip->ecc.size; ++ int eccbytes = chip->ecc.bytes; ++ int eccsteps = chip->ecc.steps / chip->planenum; ++ int ecc_pos = chip->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ uint8_t *ecc_calc = chip->buffers->ecccalc; ++ uint8_t *ecc_code = chip->buffers->ecccode; ++ uint32_t *eccpos = chip->ecc.layout->eccpos; ++ int pagesize = mtd->writesize / chip->planenum; ++ int oobsize = mtd->oobsize / chip->planenum; ++ int ecctotal = chip->ecc.total / chip->planenum; ++ static struct buf_be_corrected buf_correct0; ++ ++ chip->read_buf(mtd, buf, pagesize); ++ chip->read_buf(mtd, chip->oob_poi, oobsize); ++ ++ for (i = 0; i < ecctotal; i++) { ++ ecc_code[i] = chip->oob_poi[eccpos[i]]; ++ } ++ ++ for (i = 0; i < eccsteps; i++) { ++ int stat; ++ struct buf_be_corrected *buf_correct = &buf_correct0; ++ ++ buf_correct->data = buf + eccsize * i; ++ buf_correct->oob = chip->oob_poi + oob_per_eccsize * i; ++ ++ chip->ecc.hwctl(mtd, NAND_ECC_READ); ++ stat = chip->ecc.correct(mtd, (u8 *)buf_correct, &ecc_code[eccbytes*i], &ecc_calc[eccbytes*i]); ++ if (stat < 0) ++ mtd->ecc_stats.failed++; ++ else ++ mtd->ecc_stats.corrected += stat; ++ } ++ ++ return 0; ++} ++ ++static int nand_read_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) ++{ ++ int pagesize = mtd->writesize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ uint32_t page; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* Read first page */ ++ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); ++ nand_read_page_hwecc_bch(mtd, chip, buf); ++ ++ /* Read 2nd page */ ++ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page + ppb); ++ nand_read_page_hwecc_bch(mtd, chip, buf+pagesize); ++ return 0; ++} ++#endif /* CONFIG_MTD_NAND_DMA */ ++ ++#endif /* CONFIG_MTD_HW_BCH_ECC */ ++ ++/* read oob using two-plane mode */ ++static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ int global_page, int sndcmd) ++{ ++ int page; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* Read first page OOB */ ++ if (sndcmd) { ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ } ++ chip->read_buf(mtd, chip->oob_poi, oobsize); ++ /* Read second page OOB */ ++ page += ppb; ++ if (sndcmd) { ++ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); ++ sndcmd = 0; ++ } ++ chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize); ++ return 0; ++} ++ ++/* write oob using two-plane mode */ ++static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, ++ int global_page) ++{ ++ int status = 0, page; ++ const uint8_t *buf = chip->oob_poi; ++ int pagesize = mtd->writesize >> 1; ++ int oobsize = mtd->oobsize >> 1; ++ int ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x80, pagesize, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ chip->write_buf(mtd, buf, oobsize); ++ /* Send first command to program the OOB data */ ++ chip->cmdfunc(mtd, 0x11, -1, -1); ++ ndelay(100); ++ status = chip->waitfunc(mtd, chip); ++ ++ page += ppb; ++ buf += oobsize; ++ chip->cmdfunc(mtd, 0x81, pagesize, page); ++ chip->write_buf(mtd, buf, oobsize); ++ /* Send command to program the OOB data */ ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++ /* Wait long R/B */ ++ ndelay(100); ++ status = chip->waitfunc(mtd, chip); ++ ++ return status & NAND_STATUS_FAIL ? -EIO : 0; ++} ++ ++/* nand erase using two-plane mode */ ++static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page) ++{ ++ struct nand_chip *chip = mtd->priv; ++ int page, ppb = mtd->erasesize / mtd->writesize; ++ ++ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ ++ ++ /* send cmd 0x60, the MSB should be valid if realplane is 4 */ ++ if (chip->realplanenum == 2) ++ chip->cmdfunc(mtd, 0x60, -1, 0x00); ++ else ++ chip->cmdfunc(mtd, 0x60, -1, page & (1 << (chip->chip_shift - chip->page_shift))); ++ ++ page += ppb; ++ chip->cmdfunc(mtd, 0x60, -1, page & (~(ppb-1))); /* send cmd 0x60 */ ++ ++ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */ ++ /* Do not need wait R/B or check status */ ++} ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++ ++#if USE_IRQ ++static irqreturn_t nand_dma_irq(int irq, void *dev_id) ++{ ++ u8 dma_chan; ++ volatile int wakeup = 0; ++ ++ dma_chan = irq - IRQ_DMA_0; ++ ++ dprintk("jz4750_dma_irq %d, channel %d\n", irq, dma_chan); ++ ++ if (__dmac_channel_transmit_halt_detected(dma_chan)) { ++ __dmac_channel_clear_transmit_halt(dma_chan); ++ wakeup = 1; ++ printk("DMA HALT\n"); ++ } ++ ++ if (__dmac_channel_address_error_detected(dma_chan)) { ++ ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ __dmac_channel_clear_address_error(dma_chan); ++ ++ REG_DMAC_DSAR(dma_chan) = 0; /* reset source address register */ ++ REG_DMAC_DTAR(dma_chan) = 0; /* reset destination address register */ ++ ++ /* clear address error in DMACR */ ++ REG_DMAC_DMACR((dma_chan / HALF_DMA_NUM)) &= ~(1 << 2); ++ wakeup = 1; ++ printk("DMA address error!\n"); ++ } ++ ++ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { ++ __dmac_channel_clear_descriptor_invalid(dma_chan); ++ wakeup = 1; ++ printk("DMA DESC INVALID\n"); ++ } ++#if 1 ++ ++ while (!__dmac_channel_transmit_end_detected(dma_chan)); ++ ++ if (__dmac_channel_count_terminated_detected(dma_chan)) { ++ dprintk("DMA CT\n"); ++ __dmac_channel_clear_count_terminated(dma_chan); ++ wakeup = 0; ++ } ++#endif ++ ++ if (__dmac_channel_transmit_end_detected(dma_chan)) { ++ dprintk("DMA TT\n"); ++ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ ++ __dmac_channel_clear_transmit_end(dma_chan); ++ wakeup = 1; ++ } ++ ++ if (wakeup) { ++ dprintk("ack %d irq , wake up dma_chan %d nand_status %d\n", dma_ack, dma_chan, nand_status); ++ /* wakeup wait event */ ++ if ((dma_chan == nand_dma_chan) && (nand_status == NAND_PROG)) { ++ dprintk("nand prog dma irq, wake up----\n"); ++ dma_ack1 = 1; ++ wake_up_interruptible(&nand_prog_wait_queue); ++ } ++ ++ if ((dma_chan == bch_dma_chan) && (nand_status == NAND_READ)) { ++ dprintk("nand read irq, wake up----\n"); ++ dma_ack = 1; ++ wake_up_interruptible(&nand_read_wait_queue); ++ } ++ wakeup = 0; ++ } ++ ++ return IRQ_HANDLED; ++} ++#endif /* USE_IRQ */ ++ ++static int jz4750_nand_dma_init(struct mtd_info *mtd) ++{ ++ struct nand_chip *chip = mtd->priv; ++ int eccsize = chip->ecc.size; ++ int eccsteps = chip->ecc.steps / chip->planenum; ++ int eccbytes = chip->ecc.bytes; ++ int ecc_pos = chip->ecc.layout->eccpos[0]; ++ int oob_per_eccsize = ecc_pos / eccsteps; ++ int pagesize = mtd->writesize / chip->planenum; ++ int oobsize = mtd->oobsize / chip->planenum; ++ int i, err; ++ jz_dma_desc_8word *desc, *dma_desc_bch_ddr, *dma_desc_nand_ddr, *dma_desc_nand_cmd_pgprog; ++ u32 *pval_nand_dcs, *pval_bch_ddr, *pval_bch_dcs, *dummy; ++ u32 next; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ u8 *oobbuf; ++#endif ++ ++#if USE_IRQ ++ if ((nand_dma_chan = jz_request_dma(DMA_ID_NAND, "nand read or write", nand_dma_irq, IRQF_DISABLED, NULL)) < 0) { ++ printk("can't reqeust DMA nand channel.\n"); ++ return 0; ++ } ++ dprintk("nand dma channel:%d----\n", nand_dma_chan); ++ ++ if ((err = request_irq(IRQ_DMA_0 + bch_dma_chan, nand_dma_irq, IRQF_DISABLED, "bch_dma", NULL))) { ++ printk("bch_dma irq request err\n"); ++ return 0; ++ } ++#else ++ if ((nand_dma_chan = jz_request_dma(DMA_ID_NAND, "nand read or write", NULL, IRQF_DISABLED, NULL)) < 0) { ++ printk("can't reqeust DMA nand channel.\n"); ++ return 0; ++ } ++ dprintk("nand dma channel:%d----\n", nand_dma_chan); ++#endif ++ ++ __dmac_channel_enable_clk(nand_dma_chan); ++ __dmac_channel_enable_clk(bch_dma_chan); ++ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ if (pagesize < 4096) { ++ read_buf = prog_buf = (u8 *) __get_free_page(GFP_KERNEL); ++ } else { ++ read_buf = prog_buf = (u8 *) __get_free_pages(GFP_KERNEL, 1); ++ } ++ if (!read_buf) ++ return -ENOMEM; ++#endif ++ /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes), and the space for the value ++ * of ddr and dcs of channel 0 and channel nand_dma_chan (4 * (2 + 2) bytes) */ ++ errs = (u32 *)kmalloc(4 * (2 + 2 + 5 * eccsteps), GFP_KERNEL); ++ if (!errs) ++ return -ENOMEM; ++ ++ pval_nand_ddr = errs + 5 * eccsteps; ++ pval_nand_dcs = pval_nand_ddr + 1; ++ pval_bch_ddr = pval_nand_dcs + 1; ++ pval_bch_dcs = pval_bch_ddr + 1; ++ /* space for nand prog waiting target, the content is useless */ ++ dummy = pval_bch_dcs + 1; ++ /* space to store CMD_PGPROG(0x10) or 0x11 */ ++ pval_nand_cmd_pgprog = (u8 *)(dummy + 1); ++ ++ /* desc can't across 4KB boundary, as desc base address is fixed */ ++ /* space of descriptors for nand reading data and oob blocks */ ++ dma_desc_nand_read = (jz_dma_desc_8word *) __get_free_page(GFP_KERNEL); ++ if (!dma_desc_nand_read) ++ return -ENOMEM; ++ ++ /* space of descriptors for bch decoding */ ++ dma_desc_dec = dma_desc_nand_read + 2; ++ dma_desc_dec1 = dma_desc_dec + eccsteps; ++ dma_desc_dec2 = dma_desc_dec + eccsteps * 2; ++ ++ /* space of descriptors for notifying bch channel */ ++ dma_desc_bch_ddr = dma_desc_dec2 + eccsteps; ++ ++ /* space of descriptors for bch encoding */ ++ dma_desc_enc = dma_desc_bch_ddr + 2; ++ dma_desc_enc1 = dma_desc_enc + eccsteps; ++ ++ /* space of descriptors for nand programing data and oob blocks */ ++ dma_desc_nand_prog = dma_desc_enc1 + eccsteps; ++ ++ /* space of descriptors for nand prog waiting, including pgprog and sync */ ++ dma_desc_nand_cmd_pgprog = dma_desc_nand_prog + 2; ++ ++ /* space of descriptors for notifying nand channel, including ddr and dcsr */ ++ dma_desc_nand_ddr = dma_desc_nand_cmd_pgprog + 2; ++ ++/************************************* ++ * Setup of nand programing descriptors ++ *************************************/ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ oobbuf = prog_buf + pagesize; ++#endif ++ /* set descriptor for encoding data blocks */ ++ desc = dma_desc_enc; ++ for (i = 0; i < eccsteps; i++) { ++ next = (CPHYSADDR((u32)dma_desc_enc1) + i * (sizeof(jz_dma_desc_8word))) >> 4; ++ ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | ++ DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)prog_buf) + i * eccsize; /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ ++#endif ++ desc->ddadr = (next << 24) + eccsize / DIV_DS_BCH; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_BCH_ENC; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ desc++; ++ } ++ ++ /* set descriptor for encoding oob blocks */ ++ desc = dma_desc_enc1; ++ for (i = 0; i < eccsteps; i++) { ++ next = (CPHYSADDR((u32)dma_desc_enc) + (i + 1) * (sizeof(jz_dma_desc_8word))) >> 4; ++ ++ desc->dcmd = ++ DMAC_DCMD_BLAST | DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | ++ DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address, 28/4 = 7bytes */ ++ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ ++#endif ++ desc->ddadr = (next << 24) + (oob_per_eccsize + 3) / 4; /* size: 7 bytes -> 2 words */ ++ desc->dreqt = DMAC_DRSR_RS_BCH_ENC; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ desc++; ++ } ++ ++ next = (CPHYSADDR((u32)dma_desc_nand_ddr)) >> 4; ++ desc--; ++ desc->ddadr = (next << 24) + (oob_per_eccsize + 3) / 4; ++ ++ /* set the descriptor to set door bell of nand_dma_chan for programing nand */ ++ desc = dma_desc_nand_ddr; ++ *pval_nand_ddr = 1 << (nand_dma_chan - nand_dma_chan / HALF_DMA_NUM * HALF_DMA_NUM); ++ next = (CPHYSADDR((u32)dma_desc_nand_ddr) + sizeof(jz_dma_desc_8word)) >> 4; ++ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; ++ desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */ ++ desc->dtadr = CPHYSADDR(DMAC_DMADBSR(nand_dma_chan / HALF_DMA_NUM)); /* nand_dma_chan's descriptor addres register */ ++ desc->ddadr = (next << 24) + 1; /* size: 1 word */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("*pval_nand_ddr=0x%x\n", *pval_nand_ddr); ++ ++ /* set the descriptor to write dccsr of nand_dma_chan for programing nand, dccsr should be set at last */ ++ desc++; ++ *pval_nand_dcs = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; /* set value for writing ddr to enable channel nand_dma_chan */ ++ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; ++ desc->dsadr = CPHYSADDR((u32)pval_nand_dcs); /* DMA source address */ ++ desc->dtadr = CPHYSADDR(DMAC_DCCSR(nand_dma_chan)); /* address of dma door bell set register */ ++ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("*pval_nand_dcs=0x%x\n", *pval_nand_dcs); ++ ++ /* set descriptor for nand programing data block */ ++ desc = dma_desc_nand_prog; ++ next = (CPHYSADDR((u32)dma_desc_nand_prog) + sizeof(jz_dma_desc_8word)) >> 4; ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | ++ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)prog_buf); /* DMA source address */ ++#endif ++ desc->dtadr = CPHYSADDR((u32)(chip->IO_ADDR_W)); /* DMA target address */ ++ desc->ddadr = (next << 24) + pagesize / DIV_DS_NAND; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* set descriptor for nand programing oob block */ ++ desc++; ++ next = (CPHYSADDR((u32)dma_desc_nand_cmd_pgprog)) >> 4; ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | ++ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)oobbuf); /* DMA source address */ ++#endif ++ desc->dtadr = CPHYSADDR((u32)(chip->IO_ADDR_W)); /* DMA target address: dataport */ ++ desc->ddadr = (next << 24) + oobsize / DIV_DS_NAND; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* set descriptor for __nand_cmd(CMD_PGPROG) */ ++ desc = dma_desc_nand_cmd_pgprog; ++ *pval_nand_cmd_pgprog = NAND_CMD_PAGEPROG; ++ next = (CPHYSADDR((u32)dma_desc_nand_cmd_pgprog) + sizeof(jz_dma_desc_8word)) >> 4; ++ desc->dcmd = ++ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_8BIT | DMAC_DCMD_LINK; ++ desc->dsadr = CPHYSADDR((u32)pval_nand_cmd_pgprog); /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_R | cmd_offset); /* DMA target address: cmdport */ ++ desc->ddadr = (next << 24) + 1; /* size: 1 byte */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* set descriptor for __nand_sync() */ ++ desc++; ++#if USE_IRQ ++ desc->dcmd = ++ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_TIE; ++#else ++ desc->dcmd = ++ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; ++#endif ++ desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */ ++ desc->dtadr = CPHYSADDR((u32)dummy); /* DMA target address, the content is useless */ ++ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ ++ desc->dreqt = DMAC_DRSR_RS_NAND; ++ dprintk("1cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* eccsteps*2 + 2 + 2 + 2: ++ dma_desc_enc + dma_desc_enc1 + dma_desc_nand_prog(oob) + dma_desc_nand_ddr(csr) ++ + dma_desc_nand_cmd_pgprog(sync) */ ++ dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 2 + 2) * (sizeof(jz_dma_desc_8word))); ++ /* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */ ++ dma_cache_wback_inv((u32)pval_nand_ddr, 4 * 8); /* 8 words, a cache line */ ++ ++/************************************* ++ * Setup of nand reading descriptors ++ *************************************/ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ oobbuf = read_buf + pagesize; ++#endif ++ /* set descriptor for nand reading data block */ ++ desc = dma_desc_nand_read; ++ next = (CPHYSADDR((u32)dma_desc_nand_read) + sizeof(jz_dma_desc_8word)) >> 4; ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | ++ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; ++ desc->dsadr = CPHYSADDR((u32)(chip->IO_ADDR_R)); /* DMA source address */ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dtadr = CPHYSADDR((u32)read_buf); /* DMA target address */ ++#endif ++ desc->ddadr = (next << 24) + pagesize / DIV_DS_NAND; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_NAND; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* set descriptor for nand reading oob block */ ++ desc++; ++ next = (CPHYSADDR((u32)dma_desc_bch_ddr)) >> 4; ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | ++ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; ++ desc->dsadr = CPHYSADDR((u32)(chip->IO_ADDR_R)); /* DMA source address */ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dtadr = CPHYSADDR((u32)oobbuf); /* DMA target address */ ++#endif ++ desc->ddadr = (next << 24) + oobsize / DIV_DS_NAND; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); ++ ++ /* set the descriptor to set door bell for bch */ ++ desc = dma_desc_bch_ddr; ++ *pval_bch_ddr = DMAC_DMADBSR_DBS0; // set value for writing ddr to enable channel 0 ++ next = (CPHYSADDR((u32)dma_desc_bch_ddr) + sizeof(jz_dma_desc_8word)) >> 4; ++ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; ++ desc->dsadr = CPHYSADDR((u32)pval_bch_ddr); /* DMA source address */ ++ desc->dtadr = CPHYSADDR(DMAC_DMADBSR(0)); /* channel 1's descriptor addres register */ ++ desc->ddadr = (next << 24) + 1; /* size: 1 word */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ ++ /* set descriptor for writing dcsr */ ++ desc++; ++ *pval_bch_dcs = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; // set value for writing ddr to enable channel 1 ++ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; ++ desc->dsadr = CPHYSADDR((u32)pval_bch_dcs); /* DMA source address */ ++ desc->dtadr = CPHYSADDR(DMAC_DCCSR(bch_dma_chan)); /* address of dma door bell set register */ ++ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ ++ desc->dreqt = DMAC_DRSR_RS_AUTO; ++ ++ /* descriptors for data to be written to bch */ ++ desc = dma_desc_dec; ++ for (i = 0; i < eccsteps; i++) { ++ next = CPHYSADDR((u32)dma_desc_dec1 + i * (sizeof(jz_dma_desc_8word))) >> 4; ++ ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | ++ DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)read_buf) + i * eccsize; /* DMA source address */ ++#endif ++ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ ++ desc->ddadr = (next << 24) + eccsize / DIV_DS_BCH; /* size: eccsize bytes */ ++ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; ++ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptors for oob to be written to bch */ ++ desc = dma_desc_dec1; ++ for (i = 0; i < eccsteps; i++) { ++ next = CPHYSADDR((u32)dma_desc_dec2 + i * (sizeof(jz_dma_desc_8word))) >> 4; ++ ++ desc->dcmd = ++ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | ++ DMAC_DCMD_DS_8BIT | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address */ ++#endif ++ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ ++ desc->ddadr = (next << 24) + oob_per_eccsize; /* size: 7 bytes */ ++ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; ++ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ ++ /* descriptors for parities to be written to bch */ ++ desc = dma_desc_dec2; ++ for (i = 0; i < eccsteps; i++) { ++ next = (CPHYSADDR((u32)dma_desc_dec) + (i + 1) * (sizeof(jz_dma_desc_8word))) >> 4; ++ ++ desc->dcmd = ++ DMAC_DCMD_BLAST | DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | ++ DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ desc->dsadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA source address */ ++#endif ++ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ ++ desc->ddadr = (next << 24) + (eccbytes + 15) / DIV_DS_BCH; /* size: eccbytes bytes */ ++ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; ++ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, ++ desc->ddadr); ++ desc++; ++ } ++ desc--; ++ desc->dcmd &= ~DMAC_DCMD_LINK; ++#if USE_IRQ ++ desc->dcmd |= DMAC_DCMD_TIE; ++#endif ++ ++ dma_cache_wback_inv((u32)dma_desc_nand_read, (2 + 2 + eccsteps * 3) * (sizeof(jz_dma_desc_8word))); ++ dma_cache_wback_inv((u32)pval_bch_ddr, 4 * 2); /* two words */ ++ ++ return 0; ++} ++ ++#endif /* CONFIG_MTD_NAND_DMA */ ++/* ++ * Main initialization routine ++ */ ++int __init jznand_init(void) ++{ ++ struct nand_chip *this; ++ int nr_partitions, ret, i; ++ ++ printk(KERN_INFO "JZ NAND init"); ++#if defined(CONFIG_MTD_NAND_DMA) ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ printk(KERN_INFO " DMA mode, using DMA buffer in NAND driver.\n"); ++#else ++ printk(KERN_INFO " DMA mode, using DMA buffer in upper layer.\n"); ++#endif ++#else ++ printk(KERN_INFO " CPU mode.\n"); ++#endif ++ ++ ++ /* Allocate memory for MTD device structure and private data */ ++ jz_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); ++ if (!jz_mtd) { ++ printk("Unable to allocate JzSOC NAND MTD device structure.\n"); ++ return -ENOMEM; ++ } ++ ++ /* Allocate memory for NAND when using only one plane */ ++ jz_mtd1 = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); ++ if (!jz_mtd1) { ++ printk ("Unable to allocate JzSOC NAND MTD device structure 1.\n"); ++ kfree(jz_mtd); ++ return -ENOMEM; ++ } ++ ++ /* Get pointer to private data */ ++ this = (struct nand_chip *)(&jz_mtd[1]); ++ ++ /* Initialize structures */ ++ memset((char *)jz_mtd, 0, sizeof(struct mtd_info)); ++ memset((char *)this, 0, sizeof(struct nand_chip)); ++ ++ /* Link the private data with the MTD structure */ ++ jz_mtd->priv = this; ++ ++ if (is_share_mode()) { ++ addr_offset = NAND_ADDR_OFFSET0; ++ cmd_offset = NAND_CMD_OFFSET0; ++ } else { ++ addr_offset = NAND_ADDR_OFFSET1; ++ cmd_offset = NAND_CMD_OFFSET1; ++ } ++ ++ /* Set & initialize NAND Flash controller */ ++ jz_device_setup(); ++ ++ /* Set address of NAND IO lines to static bank1 by default */ ++ this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; ++ this->IO_ADDR_W = (void __iomem *)NAND_DATA_PORT1; ++ this->cmd_ctrl = jz_hwcontrol; ++ this->dev_ready = jz_device_ready; ++ ++#ifdef CONFIG_MTD_HW_BCH_ECC ++ this->ecc.calculate = jzsoc_nand_calculate_bch_ecc; ++ this->ecc.correct = jzsoc_nand_bch_correct_data; ++ this->ecc.hwctl = jzsoc_nand_enable_bch_hwecc; ++ this->ecc.mode = NAND_ECC_HW; ++ this->ecc.size = 512; ++ this->ecc.read_page = nand_read_page_hwecc_bch; ++ this->ecc.write_page = nand_write_page_hwecc_bch; ++#if defined(CONFIG_MTD_HW_BCH_8BIT) ++ this->ecc.bytes = 13; ++#else ++ this->ecc.bytes = 7; ++#endif ++#endif ++ ++#ifdef CONFIG_MTD_SW_HM_ECC ++ this->ecc.mode = NAND_ECC_SOFT; ++#endif ++ /* 20 us command delay time */ ++ this->chip_delay = 20; ++ /* Scan to find existance of the device */ ++ ret = nand_scan_ident(jz_mtd, NAND_MAX_CHIPS); ++ ++ if (!ret) { ++ if (this->planenum == 2) { ++ /* reset nand functions */ ++ this->erase_cmd = single_erase_cmd_planes; ++ this->ecc.read_page = nand_read_page_hwecc_bch_planes; ++ this->ecc.write_page = nand_write_page_hwecc_bch_planes; ++ this->ecc.read_oob = nand_read_oob_std_planes; ++ this->ecc.write_oob = nand_write_oob_std_planes; ++ ++ printk(KERN_INFO "Nand using two-plane mode, " ++ "and resized to writesize:%d oobsize:%d blocksize:0x%x \n", ++ jz_mtd->writesize, jz_mtd->oobsize, jz_mtd->erasesize); ++ } ++ } ++ ++ /* Determine whether all the partitions will use multiple planes if supported */ ++ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition); ++ all_use_planes = 1; ++ for (i = 0; i < nr_partitions; i++) { ++ all_use_planes &= partition_info[i].use_planes; ++ } ++ ++ if (!ret) ++ ret = nand_scan_tail(jz_mtd); ++ ++ if (ret){ ++ kfree (jz_mtd1); ++ kfree (jz_mtd); ++ return -ENXIO; ++ } ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++ jz4750_nand_dma_init(jz_mtd); ++#endif ++ ++ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.read_page = nand_read_page_hwecc_bch; ++ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.write_page = nand_write_page_hwecc_bch; ++ ++ /* Register the partitions */ ++ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name); ++ ++ if ((this->planenum == 2) && !all_use_planes) { ++ for (i = 0; i < nr_partitions; i++) { ++ if (partition_info[i].use_planes) ++ add_mtd_partitions(jz_mtd, &partition_info[i], 1); ++ else ++ add_mtd_partitions(jz_mtd1, &partition_info[i], 1); ++ } ++ } else { ++ kfree(jz_mtd1); ++ add_mtd_partitions(jz_mtd, partition_info, nr_partitions); ++ } ++ return 0; ++} ++ ++module_init(jznand_init); ++ ++/* ++ * Clean up routine ++ */ ++#ifdef MODULE ++ ++#if defined(CONFIG_MTD_NAND_DMA) ++static int jz4750_nand_dma_exit(struct mtd_info *mtd) ++{ ++ int pagesize = mtd->writesize / chip->planenum; ++ ++#if USE_IRQ ++ free_irq(IRQ_DMA_0 + nand_dma_chan, NULL); ++ free_irq(IRQ_DMA_0 + bch_dma_chan, NULL); ++#endif ++ ++ /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes), ++ * and the space for the value of ddr and dcs of channel 0 and channel ++ * nand_dma_chan (4 * (2 + 2) bytes) */ ++ kfree(errs); ++ ++ /* space for dma_desc_nand_read contains dma_desc_nand_prog, ++ * dma_desc_enc and dma_desc_dec */ ++ free_page((u32)dma_desc_nand_read); ++ ++#if defined(CONFIG_MTD_NAND_DMABUF) ++ if (pagesize < 4096) { ++ free_page((u32)prog_buf); ++ } else { ++ free_pages((u32)prog_buf, 1); ++ } ++#endif ++ ++ return 0; ++} ++#endif ++ ++static void __exit jznand_cleanup(void) ++{ ++#if defined(CONFIG_MTD_NAND_DMA) ++ jz4750_nand_dma_exit(jz_mtd); ++#endif ++ ++ /* Unregister partitions */ ++ del_mtd_partitions(jz_mtd); ++ ++ /* Unregister the device */ ++ del_mtd_device(jz_mtd); ++ ++ /* Free the MTD device structure */ ++ if ((this->planenum == 2) && !all_use_planes) ++ kfree (jz_mtd1); ++ kfree(jz_mtd); ++} ++ ++module_exit(jznand_cleanup); ++#endif --- linux-2.6.24.7.old/drivers/mtd/nand/nand_base.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/mtd/nand/nand_base.c 2009-04-12 18:13:57.000000000 +0200 @@ -52,6 +52,16 @@ #include #endif - + +#include + -+u8 nand_nce; /* indicates which chip select on JZSOC is used for ++u8 nand_nce; /* indicates which chip select on JZSOC is used for + current nand chip */ +int global_page; /* page index of large page used for nand with multiple planes */ + +struct mtd_info *jz_mtd1 = NULL; /* for 1 plane operation */ -+char all_use_planes = 1; /* indicates whether multiple planes operation is used ++char all_use_planes = 1; /* indicates whether multiple planes operation is used + by all partitions if multiple planes is supported by NAND */ + /* Define default oob placement schemes for large and small page devices */ @@ -73964,16 +17032,16 @@ .eccbytes = 3, @@ -72,6 +82,20 @@ }; - + static struct nand_ecclayout nand_oob_64 = { +#if defined(CONFIG_MTD_HW_RS_ECC) || defined(CONFIG_MTD_HW_BCH_ECC) +/* Reed-Solomon ECC or BCH ECC */ + .eccbytes = 36, + .eccpos = { + 28, 29, 30, 31, -+ 32, 33, 34, 35, 36, 37, 38, 39, -+ 40, 41, 42, 43, 44, 45, 46, 47, -+ 48, 49, 50, 51, 52, 53, 54, 55, ++ 32, 33, 34, 35, 36, 37, 38, 39, ++ 40, 41, 42, 43, 44, 45, 46, 47, ++ 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { + {.offset = 2, @@ -74029,9 +17097,9 @@ + .eccbytes = 104, + .eccpos = { + 24, 25, 26, 27, 28, 29, 30, 31, -+ 32, 33, 34, 35, 36, 37, 38, 39, -+ 40, 41, 42, 43, 44, 45, 46, 47, -+ 48, 49, 50, 51, 52, 53, 54, 55, ++ 32, 33, 34, 35, 36, 37, 38, 39, ++ 40, 41, 42, 43, 44, 45, 46, 47, ++ 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, @@ -74061,18 +17129,18 @@ + .length = 78}} +#endif }; - + static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state); - + -static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, +static int nand_do_write_oob(struct mtd_info *mtd, loff_mtd_t to, struct mtd_oob_ops *ops); - + /* @@ -95,6 +192,35 @@ DEFINE_LED_TRIGGER(nand_led_trigger); - + /** + * ffs_ll - find first bit set in a 64bit word. + * @word: The word to search @@ -74125,7 +17193,7 @@ + nand_nce = NAND_NCE4; + chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); break; - + default: @@ -298,13 +438,19 @@ * @@ -74138,7 +17206,7 @@ + int page, page1 = 0, chipnr, res = 0; struct nand_chip *chip = mtd->priv; u16 bad; - + - page = (int)(ofs >> chip->page_shift) & chip->pagemask; + if (chip->planenum > 1) { + page = ((int)(ofs >> chip->page_shift) * chip->planenum + CONFIG_MTD_BADBLOCK_FLAG_PAGE); @@ -74147,7 +17215,7 @@ + page1 &= chip->pagemask; + } else + page = ((int)(ofs >> chip->page_shift) + CONFIG_MTD_BADBLOCK_FLAG_PAGE) & chip->pagemask; - + if (getchip) { chipnr = (int)(ofs >> chip->chip_shift); @@ -327,6 +473,11 @@ @@ -74160,7 +17228,7 @@ + res = 1; + } } - + if (getchip) @@ -343,7 +494,7 @@ * This is the default implementation, which can be overridden by @@ -74189,7 +17257,7 @@ { struct nand_chip *chip = mtd->priv; @@ -554,7 +706,10 @@ - + /* Emulate NAND_CMD_READOOB */ if (command == NAND_CMD_READOOB) { - column += mtd->writesize; @@ -74199,7 +17267,7 @@ + column += mtd->writesize; command = NAND_CMD_READ0; } - + @@ -600,6 +755,8 @@ case NAND_CMD_RNDIN: case NAND_CMD_STATUS: @@ -74207,20 +17275,20 @@ + case 0x81: /* for two-plane page program */ + case 0x11: /* for two-plane page program */ return; - + /* @@ -675,7 +832,6 @@ spin_lock(lock); - + /* Hardware controller shared among independend devices */ - /* Hardware controller shared among independend devices */ if (!chip->controller->active) chip->controller->active = chip; - + @@ -797,6 +953,7 @@ return 0; } - + +#ifndef CONFIG_MTD_HW_RS_ECC /* HW&SW Hamming ECC */ /** * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function @@ -74228,7 +17296,7 @@ @@ -841,6 +998,63 @@ return 0; } - + +#else /* CONFIG_MTD_HW_RS_ECC */ + +/** @@ -74251,7 +17319,7 @@ + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint32_t page; + uint8_t flag = 0; -+ ++ + page = (buf[3]<<24) + (buf[2]<<16) + (buf[1]<<8) + buf[0]; + + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); @@ -74297,14 +17365,14 @@ + struct mtd_oob_ops *ops, size_mtd_t len) { switch(ops->mode) { - + @@ -915,7 +1129,7 @@ case MTD_OOB_AUTO: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, roffs = ops->ooboffs; - size_t bytes = 0; + size_mtd_t bytes = 0; - + for(; free->length && len; free++, len -= bytes) { /* Read request not from offset 0 ? */ @@ -925,11 +1139,11 @@ @@ -74333,7 +17401,7 @@ @@ -986,10 +1200,18 @@ if (realpage != chip->pagebuf || oob) { bufpoi = aligned ? buf : chip->buffers->databuf; - + + global_page = page; +#if defined(CONFIG_MTD_HW_RS_ECC) || defined(CONFIG_MTD_NAND_DMA) + bufpoi[0] = (uint8_t)page; @@ -74346,18 +17414,18 @@ sndcmd = 0; } +#endif - + /* Now read the page into the buffer */ if (unlikely(ops->mode == MTD_OOB_RAW)) @@ -1065,7 +1287,7 @@ sndcmd = 1; } - + - ops->retlen = ops->len - (size_t) readlen; + ops->retlen = ops->len - (size_mtd_t) readlen; if (oob) ops->oobretlen = ops->ooblen - oobreadlen; - + @@ -1088,8 +1310,8 @@ * * Get hold of the chip and call nand_do_read @@ -74390,7 +17458,7 @@ @@ -1518,12 +1740,17 @@ { int status; - + - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - - if (unlikely(raw)) @@ -74401,18 +17469,18 @@ chip->ecc.write_page(mtd, chip, buf); + else { + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); -+ ++ + if (unlikely(raw)) + chip->ecc.write_page_raw(mtd, chip, buf); + else + chip->ecc.write_page(mtd, chip, buf); + } - + /* * Cached progamming disabled for now, Not sure if its worth the @@ -1532,9 +1759,17 @@ cached = 0; - + if (!cached || !(chip->options & NAND_CACHEPRG)) { - - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); @@ -74436,16 +17504,16 @@ { - size_t len = ops->ooblen; + size_mtd_t len = ops->ooblen; - + switch(ops->mode) { - + @@ -1581,7 +1816,7 @@ case MTD_OOB_AUTO: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, woffs = ops->ooboffs; - size_t bytes = 0; + size_mtd_t bytes = 0; - + for(; free->length && len; free++, len -= bytes) { /* Write request not from offset 0 ? */ @@ -1591,11 +1826,11 @@ @@ -74538,7 +17606,7 @@ +#else + chip->realplanenum = 1; +#endif - + + if (chip->realplanenum > 1) { /* use muti planes mode */ + chip->planenum = 2; + mtd->writesize *= 2; /* two pages as one page */ @@ -74550,23 +17618,23 @@ /* * Old devices have chip data hardcoded in the device id table @@ -2312,7 +2561,7 @@ - + chip->bbt_erase_shift = chip->phys_erase_shift = ffs(mtd->erasesize) - 1; - chip->chip_shift = ffs(chip->chipsize) - 1; + chip->chip_shift = ffs_ll(chip->chipsize) - 1; - + /* Set the bad block position */ chip->badblockpos = mtd->writesize > 512 ? @@ -2344,8 +2593,8 @@ chip->cmdfunc = nand_command_lp; - + printk(KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, - nand_manuf_ids[maf_idx].name, type->name); + " 0x%02x, Chip ID: 0x%02x (%s %s) planenum:%d\n", *maf_id, dev_id, + nand_manuf_ids[maf_idx].name, type->name, chip->realplanenum); - + return type; } @@ -2412,7 +2661,7 @@ @@ -74576,7 +17644,7 @@ - int i; + int i, res; struct nand_chip *chip = mtd->priv; - + if (!(chip->options & NAND_OWN_BUFFERS)) @@ -2437,6 +2686,16 @@ case 64: @@ -74613,10 +17681,10 @@ @@ -2593,8 +2857,58 @@ if (chip->options & NAND_SKIP_BBTSCAN) return 0; - + - /* Build bad block table */ - return chip->scan_bbt(mtd); -+ /* Create jz_mtd1 for one plane operation if the NAND support multiple ++ /* Create jz_mtd1 for one plane operation if the NAND support multiple + planes operation, because some partitions will only use one plane. */ + if ((chip->planenum == 2) && !all_use_planes) { + int i, len, numblocks; @@ -74669,19 +17737,10 @@ + + return res; } - + /* module_text_address() isn't exported, and it's mostly a pointless --- linux-2.6.24.7.old/drivers/mtd/nand/nand_bbt.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/mtd/nand/nand_bbt.c 2009-04-12 18:13:57.000000000 +0200 -@@ -6,7 +6,7 @@ - * - * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) - * -- * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $ -+ * $Id: nand_bbt.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as @@ -147,15 +147,15 @@ { int res, i, j, act = 0; @@ -74691,11 +17750,11 @@ + size_mtd_t retlen, len, totlen; + loff_mtd_t from; uint8_t msk = (uint8_t) ((1 << bits) - 1); - + totlen = (num * bits) >> 3; - from = ((loff_t) page) << this->page_shift; + from = ((loff_mtd_t) page) << this->page_shift; - + while (totlen) { - len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); + len = min(totlen, (size_mtd_t) (1 << this->bbt_erase_shift)); @@ -74712,7 +17771,7 @@ + size_mtd_t len) { struct mtd_oob_ops ops; - + @@ -253,7 +253,7 @@ /* * Scan write data with oob to flash @@ -74748,9 +17807,9 @@ - size_t readlen; + loff_mtd_t from; + size_mtd_t readlen; - + printk(KERN_INFO "Scanning device for bad blocks\n"); - + @@ -403,7 +403,7 @@ * below as it makes shifting and masking less painful */ numblocks = mtd->size >> (this->bbt_erase_shift - 1); @@ -74767,10 +17826,10 @@ - from = startblock << (this->bbt_erase_shift - 1); + from = (startblock << (this->bbt_erase_shift - 1)) + (CONFIG_MTD_BADBLOCK_FLAG_PAGE << this->page_shift); //from = startblock << (this->bbt_erase_shift - 1); } - + for (i = startblock; i < numblocks;) { @@ -430,8 +430,8 @@ - + if (ret) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", @@ -74779,14 +17838,14 @@ + i >> 1, (unsigned long long)from); mtd->ecc_stats.badblocks++; } - + @@ -497,7 +497,7 @@ for (block = 0; block < td->maxblocks; block++) { - + int actblock = startblock + dir * block; - loff_t offs = actblock << this->bbt_erase_shift; + loff_mtd_t offs = actblock << this->bbt_erase_shift; - + /* Read first page */ scan_read_raw(mtd, buf, offs, mtd->writesize); @@ -567,8 +567,8 @@ @@ -74798,15 +17857,15 @@ + size_mtd_t retlen, len = 0; + loff_mtd_t to; struct mtd_oob_ops ops; - + ops.ooblen = mtd->oobsize; @@ -655,12 +655,12 @@ - + bbtoffs = chip * (numblocks >> 2); - + - to = ((loff_t) page) << this->page_shift; + to = ((loff_mtd_t) page) << this->page_shift; - + /* Must we save the block contents ? */ if (td->options & NAND_BBT_SAVECONTENT) { /* Make it block aligned */ @@ -74822,7 +17881,7 @@ - memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); + memset(&buf[offs], 0xff, (size_mtd_t) (numblocks >> sft)); ooboffs = len + (pageoffs * mtd->oobsize); - + } else { /* Calc length */ - len = (size_t) (numblocks >> sft); @@ -74853,4885 +17912,17 @@ @@ -111,6 +111,9 @@ {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16}, {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16}, - + + /* 32 Gigabit */ + {"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS}, + /* * Renesas AND 1 Gigabit. Those chips do not support extended id and * have a strange page/block layout ! The chosen minimum erasesize is ---- linux-2.6.24.7.old/drivers/mtd/ubi/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -55,4 +55,18 @@ - this if no legacy software will be used. - - source "drivers/mtd/ubi/Kconfig.debug" -+ -+config MTD_UBI_BLKDEVS -+ tristate "Common interface to block layer for UBI 'translation layers'" -+ depends on BLOCK -+ default n -+ -+config MTD_UBI_BLOCK -+ tristate "Emulate block devices" -+ default n -+ depends on MTD_UBI_BLKDEVS -+ help -+ This option enables Block layer emulation on top of UBI volumes: for -+ each UBI volumes an block device is created. This is handy to make -+ traditional filesystem (like ext2, VFAT) work on top of UBI. - endmenu ---- linux-2.6.24.7.old/drivers/mtd/ubi/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -5,3 +5,6 @@ - - ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o - ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o -+ -+obj-$(CONFIG_MTD_UBI_BLKDEVS) += bdev.o -+obj-$(CONFIG_MTD_UBI_BLOCK) += ubiblk.o ---- linux-2.6.24.7.old/drivers/mtd/ubi/bdev.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/ubi/bdev.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,432 @@ -+/* -+ * -+ * (C) 2003 David Woodhouse -+ * -+ * Interface to Linux 2.5 block layer for UBI 'translation layers'. -+ * -+ * 2008 Yurong Tan : -+ * borrow from mtd_blkdevs.c for building block device layer on top of UBI -+ * -+ */ -+#include -+#include -+#include -+#include +--- linux-2.6.24.7.old/drivers/mtd/udc_cache.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.24.7/drivers/mtd/udc_cache.c 2009-04-12 18:13:57.000000000 +0200 +@@ -0,0 +1,531 @@ +#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ubi.h" -+#include "ubiblk.h" -+ -+static LIST_HEAD(blktrans_majors); -+extern struct mutex vol_table_mutex; -+extern struct ubi_volume *vol_table[]; -+ -+extern void register_vol_user (struct vol_notifier *new); -+extern int unregister_vol_user (struct vol_notifier *old); -+extern int ubi_major2num(int major); -+ -+struct ubi_blkcore_priv { -+ struct task_struct *thread; -+ struct request_queue *rq; -+ spinlock_t queue_lock; -+}; -+ -+static int do_blktrans_request(struct ubi_blktrans_ops *tr, -+ struct ubi_blktrans_dev *dev, -+ struct request *req) -+{ -+ unsigned long block, nsect; -+ char *buf; -+ -+ block = req->sector << 9 >> tr->blkshift; -+ nsect = req->current_nr_sectors << 9 >> tr->blkshift; -+ buf = req->buffer; -+ -+ if (!blk_fs_request(req)) -+ return 0; -+ -+ if (req->sector + req->current_nr_sectors > get_capacity(req->rq_disk)) -+ return 0; -+ -+ switch(rq_data_dir(req)) { -+ case READ: -+ for (; nsect > 0; nsect--, block++, buf += tr->blksize) -+ if (tr->readsect(dev, block, buf)) -+ return 0; -+ return 1; -+ -+ case WRITE: -+ if (!tr->writesect) -+ return 0; -+ -+ for (; nsect > 0; nsect--, block++, buf += tr->blksize) -+ if (tr->writesect(dev, block, buf)) -+ return 0; -+ return 1; -+ -+ default: -+ printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req)); -+ return 0; -+ } -+} -+ -+static int ubi_blktrans_thread(void *arg) -+{ -+ struct ubi_blktrans_ops *tr = arg; -+ struct request_queue *rq = tr->blkcore_priv->rq; -+ -+ /* we might get involved when memory gets low, so use PF_MEMALLOC */ -+ current->flags |= PF_MEMALLOC; -+ -+ spin_lock_irq(rq->queue_lock); -+ while (!kthread_should_stop()) { -+ struct request *req; -+ struct ubi_blktrans_dev *dev; -+ int res = 0; -+ -+ req = elv_next_request(rq); -+ -+ if (!req) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ spin_unlock_irq(rq->queue_lock); -+ schedule(); -+ spin_lock_irq(rq->queue_lock); -+ continue; -+ } -+ dev = req->rq_disk->private_data; -+ tr = dev->tr; -+ -+ spin_unlock_irq(rq->queue_lock); -+ mutex_lock(&dev->lock); -+ res = do_blktrans_request(tr, dev, req); -+ mutex_unlock(&dev->lock); -+ spin_lock_irq(rq->queue_lock); -+ -+ end_request(req, res); -+ } -+ spin_unlock_irq(rq->queue_lock); -+ -+ return 0; -+} -+ -+static void ubi_blktrans_request(struct request_queue *rq) -+{ -+ struct ubi_blktrans_ops *tr = rq->queuedata; -+ wake_up_process(tr->blkcore_priv->thread); -+} -+ -+static int blktrans_open(struct inode *i, struct file *f) -+{ -+ struct ubi_blktrans_dev *dev; -+ struct ubi_blktrans_ops *tr; -+ int ret =0; -+ -+ dev = i->i_bdev->bd_disk->private_data; -+ tr = dev->tr; -+ -+ if (!try_module_get(tr->owner)) -+ goto out_tr; -+ -+ if(!tr->open) -+ return -1; -+ else -+ ret = tr->open(i,f); -+ -+ return ret; -+out_tr: -+ module_put(tr->owner); -+ return -1; -+} -+ -+static int blktrans_release(struct inode *i, struct file *f) -+{ -+ struct ubi_blktrans_dev *dev; -+ struct ubi_blktrans_ops *tr; -+ struct ubi_volume_desc *desc; -+ int ret = 0; -+ -+ dev = i->i_bdev->bd_disk->private_data; -+ tr = dev->tr; -+ desc = dev->uv; -+ -+ if (tr->release) -+ ret = tr->release(dev); -+ -+ module_put(tr->owner); -+ return ret; -+} -+ -+static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) -+{ -+ struct ubi_blktrans_dev *dev = bdev->bd_disk->private_data; -+ -+ if (dev->tr->getgeo) -+ return dev->tr->getgeo(dev, geo); -+ return -ENOTTY; -+} -+ -+static int blktrans_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct ubi_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data; -+ struct ubi_blktrans_ops *tr = dev->tr; -+ -+ switch (cmd) { -+ case BLKFLSBUF: -+ if (tr->flush) -+ return tr->flush(dev); -+ /* The core code did the work, we had nothing to do. */ -+ return 0; -+ default: -+ return -ENOTTY; -+ } -+} -+ -+struct block_device_operations ubi_blktrans_ops = { -+ .owner = THIS_MODULE, -+ .open = blktrans_open, -+ .release = blktrans_release, -+ .ioctl = blktrans_ioctl, -+ .getgeo = blktrans_getgeo, -+}; -+ -+int add_ubi_blktrans_dev(struct ubi_blktrans_dev *new) -+{ -+ struct ubi_blktrans_ops *tr = new->tr; -+ struct list_head *this; -+ int last_devnum = -1; -+ struct gendisk *gd; -+ -+ if (mutex_trylock(&vol_table_mutex)) { -+ mutex_unlock(&vol_table_mutex); -+ BUG(); -+ } -+ -+ list_for_each(this, &tr->devs) { -+ struct ubi_blktrans_dev *d = list_entry(this, struct ubi_blktrans_dev, list); -+ if (new->devnum == -1) { -+ /* Use first free number */ -+ if (d->devnum != last_devnum+1) { -+ /* Found a free devnum. Plug it in here */ -+ new->devnum = last_devnum+1; -+ list_add_tail(&new->list, &d->list); -+ goto added; -+ } -+ } else if (d->devnum == new->devnum) { -+ /* Required number taken */ -+ return -EBUSY; -+ } else if (d->devnum > new->devnum) { -+ /* Required number was free */ -+ list_add_tail(&new->list, &d->list); -+ goto added; -+ } -+ last_devnum = d->devnum; -+ } -+ if (new->devnum == -1) -+ new->devnum = last_devnum+1; -+ -+ if ((new->devnum << tr->part_bits) > 256) { -+ return -EBUSY; -+ } -+ -+ mutex_init(&new->lock); -+ list_add_tail(&new->list, &tr->devs); -+ added: -+ if (!tr->writesect) -+ new->readonly = 1; -+ -+ gd = alloc_disk(1 << tr->part_bits); -+ if (!gd) { -+ list_del(&new->list); -+ return -ENOMEM; -+ } -+ gd->major = tr->major; -+ gd->first_minor = (new->devnum) << tr->part_bits; -+ gd->fops = &ubi_blktrans_ops; -+ -+ if (tr->part_bits) -+ if (new->devnum < 26) -+ snprintf(gd->disk_name, sizeof(gd->disk_name), -+ "%s%c", tr->name, 'a' + new->devnum); -+ else -+ snprintf(gd->disk_name, sizeof(gd->disk_name), -+ "%s%c%c", tr->name, -+ 'a' - 1 + new->devnum / 26, -+ 'a' + new->devnum % 26); -+ else -+ snprintf(gd->disk_name, sizeof(gd->disk_name), -+ "%s%d", tr->name, new->devnum); -+ -+ /* 2.5 has capacity in units of 512 bytes while still -+ having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ -+ set_capacity(gd, (new->size * tr->blksize) >> 9); -+ -+ gd->private_data = new; -+ new->blkcore_priv = gd; -+ gd->queue = tr->blkcore_priv->rq; -+ -+ if (new->readonly) -+ set_disk_ro(gd, 1); -+ -+ add_disk(gd); -+ -+ return 0; -+} -+ -+int del_ubi_blktrans_dev(struct ubi_blktrans_dev *old) -+{ -+ if (mutex_trylock(&vol_table_mutex)) { -+ mutex_unlock(&vol_table_mutex); -+ BUG(); -+ } -+ -+ list_del(&old->list); -+ -+ del_gendisk(old->blkcore_priv); -+ put_disk(old->blkcore_priv); -+ -+ return 0; -+} -+ -+static void blktrans_notify_remove(struct ubi_volume *vol) -+{ -+ struct list_head *this, *this2, *next; -+ -+ list_for_each(this, &blktrans_majors) { -+ struct ubi_blktrans_ops *tr = list_entry(this, struct ubi_blktrans_ops, list); -+ -+ list_for_each_safe(this2, next, &tr->devs) { -+ struct ubi_blktrans_dev *dev = list_entry(this2, struct ubi_blktrans_dev, list); -+ -+ if (dev->uv->vol == vol) -+ tr->remove_vol(dev); -+ } -+ } -+} -+ -+static void blktrans_notify_add(struct ubi_volume *vol) -+{ -+ struct list_head *this; -+ -+ list_for_each(this, &blktrans_majors) { -+ struct ubi_blktrans_ops *tr = list_entry(this, struct ubi_blktrans_ops, list); -+ -+ tr->add_vol(tr,vol); -+ } -+ -+} -+ -+static struct vol_notifier blktrans_notifier = { -+ .add = blktrans_notify_add, -+ .remove = blktrans_notify_remove, -+}; -+ -+ -+int register_ubi_blktrans(struct ubi_blktrans_ops *tr) -+{ -+ int i; -+ -+ /* Register the notifier if/when the first device type is -+ registered, to prevent the link/init ordering from fucking -+ us over. */ -+ if (!blktrans_notifier.list.next) -+ register_vol_user(&blktrans_notifier); -+ -+ tr->blkcore_priv = kzalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL); -+ if (!tr->blkcore_priv) -+ return -ENOMEM; -+ -+ mutex_lock(&vol_table_mutex); -+ tr->major = register_blkdev(0, tr->name); -+ spin_lock_init(&tr->blkcore_priv->queue_lock); -+ -+ tr->blkcore_priv->rq = blk_init_queue(ubi_blktrans_request, &tr->blkcore_priv->queue_lock); -+ if (!tr->blkcore_priv->rq) { -+ unregister_blkdev(tr->major, tr->name); -+ kfree(tr->blkcore_priv); -+ mutex_unlock(&vol_table_mutex); -+ return -ENOMEM; -+ } -+ -+ tr->blkcore_priv->rq->queuedata = tr; -+ blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize); -+ tr->blkshift = ffs(tr->blksize) - 1; -+ -+ tr->blkcore_priv->thread = kthread_run(ubi_blktrans_thread, tr, -+ "%sd", tr->name); -+ if (IS_ERR(tr->blkcore_priv->thread)) { -+ blk_cleanup_queue(tr->blkcore_priv->rq); -+ unregister_blkdev(tr->major, tr->name); -+ kfree(tr->blkcore_priv); -+ mutex_unlock(&vol_table_mutex); -+ return PTR_ERR(tr->blkcore_priv->thread); -+ } -+ -+ INIT_LIST_HEAD(&tr->devs); -+ list_add(&tr->list, &blktrans_majors); -+ -+ for (i=0; iadd_vol(tr, vol_table[i]); -+ } -+ -+ mutex_unlock(&vol_table_mutex); -+ return 0; -+} -+ -+int deregister_ubi_blktrans(struct ubi_blktrans_ops *tr) -+{ -+ struct list_head *this, *next; -+ -+ mutex_lock(&vol_table_mutex); -+ -+ /* Clean up the kernel thread */ -+ kthread_stop(tr->blkcore_priv->thread); -+ -+ /* Remove it from the list of active majors */ -+ list_del(&tr->list); -+ -+ list_for_each_safe(this, next, &tr->devs) { -+ struct ubi_blktrans_dev *dev = list_entry(this, struct ubi_blktrans_dev, list); -+ tr->remove_vol(dev); -+ } -+ -+ blk_cleanup_queue(tr->blkcore_priv->rq); -+ unregister_blkdev(tr->major, tr->name); -+ -+ mutex_unlock(&vol_table_mutex); -+ -+ kfree(tr->blkcore_priv); -+ -+ BUG_ON(!list_empty(&tr->devs)); -+ return 0; -+} -+ -+static void __exit ubi_blktrans_exit(void) -+{ -+ /* No race here -- if someone's currently in register_ubi_blktrans -+ we're screwed anyway. */ -+ if (blktrans_notifier.list.next) -+ unregister_vol_user(&blktrans_notifier); -+} -+ -+ -+module_exit(ubi_blktrans_exit); -+ -+EXPORT_SYMBOL_GPL(register_ubi_blktrans); -+EXPORT_SYMBOL_GPL(deregister_ubi_blktrans); -+EXPORT_SYMBOL_GPL(add_ubi_blktrans_dev); -+EXPORT_SYMBOL_GPL(del_ubi_blktrans_dev); -+ -+MODULE_AUTHOR("David Woodhouse , Yurong Tan "); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Common interface to block layer for UBI 'translation layers'"); -+ ---- linux-2.6.24.7.old/drivers/mtd/ubi/build.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/build.c 2009-04-12 18:13:57.000000000 +0200 -@@ -18,14 +18,20 @@ - * - * Author: Artem Bityutskiy (Битюцкий Артём), - * Frank Haverkamp -+ * Yurong tan(Nancy) - */ - - /* -- * This file includes UBI initialization and building of UBI devices. At the -- * moment UBI devices may only be added while UBI is initialized, but dynamic -- * device add/remove functionality is planned. Also, at the moment we only -- * attach UBI devices by scanning, which will become a bottleneck when flashes -- * reach certain large size. Then one may improve UBI and add other methods. -+ * This file includes UBI initialization and building of UBI devices. -+ * -+ * When UBI is initialized, it attaches all the MTD devices specified as the -+ * module load parameters or the kernel boot parameters. If MTD devices were -+ * specified, UBI does not attach any MTD device, but it is possible to do -+ * later using the "UBI control device". -+ * -+ * At the moment we only attach UBI devices by scanning, which will become a -+ * bottleneck when flashes reach certain large size. Then one may improve UBI -+ * and add other methods, although it does not seem to be easy to do. - */ - - #include -@@ -33,23 +39,130 @@ - #include - #include - #include -+#include - #include -+#include - #include "ubi.h" - - /* Maximum length of the 'mtd=' parameter */ - #define MTD_PARAM_LEN_MAX 64 - -+/* add by Nancy begin */ -+DEFINE_MUTEX(vol_table_mutex); -+struct ubi_volume *vol_table[UBI_MAX_VOLUMES]; -+ -+EXPORT_SYMBOL_GPL(vol_table_mutex); -+EXPORT_SYMBOL_GPL(vol_table); -+ -+static LIST_HEAD(vol_notifiers); -+ -+int add_vol_device(struct ubi_volume *vol) -+{ -+ mutex_lock(&vol_table_mutex); -+ if (!vol_table[vol->vol_id]) { -+ -+ struct list_head *this; -+ vol_table[vol->vol_id] = vol; -+ /* No need to get a refcount on the module containing -+ the notifier, since we hold the vol_table_mutex */ -+ list_for_each(this, &vol_notifiers) { -+ struct vol_notifier *not = list_entry(this, struct vol_notifier, list); -+ not->add(vol); -+ } -+ mutex_unlock(&vol_table_mutex); -+ /* We _know_ we aren't being removed, because -+ our caller is still holding us here. So none -+ of this try_ nonsense, and no bitching about it -+ either. :) */ -+ return 0; -+ } -+ mutex_unlock(&vol_table_mutex); -+ return 1; -+} -+ -+int del_vol_device (struct ubi_volume *vol) -+{ -+ int ret; -+ struct list_head *this; -+ -+ mutex_lock(&vol_table_mutex); -+ if (vol_table[vol->vol_id] != vol) { -+ ret = -ENODEV; -+ } else if (vol->readers ||vol->writers || vol->exclusive) { -+ printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count 0\n", -+ vol->vol_id, vol->name); -+ ret = -EBUSY; -+ } else { -+ /* No need to get a refcount on the module containing -+ the notifier, since we hold the vol_table_mutex */ -+ list_for_each(this, &vol_notifiers) { -+ struct vol_notifier *not = list_entry(this, struct vol_notifier, list); -+ not->remove(vol); -+ } -+ -+ vol_table[vol->vol_id] = NULL; -+ module_put(THIS_MODULE); -+ ret = 0; -+ } -+ mutex_unlock(&vol_table_mutex); -+ return ret; -+} -+ -+void register_vol_user(struct vol_notifier *new) -+{ -+ int i; -+ -+ mutex_lock(&vol_table_mutex); -+ list_add(&new->list, &vol_notifiers); -+ __module_get(THIS_MODULE); -+ -+ for (i=0; i< UBI_MAX_VOLUMES; i++) -+ if (vol_table[i]) -+ new->add(vol_table[i]); -+ -+ mutex_unlock(&vol_table_mutex); -+} -+ -+int unregister_vol_user(struct vol_notifier *old) -+{ -+ int i; -+ -+ mutex_lock(&vol_table_mutex); -+ module_put(THIS_MODULE); -+ -+ for (i=0; i< UBI_MAX_VOLUMES; i++) -+ if (vol_table[i]) -+ old->remove(vol_table[i]); -+ -+ list_del(&old->list); -+ mutex_unlock(&vol_table_mutex); -+ return 0; -+} -+ -+static int bdev_init(struct ubi_device *ubi){ -+ int i; -+ for(i=0; ivtbl_slots; i++) -+ if(ubi->volumes[i]) -+ add_vol_device(ubi->volumes[i]); -+ return 0; -+} -+ -+EXPORT_SYMBOL_GPL(add_vol_device); -+EXPORT_SYMBOL_GPL(del_vol_device); -+EXPORT_SYMBOL_GPL(register_vol_user); -+EXPORT_SYMBOL_GPL(unregister_vol_user); -+/* add by Nancy end*/ -+ -+ - /** - * struct mtd_dev_param - MTD device parameter description data structure. - * @name: MTD device name or number string - * @vid_hdr_offs: VID header offset -- * @data_offs: data offset - */ - struct mtd_dev_param - { - char name[MTD_PARAM_LEN_MAX]; - int vid_hdr_offs; -- int data_offs; - }; - - /* Numbers of elements set in the @mtd_dev_param array */ -@@ -58,14 +171,28 @@ - /* MTD devices specification parameters */ - static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; - --/* Number of UBI devices in system */ --int ubi_devices_cnt; -+/* Root UBI "class" object (corresponds to '//class/ubi/') */ -+struct class *ubi_class; -+ -+/* Slab cache for wear-leveling entries */ -+struct kmem_cache *ubi_wl_entry_slab; -+ -+/* UBI control character device */ -+static struct miscdevice ubi_ctrl_cdev = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "ubi_ctrl", -+ .fops = &ubi_ctrl_cdev_operations, -+}; - - /* All UBI devices in system */ --struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; -+static struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; - --/* Root UBI "class" object (corresponds to '//class/ubi/') */ --struct class *ubi_class; -+/* Serializes UBI devices creations and removals */ -+DEFINE_MUTEX(ubi_devices_mutex); -+ -+/* Protects @ubi_devices and @ubi->ref_count */ -+static DEFINE_SPINLOCK(ubi_devices_lock); -+EXPORT_SYMBOL_GPL(ubi_devices_lock); - - /* "Show" method for files in '//class/ubi/' */ - static ssize_t ubi_version_show(struct class *class, char *buf) -@@ -101,38 +228,152 @@ - __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL); - static struct device_attribute dev_bgt_enabled = - __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); -+static struct device_attribute dev_mtd_num = -+ __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); -+ -+/** -+ * ubi_get_device - get UBI device. -+ * @ubi_num: UBI device number -+ * -+ * This function returns UBI device description object for UBI device number -+ * @ubi_num, or %NULL if the device does not exist. This function increases the -+ * device reference count to prevent removal of the device. In other words, the -+ * device cannot be removed if its reference count is not zero. -+ */ -+struct ubi_device *ubi_get_device(int ubi_num) -+{ -+ struct ubi_device *ubi; -+ -+ spin_lock(&ubi_devices_lock); -+ ubi = ubi_devices[ubi_num]; -+ if (ubi) { -+ ubi_assert(ubi->ref_count >= 0); -+ ubi->ref_count += 1; -+ get_device(&ubi->dev); -+ } -+ spin_unlock(&ubi_devices_lock); -+ -+ return ubi; -+} -+ -+/** -+ * ubi_put_device - drop an UBI device reference. -+ * @ubi: UBI device description object -+ */ -+void ubi_put_device(struct ubi_device *ubi) -+{ -+ spin_lock(&ubi_devices_lock); -+ ubi->ref_count -= 1; -+ put_device(&ubi->dev); -+ spin_unlock(&ubi_devices_lock); -+} -+ -+/** -+ * ubi_get_by_major - get UBI device description object by character device -+ * major number. -+ * @major: major number -+ * -+ * This function is similar to 'ubi_get_device()', but it searches the device -+ * by its major number. -+ */ -+struct ubi_device *ubi_get_by_major(int major) -+{ -+ int i; -+ struct ubi_device *ubi; -+ -+ spin_lock(&ubi_devices_lock); -+ for (i = 0; i < UBI_MAX_DEVICES; i++) { -+ ubi = ubi_devices[i]; -+ if (ubi && MAJOR(ubi->cdev.dev) == major) { -+ ubi_assert(ubi->ref_count >= 0); -+ ubi->ref_count += 1; -+ get_device(&ubi->dev); -+ spin_unlock(&ubi_devices_lock); -+ return ubi; -+ } -+ } -+ spin_unlock(&ubi_devices_lock); -+ -+ return NULL; -+} -+ -+/** -+ * ubi_major2num - get UBI device number by character device major number. -+ * @major: major number -+ * -+ * This function searches UBI device number object by its major number. If UBI -+ * device was not found, this function returns -ENODEV, otherwise the UBI device -+ * number is returned. -+ */ -+int ubi_major2num(int major) -+{ -+ int i, ubi_num = -ENODEV; -+ -+ spin_lock(&ubi_devices_lock); -+ for (i = 0; i < UBI_MAX_DEVICES; i++) { -+ struct ubi_device *ubi = ubi_devices[i]; -+ -+ if ( (ubi && MAJOR(ubi->cdev.dev) == major) || -+ (ubi && ubi->bdev_major == major)) { -+ ubi_num = ubi->ubi_num; -+ break; -+ } -+ } -+ spin_unlock(&ubi_devices_lock); -+ -+ return ubi_num; -+} -+EXPORT_SYMBOL_GPL(ubi_major2num); - - /* "Show" method for files in '//class/ubi/ubiX/' */ - static ssize_t dev_attribute_show(struct device *dev, - struct device_attribute *attr, char *buf) - { -- const struct ubi_device *ubi; -+ ssize_t ret; -+ struct ubi_device *ubi; - -+ /* -+ * The below code looks weird, but it actually makes sense. We get the -+ * UBI device reference from the contained 'struct ubi_device'. But it -+ * is unclear if the device was removed or not yet. Indeed, if the -+ * device was removed before we increased its reference count, -+ * 'ubi_get_device()' will return -ENODEV and we fail. -+ * -+ * Remember, 'struct ubi_device' is freed in the release function, so -+ * we still can use 'ubi->ubi_num'. -+ */ - ubi = container_of(dev, struct ubi_device, dev); -+ ubi = ubi_get_device(ubi->ubi_num); -+ if (!ubi) -+ return -ENODEV; -+ - if (attr == &dev_eraseblock_size) -- return sprintf(buf, "%d\n", ubi->leb_size); -+ ret = sprintf(buf, "%d\n", ubi->leb_size); - else if (attr == &dev_avail_eraseblocks) -- return sprintf(buf, "%d\n", ubi->avail_pebs); -+ ret = sprintf(buf, "%d\n", ubi->avail_pebs); - else if (attr == &dev_total_eraseblocks) -- return sprintf(buf, "%d\n", ubi->good_peb_count); -+ ret = sprintf(buf, "%d\n", ubi->good_peb_count); - else if (attr == &dev_volumes_count) -- return sprintf(buf, "%d\n", ubi->vol_count); -+ ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT); - else if (attr == &dev_max_ec) -- return sprintf(buf, "%d\n", ubi->max_ec); -+ ret = sprintf(buf, "%d\n", ubi->max_ec); - else if (attr == &dev_reserved_for_bad) -- return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); -+ ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); - else if (attr == &dev_bad_peb_count) -- return sprintf(buf, "%d\n", ubi->bad_peb_count); -+ ret = sprintf(buf, "%d\n", ubi->bad_peb_count); - else if (attr == &dev_max_vol_count) -- return sprintf(buf, "%d\n", ubi->vtbl_slots); -+ ret = sprintf(buf, "%d\n", ubi->vtbl_slots); - else if (attr == &dev_min_io_size) -- return sprintf(buf, "%d\n", ubi->min_io_size); -+ ret = sprintf(buf, "%d\n", ubi->min_io_size); - else if (attr == &dev_bgt_enabled) -- return sprintf(buf, "%d\n", ubi->thread_enabled); -+ ret = sprintf(buf, "%d\n", ubi->thread_enabled); -+ else if (attr == &dev_mtd_num) -+ ret = sprintf(buf, "%d\n", ubi->mtd->index); - else -- BUG(); -+ ret = -EINVAL; - -- return 0; -+ ubi_put_device(ubi); -+ return ret; - } - - /* Fake "release" method for UBI devices */ -@@ -150,68 +391,44 @@ - int err; - - ubi->dev.release = dev_release; -- ubi->dev.devt = MKDEV(ubi->major, 0); -+ ubi->dev.devt = ubi->cdev.dev; - ubi->dev.class = ubi_class; - sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num); - err = device_register(&ubi->dev); - if (err) -- goto out; -+ return err; - - err = device_create_file(&ubi->dev, &dev_eraseblock_size); - if (err) -- goto out_unregister; -+ return err; - err = device_create_file(&ubi->dev, &dev_avail_eraseblocks); - if (err) -- goto out_eraseblock_size; -+ return err; - err = device_create_file(&ubi->dev, &dev_total_eraseblocks); - if (err) -- goto out_avail_eraseblocks; -+ return err; - err = device_create_file(&ubi->dev, &dev_volumes_count); - if (err) -- goto out_total_eraseblocks; -+ return err; - err = device_create_file(&ubi->dev, &dev_max_ec); - if (err) -- goto out_volumes_count; -+ return err; - err = device_create_file(&ubi->dev, &dev_reserved_for_bad); - if (err) -- goto out_volumes_max_ec; -+ return err; - err = device_create_file(&ubi->dev, &dev_bad_peb_count); - if (err) -- goto out_reserved_for_bad; -+ return err; - err = device_create_file(&ubi->dev, &dev_max_vol_count); - if (err) -- goto out_bad_peb_count; -+ return err; - err = device_create_file(&ubi->dev, &dev_min_io_size); - if (err) -- goto out_max_vol_count; -+ return err; - err = device_create_file(&ubi->dev, &dev_bgt_enabled); - if (err) -- goto out_min_io_size; -- -- return 0; -- --out_min_io_size: -- device_remove_file(&ubi->dev, &dev_min_io_size); --out_max_vol_count: -- device_remove_file(&ubi->dev, &dev_max_vol_count); --out_bad_peb_count: -- device_remove_file(&ubi->dev, &dev_bad_peb_count); --out_reserved_for_bad: -- device_remove_file(&ubi->dev, &dev_reserved_for_bad); --out_volumes_max_ec: -- device_remove_file(&ubi->dev, &dev_max_ec); --out_volumes_count: -- device_remove_file(&ubi->dev, &dev_volumes_count); --out_total_eraseblocks: -- device_remove_file(&ubi->dev, &dev_total_eraseblocks); --out_avail_eraseblocks: -- device_remove_file(&ubi->dev, &dev_avail_eraseblocks); --out_eraseblock_size: -- device_remove_file(&ubi->dev, &dev_eraseblock_size); --out_unregister: -- device_unregister(&ubi->dev); --out: -- ubi_err("failed to initialize sysfs for %s", ubi->ubi_name); -+ return err; -+ err = device_create_file(&ubi->dev, &dev_mtd_num); - return err; - } - -@@ -221,6 +438,7 @@ - */ - static void ubi_sysfs_close(struct ubi_device *ubi) - { -+ device_remove_file(&ubi->dev, &dev_mtd_num); - device_remove_file(&ubi->dev, &dev_bgt_enabled); - device_remove_file(&ubi->dev, &dev_min_io_size); - device_remove_file(&ubi->dev, &dev_max_vol_count); -@@ -244,7 +462,7 @@ - - for (i = 0; i < ubi->vtbl_slots; i++) - if (ubi->volumes[i]) -- ubi_free_volume(ubi, i); -+ ubi_free_volume(ubi, ubi->volumes[i]); - } - - /** -@@ -259,9 +477,6 @@ - int i, err; - dev_t dev; - -- mutex_init(&ubi->vtbl_mutex); -- spin_lock_init(&ubi->volumes_lock); -- - sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); - - /* -@@ -278,39 +493,40 @@ - return err; - } - -+ ubi_assert(MINOR(dev) == 0); - cdev_init(&ubi->cdev, &ubi_cdev_operations); -- ubi->major = MAJOR(dev); -- dbg_msg("%s major is %u", ubi->ubi_name, ubi->major); -+ dbg_msg("%s major is %u", ubi->ubi_name, MAJOR(dev)); - ubi->cdev.owner = THIS_MODULE; - -- dev = MKDEV(ubi->major, 0); - err = cdev_add(&ubi->cdev, dev, 1); - if (err) { -- ubi_err("cannot add character device %s", ubi->ubi_name); -+ ubi_err("cannot add character device"); - goto out_unreg; - } - - err = ubi_sysfs_init(ubi); - if (err) -- goto out_cdev; -+ goto out_sysfs; - - for (i = 0; i < ubi->vtbl_slots; i++) - if (ubi->volumes[i]) { -- err = ubi_add_volume(ubi, i); -- if (err) -+ err = ubi_add_volume(ubi, ubi->volumes[i]); -+ if (err) { -+ ubi_err("cannot add volume %d", i); - goto out_volumes; -+ } - } - - return 0; - - out_volumes: - kill_volumes(ubi); -+out_sysfs: - ubi_sysfs_close(ubi); --out_cdev: - cdev_del(&ubi->cdev); - out_unreg: -- unregister_chrdev_region(MKDEV(ubi->major, 0), -- ubi->vtbl_slots + 1); -+ unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); -+ ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); - return err; - } - -@@ -323,7 +539,7 @@ - kill_volumes(ubi); - ubi_sysfs_close(ubi); - cdev_del(&ubi->cdev); -- unregister_chrdev_region(MKDEV(ubi->major, 0), ubi->vtbl_slots + 1); -+ unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); - } - - /** -@@ -370,7 +586,11 @@ - out_wl: - ubi_wl_close(ubi); - out_vtbl: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->vtbl); -+#else - vfree(ubi->vtbl); -+#endif - out_si: - ubi_scan_destroy_si(si); - return err; -@@ -384,15 +604,21 @@ - * assumed: - * o EC header is always at offset zero - this cannot be changed; - * o VID header starts just after the EC header at the closest address -- * aligned to @io->@hdrs_min_io_size; -+ * aligned to @io->hdrs_min_io_size; - * o data starts just after the VID header at the closest address aligned to -- * @io->@min_io_size -+ * @io->min_io_size - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ - static int io_init(struct ubi_device *ubi) - { -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ printk("kmalloc instead of vmalloc is used.\n"); -+#else -+ printk("vmalloc is used.\n"); -+#endif -+ - if (ubi->mtd->numeraseregions != 0) { - /* - * Some flashes have several erase regions. Different regions -@@ -407,13 +633,18 @@ - return -EINVAL; - } - -+ if (ubi->vid_hdr_offset < 0) -+ return -EINVAL; -+ - /* - * Note, in this implementation we support MTD devices with 0x7FFFFFFF - * physical eraseblocks maximum. - */ - - ubi->peb_size = ubi->mtd->erasesize; -- ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize; -+// ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize; -+ ubi->peb_count = ubi->mtd->size >> (ffs(ubi->mtd->erasesize) - 1); -+ - ubi->flash_size = ubi->mtd->size; - - if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) -@@ -424,7 +655,8 @@ - - /* Make sure minimal I/O unit is power of 2 */ - if (!is_power_of_2(ubi->min_io_size)) { -- ubi_err("bad min. I/O unit"); -+ ubi_err("min. I/O unit (%d) is not power of 2", -+ ubi->min_io_size); - return -EINVAL; - } - -@@ -453,10 +685,8 @@ - } - - /* Similar for the data offset */ -- if (ubi->leb_start == 0) { -- ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize; -- ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); -- } -+ ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE; -+ ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); - - dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset); - dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset); -@@ -499,8 +729,16 @@ - ubi->ro_mode = 1; - } - -- dbg_msg("leb_size %d", ubi->leb_size); -- dbg_msg("ro_mode %d", ubi->ro_mode); -+ ubi_msg("physical eraseblock size: %d bytes (%d KiB)", -+ ubi->peb_size, ubi->peb_size >> 10); -+ ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); -+ ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); -+ if (ubi->hdrs_min_io_size != ubi->min_io_size) -+ ubi_msg("sub-page size: %d", -+ ubi->hdrs_min_io_size); -+ ubi_msg("VID header offset: %d (aligned %d)", -+ ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); -+ ubi_msg("data offset: %d", ubi->leb_start); - - /* - * Note, ideally, we have to initialize ubi->bad_peb_count here. But -@@ -514,87 +752,171 @@ - } - - /** -- * attach_mtd_dev - attach an MTD device. -- * @mtd_dev: MTD device name or number string -- * @vid_hdr_offset: VID header offset -- * @data_offset: data offset -+ * autoresize - re-size the volume which has the "auto-resize" flag set. -+ * @ubi: UBI device description object -+ * @vol_id: ID of the volume to re-size - * -- * This function attaches an MTD device to UBI. It first treats @mtd_dev as the -- * MTD device name, and tries to open it by this name. If it is unable to open, -- * it tries to convert @mtd_dev to an integer and open the MTD device by its -- * number. Returns zero in case of success and a negative error code in case of -- * failure. -+ * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in -+ * the volume table to the largest possible size. See comments in ubi-header.h -+ * for more description of the flag. Returns zero in case of success and a -+ * negative error code in case of failure. - */ --static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, -- int data_offset) -+static int autoresize(struct ubi_device *ubi, int vol_id) - { -- struct ubi_device *ubi; -- struct mtd_info *mtd; -- int i, err; -+ struct ubi_volume_desc desc; -+ struct ubi_volume *vol = ubi->volumes[vol_id]; -+ int err, old_reserved_pebs = vol->reserved_pebs; - -- mtd = get_mtd_device_nm(mtd_dev); -- if (IS_ERR(mtd)) { -- int mtd_num; -- char *endp; -+ /* -+ * Clear the auto-resize flag in the volume in-memory copy of the -+ * volume table, and 'ubi_resize_volume()' will propogate this change -+ * to the flash. -+ */ -+ ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG; - -- if (PTR_ERR(mtd) != -ENODEV) -- return PTR_ERR(mtd); -+ if (ubi->avail_pebs == 0) { -+ struct ubi_vtbl_record vtbl_rec; - - /* -- * Probably this is not MTD device name but MTD device number - -- * check this out. -+ * No avalilable PEBs to re-size the volume, clear the flag on -+ * flash and exit. - */ -- mtd_num = simple_strtoul(mtd_dev, &endp, 0); -- if (*endp != '\0' || mtd_dev == endp) { -- ubi_err("incorrect MTD device: \"%s\"", mtd_dev); -- return -ENODEV; -- } -- -- mtd = get_mtd_device(NULL, mtd_num); -- if (IS_ERR(mtd)) -- return PTR_ERR(mtd); -+ memcpy(&vtbl_rec, &ubi->vtbl[vol_id], -+ sizeof(struct ubi_vtbl_record)); -+ err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); -+ if (err) -+ ubi_err("cannot clean auto-resize flag for volume %d", -+ vol_id); -+ } else { -+ desc.vol = vol; -+ err = ubi_resize_volume(&desc, -+ old_reserved_pebs + ubi->avail_pebs); -+ if (err) -+ ubi_err("cannot auto-resize volume %d", vol_id); - } - -- /* Check if we already have the same MTD device attached */ -- for (i = 0; i < ubi_devices_cnt; i++) -- if (ubi_devices[i]->mtd->index == mtd->index) { -- ubi_err("mtd%d is already attached to ubi%d", -+ if (err) -+ return err; -+ -+ ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, -+ vol->name, old_reserved_pebs, vol->reserved_pebs); -+ return 0; -+} -+ -+/** -+ * ubi_attach_mtd_dev - attach an MTD device. -+ * @mtd_dev: MTD device description object -+ * @ubi_num: number to assign to the new UBI device -+ * @vid_hdr_offset: VID header offset -+ * -+ * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number -+ * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in -+ * which case this function finds a vacant device nubert and assings it -+ * automatically. Returns the new UBI device number in case of success and a -+ * negative error code in case of failure. -+ * -+ * Note, the invocations of this function has to be serialized by the -+ * @ubi_devices_mutex. -+ */ -+int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) -+{ -+ struct ubi_device *ubi; -+ int i, err; -+ -+ /* -+ * Check if we already have the same MTD device attached. -+ * -+ * Note, this function assumes that UBI devices creations and deletions -+ * are serialized, so it does not take the &ubi_devices_lock. -+ */ -+ for (i = 0; i < UBI_MAX_DEVICES; i++) { -+ ubi = ubi_devices[i]; -+ if (ubi && mtd->index == ubi->mtd->index) { -+ dbg_err("mtd%d is already attached to ubi%d", - mtd->index, i); -- err = -EINVAL; -- goto out_mtd; -+ return -EEXIST; - } -+ } - -- ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device), -- GFP_KERNEL); -- if (!ubi) { -- err = -ENOMEM; -- goto out_mtd; -+ /* -+ * Make sure this MTD device is not emulated on top of an UBI volume -+ * already. Well, generally this recursion works fine, but there are -+ * different problems like the UBI module takes a reference to itself -+ * by attaching (and thus, opening) the emulated MTD device. This -+ * results in inability to unload the module. And in general it makes -+ * no sense to attach emulated MTD devices, so we prohibit this. -+ */ -+ if (mtd->type == MTD_UBIVOLUME) { -+ ubi_err("refuse attaching mtd%d - it is already emulated on " -+ "top of UBI", mtd->index); -+ return -EINVAL; - } - -- ubi->ubi_num = ubi_devices_cnt; -- ubi->mtd = mtd; -+ if (ubi_num == UBI_DEV_NUM_AUTO) { -+ /* Search for an empty slot in the @ubi_devices array */ -+ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) -+ if (!ubi_devices[ubi_num]) -+ break; -+ if (ubi_num == UBI_MAX_DEVICES) { -+ dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES); -+ return -ENFILE; -+ } -+ } else { -+ if (ubi_num >= UBI_MAX_DEVICES) -+ return -EINVAL; -+ -+ /* Make sure ubi_num is not busy */ -+ if (ubi_devices[ubi_num]) { -+ dbg_err("ubi%d already exists", ubi_num); -+ return -EEXIST; -+ } -+ } - -- dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d", -- ubi->mtd->index, ubi_devices_cnt, vid_hdr_offset, data_offset); -+ ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); -+ if (!ubi) -+ return -ENOMEM; - -+ ubi->mtd = mtd; -+ ubi->ubi_num = ubi_num; - ubi->vid_hdr_offset = vid_hdr_offset; -- ubi->leb_start = data_offset; -+ ubi->autoresize_vol_id = -1; -+ -+ mutex_init(&ubi->buf_mutex); -+ mutex_init(&ubi->ckvol_mutex); -+ mutex_init(&ubi->volumes_mutex); -+ spin_lock_init(&ubi->volumes_lock); -+ -+ dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", -+ mtd->index, ubi_num, vid_hdr_offset); - err = io_init(ubi); - if (err) - goto out_free; - -- mutex_init(&ubi->buf_mutex); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ ubi->peb_buf1 = kmalloc(ubi->peb_size, GFP_KERNEL); -+#else - ubi->peb_buf1 = vmalloc(ubi->peb_size); -+#endif -+ - if (!ubi->peb_buf1) - goto out_free; - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ ubi->peb_buf2 = kmalloc(ubi->peb_size, GFP_KERNEL); -+#else - ubi->peb_buf2 = vmalloc(ubi->peb_size); -+#endif - if (!ubi->peb_buf2) - goto out_free; - - #ifdef CONFIG_MTD_UBI_DEBUG - mutex_init(&ubi->dbg_buf_mutex); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ ubi->dbg_peb_buf = kmalloc(ubi->peb_size, GFP_KERNEL); -+#else - ubi->dbg_peb_buf = vmalloc(ubi->peb_size); -+#endif -+ - if (!ubi->dbg_peb_buf) - goto out_free; - #endif -@@ -605,22 +927,33 @@ - goto out_free; - } - -+ if (ubi->autoresize_vol_id != -1) { -+ err = autoresize(ubi, ubi->autoresize_vol_id); -+ if (err) -+ goto out_detach; -+ } -+ - err = uif_init(ubi); - if (err) - goto out_detach; - -- ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt); -- ubi_msg("MTD device name: \"%s\"", ubi->mtd->name); -+ err = bdev_init(ubi); -+ if(err) -+ goto out_detach; -+ -+ ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); -+ if (IS_ERR(ubi->bgt_thread)) { -+ err = PTR_ERR(ubi->bgt_thread); -+ ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, -+ err); -+ goto out_uif; -+ } -+ -+ ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num); -+ ubi_msg("MTD device name: \"%s\"", mtd->name); - ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); -- ubi_msg("physical eraseblock size: %d bytes (%d KiB)", -- ubi->peb_size, ubi->peb_size >> 10); -- ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); - ubi_msg("number of good PEBs: %d", ubi->good_peb_count); - ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count); -- ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); -- ubi_msg("VID header offset: %d (aligned %d)", -- ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); -- ubi_msg("data offset: %d", ubi->leb_start); - ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots); - ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD); - ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT); -@@ -638,50 +971,141 @@ - wake_up_process(ubi->bgt_thread); - } - -- ubi_devices_cnt += 1; -- return 0; -+ ubi_devices[ubi_num] = ubi; -+ return ubi_num; - -+out_uif: -+ uif_close(ubi); - out_detach: - ubi_eba_close(ubi); - ubi_wl_close(ubi); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->vtbl); -+#else - vfree(ubi->vtbl); -+#endif - out_free: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->peb_buf1); -+ kfree(ubi->peb_buf2); -+#else - vfree(ubi->peb_buf1); - vfree(ubi->peb_buf2); -+#endif - #ifdef CONFIG_MTD_UBI_DEBUG -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->dbg_peb_buf); -+#else - vfree(ubi->dbg_peb_buf); - #endif -+#endif - kfree(ubi); --out_mtd: -- put_mtd_device(mtd); -- ubi_devices[ubi_devices_cnt] = NULL; - return err; - } - - /** -- * detach_mtd_dev - detach an MTD device. -- * @ubi: UBI device description object -+ * ubi_detach_mtd_dev - detach an MTD device. -+ * @ubi_num: UBI device number to detach from -+ * @anyway: detach MTD even if device reference count is not zero -+ * -+ * This function destroys an UBI device number @ubi_num and detaches the -+ * underlying MTD device. Returns zero in case of success and %-EBUSY if the -+ * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not -+ * exist. -+ * -+ * Note, the invocations of this function has to be serialized by the -+ * @ubi_devices_mutex. - */ --static void detach_mtd_dev(struct ubi_device *ubi) -+int ubi_detach_mtd_dev(int ubi_num, int anyway) - { -- int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index; -+ struct ubi_device *ubi; -+ -+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) -+ return -EINVAL; -+ -+ spin_lock(&ubi_devices_lock); -+ ubi = ubi_devices[ubi_num]; -+ if (!ubi) { -+ spin_unlock(&ubi_devices_lock); -+ return -EINVAL; -+ } - -+ if (ubi->ref_count) { -+ if (!anyway) { -+ spin_unlock(&ubi_devices_lock); -+ return -EBUSY; -+ } -+ /* This may only happen if there is a bug */ -+ ubi_err("%s reference count %d, destroy anyway", -+ ubi->ubi_name, ubi->ref_count); -+ } -+ ubi_devices[ubi_num] = NULL; -+ spin_unlock(&ubi_devices_lock); -+ -+ ubi_assert(ubi_num == ubi->ubi_num); - dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); -+ -+ /* -+ * Before freeing anything, we have to stop the background thread to -+ * prevent it from doing anything on this device while we are freeing. -+ */ -+ if (ubi->bgt_thread) -+ kthread_stop(ubi->bgt_thread); -+ - uif_close(ubi); - ubi_eba_close(ubi); - ubi_wl_close(ubi); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->vtbl); -+#else - vfree(ubi->vtbl); -+#endif - put_mtd_device(ubi->mtd); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->peb_buf1); -+ kfree(ubi->peb_buf2); -+#else - vfree(ubi->peb_buf1); - vfree(ubi->peb_buf2); -+#endif - #ifdef CONFIG_MTD_UBI_DEBUG -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->dbg_peb_buf); -+#else - vfree(ubi->dbg_peb_buf); - #endif -- kfree(ubi_devices[ubi_num]); -- ubi_devices[ubi_num] = NULL; -- ubi_devices_cnt -= 1; -- ubi_assert(ubi_devices_cnt >= 0); -- ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num); -+#endif -+ ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); -+ kfree(ubi); -+ return 0; -+} -+ -+/** -+ * find_mtd_device - open an MTD device by its name or number. -+ * @mtd_dev: name or number of the device -+ * -+ * This function tries to open and MTD device described by @mtd_dev string, -+ * which is first treated as an ASCII number, and if it is not true, it is -+ * treated as MTD device name. Returns MTD device description object in case of -+ * success and a negative error code in case of failure. -+ */ -+static struct mtd_info * __init open_mtd_device(const char *mtd_dev) -+{ -+ struct mtd_info *mtd; -+ int mtd_num; -+ char *endp; -+ -+ mtd_num = simple_strtoul(mtd_dev, &endp, 0); -+ if (*endp != '\0' || mtd_dev == endp) { -+ /* -+ * This does not look like an ASCII integer, probably this is -+ * MTD device name. -+ */ -+ mtd = get_mtd_device_nm(mtd_dev); -+ } else -+ mtd = get_mtd_device(NULL, mtd_num); -+ -+ return mtd; - } - - static int __init ubi_init(void) -@@ -693,47 +1117,94 @@ - BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); - - if (mtd_devs > UBI_MAX_DEVICES) { -- printk("UBI error: too many MTD devices, maximum is %d\n", -- UBI_MAX_DEVICES); -+ ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES); - return -EINVAL; - } - -+ /* Create base sysfs directory and sysfs files */ - ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); -- if (IS_ERR(ubi_class)) -- return PTR_ERR(ubi_class); -+ if (IS_ERR(ubi_class)) { -+ err = PTR_ERR(ubi_class); -+ ubi_err("cannot create UBI class"); -+ goto out; -+ } - - err = class_create_file(ubi_class, &ubi_version); -- if (err) -+ if (err) { -+ ubi_err("cannot create sysfs file"); - goto out_class; -+ } -+ -+ err = misc_register(&ubi_ctrl_cdev); -+ if (err) { -+ ubi_err("cannot register device"); -+ goto out_version; -+ } -+ -+ ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab", -+ sizeof(struct ubi_wl_entry), -+ 0, 0, NULL); -+ if (!ubi_wl_entry_slab) -+ goto out_dev_unreg; - - /* Attach MTD devices */ - for (i = 0; i < mtd_devs; i++) { - struct mtd_dev_param *p = &mtd_dev_param[i]; -+ struct mtd_info *mtd; - - cond_resched(); -- err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs); -- if (err) -+ -+ mtd = open_mtd_device(p->name); -+ if (IS_ERR(mtd)) { -+ err = PTR_ERR(mtd); -+ goto out_detach; -+ } -+ -+ mutex_lock(&ubi_devices_mutex); -+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, -+ p->vid_hdr_offs); -+ mutex_unlock(&ubi_devices_mutex); -+ if (err < 0) { -+ put_mtd_device(mtd); -+ ubi_err("cannot attach mtd%d", mtd->index); - goto out_detach; -+ } - } - - return 0; - - out_detach: - for (k = 0; k < i; k++) -- detach_mtd_dev(ubi_devices[k]); -+ if (ubi_devices[k]) { -+ mutex_lock(&ubi_devices_mutex); -+ ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1); -+ mutex_unlock(&ubi_devices_mutex); -+ } -+ kmem_cache_destroy(ubi_wl_entry_slab); -+out_dev_unreg: -+ misc_deregister(&ubi_ctrl_cdev); -+out_version: - class_remove_file(ubi_class, &ubi_version); - out_class: - class_destroy(ubi_class); -+out: -+ ubi_err("UBI error: cannot initialize UBI, error %d", err); - return err; - } - module_init(ubi_init); - - static void __exit ubi_exit(void) - { -- int i, n = ubi_devices_cnt; -+ int i; - -- for (i = 0; i < n; i++) -- detach_mtd_dev(ubi_devices[i]); -+ for (i = 0; i < UBI_MAX_DEVICES; i++) -+ if (ubi_devices[i]) { -+ mutex_lock(&ubi_devices_mutex); -+ ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1); -+ mutex_unlock(&ubi_devices_mutex); -+ } -+ kmem_cache_destroy(ubi_wl_entry_slab); -+ misc_deregister(&ubi_ctrl_cdev); - class_remove_file(ubi_class, &ubi_version); - class_destroy(ubi_class); - } -@@ -754,7 +1225,8 @@ - - result = simple_strtoul(str, &endp, 0); - if (str == endp || result < 0) { -- printk("UBI error: incorrect bytes count: \"%s\"\n", str); -+ printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n", -+ str); - return -EINVAL; - } - -@@ -764,15 +1236,14 @@ - case 'M': - result *= 1024; - case 'K': -- case 'k': - result *= 1024; -- if (endp[1] == 'i' && (endp[2] == '\0' || -- endp[2] == 'B' || endp[2] == 'b')) -+ if (endp[1] == 'i' && endp[2] == 'B') - endp += 2; - case '\0': - break; - default: -- printk("UBI error: incorrect bytes count: \"%s\"\n", str); -+ printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n", -+ str); - return -EINVAL; - } - -@@ -793,23 +1264,27 @@ - struct mtd_dev_param *p; - char buf[MTD_PARAM_LEN_MAX]; - char *pbuf = &buf[0]; -- char *tokens[3] = {NULL, NULL, NULL}; -+ char *tokens[2] = {NULL, NULL}; -+ -+ if (!val) -+ return -EINVAL; - - if (mtd_devs == UBI_MAX_DEVICES) { -- printk("UBI error: too many parameters, max. is %d\n", -+ printk(KERN_ERR "UBI error: too many parameters, max. is %d\n", - UBI_MAX_DEVICES); - return -EINVAL; - } - - len = strnlen(val, MTD_PARAM_LEN_MAX); - if (len == MTD_PARAM_LEN_MAX) { -- printk("UBI error: parameter \"%s\" is too long, max. is %d\n", -- val, MTD_PARAM_LEN_MAX); -+ printk(KERN_ERR "UBI error: parameter \"%s\" is too long, " -+ "max. is %d\n", val, MTD_PARAM_LEN_MAX); - return -EINVAL; - } - - if (len == 0) { -- printk("UBI warning: empty 'mtd=' parameter - ignored\n"); -+ printk(KERN_WARNING "UBI warning: empty 'mtd=' parameter - " -+ "ignored\n"); - return 0; - } - -@@ -819,11 +1294,12 @@ - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - -- for (i = 0; i < 3; i++) -+ for (i = 0; i < 2; i++) - tokens[i] = strsep(&pbuf, ","); - - if (pbuf) { -- printk("UBI error: too many arguments at \"%s\"\n", val); -+ printk(KERN_ERR "UBI error: too many arguments at \"%s\"\n", -+ val); - return -EINVAL; - } - -@@ -832,13 +1308,9 @@ - - if (tokens[1]) - p->vid_hdr_offs = bytes_str_to_int(tokens[1]); -- if (tokens[2]) -- p->data_offs = bytes_str_to_int(tokens[2]); - - if (p->vid_hdr_offs < 0) - return p->vid_hdr_offs; -- if (p->data_offs < 0) -- return p->data_offs; - - mtd_devs += 1; - return 0; -@@ -846,16 +1318,15 @@ - - module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000); - MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: " -- "mtd=[,,]. " -+ "mtd=[,].\n" - "Multiple \"mtd\" parameters may be specified.\n" -- "MTD devices may be specified by their number or name. " -- "Optional \"vid_hdr_offs\" and \"data_offs\" parameters " -- "specify UBI VID header position and data starting " -- "position to be used by UBI.\n" -- "Example: mtd=content,1984,2048 mtd=4 - attach MTD device" -- "with name content using VID header offset 1984 and data " -- "start 2048, and MTD device number 4 using default " -- "offsets"); -+ "MTD devices may be specified by their number or name.\n" -+ "Optional \"vid_hdr_offs\" parameter specifies UBI VID " -+ "header position and data starting position to be used " -+ "by UBI.\n" -+ "Example: mtd=content,1984 mtd=4 - attach MTD device" -+ "with name \"content\" using VID header offset 1984, and " -+ "MTD device number 4 with default VID header offset."); - - MODULE_VERSION(__stringify(UBI_VERSION)); - MODULE_DESCRIPTION("UBI - Unsorted Block Images"); ---- linux-2.6.24.7.old/drivers/mtd/ubi/cdev.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/cdev.c 2009-04-12 18:13:57.000000000 +0200 -@@ -28,6 +28,11 @@ - * - * Major and minor numbers are assigned dynamically to both UBI and volume - * character devices. -+ * -+ * Well, there is the third kind of character devices - the UBI control -+ * character device, which allows to manipulate by UBI devices - create and -+ * delete them. In other words, it is used for attaching and detaching MTD -+ * devices. - */ - - #include -@@ -39,34 +44,6 @@ - #include - #include "ubi.h" - --/* -- * Maximum sequence numbers of UBI and volume character device IOCTLs (direct -- * logical eraseblock erase is a debug-only feature). -- */ --#define UBI_CDEV_IOC_MAX_SEQ 2 --#ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO --#define VOL_CDEV_IOC_MAX_SEQ 1 --#else --#define VOL_CDEV_IOC_MAX_SEQ 2 --#endif -- --/** -- * major_to_device - get UBI device object by character device major number. -- * @major: major number -- * -- * This function returns a pointer to the UBI device object. -- */ --static struct ubi_device *major_to_device(int major) --{ -- int i; -- -- for (i = 0; i < ubi_devices_cnt; i++) -- if (ubi_devices[i] && ubi_devices[i]->major == major) -- return ubi_devices[i]; -- BUG(); -- return NULL; --} -- - /** - * get_exclusive - get exclusive access to an UBI volume. - * @desc: volume descriptor -@@ -124,9 +101,11 @@ - static int vol_cdev_open(struct inode *inode, struct file *file) - { - struct ubi_volume_desc *desc; -- const struct ubi_device *ubi = major_to_device(imajor(inode)); -- int vol_id = iminor(inode) - 1; -- int mode; -+ int vol_id = iminor(inode) - 1, mode, ubi_num; -+ -+ ubi_num = ubi_major2num(imajor(inode)); -+ if (ubi_num < 0) -+ return ubi_num; - - if (file->f_mode & FMODE_WRITE) - mode = UBI_READWRITE; -@@ -135,7 +114,7 @@ - - dbg_msg("open volume %d, mode %d", vol_id, mode); - -- desc = ubi_open_volume(ubi->ubi_num, vol_id, mode); -+ desc = ubi_open_volume(ubi_num, vol_id, mode); - if (IS_ERR(desc)) - return PTR_ERR(desc); - -@@ -153,8 +132,23 @@ - if (vol->updating) { - ubi_warn("update of volume %d not finished, volume is damaged", - vol->vol_id); -+ ubi_assert(!vol->changing_leb); - vol->updating = 0; -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(vol->upd_buf); -+#else - vfree(vol->upd_buf); -+#endif -+ } else if (vol->changing_leb) { -+ dbg_msg("only %lld of %lld bytes received for atomic LEB change" -+ " for volume %d:%d, cancel", vol->upd_received, -+ vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id); -+ vol->changing_leb = 0; -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(vol->upd_buf); -+#else -+ vfree(vol->upd_buf); -+#endif - } - - ubi_close_volume(desc); -@@ -205,13 +199,13 @@ - struct ubi_volume_desc *desc = file->private_data; - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; -- int err, lnum, off, len, vol_id = desc->vol->vol_id, tbuf_size; -+ int err, lnum, off, len, tbuf_size; - size_t count_save = count; - void *tbuf; - uint64_t tmp; - - dbg_msg("read %zd bytes from offset %lld of volume %d", -- count, *offp, vol_id); -+ count, *offp, vol->vol_id); - - if (vol->updating) { - dbg_err("updating"); -@@ -225,7 +219,7 @@ - return 0; - - if (vol->corrupted) -- dbg_msg("read from corrupted volume %d", vol_id); -+ dbg_msg("read from corrupted volume %d", vol->vol_id); - - if (*offp + count > vol->used_bytes) - count_save = count = vol->used_bytes - *offp; -@@ -233,7 +227,11 @@ - tbuf_size = vol->usable_leb_size; - if (count < tbuf_size) - tbuf_size = ALIGN(count, ubi->min_io_size); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ tbuf = kmalloc(tbuf_size, GFP_KERNEL); -+#else - tbuf = vmalloc(tbuf_size); -+#endif - if (!tbuf) - return -ENOMEM; - -@@ -249,7 +247,7 @@ - if (off + len >= vol->usable_leb_size) - len = vol->usable_leb_size - off; - -- err = ubi_eba_read_leb(ubi, vol_id, lnum, tbuf, off, len, 0); -+ err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0); - if (err) - break; - -@@ -272,7 +270,11 @@ - len = count > tbuf_size ? tbuf_size : count; - } while (count); - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(tbuf); -+#else - vfree(tbuf); -+#endif - return err ? err : count_save - count; - } - -@@ -289,13 +291,13 @@ - struct ubi_volume_desc *desc = file->private_data; - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; -- int lnum, off, len, tbuf_size, vol_id = vol->vol_id, err = 0; -+ int lnum, off, len, tbuf_size, err = 0; - size_t count_save = count; - char *tbuf; - uint64_t tmp; - - dbg_msg("requested: write %zd bytes to offset %lld of volume %u", -- count, *offp, desc->vol->vol_id); -+ count, *offp, vol->vol_id); - - if (vol->vol_type == UBI_STATIC_VOLUME) - return -EROFS; -@@ -321,7 +323,12 @@ - tbuf_size = vol->usable_leb_size; - if (count < tbuf_size) - tbuf_size = ALIGN(count, ubi->min_io_size); -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ tbuf = kmalloc(tbuf_size, GFP_KERNEL); -+#else - tbuf = vmalloc(tbuf_size); -+#endif - if (!tbuf) - return -ENOMEM; - -@@ -339,7 +346,7 @@ - break; - } - -- err = ubi_eba_write_leb(ubi, vol_id, lnum, tbuf, off, len, -+ err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len, - UBI_UNKNOWN); - if (err) - break; -@@ -356,7 +363,11 @@ - len = count > tbuf_size ? tbuf_size : count; - } - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(tbuf); -+#else - vfree(tbuf); -+#endif - return err ? err : count_save - count; - } - -@@ -372,22 +383,32 @@ - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - -- if (!vol->updating) -+ if (!vol->updating && !vol->changing_leb) - return vol_cdev_direct_write(file, buf, count, offp); - -- err = ubi_more_update_data(ubi, vol->vol_id, buf, count); -+ if (vol->updating) -+ err = ubi_more_update_data(ubi, vol, buf, count); -+ else -+ err = ubi_more_leb_change_data(ubi, vol, buf, count); -+ - if (err < 0) { -- ubi_err("cannot write %zd bytes of update data", count); -+ ubi_err("cannot accept more %zd bytes of data, error %d", -+ count, err); - return err; - } - - if (err) { - /* -- * Update is finished, @err contains number of actually written -- * bytes now. -+ * The operation is finished, @err contains number of actually -+ * written bytes. - */ - count = err; - -+ if (vol->changing_leb) { -+ revoke_exclusive(desc, UBI_READWRITE); -+ return count; -+ } -+ - err = ubi_check_volume(ubi, vol->vol_id); - if (err < 0) - return err; -@@ -402,7 +423,6 @@ - revoke_exclusive(desc, UBI_READWRITE); - } - -- *offp += count; - return count; - } - -@@ -416,6 +436,47 @@ - void __user *argp = (void __user *)arg; - - switch (cmd) { -+ /* LEB read command */ -+ case UBI_IOCLEBREAD: -+ { -+ struct ubi_leb leb; -+ int pnum; -+ char *lebbuf; -+ -+ if (copy_from_user(&leb, argp, sizeof(struct ubi_leb))){ -+ err = -EFAULT; -+ break; -+ } -+ -+ pnum = vol->eba_tbl[leb.lnum]; -+ if (pnum < 0) { -+ //the LEB is clean, no need dump -+ err = 1; -+ break; -+ } -+ -+ lebbuf = kmalloc(vol->ubi->leb_size, GFP_KERNEL); -+ if (!lebbuf){ -+ err = -ENOMEM; -+ break; -+ } -+ -+ err= ubi_eba_read_leb(ubi, vol, leb.lnum, lebbuf, 0, vol->ubi->leb_size, 0); -+ if (err){ -+ kfree(lebbuf); -+ break; -+ } -+ -+ err = copy_to_user(leb.buf, lebbuf, vol->ubi->leb_size); -+ if (err) { -+ kfree(lebbuf); -+ err = -EFAULT; -+ break; -+ } -+ kfree(lebbuf); -+ break; -+ } -+ - /* Volume update command */ - case UBI_IOCVOLUP: - { -@@ -447,11 +508,46 @@ - if (err < 0) - break; - -- err = ubi_start_update(ubi, vol->vol_id, bytes); -+ err = ubi_start_update(ubi, vol, bytes); - if (bytes == 0) - revoke_exclusive(desc, UBI_READWRITE); -+ break; -+ } -+ -+ /* Atomic logical eraseblock change command */ -+ case UBI_IOCEBCH: -+ { -+ struct ubi_leb_change_req req; -+ -+ err = copy_from_user(&req, argp, -+ sizeof(struct ubi_leb_change_req)); -+ if (err) { -+ err = -EFAULT; -+ break; -+ } -+ -+ if (desc->mode == UBI_READONLY || -+ vol->vol_type == UBI_STATIC_VOLUME) { -+ err = -EROFS; -+ break; -+ } -+ -+ /* Validate the request */ -+ err = -EINVAL; -+ if (req.lnum < 0 || req.lnum >= vol->reserved_pebs || -+ req.bytes < 0 || req.lnum >= vol->usable_leb_size) -+ break; -+ if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM && -+ req.dtype != UBI_UNKNOWN) -+ break; - -- file->f_pos = 0; -+ err = get_exclusive(desc); -+ if (err < 0) -+ break; -+ -+ err = ubi_start_leb_change(ubi, vol, &req); -+ if (req.bytes == 0) -+ revoke_exclusive(desc, UBI_READWRITE); - break; - } - -@@ -467,7 +563,8 @@ - break; - } - -- if (desc->mode == UBI_READONLY) { -+ if (desc->mode == UBI_READONLY || -+ vol->vol_type == UBI_STATIC_VOLUME) { - err = -EROFS; - break; - } -@@ -477,13 +574,8 @@ - break; - } - -- if (vol->vol_type != UBI_DYNAMIC_VOLUME) { -- err = -EROFS; -- break; -- } -- - dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); -- err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum); -+ err = ubi_eba_unmap_leb(ubi, vol, lnum); - if (err) - break; - -@@ -580,9 +672,9 @@ - if (!capable(CAP_SYS_RESOURCE)) - return -EPERM; - -- ubi = major_to_device(imajor(inode)); -- if (IS_ERR(ubi)) -- return PTR_ERR(ubi); -+ ubi = ubi_get_by_major(imajor(inode)); -+ if (!ubi) -+ return -ENODEV; - - switch (cmd) { - /* Create volume command */ -@@ -591,8 +683,7 @@ - struct ubi_mkvol_req req; - - dbg_msg("create volume"); -- err = copy_from_user(&req, argp, -- sizeof(struct ubi_mkvol_req)); -+ err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req)); - if (err) { - err = -EFAULT; - break; -@@ -604,7 +695,9 @@ - - req.name[req.name_len] = '\0'; - -+ mutex_lock(&ubi->volumes_mutex); - err = ubi_create_volume(ubi, &req); -+ mutex_unlock(&ubi->volumes_mutex); - if (err) - break; - -@@ -633,10 +726,16 @@ - break; - } - -+ mutex_lock(&ubi->volumes_mutex); - err = ubi_remove_volume(desc); -- if (err) -- ubi_close_volume(desc); -+ mutex_unlock(&ubi->volumes_mutex); - -+ /* -+ * The volume is deleted (unless an error occurred), and the -+ * 'struct ubi_volume' object will be freed when -+ * 'ubi_close_volume()' will call 'put_device()'. -+ */ -+ ubi_close_volume(desc); - break; - } - -@@ -648,8 +747,7 @@ - struct ubi_rsvol_req req; - - dbg_msg("re-size volume"); -- err = copy_from_user(&req, argp, -- sizeof(struct ubi_rsvol_req)); -+ err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req)); - if (err) { - err = -EFAULT; - break; -@@ -669,7 +767,9 @@ - pebs = !!do_div(tmp, desc->vol->usable_leb_size); - pebs += tmp; - -+ mutex_lock(&ubi->volumes_mutex); - err = ubi_resize_volume(desc, pebs); -+ mutex_unlock(&ubi->volumes_mutex); - ubi_close_volume(desc); - break; - } -@@ -679,9 +779,93 @@ - break; - } - -+ ubi_put_device(ubi); -+ return err; -+} -+ -+static int ctrl_cdev_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ int err = 0; -+ void __user *argp = (void __user *)arg; -+ -+ if (!capable(CAP_SYS_RESOURCE)) -+ return -EPERM; -+ -+ switch (cmd) { -+ /* Attach an MTD device command */ -+ case UBI_IOCATT: -+ { -+ struct ubi_attach_req req; -+ struct mtd_info *mtd; -+ -+ dbg_msg("attach MTD device"); -+ err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req)); -+ if (err) { -+ err = -EFAULT; -+ break; -+ } -+ -+ if (req.mtd_num < 0 || -+ (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) { -+ err = -EINVAL; -+ break; -+ } -+ -+ mtd = get_mtd_device(NULL, req.mtd_num); -+ if (IS_ERR(mtd)) { -+ err = PTR_ERR(mtd); -+ break; -+ } -+ -+ /* -+ * Note, further request verification is done by -+ * 'ubi_attach_mtd_dev()'. -+ */ -+ mutex_lock(&ubi_devices_mutex); -+ err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset); -+ mutex_unlock(&ubi_devices_mutex); -+ if (err < 0) -+ put_mtd_device(mtd); -+ else -+ /* @err contains UBI device number */ -+ err = put_user(err, (__user int32_t *)argp); -+ -+ break; -+ } -+ -+ /* Detach an MTD device command */ -+ case UBI_IOCDET: -+ { -+ int ubi_num; -+ -+ dbg_msg("dettach MTD device"); -+ err = get_user(ubi_num, (__user int32_t *)argp); -+ if (err) { -+ err = -EFAULT; -+ break; -+ } -+ -+ mutex_lock(&ubi_devices_mutex); -+ err = ubi_detach_mtd_dev(ubi_num, 0); -+ mutex_unlock(&ubi_devices_mutex); -+ break; -+ } -+ -+ default: -+ err = -ENOTTY; -+ break; -+ } -+ - return err; - } - -+/* UBI control character device operations */ -+struct file_operations ubi_ctrl_cdev_operations = { -+ .ioctl = ctrl_cdev_ioctl, -+ .owner = THIS_MODULE, -+}; -+ - /* UBI character device operations */ - struct file_operations ubi_cdev_operations = { - .owner = THIS_MODULE, ---- linux-2.6.24.7.old/drivers/mtd/ubi/debug.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/debug.h 2009-04-12 18:13:57.000000000 +0200 -@@ -39,8 +39,9 @@ - - #ifdef CONFIG_MTD_UBI_DEBUG_MSG - /* Generic debugging message */ --#define dbg_msg(fmt, ...) \ -- printk(KERN_DEBUG "UBI DBG: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__) -+#define dbg_msg(fmt, ...) \ -+ printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \ -+ current->pid, __FUNCTION__, ##__VA_ARGS__) - - #define ubi_dbg_dump_stack() dump_stack() - -@@ -76,38 +77,32 @@ - - #ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA - /* Messages from the eraseblock association unit */ --#define dbg_eba(fmt, ...) \ -- printk(KERN_DEBUG "UBI DBG eba: %s: " fmt "\n", __FUNCTION__, \ -- ##__VA_ARGS__) -+#define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) - #else - #define dbg_eba(fmt, ...) ({}) - #endif - - #ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL - /* Messages from the wear-leveling unit */ --#define dbg_wl(fmt, ...) \ -- printk(KERN_DEBUG "UBI DBG wl: %s: " fmt "\n", __FUNCTION__, \ -- ##__VA_ARGS__) -+#define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) - #else - #define dbg_wl(fmt, ...) ({}) - #endif - - #ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO - /* Messages from the input/output unit */ --#define dbg_io(fmt, ...) \ -- printk(KERN_DEBUG "UBI DBG io: %s: " fmt "\n", __FUNCTION__, \ -- ##__VA_ARGS__) -+#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) - #else - #define dbg_io(fmt, ...) ({}) - #endif - - #ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD - /* Initialization and build messages */ --#define dbg_bld(fmt, ...) \ -- printk(KERN_DEBUG "UBI DBG bld: %s: " fmt "\n", __FUNCTION__, \ -- ##__VA_ARGS__) -+#define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) -+#define UBI_IO_DEBUG 1 - #else - #define dbg_bld(fmt, ...) ({}) -+#define UBI_IO_DEBUG 0 - #endif - - #ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS ---- linux-2.6.24.7.old/drivers/mtd/ubi/eba.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/eba.c 2009-04-12 18:13:57.000000000 +0200 -@@ -31,7 +31,7 @@ - * logical eraseblock it is locked for reading or writing. The per-logical - * eraseblock locking is implemented by means of the lock tree. The lock tree - * is an RB-tree which refers all the currently locked logical eraseblocks. The -- * lock tree elements are &struct ltree_entry objects. They are indexed by -+ * lock tree elements are &struct ubi_ltree_entry objects. They are indexed by - * (@vol_id, @lnum) pairs. - * - * EBA also maintains the global sequence counter which is incremented each -@@ -45,34 +45,11 @@ - #include - #include - #include "ubi.h" -- -+#include "ubiblk.h" - /* Number of physical eraseblocks reserved for atomic LEB change operation */ - #define EBA_RESERVED_PEBS 1 - - /** -- * struct ltree_entry - an entry in the lock tree. -- * @rb: links RB-tree nodes -- * @vol_id: volume ID of the locked logical eraseblock -- * @lnum: locked logical eraseblock number -- * @users: how many tasks are using this logical eraseblock or wait for it -- * @mutex: read/write mutex to implement read/write access serialization to -- * the (@vol_id, @lnum) logical eraseblock -- * -- * When a logical eraseblock is being locked - corresponding &struct ltree_entry -- * object is inserted to the lock tree (@ubi->ltree). -- */ --struct ltree_entry { -- struct rb_node rb; -- int vol_id; -- int lnum; -- int users; -- struct rw_semaphore mutex; --}; -- --/* Slab cache for lock-tree entries */ --static struct kmem_cache *ltree_slab; -- --/** - * next_sqnum - get next sequence number. - * @ubi: UBI device description object - * -@@ -101,7 +78,7 @@ - */ - static int ubi_get_compat(const struct ubi_device *ubi, int vol_id) - { -- if (vol_id == UBI_LAYOUT_VOL_ID) -+ if (vol_id == UBI_LAYOUT_VOLUME_ID) - return UBI_LAYOUT_VOLUME_COMPAT; - return 0; - } -@@ -112,20 +89,20 @@ - * @vol_id: volume ID - * @lnum: logical eraseblock number - * -- * This function returns a pointer to the corresponding &struct ltree_entry -+ * This function returns a pointer to the corresponding &struct ubi_ltree_entry - * object if the logical eraseblock is locked and %NULL if it is not. - * @ubi->ltree_lock has to be locked. - */ --static struct ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id, -- int lnum) -+static struct ubi_ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id, -+ int lnum) - { - struct rb_node *p; - - p = ubi->ltree.rb_node; - while (p) { -- struct ltree_entry *le; -+ struct ubi_ltree_entry *le; - -- le = rb_entry(p, struct ltree_entry, rb); -+ le = rb_entry(p, struct ubi_ltree_entry, rb); - - if (vol_id < le->vol_id) - p = p->rb_left; -@@ -155,15 +132,17 @@ - * Returns pointer to the lock tree entry or %-ENOMEM if memory allocation - * failed. - */ --static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id, -- int lnum) -+static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi, -+ int vol_id, int lnum) - { -- struct ltree_entry *le, *le1, *le_free; -+ struct ubi_ltree_entry *le, *le1, *le_free; - -- le = kmem_cache_alloc(ltree_slab, GFP_NOFS); -+ le = kmalloc(sizeof(struct ubi_ltree_entry), GFP_NOFS); - if (!le) - return ERR_PTR(-ENOMEM); - -+ le->users = 0; -+ init_rwsem(&le->mutex); - le->vol_id = vol_id; - le->lnum = lnum; - -@@ -189,7 +168,7 @@ - p = &ubi->ltree.rb_node; - while (*p) { - parent = *p; -- le1 = rb_entry(parent, struct ltree_entry, rb); -+ le1 = rb_entry(parent, struct ubi_ltree_entry, rb); - - if (vol_id < le1->vol_id) - p = &(*p)->rb_left; -@@ -211,7 +190,7 @@ - spin_unlock(&ubi->ltree_lock); - - if (le_free) -- kmem_cache_free(ltree_slab, le_free); -+ kfree(le_free); - - return le; - } -@@ -227,7 +206,7 @@ - */ - static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum) - { -- struct ltree_entry *le; -+ struct ubi_ltree_entry *le; - - le = ltree_add_entry(ubi, vol_id, lnum); - if (IS_ERR(le)) -@@ -245,7 +224,7 @@ - static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum) - { - int free = 0; -- struct ltree_entry *le; -+ struct ubi_ltree_entry *le; - - spin_lock(&ubi->ltree_lock); - le = ltree_lookup(ubi, vol_id, lnum); -@@ -259,7 +238,7 @@ - - up_read(&le->mutex); - if (free) -- kmem_cache_free(ltree_slab, le); -+ kfree(le); - } - - /** -@@ -273,7 +252,7 @@ - */ - static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum) - { -- struct ltree_entry *le; -+ struct ubi_ltree_entry *le; - - le = ltree_add_entry(ubi, vol_id, lnum); - if (IS_ERR(le)) -@@ -283,6 +262,44 @@ - } - - /** -+ * leb_write_lock - lock logical eraseblock for writing. -+ * @ubi: UBI device description object -+ * @vol_id: volume ID -+ * @lnum: logical eraseblock number -+ * -+ * This function locks a logical eraseblock for writing if there is no -+ * contention and does nothing if there is contention. Returns %0 in case of -+ * success, %1 in case of contention, and and a negative error code in case of -+ * failure. -+ */ -+static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum) -+{ -+ int free; -+ struct ubi_ltree_entry *le; -+ -+ le = ltree_add_entry(ubi, vol_id, lnum); -+ if (IS_ERR(le)) -+ return PTR_ERR(le); -+ if (down_write_trylock(&le->mutex)) -+ return 0; -+ -+ /* Contention, cancel */ -+ spin_lock(&ubi->ltree_lock); -+ le->users -= 1; -+ ubi_assert(le->users >= 0); -+ if (le->users == 0) { -+ rb_erase(&le->rb, &ubi->ltree); -+ free = 1; -+ } else -+ free = 0; -+ spin_unlock(&ubi->ltree_lock); -+ if (free) -+ kfree(le); -+ -+ return 1; -+} -+ -+/** - * leb_write_unlock - unlock logical eraseblock. - * @ubi: UBI device description object - * @vol_id: volume ID -@@ -291,7 +308,7 @@ - static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum) - { - int free; -- struct ltree_entry *le; -+ struct ubi_ltree_entry *le; - - spin_lock(&ubi->ltree_lock); - le = ltree_lookup(ubi, vol_id, lnum); -@@ -306,23 +323,23 @@ - - up_write(&le->mutex); - if (free) -- kmem_cache_free(ltree_slab, le); -+ kfree(le); - } - - /** - * ubi_eba_unmap_leb - un-map logical eraseblock. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * - * This function un-maps logical eraseblock @lnum and schedules corresponding - * physical eraseblock for erasure. Returns zero in case of success and a - * negative error code in case of failure. - */ --int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum) -+int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum) - { -- int idx = vol_id2idx(ubi, vol_id), err, pnum; -- struct ubi_volume *vol = ubi->volumes[idx]; -+ int err, pnum, vol_id = vol->vol_id; - - if (ubi->ro_mode) - return -EROFS; -@@ -349,7 +366,7 @@ - /** - * ubi_eba_read_leb - read data. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * @buf: buffer to store the read data - * @offset: offset from where to read -@@ -365,12 +382,11 @@ - * returned for any volume type if an ECC error was detected by the MTD device - * driver. Other negative error cored may be returned in case of other errors. - */ --int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, -- int offset, int len, int check) -+int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, -+ void *buf, int offset, int len, int check) - { -- int err, pnum, scrub = 0, idx = vol_id2idx(ubi, vol_id); -+ int err, pnum, scrub = 0, vol_id = vol->vol_id; - struct ubi_vid_hdr *vid_hdr; -- struct ubi_volume *vol = ubi->volumes[idx]; - uint32_t uninitialized_var(crc); - - err = leb_read_lock(ubi, vol_id, lnum); -@@ -578,7 +594,7 @@ - /** - * ubi_eba_write_leb - write data to dynamic volume. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * @buf: the data to write - * @offset: offset within the logical eraseblock where to write -@@ -586,15 +602,14 @@ - * @dtype: data type - * - * This function writes data to logical eraseblock @lnum of a dynamic volume -- * @vol_id. Returns zero in case of success and a negative error code in case -+ * @vol. Returns zero in case of success and a negative error code in case - * of failure. In case of error, it is possible that something was still - * written to the flash media, but may be some garbage. - */ --int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, -+int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, - const void *buf, int offset, int len, int dtype) - { -- int idx = vol_id2idx(ubi, vol_id), err, pnum, tries = 0; -- struct ubi_volume *vol = ubi->volumes[idx]; -+ int err, pnum, tries = 0, vol_id = vol->vol_id; - struct ubi_vid_hdr *vid_hdr; - - if (ubi->ro_mode) -@@ -613,7 +628,8 @@ - if (err) { - ubi_warn("failed to write data to PEB %d", pnum); - if (err == -EIO && ubi->bad_allowed) -- err = recover_peb(ubi, pnum, vol_id, lnum, buf, offset, len); -+ err = recover_peb(ubi, pnum, vol_id, lnum, buf, -+ offset, len); - if (err) - ubi_ro_mode(ubi); - } -@@ -656,11 +672,14 @@ - goto write_error; - } - -- err = ubi_io_write_data(ubi, buf, pnum, offset, len); -- if (err) { -- ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, " -- "PEB %d", len, offset, vol_id, lnum, pnum); -- goto write_error; -+ if (len) { -+ err = ubi_io_write_data(ubi, buf, pnum, offset, len); -+ if (err) { -+ ubi_warn("failed to write %d bytes at offset %d of " -+ "LEB %d:%d, PEB %d", len, offset, vol_id, -+ lnum, pnum); -+ goto write_error; -+ } - } - - vol->eba_tbl[lnum] = pnum; -@@ -698,7 +717,7 @@ - /** - * ubi_eba_write_leb_st - write data to static volume. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * @buf: data to write - * @len: how many bytes to write -@@ -706,7 +725,7 @@ - * @used_ebs: how many logical eraseblocks will this volume contain - * - * This function writes data to logical eraseblock @lnum of static volume -- * @vol_id. The @used_ebs argument should contain total number of logical -+ * @vol. The @used_ebs argument should contain total number of logical - * eraseblock in this static volume. - * - * When writing to the last logical eraseblock, the @len argument doesn't have -@@ -718,12 +737,11 @@ - * volumes. This function returns zero in case of success and a negative error - * code in case of failure. - */ --int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, -- const void *buf, int len, int dtype, int used_ebs) -+int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum, const void *buf, int len, int dtype, -+ int used_ebs) - { -- int err, pnum, tries = 0, data_size = len; -- int idx = vol_id2idx(ubi, vol_id); -- struct ubi_volume *vol = ubi->volumes[idx]; -+ int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id; - struct ubi_vid_hdr *vid_hdr; - uint32_t crc; - -@@ -819,7 +837,7 @@ - /* - * ubi_eba_atomic_leb_change - change logical eraseblock atomically. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * @buf: data to write - * @len: how many bytes to write -@@ -834,17 +852,27 @@ - * UBI reserves one LEB for the "atomic LEB change" operation, so only one - * LEB change may be done at a time. This is ensured by @ubi->alc_mutex. - */ --int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, -- const void *buf, int len, int dtype) -+int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum, const void *buf, int len, int dtype) - { -- int err, pnum, tries = 0, idx = vol_id2idx(ubi, vol_id); -- struct ubi_volume *vol = ubi->volumes[idx]; -+ int err, pnum, tries = 0, vol_id = vol->vol_id; - struct ubi_vid_hdr *vid_hdr; - uint32_t crc; - - if (ubi->ro_mode) - return -EROFS; - -+ if (len == 0) { -+ /* -+ * Special case when data length is zero. In this case the LEB -+ * has to be unmapped and mapped somewhere else. -+ */ -+ err = ubi_eba_unmap_leb(ubi, vol, lnum); -+ if (err) -+ return err; -+ return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype); -+ } -+ - vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); - if (!vid_hdr) - return -ENOMEM; -@@ -928,20 +956,6 @@ - } - - /** -- * ltree_entry_ctor - lock tree entries slab cache constructor. -- * @obj: the lock-tree entry to construct -- * @cache: the lock tree entry slab cache -- * @flags: constructor flags -- */ --static void ltree_entry_ctor(struct kmem_cache *cache, void *obj) --{ -- struct ltree_entry *le = obj; -- -- le->users = 0; -- init_rwsem(&le->mutex); --} -- --/** - * ubi_eba_copy_leb - copy logical eraseblock. - * @ubi: UBI device description object - * @from: physical eraseblock number from where to copy -@@ -950,14 +964,16 @@ - * - * This function copies logical eraseblock from physical eraseblock @from to - * physical eraseblock @to. The @vid_hdr buffer may be changed by this -- * function. Returns zero in case of success, %UBI_IO_BITFLIPS if the operation -- * was canceled because bit-flips were detected at the target PEB, and a -- * negative error code in case of failure. -+ * function. Returns: -+ * o %0 in case of success; -+ * o %1 if the operation was canceled and should be tried later (e.g., -+ * because a bit-flip was detected at the target PEB); -+ * o %2 if the volume is being deleted and this LEB should not be moved. - */ - int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, - struct ubi_vid_hdr *vid_hdr) - { -- int err, vol_id, lnum, data_size, aldata_size, pnum, idx; -+ int err, vol_id, lnum, data_size, aldata_size, idx; - struct ubi_volume *vol; - uint32_t crc; - -@@ -973,51 +989,67 @@ - data_size = aldata_size = - ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); - -- /* -- * We do not want anybody to write to this logical eraseblock while we -- * are moving it, so we lock it. -- */ -- err = leb_write_lock(ubi, vol_id, lnum); -- if (err) -- return err; -- -- mutex_lock(&ubi->buf_mutex); -- -- /* -- * But the logical eraseblock might have been put by this time. -- * Cancel if it is true. -- */ - idx = vol_id2idx(ubi, vol_id); -- -+ spin_lock(&ubi->volumes_lock); - /* -- * We may race with volume deletion/re-size, so we have to hold -- * @ubi->volumes_lock. -+ * Note, we may race with volume deletion, which means that the volume -+ * this logical eraseblock belongs to might be being deleted. Since the -+ * volume deletion unmaps all the volume's logical eraseblocks, it will -+ * be locked in 'ubi_wl_put_peb()' and wait for the WL worker to finish. - */ -- spin_lock(&ubi->volumes_lock); - vol = ubi->volumes[idx]; - if (!vol) { -- dbg_eba("volume %d was removed meanwhile", vol_id); -+ /* No need to do further work, cancel */ -+ dbg_eba("volume %d is being removed, cancel", vol_id); - spin_unlock(&ubi->volumes_lock); -- goto out_unlock; -+ return 2; - } -+ spin_unlock(&ubi->volumes_lock); - -- pnum = vol->eba_tbl[lnum]; -- if (pnum != from) { -- dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to " -- "PEB %d, cancel", vol_id, lnum, from, pnum); -- spin_unlock(&ubi->volumes_lock); -- goto out_unlock; -+ /* -+ * We do not want anybody to write to this logical eraseblock while we -+ * are moving it, so lock it. -+ * -+ * Note, we are using non-waiting locking here, because we cannot sleep -+ * on the LEB, since it may cause deadlocks. Indeed, imagine a task is -+ * unmapping the LEB which is mapped to the PEB we are going to move -+ * (@from). This task locks the LEB and goes sleep in the -+ * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are -+ * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the -+ * LEB is already locked, we just do not move it and return %1. -+ */ -+ err = leb_write_trylock(ubi, vol_id, lnum); -+ if (err) { -+ dbg_eba("contention on LEB %d:%d, cancel", vol_id, lnum); -+ return err; - } -- spin_unlock(&ubi->volumes_lock); - -- /* OK, now the LEB is locked and we can safely start moving it */ -+ /* -+ * The LEB might have been put meanwhile, and the task which put it is -+ * probably waiting on @ubi->move_mutex. No need to continue the work, -+ * cancel it. -+ */ -+ if (vol->eba_tbl[lnum] != from) { -+ dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to " -+ "PEB %d, cancel", vol_id, lnum, from, -+ vol->eba_tbl[lnum]); -+ err = 1; -+ goto out_unlock_leb; -+ } - -+ /* -+ * OK, now the LEB is locked and we can safely start moving iy. Since -+ * this function utilizes thie @ubi->peb1_buf buffer which is shared -+ * with some other functions, so lock the buffer by taking the -+ * @ubi->buf_mutex. -+ */ -+ mutex_lock(&ubi->buf_mutex); - dbg_eba("read %d bytes of data", aldata_size); - err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size); - if (err && err != UBI_IO_BITFLIPS) { - ubi_warn("error %d while reading data from PEB %d", - err, from); -- goto out_unlock; -+ goto out_unlock_buf; - } - - /* -@@ -1053,7 +1085,7 @@ - - err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); - if (err) -- goto out_unlock; -+ goto out_unlock_buf; - - cond_resched(); - -@@ -1062,13 +1094,15 @@ - if (err) { - if (err != UBI_IO_BITFLIPS) - ubi_warn("cannot read VID header back from PEB %d", to); -- goto out_unlock; -+ else -+ err = 1; -+ goto out_unlock_buf; - } - - if (data_size > 0) { - err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); - if (err) -- goto out_unlock; -+ goto out_unlock_buf; - - cond_resched(); - -@@ -1082,7 +1116,9 @@ - if (err != UBI_IO_BITFLIPS) - ubi_warn("cannot read data back from PEB %d", - to); -- goto out_unlock; -+ else -+ err = 1; -+ goto out_unlock_buf; - } - - cond_resched(); -@@ -1090,15 +1126,16 @@ - if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { - ubi_warn("read data back from PEB %d - it is different", - to); -- goto out_unlock; -+ goto out_unlock_buf; - } - } - - ubi_assert(vol->eba_tbl[lnum] == from); - vol->eba_tbl[lnum] = to; - --out_unlock: -+out_unlock_buf: - mutex_unlock(&ubi->buf_mutex); -+out_unlock_leb: - leb_write_unlock(ubi, vol_id, lnum); - return err; - } -@@ -1125,14 +1162,6 @@ - mutex_init(&ubi->alc_mutex); - ubi->ltree = RB_ROOT; - -- if (ubi_devices_cnt == 0) { -- ltree_slab = kmem_cache_create("ubi_ltree_slab", -- sizeof(struct ltree_entry), 0, -- 0, <ree_entry_ctor); -- if (!ltree_slab) -- return -ENOMEM; -- } -- - ubi->global_sqnum = si->max_sqnum + 1; - num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; - -@@ -1168,6 +1197,15 @@ - } - } - -+ if (ubi->avail_pebs < EBA_RESERVED_PEBS) { -+ ubi_err("no enough physical eraseblocks (%d, need %d)", -+ ubi->avail_pebs, EBA_RESERVED_PEBS); -+ err = -ENOSPC; -+ goto out_free; -+ } -+ ubi->avail_pebs -= EBA_RESERVED_PEBS; -+ ubi->rsvd_pebs += EBA_RESERVED_PEBS; -+ - if (ubi->bad_allowed) { - ubi_calculate_reserved(ubi); - -@@ -1184,15 +1222,6 @@ - ubi->rsvd_pebs += ubi->beb_rsvd_pebs; - } - -- if (ubi->avail_pebs < EBA_RESERVED_PEBS) { -- ubi_err("no enough physical eraseblocks (%d, need %d)", -- ubi->avail_pebs, EBA_RESERVED_PEBS); -- err = -ENOSPC; -- goto out_free; -- } -- ubi->avail_pebs -= EBA_RESERVED_PEBS; -- ubi->rsvd_pebs += EBA_RESERVED_PEBS; -- - dbg_eba("EBA unit is initialized"); - return 0; - -@@ -1202,8 +1231,6 @@ - continue; - kfree(ubi->volumes[i]->eba_tbl); - } -- if (ubi_devices_cnt == 0) -- kmem_cache_destroy(ltree_slab); - return err; - } - -@@ -1222,6 +1249,141 @@ - continue; - kfree(ubi->volumes[i]->eba_tbl); - } -- if (ubi_devices_cnt == 1) -- kmem_cache_destroy(ltree_slab); - } -+ -+/* add by Nancy begin */ -+ -+static int ubiblk_fill_writecache(struct ubiblk_dev *ubiblk) -+{ -+ struct ubi_volume_desc *uv = ubiblk->uv; -+ struct ubi_device *ubi = uv->vol->ubi; -+ int ppb = ubi->leb_size / ubi->min_io_size; -+ unsigned short subpage_shift = 9; -+ unsigned short spp = ubi->min_io_size >> subpage_shift; -+ unsigned short page_shift = ffs(ubi->min_io_size) - 1; -+ unsigned short sectors_in_page_shift = ffs(ubi->min_io_size / 512) - 1; -+ unsigned short page, sector; -+ char page_buf[ubi->min_io_size]; -+ -+ if (!page_buf) -+ return -ENOMEM; -+ -+ for (page = 0; page < ppb; page++) { -+ if ( !ubiblk->page_sts[page]) { -+ ubi_leb_read(uv, ubiblk->vbw, -+ &ubiblk->write_cache[page<min_io_size, 0); -+ }else{ -+ for(sector = 0; sector < spp; sector++) -+ if( !ubiblk->subpage_sts[(page<vbw, -+ page_buf, -+ page<min_io_size, 0); -+ for(sector = 0; sector < spp; sector++) -+ if(!ubiblk->subpage_sts[(page<write_cache[ \ -+ (page<vol_id; -+ struct ubi_vid_hdr *vid_hdr; -+ uint32_t crc; -+ -+ if (ubi->ro_mode) -+ return -EROFS; -+ -+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); -+ if (!vid_hdr) -+ return -ENOMEM; -+ -+ ubiblk_fill_writecache(ubiblk); -+ mutex_lock(&ubi->alc_mutex); -+ err = leb_write_lock(ubi, vol_id, lnum); -+ if (err) -+ goto out_mutex; -+ -+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); -+ vid_hdr->vol_id = cpu_to_be32(vol_id); -+ vid_hdr->lnum = cpu_to_be32(lnum); -+ vid_hdr->compat = ubi_get_compat(ubi, vol_id); -+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad); -+ -+ crc = crc32(UBI_CRC32_INIT, buf, len); -+ vid_hdr->vol_type = UBI_VID_DYNAMIC; -+ vid_hdr->data_size = cpu_to_be32(len); -+ vid_hdr->copy_flag = 1; -+ vid_hdr->data_crc = cpu_to_be32(crc); -+ -+retry: -+ pnum = ubi_wl_get_peb(ubi, dtype); -+ if (pnum < 0) { -+ err = pnum; -+ goto out_leb_unlock; -+ } -+ -+ dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d", -+ vol_id, lnum, vol->eba_tbl[lnum], pnum); -+ -+ err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); -+ if (err) { -+ ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", -+ vol_id, lnum, pnum); -+ goto write_error; -+ } -+ -+ err = ubi_io_write_data(ubi, buf, pnum, 0, len); -+ if (err) { -+ ubi_warn("failed to write %d bytes of data to PEB %d", -+ len, pnum); -+ goto write_error; -+ } -+ if (vol->eba_tbl[lnum] >= 0) { -+ err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 0); -+ if (err) -+ goto out_leb_unlock; -+ } -+ -+ vol->eba_tbl[lnum] = pnum; -+ -+out_leb_unlock: -+ leb_write_unlock(ubi, vol_id, lnum); -+out_mutex: -+ mutex_unlock(&ubi->alc_mutex); -+ ubi_free_vid_hdr(ubi, vid_hdr); -+ return err; -+ -+write_error: -+ if (err != -EIO || !ubi->bad_allowed) { -+ /* -+ * This flash device does not admit of bad eraseblocks or -+ * something nasty and unexpected happened. Switch to read-only -+ * mode just in case. -+ */ -+ ubi_ro_mode(ubi); -+ goto out_leb_unlock; -+ } -+ -+ err = ubi_wl_put_peb(ubi, pnum, 1); -+ if (err || ++tries > UBI_IO_RETRIES) { -+ ubi_ro_mode(ubi); -+ goto out_leb_unlock; -+ } -+ -+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); -+ ubi_msg("try another PEB"); -+ goto retry; -+} -+ -+/* add by Nancy end*/ -+ ---- linux-2.6.24.7.old/drivers/mtd/ubi/gluebi.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/gluebi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -103,15 +103,15 @@ - * This function returns zero in case of success and a negative error code in - * case of failure. - */ --static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, unsigned char *buf) -+static int gluebi_read(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, unsigned char *buf) - { - int err = 0, lnum, offs, total_read; - struct ubi_volume *vol; - struct ubi_device *ubi; - uint64_t tmp = from; - -- dbg_msg("read %zd bytes from offset %lld", len, from); -+ dbg_msg("read %lld bytes from offset %lld", len, from); - - if (len < 0 || from < 0 || from + len > mtd->size) - return -EINVAL; -@@ -129,8 +129,7 @@ - if (to_read > total_read) - to_read = total_read; - -- err = ubi_eba_read_leb(ubi, vol->vol_id, lnum, buf, offs, -- to_read, 0); -+ err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0); - if (err) - break; - -@@ -155,15 +154,15 @@ - * This function returns zero in case of success and a negative error code in - * case of failure. - */ --static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, -- size_t *retlen, const u_char *buf) -+static int gluebi_write(struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len, -+ size_mtd_t *retlen, const u_char *buf) - { - int err = 0, lnum, offs, total_written; - struct ubi_volume *vol; - struct ubi_device *ubi; - uint64_t tmp = to; - -- dbg_msg("write %zd bytes to offset %lld", len, to); -+ dbg_msg("write %lld bytes to offset %lld", len, to); - - if (len < 0 || to < 0 || len + to > mtd->size) - return -EINVAL; -@@ -177,7 +176,7 @@ - offs = do_div(tmp, mtd->erasesize); - lnum = tmp; - -- if (len % mtd->writesize || offs % mtd->writesize) -+ if ((u32)len % mtd->writesize || offs % mtd->writesize) - return -EINVAL; - - total_written = len; -@@ -187,8 +186,8 @@ - if (to_write > total_written) - to_write = total_written; - -- err = ubi_eba_write_leb(ubi, vol->vol_id, lnum, buf, offs, -- to_write, UBI_UNKNOWN); -+ err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write, -+ UBI_UNKNOWN); - if (err) - break; - -@@ -216,7 +215,7 @@ - struct ubi_volume *vol; - struct ubi_device *ubi; - -- dbg_msg("erase %u bytes at offset %u", instr->len, instr->addr); -+ dbg_msg("erase %llu bytes at offset %llu", instr->len, instr->addr); - - if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) - return -EINVAL; -@@ -224,11 +223,11 @@ - if (instr->len < 0 || instr->addr + instr->len > mtd->size) - return -EINVAL; - -- if (instr->addr % mtd->writesize || instr->len % mtd->writesize) -+ if ((u32)instr->addr % mtd->writesize || (u32)instr->len % mtd->writesize) - return -EINVAL; - -- lnum = instr->addr / mtd->erasesize; -- count = instr->len / mtd->erasesize; -+ lnum = instr->addr >> (ffs(mtd->erasesize)-1); -+ count = instr->len >> (ffs(mtd->erasesize)-1); - - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); - ubi = vol->ubi; -@@ -237,7 +236,7 @@ - return -EROFS; - - for (i = 0; i < count; i++) { -- err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum + i); -+ err = ubi_eba_unmap_leb(ubi, vol, lnum + i); - if (err) - goto out_err; - } -@@ -292,11 +291,12 @@ - /* - * In case of dynamic volume, MTD device size is just volume size. In - * case of a static volume the size is equivalent to the amount of data -- * bytes, which is zero at this moment and will be changed after volume -- * update. -+ * bytes. - */ - if (vol->vol_type == UBI_DYNAMIC_VOLUME) - mtd->size = vol->usable_leb_size * vol->reserved_pebs; -+ else -+ mtd->size = vol->used_bytes; - - if (add_mtd_device(mtd)) { - ubi_err("cannot not add MTD device\n"); -@@ -304,7 +304,7 @@ - return -ENFILE; - } - -- dbg_msg("added mtd%d (\"%s\"), size %u, EB size %u", -+ dbg_msg("added mtd%d (\"%s\"), size %llu, EB size %u", - mtd->index, mtd->name, mtd->size, mtd->erasesize); - return 0; - } ---- linux-2.6.24.7.old/drivers/mtd/ubi/io.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/io.c 2009-04-12 18:13:57.000000000 +0200 -@@ -135,8 +135,8 @@ - int len) - { - int err, retries = 0; -- size_t read; -- loff_t addr; -+ size_mtd_t read; -+ loff_mtd_t addr; - - dbg_io("read %d bytes from PEB %d:%d", len, pnum, offset); - -@@ -148,7 +148,7 @@ - if (err) - return err > 0 ? -EINVAL : err; - -- addr = (loff_t)pnum * ubi->peb_size + offset; -+ addr = (loff_mtd_t)pnum * ubi->peb_size + offset; - retry: - err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); - if (err) { -@@ -164,15 +164,25 @@ - - if (read != len && retries++ < UBI_IO_RETRIES) { - dbg_io("error %d while reading %d bytes from PEB %d:%d, " -- "read only %zd bytes, retry", -+ "read only %lld bytes, retry", - err, len, pnum, offset, read); - yield(); - goto retry; - } - - ubi_err("error %d while reading %d bytes from PEB %d:%d, " -- "read %zd bytes", err, len, pnum, offset, read); -+ "read %lld bytes", err, len, pnum, offset, read); - ubi_dbg_dump_stack(); -+ -+ /* -+ * The driver should never return -EBADMSG if it failed to read -+ * all the requested data. But some buggy drivers might do -+ * this, so we change it to -EIO. -+ */ -+ if (read != len && err == -EBADMSG) { -+ ubi_assert(0); -+ err = -EIO; -+ } - } else { - ubi_assert(len == read); - -@@ -206,8 +216,8 @@ - int len) - { - int err; -- size_t written; -- loff_t addr; -+ size_mtd_t written; -+ loff_mtd_t addr; - - dbg_io("write %d bytes to PEB %d:%d", len, pnum, offset); - -@@ -252,11 +262,11 @@ - return -EIO; - } - -- addr = (loff_t)pnum * ubi->peb_size + offset; -+ addr = (loff_mtd_t)pnum * ubi->peb_size + offset; - err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf); - if (err) { - ubi_err("error %d while writing %d bytes to PEB %d:%d, written" -- " %zd bytes", err, len, pnum, offset, written); -+ " %lld bytes", err, len, pnum, offset, written); - ubi_dbg_dump_stack(); - } else - ubi_assert(written == len); -@@ -298,7 +308,7 @@ - memset(&ei, 0, sizeof(struct erase_info)); - - ei.mtd = ubi->mtd; -- ei.addr = (loff_t)pnum * ubi->peb_size; -+ ei.addr = (loff_mtd_t)pnum * ubi->peb_size; - ei.len = ubi->peb_size; - ei.callback = erase_callback; - ei.priv = (unsigned long)&wq; -@@ -501,7 +511,7 @@ - if (ubi->bad_allowed) { - int ret; - -- ret = mtd->block_isbad(mtd, (loff_t)pnum * ubi->peb_size); -+ ret = mtd->block_isbad(mtd, (loff_mtd_t)pnum * ubi->peb_size); - if (ret < 0) - ubi_err("error %d while checking if PEB %d is bad", - ret, pnum); -@@ -536,7 +546,7 @@ - if (!ubi->bad_allowed) - return 0; - -- err = mtd->block_markbad(mtd, (loff_t)pnum * ubi->peb_size); -+ err = mtd->block_markbad(mtd, (loff_mtd_t)pnum * ubi->peb_size); - if (err) - ubi_err("cannot mark PEB %d bad, error %d", pnum, err); - return err; -@@ -621,6 +631,8 @@ - - dbg_io("read EC header from PEB %d", pnum); - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); -+ if (UBI_IO_DEBUG) -+ verbose = 1; - - err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); - if (err) { -@@ -894,6 +906,8 @@ - - dbg_io("read VID header from PEB %d", pnum); - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); -+ if (UBI_IO_DEBUG) -+ verbose = 1; - - p = (char *)vid_hdr - ubi->vid_hdr_shift; - err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, -@@ -1218,15 +1232,15 @@ - static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, - int len) - { -- size_t read; -+ size_mtd_t read; - int err; -- loff_t addr = (loff_t)pnum * ubi->peb_size + offset; -+ loff_mtd_t addr = (loff_mtd_t)pnum * ubi->peb_size + offset; - - mutex_lock(&ubi->dbg_buf_mutex); - err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf); - if (err && err != -EUCLEAN) { - ubi_err("error %d while reading %d bytes from PEB %d:%d, " -- "read %zd bytes", err, len, pnum, offset, read); -+ "read %lld bytes", err, len, pnum, offset, read); - goto error; - } - ---- linux-2.6.24.7.old/drivers/mtd/ubi/kapi.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/kapi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -24,29 +24,36 @@ - #include - #include - #include "ubi.h" -+#include "ubiblk.h" - -+extern int ubiblk_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum, void *buf, int len, int dtype, struct ubiblk_dev *ubiblk); - /** - * ubi_get_device_info - get information about UBI device. - * @ubi_num: UBI device number - * @di: the information is stored here - * -- * This function returns %0 in case of success and a %-ENODEV if there is no -- * such UBI device. -+ * This function returns %0 in case of success, %-EINVAL if the UBI device -+ * number is invalid, and %-ENODEV if there is no such UBI device. - */ - int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) - { -- const struct ubi_device *ubi; -+ struct ubi_device *ubi; -+ -+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) -+ return -EINVAL; - -- if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || -- !ubi_devices[ubi_num]) -+ ubi = ubi_get_device(ubi_num); -+ if (!ubi) - return -ENODEV; - -- ubi = ubi_devices[ubi_num]; - di->ubi_num = ubi->ubi_num; - di->leb_size = ubi->leb_size; - di->min_io_size = ubi->min_io_size; - di->ro_mode = ubi->ro_mode; -- di->cdev = MKDEV(ubi->major, 0); -+ di->cdev = ubi->cdev.dev; -+ -+ ubi_put_device(ubi); - return 0; - } - EXPORT_SYMBOL_GPL(ubi_get_device_info); -@@ -73,7 +80,7 @@ - vi->usable_leb_size = vol->usable_leb_size; - vi->name_len = vol->name_len; - vi->name = vol->name; -- vi->cdev = MKDEV(ubi->major, vi->vol_id + 1); -+ vi->cdev = vol->cdev.dev; - } - EXPORT_SYMBOL_GPL(ubi_get_volume_info); - -@@ -104,37 +111,39 @@ - - dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); - -- err = -ENODEV; -- if (ubi_num < 0) -- return ERR_PTR(err); -- -- ubi = ubi_devices[ubi_num]; -- -- if (!try_module_get(THIS_MODULE)) -- return ERR_PTR(err); -- -- if (ubi_num >= UBI_MAX_DEVICES || !ubi) -- goto out_put; -+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) -+ return ERR_PTR(-EINVAL); - -- err = -EINVAL; -- if (vol_id < 0 || vol_id >= ubi->vtbl_slots) -- goto out_put; - if (mode != UBI_READONLY && mode != UBI_READWRITE && - mode != UBI_EXCLUSIVE) -- goto out_put; -+ return ERR_PTR(-EINVAL); -+ -+ /* -+ * First of all, we have to get the UBI device to prevent its removal. -+ */ -+ ubi = ubi_get_device(ubi_num); -+ if (!ubi) -+ return ERR_PTR(-ENODEV); -+ -+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots) { -+ err = -EINVAL; -+ goto out_put_ubi; -+ } - - desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); - if (!desc) { - err = -ENOMEM; -- goto out_put; -+ goto out_put_ubi; - } - -+ err = -ENODEV; -+ if (!try_module_get(THIS_MODULE)) -+ goto out_free; -+ - spin_lock(&ubi->volumes_lock); - vol = ubi->volumes[vol_id]; -- if (!vol) { -- err = -ENODEV; -+ if (!vol) - goto out_unlock; -- } - - err = -EBUSY; - switch (mode) { -@@ -156,21 +165,19 @@ - vol->exclusive = 1; - break; - } -+ get_device(&vol->dev); -+ vol->ref_count += 1; - spin_unlock(&ubi->volumes_lock); - - desc->vol = vol; - desc->mode = mode; - -- /* -- * To prevent simultaneous checks of the same volume we use @vtbl_mutex, -- * although it is not the purpose it was introduced for. -- */ -- mutex_lock(&ubi->vtbl_mutex); -+ mutex_lock(&ubi->ckvol_mutex); - if (!vol->checked) { - /* This is the first open - check the volume */ - err = ubi_check_volume(ubi, vol_id); - if (err < 0) { -- mutex_unlock(&ubi->vtbl_mutex); -+ mutex_unlock(&ubi->ckvol_mutex); - ubi_close_volume(desc); - return ERR_PTR(err); - } -@@ -181,14 +188,17 @@ - } - vol->checked = 1; - } -- mutex_unlock(&ubi->vtbl_mutex); -+ mutex_unlock(&ubi->ckvol_mutex); -+ - return desc; - - out_unlock: - spin_unlock(&ubi->volumes_lock); -- kfree(desc); --out_put: - module_put(THIS_MODULE); -+out_free: -+ kfree(desc); -+out_put_ubi: -+ ubi_put_device(ubi); - return ERR_PTR(err); - } - EXPORT_SYMBOL_GPL(ubi_open_volume); -@@ -205,8 +215,8 @@ - int mode) - { - int i, vol_id = -1, len; -- struct ubi_volume_desc *ret; - struct ubi_device *ubi; -+ struct ubi_volume_desc *ret; - - dbg_msg("open volume %s, mode %d", name, mode); - -@@ -217,14 +227,12 @@ - if (len > UBI_VOL_NAME_MAX) - return ERR_PTR(-EINVAL); - -- ret = ERR_PTR(-ENODEV); -- if (!try_module_get(THIS_MODULE)) -- return ret; -- -- if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi_devices[ubi_num]) -- goto out_put; -+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) -+ return ERR_PTR(-EINVAL); - -- ubi = ubi_devices[ubi_num]; -+ ubi = ubi_get_device(ubi_num); -+ if (!ubi) -+ return ERR_PTR(-ENODEV); - - spin_lock(&ubi->volumes_lock); - /* Walk all volumes of this UBI device */ -@@ -238,13 +246,16 @@ - } - spin_unlock(&ubi->volumes_lock); - -- if (vol_id < 0) -- goto out_put; -- -- ret = ubi_open_volume(ubi_num, vol_id, mode); -+ if (vol_id >= 0) -+ ret = ubi_open_volume(ubi_num, vol_id, mode); -+ else -+ ret = ERR_PTR(-ENODEV); - --out_put: -- module_put(THIS_MODULE); -+ /* -+ * We should put the UBI device even in case of success, because -+ * 'ubi_open_volume()' took a reference as well. -+ */ -+ ubi_put_device(ubi); - return ret; - } - EXPORT_SYMBOL_GPL(ubi_open_volume_nm); -@@ -256,10 +267,11 @@ - void ubi_close_volume(struct ubi_volume_desc *desc) - { - struct ubi_volume *vol = desc->vol; -+ struct ubi_device *ubi = vol->ubi; - - dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); - -- spin_lock(&vol->ubi->volumes_lock); -+ spin_lock(&ubi->volumes_lock); - switch (desc->mode) { - case UBI_READONLY: - vol->readers -= 1; -@@ -270,9 +282,12 @@ - case UBI_EXCLUSIVE: - vol->exclusive = 0; - } -- spin_unlock(&vol->ubi->volumes_lock); -+ vol->ref_count -= 1; -+ spin_unlock(&ubi->volumes_lock); - - kfree(desc); -+ put_device(&vol->dev); -+ ubi_put_device(ubi); - module_put(THIS_MODULE); - } - EXPORT_SYMBOL_GPL(ubi_close_volume); -@@ -332,7 +347,7 @@ - if (len == 0) - return 0; - -- err = ubi_eba_read_leb(ubi, vol_id, lnum, buf, offset, len, check); -+ err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); - if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { - ubi_warn("mark volume %d as corrupted", vol_id); - vol->corrupted = 1; -@@ -399,7 +414,7 @@ - if (len == 0) - return 0; - -- return ubi_eba_write_leb(ubi, vol_id, lnum, buf, offset, len, dtype); -+ return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len, dtype); - } - EXPORT_SYMBOL_GPL(ubi_leb_write); - -@@ -448,7 +463,7 @@ - if (len == 0) - return 0; - -- return ubi_eba_atomic_leb_change(ubi, vol_id, lnum, buf, len, dtype); -+ return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype); - } - EXPORT_SYMBOL_GPL(ubi_leb_change); - -@@ -468,9 +483,9 @@ - { - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; -- int err, vol_id = vol->vol_id; -+ int err; - -- dbg_msg("erase LEB %d:%d", vol_id, lnum); -+ dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); - - if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) - return -EROFS; -@@ -481,7 +496,7 @@ - if (vol->upd_marker) - return -EBADF; - -- err = ubi_eba_unmap_leb(ubi, vol_id, lnum); -+ err = ubi_eba_unmap_leb(ubi, vol, lnum); - if (err) - return err; - -@@ -529,9 +544,8 @@ - { - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; -- int vol_id = vol->vol_id; - -- dbg_msg("unmap LEB %d:%d", vol_id, lnum); -+ dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); - - if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) - return -EROFS; -@@ -542,11 +556,55 @@ - if (vol->upd_marker) - return -EBADF; - -- return ubi_eba_unmap_leb(ubi, vol_id, lnum); -+ return ubi_eba_unmap_leb(ubi, vol, lnum); - } - EXPORT_SYMBOL_GPL(ubi_leb_unmap); - - /** -+ * ubi_leb_map - map logical erasblock to a physical eraseblock. -+ * @desc: volume descriptor -+ * @lnum: logical eraseblock number -+ * @dtype: expected data type -+ * -+ * This function maps an un-mapped logical eraseblock @lnum to a physical -+ * eraseblock. This means, that after a successfull invocation of this -+ * function the logical eraseblock @lnum will be empty (contain only %0xFF -+ * bytes) and be mapped to a physical eraseblock, even if an unclean reboot -+ * happens. -+ * -+ * This function returns zero in case of success, %-EBADF if the volume is -+ * damaged because of an interrupted update, %-EBADMSG if the logical -+ * eraseblock is already mapped, and other negative error codes in case of -+ * other failures. -+ */ -+int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype) -+{ -+ struct ubi_volume *vol = desc->vol; -+ struct ubi_device *ubi = vol->ubi; -+ -+ dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); -+ -+ if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) -+ return -EROFS; -+ -+ if (lnum < 0 || lnum >= vol->reserved_pebs) -+ return -EINVAL; -+ -+ if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && -+ dtype != UBI_UNKNOWN) -+ return -EINVAL; -+ -+ if (vol->upd_marker) -+ return -EBADF; -+ -+ if (vol->eba_tbl[lnum] >= 0) -+ return -EBADMSG; -+ -+ return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype); -+} -+EXPORT_SYMBOL_GPL(ubi_leb_map); -+ -+/** - * ubi_is_mapped - check if logical eraseblock is mapped. - * @desc: volume descriptor - * @lnum: logical eraseblock number -@@ -577,3 +635,138 @@ - return vol->eba_tbl[lnum] >= 0; - } - EXPORT_SYMBOL_GPL(ubi_is_mapped); -+ -+/* add by Nancy start */ -+ -+int ubiblk_leb_change(struct ubiblk_dev *ubiblk) -+{ -+ struct ubi_volume *vol = ubiblk->uv->vol; -+ struct ubi_device *ubi = vol->ubi; -+ int vol_id = vol->vol_id; -+ -+ struct ubi_volume_desc *desc = ubiblk->uv; -+ int lnum = ubiblk->vbw; -+ int len = ubi->leb_size; -+ int dtype = UBI_UNKNOWN; -+ void *buf = ubiblk->write_cache; -+ -+ dbg_msg("atomically write %d bytes to LEB %d:%d", len, vol_id, lnum); -+ -+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots) -+ return -EINVAL; -+ -+ if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) -+ return -EROFS; -+ -+ if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 || -+ len > vol->usable_leb_size || len % ubi->min_io_size) -+ return -EINVAL; -+ -+ if (vol->upd_marker) -+ return -EBADF; -+ -+ if (len == 0) -+ return 0; -+ -+ return ubiblk_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype, ubiblk); -+} -+EXPORT_SYMBOL_GPL(ubiblk_leb_change); -+ -+ -+void ubi_open_blkdev(int ubi_num, int vol_id, int mode) -+{ -+ int err; -+ struct ubi_device *ubi; -+ struct ubi_volume *vol; -+ -+ dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); -+ -+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) -+ return; -+ -+ if (mode != UBI_READONLY && mode != UBI_READWRITE && -+ mode != UBI_EXCLUSIVE) -+ return; -+ /* -+ * First of all, we have to get the UBI device to prevent its removal. -+ */ -+ ubi = ubi_get_device(ubi_num); -+ if (!ubi) -+ return; -+ -+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots) { -+ err = -EINVAL; -+ goto out_put_ubi; -+ } -+ -+ err = -ENODEV; -+ if (!try_module_get(THIS_MODULE)) -+ goto out_put_ubi; -+ -+ spin_lock(&ubi->volumes_lock); -+ vol = ubi->volumes[vol_id]; -+ if (!vol) -+ goto out_unlock; -+ -+ err = -EBUSY; -+ switch (mode) { -+ case UBI_READONLY: -+ if (vol->exclusive) -+ goto out_unlock; -+ vol->readers += 1; -+ break; -+ -+ case UBI_READWRITE: -+ if (vol->exclusive || vol->writers > 0) -+ goto out_unlock; -+ vol->writers += 1; -+ break; -+ -+ case UBI_EXCLUSIVE: -+ if (vol->exclusive || vol->writers || vol->readers) -+ goto out_unlock; -+ vol->exclusive = 1; -+ break; -+ } -+ get_device(&vol->dev); -+ vol->ref_count += 1; -+ spin_unlock(&ubi->volumes_lock); -+ return; -+ -+out_unlock: -+ spin_unlock(&ubi->volumes_lock); -+ module_put(THIS_MODULE); -+out_put_ubi: -+ ubi_put_device(ubi); -+ return; -+} -+EXPORT_SYMBOL_GPL(ubi_open_blkdev); -+ -+ -+void ubi_close_blkdev(struct ubi_volume_desc *desc) -+{ -+ struct ubi_volume *vol = desc->vol; -+ struct ubi_device *ubi = vol->ubi; -+ -+ dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); -+ -+ spin_lock(&ubi->volumes_lock); -+ switch (desc->mode) { -+ case UBI_READONLY: -+ vol->readers -= 1; -+ break; -+ case UBI_READWRITE: -+ vol->writers -= 1; -+ break; -+ case UBI_EXCLUSIVE: -+ vol->exclusive = 0; -+ } -+ vol->ref_count -= 1; -+ spin_unlock(&ubi->volumes_lock); -+ put_device(&vol->dev); -+ ubi_put_device(ubi); -+ module_put(THIS_MODULE); -+} -+EXPORT_SYMBOL_GPL(ubi_close_blkdev); -+/* add by Nancy end */ -+ ---- linux-2.6.24.7.old/drivers/mtd/ubi/misc.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/misc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -67,7 +67,12 @@ - if (vol->vol_type != UBI_STATIC_VOLUME) - return 0; - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ buf = kmalloc(vol->usable_leb_size, GFP_KERNEL); -+#else - buf = vmalloc(vol->usable_leb_size); -+#endif -+ - if (!buf) - return -ENOMEM; - -@@ -79,7 +84,7 @@ - else - size = vol->usable_leb_size; - -- err = ubi_eba_read_leb(ubi, vol_id, i, buf, 0, size, 1); -+ err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1); - if (err) { - if (err == -EBADMSG) - err = 1; -@@ -87,7 +92,11 @@ - } - } - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(buf); -+#else - vfree(buf); -+#endif - return err; - } - ---- linux-2.6.24.7.old/drivers/mtd/ubi/scan.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/scan.c 2009-04-12 18:13:57.000000000 +0200 -@@ -42,6 +42,7 @@ - - #include - #include -+#include - #include "ubi.h" - - #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID -@@ -92,27 +93,6 @@ - } - - /** -- * commit_to_mean_value - commit intermediate results to the final mean erase -- * counter value. -- * @si: scanning information -- * -- * This is a helper function which calculates partial mean erase counter mean -- * value and adds it to the resulting mean value. As we can work only in -- * integer arithmetic and we want to calculate the mean value of erase counter -- * accurately, we first sum erase counter values in @si->ec_sum variable and -- * count these components in @si->ec_count. If this temporary @si->ec_sum is -- * going to overflow, we calculate the partial mean value -- * (@si->ec_sum/@si->ec_count) and add it to @si->mean_ec. -- */ --static void commit_to_mean_value(struct ubi_scan_info *si) --{ -- si->ec_sum /= si->ec_count; -- if (si->ec_sum % si->ec_count >= si->ec_count / 2) -- si->mean_ec += 1; -- si->mean_ec += si->ec_sum; --} -- --/** - * validate_vid_hdr - check that volume identifier header is correct and - * consistent. - * @vid_hdr: the volume identifier header to check -@@ -286,9 +266,14 @@ - * FIXME: but this is anyway obsolete and will be removed at - * some point. - */ -- - dbg_bld("using old crappy leb_ver stuff"); - -+ if (v1 == v2) { -+ ubi_err("PEB %d and PEB %d have the same version %lld", -+ seb->pnum, pnum, v1); -+ return -EINVAL; -+ } -+ - abs = v1 - v2; - if (abs < 0) - abs = -abs; -@@ -353,7 +338,11 @@ - /* Read the data of the copy and check the CRC */ - - len = be32_to_cpu(vid_hdr->data_size); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ buf = kmalloc(len, GFP_KERNEL); -+#else - buf = vmalloc(len); -+#endif - if (!buf) { - err = -ENOMEM; - goto out_free_vidh; -@@ -376,7 +365,11 @@ - bitflips = !!err; - } - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(buf); -+#else - vfree(buf); -+#endif - ubi_free_vid_hdr(ubi, vh); - - if (second_is_newer) -@@ -387,10 +380,14 @@ - return second_is_newer | (bitflips << 1) | (corrupted << 2); - - out_free_buf: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(buf); -+#else - vfree(buf); -+#endif -+ - out_free_vidh: - ubi_free_vid_hdr(ubi, vh); -- ubi_assert(err < 0); - return err; - } - -@@ -769,7 +766,7 @@ - */ - static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) - { -- long long ec; -+ long long uninitialized_var(ec); - int err, bitflips = 0, vol_id, ec_corr = 0; - - dbg_bld("scan PEB %d", pnum); -@@ -854,7 +851,7 @@ - } - - vol_id = be32_to_cpu(vidh->vol_id); -- if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) { -+ if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) { - int lnum = be32_to_cpu(vidh->lnum); - - /* Unsupported internal volume */ -@@ -897,15 +894,8 @@ - - adjust_mean_ec: - if (!ec_corr) { -- if (si->ec_sum + ec < ec) { -- commit_to_mean_value(si); -- si->ec_sum = 0; -- si->ec_count = 0; -- } else { -- si->ec_sum += ec; -- si->ec_count += 1; -- } -- -+ si->ec_sum += ec; -+ si->ec_count += 1; - if (ec > si->max_ec) - si->max_ec = ec; - if (ec < si->min_ec) -@@ -961,9 +951,11 @@ - - dbg_msg("scanning is finished"); - -- /* Finish mean erase counter calculations */ -- if (si->ec_count) -- commit_to_mean_value(si); -+ /* Calculate mean erase counter */ -+ if (si->ec_count) { -+ do_div(si->ec_sum, si->ec_count); -+ si->mean_ec = si->ec_sum; -+ } - - if (si->is_empty) - ubi_msg("empty MTD device detected"); ---- linux-2.6.24.7.old/drivers/mtd/ubi/scan.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/scan.h 2009-04-12 18:13:57.000000000 +0200 -@@ -124,7 +124,7 @@ - int max_ec; - unsigned long long max_sqnum; - int mean_ec; -- int ec_sum; -+ uint64_t ec_sum; - int ec_count; - }; - ---- linux-2.6.24.7.old/drivers/mtd/ubi/ubi-media.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/ubi/ubi-media.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,372 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Артём) -+ * Thomas Gleixner -+ * Frank Haverkamp -+ * Oliver Lohmann -+ * Andreas Arnez -+ */ -+ -+/* -+ * This file defines the layout of UBI headers and all the other UBI on-flash -+ * data structures. -+ */ -+ -+#ifndef __UBI_MEDIA_H__ -+#define __UBI_MEDIA_H__ -+ -+#include -+ -+/* The version of UBI images supported by this implementation */ -+#define UBI_VERSION 1 -+ -+/* The highest erase counter value supported by this implementation */ -+#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF -+ -+/* The initial CRC32 value used when calculating CRC checksums */ -+#define UBI_CRC32_INIT 0xFFFFFFFFU -+ -+/* Erase counter header magic number (ASCII "UBI#") */ -+#define UBI_EC_HDR_MAGIC 0x55424923 -+/* Volume identifier header magic number (ASCII "UBI!") */ -+#define UBI_VID_HDR_MAGIC 0x55424921 -+ -+/* -+ * Volume type constants used in the volume identifier header. -+ * -+ * @UBI_VID_DYNAMIC: dynamic volume -+ * @UBI_VID_STATIC: static volume -+ */ -+enum { -+ UBI_VID_DYNAMIC = 1, -+ UBI_VID_STATIC = 2 -+}; -+ -+/* -+ * Volume flags used in the volume table record. -+ * -+ * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume -+ * -+ * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume -+ * table. UBI automatically re-sizes the volume which has this flag and makes -+ * the volume to be of largest possible size. This means that if after the -+ * initialization UBI finds out that there are available physical eraseblocks -+ * present on the device, it automatically appends all of them to the volume -+ * (the physical eraseblocks reserved for bad eraseblocks handling and other -+ * reserved physical eraseblocks are not taken). So, if there is a volume with -+ * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical -+ * eraseblocks will be zero after UBI is loaded, because all of them will be -+ * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared -+ * after the volume had been initialized. -+ * -+ * The auto-resize feature is useful for device production purposes. For -+ * example, different NAND flash chips may have different amount of initial bad -+ * eraseblocks, depending of particular chip instance. Manufacturers of NAND -+ * chips usually guarantee that the amount of initial bad eraseblocks does not -+ * exceed certain percent, e.g. 2%. When one creates an UBI image which will be -+ * flashed to the end devices in production, he does not know the exact amount -+ * of good physical eraseblocks the NAND chip on the device will have, but this -+ * number is required to calculate the volume sized and put them to the volume -+ * table of the UBI image. In this case, one of the volumes (e.g., the one -+ * which will store the root file system) is marked as "auto-resizable", and -+ * UBI will adjust its size on the first boot if needed. -+ * -+ * Note, first UBI reserves some amount of physical eraseblocks for bad -+ * eraseblock handling, and then re-sizes the volume, not vice-versa. This -+ * means that the pool of reserved physical eraseblocks will always be present. -+ */ -+enum { -+ UBI_VTBL_AUTORESIZE_FLG = 0x01, -+}; -+ -+/* -+ * Compatibility constants used by internal volumes. -+ * -+ * @UBI_COMPAT_DELETE: delete this internal volume before anything is written -+ * to the flash -+ * @UBI_COMPAT_RO: attach this device in read-only mode -+ * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its -+ * physical eraseblocks, don't allow the wear-leveling unit to move them -+ * @UBI_COMPAT_REJECT: reject this UBI image -+ */ -+enum { -+ UBI_COMPAT_DELETE = 1, -+ UBI_COMPAT_RO = 2, -+ UBI_COMPAT_PRESERVE = 4, -+ UBI_COMPAT_REJECT = 5 -+}; -+ -+/* Sizes of UBI headers */ -+#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr) -+#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr) -+ -+/* Sizes of UBI headers without the ending CRC */ -+#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32)) -+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32)) -+ -+/** -+ * struct ubi_ec_hdr - UBI erase counter header. -+ * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC) -+ * @version: version of UBI implementation which is supposed to accept this -+ * UBI image -+ * @padding1: reserved for future, zeroes -+ * @ec: the erase counter -+ * @vid_hdr_offset: where the VID header starts -+ * @data_offset: where the user data start -+ * @padding2: reserved for future, zeroes -+ * @hdr_crc: erase counter header CRC checksum -+ * -+ * The erase counter header takes 64 bytes and has a plenty of unused space for -+ * future usage. The unused fields are zeroed. The @version field is used to -+ * indicate the version of UBI implementation which is supposed to be able to -+ * work with this UBI image. If @version is greater then the current UBI -+ * version, the image is rejected. This may be useful in future if something -+ * is changed radically. This field is duplicated in the volume identifier -+ * header. -+ * -+ * The @vid_hdr_offset and @data_offset fields contain the offset of the the -+ * volume identifier header and user data, relative to the beginning of the -+ * physical eraseblock. These values have to be the same for all physical -+ * eraseblocks. -+ */ -+struct ubi_ec_hdr { -+ __be32 magic; -+ __u8 version; -+ __u8 padding1[3]; -+ __be64 ec; /* Warning: the current limit is 31-bit anyway! */ -+ __be32 vid_hdr_offset; -+ __be32 data_offset; -+ __u8 padding2[36]; -+ __be32 hdr_crc; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubi_vid_hdr - on-flash UBI volume identifier header. -+ * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC) -+ * @version: UBI implementation version which is supposed to accept this UBI -+ * image (%UBI_VERSION) -+ * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) -+ * @copy_flag: if this logical eraseblock was copied from another physical -+ * eraseblock (for wear-leveling reasons) -+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, -+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) -+ * @vol_id: ID of this volume -+ * @lnum: logical eraseblock number -+ * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be -+ * removed, kept only for not breaking older UBI users) -+ * @data_size: how many bytes of data this logical eraseblock contains -+ * @used_ebs: total number of used logical eraseblocks in this volume -+ * @data_pad: how many bytes at the end of this physical eraseblock are not -+ * used -+ * @data_crc: CRC checksum of the data stored in this logical eraseblock -+ * @padding1: reserved for future, zeroes -+ * @sqnum: sequence number -+ * @padding2: reserved for future, zeroes -+ * @hdr_crc: volume identifier header CRC checksum -+ * -+ * The @sqnum is the value of the global sequence counter at the time when this -+ * VID header was created. The global sequence counter is incremented each time -+ * UBI writes a new VID header to the flash, i.e. when it maps a logical -+ * eraseblock to a new physical eraseblock. The global sequence counter is an -+ * unsigned 64-bit integer and we assume it never overflows. The @sqnum -+ * (sequence number) is used to distinguish between older and newer versions of -+ * logical eraseblocks. -+ * -+ * There are 2 situations when there may be more then one physical eraseblock -+ * corresponding to the same logical eraseblock, i.e., having the same @vol_id -+ * and @lnum values in the volume identifier header. Suppose we have a logical -+ * eraseblock L and it is mapped to the physical eraseblock P. -+ * -+ * 1. Because UBI may erase physical eraseblocks asynchronously, the following -+ * situation is possible: L is asynchronously erased, so P is scheduled for -+ * erasure, then L is written to,i.e. mapped to another physical eraseblock P1, -+ * so P1 is written to, then an unclean reboot happens. Result - there are 2 -+ * physical eraseblocks P and P1 corresponding to the same logical eraseblock -+ * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the -+ * flash. -+ * -+ * 2. From time to time UBI moves logical eraseblocks to other physical -+ * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P -+ * to P1, and an unclean reboot happens before P is physically erased, there -+ * are two physical eraseblocks P and P1 corresponding to L and UBI has to -+ * select one of them when the flash is attached. The @sqnum field says which -+ * PEB is the original (obviously P will have lower @sqnum) and the copy. But -+ * it is not enough to select the physical eraseblock with the higher sequence -+ * number, because the unclean reboot could have happen in the middle of the -+ * copying process, so the data in P is corrupted. It is also not enough to -+ * just select the physical eraseblock with lower sequence number, because the -+ * data there may be old (consider a case if more data was added to P1 after -+ * the copying). Moreover, the unclean reboot may happen when the erasure of P -+ * was just started, so it result in unstable P, which is "mostly" OK, but -+ * still has unstable bits. -+ * -+ * UBI uses the @copy_flag field to indicate that this logical eraseblock is a -+ * copy. UBI also calculates data CRC when the data is moved and stores it at -+ * the @data_crc field of the copy (P1). So when UBI needs to pick one physical -+ * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is -+ * examined. If it is cleared, the situation* is simple and the newer one is -+ * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC -+ * checksum is correct, this physical eraseblock is selected (P1). Otherwise -+ * the older one (P) is selected. -+ * -+ * Note, there is an obsolete @leb_ver field which was used instead of @sqnum -+ * in the past. But it is not used anymore and we keep it in order to be able -+ * to deal with old UBI images. It will be removed at some point. -+ * -+ * There are 2 sorts of volumes in UBI: user volumes and internal volumes. -+ * Internal volumes are not seen from outside and are used for various internal -+ * UBI purposes. In this implementation there is only one internal volume - the -+ * layout volume. Internal volumes are the main mechanism of UBI extensions. -+ * For example, in future one may introduce a journal internal volume. Internal -+ * volumes have their own reserved range of IDs. -+ * -+ * The @compat field is only used for internal volumes and contains the "degree -+ * of their compatibility". It is always zero for user volumes. This field -+ * provides a mechanism to introduce UBI extensions and to be still compatible -+ * with older UBI binaries. For example, if someone introduced a journal in -+ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the -+ * journal volume. And in this case, older UBI binaries, which know nothing -+ * about the journal volume, would just delete this volume and work perfectly -+ * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image -+ * - it just ignores the Ext3fs journal. -+ * -+ * The @data_crc field contains the CRC checksum of the contents of the logical -+ * eraseblock if this is a static volume. In case of dynamic volumes, it does -+ * not contain the CRC checksum as a rule. The only exception is when the -+ * data of the physical eraseblock was moved by the wear-leveling unit, then -+ * the wear-leveling unit calculates the data CRC and stores it in the -+ * @data_crc field. And of course, the @copy_flag is %in this case. -+ * -+ * The @data_size field is used only for static volumes because UBI has to know -+ * how many bytes of data are stored in this eraseblock. For dynamic volumes, -+ * this field usually contains zero. The only exception is when the data of the -+ * physical eraseblock was moved to another physical eraseblock for -+ * wear-leveling reasons. In this case, UBI calculates CRC checksum of the -+ * contents and uses both @data_crc and @data_size fields. In this case, the -+ * @data_size field contains data size. -+ * -+ * The @used_ebs field is used only for static volumes and indicates how many -+ * eraseblocks the data of the volume takes. For dynamic volumes this field is -+ * not used and always contains zero. -+ * -+ * The @data_pad is calculated when volumes are created using the alignment -+ * parameter. So, effectively, the @data_pad field reduces the size of logical -+ * eraseblocks of this volume. This is very handy when one uses block-oriented -+ * software (say, cramfs) on top of the UBI volume. -+ */ -+struct ubi_vid_hdr { -+ __be32 magic; -+ __u8 version; -+ __u8 vol_type; -+ __u8 copy_flag; -+ __u8 compat; -+ __be32 vol_id; -+ __be32 lnum; -+ __be32 leb_ver; /* obsolete, to be removed, don't use */ -+ __be32 data_size; -+ __be32 used_ebs; -+ __be32 data_pad; -+ __be32 data_crc; -+ __u8 padding1[4]; -+ __be64 sqnum; -+ __u8 padding2[12]; -+ __be32 hdr_crc; -+} __attribute__ ((packed)); -+ -+/* Internal UBI volumes count */ -+#define UBI_INT_VOL_COUNT 1 -+ -+/* -+ * Starting ID of internal volumes. There is reserved room for 4096 internal -+ * volumes. -+ */ -+#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096) -+ -+/* The layout volume contains the volume table */ -+ -+#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START -+#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC -+#define UBI_LAYOUT_VOLUME_ALIGN 1 -+#define UBI_LAYOUT_VOLUME_EBS 2 -+#define UBI_LAYOUT_VOLUME_NAME "layout volume" -+#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT -+ -+/* The maximum number of volumes per one UBI device */ -+#define UBI_MAX_VOLUMES 128 -+ -+/* The maximum volume name length */ -+#define UBI_VOL_NAME_MAX 127 -+ -+/* Size of the volume table record */ -+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record) -+ -+/* Size of the volume table record without the ending CRC */ -+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32)) -+ -+/** -+ * struct ubi_vtbl_record - a record in the volume table. -+ * @reserved_pebs: how many physical eraseblocks are reserved for this volume -+ * @alignment: volume alignment -+ * @data_pad: how many bytes are unused at the end of the each physical -+ * eraseblock to satisfy the requested alignment -+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @upd_marker: if volume update was started but not finished -+ * @name_len: volume name length -+ * @name: the volume name -+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) -+ * @padding: reserved, zeroes -+ * @crc: a CRC32 checksum of the record -+ * -+ * The volume table records are stored in the volume table, which is stored in -+ * the layout volume. The layout volume consists of 2 logical eraseblock, each -+ * of which contains a copy of the volume table (i.e., the volume table is -+ * duplicated). The volume table is an array of &struct ubi_vtbl_record -+ * objects indexed by the volume ID. -+ * -+ * If the size of the logical eraseblock is large enough to fit -+ * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES -+ * records. Otherwise, it contains as many records as it can fit (i.e., size of -+ * logical eraseblock divided by sizeof(struct ubi_vtbl_record)). -+ * -+ * The @upd_marker flag is used to implement volume update. It is set to %1 -+ * before update and set to %0 after the update. So if the update operation was -+ * interrupted, UBI knows that the volume is corrupted. -+ * -+ * The @alignment field is specified when the volume is created and cannot be -+ * later changed. It may be useful, for example, when a block-oriented file -+ * system works on top of UBI. The @data_pad field is calculated using the -+ * logical eraseblock size and @alignment. The alignment must be multiple to the -+ * minimal flash I/O unit. If @alignment is 1, all the available space of -+ * the physical eraseblocks is used. -+ * -+ * Empty records contain all zeroes and the CRC checksum of those zeroes. -+ */ -+struct ubi_vtbl_record { -+ __be32 reserved_pebs; -+ __be32 alignment; -+ __be32 data_pad; -+ __u8 vol_type; -+ __u8 upd_marker; -+ __be16 name_len; -+ __u8 name[UBI_VOL_NAME_MAX+1]; -+ __u8 flags; -+ __u8 padding[23]; -+ __be32 crc; -+} __attribute__ ((packed)); -+ -+#endif /* !__UBI_MEDIA_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/ubi/ubi.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/ubi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -37,10 +37,9 @@ - #include - #include - #include -- --#include - #include - -+#include "ubi-media.h" - #include "scan.h" - #include "debug.h" - -@@ -94,8 +93,43 @@ - UBI_IO_BITFLIPS - }; - --extern int ubi_devices_cnt; --extern struct ubi_device *ubi_devices[]; -+/** -+ * struct ubi_wl_entry - wear-leveling entry. -+ * @rb: link in the corresponding RB-tree -+ * @ec: erase counter -+ * @pnum: physical eraseblock number -+ * -+ * This data structure is used in the WL unit. Each physical eraseblock has a -+ * corresponding &struct wl_entry object which may be kept in different -+ * RB-trees. See WL unit for details. -+ */ -+struct ubi_wl_entry { -+ struct rb_node rb; -+ int ec; -+ int pnum; -+}; -+ -+/** -+ * struct ubi_ltree_entry - an entry in the lock tree. -+ * @rb: links RB-tree nodes -+ * @vol_id: volume ID of the locked logical eraseblock -+ * @lnum: locked logical eraseblock number -+ * @users: how many tasks are using this logical eraseblock or wait for it -+ * @mutex: read/write mutex to implement read/write access serialization to -+ * the (@vol_id, @lnum) logical eraseblock -+ * -+ * This data structure is used in the EBA unit to implement per-LEB locking. -+ * When a logical eraseblock is being locked - corresponding -+ * &struct ubi_ltree_entry object is inserted to the lock tree (@ubi->ltree). -+ * See EBA unit for details. -+ */ -+struct ubi_ltree_entry { -+ struct rb_node rb; -+ int vol_id; -+ int lnum; -+ int users; -+ struct rw_semaphore mutex; -+}; - - struct ubi_volume_desc; - -@@ -105,11 +139,10 @@ - * @cdev: character device object to create character device - * @ubi: reference to the UBI device description object - * @vol_id: volume ID -+ * @ref_count: volume reference count - * @readers: number of users holding this volume in read-only mode - * @writers: number of users holding this volume in read-write mode - * @exclusive: whether somebody holds this volume in exclusive mode -- * @removed: if the volume was removed -- * @checked: if this static volume was checked - * - * @reserved_pebs: how many physical eraseblocks are reserved for this volume - * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -@@ -117,21 +150,30 @@ - * @used_ebs: how many logical eraseblocks in this volume contain data - * @last_eb_bytes: how many bytes are stored in the last logical eraseblock - * @used_bytes: how many bytes of data this volume contains -- * @upd_marker: non-zero if the update marker is set for this volume -- * @corrupted: non-zero if the volume is corrupted (static volumes only) - * @alignment: volume alignment - * @data_pad: how many bytes are not used at the end of physical eraseblocks to -- * satisfy the requested alignment -+ * satisfy the requested alignment - * @name_len: volume name length - * @name: volume name - * -- * @updating: whether the volume is being updated - * @upd_ebs: how many eraseblocks are expected to be updated -- * @upd_bytes: how many bytes are expected to be received -- * @upd_received: how many update bytes were already received -- * @upd_buf: update buffer which is used to collect update data -+ * @ch_lnum: LEB number which is being changing by the atomic LEB change -+ * operation -+ * @ch_dtype: data persistency type which is being changing by the atomic LEB -+ * change operation -+ * @upd_bytes: how many bytes are expected to be received for volume update or -+ * atomic LEB change -+ * @upd_received: how many bytes were already received for volume update or -+ * atomic LEB change -+ * @upd_buf: update buffer which is used to collect update data or data for -+ * atomic LEB change - * - * @eba_tbl: EBA table of this volume (LEB->PEB mapping) -+ * @checked: %1 if this static volume was checked -+ * @corrupted: %1 if the volume is corrupted (static volumes only) -+ * @upd_marker: %1 if the update marker is set for this volume -+ * @updating: %1 if the volume is being updated -+ * @changing_leb: %1 if the atomic LEB change ioctl command is in progress - * - * @gluebi_desc: gluebi UBI volume descriptor - * @gluebi_refcount: reference count of the gluebi MTD device -@@ -150,11 +192,10 @@ - struct cdev cdev; - struct ubi_device *ubi; - int vol_id; -+ int ref_count; - int readers; - int writers; - int exclusive; -- int removed; -- int checked; - - int reserved_pebs; - int vol_type; -@@ -162,29 +203,45 @@ - int used_ebs; - int last_eb_bytes; - long long used_bytes; -- int upd_marker; -- int corrupted; - int alignment; - int data_pad; - int name_len; - char name[UBI_VOL_NAME_MAX+1]; - -- int updating; - int upd_ebs; -+ int ch_lnum; -+ int ch_dtype; - long long upd_bytes; - long long upd_received; - void *upd_buf; - - int *eba_tbl; -+ unsigned int checked:1; -+ unsigned int corrupted:1; -+ unsigned int upd_marker:1; -+ unsigned int updating:1; -+ unsigned int changing_leb:1; - - #ifdef CONFIG_MTD_UBI_GLUEBI -- /* Gluebi-related stuff may be compiled out */ -+ /* -+ * Gluebi-related stuff may be compiled out. -+ * TODO: this should not be built into UBI but should be a separate -+ * ubimtd driver which works on top of UBI and emulates MTD devices. -+ */ - struct ubi_volume_desc *gluebi_desc; - int gluebi_refcount; - struct mtd_info gluebi_mtd; - #endif -+ int bdev_mode; //add by Nancy - }; - -+struct vol_notifier { -+ void (*add)(struct ubi_volume *vol); -+ void (*remove)(struct ubi_volume *vol); -+ struct list_head list; -+}; -+ -+ - /** - * struct ubi_volume_desc - descriptor of the UBI volume returned when it is - * opened. -@@ -200,28 +257,31 @@ - - /** - * struct ubi_device - UBI device description structure -- * @dev: class device object to use the the Linux device model -+ * @dev: UBI device object to use the the Linux device model - * @cdev: character device object to create character device - * @ubi_num: UBI device number - * @ubi_name: UBI device name -- * @major: character device major number - * @vol_count: number of volumes in this UBI device - * @volumes: volumes of this UBI device - * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs, -- * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, @vol->readers, -- * @vol->writers, @vol->exclusive, @vol->removed, @vol->mapping and -- * @vol->eba_tbl. -+ * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, -+ * @vol->readers, @vol->writers, @vol->exclusive, -+ * @vol->ref_count, @vol->mapping and @vol->eba_tbl. -+ * @ref_count: count of references on the UBI device - * - * @rsvd_pebs: count of reserved physical eraseblocks - * @avail_pebs: count of available physical eraseblocks - * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB -- * handling -+ * handling - * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling - * -+ * @autoresize_vol_id: ID of the volume which has to be auto-resized at the end -+ * of UBI ititializetion - * @vtbl_slots: how many slots are available in the volume table - * @vtbl_size: size of the volume table in bytes - * @vtbl: in-RAM volume table copy -- * @vtbl_mutex: protects on-flash volume table -+ * @volumes_mutex: protects on-flash volume table and serializes volume -+ * changes, like creation, deletion, update, resize - * - * @max_ec: current highest erase counter value - * @mean_ec: current mean erase counter value -@@ -238,15 +298,15 @@ - * @prot.pnum: protection tree indexed by physical eraseblock numbers - * @prot.aec: protection tree indexed by absolute erase counter value - * @wl_lock: protects the @used, @free, @prot, @lookuptbl, @abs_ec, @move_from, -- * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works -- * fields -+ * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works -+ * fields -+ * @move_mutex: serializes eraseblock moves - * @wl_scheduled: non-zero if the wear-leveling was scheduled - * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any -- * physical eraseblock -+ * physical eraseblock - * @abs_ec: absolute erase counter - * @move_from: physical eraseblock from where the data is being moved - * @move_to: physical eraseblock where the data is being moved to -- * @move_from_put: if the "from" PEB was put - * @move_to_put: if the "to" PEB was put - * @works: list of pending works - * @works_count: count of pending works -@@ -273,36 +333,39 @@ - * @hdrs_min_io_size - * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset - * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or -- * not -+ * not - * @mtd: MTD device descriptor - * - * @peb_buf1: a buffer of PEB size used for different purposes - * @peb_buf2: another buffer of PEB size used for different purposes - * @buf_mutex: proptects @peb_buf1 and @peb_buf2 -- * @dbg_peb_buf: buffer of PEB size used for debugging -+ * @dbg_peb_buf: buffer of PEB size used for debugging - * @dbg_buf_mutex: proptects @dbg_peb_buf - */ - struct ubi_device { - struct cdev cdev; -+ int bdev_major; //add by Nancy - struct device dev; - int ubi_num; - char ubi_name[sizeof(UBI_NAME_STR)+5]; -- int major; - int vol_count; - struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT]; - spinlock_t volumes_lock; -+ int ref_count; - - int rsvd_pebs; - int avail_pebs; - int beb_rsvd_pebs; - int beb_rsvd_level; - -+ int autoresize_vol_id; - int vtbl_slots; - int vtbl_size; - struct ubi_vtbl_record *vtbl; -- struct mutex vtbl_mutex; -+ struct mutex volumes_mutex; - - int max_ec; -+ /* TODO: mean_ec is not updated run-time, fix */ - int mean_ec; - - /* EBA unit's stuff */ -@@ -320,12 +383,13 @@ - struct rb_root aec; - } prot; - spinlock_t wl_lock; -+ struct mutex move_mutex; -+ struct rw_semaphore work_sem; - int wl_scheduled; - struct ubi_wl_entry **lookuptbl; - unsigned long long abs_ec; - struct ubi_wl_entry *move_from; - struct ubi_wl_entry *move_to; -- int move_from_put; - int move_to_put; - struct list_head works; - int works_count; -@@ -355,15 +419,19 @@ - void *peb_buf1; - void *peb_buf2; - struct mutex buf_mutex; -+ struct mutex ckvol_mutex; - #ifdef CONFIG_MTD_UBI_DEBUG - void *dbg_peb_buf; - struct mutex dbg_buf_mutex; - #endif - }; - -+extern struct kmem_cache *ubi_wl_entry_slab; -+extern struct file_operations ubi_ctrl_cdev_operations; - extern struct file_operations ubi_cdev_operations; - extern struct file_operations ubi_vol_cdev_operations; - extern struct class *ubi_class; -+extern struct mutex ubi_devices_mutex; - - /* vtbl.c */ - int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, -@@ -374,13 +442,18 @@ - int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req); - int ubi_remove_volume(struct ubi_volume_desc *desc); - int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs); --int ubi_add_volume(struct ubi_device *ubi, int vol_id); --void ubi_free_volume(struct ubi_device *ubi, int vol_id); -+int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol); -+void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol); - - /* upd.c */ --int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes); --int ubi_more_update_data(struct ubi_device *ubi, int vol_id, -+int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, -+ long long bytes); -+int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, - const void __user *buf, int count); -+int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, -+ const struct ubi_leb_change_req *req); -+int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, -+ const void __user *buf, int count); - - /* misc.c */ - int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length); -@@ -399,16 +472,17 @@ - #endif - - /* eba.c */ --int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum); --int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, -- int offset, int len, int check); --int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, -+int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum); -+int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, -+ void *buf, int offset, int len, int check); -+int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, - const void *buf, int offset, int len, int dtype); --int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, -- const void *buf, int len, int dtype, -+int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum, const void *buf, int len, int dtype, - int used_ebs); --int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, -- const void *buf, int len, int dtype); -+int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum, const void *buf, int len, int dtype); - int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, - struct ubi_vid_hdr *vid_hdr); - int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); -@@ -421,6 +495,7 @@ - int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum); - int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); - void ubi_wl_close(struct ubi_device *ubi); -+int ubi_thread(void *u); - - /* io.c */ - int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, -@@ -438,6 +513,14 @@ - struct ubi_vid_hdr *vid_hdr, int verbose); - int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, - struct ubi_vid_hdr *vid_hdr); -+ -+/* build.c */ -+int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset); -+int ubi_detach_mtd_dev(int ubi_num, int anyway); -+struct ubi_device *ubi_get_device(int ubi_num); -+void ubi_put_device(struct ubi_device *ubi); -+struct ubi_device *ubi_get_by_major(int major); -+int ubi_major2num(int major); - - /* - * ubi_rb_for_each_entry - walk an RB-tree. -@@ -523,8 +606,10 @@ - */ - static inline void ubi_ro_mode(struct ubi_device *ubi) - { -- ubi->ro_mode = 1; -- ubi_warn("switch to read-only mode"); -+ if (!ubi->ro_mode) { -+ ubi->ro_mode = 1; -+ ubi_warn("switch to read-only mode"); -+ } - } - - /** ---- linux-2.6.24.7.old/drivers/mtd/ubi/ubiblk.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/ubi/ubiblk.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,359 @@ -+/* -+ * Direct UBI block device access -+ * -+ * (C) 2000-2003 Nicolas Pitre -+ * (C) 1999-2003 David Woodhouse -+ * (C) 2008 Yurong Tan : -+ * borrow mtdblock.c to work on top of UBI -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ +#include +#include +#include @@ -79740,2693 +17931,534 @@ +#include +#include +#include ++#include ++#include ++#include +#include -+#include "ubi.h" -+#include "ubiblk.h" ++#include + -+#define UBIBLK_UNMAPPED 0 -+#define UBIBLK_SECTOR_SIZE 512 ++#define CACHE_MAX_NUM 256 ++#define SECTOR_SIZE 512 + -+extern void ubi_open_blkdev(int ubi_num, int vol_id, int mode); -+extern void ubi_close_blkdev(struct ubi_volume_desc *desc); -+static void ubiblk_setup_writecache(struct ubiblk_dev *ubiblk, int virt_block); -+static int ubiblk_flush_writecache(struct ubiblk_dev *ubiblk); -+extern int ubiblk_leb_change(struct ubiblk_dev *ubiblk); ++//#define UDC_CACHE_DEBUG + -+struct ubiblk_dev *ubiblks[UBI_MAX_VOLUMES]; -+static unsigned short subpage_shift; -+ -+static int ubiblk_flush_writecache(struct ubiblk_dev *ubiblk) -+{ -+ if (STATE_UNUSED == ubiblk->write_cache_state) -+ return 0; -+ ubiblk_leb_change(ubiblk); -+ ubiblk->write_cache_state = STATE_UNUSED; -+ -+ return 0; -+} -+ -+static void ubiblk_setup_writecache(struct ubiblk_dev *ubiblk, int virt_block) -+{ -+ struct ubi_volume_desc *uv = ubiblk->uv; -+ struct ubi_device *ubi = uv->vol->ubi; -+ int ppb = ubi->leb_size / ubi->min_io_size; -+ unsigned short spp = ubi->min_io_size >> subpage_shift; -+ -+ ubiblk->vbw = virt_block; -+ ubiblk->write_cache_state = STATE_USED; -+ -+ memset(ubiblk->page_sts, 0, ppb); -+ memset(ubiblk->subpage_sts, 0, ppb*spp); -+} -+ -+static int do_cached_write (struct ubiblk_dev *ubiblk, unsigned long sector, -+ int len, const char *buf) -+{ -+ struct ubi_volume_desc *uv = ubiblk->uv; -+ struct ubi_device *ubi = uv->vol->ubi; -+ int ppb = ubi->leb_size / ubi->min_io_size; -+ unsigned short sectors_per_page = ubi->min_io_size / len; -+ unsigned short sectors_in_page_shift = ffs(sectors_per_page) - 1; -+ unsigned short page_shift = ffs(ubi->min_io_size) - 1; -+ unsigned short virt_block, page, subpage; -+ unsigned long virt_page; -+ -+ virt_page = sector / sectors_per_page; -+ subpage = sector % sectors_per_page; -+ virt_block = virt_page / ppb; -+ page = virt_page % ppb; -+ -+ if(ubi_is_mapped(uv, virt_block) == UBIBLK_UNMAPPED ){ -+ mutex_lock(&ubiblk->cache_mutex); -+ ubiblk_flush_writecache(ubiblk); -+ mutex_unlock(&ubiblk->cache_mutex); -+ -+ ubiblk_setup_writecache(ubiblk, virt_block); -+ } else { -+ if ( STATE_USED == ubiblk->write_cache_state ) { -+ if ( ubiblk->vbw != virt_block) { -+ // Commit before we start a new cache. -+ mutex_lock(&ubiblk->cache_mutex); -+ ubiblk_flush_writecache(ubiblk); -+ mutex_unlock(&ubiblk->cache_mutex); -+ -+ ubiblk_setup_writecache(ubiblk, virt_block); -+ } else { -+ //printk("cache hit: 0x%x\n", virt_page); -+ } -+ } else { -+// printk("with existing mapping\n"); -+ ubiblk_setup_writecache(ubiblk, virt_block); -+ } -+ } -+ ubiblk->page_sts[page] = 1; -+ ubiblk->subpage_sts[(page<write_cache[(page<uv; -+ int ppb = uv->vol->ubi->leb_size / uv->vol->ubi->min_io_size; -+ unsigned short sectors_per_page = uv->vol->ubi->min_io_size >> 9; -+ unsigned short page_shift = ffs(uv->vol->ubi->min_io_size) - 1; -+ unsigned short virt_block, page, page_offset; -+ unsigned long virt_page; -+ -+ virt_page = sector / sectors_per_page; -+ page_offset = sector % sectors_per_page; -+ virt_block = virt_page / ppb; -+ page = virt_page % ppb; -+ -+ if(ubiblk->vbw == virt_block){ -+ mutex_lock(&ubiblk->cache_mutex); -+ ubiblk_flush_writecache(ubiblk); -+ mutex_unlock(&ubiblk->cache_mutex); -+ } -+ -+ if ( ubi_is_mapped( uv, virt_block) == UBIBLK_UNMAPPED){ -+ /* In a Flash Memory device, there might be a logical block that is -+ * not allcated to a physical block due to the block not being used. -+ * All data returned should be set to 0xFF when accessing this logical -+ * block. -+ */ -+ -+ //printk("address translate fail\n"); -+ memset(buf, 0xFF, UBIBLK_SECTOR_SIZE); -+ } else { -+ -+ if( ubiblk->vbr != virt_block ||ubiblk->read_cache_state == STATE_UNUSED ){ -+ ubiblk->vbr = virt_block; -+ ubi_leb_read(uv, virt_block, ubiblk->read_cache, 0, uv->vol->usable_leb_size, 0); -+ ubiblk->read_cache_state = STATE_USED; -+ } -+ memcpy(buf, &ubiblk->read_cache[(page<devnum]; -+ return do_cached_read(ubiblk, block, UBIBLK_SECTOR_SIZE, buf); -+} -+ -+static int ubiblk_writesect(struct ubi_blktrans_dev *dev, -+ unsigned long block, char *buf) -+{ -+ struct ubiblk_dev *ubiblk = ubiblks[dev->devnum]; -+ return do_cached_write(ubiblk, block, UBIBLK_SECTOR_SIZE, buf); -+} -+ -+static int ubiblk_init_vol(int dev, struct ubi_volume_desc *uv) -+{ -+ struct ubiblk_dev *ubiblk; -+ struct ubi_device *ubi = uv->vol->ubi; -+ int ppb = ubi->leb_size / ubi->min_io_size; -+ unsigned short spp = ubi->min_io_size >> subpage_shift; -+ -+ ubiblk = kmalloc(sizeof(struct ubiblk_dev), GFP_KERNEL); -+ if (!ubiblk) -+ return -ENOMEM; -+ -+ memset(ubiblk, 0, sizeof(*ubiblk)); -+ -+ ubiblk->count = 1; -+ ubiblk->uv = uv; -+ mutex_init (&ubiblk->cache_mutex); -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ ubiblk->write_cache = kmalloc(ubiblk->uv->vol->usable_leb_size, GFP_KERNEL); -+ ubiblk->read_cache = kmalloc(ubiblk->uv->vol->usable_leb_size, GFP_KERNEL); -+ ubiblk->page_sts = kmalloc(ppb, GFP_KERNEL); -+ ubiblk->subpage_sts = kmalloc(ppb*spp, GFP_KERNEL); ++#ifdef UDC_CACHE_DEBUG ++#define dprintk(a...) printk(a) +#else -+ ubiblk->write_cache = vmalloc(ubiblk->uv->vol->usable_leb_size); -+ ubiblk->read_cache = vmalloc(ubiblk->uv->vol->usable_leb_size); -+ ubiblk->page_sts = vmalloc(ppb); -+ ubiblk->subpage_sts = vmalloc(ppb*spp); ++#define dprintk(a...) while(0){} +#endif + -+ if(!ubiblk->write_cache || -+ !ubiblk->read_cache || -+ !ubiblk->page_sts || -+ !ubiblk->subpage_sts) -+ return -ENOMEM; ++typedef struct { ++ unsigned short CacheState; ++ unsigned short UseCount; ++ unsigned short CacheChange; ++ unsigned short CacheReserve; ++ unsigned int BlockId; ++ unsigned char *aBlockData; ++} SSFDC__LB_CACHE; + -+ ubiblk->write_cache_state = STATE_UNUSED; -+ ubiblk->read_cache_state = STATE_UNUSED; ++#define FREE_CACHE 0 ++#define PREWRITE_CACHE 2 ++#define OFTEN_USE_CACHE 3 ++#define SECTOR_SHIFT 9 + -+ ubiblks[dev] = ubiblk; -+ DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); ++#define CACHE_TO_UNCATCH(x) ((unsigned int)x | 0xa0000000) ++static unsigned int __aBlockData[SECTOR_SIZE * CACHE_MAX_NUM / 4] __attribute__ ((aligned (32))); ++static SSFDC__LB_CACHE ssfdc_cache[CACHE_MAX_NUM]; ++static unsigned short Cur_CacheCount = 0; ++int FlushDataState = 0; ++static struct mtdblk_dev *g_udc_mtdblk; ++static struct mtd_info *g_udc_mtd; ++ ++extern int udc_mtdblock_readsect(struct mtdblk_dev *, unsigned long, char *, int); ++extern int udc_mtdblock_writesect(struct mtdblk_dev *, unsigned long, char *); ++extern struct mtdblk_dev *udc_get_mtdblk(void); ++extern struct mtd_info *udc_get_mtd(void); ++extern void udc_flush_cache(struct mtdblk_dev *mtdblk); ++ ++#define _NAND_LB_Write(pCache) udc_mtdblock_writesect(g_udc_mtdblk, pCache->BlockId,pCache->aBlockData) ++#define _NAND_LB_Read(Sector,pBuffer) udc_mtdblock_readsect(g_udc_mtdblk, Sector, pBuffer, SECTOR_SIZE); ++ ++#define DMA_ENABLE 0 ++ ++#if DMA_ENABLE ++#define DMA_CHANNEL 5 ++#define PHYSADDR(x) virt_to_phys((void *)x) ++#else ++#define lb_memcpy memcpy ++#endif ++ ++#if DMA_ENABLE ++static void lb_memcpy(void *target,void* source,unsigned int len) ++{ ++ int ch = DMA_CHANNEL; ++ if(((unsigned int)source < 0xa0000000) && len) ++ dma_cache_wback_inv((unsigned long)source, len); ++ if(((unsigned int)target < 0xa0000000) && len) ++ dma_cache_wback_inv((unsigned long)target, len); ++ ++ REG_DMAC_DSAR(ch) = PHYSADDR((unsigned long)source); ++ REG_DMAC_DTAR(ch) = PHYSADDR((unsigned long)target); ++ REG_DMAC_DTCR(ch) = len / 32; ++ REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AUTO; ++ REG_DMAC_DCMD(ch) = DMAC_DCMD_SAI| DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32|DMAC_DCMD_DS_32BYTE; ++ REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; ++ while ( REG_DMAC_DTCR(ch) ); ++} ++#endif ++ ++static void _NAND_LB_InitCache(void) ++{ ++ int i; ++ SSFDC__LB_CACHE *pCache = ssfdc_cache; ++#if DMA_ENABLE ++ unsigned char * ptr = (unsigned char *)CACHE_TO_UNCATCH(__aBlockData); ++#else ++ unsigned char * ptr = (unsigned char *)(__aBlockData); ++#endif ++ for(i = 0;i < CACHE_MAX_NUM;i++) ++ { ++ pCache->CacheState = FREE_CACHE; ++ pCache->UseCount = 0; ++ pCache->CacheChange = 0; ++ pCache->aBlockData = ptr; ++ ptr+=SECTOR_SIZE; ++ pCache++; ++ } ++ Cur_CacheCount = 0; ++} ++ ++static SSFDC__LB_CACHE * _NAND_LB_GetFreeCache(void) ++{ ++ int ret = 0; ++ SSFDC__LB_CACHE *pCacheInfo = &ssfdc_cache[Cur_CacheCount]; ++ while(1) ++ { ++ if(ret >= CACHE_MAX_NUM) ++ return 0; ++ if(pCacheInfo >= &ssfdc_cache[CACHE_MAX_NUM]) ++ { ++ pCacheInfo = ssfdc_cache; ++ Cur_CacheCount = 0; ++ } ++ ++ if(pCacheInfo->CacheState == FREE_CACHE) ++ { ++ return pCacheInfo; ++ } ++ pCacheInfo++; ++ Cur_CacheCount++; ++ ret++; ++ } + return 0; +} + -+static int ubiblk_open(struct inode *i, struct file *f ) ++static void _NAND_LB_CloseCACHES(unsigned int sectorstart,unsigned int sectorend) +{ -+ struct ubi_volume_desc *desc; -+ struct ubi_blktrans_dev *dev; -+ int ubi_num = ubi_major2num(imajor(i)); -+ int vol_id = iminor(i); -+ int mode; -+ int ret = 0; ++ unsigned int i; ++ SSFDC__LB_CACHE *pCache = ssfdc_cache; ++ for( i = 0;i < CACHE_MAX_NUM;i++){ ++ if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){ ++ pCache->CacheChange = 0; ++ pCache->CacheState = FREE_CACHE; ++ pCache->UseCount = 0; ++ } ++ pCache++; ++ } ++} + -+ if (f->f_mode & FMODE_WRITE) -+ mode = UBI_READWRITE; -+ else -+ mode = UBI_READONLY; ++static void _NAND_LB_FLUSHCACHES(unsigned int sectorstart,unsigned int sectorend) ++{ ++ unsigned int i; ++ SSFDC__LB_CACHE *pCache = ssfdc_cache; ++ for( i = 0;i < CACHE_MAX_NUM;i++){ ++ if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){ ++ if(pCache->CacheChange) ++ _NAND_LB_Write(pCache); ++ pCache->CacheChange = 0; ++ pCache->CacheState = FREE_CACHE; ++ pCache->UseCount = 0; ++ } ++ pCache++; + -+ dev = i->i_bdev->bd_disk->private_data; -+ if (ubiblks[dev->devnum]) { -+ ubiblks[dev->devnum]->count++; -+ ubi_open_blkdev(ubi_num, vol_id, mode); -+ printk("%s: increase use count\n",__FUNCTION__); ++ } ++} ++ ++inline static int Get_NAND_CacheFreeCount(void) ++{ ++ SSFDC__LB_CACHE *pCache = ssfdc_cache; ++ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; ++ unsigned int count = 0; ++ while(pCache < pEndCache) ++ { ++ if(pCache->CacheState == FREE_CACHE) ++ count++; ++ pCache++; ++ } ++ return count; ++ ++} ++ ++static unsigned int _NAND_LB_PreWiteToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update) ++{ ++ SSFDC__LB_CACHE *pWriteCache; ++ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; ++ unsigned int sector = -1; ++ unsigned int flag; ++ while(1) ++ { ++ sector = -1; ++ flag = 0; ++ pWriteCache = ssfdc_cache; ++ while(pWriteCache < pEndCache) ++ { ++ if(pWriteCache->CacheState == update) //PREWRITE_CACHE ++ { ++ if(pWriteCache->BlockId < sector) ++ { ++ sector = pWriteCache->BlockId; ++ pCache = pWriteCache; ++ } ++ }else ++ flag++; ++ pWriteCache++; ++ } ++ ++ if(flag < CACHE_MAX_NUM) ++ { ++ if(pCache->CacheChange) ++ { ++ _NAND_LB_Write(pCache); ++ pCache->CacheChange = 0; ++ } ++ pCache->CacheState = FREE_CACHE; ++ pCache->UseCount = 0; ++ (*count)++; ++ }else ++ break; ++ } ++ return 0; ++} ++ ++static void _NAND_LB_OftenToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update) ++{ ++ SSFDC__LB_CACHE *pWriteCache = pCache; ++ SSFDC__LB_CACHE *pOldCache = pCache; ++ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; ++ ++ dprintk("%s!\n",__FUNCTION__); ++ while(pCache) ++ { ++ if(pCache->CacheState == OFTEN_USE_CACHE) ++ { ++ if(pWriteCache->CacheState != OFTEN_USE_CACHE) ++ pWriteCache = pCache; ++ else if(pWriteCache->UseCount > pCache->UseCount) ++ { ++ pWriteCache = pCache; ++ } ++ } ++ pCache++; ++ if(pCache >= pEndCache) ++ break; ++ } ++ if(pWriteCache->CacheState == OFTEN_USE_CACHE) ++ { ++ (*count)++; ++ if(pWriteCache->CacheChange) ++ _NAND_LB_Write(pWriteCache); ++ pWriteCache->CacheState = FREE_CACHE; ++ ++ pWriteCache->UseCount = 0; ++ pWriteCache->CacheChange = 0; ++ if(update != -1) ++ update--; ++ if(update != 0) ++ _NAND_LB_OftenToNand(pOldCache,count,update); ++ } ++} ++ ++static int _NAND_LB_FreeCache(unsigned int update) ++{ ++ unsigned short freecount = 0,totalfree = 0; ++ ++ freecount = 0; ++ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE); ++ ++ totalfree += freecount; ++ dprintk("free count = %d\n",freecount); ++ if(freecount == 0) ++ { ++ freecount = 0; ++ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); ++ totalfree += freecount; ++ update = 0; ++ } ++ if(update) ++ { ++ if(Get_NAND_CacheFreeCount() < CACHE_MAX_NUM * 1 / 4) // because fat is 4 sector ++ { ++ freecount = 0; ++ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); ++ totalfree += freecount; ++ } ++ } ++ ++ dprintk("Free = %d\r\n",totalfree); ++ return totalfree; ++} ++ ++static int _NAND_LB_GetFromCache(unsigned int Sector, void *pBuffer) { ++ ++ SSFDC__LB_CACHE *pCache = &ssfdc_cache[Cur_CacheCount]; ++ SSFDC__LB_CACHE *pUseCache = 0; ++ unsigned short i; ++ dprintk("sector = %x pBuffer = %x\n",Sector,pBuffer); ++ if(pCache >= &ssfdc_cache[CACHE_MAX_NUM]) ++ pCache = ssfdc_cache; ++ ++ i = 0; ++ while (1) { ++ if(pCache->CacheState != FREE_CACHE) ++ { ++ if (Sector == pCache->BlockId) { ++ dprintk("Cache is use = %d\r\n",pCache->BlockId); ++ pUseCache = pCache; ++ pCache->UseCount++; ++ if(pCache->UseCount == 0) ++ pCache->UseCount = -1; ++ pCache->CacheState = OFTEN_USE_CACHE; ++ } ++ } ++ pCache--; ++ if(pCache < ssfdc_cache) ++ pCache = &ssfdc_cache[CACHE_MAX_NUM - 1]; ++ ++ i++; ++ if (i >= CACHE_MAX_NUM) { ++ break; /* Sector not in cache */ ++ } ++ } ++ if (pUseCache) { ++ dprintk("From Cache %d\r\n",Sector); ++ lb_memcpy(pBuffer, pUseCache->aBlockData, SECTOR_SIZE); + return 0; + } -+ -+ desc = ubi_open_volume(ubi_num, vol_id, mode); -+ if (IS_ERR(desc)) -+ return PTR_ERR(desc); -+ -+ desc->vol->bdev_mode = mode; -+ dev->uv = desc; ++ return -1; ++} + -+ subpage_shift = ffs(UBIBLK_SECTOR_SIZE)-1; -+ ret = ubiblk_init_vol(dev->devnum, desc); ++static void _NAND_LB_ClearCache(void) { ++ ++ unsigned short freecount = 0; ++ dprintk("Clear Cache\r\n"); ++ ++ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE); ++ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); ++} ++ ++static void _NAND_LB_CopyToCache(unsigned int Sector, void *pBuffer,unsigned short rw) ++{ ++ SSFDC__LB_CACHE *pCache = _NAND_LB_GetFreeCache(); ++ dprintk("Copy to Cache = 0x%08x 0x%08x\r\n",pCache,ssfdc_cache); ++ ++ if(!pCache) ++ { ++ _NAND_LB_FreeCache(rw); ++ ++ pCache = _NAND_LB_GetFreeCache(); ++ } ++ pCache->BlockId = Sector; ++ pCache->CacheState = PREWRITE_CACHE; ++ pCache->UseCount = 0; ++ pCache->CacheChange = rw; ++ ++ lb_memcpy(pCache->aBlockData,pBuffer,SECTOR_SIZE); ++} ++ ++ ++static int _NAND_LB_UpdateInCache(unsigned int Sector, void *pBuffer) { ++ short i,ret = 0; ++ i = Cur_CacheCount; ++ if(Cur_CacheCount > CACHE_MAX_NUM) ++ i = 0; ++ while(1) ++ { ++ if(ret >= CACHE_MAX_NUM) ++ return -1; ++ if(ssfdc_cache[i].CacheState != FREE_CACHE) ++ { ++ ++ if(ssfdc_cache[i].BlockId == Sector) ++ { ++ dprintk("UpdateInCache = %d\r\n",Sector); ++ ssfdc_cache[i].CacheState = OFTEN_USE_CACHE; ++ ssfdc_cache[i].UseCount++; ++ ssfdc_cache[i].CacheChange = 1; ++ lb_memcpy(ssfdc_cache[i].aBlockData,pBuffer,SECTOR_SIZE); ++ return 0; ++ } ++ } ++ i--; ++ if(i < 0) ++ i = CACHE_MAX_NUM - 1; ++ ret++; ++ } ++ return -1; ++} ++ ++static int NAND_LB_MultiRead(unsigned int Sector, void *pBuffer,unsigned int SectorCount) ++{ ++ int i,ret,end; ++ void *p; ++ ++ dprintk("NAND_LB_MultiRead = %d %d \n",Sector,SectorCount); ++ end = Sector + SectorCount; ++ _NAND_LB_FLUSHCACHES(Sector,end); ++ ++ p = pBuffer; ++ for (i = Sector; i < end; i ++) ++ { ++ ret = udc_mtdblock_readsect(g_udc_mtdblk, i, p, SECTOR_SIZE); ++ p += SECTOR_SIZE; ++ } + return ret; +} + -+static int ubiblk_release(struct ubi_blktrans_dev *ubd) ++static int NAND_LB_Read(unsigned int Sector, void *pBuffer) +{ -+ int dev = ubd->devnum; -+ struct ubiblk_dev *ubiblk = ubiblks[dev]; -+ struct ubi_device *ubi = ubiblk->uv->vol->ubi; -+ -+ mutex_lock(&ubiblk->cache_mutex); -+ ubiblk_flush_writecache(ubiblk); -+ mutex_unlock(&ubiblk->cache_mutex); -+ -+ ubiblk->count --; -+ if (!ubiblk->count) { -+ /* It was the last usage. Free the device */ -+ ubiblks[dev] = NULL; -+ -+ if (ubi->mtd->sync) -+ ubi->mtd->sync(ubi->mtd); -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubiblk->write_cache); -+ kfree(ubiblk->read_cache); ++ int x; ++#if DMA_ENABLE ++ unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer); ++ dma_cache_wback_inv(pBuffer,SECTOR_SIZE); +#else -+ vfree(ubiblk->write_cache); -+ vfree(ubiblk->read_cache); ++ unsigned char *ptr = (unsigned char *)pBuffer; +#endif -+ kfree(ubiblk); -+ -+ ubi_close_volume(ubiblk->uv); -+ return 0; ++ dprintk("LB_Read = %d \n",Sector); ++ if(_NAND_LB_GetFromCache(Sector,ptr)) ++ { ++ x = _NAND_LB_Read(Sector,ptr); ++ _NAND_LB_CopyToCache(Sector,ptr,0); + } -+ else{ -+ printk("%s: decrease use count\n",__FUNCTION__); -+ ubi_close_blkdev(ubiblk->uv); -+ return 0; -+ } -+ return 1; ++ return 512; +} -+static int ubiblk_flush(struct ubi_blktrans_dev *dev) -+{ -+ struct ubiblk_dev *ubiblk = ubiblks[dev->devnum]; -+ struct ubi_device *ubi = ubiblk->uv->vol->ubi; -+ -+ mutex_lock(&ubiblk->cache_mutex); -+ ubiblk_flush_writecache(ubiblk); -+ mutex_unlock(&ubiblk->cache_mutex); + -+ if (ubi->mtd->sync) -+ ubi->mtd->sync(ubi->mtd); ++static int NAND_LB_MultiWrite(unsigned int Sector, void *pBuffer,unsigned int SectorCount) ++{ ++ int i,ret; ++ unsigned char *p; ++ ++ _NAND_LB_CloseCACHES(Sector,Sector + SectorCount); ++ p = (unsigned char *)pBuffer; ++ for (i = Sector; i < Sector + SectorCount; i ++) ++ { ++ ret = udc_mtdblock_writesect(g_udc_mtdblk, i, p); ++ p += 512; ++ } ++ return ret; ++} ++ ++static int NAND_LB_Write(unsigned int Sector, void *pBuffer) ++{ ++#if DMA_ENABLE ++ unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer); ++ dma_cache_wback_inv(pBuffer,SECTOR_SIZE); ++#else ++ unsigned char *ptr = (unsigned char *)pBuffer; ++#endif ++ dprintk("LB_Write = %x %x\r\n",Sector,pBuffer); ++ if(_NAND_LB_UpdateInCache(Sector,ptr)) ++ { ++ _NAND_LB_CopyToCache(Sector,ptr,1); ++ } ++ return 512; ++} ++/********************************************************************* ++* ++* Global functions ++* ++***********************************************************************/ ++ ++int NAND_LB_Init(void) ++{ ++ dprintk("UDC CACHE Init \n"); ++ _NAND_LB_InitCache(); ++ g_udc_mtdblk = udc_get_mtdblk(); ++ g_udc_mtd = udc_get_mtd(); + return 0; +} + -+void ubiblk_add_vol_dev(struct ubi_blktrans_ops *tr, struct ubi_volume *vol) ++int NAND_LB_FLASHCACHE(void) +{ -+ struct ubi_blktrans_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) -+ return; -+ -+ dev->devnum = vol->vol_id; -+ dev->size = vol->used_bytes >> 9; -+ dev->tr = tr; -+ -+ if (vol->bdev_mode == UBI_READONLY) -+ dev->readonly = 1; -+ -+ vol->ubi->bdev_major = tr->major; -+ -+ add_ubi_blktrans_dev(dev); -+} -+ -+void ubiblk_remove_vol_dev(struct ubi_blktrans_dev *dev) -+{ -+ del_ubi_blktrans_dev(dev); -+ kfree(dev); -+} -+ -+static int ubiblk_getgeo(struct ubi_blktrans_dev *dev, struct hd_geometry *geo) -+{ -+ memset(geo, 0, sizeof(*geo)); -+ geo->heads = 4; -+ geo->sectors = 16; -+ geo->cylinders = dev->size/(4*16); ++ dprintk("Flush lb cache !\n"); ++ _NAND_LB_ClearCache(); ++// dprintk("Flush mtd cache !\n"); ++// udc_flush_cache(g_udc_mtdblk); + return 0; +} + -+static struct ubi_blktrans_ops ubiblk_tr = { -+ .name = "ubiblock", -+ .major = 0, -+ .part_bits = 0, -+ .blksize = UBIBLK_SECTOR_SIZE, -+ .open = ubiblk_open, -+ .release = ubiblk_release, -+ .readsect = ubiblk_readsect, -+ .writesect = ubiblk_writesect, -+ .getgeo = ubiblk_getgeo, -+ .flush = ubiblk_flush, -+ .add_vol = ubiblk_add_vol_dev, -+ .remove_vol = ubiblk_remove_vol_dev, -+ .owner = THIS_MODULE, -+}; -+ -+static int __init init_ubiblock(void) ++int NAND_MTD_FLASHCACHE(void) +{ -+ return register_ubi_blktrans(&ubiblk_tr); -+} -+ -+static void __exit cleanup_ubiblock(void) -+{ -+ deregister_ubi_blktrans(&ubiblk_tr); -+} -+ -+module_init(init_ubiblock); -+module_exit(cleanup_ubiblock); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Nicolas Pitre , Yurong Tan "); -+MODULE_DESCRIPTION("Caching read/erase/writeback block device emulation access to UBI volumes"); ---- linux-2.6.24.7.old/drivers/mtd/ubi/ubiblk.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/ubi/ubiblk.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,85 @@ -+/* -+ * (C) 2003 David Woodhouse -+ * (C) 2008 Yurong Tan : borrow from MTD blktrans.h for UBI used -+ * Interface to Linux block layer for UBI 'translation layers'. -+ */ -+ -+#ifndef __UBI_TRANS_H__ -+#define __UBI_TRANS_H__ -+ -+#include -+#include -+#include "ubi.h" -+ -+struct hd_geometry; -+struct ubi_volume_desc; -+struct ubi_blktrans_ops; -+struct file; -+struct inode; -+ -+struct ubiblk_dev { -+ struct ubi_volume_desc *uv; -+ int count; -+ struct mutex cache_mutex; -+ unsigned short vbw; //virt block number of write cache -+ unsigned short vbr; //virt block number of read cache -+ -+ unsigned char *write_cache; -+ unsigned char *page_sts; -+ unsigned char *subpage_sts; -+ -+ unsigned char *read_cache; -+ enum { STATE_UNUSED, STATE_USED } read_cache_state, write_cache_state; -+}; -+ -+struct ubi_blktrans_dev { -+ struct ubi_blktrans_ops *tr; -+ struct list_head list; -+ struct ubi_volume_desc *uv; -+ struct mutex lock; -+ int devnum; -+ unsigned long size; -+ int readonly; -+ void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */ -+}; -+ -+struct blkcore_priv; /* Differs for 2.4 and 2.5 kernels; private */ -+ -+struct ubi_blktrans_ops { -+ char *name; -+ int major; -+ int part_bits; -+ int blksize; -+ int blkshift; -+ -+ /* Access functions */ -+ int (*readsect)(struct ubi_blktrans_dev *dev, -+ unsigned long block, char *buffer); -+ int (*writesect)(struct ubi_blktrans_dev *dev, -+ unsigned long block, char *buffer); -+ -+ /* Block layer ioctls */ -+ int (*getgeo)(struct ubi_blktrans_dev *dev, struct hd_geometry *geo); -+ int (*flush)(struct ubi_blktrans_dev *dev); -+ -+ /* Called with mtd_table_mutex held; no race with add/remove */ -+ int (*open)(struct inode *i, struct file *f); -+ int (*release)(struct ubi_blktrans_dev *dev); -+ -+ /* Called on {de,}registration and on subsequent addition/removal -+ of devices, with mtd_table_mutex held. */ -+ void (*add_vol)(struct ubi_blktrans_ops *tr, struct ubi_volume *vol); -+ void (*remove_vol)(struct ubi_blktrans_dev *dev); -+ -+ struct list_head devs; -+ struct list_head list; -+ struct module *owner; -+ -+ struct ubi_blkcore_priv *blkcore_priv; -+}; -+ -+extern int add_ubi_blktrans_dev(struct ubi_blktrans_dev *new); -+extern int del_ubi_blktrans_dev(struct ubi_blktrans_dev *old); -+extern int register_ubi_blktrans(struct ubi_blktrans_ops *tr); -+extern int deregister_ubi_blktrans(struct ubi_blktrans_ops *tr); -+#endif /* __UBI_TRANS_H__ */ ---- linux-2.6.24.7.old/drivers/mtd/ubi/upd.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/upd.c 2009-04-12 18:13:57.000000000 +0200 -@@ -22,7 +22,8 @@ - */ - - /* -- * This file contains implementation of the volume update functionality. -+ * This file contains implementation of the volume update and atomic LEB change -+ * functionality. - * - * The update operation is based on the per-volume update marker which is - * stored in the volume table. The update marker is set before the update -@@ -45,29 +46,31 @@ - /** - * set_update_marker - set update marker. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * -- * This function sets the update marker flag for volume @vol_id. Returns zero -+ * This function sets the update marker flag for volume @vol. Returns zero - * in case of success and a negative error code in case of failure. - */ --static int set_update_marker(struct ubi_device *ubi, int vol_id) -+static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol) - { - int err; - struct ubi_vtbl_record vtbl_rec; -- struct ubi_volume *vol = ubi->volumes[vol_id]; - -- dbg_msg("set update marker for volume %d", vol_id); -+ dbg_msg("set update marker for volume %d", vol->vol_id); - - if (vol->upd_marker) { -- ubi_assert(ubi->vtbl[vol_id].upd_marker); -+ ubi_assert(ubi->vtbl[vol->vol_id].upd_marker); - dbg_msg("already set"); - return 0; - } - -- memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); -+ memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], -+ sizeof(struct ubi_vtbl_record)); - vtbl_rec.upd_marker = 1; - -- err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); -+ mutex_lock(&ubi->volumes_mutex); -+ err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); -+ mutex_unlock(&ubi->volumes_mutex); - vol->upd_marker = 1; - return err; - } -@@ -75,23 +78,24 @@ - /** - * clear_update_marker - clear update marker. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @bytes: new data size in bytes - * -- * This function clears the update marker for volume @vol_id, sets new volume -+ * This function clears the update marker for volume @vol, sets new volume - * data size and clears the "corrupted" flag (static volumes only). Returns - * zero in case of success and a negative error code in case of failure. - */ --static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long bytes) -+static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol, -+ long long bytes) - { - int err; - uint64_t tmp; - struct ubi_vtbl_record vtbl_rec; -- struct ubi_volume *vol = ubi->volumes[vol_id]; - -- dbg_msg("clear update marker for volume %d", vol_id); -+ dbg_msg("clear update marker for volume %d", vol->vol_id); - -- memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); -+ memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], -+ sizeof(struct ubi_vtbl_record)); - ubi_assert(vol->upd_marker && vtbl_rec.upd_marker); - vtbl_rec.upd_marker = 0; - -@@ -106,7 +110,9 @@ - vol->last_eb_bytes = vol->usable_leb_size; - } - -- err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); -+ mutex_lock(&ubi->volumes_mutex); -+ err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); -+ mutex_unlock(&ubi->volumes_mutex); - vol->upd_marker = 0; - return err; - } -@@ -114,35 +120,36 @@ - /** - * ubi_start_update - start volume update. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @bytes: update bytes - * - * This function starts volume update operation. If @bytes is zero, the volume - * is just wiped out. Returns zero in case of success and a negative error code - * in case of failure. - */ --int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes) -+int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, -+ long long bytes) - { - int i, err; - uint64_t tmp; -- struct ubi_volume *vol = ubi->volumes[vol_id]; - -- dbg_msg("start update of volume %d, %llu bytes", vol_id, bytes); -+ dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes); -+ ubi_assert(!vol->updating && !vol->changing_leb); - vol->updating = 1; - -- err = set_update_marker(ubi, vol_id); -+ err = set_update_marker(ubi, vol); - if (err) - return err; - - /* Before updating - wipe out the volume */ - for (i = 0; i < vol->reserved_pebs; i++) { -- err = ubi_eba_unmap_leb(ubi, vol_id, i); -+ err = ubi_eba_unmap_leb(ubi, vol, i); - if (err) - return err; - } - - if (bytes == 0) { -- err = clear_update_marker(ubi, vol_id, 0); -+ err = clear_update_marker(ubi, vol, 0); - if (err) - return err; - err = ubi_wl_flush(ubi); -@@ -150,7 +157,11 @@ - vol->updating = 0; - } - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL); -+#else - vol->upd_buf = vmalloc(ubi->leb_size); -+#endif - if (!vol->upd_buf) - return -ENOMEM; - -@@ -163,9 +174,46 @@ - } - - /** -+ * ubi_start_leb_change - start atomic LEB change. -+ * @ubi: UBI device description object -+ * @vol: volume description object -+ * @req: operation request -+ * -+ * This function starts atomic LEB change operation. Returns zero in case of -+ * success and a negative error code in case of failure. -+ */ -+int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, -+ const struct ubi_leb_change_req *req) -+{ -+ ubi_assert(!vol->updating && !vol->changing_leb); -+ -+ dbg_msg("start changing LEB %d:%d, %u bytes", -+ vol->vol_id, req->lnum, req->bytes); -+ if (req->bytes == 0) -+ return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0, -+ req->dtype); -+ -+ vol->upd_bytes = req->bytes; -+ vol->upd_received = 0; -+ vol->changing_leb = 1; -+ vol->ch_lnum = req->lnum; -+ vol->ch_dtype = req->dtype; -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ vol->upd_buf = kmalloc(req->bytes, GFP_KERNEL); -+#else -+ vol->upd_buf = vmalloc(req->bytes); -+#endif -+ if (!vol->upd_buf) -+ return -ENOMEM; -+ ++ dprintk("Flush mtd cache !\n"); ++ udc_flush_cache(g_udc_mtdblk); + return 0; +} + -+/** - * write_leb - write update data. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * @buf: data to write - * @len: data size -@@ -191,26 +239,22 @@ - * This function returns zero in case of success and a negative error code in - * case of failure. - */ --static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, -- int len, int used_ebs) -+static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, -+ void *buf, int len, int used_ebs) - { -- int err, l; -- struct ubi_volume *vol = ubi->volumes[vol_id]; -+ int err; - - if (vol->vol_type == UBI_DYNAMIC_VOLUME) { -- l = ALIGN(len, ubi->min_io_size); -- memset(buf + len, 0xFF, l - len); -+ len = ALIGN(len, ubi->min_io_size); -+ memset(buf + len, 0xFF, len - len); - -- l = ubi_calc_data_len(ubi, buf, l); -- if (l == 0) { -+ len = ubi_calc_data_len(ubi, buf, len); -+ if (len == 0) { - dbg_msg("all %d bytes contain 0xFF - skip", len); - return 0; - } -- if (len != l) -- dbg_msg("skip last %d bytes (0xFF)", len - l); - -- err = ubi_eba_write_leb(ubi, vol_id, lnum, buf, 0, l, -- UBI_UNKNOWN); -+ err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len, UBI_UNKNOWN); - } else { - /* - * When writing static volume, and this is the last logical -@@ -222,7 +266,7 @@ - * contain zeros, not random trash. - */ - memset(buf + len, 0, vol->usable_leb_size - len); -- err = ubi_eba_write_leb_st(ubi, vol_id, lnum, buf, len, -+ err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len, - UBI_UNKNOWN, used_ebs); - } - -@@ -236,16 +280,15 @@ - * @count: how much bytes to write - * - * This function writes more data to the volume which is being updated. It may -- * be called arbitrary number of times until all of the update data arrive. -- * This function returns %0 in case of success, number of bytes written during -- * the last call if the whole volume update was successfully finished, and a -+ * be called arbitrary number of times until all the update data arriveis. This -+ * function returns %0 in case of success, number of bytes written during the -+ * last call if the whole volume update has been successfully finished, and a - * negative error code in case of failure. - */ --int ubi_more_update_data(struct ubi_device *ubi, int vol_id, -+int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, - const void __user *buf, int count) - { - uint64_t tmp; -- struct ubi_volume *vol = ubi->volumes[vol_id]; - int lnum, offs, err = 0, len, to_write = count; - - dbg_msg("write %d of %lld bytes, %lld already passed", -@@ -290,8 +333,8 @@ - * is the last chunk, it's time to flush the buffer. - */ - ubi_assert(flush_len <= vol->usable_leb_size); -- err = write_leb(ubi, vol_id, lnum, vol->upd_buf, -- flush_len, vol->upd_ebs); -+ err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len, -+ vol->upd_ebs); - if (err) - return err; - } -@@ -312,37 +355,102 @@ - else - len = count; - -- err = copy_from_user(vol->upd_buf, buf, len); -+ err= copy_from_user(&lnum, buf, sizeof(lnum)); -+ if (err) -+ return -EFAULT; -+ err = copy_from_user(vol->upd_buf, &(((char*)buf)[sizeof(unsigned int)]), len); - if (err) - return -EFAULT; - - if (len == vol->usable_leb_size || - vol->upd_received + len == vol->upd_bytes) { -- err = write_leb(ubi, vol_id, lnum, vol->upd_buf, len, -- vol->upd_ebs); -+ err = write_leb(ubi, vol, lnum, vol->upd_buf, -+ len, vol->upd_ebs); - if (err) - break; - } - - vol->upd_received += len; - count -= len; -- lnum += 1; -+// lnum += 1; - buf += len; - } - - ubi_assert(vol->upd_received <= vol->upd_bytes); - if (vol->upd_received == vol->upd_bytes) { - /* The update is finished, clear the update marker */ -- err = clear_update_marker(ubi, vol_id, vol->upd_bytes); -+ err = clear_update_marker(ubi, vol, vol->upd_bytes); - if (err) - return err; - err = ubi_wl_flush(ubi); - if (err == 0) { -+ vol->updating = 0; - err = to_write; -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(vol->upd_buf); -+#else - vfree(vol->upd_buf); -- vol->updating = 0; -+#endif - } - } - - return err; - } -+ -+/** -+ * ubi_more_leb_change_data - accept more data for atomic LEB change. -+ * @vol: volume description object -+ * @buf: write data (user-space memory buffer) -+ * @count: how much bytes to write -+ * -+ * This function accepts more data to the volume which is being under the -+ * "atomic LEB change" operation. It may be called arbitrary number of times -+ * until all data arrives. This function returns %0 in case of success, number -+ * of bytes written during the last call if the whole "atomic LEB change" -+ * operation has been successfully finished, and a negative error code in case -+ * of failure. -+ */ -+int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, -+ const void __user *buf, int count) ++int udc_read(unsigned int offset, unsigned int len, unsigned char *buf) +{ -+ int err; ++ unsigned long block,sector,i; + -+ dbg_msg("write %d of %lld bytes, %lld already passed", -+ count, vol->upd_bytes, vol->upd_received); ++ block = offset >> SECTOR_SHIFT; ++ sector = len >> SECTOR_SHIFT; ++ dprintk("read dev = ia:%x, s:%d c:%d\r\n",buf,block,sector); + -+ if (ubi->ro_mode) -+ return -EROFS; -+ -+ if (vol->upd_received + count > vol->upd_bytes) -+ count = vol->upd_bytes - vol->upd_received; -+ -+ err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count); -+ if (err) -+ return -EFAULT; -+ -+ vol->upd_received += count; -+ -+ if (vol->upd_received == vol->upd_bytes) { -+ int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size); -+ -+ memset(vol->upd_buf + vol->upd_bytes, 0xFF, len - vol->upd_bytes); -+ len = ubi_calc_data_len(ubi, vol->upd_buf, len); -+ err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum, -+ vol->upd_buf, len, UBI_UNKNOWN); -+ if (err) -+ return err; ++ if (sector <= 8) ++ { ++ for(i = 0;i < sector; i++) ++ { ++ NAND_LB_Read(block + i,(void *)(buf)); ++ buf += 512; ++ } + } -+ -+ ubi_assert(vol->upd_received <= vol->upd_bytes); -+ if (vol->upd_received == vol->upd_bytes) { -+ vol->changing_leb = 0; -+ err = count; -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(vol->upd_buf); -+#else -+ vfree(vol->upd_buf); -+#endif -+ } -+ -+ return err; -+} ---- linux-2.6.24.7.old/drivers/mtd/ubi/vmt.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/vmt.c 2009-04-12 18:13:57.000000000 +0200 -@@ -63,21 +63,30 @@ - * B. process 2 removes volume Y; - * C. process 1 starts reading the //class/ubi/ubiX_Y/reserved_ebs file; - * -- * What we want to do in a situation like that is to return error when the file -- * is read. This is done by means of the 'removed' flag and the 'vol_lock' of -- * the UBI volume description object. -+ * In this situation, this function will return %-ENODEV because it will find -+ * out that the volume was removed from the @ubi->volumes array. - */ - static ssize_t vol_attribute_show(struct device *dev, - struct device_attribute *attr, char *buf) - { - int ret; - struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); -+ struct ubi_device *ubi; - -- spin_lock(&vol->ubi->volumes_lock); -- if (vol->removed) { -- spin_unlock(&vol->ubi->volumes_lock); -+ ubi = ubi_get_device(vol->ubi->ubi_num); -+ if (!ubi) -+ return -ENODEV; -+ -+ spin_lock(&ubi->volumes_lock); -+ if (!ubi->volumes[vol->vol_id]) { -+ spin_unlock(&ubi->volumes_lock); -+ ubi_put_device(ubi); - return -ENODEV; - } -+ /* Take a reference to prevent volume removal */ -+ vol->ref_count += 1; -+ spin_unlock(&ubi->volumes_lock); -+ - if (attr == &attr_vol_reserved_ebs) - ret = sprintf(buf, "%d\n", vol->reserved_pebs); - else if (attr == &attr_vol_type) { -@@ -94,15 +103,22 @@ - ret = sprintf(buf, "%d\n", vol->corrupted); - else if (attr == &attr_vol_alignment) - ret = sprintf(buf, "%d\n", vol->alignment); -- else if (attr == &attr_vol_usable_eb_size) { -+ else if (attr == &attr_vol_usable_eb_size) - ret = sprintf(buf, "%d\n", vol->usable_leb_size); -- } else if (attr == &attr_vol_data_bytes) -+ else if (attr == &attr_vol_data_bytes) - ret = sprintf(buf, "%lld\n", vol->used_bytes); - else if (attr == &attr_vol_upd_marker) - ret = sprintf(buf, "%d\n", vol->upd_marker); - else -- BUG(); -- spin_unlock(&vol->ubi->volumes_lock); -+ /* This must be a bug */ -+ ret = -EINVAL; -+ -+ /* We've done the operation, drop volume and UBI device references */ -+ spin_lock(&ubi->volumes_lock); -+ vol->ref_count -= 1; -+ ubi_assert(vol->ref_count >= 0); -+ spin_unlock(&ubi->volumes_lock); -+ ubi_put_device(ubi); - return ret; - } - -@@ -110,7 +126,7 @@ - static void vol_release(struct device *dev) - { - struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); -- ubi_assert(vol->removed); -+ - kfree(vol); - } - -@@ -152,9 +168,7 @@ - if (err) - return err; - err = device_create_file(&vol->dev, &attr_vol_upd_marker); -- if (err) -- return err; -- return 0; -+ return err; - } - - /** -@@ -180,16 +194,18 @@ - * @req: volume creation request - * - * This function creates volume described by @req. If @req->vol_id id -- * %UBI_VOL_NUM_AUTO, this function automatically assigne ID to the new volume -+ * %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume - * and saves it in @req->vol_id. Returns zero in case of success and a negative -- * error code in case of failure. -+ * error code in case of failure. Note, the caller has to have the -+ * @ubi->volumes_mutex locked. - */ - int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) - { -- int i, err, vol_id = req->vol_id; -+ int i, err, vol_id = req->vol_id, dont_free = 0; - struct ubi_volume *vol; - struct ubi_vtbl_record vtbl_rec; - uint64_t bytes; -+ dev_t dev; - - if (ubi->ro_mode) - return -EROFS; -@@ -199,7 +215,6 @@ - return -ENOMEM; - - spin_lock(&ubi->volumes_lock); -- - if (vol_id == UBI_VOL_NUM_AUTO) { - /* Find unused volume ID */ - dbg_msg("search for vacant volume ID"); -@@ -252,6 +267,7 @@ - } - ubi->avail_pebs -= vol->reserved_pebs; - ubi->rsvd_pebs += vol->reserved_pebs; -+ spin_unlock(&ubi->volumes_lock); - - vol->vol_id = vol_id; - vol->alignment = req->alignment; -@@ -259,10 +275,7 @@ - vol->vol_type = req->vol_type; - vol->name_len = req->name_len; - memcpy(vol->name, req->name, vol->name_len + 1); -- vol->exclusive = 1; - vol->ubi = ubi; -- ubi->volumes[vol_id] = vol; -- spin_unlock(&ubi->volumes_lock); - - /* - * Finish all pending erases because there may be some LEBs belonging -@@ -299,9 +312,10 @@ - /* Register character device for the volume */ - cdev_init(&vol->cdev, &ubi_vol_cdev_operations); - vol->cdev.owner = THIS_MODULE; -- err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol_id + 1), 1); -+ dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1); -+ err = cdev_add(&vol->cdev, dev, 1); - if (err) { -- ubi_err("cannot add character device for volume %d", vol_id); -+ ubi_err("cannot add character device"); - goto out_mapping; - } - -@@ -311,12 +325,15 @@ - - vol->dev.release = vol_release; - vol->dev.parent = &ubi->dev; -- vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1); -+ vol->dev.devt = dev; - vol->dev.class = ubi_class; -+ - sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); - err = device_register(&vol->dev); -- if (err) -+ if (err) { -+ ubi_err("cannot register device"); - goto out_gluebi; -+ } - - err = volume_sysfs_init(ubi, vol); - if (err) -@@ -339,15 +356,29 @@ - goto out_sysfs; - - spin_lock(&ubi->volumes_lock); -+ ubi->volumes[vol_id] = vol; - ubi->vol_count += 1; -- vol->exclusive = 0; - spin_unlock(&ubi->volumes_lock); - - paranoid_check_volumes(ubi); - return 0; - -+out_sysfs: -+ /* -+ * We have registered our device, we should not free the volume* -+ * description object in this function in case of an error - it is -+ * freed by the release function. -+ * -+ * Get device reference to prevent the release function from being -+ * called just after sysfs has been closed. -+ */ -+ dont_free = 1; -+ get_device(&vol->dev); -+ volume_sysfs_close(vol); - out_gluebi: -- err = ubi_destroy_gluebi(vol); -+ if (ubi_destroy_gluebi(vol)) -+ dbg_err("cannot destroy gluebi for volume %d:%d", -+ ubi->ubi_num, vol_id); - out_cdev: - cdev_del(&vol->cdev); - out_mapping: -@@ -356,26 +387,13 @@ - spin_lock(&ubi->volumes_lock); - ubi->rsvd_pebs -= vol->reserved_pebs; - ubi->avail_pebs += vol->reserved_pebs; -- ubi->volumes[vol_id] = NULL; - out_unlock: - spin_unlock(&ubi->volumes_lock); -- kfree(vol); -- return err; -- -- /* -- * We are registered, so @vol is destroyed in the release function and -- * we have to de-initialize differently. -- */ --out_sysfs: -- err = ubi_destroy_gluebi(vol); -- cdev_del(&vol->cdev); -- kfree(vol->eba_tbl); -- spin_lock(&ubi->volumes_lock); -- ubi->rsvd_pebs -= vol->reserved_pebs; -- ubi->avail_pebs += vol->reserved_pebs; -- ubi->volumes[vol_id] = NULL; -- spin_unlock(&ubi->volumes_lock); -- volume_sysfs_close(vol); -+ if (dont_free) -+ put_device(&vol->dev); + else -+ kfree(vol); -+ ubi_err("cannot create volume %d, error %d", vol_id, err); - return err; - } - -@@ -385,7 +403,8 @@ - * - * This function removes volume described by @desc. The volume has to be opened - * in "exclusive" mode. Returns zero in case of success and a negative error -- * code in case of failure. -+ * code in case of failure. The caller has to have the @ubi->volumes_mutex -+ * locked. - */ - int ubi_remove_volume(struct ubi_volume_desc *desc) - { -@@ -400,30 +419,36 @@ - if (ubi->ro_mode) - return -EROFS; - -+ spin_lock(&ubi->volumes_lock); -+ if (vol->ref_count > 1) { -+ /* -+ * The volume is busy, probably someone is reading one of its -+ * sysfs files. -+ */ -+ err = -EBUSY; -+ goto out_unlock; -+ } -+ ubi->volumes[vol_id] = NULL; -+ spin_unlock(&ubi->volumes_lock); ++ NAND_LB_MultiRead(block, buf, sector); + - err = ubi_destroy_gluebi(vol); - if (err) -- return err; -+ goto out_err; - - err = ubi_change_vtbl_record(ubi, vol_id, NULL); - if (err) -- return err; -+ goto out_err; - - for (i = 0; i < vol->reserved_pebs; i++) { -- err = ubi_eba_unmap_leb(ubi, vol_id, i); -+ err = ubi_eba_unmap_leb(ubi, vol, i); - if (err) -- return err; -+ goto out_err; - } - -- spin_lock(&ubi->volumes_lock); -- vol->removed = 1; -- ubi->volumes[vol_id] = NULL; -- spin_unlock(&ubi->volumes_lock); -- - kfree(vol->eba_tbl); - vol->eba_tbl = NULL; - cdev_del(&vol->cdev); - volume_sysfs_close(vol); -- kfree(desc); - - spin_lock(&ubi->volumes_lock); - ubi->rsvd_pebs -= reserved_pebs; -@@ -441,8 +466,15 @@ - spin_unlock(&ubi->volumes_lock); - - paranoid_check_volumes(ubi); -- module_put(THIS_MODULE); - return 0; ++ return len; ++} + -+out_err: -+ ubi_err("cannot remove volume %d, error %d", vol_id, err); -+ spin_lock(&ubi->volumes_lock); -+ ubi->volumes[vol_id] = vol; -+out_unlock: -+ spin_unlock(&ubi->volumes_lock); -+ return err; - } - - /** -@@ -450,8 +482,9 @@ - * @desc: volume descriptor - * @reserved_pebs: new size in physical eraseblocks - * -- * This function returns zero in case of success, and a negative error code in -- * case of failure. -+ * This function re-sizes the volume and returns zero in case of success, and a -+ * negative error code in case of failure. The caller has to have the -+ * @ubi->volumes_mutex locked. - */ - int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) - { -@@ -466,8 +499,6 @@ - - dbg_msg("re-size volume %d to from %d to %d PEBs", - vol_id, vol->reserved_pebs, reserved_pebs); -- ubi_assert(desc->mode == UBI_EXCLUSIVE); -- ubi_assert(vol == ubi->volumes[vol_id]); - - if (vol->vol_type == UBI_STATIC_VOLUME && - reserved_pebs < vol->used_ebs) { -@@ -487,6 +518,14 @@ - for (i = 0; i < reserved_pebs; i++) - new_mapping[i] = UBI_LEB_UNMAPPED; - -+ spin_lock(&ubi->volumes_lock); -+ if (vol->ref_count > 1) { -+ spin_unlock(&ubi->volumes_lock); -+ err = -EBUSY; -+ goto out_free; -+ } -+ spin_unlock(&ubi->volumes_lock); ++int udc_write(unsigned int offset, unsigned int len, unsigned char *buf) ++{ ++ unsigned long block,sector,i; + - /* Reserve physical eraseblocks */ - pebs = reserved_pebs - vol->reserved_pebs; - if (pebs > 0) { -@@ -516,7 +555,7 @@ - - if (pebs < 0) { - for (i = 0; i < -pebs; i++) { -- err = ubi_eba_unmap_leb(ubi, vol_id, reserved_pebs + i); -+ err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i); - if (err) - goto out_acc; - } -@@ -565,27 +604,28 @@ - /** - * ubi_add_volume - add volume. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * -- * This function adds an existin volume and initializes all its data -- * structures. Returnes zero in case of success and a negative error code in -+ * This function adds an existing volume and initializes all its data -+ * structures. Returns zero in case of success and a negative error code in - * case of failure. - */ --int ubi_add_volume(struct ubi_device *ubi, int vol_id) -+int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) - { -- int err; -- struct ubi_volume *vol = ubi->volumes[vol_id]; -+ int err, vol_id = vol->vol_id; -+ dev_t dev; - - dbg_msg("add volume %d", vol_id); - ubi_dbg_dump_vol_info(vol); -- ubi_assert(vol); - - /* Register character device for the volume */ - cdev_init(&vol->cdev, &ubi_vol_cdev_operations); - vol->cdev.owner = THIS_MODULE; -- err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol->vol_id + 1), 1); -+ dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1); -+ err = cdev_add(&vol->cdev, dev, 1); - if (err) { -- ubi_err("cannot add character device for volume %d", vol_id); -+ ubi_err("cannot add character device for volume %d, error %d", -+ vol_id, err); - return err; - } - -@@ -595,7 +635,7 @@ - - vol->dev.release = vol_release; - vol->dev.parent = &ubi->dev; -- vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1); -+ vol->dev.devt = dev; - vol->dev.class = ubi_class; - sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); - err = device_register(&vol->dev); -@@ -623,22 +663,19 @@ - /** - * ubi_free_volume - free volume. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * -- * This function frees all resources for volume @vol_id but does not remove it. -+ * This function frees all resources for volume @vol but does not remove it. - * Used only when the UBI device is detached. - */ --void ubi_free_volume(struct ubi_device *ubi, int vol_id) -+void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) - { - int err; -- struct ubi_volume *vol = ubi->volumes[vol_id]; - -- dbg_msg("free volume %d", vol_id); -- ubi_assert(vol); -+ dbg_msg("free volume %d", vol->vol_id); - -- vol->removed = 1; -+ ubi->volumes[vol->vol_id] = NULL; - err = ubi_destroy_gluebi(vol); -- ubi->volumes[vol_id] = NULL; - cdev_del(&vol->cdev); - volume_sysfs_close(vol); - } -@@ -708,11 +745,6 @@ - goto fail; - } - -- if (vol->upd_marker != 0 && vol->upd_marker != 1) { -- ubi_err("bad upd_marker"); -- goto fail; -- } -- - if (vol->upd_marker && vol->corrupted) { - dbg_err("update marker and corrupted simultaneously"); - goto fail; -@@ -747,7 +779,7 @@ - - n = (long long)vol->used_ebs * vol->usable_leb_size; - if (vol->vol_type == UBI_DYNAMIC_VOLUME) { -- if (vol->corrupted != 0) { -+ if (vol->corrupted) { - ubi_err("corrupted dynamic volume"); - goto fail; - } -@@ -764,10 +796,6 @@ - goto fail; - } - } else { -- if (vol->corrupted != 0 && vol->corrupted != 1) { -- ubi_err("bad corrupted"); -- goto fail; -- } - if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { - ubi_err("bad used_ebs"); - goto fail; -@@ -820,9 +848,7 @@ - { - int i; - -- mutex_lock(&ubi->vtbl_mutex); - for (i = 0; i < ubi->vtbl_slots; i++) - paranoid_check_volume(ubi, i); -- mutex_unlock(&ubi->vtbl_mutex); - } - #endif ---- linux-2.6.24.7.old/drivers/mtd/ubi/vtbl.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/vtbl.c 2009-04-12 18:13:57.000000000 +0200 -@@ -86,8 +86,10 @@ - { - int i, err; - uint32_t crc; -+ struct ubi_volume *layout_vol; - - ubi_assert(idx >= 0 && idx < ubi->vtbl_slots); -+ layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; - - if (!vtbl_rec) - vtbl_rec = &empty_vtbl_record; -@@ -96,31 +98,25 @@ - vtbl_rec->crc = cpu_to_be32(crc); - } - -- mutex_lock(&ubi->vtbl_mutex); - memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); - for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { -- err = ubi_eba_unmap_leb(ubi, UBI_LAYOUT_VOL_ID, i); -- if (err) { -- mutex_unlock(&ubi->vtbl_mutex); -+ err = ubi_eba_unmap_leb(ubi, layout_vol, i); -+ if (err) - return err; -- } -- err = ubi_eba_write_leb(ubi, UBI_LAYOUT_VOL_ID, i, ubi->vtbl, 0, ++ block = offset >> SECTOR_SHIFT; ++ sector = len >> SECTOR_SHIFT; ++ dprintk("write dev s:%d c:%d\r\n",block,sector); + -+ err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0, - ubi->vtbl_size, UBI_LONGTERM); -- if (err) { -- mutex_unlock(&ubi->vtbl_mutex); -+ if (err) - return err; -- } - } - - paranoid_vtbl_check(ubi); -- mutex_unlock(&ubi->vtbl_mutex); -- return ubi_wl_flush(ubi); -+ return 0; - } - - /** -- * vol_til_check - check if volume table is not corrupted and contains sensible -- * data. -- * -+ * vtbl_check - check if volume table is not corrupted and contains sensible -+ * data. - * @ubi: UBI device description object - * @vtbl: volume table - * -@@ -273,7 +269,7 @@ - * this volume table copy was found during scanning. It has to be wiped - * out. - */ -- sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID); -+ sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID); - if (sv) - old_seb = ubi_scan_find_seb(sv, copy); - -@@ -285,7 +281,7 @@ - } - - vid_hdr->vol_type = UBI_VID_DYNAMIC; -- vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID); -+ vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID); - vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT; - vid_hdr->data_size = vid_hdr->used_ebs = - vid_hdr->data_pad = cpu_to_be32(0); -@@ -378,7 +374,11 @@ - - /* Read both LEB 0 and LEB 1 into memory */ - ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ leb[seb->lnum] = kmalloc(ubi->vtbl_size, GFP_KERNEL); -+#else - leb[seb->lnum] = vmalloc(ubi->vtbl_size); -+#endif - if (!leb[seb->lnum]) { - err = -ENOMEM; - goto out_free; -@@ -414,7 +414,11 @@ - } - - /* Both LEB 1 and LEB 2 are OK and consistent */ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(leb[1]); -+#else - vfree(leb[1]); -+#endif - return leb[0]; - } else { - /* LEB 0 is corrupted or does not exist */ -@@ -434,14 +438,23 @@ - if (err) - goto out_free; - ubi_msg("volume table was restored"); -- -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(leb[0]); -+#else - vfree(leb[0]); -+#endif - return leb[1]; - } - - out_free: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(leb[0]); -+ kfree(leb[1]); -+#else - vfree(leb[0]); - vfree(leb[1]); -+#endif -+ - return ERR_PTR(err); - } - -@@ -459,7 +472,11 @@ - int i; - struct ubi_vtbl_record *vtbl; - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ vtbl = kmalloc(ubi->vtbl_size, GFP_KERNEL); -+#else - vtbl = vmalloc(ubi->vtbl_size); -+#endif - if (!vtbl) - return ERR_PTR(-ENOMEM); - memset(vtbl, 0, ubi->vtbl_size); -@@ -472,7 +489,11 @@ - - err = create_vtbl(ubi, si, i, vtbl); - if (err) { -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(vtbl); -+#else - vfree(vtbl); -+#endif - return ERR_PTR(err); - } - } -@@ -518,6 +539,18 @@ - vol->name[vol->name_len] = '\0'; - vol->vol_id = i; - -+ if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { -+ /* Auto re-size flag may be set only for one volume */ -+ if (ubi->autoresize_vol_id != -1) { -+ ubi_err("more then one auto-resize volume (%d " -+ "and %d)", ubi->autoresize_vol_id, i); -+ kfree(vol); -+ return -EINVAL; -+ } -+ -+ ubi->autoresize_vol_id = i; ++ if(sector <= 8) ++ { ++ for(i = 0;i < sector; i++) ++ { ++ NAND_LB_Write(block + i,(void *)(buf)); ++ buf += 512; ++ FlushDataState = 1; + } ++ }else ++ NAND_LB_MultiWrite(block,(void *)(buf),sector); + - ubi_assert(!ubi->volumes[i]); - ubi->volumes[i] = vol; - ubi->vol_count += 1; -@@ -568,6 +601,7 @@ - vol->last_eb_bytes = sv->last_data_size; - } - -+ /* And add the layout volume */ - vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); - if (!vol) - return -ENOMEM; -@@ -582,7 +616,8 @@ - vol->last_eb_bytes = vol->reserved_pebs; - vol->used_bytes = - (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad); -- vol->vol_id = UBI_LAYOUT_VOL_ID; -+ vol->vol_id = UBI_LAYOUT_VOLUME_ID; -+ vol->ref_count = 1; - - ubi_assert(!ubi->volumes[i]); - ubi->volumes[vol_id2idx(ubi, vol->vol_id)] = vol; -@@ -734,7 +769,7 @@ - ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE; - ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size); - -- sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID); -+ sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID); - if (!sv) { - /* - * No logical eraseblocks belonging to the layout volume were -@@ -786,7 +821,11 @@ - return 0; - - out_free: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->vtbl); -+#else - vfree(ubi->vtbl); -+#endif - for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) - if (ubi->volumes[i]) { - kfree(ubi->volumes[i]); ---- linux-2.6.24.7.old/drivers/mtd/ubi/wl.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/wl.c 2009-04-12 18:13:57.000000000 +0200 -@@ -117,21 +117,6 @@ - #define WL_MAX_FAILURES 32 - - /** -- * struct ubi_wl_entry - wear-leveling entry. -- * @rb: link in the corresponding RB-tree -- * @ec: erase counter -- * @pnum: physical eraseblock number -- * -- * Each physical eraseblock has a corresponding &struct wl_entry object which -- * may be kept in different RB-trees. -- */ --struct ubi_wl_entry { -- struct rb_node rb; -- int ec; -- int pnum; --}; -- --/** - * struct ubi_wl_prot_entry - PEB protection entry. - * @rb_pnum: link in the @wl->prot.pnum RB-tree - * @rb_aec: link in the @wl->prot.aec RB-tree -@@ -216,9 +201,6 @@ - #define paranoid_check_in_wl_tree(e, root) - #endif - --/* Slab cache for wear-leveling entries */ --static struct kmem_cache *wl_entries_slab; -- - /** - * wl_tree_add - add a wear-leveling entry to a WL RB-tree. - * @e: the wear-leveling entry to add -@@ -267,15 +249,26 @@ - int err; - struct ubi_work *wrk; - -- spin_lock(&ubi->wl_lock); -+ cond_resched(); - -+ /* -+ * @ubi->work_sem is used to synchronize with the workers. Workers take -+ * it in read mode, so many of them may be doing works at a time. But -+ * the queue flush code has to be sure the whole queue of works is -+ * done, and it takes the mutex in write mode. -+ */ -+ down_read(&ubi->work_sem); -+ spin_lock(&ubi->wl_lock); - if (list_empty(&ubi->works)) { - spin_unlock(&ubi->wl_lock); -+ up_read(&ubi->work_sem); - return 0; - } - - wrk = list_entry(ubi->works.next, struct ubi_work, list); - list_del(&wrk->list); -+ ubi->works_count -= 1; -+ ubi_assert(ubi->works_count >= 0); - spin_unlock(&ubi->wl_lock); - - /* -@@ -286,11 +279,8 @@ - err = wrk->func(ubi, wrk, 0); - if (err) - ubi_err("work failed with error code %d", err); -+ up_read(&ubi->work_sem); - -- spin_lock(&ubi->wl_lock); -- ubi->works_count -= 1; -- ubi_assert(ubi->works_count >= 0); -- spin_unlock(&ubi->wl_lock); - return err; - } - -@@ -549,8 +539,12 @@ - * prot_tree_del - remove a physical eraseblock from the protection trees - * @ubi: UBI device description object - * @pnum: the physical eraseblock to remove -+ * -+ * This function returns PEB @pnum from the protection trees and returns zero -+ * in case of success and %-ENODEV if the PEB was not found in the protection -+ * trees. - */ --static void prot_tree_del(struct ubi_device *ubi, int pnum) -+static int prot_tree_del(struct ubi_device *ubi, int pnum) - { - struct rb_node *p; - struct ubi_wl_prot_entry *pe = NULL; -@@ -561,7 +555,7 @@ - pe = rb_entry(p, struct ubi_wl_prot_entry, rb_pnum); - - if (pnum == pe->e->pnum) -- break; -+ goto found; - - if (pnum < pe->e->pnum) - p = p->rb_left; -@@ -569,10 +563,14 @@ - p = p->rb_right; - } - -+ return -ENODEV; ++ return len; ++} + -+found: - ubi_assert(pe->e->pnum == pnum); - rb_erase(&pe->rb_aec, &ubi->prot.aec); - rb_erase(&pe->rb_pnum, &ubi->prot.pnum); - kfree(pe); -+ return 0; - } - - /** -@@ -744,7 +742,8 @@ - static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, - int cancel) - { -- int err, put = 0; -+ int err, put = 0, scrubbing = 0, protect = 0; -+ struct ubi_wl_prot_entry *uninitialized_var(pe); - struct ubi_wl_entry *e1, *e2; - struct ubi_vid_hdr *vid_hdr; - -@@ -757,21 +756,17 @@ - if (!vid_hdr) - return -ENOMEM; - -+ mutex_lock(&ubi->move_mutex); - spin_lock(&ubi->wl_lock); -+ ubi_assert(!ubi->move_from && !ubi->move_to); -+ ubi_assert(!ubi->move_to_put); - -- /* -- * Only one WL worker at a time is supported at this implementation, so -- * make sure a PEB is not being moved already. -- */ -- if (ubi->move_to || !ubi->free.rb_node || -+ if (!ubi->free.rb_node || - (!ubi->used.rb_node && !ubi->scrub.rb_node)) { - /* -- * Only one WL worker at a time is supported at this -- * implementation, so if a LEB is already being moved, cancel. -- * -- * No free physical eraseblocks? Well, we cancel wear-leveling -- * then. It will be triggered again when a free physical -- * eraseblock appears. -+ * No free physical eraseblocks? Well, they must be waiting in -+ * the queue to be erased. Cancel movement - it will be -+ * triggered again when a free physical eraseblock appears. - * - * No used physical eraseblocks? They must be temporarily - * protected from being moved. They will be moved to the -@@ -780,10 +775,7 @@ - */ - dbg_wl("cancel WL, a list is empty: free %d, used %d", - !ubi->free.rb_node, !ubi->used.rb_node); -- ubi->wl_scheduled = 0; -- spin_unlock(&ubi->wl_lock); -- ubi_free_vid_hdr(ubi, vid_hdr); -- return 0; -+ goto out_cancel; - } - - if (!ubi->scrub.rb_node) { -@@ -798,27 +790,24 @@ - if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) { - dbg_wl("no WL needed: min used EC %d, max free EC %d", - e1->ec, e2->ec); -- ubi->wl_scheduled = 0; -- spin_unlock(&ubi->wl_lock); -- ubi_free_vid_hdr(ubi, vid_hdr); -- return 0; -+ goto out_cancel; - } - paranoid_check_in_wl_tree(e1, &ubi->used); - rb_erase(&e1->rb, &ubi->used); - dbg_wl("move PEB %d EC %d to PEB %d EC %d", - e1->pnum, e1->ec, e2->pnum, e2->ec); - } else { -+ /* Perform scrubbing */ -+ scrubbing = 1; - e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb); - e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); - paranoid_check_in_wl_tree(e1, &ubi->scrub); -- rb_erase(&e1->rb, &ubi->scrub); -+ rb_erase(&e1->rb, &ubi->scrub); - dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum); - } - - paranoid_check_in_wl_tree(e2, &ubi->free); - rb_erase(&e2->rb, &ubi->free); -- ubi_assert(!ubi->move_from && !ubi->move_to); -- ubi_assert(!ubi->move_to_put && !ubi->move_from_put); - ubi->move_from = e1; - ubi->move_to = e2; - spin_unlock(&ubi->wl_lock); -@@ -828,6 +817,10 @@ - * We so far do not know which logical eraseblock our physical - * eraseblock (@e1) belongs to. We have to read the volume identifier - * header first. -+ * -+ * Note, we are protected from this PEB being unmapped and erased. The -+ * 'ubi_wl_put_peb()' would wait for moving to be finished if the PEB -+ * which is being moved was unmapped. - */ - - err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0); -@@ -842,32 +835,51 @@ - * likely have the VID header in place. - */ - dbg_wl("PEB %d has no VID header", e1->pnum); -- err = 0; -- } else { -- ubi_err("error %d while reading VID header from PEB %d", -- err, e1->pnum); -- if (err > 0) -- err = -EIO; -+ goto out_not_moved; - } -- goto error; -+ -+ ubi_err("error %d while reading VID header from PEB %d", -+ err, e1->pnum); -+ if (err > 0) -+ err = -EIO; -+ goto out_error; - } - - err = ubi_eba_copy_leb(ubi, e1->pnum, e2->pnum, vid_hdr); - if (err) { -- if (err == UBI_IO_BITFLIPS) -- err = 0; -- goto error; -+ -+ if (err < 0) -+ goto out_error; -+ if (err == 1) -+ goto out_not_moved; -+ -+ /* -+ * For some reason the LEB was not moved - it might be because -+ * the volume is being deleted. We should prevent this PEB from -+ * being selected for wear-levelling movement for some "time", -+ * so put it to the protection tree. -+ */ -+ -+ dbg_wl("cancelled moving PEB %d", e1->pnum); -+ pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS); -+ if (!pe) { -+ err = -ENOMEM; -+ goto out_error; -+ } -+ -+ protect = 1; - } - - ubi_free_vid_hdr(ubi, vid_hdr); - spin_lock(&ubi->wl_lock); -+ if (protect) -+ prot_tree_add(ubi, e1, pe, protect); - if (!ubi->move_to_put) - wl_tree_add(e2, &ubi->used); - else - put = 1; - ubi->move_from = ubi->move_to = NULL; -- ubi->move_from_put = ubi->move_to_put = 0; -- ubi->wl_scheduled = 0; -+ ubi->move_to_put = ubi->wl_scheduled = 0; - spin_unlock(&ubi->wl_lock); - - if (put) { -@@ -877,62 +889,67 @@ - */ - dbg_wl("PEB %d was put meanwhile, erase", e2->pnum); - err = schedule_erase(ubi, e2, 0); -- if (err) { -- kmem_cache_free(wl_entries_slab, e2); -- ubi_ro_mode(ubi); -- } -+ if (err) -+ goto out_error; - } - -- err = schedule_erase(ubi, e1, 0); -- if (err) { -- kmem_cache_free(wl_entries_slab, e1); -- ubi_ro_mode(ubi); -+ if (!protect) { -+ err = schedule_erase(ubi, e1, 0); -+ if (err) -+ goto out_error; - } - -+ - dbg_wl("done"); -- return err; -+ mutex_unlock(&ubi->move_mutex); -+ return 0; - - /* -- * Some error occurred. @e1 was not changed, so return it back. @e2 -- * might be changed, schedule it for erasure. -+ * For some reasons the LEB was not moved, might be an error, might be -+ * something else. @e1 was not changed, so return it back. @e2 might -+ * be changed, schedule it for erasure. - */ --error: -- if (err) -- dbg_wl("error %d occurred, cancel operation", err); -- ubi_assert(err <= 0); -- -+out_not_moved: - ubi_free_vid_hdr(ubi, vid_hdr); - spin_lock(&ubi->wl_lock); -- ubi->wl_scheduled = 0; -- if (ubi->move_from_put) -- put = 1; -+ if (scrubbing) -+ wl_tree_add(e1, &ubi->scrub); - else - wl_tree_add(e1, &ubi->used); - ubi->move_from = ubi->move_to = NULL; -- ubi->move_from_put = ubi->move_to_put = 0; -+ ubi->move_to_put = ubi->wl_scheduled = 0; - spin_unlock(&ubi->wl_lock); - -- if (put) { -- /* -- * Well, the target PEB was put meanwhile, schedule it for -- * erasure. -- */ -- dbg_wl("PEB %d was put meanwhile, erase", e1->pnum); -- err = schedule_erase(ubi, e1, 0); -- if (err) { -- kmem_cache_free(wl_entries_slab, e1); -- ubi_ro_mode(ubi); -- } -- } -- - err = schedule_erase(ubi, e2, 0); -- if (err) { -- kmem_cache_free(wl_entries_slab, e2); -- ubi_ro_mode(ubi); -- } -+ if (err) -+ goto out_error; -+ -+ mutex_unlock(&ubi->move_mutex); -+ return 0; -+ -+out_error: -+ ubi_err("error %d while moving PEB %d to PEB %d", -+ err, e1->pnum, e2->pnum); -+ -+ ubi_free_vid_hdr(ubi, vid_hdr); -+ spin_lock(&ubi->wl_lock); -+ ubi->move_from = ubi->move_to = NULL; -+ ubi->move_to_put = ubi->wl_scheduled = 0; -+ spin_unlock(&ubi->wl_lock); - -- yield(); -+ kmem_cache_free(ubi_wl_entry_slab, e1); -+ kmem_cache_free(ubi_wl_entry_slab, e2); -+ ubi_ro_mode(ubi); -+ -+ mutex_unlock(&ubi->move_mutex); - return err; -+ -+out_cancel: -+ ubi->wl_scheduled = 0; -+ spin_unlock(&ubi->wl_lock); -+ mutex_unlock(&ubi->move_mutex); -+ ubi_free_vid_hdr(ubi, vid_hdr); -+ return 0; - } - - /** -@@ -1020,7 +1037,7 @@ - if (cancel) { - dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); - kfree(wl_wrk); -- kmem_cache_free(wl_entries_slab, e); -+ kmem_cache_free(ubi_wl_entry_slab, e); - return 0; - } - -@@ -1049,7 +1066,7 @@ - - ubi_err("failed to erase PEB %d, error %d", pnum, err); - kfree(wl_wrk); -- kmem_cache_free(wl_entries_slab, e); -+ kmem_cache_free(ubi_wl_entry_slab, e); - - if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || - err == -EBUSY) { -@@ -1119,8 +1136,7 @@ - } - - /** -- * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling -- * unit. -+ * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling unit. - * @ubi: UBI device description object - * @pnum: physical eraseblock to return - * @torture: if this physical eraseblock has to be tortured -@@ -1128,7 +1144,7 @@ - * This function is called to return physical eraseblock @pnum to the pool of - * free physical eraseblocks. The @torture flag has to be set if an I/O error - * occurred to this @pnum and it has to be tested. This function returns zero -- * in case of success and a negative error code in case of failure. -+ * in case of success, and a negative error code in case of failure. - */ - int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) - { -@@ -1139,8 +1155,8 @@ - ubi_assert(pnum >= 0); - ubi_assert(pnum < ubi->peb_count); - -+retry: - spin_lock(&ubi->wl_lock); -- - e = ubi->lookuptbl[pnum]; - if (e == ubi->move_from) { - /* -@@ -1148,17 +1164,22 @@ - * be moved. It will be scheduled for erasure in the - * wear-leveling worker. - */ -- dbg_wl("PEB %d is being moved", pnum); -- ubi_assert(!ubi->move_from_put); -- ubi->move_from_put = 1; -+ dbg_wl("PEB %d is being moved, wait", pnum); - spin_unlock(&ubi->wl_lock); -- return 0; -+ -+ /* Wait for the WL worker by taking the @ubi->move_mutex */ -+ mutex_lock(&ubi->move_mutex); -+ mutex_unlock(&ubi->move_mutex); -+ goto retry; - } else if (e == ubi->move_to) { - /* - * User is putting the physical eraseblock which was selected - * as the target the data is moved to. It may happen if the EBA -- * unit already re-mapped the LEB but the WL unit did has not -- * put the PEB to the "used" tree. -+ * unit already re-mapped the LEB in 'ubi_eba_copy_leb()' but -+ * the WL unit has not put the PEB to the "used" tree yet, but -+ * it is about to do this. So we just set a flag which will -+ * tell the WL worker that the PEB is not needed anymore and -+ * should be scheduled for erasure. - */ - dbg_wl("PEB %d is the target of data moving", pnum); - ubi_assert(!ubi->move_to_put); -@@ -1172,8 +1193,15 @@ - } else if (in_wl_tree(e, &ubi->scrub)) { - paranoid_check_in_wl_tree(e, &ubi->scrub); - rb_erase(&e->rb, &ubi->scrub); -- } else -- prot_tree_del(ubi, e->pnum); -+ } else { -+ err = prot_tree_del(ubi, e->pnum); -+ if (err) { -+ ubi_err("PEB %d not found", pnum); -+ ubi_ro_mode(ubi); -+ spin_unlock(&ubi->wl_lock); -+ return err; -+ } -+ } - } - spin_unlock(&ubi->wl_lock); - -@@ -1227,8 +1255,17 @@ - if (in_wl_tree(e, &ubi->used)) { - paranoid_check_in_wl_tree(e, &ubi->used); - rb_erase(&e->rb, &ubi->used); -- } else -- prot_tree_del(ubi, pnum); -+ } else { -+ int err; -+ -+ err = prot_tree_del(ubi, e->pnum); -+ if (err) { -+ ubi_err("PEB %d not found", pnum); -+ ubi_ro_mode(ubi); -+ spin_unlock(&ubi->wl_lock); -+ return err; -+ } -+ } - - wl_tree_add(e, &ubi->scrub); - spin_unlock(&ubi->wl_lock); -@@ -1249,17 +1286,32 @@ - */ - int ubi_wl_flush(struct ubi_device *ubi) - { -- int err, pending_count; -- -- pending_count = ubi->works_count; -- -- dbg_wl("flush (%d pending works)", pending_count); -+ int err; - - /* - * Erase while the pending works queue is not empty, but not more then - * the number of currently pending works. - */ -- while (pending_count-- > 0) { -+ dbg_wl("flush (%d pending works)", ubi->works_count); -+ while (ubi->works_count) { -+ err = do_work(ubi); -+ if (err) -+ return err; -+ } -+ -+ /* -+ * Make sure all the works which have been done in parallel are -+ * finished. -+ */ -+ down_write(&ubi->work_sem); -+ up_write(&ubi->work_sem); -+ -+ /* -+ * And in case last was the WL worker and it cancelled the LEB -+ * movement, flush again. -+ */ -+ while (ubi->works_count) { -+ dbg_wl("flush more (%d pending works)", ubi->works_count); - err = do_work(ubi); - if (err) - return err; -@@ -1294,7 +1346,7 @@ - rb->rb_right = NULL; - } - -- kmem_cache_free(wl_entries_slab, e); -+ kmem_cache_free(ubi_wl_entry_slab, e); - } - } - } -@@ -1303,7 +1355,7 @@ - * ubi_thread - UBI background thread. - * @u: the UBI device description object pointer - */ --static int ubi_thread(void *u) -+int ubi_thread(void *u) - { - int failures = 0; - struct ubi_device *ubi = u; -@@ -1394,36 +1446,22 @@ - ubi->used = ubi->free = ubi->scrub = RB_ROOT; - ubi->prot.pnum = ubi->prot.aec = RB_ROOT; - spin_lock_init(&ubi->wl_lock); -+ mutex_init(&ubi->move_mutex); -+ init_rwsem(&ubi->work_sem); - ubi->max_ec = si->max_ec; - INIT_LIST_HEAD(&ubi->works); - - sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num); - -- ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); -- if (IS_ERR(ubi->bgt_thread)) { -- err = PTR_ERR(ubi->bgt_thread); -- ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, -- err); -- return err; -- } -- -- if (ubi_devices_cnt == 0) { -- wl_entries_slab = kmem_cache_create("ubi_wl_entry_slab", -- sizeof(struct ubi_wl_entry), -- 0, 0, NULL); -- if (!wl_entries_slab) -- return -ENOMEM; -- } -- - err = -ENOMEM; - ubi->lookuptbl = kzalloc(ubi->peb_count * sizeof(void *), GFP_KERNEL); - if (!ubi->lookuptbl) -- goto out_free; -+ return err; - - list_for_each_entry_safe(seb, tmp, &si->erase, u.list) { - cond_resched(); - -- e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); -+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) - goto out_free; - -@@ -1431,7 +1469,7 @@ - e->ec = seb->ec; - ubi->lookuptbl[e->pnum] = e; - if (schedule_erase(ubi, e, 0)) { -- kmem_cache_free(wl_entries_slab, e); -+ kmem_cache_free(ubi_wl_entry_slab, e); - goto out_free; - } - } -@@ -1439,7 +1477,7 @@ - list_for_each_entry(seb, &si->free, u.list) { - cond_resched(); - -- e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); -+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) - goto out_free; - -@@ -1453,7 +1491,7 @@ - list_for_each_entry(seb, &si->corr, u.list) { - cond_resched(); - -- e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); -+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) - goto out_free; - -@@ -1461,7 +1499,7 @@ - e->ec = seb->ec; - ubi->lookuptbl[e->pnum] = e; - if (schedule_erase(ubi, e, 0)) { -- kmem_cache_free(wl_entries_slab, e); -+ kmem_cache_free(ubi_wl_entry_slab, e); - goto out_free; - } - } -@@ -1470,7 +1508,7 @@ - ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { - cond_resched(); - -- e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); -+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) - goto out_free; - -@@ -1510,8 +1548,6 @@ - tree_destroy(&ubi->free); - tree_destroy(&ubi->scrub); - kfree(ubi->lookuptbl); -- if (ubi_devices_cnt == 0) -- kmem_cache_destroy(wl_entries_slab); - return err; - } - -@@ -1541,7 +1577,7 @@ - rb->rb_right = NULL; - } - -- kmem_cache_free(wl_entries_slab, pe->e); -+ kmem_cache_free(ubi_wl_entry_slab, pe->e); - kfree(pe); - } - } -@@ -1553,10 +1589,6 @@ - */ - void ubi_wl_close(struct ubi_device *ubi) - { -- dbg_wl("disable \"%s\"", ubi->bgt_name); -- if (ubi->bgt_thread) -- kthread_stop(ubi->bgt_thread); -- - dbg_wl("close the UBI wear-leveling unit"); - - cancel_pending(ubi); -@@ -1565,8 +1597,6 @@ - tree_destroy(&ubi->free); - tree_destroy(&ubi->scrub); - kfree(ubi->lookuptbl); -- if (ubi_devices_cnt == 1) -- kmem_cache_destroy(wl_entries_slab); - } - - #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID ---- linux-2.6.24.7.old/drivers/mtd/udc_cache.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/udc_cache.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,531 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define CACHE_MAX_NUM 256 -+#define SECTOR_SIZE 512 -+ -+//#define UDC_CACHE_DEBUG -+ -+#ifdef UDC_CACHE_DEBUG -+#define dprintk(a...) printk(a) -+#else -+#define dprintk(a...) while(0){} -+#endif -+ -+typedef struct { -+ unsigned short CacheState; -+ unsigned short UseCount; -+ unsigned short CacheChange; -+ unsigned short CacheReserve; -+ unsigned int BlockId; -+ unsigned char *aBlockData; -+} SSFDC__LB_CACHE; -+ -+#define FREE_CACHE 0 -+#define PREWRITE_CACHE 2 -+#define OFTEN_USE_CACHE 3 -+#define SECTOR_SHIFT 9 -+ -+#define CACHE_TO_UNCATCH(x) ((unsigned int)x | 0xa0000000) -+static unsigned int __aBlockData[SECTOR_SIZE * CACHE_MAX_NUM / 4] __attribute__ ((aligned (32))); -+static SSFDC__LB_CACHE ssfdc_cache[CACHE_MAX_NUM]; -+static unsigned short Cur_CacheCount = 0; -+int FlushDataState = 0; -+static struct mtdblk_dev *g_udc_mtdblk; -+static struct mtd_info *g_udc_mtd; -+ -+extern int udc_mtdblock_readsect(struct mtdblk_dev *, unsigned long, char *, int); -+extern int udc_mtdblock_writesect(struct mtdblk_dev *, unsigned long, char *); -+extern struct mtdblk_dev *udc_get_mtdblk(void); -+extern struct mtd_info *udc_get_mtd(void); -+extern void udc_flush_cache(struct mtdblk_dev *mtdblk); -+ -+#define _NAND_LB_Write(pCache) udc_mtdblock_writesect(g_udc_mtdblk, pCache->BlockId,pCache->aBlockData) -+#define _NAND_LB_Read(Sector,pBuffer) udc_mtdblock_readsect(g_udc_mtdblk, Sector, pBuffer, SECTOR_SIZE); -+ -+#define DMA_ENABLE 0 -+ -+#if DMA_ENABLE -+#define DMA_CHANNEL 5 -+#define PHYSADDR(x) virt_to_phys((void *)x) -+#else -+#define lb_memcpy memcpy -+#endif -+ -+#if DMA_ENABLE -+static void lb_memcpy(void *target,void* source,unsigned int len) -+{ -+ int ch = DMA_CHANNEL; -+ if(((unsigned int)source < 0xa0000000) && len) -+ dma_cache_wback_inv((unsigned long)source, len); -+ if(((unsigned int)target < 0xa0000000) && len) -+ dma_cache_wback_inv((unsigned long)target, len); -+ -+ REG_DMAC_DSAR(ch) = PHYSADDR((unsigned long)source); -+ REG_DMAC_DTAR(ch) = PHYSADDR((unsigned long)target); -+ REG_DMAC_DTCR(ch) = len / 32; -+ REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AUTO; -+ REG_DMAC_DCMD(ch) = DMAC_DCMD_SAI| DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32|DMAC_DCMD_DS_32BYTE; -+ REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; -+ while ( REG_DMAC_DTCR(ch) ); -+} -+#endif -+ -+static void _NAND_LB_InitCache(void) -+{ -+ int i; -+ SSFDC__LB_CACHE *pCache = ssfdc_cache; -+#if DMA_ENABLE -+ unsigned char * ptr = (unsigned char *)CACHE_TO_UNCATCH(__aBlockData); -+#else -+ unsigned char * ptr = (unsigned char *)(__aBlockData); -+#endif -+ for(i = 0;i < CACHE_MAX_NUM;i++) -+ { -+ pCache->CacheState = FREE_CACHE; -+ pCache->UseCount = 0; -+ pCache->CacheChange = 0; -+ pCache->aBlockData = ptr; -+ ptr+=SECTOR_SIZE; -+ pCache++; -+ } -+ Cur_CacheCount = 0; -+} -+ -+static SSFDC__LB_CACHE * _NAND_LB_GetFreeCache(void) -+{ -+ int ret = 0; -+ SSFDC__LB_CACHE *pCacheInfo = &ssfdc_cache[Cur_CacheCount]; -+ while(1) -+ { -+ if(ret >= CACHE_MAX_NUM) -+ return 0; -+ if(pCacheInfo >= &ssfdc_cache[CACHE_MAX_NUM]) -+ { -+ pCacheInfo = ssfdc_cache; -+ Cur_CacheCount = 0; -+ } -+ -+ if(pCacheInfo->CacheState == FREE_CACHE) -+ { -+ return pCacheInfo; -+ } -+ pCacheInfo++; -+ Cur_CacheCount++; -+ ret++; -+ } -+ return 0; -+} -+ -+static void _NAND_LB_CloseCACHES(unsigned int sectorstart,unsigned int sectorend) -+{ -+ unsigned int i; -+ SSFDC__LB_CACHE *pCache = ssfdc_cache; -+ for( i = 0;i < CACHE_MAX_NUM;i++){ -+ if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){ -+ pCache->CacheChange = 0; -+ pCache->CacheState = FREE_CACHE; -+ pCache->UseCount = 0; -+ } -+ pCache++; -+ } -+} -+ -+static void _NAND_LB_FLUSHCACHES(unsigned int sectorstart,unsigned int sectorend) -+{ -+ unsigned int i; -+ SSFDC__LB_CACHE *pCache = ssfdc_cache; -+ for( i = 0;i < CACHE_MAX_NUM;i++){ -+ if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){ -+ if(pCache->CacheChange) -+ _NAND_LB_Write(pCache); -+ pCache->CacheChange = 0; -+ pCache->CacheState = FREE_CACHE; -+ pCache->UseCount = 0; -+ } -+ pCache++; -+ -+ } -+} -+ -+inline static int Get_NAND_CacheFreeCount(void) -+{ -+ SSFDC__LB_CACHE *pCache = ssfdc_cache; -+ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; -+ unsigned int count = 0; -+ while(pCache < pEndCache) -+ { -+ if(pCache->CacheState == FREE_CACHE) -+ count++; -+ pCache++; -+ } -+ return count; -+ -+} -+ -+static unsigned int _NAND_LB_PreWiteToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update) -+{ -+ SSFDC__LB_CACHE *pWriteCache; -+ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; -+ unsigned int sector = -1; -+ unsigned int flag; -+ while(1) -+ { -+ sector = -1; -+ flag = 0; -+ pWriteCache = ssfdc_cache; -+ while(pWriteCache < pEndCache) -+ { -+ if(pWriteCache->CacheState == update) //PREWRITE_CACHE -+ { -+ if(pWriteCache->BlockId < sector) -+ { -+ sector = pWriteCache->BlockId; -+ pCache = pWriteCache; -+ } -+ }else -+ flag++; -+ pWriteCache++; -+ } -+ -+ if(flag < CACHE_MAX_NUM) -+ { -+ if(pCache->CacheChange) -+ { -+ _NAND_LB_Write(pCache); -+ pCache->CacheChange = 0; -+ } -+ pCache->CacheState = FREE_CACHE; -+ pCache->UseCount = 0; -+ (*count)++; -+ }else -+ break; -+ } -+ return 0; -+} -+ -+static void _NAND_LB_OftenToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update) -+{ -+ SSFDC__LB_CACHE *pWriteCache = pCache; -+ SSFDC__LB_CACHE *pOldCache = pCache; -+ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; -+ -+ dprintk("%s!\n",__FUNCTION__); -+ while(pCache) -+ { -+ if(pCache->CacheState == OFTEN_USE_CACHE) -+ { -+ if(pWriteCache->CacheState != OFTEN_USE_CACHE) -+ pWriteCache = pCache; -+ else if(pWriteCache->UseCount > pCache->UseCount) -+ { -+ pWriteCache = pCache; -+ } -+ } -+ pCache++; -+ if(pCache >= pEndCache) -+ break; -+ } -+ if(pWriteCache->CacheState == OFTEN_USE_CACHE) -+ { -+ (*count)++; -+ if(pWriteCache->CacheChange) -+ _NAND_LB_Write(pWriteCache); -+ pWriteCache->CacheState = FREE_CACHE; -+ -+ pWriteCache->UseCount = 0; -+ pWriteCache->CacheChange = 0; -+ if(update != -1) -+ update--; -+ if(update != 0) -+ _NAND_LB_OftenToNand(pOldCache,count,update); -+ } -+} -+ -+static int _NAND_LB_FreeCache(unsigned int update) -+{ -+ unsigned short freecount = 0,totalfree = 0; -+ -+ freecount = 0; -+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE); -+ -+ totalfree += freecount; -+ dprintk("free count = %d\n",freecount); -+ if(freecount == 0) -+ { -+ freecount = 0; -+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); -+ totalfree += freecount; -+ update = 0; -+ } -+ if(update) -+ { -+ if(Get_NAND_CacheFreeCount() < CACHE_MAX_NUM * 1 / 4) // because fat is 4 sector -+ { -+ freecount = 0; -+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); -+ totalfree += freecount; -+ } -+ } -+ -+ dprintk("Free = %d\r\n",totalfree); -+ return totalfree; -+} -+ -+static int _NAND_LB_GetFromCache(unsigned int Sector, void *pBuffer) { -+ -+ SSFDC__LB_CACHE *pCache = &ssfdc_cache[Cur_CacheCount]; -+ SSFDC__LB_CACHE *pUseCache = 0; -+ unsigned short i; -+ dprintk("sector = %x pBuffer = %x\n",Sector,pBuffer); -+ if(pCache >= &ssfdc_cache[CACHE_MAX_NUM]) -+ pCache = ssfdc_cache; -+ -+ i = 0; -+ while (1) { -+ if(pCache->CacheState != FREE_CACHE) -+ { -+ if (Sector == pCache->BlockId) { -+ dprintk("Cache is use = %d\r\n",pCache->BlockId); -+ pUseCache = pCache; -+ pCache->UseCount++; -+ if(pCache->UseCount == 0) -+ pCache->UseCount = -1; -+ pCache->CacheState = OFTEN_USE_CACHE; -+ } -+ } -+ pCache--; -+ if(pCache < ssfdc_cache) -+ pCache = &ssfdc_cache[CACHE_MAX_NUM - 1]; -+ -+ i++; -+ if (i >= CACHE_MAX_NUM) { -+ break; /* Sector not in cache */ -+ } -+ } -+ if (pUseCache) { -+ dprintk("From Cache %d\r\n",Sector); -+ lb_memcpy(pBuffer, pUseCache->aBlockData, SECTOR_SIZE); -+ return 0; -+ } -+ return -1; -+} -+ -+static void _NAND_LB_ClearCache(void) { -+ -+ unsigned short freecount = 0; -+ dprintk("Clear Cache\r\n"); -+ -+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE); -+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); -+} -+ -+static void _NAND_LB_CopyToCache(unsigned int Sector, void *pBuffer,unsigned short rw) -+{ -+ SSFDC__LB_CACHE *pCache = _NAND_LB_GetFreeCache(); -+ dprintk("Copy to Cache = 0x%08x 0x%08x\r\n",pCache,ssfdc_cache); -+ -+ if(!pCache) -+ { -+ _NAND_LB_FreeCache(rw); -+ -+ pCache = _NAND_LB_GetFreeCache(); -+ } -+ pCache->BlockId = Sector; -+ pCache->CacheState = PREWRITE_CACHE; -+ pCache->UseCount = 0; -+ pCache->CacheChange = rw; -+ -+ lb_memcpy(pCache->aBlockData,pBuffer,SECTOR_SIZE); -+} -+ -+ -+static int _NAND_LB_UpdateInCache(unsigned int Sector, void *pBuffer) { -+ short i,ret = 0; -+ i = Cur_CacheCount; -+ if(Cur_CacheCount > CACHE_MAX_NUM) -+ i = 0; -+ while(1) -+ { -+ if(ret >= CACHE_MAX_NUM) -+ return -1; -+ if(ssfdc_cache[i].CacheState != FREE_CACHE) -+ { -+ -+ if(ssfdc_cache[i].BlockId == Sector) -+ { -+ dprintk("UpdateInCache = %d\r\n",Sector); -+ ssfdc_cache[i].CacheState = OFTEN_USE_CACHE; -+ ssfdc_cache[i].UseCount++; -+ ssfdc_cache[i].CacheChange = 1; -+ lb_memcpy(ssfdc_cache[i].aBlockData,pBuffer,SECTOR_SIZE); -+ return 0; -+ } -+ } -+ i--; -+ if(i < 0) -+ i = CACHE_MAX_NUM - 1; -+ ret++; -+ } -+ return -1; -+} -+ -+static int NAND_LB_MultiRead(unsigned int Sector, void *pBuffer,unsigned int SectorCount) -+{ -+ int i,ret,end; -+ void *p; -+ -+ dprintk("NAND_LB_MultiRead = %d %d \n",Sector,SectorCount); -+ end = Sector + SectorCount; -+ _NAND_LB_FLUSHCACHES(Sector,end); -+ -+ p = pBuffer; -+ for (i = Sector; i < end; i ++) -+ { -+ ret = udc_mtdblock_readsect(g_udc_mtdblk, i, p, SECTOR_SIZE); -+ p += SECTOR_SIZE; -+ } -+ return ret; -+} -+ -+static int NAND_LB_Read(unsigned int Sector, void *pBuffer) -+{ -+ int x; -+#if DMA_ENABLE -+ unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer); -+ dma_cache_wback_inv(pBuffer,SECTOR_SIZE); -+#else -+ unsigned char *ptr = (unsigned char *)pBuffer; -+#endif -+ dprintk("LB_Read = %d \n",Sector); -+ if(_NAND_LB_GetFromCache(Sector,ptr)) -+ { -+ x = _NAND_LB_Read(Sector,ptr); -+ _NAND_LB_CopyToCache(Sector,ptr,0); -+ } -+ return 512; -+} -+ -+static int NAND_LB_MultiWrite(unsigned int Sector, void *pBuffer,unsigned int SectorCount) -+{ -+ int i,ret; -+ unsigned char *p; -+ -+ _NAND_LB_CloseCACHES(Sector,Sector + SectorCount); -+ p = (unsigned char *)pBuffer; -+ for (i = Sector; i < Sector + SectorCount; i ++) -+ { -+ ret = udc_mtdblock_writesect(g_udc_mtdblk, i, p); -+ p += 512; -+ } -+ return ret; -+} -+ -+static int NAND_LB_Write(unsigned int Sector, void *pBuffer) -+{ -+#if DMA_ENABLE -+ unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer); -+ dma_cache_wback_inv(pBuffer,SECTOR_SIZE); -+#else -+ unsigned char *ptr = (unsigned char *)pBuffer; -+#endif -+ dprintk("LB_Write = %x %x\r\n",Sector,pBuffer); -+ if(_NAND_LB_UpdateInCache(Sector,ptr)) -+ { -+ _NAND_LB_CopyToCache(Sector,ptr,1); -+ } -+ return 512; -+} -+/********************************************************************* -+* -+* Global functions -+* -+***********************************************************************/ -+ -+int NAND_LB_Init(void) -+{ -+ dprintk("UDC CACHE Init \n"); -+ _NAND_LB_InitCache(); -+ g_udc_mtdblk = udc_get_mtdblk(); -+ g_udc_mtd = udc_get_mtd(); -+ return 0; -+} -+ -+int NAND_LB_FLASHCACHE(void) -+{ -+ dprintk("Flush lb cache !\n"); -+ _NAND_LB_ClearCache(); -+// dprintk("Flush mtd cache !\n"); -+// udc_flush_cache(g_udc_mtdblk); -+ return 0; -+} -+ -+int NAND_MTD_FLASHCACHE(void) -+{ -+ dprintk("Flush mtd cache !\n"); -+ udc_flush_cache(g_udc_mtdblk); -+ return 0; -+} -+ -+int udc_read(unsigned int offset, unsigned int len, unsigned char *buf) -+{ -+ unsigned long block,sector,i; -+ -+ block = offset >> SECTOR_SHIFT; -+ sector = len >> SECTOR_SHIFT; -+ dprintk("read dev = ia:%x, s:%d c:%d\r\n",buf,block,sector); -+ -+ if (sector <= 8) -+ { -+ for(i = 0;i < sector; i++) -+ { -+ NAND_LB_Read(block + i,(void *)(buf)); -+ buf += 512; -+ } -+ } -+ else -+ NAND_LB_MultiRead(block, buf, sector); -+ -+ return len; -+} -+ -+int udc_write(unsigned int offset, unsigned int len, unsigned char *buf) -+{ -+ unsigned long block,sector,i; -+ -+ block = offset >> SECTOR_SHIFT; -+ sector = len >> SECTOR_SHIFT; -+ dprintk("write dev s:%d c:%d\r\n",block,sector); -+ -+ if(sector <= 8) -+ { -+ for(i = 0;i < sector; i++) -+ { -+ NAND_LB_Write(block + i,(void *)(buf)); -+ buf += 512; -+ FlushDataState = 1; -+ } -+ }else -+ NAND_LB_MultiWrite(block,(void *)(buf),sector); -+ -+ return len; -+} -+ -+EXPORT_SYMBOL_GPL(udc_write); -+EXPORT_SYMBOL_GPL(udc_read); -+EXPORT_SYMBOL_GPL(NAND_LB_Init); -+EXPORT_SYMBOL_GPL(NAND_LB_FLASHCACHE); -+EXPORT_SYMBOL_GPL(FlushDataState); -+EXPORT_SYMBOL_GPL(NAND_MTD_FLASHCACHE); ++EXPORT_SYMBOL_GPL(udc_write); ++EXPORT_SYMBOL_GPL(udc_read); ++EXPORT_SYMBOL_GPL(NAND_LB_Init); ++EXPORT_SYMBOL_GPL(NAND_LB_FLASHCACHE); ++EXPORT_SYMBOL_GPL(FlushDataState); ++EXPORT_SYMBOL_GPL(NAND_MTD_FLASHCACHE); --- linux-2.6.24.7.old/drivers/net/Kconfig 2009-04-12 18:05:07.000000000 +0200 +++ linux-2.6.24.7/drivers/net/Kconfig 2009-04-12 18:13:57.000000000 +0200 @@ -333,6 +333,24 @@ or internal device. It is safe to say Y or M here even if your ethernet card lack MII. - + +config JZ_ETH + tristate "JZ4730/JZ5730 On-Chip Ethernet support" + depends on NET_ETHERNET && (SOC_JZ4730 || SOC_JZ5730 || JZ_FPGA) @@ -83496,12 +19528,12 @@ + help + This is a driver for SMSC's LAN911x series of Ethernet chipsets + including the new LAN9115, LAN9116, LAN9117, and LAN9118. -+ Say Y if you want it compiled into the kernel, ++ Say Y if you want it compiled into the kernel, + and read the Ethernet-HOWTO, available from + . + -+ This driver is also available as a module. The module will be -+ called smc911x. If you want to compile it as a module, say M ++ This driver is also available as a module. The module will be ++ called smc911x. If you want to compile it as a module, say M + here and read + +config NET_VENDOR_RACAL @@ -83996,9 +20028,9 @@ + select MII + ---help--- + This driver supports Intel(R) PRO/100 family of adapters. -+ To verify that your adapter is supported, find the board ID number -+ on the adapter. Look for a label that has a barcode and a number -+ in the format 123456-001 (six digits hyphen three digits). ++ To verify that your adapter is supported, find the board ID number ++ on the adapter. Look for a label that has a barcode and a number ++ in the format 123456-001 (six digits hyphen three digits). + + Use the above information and the Adapter & Driver ID Guide at: + @@ -84010,7 +20042,7 @@ + + + -+ More specific information on configuring the driver is in ++ More specific information on configuring the driver is in + . + + To compile this driver as a module, choose M here. The module @@ -84497,7 +20529,7 @@ + depends on PCI + ---help--- + This driver supports Intel(R) PRO/1000 gigabit ethernet family of -+ adapters. For more information on how to identify your adapter, go ++ adapters. For more information on how to identify your adapter, go + to the Adapter & Driver ID Guide at: + + @@ -84507,7 +20539,7 @@ + + + -+ More specific information on configuring the driver is in ++ More specific information on configuring the driver is in + . + + To compile this driver as a module, choose M here. The module @@ -84642,7 +20674,7 @@ + ---help--- + Say Y here for the r8169 driver to support the functions required + by the kernel 802.1Q code. -+ ++ + If in doubt, say Y. + +config SB1250_MAC @@ -84681,7 +20713,7 @@ + and related Gigabit Ethernet adapters. It is a new smaller driver + with better performance and more complete ethtool support. + -+ It does not support the link failover and network management ++ It does not support the link failover and network management + features that "portable" vendor supplied sk98lin driver does. + + This driver supports adapters based on the original Yukon chipset: @@ -84802,16 +20834,16 @@ + - SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter + - SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link) + - SMC EZ Card 1000 (SMC9452TXV.2) -+ ++ + The adapters support Jumbo Frames. + The dual link adapters support link-failover and dual port features. -+ Both Marvell Yukon and SysKonnect SK-98xx/SK-95xx adapters support -+ the scatter-gather functionality with sendfile(). Please refer to ++ Both Marvell Yukon and SysKonnect SK-98xx/SK-95xx adapters support ++ the scatter-gather functionality with sendfile(). Please refer to + for more information about + optional driver parameters. + Questions concerning this driver may be addressed to: + -+ ++ + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module will @@ -85060,7 +21092,7 @@ + + + -+ More specific information on configuring the driver is in ++ More specific information on configuring the driver is in + . + + To compile this driver as a module, choose M here. The module @@ -85084,8 +21116,8 @@ + tristate "S2IO 10Gbe XFrame NIC" + depends on PCI + ---help--- -+ This driver supports the 10Gbe XFrame NIC of S2IO. -+ More specific information on configuring the driver is in ++ This driver supports the 10Gbe XFrame NIC of S2IO. ++ More specific information on configuring the driver is in + . + +config S2IO_NAPI @@ -85479,9 +21511,9 @@ + Support for PPP over Ethernet. + + This driver requires the latest version of pppd from the CVS -+ repository at cvs.samba.org. Alternatively, see the ++ repository at cvs.samba.org. Alternatively, see the + RoaringPenguin package () -+ which contains instruction on how to use this driver (under ++ which contains instruction on how to use this driver (under + the heading "Kernel mode PPPoE"). + +config PPPOATM @@ -85648,7 +21680,7 @@ @@ -84,6 +84,8 @@ obj-$(CONFIG_MII) += mii.o obj-$(CONFIG_PHYLIB) += phy/ - + +obj-$(CONFIG_JZ_ETH) += jz_eth.o +obj-$(CONFIG_JZCS8900) += jzcs8900a.o obj-$(CONFIG_SUNDANCE) += sundance.o @@ -85729,7 +21761,7 @@ + */ +static irqreturn_t jz_eth_interrupt(int irq, void *dev_id); + -+static int link_check_thread (void *data); ++static int link_check_thread (void *data); + +/* + * Get MAC address @@ -85791,7 +21823,7 @@ + int i; + unsigned char flag0=0; + unsigned char flag1=0xff; -+ ++ + dev->dev_addr[0] = 0xff; + if (hwaddr != NULL) { + /* insmod jz-ethc.o hwaddr=00:ef:a3:c1:00:10 */ @@ -85858,7 +21890,7 @@ + np->thread_die = 0; + init_waitqueue_head(&np->thr_wait); + init_completion (&np->thr_exited); -+ np->thr_pid = kernel_thread (link_check_thread,(void *)dev, ++ np->thr_pid = kernel_thread (link_check_thread,(void *)dev, + CLONE_FS | CLONE_FILES); + if (np->thr_pid < 0) + errprintk("%s: unable to start kernel thread\n",dev->name); @@ -85915,7 +21947,7 @@ + + if (np->thread_die) + break; -+ ++ + current_link=mii_link_ok(&mii_info); + if (np->link_state!=current_link) { + if (current_link) { @@ -85931,7 +21963,7 @@ + np->link_state=current_link; + + } -+ complete_and_exit (&np->thr_exited, 0); ++ complete_and_exit (&np->thr_exited, 0); +} + +#ifdef DEBUG @@ -85939,60 +21971,60 @@ + * Display ethernet packet header + * This routine is used for test function + */ -+static void eth_dbg_rx(struct sk_buff *skb, int len) ++static void eth_dbg_rx(struct sk_buff *skb, int len) +{ + -+ int i, j; -+ ++ int i, j; ++ + printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n", -+ (u8)skb->data[0], -+ (u8)skb->data[1], ++ (u8)skb->data[0], ++ (u8)skb->data[1], + (u8)skb->data[2], -+ (u8)skb->data[3], -+ (u8)skb->data[4], -+ (u8)skb->data[5], -+ (u8)skb->data[6], -+ (u8)skb->data[7], -+ (u8)skb->data[8], ++ (u8)skb->data[3], ++ (u8)skb->data[4], ++ (u8)skb->data[5], ++ (u8)skb->data[6], ++ (u8)skb->data[7], ++ (u8)skb->data[8], + (u8)skb->data[9], -+ (u8)skb->data[10], -+ (u8)skb->data[11], -+ (u8)skb->data[12], -+ (u8)skb->data[13], -+ len); -+ for (j=0; len>0; j+=16, len-=16) { -+ printk(" %03x: ",j); -+ for (i=0; i<16 && idata[i+j]); -+ } -+ printk("\n"); -+ } -+ return; -+ } -+#endif ++ (u8)skb->data[10], ++ (u8)skb->data[11], ++ (u8)skb->data[12], ++ (u8)skb->data[13], ++ len); ++ for (j=0; len>0; j+=16, len-=16) { ++ printk(" %03x: ",j); ++ for (i=0; i<16 && idata[i+j]); ++ } ++ printk("\n"); ++ } ++ return; ++ } ++#endif + +/* + * Reset ethernet device + */ +static inline void jz_eth_reset(void) -+{ -+ u32 i; ++{ ++ u32 i; + i = readl(DMA_BMR); -+ writel(i | BMR_SWR, DMA_BMR); -+ for(i = 0; i < 1000; i++) { -+ if(!(readl(DMA_BMR) & BMR_SWR)) break; -+ mdelay(1); -+ } ++ writel(i | BMR_SWR, DMA_BMR); ++ for(i = 0; i < 1000; i++) { ++ if(!(readl(DMA_BMR) & BMR_SWR)) break; ++ mdelay(1); ++ } +} + +/* -+ * MII operation routines ++ * MII operation routines + */ +static inline void mii_wait(void) +{ + int i; + for(i = 0; i < 10000; i++) { -+ if(!(readl(MAC_MIIA) & 0x1)) ++ if(!(readl(MAC_MIIA) & 0x1)) + break; + mdelay(1); + } @@ -86004,19 +22036,19 @@ +{ + u32 mii_cmd = (phy_id << 11) | (location << 6) | 1; + int retval = 0; -+ ++ + writel(mii_cmd, MAC_MIIA); + mii_wait(); + retval = readl(MAC_MIID) & 0x0000ffff; -+ ++ + return retval; -+ ++ +} + +static void mdio_write(struct net_device *dev,int phy_id, int location, int data) +{ + u32 mii_cmd = (phy_id << 11) | (location << 6) | 0x2 | 1; -+ ++ + writel(mii_cmd, MAC_MIIA); + writel(data & 0x0000ffff, MAC_MIID); + mii_wait(); @@ -86028,7 +22060,7 @@ + */ +static int jz_search_mii_phy(struct net_device *dev) +{ -+ ++ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + int phy, phy_idx = 0; + @@ -86058,7 +22090,7 @@ + phy = np->valid_phy; + np->advertising = mdio_read(dev,phy, 4); + } -+ return phy_idx; ++ return phy_idx; +} + +/* @@ -86107,10 +22139,10 @@ +{ + int i, hash_index; + u32 mcr, hash_h, hash_l, hash_bit; -+ ++ + mcr = readl(MAC_MCR); + mcr &= ~(MCR_PR | MCR_PM | MCR_HP); -+ ++ + if (dev->flags & IFF_PROMISC) { + /* Accept any kinds of packets */ + mcr |= MCR_PR; @@ -86137,7 +22169,7 @@ + hash_index = jz_hashtable_index(mclist->dmi_addr); + hash_bit=0x00000001; + hash_bit <<= (hash_index & 0x1f); -+ if (hash_index > 0x1f) ++ if (hash_index > 0x1f) + hash_h |= hash_bit; + else + hash_l |= hash_bit; @@ -86167,16 +22199,16 @@ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + unsigned int mii_reg0; + unsigned int count; -+ ++ + mii_reg0 = mdio_read(dev,np->valid_phy,MII_BMCR); -+ mii_reg0 |=MII_CR_RST; ++ mii_reg0 |=MII_CR_RST; + mdio_write(dev,np->valid_phy,MII_BMCR,mii_reg0); //reset phy + for ( count = 0; count < 1000; count++) { + mdelay(1); + mii_reg0 = mdio_read(dev,np->valid_phy,MII_BMCR); + if (!(mii_reg0 & MII_CR_RST)) break; //reset completed + } -+ if (count>=100) ++ if (count>=100) + return 1; //phy error + else + return 0; @@ -86186,33 +22218,33 @@ + * Show all mii registers - this routine is used for test + */ +#ifdef DEBUG -+static void mii_db_out(struct net_device *dev) ++static void mii_db_out(struct net_device *dev) +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + unsigned int mii_test; + + mii_test = mdio_read(dev,np->valid_phy,MII_BMCR); + DBPRINTK("BMCR ====> 0x%4.4x \n",mii_test); -+ ++ + mii_test = mdio_read(dev,np->valid_phy,MII_BMSR); + DBPRINTK("BMSR ====> 0x%4.4x \n",mii_test); -+ ++ + mii_test = mdio_read(dev,np->valid_phy,MII_ANAR); + DBPRINTK("ANAR ====> 0x%4.4x \n",mii_test); -+ ++ + mii_test = mdio_read(dev,np->valid_phy,MII_ANLPAR); + DBPRINTK("ANLPAR ====> 0x%4.4x \n",mii_test); -+ ++ + mii_test = mdio_read(dev,np->valid_phy,16); + DBPRINTK("REG16 ====> 0x%4.4x \n",mii_test); -+ ++ + mii_test = mdio_read(dev,np->valid_phy,17); + DBPRINTK("REG17 ====> 0x%4.4x \n",mii_test); +} +#endif + +/* -+ * Start Auto-Negotiation function for PHY ++ * Start Auto-Negotiation function for PHY + */ +static int jz_autonet_complete(struct net_device *dev) +{ @@ -86226,11 +22258,11 @@ + if (mii_reg1 & 0x0020) break; + } + //mii_db_out(dev); //for debug to display all register of MII -+ if (count >= timeout) ++ if (count >= timeout) + return 1; //auto negotiation error + else + return 0; -+} ++} + +/* + * Get current mode of eth phy @@ -86241,7 +22273,7 @@ + unsigned int mii_reg17; + u32 flag = 0; + -+ mii_reg17 = mdio_read(dev,np->valid_phy,MII_DSCSR); ++ mii_reg17 = mdio_read(dev,np->valid_phy,MII_DSCSR); + np->media = mii_reg17>>12; + if (np->media==8) { + infoprintk("%s: Current Operation Mode is [100M Full Duplex]",dev->name); @@ -86285,7 +22317,7 @@ + /* mii operation */ + if (jz_phy_reset(dev)) { + errprintk("PHY device do not reset!\n"); -+ return -EPERM; // return operation not permitted ++ return -EPERM; // return operation not permitted + } +#endif + /* Set MAC address */ @@ -86311,17 +22343,17 @@ + ecmd.transceiver = XCVR_INTERNAL; + ecmd.phy_address = np->valid_phy; + ecmd.autoneg = AUTONEG_ENABLE; -+ ++ + mii_ethtool_sset(&mii_info,&ecmd); -+ if (jz_autonet_complete(dev)) ++ if (jz_autonet_complete(dev)) + errprintk("%s: Ethernet Module AutoNegotiation failed\n",dev->name); + mii_ethtool_gset(&mii_info,&ecmd); -+ ++ + infoprintk("%s: Provide Modes: ",dev->name); -+ for (i = 0; i < 5;i++) ++ for (i = 0; i < 5;i++) + if (ecmd.advertising & (1<full_duplex) + mcr |= MCR_FDX; + mcr |= MCR_BFD | MCR_TE | MCR_RE | MCR_OWD|MCR_HBD; @@ -86422,10 +22454,10 @@ +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + int tmp; -+ ++ + tmp = readl(DMA_MFC); // After read clear to zero + np->stats.rx_missed_errors += (tmp & MFC_CNT2) + ((tmp & MFC_CNT1) >> 16); -+ ++ + return &np->stats; +} + @@ -86542,7 +22574,7 @@ + return -EPERM; + mdio_write(dev,np->valid_phy, data->reg_num & 0x1f, data->val_in); + return 0; -+ case READ_COMMAND: ++ case READ_COMMAND: + data = (struct mii_ioctl_data *)rq->ifr_data; + if (copy_from_user(&rdata,data,sizeof(rdata))) + return -EFAULT; @@ -86634,7 +22666,7 @@ +} + +/* -+ * Tx timeout routine ++ * Tx timeout routine + */ +static void jz_eth_tx_timeout(struct net_device *dev) +{ @@ -86691,7 +22723,7 @@ +{ + struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; + int entry = np->tx_head % NUM_TX_DESCS; -+ ++ + np->tx_ring[entry].buf1_addr = cpu_to_le32(virt_to_bus(buf)); + np->tx_ring[entry].desc1 &= cpu_to_le32((TD_TER | TD_TCH)); + np->tx_ring[entry].desc1 |= cpu_to_le32(flags); @@ -86758,7 +22790,7 @@ + if (sts & (DMA_INT_RI | DMA_INT_RU)) /* Rx IRQ */ + eth_rxready(dev); + if (sts & (DMA_INT_TI | DMA_INT_TU)) /* Tx IRQ */ -+ eth_txdone(dev); ++ eth_txdone(dev); + + /* check error conditions */ + if (sts & DMA_INT_FB){ /* fatal bus error */ @@ -86781,7 +22813,7 @@ + } + writel(omr | OMR_ST | OMR_SR, DMA_OMR); + } -+ } ++ } + } + + writel(readl(DMA_IMR) | IMR_ENABLE, DMA_IMR); /* enable interrupt */ @@ -86887,7 +22919,7 @@ + dev->priv = np; + memset(np, 0, sizeof(struct jz_eth_private)); + -+ np->vaddr_rx_buf = (u32)dma_alloc_noncoherent(NULL, NUM_RX_DESCS*RX_BUF_SIZE, ++ np->vaddr_rx_buf = (u32)dma_alloc_noncoherent(NULL, NUM_RX_DESCS*RX_BUF_SIZE, + &np->dma_rx_buf, 0); + + if (!np->vaddr_rx_buf) { @@ -86943,7 +22975,7 @@ + dma_free_noncoherent(NULL, NUM_RX_DESCS * RX_BUF_SIZE, + (void *)np->vaddr_rx_buf, np->dma_rx_buf); + free_netdev(dev); -+} ++} + +module_init(jz_eth_init); +module_exit(jz_eth_exit); @@ -87109,9 +23141,9 @@ +#define DMA_INT_RS 0x00000100 // Receive stop +#define DMA_INT_RU 0x00000080 // Receive buffer unavailble +#define DMA_INT_RI 0x00000040 // Receive interrupt -+#define DMA_INT_UN 0x00000020 // Underflow ++#define DMA_INT_UN 0x00000020 // Underflow +#define DMA_INT_TJ 0x00000008 // Transmit jabber timeout -+#define DMA_INT_TU 0x00000004 // Transmit buffer unavailble ++#define DMA_INT_TU 0x00000004 // Transmit buffer unavailble +#define DMA_INT_TS 0x00000002 // Transmit stop +#define DMA_INT_TI 0x00000001 // Transmit interrupt + @@ -87280,7 +23312,7 @@ +/* + * MII Management DAVICOM Specified Configuration And Status Register + */ -+#define MII_DSCSR_100FDX 0x8000 /* 100M Full Duplex Operation Mode */ ++#define MII_DSCSR_100FDX 0x8000 /* 100M Full Duplex Operation Mode */ +#define MII_DSCSR_100HDX 0x4000 /* 100M Half Duplex Operation Mode */ +#define MII_DSCSR_10FDX 0x2000 /* 10M Full Duplex Operation Mode */ +#define MII_DSCSR_10HDX 0x1000 /* 10M Half Duplex Operation Mode */ @@ -87306,7 +23338,7 @@ +#define NUM_TX_DESCS 16 + +static const char *media_types[] = { -+ "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", ++ "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", + "100baseTx-FD", "100baseT4", 0 +}; + @@ -87315,14 +23347,14 @@ + unsigned int desc1; + unsigned int buf1_addr; + unsigned int next_addr; -+} jz_desc_t; ++} jz_desc_t; + +struct jz_eth_private { + jz_desc_t tx_ring[NUM_TX_DESCS]; /* transmit descriptors */ + jz_desc_t rx_ring[NUM_RX_DESCS]; /* receive descriptors */ + dma_addr_t dma_tx_ring; /* bus address of tx ring */ + dma_addr_t dma_rx_ring; /* bus address of rx ring */ -+ dma_addr_t dma_rx_buf; /* DMA address of rx buffer */ ++ dma_addr_t dma_rx_buf; /* DMA address of rx buffer */ + unsigned int vaddr_rx_buf; /* virtual address of rx buffer */ + + unsigned int rx_head; /* first rx descriptor */ @@ -87360,7 +23392,7 @@ +/* + * linux/drivers/net/jzcs8900a.c + * -+ * Author: Lucifer ++ * Author: Lucifer + * + * A Cirrus Logic CS8900A driver for Linux + * based on the cs89x0 driver written by Russell Nelson, @@ -87413,7 +23445,7 @@ + +#include "jzcs8900a.h" + -+#define FULL_DUPLEX ++#define FULL_DUPLEX +#define INT_PIN 0 +#ifdef CONFIG_SOC_JZ4740 +#define CIRRUS_DEFAULT_IO 0xa8000000 @@ -87442,20 +23474,20 @@ + +/* + * I/O routines -+ */ ++ */ +static void gpio_init_cs8900(void) +{ +#ifdef CONFIG_SOC_JZ4740 -+ __gpio_as_func0(60); //CS4# ++ __gpio_as_func0(60); //CS4# + __gpio_as_func0(61); //RD# -+ __gpio_as_func0(62); //WR# ++ __gpio_as_func0(62); //WR# + __gpio_as_irq_high_level(59); //irq + __gpio_disable_pull(59); //disable pull + REG_EMC_SMCR4 |= (1 << 6); //16bit +#elif CONFIG_SOC_JZ4750 + __gpio_as_func0(32*2+23); //CS3# -+ __gpio_as_func0(32*2+25); //RD# -+ __gpio_as_func0(32*2+26); //WR# ++ __gpio_as_func0(32*2+25); //RD# ++ __gpio_as_func0(32*2+26); //WR# + +#ifdef CONFIG_JZ4750_FUWA + __gpio_as_irq_high_level(32*4+20); //irq @@ -87921,8 +23953,8 @@ + printk(KERN_ERR " Cannot register net device\n"); + free_netdev(dev); + return -ENOMEM; -+ } -+ ++ } ++ + return (0); +} + @@ -88014,7 +24046,7 @@ +/* + * linux/drivers/net/jzcs8900a.h + * -+ * Author: Lucifer ++ * Author: Lucifer + * + * A Cirrus Logic CS8900A driver for Linux + * based on the cs89x0 driver written by Russell Nelson, @@ -88259,7 +24291,7 @@ @@ -74,6 +74,8 @@ return device_register(&protocol->dev); } - + +EXPORT_SYMBOL(pnp_register_protocol); + /** @@ -88268,7 +24300,7 @@ @@ -86,6 +88,8 @@ device_unregister(&protocol->dev); } - + +EXPORT_SYMBOL(pnp_unregister_protocol); + static void pnp_free_ids(struct pnp_dev *dev) @@ -88277,7 +24309,7 @@ @@ -166,6 +170,8 @@ return 0; } - + +EXPORT_SYMBOL(pnp_add_device); + void __pnp_remove_device(struct pnp_dev *dev) @@ -88286,7 +24318,7 @@ @@ -175,6 +181,21 @@ device_unregister(&dev->dev); } - + +/** + * pnp_remove_device - removes a pnp device from the pnp layer + * @dev: pointer to dev to add @@ -88315,7 +24347,7 @@ --- linux-2.6.24.7.old/drivers/pnp/resource.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/pnp/resource.c 2009-04-12 18:13:57.000000000 +0200 @@ -404,6 +404,10 @@ - + int pnp_check_dma(struct pnp_dev *dev, int idx) { + printk("*********** %s, %s, line[%d]: Fix me, this should update in the future *********\n", @@ -88327,15 +24359,6 @@ struct pnp_dev *tdev; --- linux-2.6.24.7.old/drivers/serial/8250.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/serial/8250.c 2009-04-12 18:13:57.000000000 +0200 -@@ -12,7 +12,7 @@ - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * -- * $Id: 8250.c,v 1.90 2002/07/28 10:03:27 rmk Exp $ -+ * $Id: 8250.c,v 1.5 2008-07-14 06:40:28 lhhuang Exp $ - * - * A note about mapbase / membase - * @@ -181,7 +181,7 @@ [PORT_16550A] = { .name = "16550A", @@ -88347,7 +24370,7 @@ }, @@ -400,6 +400,10 @@ break; - + case UPIO_MEM: +#if defined(CONFIG_JZSOC) + if (offset == (UART_FCR << up->port.regshift)) @@ -88355,11 +24378,11 @@ +#endif writeb(value, up->port.membase + offset); break; - + @@ -1981,6 +1985,83 @@ serial_unlink_irq_chain(up); } - + +#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730) +static unsigned short quot1[3] = {0}; /* quot[0]:baud_div, quot[1]:umr, quot[2]:uacr */ +static unsigned short * serial8250_get_divisor(struct uart_port *port, unsigned int baud) @@ -88441,11 +24464,11 @@ { unsigned int quot; @@ -2000,6 +2081,7 @@ - + return quot; } +#endif - + static void serial8250_set_termios(struct uart_port *port, struct ktermios *termios, @@ -2009,6 +2091,9 @@ @@ -88455,7 +24478,7 @@ +#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730) + unsigned short *quot1; +#endif - + switch (termios->c_cflag & CSIZE) { case CS5: @@ -2041,7 +2126,12 @@ @@ -88468,24 +24491,24 @@ +#else quot = serial8250_get_divisor(port, baud); +#endif - + /* * Oxford Semi 952 rev B workaround @@ -2119,6 +2209,10 @@ if (up->capabilities & UART_CAP_UUE) up->ier |= UART_IER_UUE | UART_IER_RTOIE; - + +#ifdef CONFIG_JZSOC + up->ier |= UART_IER_RTOIE; /* Set this flag, or very slow */ +#endif + serial_out(up, UART_IER, up->ier); - + if (up->capabilities & UART_CAP_EFR) { @@ -2153,7 +2247,15 @@ serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ } - + +#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730) +#define UART_UMR 9 +#define UART_UACR 10 @@ -88495,27 +24518,9 @@ +#else serial_dl_write(up, quot); +#endif - + /* * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR -@@ -2866,7 +2968,7 @@ - if (nr_uarts > UART_NR) - nr_uarts = UART_NR; - -- printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ " -+ printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.5 $ " - "%d ports, IRQ sharing %sabled\n", nr_uarts, - share_irqs ? "en" : "dis"); - -@@ -2927,7 +3029,7 @@ - EXPORT_SYMBOL(serial8250_resume_port); - - MODULE_LICENSE("GPL"); --MODULE_DESCRIPTION("Generic 8250/16x50 serial driver $Revision: 1.90 $"); -+MODULE_DESCRIPTION("Generic 8250/16x50 serial driver $Revision: 1.5 $"); - - module_param(share_irqs, uint, 0644); - MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" --- linux-2.6.24.7.old/drivers/usb/Kconfig 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/usb/Kconfig 2009-04-12 18:13:57.000000000 +0200 @@ -41,6 +41,7 @@ @@ -88523,16 +24528,16 @@ # MIPS: default y if SOC_AU1X00 + default y if JZSOC - # more: - default PCI - + # SH: + default y if CPU_SUBTYPE_SH7720 + default y if CPU_SUBTYPE_SH7721 --- linux-2.6.24.7.old/drivers/usb/core/hub.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/usb/core/hub.c 2009-04-12 18:13:57.000000000 +0200 @@ -2484,11 +2484,35 @@ struct device *hub_dev = hub->intfdev; u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); int status, i; -- +- +#ifdef CONFIG_JZSOC + static char jzhub = 1; /* the hub first to be initialized is jzsoc on-chip hub */ +#endif @@ -88540,7 +24545,7 @@ dev_dbg (hub_dev, "port %d, status %04x, change %04x, %s\n", port1, portstatus, portchange, portspeed (portstatus)); - + +#ifdef CONFIG_SOC_JZ4730 + /* + * On Jz4730, we assume that the first USB port was used as device. @@ -88570,13 +24575,13 @@ @@ -93,6 +93,47 @@ Many controller drivers are platform-specific; these often need board-specific hooks. - + +config USB_GADGET_JZ4740 + boolean "JZ4740 UDC" + depends on SOC_JZ4740 + select USB_GADGET_DUALSPEED + help -+ Select this to support the Ingenic JZ4740 processor ++ Select this to support the Ingenic JZ4740 processor + high speed USB device controller. + +config USB_JZ4740 @@ -88590,7 +24595,7 @@ + depends on SOC_JZ4750 + select USB_GADGET_DUALSPEED + help -+ Select this to support the Ingenic JZ4750 processor ++ Select this to support the Ingenic JZ4750 processor + high speed USB device controller. + +config USB_JZ4750 @@ -88603,7 +24608,7 @@ + boolean "JZ4730 UDC" + depends on SOC_JZ4730 + help -+ Select this to support the Ingenic JZ4730 processor ++ Select this to support the Ingenic JZ4730 processor + full speed USB device controller. + +config USB_JZ4730 @@ -88618,7 +24623,7 @@ @@ -509,6 +550,14 @@ behavior of USB Mass Storage hosts. Not needed for normal operation. - + +config UDC_USE_LB_CACHE + bool "enable lb cache" + depends on USB_FILE_STORAGE && (SOC_JZ4740 || SOC_JZ4750) @@ -88633,20 +24638,20 @@ --- linux-2.6.24.7.old/drivers/usb/gadget/Makefile 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/usb/gadget/Makefile 2009-04-12 18:13:57.000000000 +0200 @@ -17,6 +17,9 @@ - obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o obj-$(CONFIG_USB_M66592) += m66592-udc.o + obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o +obj-$(CONFIG_USB_JZ4740) += jz4740_udc.o +obj-$(CONFIG_USB_JZ4730) += jz4730_udc.o +obj-$(CONFIG_USB_JZ4750) += jz4740_udc.o - + # # USB gadget drivers --- linux-2.6.24.7.old/drivers/usb/gadget/file_storage.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/usb/gadget/file_storage.c 2009-04-12 18:13:57.000000000 +0200 @@ -274,6 +274,18 @@ - - + + /*-------------------------------------------------------------------------*/ +#if defined(CONFIG_UDC_USE_LB_CACHE) +#define GHOST @@ -88660,7 +24665,7 @@ +extern int NAND_MTD_FLASHCACHE(void); +extern int FlushDataState; +#endif - + #ifdef DEBUG #define LDBG(lun,fmt,args...) \ @@ -349,8 +361,8 @@ @@ -88679,7 +24684,7 @@ #define STRING_CONFIG 4 #define STRING_INTERFACE 5 +#define STRING_MS_OS 0xee - + /* There is only one configuration. */ #define CONFIG_VALUE 1 @@ -997,6 +1010,7 @@ @@ -88689,9 +24694,9 @@ + {STRING_MS_OS, "Microsoft"}, {} }; - + @@ -1618,9 +1632,14 @@ - + /* Perform the read */ file_offset_tmp = file_offset; +#ifdef GHOST @@ -88706,7 +24711,7 @@ (unsigned long long) file_offset, (int) nread); @@ -1799,9 +1818,13 @@ - + /* Perform the write */ file_offset_tmp = file_offset; +#ifdef GHOST @@ -88720,7 +24725,7 @@ (unsigned long long) file_offset, (int) nwritten); @@ -1976,9 +1999,19 @@ - + /* Perform the read */ file_offset_tmp = file_offset; +#ifdef GHOST @@ -88742,11 +24747,11 @@ @@ -2013,7 +2046,7 @@ { u8 *buf = (u8 *) bh->buf; - + - static char vendor_id[] = "Linux "; + static char vendor_id[] = "Ingenic "; static char product_id[] = "File-Stor Gadget"; - + if (!fsg->curlun) { // Unsupported LUNs are okay @@ -2857,6 +2890,15 @@ reply = check_command(fsg, 6, DATA_DIR_NONE, @@ -88756,16 +24761,16 @@ + if( FlushDataState >= 1) + FlushDataState++; + if(FlushDataState > 6) -+ { ++ { + NAND_LB_FLASHCACHE(); + FlushDataState = 0; + } +#endif break; - + /* Although optional, this command is used by MS-Windows. We @@ -3404,6 +3446,13 @@ - + /* The main loop */ while (fsg->state != FSG_STATE_TERMINATED) { +#ifdef GHOST @@ -88783,17 +24788,17 @@ LDBG(curlun, "open backing file: %s\n", filename); rc = 0; +#ifdef GHOST -+ NAND_LB_Init(); ++ NAND_LB_Init(); +#endif - + out: filp_close(filp, current->files); --- linux-2.6.24.7.old/drivers/usb/gadget/gadget_chips.h 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/usb/gadget/gadget_chips.h 2009-04-12 18:13:57.000000000 +0200 @@ -11,6 +11,18 @@ - * Some are available on 2.4 kernels; several are available, but not - * yet pushed in the 2.6 mainline tree. - */ + #ifndef __GADGET_CHIPS_H + #define __GADGET_CHIPS_H + +#ifdef CONFIG_USB_GADGET_JZ4740 +#define gadget_is_jz4740(g) !strcmp("jz4740_udc", (g)->name) +#else @@ -88810,13 +24815,13 @@ #define gadget_is_net2280(g) !strcmp("net2280", (g)->name) #else @@ -212,5 +224,9 @@ - return 0x20; - else if (gadget_is_m66592(gadget)) - return 0x21; + return 0x21; + else if (gadget_is_fsl_qe(gadget)) + return 0x22; + else if (gadget_is_jz4730(gadget)) -+ return 0x22; -+ else if (gadget_is_jz4740(gadget)) + return 0x23; ++ else if (gadget_is_jz4740(gadget)) ++ return 0x24; return -ENOENT; } --- linux-2.6.24.7.old/drivers/usb/gadget/jz4730_udc.c 1970-01-01 01:00:00.000000000 +0100 @@ -88897,7 +24902,7 @@ +static void jz4730_udc_release (struct device *dev) {} +/*-------------------------------------------------------------------------*/ + -+static int jz4730_ep_enable(struct usb_ep *_ep, ++static int jz4730_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct jz4730_udc *dev; @@ -89047,7 +25052,7 @@ +static __inline__ int write_packet(struct jz4730_ep *ep, + struct jz4730_request *req, int max) +{ -+ u8 *buf; ++ u8 *buf; + int length, nlong, nbyte; + volatile u32 *fifo = (volatile u32 *)ep->fifo; + @@ -89076,13 +25081,13 @@ + *((volatile u8 *)fifo) = *buf++; + } + } -+ ++ + writel(0, (unsigned int *)UDC_TXCONFIRM); + + return length; +} + -+static __inline__ int read_packet(struct jz4730_ep *ep, ++static __inline__ int read_packet(struct jz4730_ep *ep, + struct jz4730_request *req, int count) +{ + u8 *buf; @@ -89234,7 +25239,7 @@ + + /* always require a cpu-view buffer so pio works */ + req = container_of(_req, struct jz4730_request, req); -+ if (unlikely(!_req || !_req->complete ++ if (unlikely(!_req || !_req->complete + || !_req->buf || !list_empty(&req->queue))) + return -EINVAL; + ep = container_of(_ep, struct jz4730_ep, ep); @@ -89263,17 +25268,17 @@ + if (list_empty(&ep->queue) && likely(!ep->stopped)) { + if (unlikely(ep->index == 0)) { + pio_irq_enable(ep); -+ if (ep->irq_pending || ++ if (ep->irq_pending || + (REG_UDC_EPIntR & UDC_EPIntR_OUTEP0)) { + u32 stats, count; -+ ++ + stats = REG_UDC_EP0OutSR; + if (stats & UDC_EPSR_OUT_RCVDATA) { + ep->irq_pending = 0; + REG_UDC_EP0OutSR &= ~UDC_EPSR_OUT_MASK; + if (REG_UDC_EPIntR & UDC_EPIntR_OUTEP0) + REG_UDC_EPIntR = UDC_EPIntR_OUTEP0; -+ ++ + count = OUT_COUNT(stats); + if (read_fifo(ep, req, count) == 1) + req = 0; @@ -89282,7 +25287,7 @@ + + } else if (ep->is_in) { + /* EP1 ~ EP4 */ -+ if (ep->irq_pending || ++ if (ep->irq_pending || + (REG_UDC_EPIntR & UDC_EPIntR_INEP2)) { + if (REG_UDC_EP2InSR & UDC_EPSR_IN) { + ep->irq_pending = 0; @@ -89299,7 +25304,7 @@ + /* EP5 ~ EP7 */ + pio_irq_enable(ep); + -+ if (ep->irq_pending || ++ if (ep->irq_pending || + (REG_UDC_EPIntR & UDC_EPIntR_OUTEP5)) { + u32 stats, count; + @@ -89315,7 +25320,7 @@ + req = 0; + } + } -+ } ++ } + } + + /* pio or dma irq handler advances the queue. */ @@ -89372,7 +25377,7 @@ + spin_unlock_irqrestore (&dev->lock, flags); + return -EINVAL; + } -+ ++ + /* queue head may be partially complete. */ + if (ep->queue.next == &req->queue) { + done (ep, req, -ECONNRESET); @@ -89592,7 +25597,7 @@ + REG_UDC_EP4InfR = (MAX_EP4_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (1 << 4) | (4 << 0); + REG_UDC_EP5InfR = (MAX_EP5_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (5 << 0); + REG_UDC_EP6InfR = (MAX_EP6_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (6 << 0); -+ REG_UDC_EP7InfR = (MAX_EP7_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (0 << 4) | (7 << 0); ++ REG_UDC_EP7InfR = (MAX_EP7_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (0 << 4) | (7 << 0); + + REG_UDC_STCMAR = 0xffff; +} @@ -89636,7 +25641,7 @@ +{ + struct jz4730_udc *dev = the_controller; + int retval; -+ ++ + if (!driver +// || driver->speed != USB_SPEED_FULL + || !driver->bind @@ -89780,7 +25785,7 @@ +/* + * Simulate a USB_REQ_SET_CONFIGURATION to the function driver, + * this is required to enable the endpoints of the function driver. -+ * UDC should let software have the chance to handle this standard ++ * UDC should let software have the chance to handle this standard + * request, unfortunately UDC can't do that. + */ +static void psudo_set_config(void) @@ -89821,7 +25826,7 @@ + } +} + -+/* ++/* + * Read 8 bytes setup packet from EP0 RX buffer + */ +static void read_setup_packet(u8 *buf) @@ -90065,7 +26070,7 @@ + jz4730_epn_in(dev, 1); + } + } -+ ++ + REG_UDC_EPIntR = UDC_EPIntR_INEP1; + } + @@ -90086,7 +26091,7 @@ + .bus_id = "gadget", + }, + }, -+ /* control endpoint no need to init here!*/ ++ /* control endpoint no need to init here!*/ + /* control endpoint */ +}; + @@ -90261,8 +26266,8 @@ +#define TXFIFOEP3 (TXFIFOEP2 + MAX_EP2_SIZE) /* EP3 IN */ +#define TXFIFOEP4 (TXFIFOEP3 + MAX_EP3_SIZE) /* EP4 IN */ + -+static u32 ep_fifo[MAX_EP_NUM] = {TXFIFOEP0, TXFIFOEP1, TXFIFOEP2, -+ TXFIFOEP3, TXFIFOEP4, RXFIFO, RXFIFO, ++static u32 ep_fifo[MAX_EP_NUM] = {TXFIFOEP0, TXFIFOEP1, TXFIFOEP2, ++ TXFIFOEP3, TXFIFOEP4, RXFIFO, RXFIFO, + RXFIFO}; + +#define OUT_COUNT(stats) \ @@ -90439,7 +26444,7 @@ +/* + * Local declarations. + */ -+static int jz4740_ep_enable(struct usb_ep *_ep, ++static int jz4740_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc); +static int jz4740_ep_disable(struct usb_ep *_ep); +static struct usb_request *jz4740_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags); @@ -90561,7 +26566,7 @@ +static __inline__ int write_packet(struct jz4740_ep *ep, + struct jz4740_request *req, int max) +{ -+ u8 *buf; ++ u8 *buf; + int length, nlong, nbyte; + volatile u32 *fifo = (volatile u32 *)ep->fifo; + @@ -90587,7 +26592,7 @@ + return length; +} + -+static __inline__ int read_packet(struct jz4740_ep *ep, ++static __inline__ int read_packet(struct jz4740_ep *ep, + struct jz4740_request *req, int count) +{ + u8 *buf; @@ -90782,7 +26787,7 @@ + * for set_configuration as well as eventual disconnect. + */ + udc_enable(dev); -+ DEBUG("%s: registered gadget driver '%s'\n", dev->gadget.name, ++ DEBUG("%s: registered gadget driver '%s'\n", dev->gadget.name, + driver->driver.name); + + return 0; @@ -90877,7 +26882,7 @@ + + usb_writel(USB_REG_ADDR1, physaddr); + usb_writel(USB_REG_COUNT1, count); -+ usb_writel(USB_REG_CNTL1, USB_CNTL_ENA | USB_CNTL_DIR_IN | USB_CNTL_MODE_1 | ++ usb_writel(USB_REG_CNTL1, USB_CNTL_ENA | USB_CNTL_DIR_IN | USB_CNTL_MODE_1 | + USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep))); + } + else { /* Bulk-OUT transfer using DMA channel 2 */ @@ -90892,7 +26897,7 @@ + + usb_writel(USB_REG_ADDR2, physaddr); + usb_writel(USB_REG_COUNT2, count); -+ usb_writel(USB_REG_CNTL2, USB_CNTL_ENA | USB_CNTL_MODE_1 | ++ usb_writel(USB_REG_CNTL2, USB_CNTL_ENA | USB_CNTL_MODE_1 | + USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep))); + } +} @@ -91271,7 +27276,7 @@ + * PIO mode starts here ... + */ + -+ while ((csr = usb_readb(ep->csr)) & ++ while ((csr = usb_readb(ep->csr)) & + (USB_OUTCSR_OUTPKTRDY | USB_OUTCSR_SENTSTALL)) { + DEBUG("%s: %x\n", __FUNCTION__, csr); + @@ -92094,11 +28099,11 @@ + jz4740_set_halt(&qep->ep, 0); + } + spin_lock(&dev->lock); -+ ++ + usb_set_index(0); + + /* Reply with a ZLP on next IN token */ -+ usb_setb(USB_REG_CSR0, ++ usb_setb(USB_REG_CSR0, + (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); + return; + } @@ -92109,7 +28114,7 @@ + } + + /* gadget drivers see class/vendor specific requests, -+ * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, ++ * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, + * and more. + */ + if (likely((u32)dev->driver)) { @@ -92281,7 +28286,7 @@ + */ +static void jz4740_reset_irq(struct jz4740_udc *dev) +{ -+ dev->gadget.speed = (usb_readb(USB_REG_POWER) & USB_POWER_HSMODE) ? ++ dev->gadget.speed = (usb_readb(USB_REG_POWER) & USB_POWER_HSMODE) ? + USB_SPEED_HIGH : USB_SPEED_FULL; + + DEBUG_SETUP("%s: address = %d, speed = %s\n", __FUNCTION__, dev->usb_address, @@ -92303,13 +28308,13 @@ + if (!intr_usb && !intr_in && !intr_out && !intr_dma) + return IRQ_HANDLED; + -+ DEBUG("intr_out = %x intr_in=%x intr_usb=%x\n", ++ DEBUG("intr_out = %x intr_in=%x intr_usb=%x\n", + intr_out, intr_in, intr_usb); + + spin_lock(&dev->lock); + + /* Check for resume from suspend mode */ -+ if ((intr_usb & USB_INTR_RESUME) && ++ if ((intr_usb & USB_INTR_RESUME) && + (usb_readb(USB_REG_INTRUSBE) & USB_INTR_RESUME)) { + DEBUG("USB resume\n"); + } @@ -92321,7 +28326,7 @@ + jz_udc_active = 1; +#endif + if (udc_debug) { -+ /* We have tested the cable type, disable module and ++ /* We have tested the cable type, disable module and + * disconnect from host right now. + */ + udc_disable(dev); @@ -92368,7 +28373,7 @@ + } + + /* Check for suspend mode */ -+ if ((intr_usb & USB_INTR_SUSPEND) && ++ if ((intr_usb & USB_INTR_SUSPEND) && + (usb_readb(USB_REG_INTRUSBE) & USB_INTR_SUSPEND)) { + DEBUG("USB suspend\n"); + dev->driver->suspend(&dev->gadget); @@ -92709,15 +28714,15 @@ @@ -977,6 +977,11 @@ #define PCI_DRIVER ohci_pci_driver #endif - + +#ifdef CONFIG_JZSOC +#include "ohci-jz.c" +#define PLATFORM_DRIVER ohci_hcd_jz_driver +#endif + - #ifdef CONFIG_SA1111 + #if defined(CONFIG_ARCH_SA1100) && defined(CONFIG_SA1111) #include "ohci-sa1111.c" - #define SA1111_DRIVER ohci_hcd_sa1111_driver + #define SA1111_DRIVER ohci_hcd_sa1111_driver#ifdef CONFIG_SA1111 --- linux-2.6.24.7.old/drivers/usb/host/ohci-jz.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/drivers/usb/host/ohci-jz.c 2009-04-12 18:13:57.000000000 +0200 @@ -0,0 +1,260 @@ @@ -92986,7 +28991,7 @@ @@ -201,6 +201,222 @@ comment "Frame buffer hardware drivers" depends on FB - + +config FB_JZSOC + tristate "JZSOC LCD controller support" + depends on FB && JZSOC @@ -93001,7 +29006,7 @@ + depends on FB_JZSOC && SOC_JZ4740 + default n + ---help--- -+ This is the frame buffer device driver for the JZ4740 Smart LCD controller. ++ This is the frame buffer device driver for the JZ4740 Smart LCD controller. + If select this, please set to . + +choice @@ -93018,7 +29023,7 @@ + bool "SPFD5420A Smart LCD panel" + ---help--- + Driver for Smart LCD SPFD5420A 18-bit sytem interface, 18BPP. -+ ++ +config JZ_SLCD_TRULY + bool "TRULY Smart LCD panel (MAX Pixels 400x240)" + ---help--- @@ -93210,7 +29215,7 @@ +++ linux-2.6.24.7/drivers/video/Makefile 2009-04-12 18:13:57.000000000 +0200 @@ -28,6 +28,10 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o - + # Hardware specific drivers go first +obj-$(CONFIG_FB_JZLCD_4730_4740) += jzlcd.o +obj-$(CONFIG_FB_JZ4740_SLCD) += jz4740_slcd.o @@ -93222,9 +29227,9 @@ --- linux-2.6.24.7.old/drivers/video/console/Kconfig 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/video/console/Kconfig 2009-04-12 18:13:57.000000000 +0200 @@ -134,6 +134,14 @@ - + If unsure, select n. - + +config FRAMEBUFFER_CONSOLE_CURSOR_FLASH + bool "Framebuffer Console Cursor flash" + depends on FRAMEBUFFER_CONSOLE @@ -93239,7 +29244,7 @@ --- linux-2.6.24.7.old/drivers/video/console/fbcon.c 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/video/console/fbcon.c 2009-04-12 18:13:57.000000000 +0200 @@ -399,6 +399,7 @@ - + static void fb_flashcursor(struct work_struct *work) { +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH @@ -93252,7 +29257,7 @@ release_console_sem(); +#endif } - + #if defined(CONFIG_ATARI) || defined(CONFIG_MAC) --- linux-2.6.24.7.old/drivers/video/jz4740_slcd.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.24.7/drivers/video/jz4740_slcd.c 2009-04-12 18:13:57.000000000 +0200 @@ -93347,7 +29352,7 @@ + unsigned int bpp; /* bit per pixel */ + unsigned int bus; + unsigned int pclk; /* pixel clk */ -+ ++ +}; + +static struct jzfb_info jzfb = { @@ -93400,7 +29405,7 @@ + REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff); + break; + case 18: -+ cmd = ((cmd & 0xff) << 1) | ((cmd & 0xff00) << 2); ++ cmd = ((cmd & 0xff) << 1) | ((cmd & 0xff00) << 2); + data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); + while (REG_SLCD_STATE & SLCD_STATE_BUSY); + REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd; @@ -93445,7 +29450,7 @@ + udelay(1); + Mcupanel_RegSet(0x21,y) ; + udelay(1); -+ Mcupanel_Command(0x22); ++ Mcupanel_Command(0x22); + +} +#endif @@ -93501,7 +29506,7 @@ + red = 1 << 3; + if (((blue >> 3) == 0) && ((blue >> 2) != 0)) + blue = 1 << 3; -+ ctmp = ((red >> 3) << 11) ++ ctmp = ((red >> 3) << 11) + | ((green >> 2) << 5) | (blue >> 3); + + ptr = (unsigned short *)slcd_palette; @@ -93509,20 +29514,20 @@ + ptr[regno] = ctmp; + + break; -+ ++ + case 15: + if (regno < 16) + ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 10) | ++ ((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3); + break; + case 16: + if (regno < 16) { + ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 11) | ++ ((red >> 3) << 11) | + ((green >> 2) << 5) | -+ (blue >> 3); ++ (blue >> 3); + } + break; + case 18: @@ -93530,9 +29535,9 @@ + case 32: + if (regno < 16) + ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ (red << 16) | ++ (red << 16) | + (green << 8) | -+ (blue << 0); ++ (blue << 0); + +/* if (regno < 16) { + unsigned val; @@ -93594,7 +29599,7 @@ + else { + while (REG_SLCD_STATE & SLCD_STATE_BUSY); + __dmac_channel_set_doorbell(dma_chan); -+ } ++ } + break; + case FBIO_SET_REG: + if (copy_from_user(®_buf, argp, sizeof(reg_buf))) @@ -93657,7 +29662,7 @@ +} + + -+/* ++/* + * set the video mode according to info->var + */ +static int jzfb_set_par(struct fb_info *info) @@ -93696,7 +29701,7 @@ + return 0; +} + -+/* ++/* + * pan display + */ +static int jzfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) @@ -93770,7 +29775,7 @@ + var->vsync_len = 0; + var->sync = 0; + var->activate &= ~FB_ACTIVATE_TEST; -+ ++ + /* + * CONUPDATE and SMOOTH_XPAN are equal. However, + * SMOOTH_XPAN is only used internally by fbcon. @@ -94052,8 +30057,8 @@ + + if (slcd_frame) { + -+ for (tmp=(unsigned char *)slcd_frame; -+ tmp < slcd_frame + (PAGE_SIZE << page_shift); ++ for (tmp=(unsigned char *)slcd_frame; ++ tmp < slcd_frame + (PAGE_SIZE << page_shift); + tmp += PAGE_SIZE) { + map = virt_to_page(tmp); + clear_bit(PG_reserved, &map->flags); @@ -94105,7 +30110,7 @@ + + /* Prepare Palette Descriptor */ + slcd_palette_desc.dcmd = DMAC_DCMD_SAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 -+ | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V ++ | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V + | DMAC_DCMD_DES_VIE | DMAC_DCMD_LINK; + switch (slcd_palette_desc.dcmd & DMAC_DCMD_DS_MASK) { + case DMAC_DCMD_DS_32BYTE: @@ -94161,7 +30166,7 @@ + default: + break; + } -+ ++ + slcd_frame_desc.dsadr = slcd_frame_src_phys_addr; /* DMA source address */ + slcd_frame_desc.dtadr = slcd_dma_dst_phys_addr; /* DMA target address */ + slcd_frame_desc.ddadr = (volatile unsigned int)((next << 24) | (frm_size & 0xffffff)); /* offset and size*/ @@ -94182,16 +30187,16 @@ + /* Configure SLCD module for initialize smart lcd registers*/ + switch (jzfb.bus) { + case 8: -+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2 -+ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW -+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING ++ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2 ++ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW ++ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING + | SLCD_CFG_TYPE_PARALLEL; + __gpio_as_slcd_8bit(); + break; + case 9: + REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2 -+ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW -+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING ++ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW ++ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING + | SLCD_CFG_TYPE_PARALLEL; + __gpio_as_slcd_9bit(); + break; @@ -94204,8 +30209,8 @@ + break; + case 18: + REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_18 -+ | SLCD_CFG_CWIDTH_18BIT | SLCD_CFG_CS_ACTIVE_LOW -+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING ++ | SLCD_CFG_CWIDTH_18BIT | SLCD_CFG_CS_ACTIVE_LOW ++ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING + | SLCD_CFG_TYPE_PARALLEL; + __gpio_as_slcd_18bit(); + break; @@ -94360,7 +30365,7 @@ + + if (__dmac_channel_transmit_end_detected(dma_chan)) { + printk("DMA TT\n"); -+ __dmac_channel_clear_transmit_end(dma_chan); ++ __dmac_channel_clear_transmit_end(dma_chan); + if (non_link_desp) { + slcd_frame_desc.dcmd |= DMAC_DCMD_TIE; + slcd_frame_desc.dcmd &= ~DMAC_DCMD_LINK; @@ -94425,7 +30430,7 @@ + __slcd_close_backlight(); + __dmac_disable_channel(dma_chan); + __slcd_dma_disable(); /* Quick Disable */ -+ __slcd_special_off(); ++ __slcd_special_off(); + __cpm_stop_lcd(); + return 0; +} @@ -94468,7 +30473,7 @@ + __dmac_enable_channel(dma_chan); + __dmac_channel_set_doorbell(dma_chan); + mdelay(200); -+ __slcd_set_backlight_level(80); ++ __slcd_set_backlight_level(80); + return 0; +} + @@ -94624,8 +30629,8 @@ +#define FBIO_SET_REG 0x4690 + +#ifdef CONFIG_JZ_SLCD_LGDP4551 -+#define PIN_CS_N (32*2+18) /* Chip select :SLCD_WR: GPC18 */ -+#define PIN_RESET_N (32*2+21) /* LCD reset :SLCD_RST: GPC21*/ ++#define PIN_CS_N (32*2+18) /* Chip select :SLCD_WR: GPC18 */ ++#define PIN_RESET_N (32*2+21) /* LCD reset :SLCD_RST: GPC21*/ +#define PIN_RS_N (32*2+19) + +#define __slcd_special_pin_init() \ @@ -94823,9 +30828,9 @@ + else /*bpp = 18*/ \ + Mcupanel_RegSet(0x0003, 0x1010 | 0xC8); /*Entry Mode 0x1030*/ \ + /*#endif */ \ -+ Mcupanel_RegSet(0x0006, 0x0000); /*Outline Sharpening Control*/\ ++ Mcupanel_RegSet(0x0006, 0x0000); /*Outline Sharpening Control*/\ + Mcupanel_RegSet(0x0008, 0x0808); /*Sets the number of lines for front/back porch period*/\ -+ Mcupanel_RegSet(0x0009, 0x0001); /*Display Control 3 */\ ++ Mcupanel_RegSet(0x0009, 0x0001); /*Display Control 3 */\ + Mcupanel_RegSet(0x000B, 0x0010); /*Low Power Control*/\ + Mcupanel_RegSet(0x000C, 0x0000); /*External Display Interface Control 1 /*0x0001*/\ + Mcupanel_RegSet(0x000F, 0x0000); /*External Display Interface Control 2 */\ @@ -94846,7 +30851,7 @@ + mdelay(10); \ + Mcupanel_RegSet(0x0020, 0x021e); /*Panel Interface Control 4 */\ + Mcupanel_RegSet(0x0021, 0x0202); /*Panel Interface Control 5 */\ -+ Mcupanel_RegSet(0x0022, 0x0100); /*Panel Interface Control 6*/\ ++ Mcupanel_RegSet(0x0022, 0x0100); /*Panel Interface Control 6*/\ + Mcupanel_RegSet(0x0090, 0x0000); /*Frame Marker Control */\ + Mcupanel_RegSet(0x0092, 0x0000); /*MDDI Sub-display Control */\ + /*===Gamma setting=== */\ @@ -94990,7 +30995,7 @@ +/* + * -------------------------------- + * NOTE: -+ * This LCD driver support TFT16 TFT32 LCD, not support STN and Special TFT LCD ++ * This LCD driver support TFT16 TFT32 LCD, not support STN and Special TFT LCD + * now. + * It seems not necessory to support STN and Special TFT. + * If it's necessary, update this driver in the future. @@ -95082,7 +31087,7 @@ +struct jz4750lcd_info jz4750_lcd_panel = { +#if defined(CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF02) + .panel = { -+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ ++ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ + LCD_CFG_NEWDES | /* 8words descriptor */ + LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */ + LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */ @@ -95109,7 +31114,7 @@ + }, +#elif defined(CONFIG_JZ4750_LCD_AUO_A043FL01V2) + .panel = { -+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ ++ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ + LCD_CFG_NEWDES | /* 8words descriptor */ + LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */ + LCD_CFG_MODE_TFT_24BIT | /* output 18bpp */ @@ -95137,8 +31142,8 @@ + }, +#elif defined(CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W) + .panel = { -+// .cfg = LCD_CFG_LCDPIN_SLCD | LCD_CFG_RECOVER | /* Underrun recover*/ -+ .cfg = LCD_CFG_LCDPIN_SLCD | /* Underrun recover*/ ++// .cfg = LCD_CFG_LCDPIN_SLCD | LCD_CFG_RECOVER | /* Underrun recover*/ ++ .cfg = LCD_CFG_LCDPIN_SLCD | /* Underrun recover*/ + LCD_CFG_NEWDES | /* 8words descriptor */ + LCD_CFG_MODE_SLCD, /* TFT Smart LCD panel */ + .slcd_cfg = SLCD_CFG_DWIDTH_16BIT | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING | SLCD_CFG_TYPE_PARALLEL, @@ -95164,7 +31169,7 @@ + +#elif defined(CONFIG_JZ4750_LCD_FOXCONN_PT035TN01) + .panel = { -+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ ++ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ + LCD_CFG_NEWDES | /* 8words descriptor */ + LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */ +// LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */ @@ -95194,7 +31199,7 @@ + }, +#elif defined(CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL) + .panel = { -+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ ++ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ + LCD_CFG_NEWDES | /* 8words descriptor */ + LCD_CFG_MODE_SERIAL_TFT | /* Serial TFT panel */ + LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */ @@ -95222,8 +31227,8 @@ + }, +#elif defined(CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A) + .panel = { -+// .cfg = LCD_CFG_LCDPIN_SLCD | LCD_CFG_RECOVER | /* Underrun recover*/ -+ .cfg = LCD_CFG_LCDPIN_SLCD | /* Underrun recover*/ ++// .cfg = LCD_CFG_LCDPIN_SLCD | LCD_CFG_RECOVER | /* Underrun recover*/ ++ .cfg = LCD_CFG_LCDPIN_SLCD | /* Underrun recover*/ +// LCD_CFG_DITHER | /* dither */ + LCD_CFG_NEWDES | /* 8words descriptor */ + LCD_CFG_MODE_SLCD, /* TFT Smart LCD panel */ @@ -95420,7 +31425,7 @@ + red = 1 << 3; + if (((blue >> 3) == 0) && ((blue >> 2) != 0)) + blue = 1 << 3; -+ ctmp = ((red >> 3) << 11) ++ ctmp = ((red >> 3) << 11) + | ((green >> 2) << 5) | (blue >> 3); + } + @@ -95429,28 +31434,28 @@ + ptr[regno] = ctmp; + + break; -+ ++ + case 15: + if (regno < 16) + ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 10) | ++ ((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3); + break; + case 16: + if (regno < 16) { + ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 11) | ++ ((red >> 3) << 11) | + ((green >> 2) << 5) | -+ (blue >> 3); ++ (blue >> 3); + } + break; + case 17 ... 32: + if (regno < 16) + ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ (red << 16) | ++ (red << 16) | + (green << 8) | -+ (blue << 0); ++ (blue << 0); + +/* if (regno < 16) { + unsigned val; @@ -95467,7 +31472,7 @@ +} + + -+/* ++/* + * switch to tve mode from lcd mode + * mode: + * PANEL_MODE_TVE_PAL: switch to TVE_PAL mode @@ -95558,7 +31563,7 @@ + break; + case FBIODISPOFF: + __lcd_display_off(); -+ if ( jz4750_lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD || ++ if ( jz4750_lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD || + jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) /* */ + __lcd_clr_ena(); /* Smart lcd and TVE mode only support quick disable */ + else @@ -95674,7 +31679,7 @@ +} + + -+/* ++/* + * set the video mode according to info->var + */ +static int jz4750fb_set_par(struct fb_info *info) @@ -95716,7 +31721,7 @@ + return 0; +} + -+/* ++/* + * pan display + */ +static int jz4750fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) @@ -95788,7 +31793,7 @@ + var->vsync_len = 0; + var->sync = 0; + var->activate &= ~FB_ACTIVATE_TEST; -+ ++ + /* + * CONUPDATE and SMOOTH_XPAN are equal. However, + * SMOOTH_XPAN is only used internally by fbcon. @@ -96047,7 +32052,7 @@ + */ + page = (unsigned long)lcd_palette; + SetPageReserved(virt_to_page((void*)page)); -+ ++ + for (page = (unsigned long)lcd_frame0; + page < PAGE_ALIGN((unsigned long)lcd_frame0 + (PAGE_SIZE<flags); @@ -96159,29 +32164,29 @@ + dma1_desc1 = dma_desc_base + 6; + + /* -+ * Normal TFT panel's DMA Chan0: -+ * TO LCD Panel: -+ * no palette: dma0_desc0 <<==>> dma0_desc0 ++ * Normal TFT panel's DMA Chan0: ++ * TO LCD Panel: ++ * no palette: dma0_desc0 <<==>> dma0_desc0 + * palette : dma0_desc_palette <<==>> dma0_desc0 + * TO TV Encoder: + * no palette: dma0_desc0 <<==>> dma0_desc1 -+ * palette: dma0_desc_palette --> dma0_desc0 ++ * palette: dma0_desc_palette --> dma0_desc0 + * --> dma0_desc1 --> dma0_desc_palette --> ... -+ * -+ * SMART LCD TFT panel(dma0_desc_cmd)'s DMA Chan0: ++ * ++ * SMART LCD TFT panel(dma0_desc_cmd)'s DMA Chan0: + * TO LCD Panel: -+ * no palette: dma0_desc_cmd <<==>> dma0_desc0 ++ * no palette: dma0_desc_cmd <<==>> dma0_desc0 + * palette : dma0_desc_palette --> dma0_desc_cmd + * --> dma0_desc0 --> dma0_desc_palette --> ... + * TO TV Encoder: -+ * no palette: dma0_desc_cmd --> dma0_desc0 ++ * no palette: dma0_desc_cmd --> dma0_desc0 + * --> dma0_desc1 --> dma0_desc_cmd --> ... -+ * palette: dma0_desc_palette --> dma0_desc_cmd -+ * --> dma0_desc0 --> dma0_desc1 ++ * palette: dma0_desc_palette --> dma0_desc_cmd ++ * --> dma0_desc0 --> dma0_desc1 + * --> dma0_desc_palette --> ... + * DMA Chan1: + * TO LCD Panel: -+ * dma1_desc0 <<==>> dma1_desc0 ++ * dma1_desc0 <<==>> dma1_desc0 + * TO TV Encoder: + * dma1_desc0 <<==>> dma1_desc1 + */ @@ -96193,17 +32198,17 @@ + dma0_desc_cmd0->frame_id = (unsigned int)0x0da0cad0; /* dma0's cmd0 */ + dma0_desc_cmd0->cmd = LCD_CMD_CMD | 3; /* command */ + dma0_desc_cmd0->offsize = 0; -+ dma0_desc_cmd0->page_width = 0; ++ dma0_desc_cmd0->page_width = 0; + dma0_desc_cmd0->cmd_num = 3; + + /* Dummy Command Descriptor, cmd_num is 0 */ + dma0_desc_cmd->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+ dma0_desc_cmd->databuf = 0; ++ dma0_desc_cmd->databuf = 0; + dma0_desc_cmd->frame_id = (unsigned int)0x0da000cd; /* dma0's cmd0 */ + dma0_desc_cmd->cmd = LCD_CMD_CMD | 0; /* dummy command */ + dma0_desc_cmd->cmd_num = 0; -+ dma0_desc_cmd->offsize = 0; -+ dma0_desc_cmd->page_width = 0; ++ dma0_desc_cmd->offsize = 0; ++ dma0_desc_cmd->page_width = 0; + + /* Palette Descriptor */ + dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd0); @@ -96274,7 +32279,7 @@ + +#if 0 + /* Palette Descriptor */ -+ if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) ++ if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) +// dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); + dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd1); + else @@ -96294,7 +32299,7 @@ + +//--------------------------------- + dma0_desc_cmd1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+ dma0_desc_cmd1->databuf = 0; ++ dma0_desc_cmd1->databuf = 0; + dma0_desc_cmd1->frame_id = (unsigned int)0x0da0cad1; /* dma0's cmd0 */ + dma0_desc_cmd1->cmd = LCD_CMD_CMD | 0; /* dummy command */ + dma0_desc_cmd1->cmd_num = 0; @@ -96308,10 +32313,10 @@ + if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup?? */ +// dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_palette); //tft + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); // smart lcd -+ else if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) ++ else if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd1); +// dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); -+ else ++ else + dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + } + @@ -96322,10 +32327,10 @@ + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ + if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup?? */ + dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_palette); -+ -+ else if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) ++ ++ else if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) + dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); -+ else ++ else + dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); + dma0_desc1->frame_id = (unsigned int)0x0000da01; /* DMA0'1 */ + } @@ -96388,7 +32393,7 @@ + REG_LCD_CTRL = lcd_info->panel.ctrl; /* LCDC Controll Register */ + REG_LCD_CFG = lcd_info->panel.cfg; /* LCDC Configure Register */ + REG_SLCD_CFG = lcd_info->panel.slcd_cfg; /* Smart LCD Configure Register */ -+ ++ + if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) /* enable Smart LCD DMA */ + REG_SLCD_CTRL = SLCD_CTRL_DMA_EN; + @@ -96435,9 +32440,9 @@ +static void jz4750fb_foreground_resize( struct jz4750lcd_info * lcd_info ) +{ + int fg0_line_size, fg0_frm_size, fg1_line_size, fg1_frm_size; -+ /* -+ * NOTE: -+ * Foreground change sequence: ++ /* ++ * NOTE: ++ * Foreground change sequence: + * 1. Change Position Registers -> LCD_OSDCTL.Change; + * 2. LCD_OSDCTRL.Change -> descripter->Size + * Foreground, only one of the following can be change at one time: @@ -96446,8 +32451,8 @@ + * 3. F1 size + * 4. F1 position + */ -+ -+ /* ++ ++ /* + * The rules of f0, f1's position: + * f0.x + f0.w <= panel.w; + * f0.y + f0.h <= panel.h; @@ -96463,19 +32468,19 @@ + lcd_info->osd.fg0.x = lcd_info->panel.w - 1; + if ( lcd_info->osd.fg0.y >= lcd_info->panel.h ) + lcd_info->osd.fg0.y = lcd_info->panel.h - 1; -+ if ( lcd_info->osd.fg0.x + lcd_info->osd.fg0.w > lcd_info->panel.w ) ++ if ( lcd_info->osd.fg0.x + lcd_info->osd.fg0.w > lcd_info->panel.w ) + lcd_info->osd.fg0.w = lcd_info->panel.w - lcd_info->osd.fg0.x; -+ if ( lcd_info->osd.fg0.y + lcd_info->osd.fg0.h > lcd_info->panel.h ) ++ if ( lcd_info->osd.fg0.y + lcd_info->osd.fg0.h > lcd_info->panel.h ) + lcd_info->osd.fg0.h = lcd_info->panel.h - lcd_info->osd.fg0.y; + /* Foreground 1 */ + /* Case TVE ??? TVE 720x573 or 720x480*/ -+ if ( lcd_info->osd.fg1.x >= lcd_info->panel.w ) ++ if ( lcd_info->osd.fg1.x >= lcd_info->panel.w ) + lcd_info->osd.fg1.x = lcd_info->panel.w - 1; -+ if ( lcd_info->osd.fg1.y >= lcd_info->panel.h ) ++ if ( lcd_info->osd.fg1.y >= lcd_info->panel.h ) + lcd_info->osd.fg1.y = lcd_info->panel.h - 1; -+ if ( lcd_info->osd.fg1.x + lcd_info->osd.fg1.w > lcd_info->panel.w ) ++ if ( lcd_info->osd.fg1.x + lcd_info->osd.fg1.w > lcd_info->panel.w ) + lcd_info->osd.fg1.w = lcd_info->panel.w - lcd_info->osd.fg1.x; -+ if ( lcd_info->osd.fg1.y + lcd_info->osd.fg1.h > lcd_info->panel.h ) ++ if ( lcd_info->osd.fg1.y + lcd_info->osd.fg1.h > lcd_info->panel.h ) + lcd_info->osd.fg1.h = lcd_info->panel.h - lcd_info->osd.fg1.y; + +// fg0_line_size = lcd_info->osd.fg0.w*((lcd_info->osd.fg0.bpp+7)/8); @@ -96496,20 +32501,20 @@ + } + + /* set change */ -+ if ( !(lcd_info->osd.osd_ctrl & LCD_OSDCTRL_IPU) && ++ if ( !(lcd_info->osd.osd_ctrl & LCD_OSDCTRL_IPU) && + (lcd_info->osd.fg_change != FG_CHANGE_ALL) ) + REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; + + /* wait change ready??? */ +// while ( REG_LCD_OSDS & LCD_OSDS_READY ) /* fix in the future, Wolfgang, 06-20-2008 */ + print_dbg("wait LCD_OSDS_READY\n"); -+ ++ + if ( lcd_info->osd.fg_change & FG0_CHANGE_SIZE ) { /* change FG0 size */ + if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* output to TV */ + dma0_desc0->cmd = dma0_desc1->cmd = (fg0_frm_size/4)/2; -+ dma0_desc0->offsize = dma0_desc1->offsize ++ dma0_desc0->offsize = dma0_desc1->offsize + = fg0_line_size/4; -+ dma0_desc0->page_width = dma0_desc1->page_width ++ dma0_desc0->page_width = dma0_desc1->page_width + = fg0_line_size/4; + dma0_desc1->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size)); + } @@ -96519,7 +32524,7 @@ + dma0_desc0->page_width = dma0_desc1->page_width = 0; + } + -+ dma0_desc0->desc_size = dma0_desc1->desc_size ++ dma0_desc0->desc_size = dma0_desc1->desc_size + = lcd_info->osd.fg0.h << 16 | lcd_info->osd.fg0.w; + REG_LCD_SIZE0 = (lcd_info->osd.fg0.h<<16)|lcd_info->osd.fg0.w; + @@ -96537,8 +32542,8 @@ + dma1_desc0->offsize = dma1_desc1->offsize = 0; + dma1_desc0->page_width = dma1_desc1->page_width = 0; + } -+ -+ dma1_desc0->desc_size = dma1_desc1->desc_size ++ ++ dma1_desc0->desc_size = dma1_desc1->desc_size + = lcd_info->osd.fg1.h << 16 | lcd_info->osd.fg1.w; + REG_LCD_SIZE1 = lcd_info->osd.fg1.h << 16|lcd_info->osd.fg1.w; + } @@ -96602,7 +32607,7 @@ + } + + __cpm_set_pixdiv(val); -+ ++ + dprintk("REG_CPM_LPCDR = 0x%08x\n", REG_CPM_LPCDR); + val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */ + val =__cpm_get_pllout2() / val; @@ -96612,7 +32617,7 @@ + } + __cpm_set_ldiv( val ); + REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */ -+ ++ + } + + dprintk("REG_CPM_LPCDR=0x%08x\n", REG_CPM_LPCDR); @@ -96628,7 +32633,7 @@ +#else + +#error "Set lcd clock first, Not support your chipset now!!!" -+ /* ++ /* + * set lcd device clock and lcd pixel clock. + * what about TVE mode??? + * @@ -96637,7 +32642,7 @@ + +} + -+/* ++/* + * jz4750fb_set_mode(), set osd configure, resize foreground + * + */ @@ -96650,8 +32655,8 @@ + jz4750fb_set_var(&cfb->fb.var, -1, &cfb->fb); +} + -+/* -+ * jz4750fb_deep_set_mode, ++/* ++ * jz4750fb_deep_set_mode, + * + */ +static void jz4750fb_deep_set_mode( struct jz4750lcd_info * lcd_info ) @@ -96728,7 +32733,7 @@ +static int jzfb_resume(void) +{ + __cpm_start_lcd(); -+ __gpio_set_pin(GPIO_DISP_OFF_N); ++ __gpio_set_pin(GPIO_DISP_OFF_N); + __lcd_special_on(); + __lcd_set_ena(); + mdelay(200); @@ -96847,7 +32852,7 @@ +#if 1 + for (j = 0;j < h; j++) + for (i = 0;i < wpl; i++) { -+ if((i/8)%8==7) ++ if((i/8)%8==7) + *ptr++ = 0xffffff; + else if ((i/8)%8==1) + *ptr++ = 0xff0000; @@ -96867,7 +32872,7 @@ +#else + for (j = 0;j < h; j++) + for (i = 0;i < wpl; i++) { -+ if((i/8)%8==7) ++ if((i/8)%8==7) + *ptr++ = 0x00ff0000; + else if ((i/8)%8==1) + *ptr++ = 0xffff0000; @@ -96902,22 +32907,22 @@ + case 1: + if(i%(wpl*8)==0) + data = ((i/(wpl*8))%2)*0xffffffff; -+ *ptr++ = data; ++ *ptr++ = data; + break; + case 2: + if(i%(wpl*8)==0) + data = ((i/(wpl*8))%4)*0x55555555; -+ *ptr++ = data; ++ *ptr++ = data; + break; + case 4: + if(i%(wpl*8)==0) + data = ((i/(wpl*8))%16)*0x11111111; -+ *ptr++ = data; ++ *ptr++ = data; + break; + case 8: + if(i%(wpl*8)==0) + data = ((i/(wpl*8))%256)*0x01010101; -+ *ptr++ = data; ++ *ptr++ = data; + break; + } + } @@ -96973,7 +32978,7 @@ + } + +} -+#endif ++#endif + +static int __init jz4750fb_init(void) +{ @@ -96987,7 +32992,7 @@ + __gpio_as_lcd_24bit(); + else + __gpio_as_lcd_18bit(); -+ /* In special mode, we only need init special pin, ++ /* In special mode, we only need init special pin, + * as general lcd pin has init in uboot */ +#if defined(CONFIG_SOC_JZ4750) + switch (jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) { @@ -97000,7 +33005,7 @@ + ; + } +#endif -+ if ( jz4750_lcd_info->osd.fg0.bpp > 16 && ++ if ( jz4750_lcd_info->osd.fg0.bpp > 16 && + jz4750_lcd_info->osd.fg0.bpp < 32 ) { + jz4750_lcd_info->osd.fg0.bpp = 32; + } @@ -97013,7 +33018,7 @@ + jz4750_lcd_info->osd.fg1.bpp = 32; + break; + default: -+ printk("jz4750fb fg1 not support bpp(%d), force to 32bpp\n", ++ printk("jz4750fb fg1 not support bpp(%d), force to 32bpp\n", + jz4750_lcd_info->osd.fg1.bpp); + jz4750_lcd_info->osd.fg1.bpp = 32; + } @@ -97139,7 +33144,7 @@ +struct jz4750_lcd_dma_desc { + unsigned int next_desc; /* LCDDAx */ + unsigned int databuf; /* LCDSAx */ -+ unsigned int frame_id; /* LCDFIDx */ ++ unsigned int frame_id; /* LCDFIDx */ + unsigned int cmd; /* LCDCMDx */ + unsigned int offsize; /* Stride Offsize(in word) */ + unsigned int page_width; /* Stride Pagewidth(in word) */ @@ -97312,7 +33317,7 @@ + __gpio_set_pin(SPEN); \ + udelay(400); \ + } while(0) -+ ++ +#define __lcd_special_pin_init() \ + do { \ + __gpio_as_output(SPEN); /* use SPDA */ \ @@ -97417,7 +33422,7 @@ + __spi_write_reg1((reg<<2), val); \ + udelay(100); \ + }while(0) -+ ++ + #define __lcd_special_pin_init() \ + do { \ + __gpio_as_output(SPEN); /* use SPDA */\ @@ -97510,7 +33515,7 @@ + __spi_write_reg1((reg<<2|2), val); \ + udelay(100); \ + }while(0) -+ ++ + #define __lcd_special_pin_init() \ + do { \ + __gpio_as_output(SPEN); /* use SPDA */\ @@ -97560,7 +33565,7 @@ + __spi_write_reg(0x36, 0x20); \ +*/ +// } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level -+ ++ + #define __lcd_special_off() \ + do { \ + __spi_write_reg(0x00, 0x03); \ @@ -97570,14 +33575,14 @@ + +#if defined(CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W) +static inline void CmdWrite(unsigned int cmd) -+{ ++{ + while (REG_SLCD_STATE & SLCD_STATE_BUSY); /* wait slcd ready */ + udelay(30); + REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd; +} + +static inline void DataWrite(unsigned int data) -+{ ++{ + while (REG_SLCD_STATE & SLCD_STATE_BUSY); /* wait slcd ready */ +// udelay(30); + REG_SLCD_DATA = SLCD_DATA_RS_DATA | data; @@ -97586,11 +33591,11 @@ + +static inline void delay(long delay_time) +{ -+ long cnt; ++ long cnt; + +// delay_time *= (384/8); + delay_time *= (43/8); -+ ++ + for (cnt=0;cntdatabuf = virt_to_phys((void *)lcd_frame[0]); + if ( rotate_angle == FB_ROTATE_UR || \ -+ jzlcd_info->rotate_daemon_thread == NULL) ++ jzlcd_info->rotate_daemon_thread == NULL) + jzlcd_info->rotate_daemon_thread = kthread_run( jzfb_rotate_daemon_thread, jzlcd_info, "%s", "jzlcd-rotate-daemon"); /* start rotate daemon */ + rotate_angle = angle; + break; @@ -99014,7 +35019,7 @@ + printk("Invalid angle(%d)\n", (unsigned int)angle); + } + fb->fix.line_length = fb->var.xres * CONFIG_JZLCD_FRAMEBUFFER_BPP/8; -+ dma_cache_wback_inv((unsigned int)(lcd_frame_desc0), sizeof(struct lcd_desc)); ++ dma_cache_wback_inv((unsigned int)(lcd_frame_desc0), sizeof(struct lcd_desc)); + return 0; +} + @@ -99069,7 +35074,7 @@ + red = 1 << 3; + if (((blue >> 3) == 0) && ((blue >> 2) != 0)) + blue = 1 << 3; -+ ctmp = ((red >> 3) << 11) ++ ctmp = ((red >> 3) << 11) + | ((green >> 2) << 5) | (blue >> 3); + } + @@ -99078,20 +35083,20 @@ + ptr[regno] = ctmp; + + break; -+ ++ + case 15: + if (regno < 16) + ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 10) | ++ ((red >> 3) << 10) | + ((green >> 3) << 5) | + (blue >> 3); + break; + case 16: + if (regno < 16) { + ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 11) | ++ ((red >> 3) << 11) | + ((green >> 2) << 5) | -+ (blue >> 3); ++ (blue >> 3); + } + break; + case 18: @@ -99099,9 +35104,9 @@ + case 32: + if (regno < 16) + ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ (red << 16) | ++ (red << 16) | + (green << 8) | -+ (blue << 0); ++ (blue << 0); + +/* if (regno < 16) { + unsigned val; @@ -99202,7 +35207,7 @@ +} + + -+/* ++/* + * set the video mode according to info->var + */ +static int jzfb_set_par(struct fb_info *info) @@ -99247,7 +35252,7 @@ + return 0; +} + -+/* ++/* + * pan display + */ +static int jzfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) @@ -99323,7 +35328,7 @@ + var->vsync_len = 0; + var->sync = 0; + var->activate &= ~FB_ACTIVATE_TEST; -+ ++ + /* + * CONUPDATE and SMOOTH_XPAN are equal. However, + * SMOOTH_XPAN is only used internally by fbcon. @@ -99573,7 +35578,7 @@ + set_bit(PG_reserved, &map->flags); + } + jz_lcd_buffer_addrs.fb_phys_addr[t] = virt_to_phys((void *)lcd_frame[t]); -+ printk("jzlcd fb[%d] phys addr =0x%08x\n", ++ printk("jzlcd fb[%d] phys addr =0x%08x\n", + t, jz_lcd_buffer_addrs.fb_phys_addr[t]); + } +#if !defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) @@ -99595,7 +35600,7 @@ + set_bit(PG_reserved, &map->flags); + } + -+ printk("Rotate userfb phys addr =0x%08x\n", ++ printk("Rotate userfb phys addr =0x%08x\n", + (unsigned int)virt_to_phys((void *)lcd_frame_user_fb)); + cfb->fb.fix.smem_start = virt_to_phys((void *)lcd_frame_user_fb); + cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); @@ -99654,8 +35659,8 @@ + + for ( t=0; t < CONFIG_JZLCD_FRAMEBUFFER_MAX; t++ ) { + if (lcd_frame[t]) { -+ for (tmp=(unsigned char *)lcd_frame[t]; -+ tmp < lcd_frame[t] + (PAGE_SIZE << page_shift); ++ for (tmp=(unsigned char *)lcd_frame[t]; ++ tmp < lcd_frame[t] + (PAGE_SIZE << page_shift); + tmp += PAGE_SIZE) { + map = virt_to_page(tmp); + clear_bit(PG_reserved, &map->flags); @@ -99665,15 +35670,15 @@ + } +#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) + if (lcd_frame_user_fb) { -+ for (tmp=(unsigned char *)lcd_frame_user_fb; -+ tmp < lcd_frame_user_fb + (PAGE_SIZE << page_shift); ++ for (tmp=(unsigned char *)lcd_frame_user_fb; ++ tmp < lcd_frame_user_fb + (PAGE_SIZE << page_shift); + tmp += PAGE_SIZE) { + map = virt_to_page(tmp); + clear_bit(PG_reserved, &map->flags); + } + free_pages((int)lcd_frame_user_fb, page_shift); + } -+ ++ +#endif +} + @@ -100086,11 +36091,11 @@ +static int jzfb_resume(void) +{ + __cpm_start_lcd(); -+ __gpio_set_pin(GPIO_DISP_OFF_N); ++ __gpio_set_pin(GPIO_DISP_OFF_N); + __lcd_special_on(); + __lcd_set_ena(); + mdelay(200); -+ __lcd_set_backlight_level(80); ++ __lcd_set_backlight_level(80); + + return 0; +} @@ -100132,7 +36137,7 @@ + struct lcd_cfb_info *cfb; + int err = 0; + -+ /* In special mode, we only need init special pin, ++ /* In special mode, we only need init special pin, + * as general lcd pin has init in uboot */ +#if defined(CONFIG_SOC_JZ4740) || defined(CONFIG_SOC_JZ4750) + switch (jzfb.cfg & MODE_MASK) { @@ -100275,7 +36280,7 @@ +struct lcd_desc{ + unsigned int next_desc; /* LCDDAx */ + unsigned int databuf; /* LCDSAx */ -+ unsigned int frame_id; /* LCDFIDx */ ++ unsigned int frame_id; /* LCDFIDx */ + unsigned int cmd; /* LCDCMDx */ +}; + @@ -100582,7 +36587,7 @@ + __gpio_set_pin(SPEN); \ + udelay(400); \ + } while(0) -+ ++ +#define __lcd_special_pin_init() \ + do { \ + __gpio_as_output(SPEN); /* use SPDA */ \ @@ -100686,7 +36691,7 @@ + __spi_write_reg1((reg<<2|2), val); \ + udelay(100); \ + }while(0) -+ ++ + #define __lcd_special_pin_init() \ + do { \ + __gpio_as_output(SPEN); /* use SPDA */\ @@ -100736,7 +36741,7 @@ + __spi_write_reg(0x36, 0x20); \ +*/ +// } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level -+ ++ + #define __lcd_special_off() \ + do { \ + __spi_write_reg(0x00, 0x03); \ @@ -100799,7 +36804,7 @@ +} while (0) + +#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) -+ ++ +#define __lcd_display_pin_init() \ +do { \ + __lcd_special_pin_init();\ @@ -100820,7 +36825,7 @@ +} while (0) + +#else -+ ++ +#define __lcd_display_pin_init() \ +do { \ + __gpio_as_output(GPIO_DISP_OFF_N); \ @@ -100833,7 +36838,7 @@ + __lcd_set_backlight_level(8); \ + __gpio_set_pin(GPIO_DISP_OFF_N); \ +} while (0) -+ ++ +#define __lcd_display_off() \ +do { \ + __lcd_set_backlight_level(0); \ @@ -101049,9 +37054,9 @@ --- linux-2.6.24.7.old/drivers/watchdog/Kconfig 2008-05-07 01:22:34.000000000 +0200 +++ linux-2.6.24.7/drivers/watchdog/Kconfig 2009-04-12 18:13:57.000000000 +0200 @@ -45,6 +45,15 @@ - + # Architecture Independent - + +config JZ_WDT + bool 'JzSoC On-Chip watchdog' + help @@ -101069,7 +37074,7 @@ @@ -10,6 +10,9 @@ # that also fails then you can fall back to the software watchdog # to give you some cover. - + +# JZ-watchdog timer +obj-$(CONFIG_JZ_WDT) += jz_wdt.o +